commit 223460295a87c83aa9a8b145f5eaf70c4d714b3e
parent caf58caa5da948e97030121d3c4c24b95c338c48
Author: Matthew Carlson <matt@mcarlson.xyz>
Date: Sat, 3 Jul 2021 01:55:38 +0000
dynamic+stack
Diffstat:
M | herbe.c | | | 226 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------ |
1 file changed, 175 insertions(+), 51 deletions(-)
diff --git a/herbe.c b/herbe.c
@@ -1,13 +1,18 @@
-#include <X11/Xlib.h>
#include <X11/Xft/Xft.h>
+#include <X11/Xlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <signal.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
-#include <signal.h>
-#include <unistd.h>
#include <string.h>
-#include <stdarg.h>
-#include <fcntl.h>
-#include <semaphore.h>
+#include <sys/file.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <unistd.h>
#include "config.h"
@@ -16,9 +21,19 @@
#define EXIT_DISMISS 2
Display *display;
+XftFont *font;
Window window;
+int num_of_lines;
+char **lines;
int exit_code = EXIT_DISMISS;
+struct mq_object {
+ pid_t pid;
+ long timestamp;
+ char buffer[1024];
+};
+long lastTimestamp;
+
static void die(const char *format, ...)
{
va_list ap;
@@ -29,6 +44,19 @@ static void die(const char *format, ...)
exit(EXIT_FAIL);
}
+void read_y_offset(unsigned int **offset, int *id) {
+ int shm_id = shmget(8432, sizeof(unsigned int), IPC_CREAT | 0660);
+ if (shm_id == -1) die("shmget failed");
+
+ *offset = (unsigned int *)shmat(shm_id, 0, 0);
+ if (*offset == (unsigned int *)-1) die("shmat failed\n");
+ *id = shm_id;
+}
+
+void free_y_offset(int id) {
+ shmctl(id, IPC_RMID, NULL);
+}
+
int get_max_len(char *string, XftFont *font, int max_text_width)
{
int eol = strlen(string);
@@ -70,6 +98,81 @@ int get_max_len(char *string, XftFont *font, int max_text_width)
return ++eol;
}
+void freeLines() {
+ if(lines) {
+ for (int i = 0; i < num_of_lines; i++)
+ free(lines[i]);
+ free(lines);
+ }
+}
+
+void constructLines(char* strList[], int numberOfStrings) {
+ freeLines();
+ int max_text_width = width - 2 * padding;
+ num_of_lines = 0;
+ int lines_size = 5;
+ lines = malloc(lines_size * sizeof(char *));
+ if (!lines)
+ die("malloc failed");
+
+ for (int i = 0; i < numberOfStrings; i++)
+ {
+ for (unsigned int eol = get_max_len(strList[i], font, max_text_width); eol; strList[i] += eol, num_of_lines++, eol = get_max_len(strList[i], font, max_text_width))
+ {
+ if (lines_size <= num_of_lines)
+ {
+ lines = realloc(lines, (lines_size += 5) * sizeof(char *));
+ if (!lines)
+ die("realloc failed");
+ }
+ lines[num_of_lines] = malloc((eol + 1) * sizeof(char));
+ if (!lines[num_of_lines])
+ die("malloc failed");
+
+ strncpy(lines[num_of_lines], strList[i], eol);
+ lines[num_of_lines][eol] = '\0';
+ }
+ }
+}
+
+void reload(union sigval sv);
+void readAllEvents(mqd_t mqd) {
+
+ struct sigevent event = {.sigev_notify=SIGEV_THREAD, .sigev_signo=SIGHUP, .sigev_value.sival_int=mqd, .sigev_notify_function=reload};
+ if(mq_notify(mqd, &event) == -1) {
+ perror("mq_notify failed");
+ exit(1);
+ }
+ struct mq_object object;
+ while(1) {
+ int ret = mq_receive(mqd, (char*)&object, sizeof(object), NULL);
+ if(ret==-1) {
+ if(errno == EAGAIN)
+ return;
+ perror("mq_receive");
+ exit(1);
+ }
+ if(object.timestamp && lastTimestamp > object.timestamp)
+ return;
+ if(object.timestamp)
+ lastTimestamp = object.timestamp;
+ char *buffer = object.buffer;
+
+ constructLines(&buffer, 1);
+ kill(object.pid, SIGTERM);
+ }
+}
+void reload(union sigval sv) {
+ // we've already timed out
+ if(alarm(duration) == 0)
+ return;
+ readAllEvents(sv.sival_int);
+ XEvent event;
+ event.type = Expose;
+ XSendEvent(display, window, 0, 0, &event);
+ XFlush(display);
+}
+
void expire(int sig)
{
XEvent event;
@@ -79,13 +182,54 @@ void expire(int sig)
XFlush(display);
}
+void exitSuccess() {
+ exit(0);
+}
+
int main(int argc, char *argv[])
{
if (argc == 1)
{
- sem_unlink("/herbe");
die("Usage: %s body", argv[0]);
}
+
+ const char* id =getenv("HERBE_ID");
+ mqd_t mqd=-1;
+ if(id) {
+ struct mq_attr attr = { .mq_maxmsg = 10, .mq_msgsize = sizeof(struct mq_object) };
+ mqd = mq_open(id, O_RDWR|O_CREAT|O_NONBLOCK, 0722, &attr);
+ if(mqd==-1){
+ perror("mq_open");
+ die("mq_open");
+ }
+ while (1) {
+ if(flock(mqd, LOCK_EX|LOCK_NB) == 0) {
+ // if we get the lock, register for events
+ break;
+ }
+ if(errno != EWOULDBLOCK) {
+ perror("flock");
+ exit(1);
+ }
+ // someone else is listening for events
+ char* ts_str = getenv("NOTIFICATION_ID");
+ lastTimestamp = ts_str?atol(ts_str):0;
+ struct mq_object object = {getpid(), lastTimestamp, {0}};
+ char *buffer=object.buffer;
+ for(int i=1;i<argc;i++) {
+ strcat(buffer, argv[i]);
+ strcat(buffer, "\n");
+ }
+ signal(SIGTERM, exitSuccess);
+ if(mq_send(mqd, (char*)&object, sizeof(object), 1)==-1) {
+ perror("mq_send");
+ exit(1);
+ }
+ signal(SIGALRM, SIG_IGN);
+ alarm(1);
+ pause();
+ }
+ }
struct sigaction act_expire, act_ignore;
@@ -121,46 +265,26 @@ int main(int argc, char *argv[])
attributes.background_pixel = color.pixel;
XftColorAllocName(display, visual, colormap, border_color, &color);
attributes.border_pixel = color.pixel;
+ font = XftFontOpenName(display, screen, font_pattern);
- int num_of_lines = 0;
- int max_text_width = width - 2 * padding;
- int lines_size = 5;
- char **lines = malloc(lines_size * sizeof(char *));
- if (!lines)
- die("malloc failed");
+ constructLines(argv+1, argc-1);
- XftFont *font = XftFontOpenName(display, screen, font_pattern);
+ //unsigned int x = pos_x;
+ //unsigned int y = pos_y;
+ int y_offset_id;
+ unsigned int *y_offset;
+ read_y_offset(&y_offset, &y_offset_id);
- for (int i = 1; i < argc; i++)
- {
- for (unsigned int eol = get_max_len(argv[i], font, max_text_width); eol; argv[i] += eol, num_of_lines++, eol = get_max_len(argv[i], font, max_text_width))
- {
- if (lines_size <= num_of_lines)
- {
- lines = realloc(lines, (lines_size += 5) * sizeof(char *));
- if (!lines)
- die("realloc failed");
- }
-
- lines[num_of_lines] = malloc((eol + 1) * sizeof(char));
- if (!lines[num_of_lines])
- die("malloc failed");
-
- strncpy(lines[num_of_lines], argv[i], eol);
- lines[num_of_lines][eol] = '\0';
- }
- }
-
- unsigned int x = pos_x;
- unsigned int y = pos_y;
unsigned int text_height = font->ascent - font->descent;
unsigned int height = (num_of_lines - 1) * line_spacing + num_of_lines * text_height + 2 * padding;
+ unsigned int x = pos_x;
+ unsigned int y = pos_y + *y_offset;
+ unsigned int used_y_offset = (*y_offset) += height + padding;
if (corner == TOP_RIGHT || corner == BOTTOM_RIGHT)
- x = screen_width - width - border_size * 2 - pos_x;
-
+ x = screen_width - width - border_size * 2 - x;
if (corner == BOTTOM_LEFT || corner == BOTTOM_RIGHT)
- y = screen_height - height - border_size * 2 - pos_y;
+ y = screen_height - height - border_size * 2 - y;
window = XCreateWindow(display, RootWindow(display, screen), x, y, width, height, border_size, DefaultDepth(display, screen),
CopyFromParent, visual, CWOverrideRedirect | CWBackPixel | CWBorderPixel, &attributes);
@@ -171,15 +295,16 @@ int main(int argc, char *argv[])
XSelectInput(display, window, ExposureMask | ButtonPress);
XMapWindow(display, window);
- sem_t *mutex = sem_open("/herbe", O_CREAT, 0644, 1);
- sem_wait(mutex);
-
sigaction(SIGUSR1, &act_expire, 0);
sigaction(SIGUSR2, &act_expire, 0);
if (duration != 0)
alarm(duration);
+ if(id) {
+ readAllEvents(mqd);
+ }
+
for (;;)
{
XEvent event;
@@ -203,18 +328,18 @@ int main(int argc, char *argv[])
}
}
}
+
+ if (used_y_offset == *y_offset) free_y_offset(y_offset_id);
+ freeLines();
- sem_post(mutex);
- sem_close(mutex);
-
- for (int i = 0; i < num_of_lines; i++)
- free(lines[i]);
-
- free(lines);
XftDrawDestroy(draw);
XftColorFree(display, visual, colormap, &color);
XftFontClose(display, font);
XCloseDisplay(display);
+ if(id) {
+ mq_close(mqd);
+ }
+
return exit_code;
-}
-\ No newline at end of file
+}