commit f8e5c4741fa8d998eb6ce1df324482ad78cc4100
parent ae7bb6697cae508455a145c79b61fcf86417d775
Author: hhvn <dev@hhvn.uk>
Date: Tue, 19 Apr 2022 22:29:03 +0100
Clean up
I fixed the bug where herbe displays no text and refuses to close on
SIGINT too. die() would not sem_post and sem_close and neither would
any SIGHUPs.
Diffstat:
M | config.h | | | 23 | +++++++++++------------ |
M | herbe.c | | | 251 | +++++++++++++++++++++++++++++++++++++++++++------------------------------------ |
2 files changed, 147 insertions(+), 127 deletions(-)
diff --git a/config.h b/config.h
@@ -1,19 +1,18 @@
-static const char *background_color = "#0a0a10";
-static const char *border_color = "#30404e";
-static const char *font_color = "#1e5eb3";
-static const char *font_pattern = "monospace:size=7";
-static const unsigned line_spacing = 5;
-static const unsigned int padding = 15;
+char *background_color = "#0a0a10";
+char *border_color = "#30404e";
+char *font_color = "#1e5eb3";
+char *font_pattern = "monospace:size=7";
-static const unsigned int width = 650;
-static const unsigned int border_size = 2;
-static const unsigned int pos_x = 10;
-static const unsigned int pos_y = 25;
+unsigned lpad = 5;
+unsigned pad = 15;
+unsigned border = 2;
-enum corners { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT };
enum corners corner = TOP_LEFT;
+unsigned w = 650;
+unsigned x = 10;
+unsigned y = 25;
-static const unsigned int duration = 500; /* in seconds */
+unsigned int duration = 0; /* in seconds, 0 = none */
#define DISMISS_BUTTON Button1
#define ACTION_BUTTON Button3
diff --git a/herbe.c b/herbe.c
@@ -6,41 +6,78 @@
#include <unistd.h>
#include <string.h>
#include <stdarg.h>
+#include <limits.h>
+#include <errno.h>
#include <fcntl.h>
#include <semaphore.h>
+#define EXIT_ACTION EXIT_SUCCESS
+#define EXIT_DISMISS 2
+
+enum colours { COLOR_FONT, COLOR_BACKGROUND, COLOR_BORDER, COLOR_LAST };
+enum corners { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT };
+
+/* allow references to enum */
#include "config.h"
-#define EXIT_ACTION 0
-#define EXIT_FAIL 1
-#define EXIT_DISMISS 2
+struct {
+ size_t len;
+ size_t size;
+ size_t width;
+ char **lines;
+} body = {0, 0, 0, NULL};
+
+Display *display = NULL;
+XftDraw *draw = NULL;
+XftFont *font = NULL;
+Visual *visual = NULL;
+Colormap colormap = 0;
+Window window = 0;
+sem_t *mutex = NULL;
+XftColor color[COLOR_LAST];
+
+void
+cleanup(void) {
+ size_t i;
+
+ if (mutex) {
+ sem_post(mutex);
+ sem_close(mutex);
+ }
+ for (i = 0; i < body.len; i++)
+ free(body.lines[i]);
+ free(body.lines);
+ if (draw)
+ XftDrawDestroy(draw);
+ if (display) {
+ XCloseDisplay(display);
+ if (visual)
+ for (i = 0; i < COLOR_LAST; i++)
+ XftColorFree(display, visual, colormap, &color[i]);
+ }
+}
-Display *display;
-Window window;
-int exit_code = EXIT_DISMISS;
-
-static void die(const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- vfprintf(stderr, format, ap);
- fprintf(stderr, "\n");
- va_end(ap);
- exit(EXIT_FAIL);
+void
+die(const char *str) {
+ perror(str);
+ cleanup();
+ exit(EXIT_FAILURE);
}
-int get_max_len(char *string, XftFont *font, int max_text_width)
-{
- int eol = strlen(string);
+size_t
+fontlen(char *string) {
+ size_t eol, tmp, i;
XGlyphInfo info;
+
+ eol = strlen(string);
XftTextExtentsUtf8(display, font, (FcChar8 *)string, eol, &info);
- if (info.width > max_text_width)
+ if (info.width > body.width)
{
- eol = max_text_width / font->max_advance_width;
+ eol = body.width / font->max_advance_width;
info.width = 0;
- while (info.width < max_text_width)
+ while (info.width < body.width)
{
eol++;
XftTextExtentsUtf8(display, font, (FcChar8 *)string, eol, &info);
@@ -49,45 +86,52 @@ int get_max_len(char *string, XftFont *font, int max_text_width)
eol--;
}
- for (int i = 0; i < eol; i++)
+ for (i = 0; i < eol; i++)
if (string[i] == '\n')
{
string[i] = ' ';
return ++i;
}
- if (info.width <= max_text_width)
+ if (info.width <= body.width)
return eol;
- int temp = eol;
+ tmp = eol;
while (string[eol] != ' ' && eol)
--eol;
if (eol == 0)
- return temp;
+ return tmp;
else
return ++eol;
}
-void expire(int sig)
-{
+void
+expire(int sig) {
XEvent event;
event.type = ButtonPress;
- event.xbutton.button = (sig == SIGUSR2) ? (ACTION_BUTTON) : (DISMISS_BUTTON);
+ event.xbutton.button = (sig == SIGUSR2) ? ACTION_BUTTON : DISMISS_BUTTON;
XSendEvent(display, window, 0, 0, &event);
XFlush(display);
}
-int main(int argc, char *argv[])
-{
- if (argc == 1)
- {
- sem_unlink("/herbe");
- die("Usage: %s body", argv[0]);
- }
-
+int
+main(int argc, char *argv[]) {
struct sigaction act_expire, act_ignore;
+ int screen, sw, sh;
+ int h, th;
+ size_t eol;
+ size_t i;
+ XSetWindowAttributes attributes;
+ char spath[NAME_MAX];
+
+ snprintf(spath, sizeof(spath), "/herbe-%d", getuid());
+
+ if (argc == 1) {
+ fprintf(stderr, "usage: herbe body...\n");
+ return EXIT_FAILURE;
+ }
act_expire.sa_handler = expire;
act_expire.sa_flags = SA_RESTART;
@@ -97,124 +141,101 @@ int main(int argc, char *argv[])
act_ignore.sa_flags = 0;
sigemptyset(&act_ignore.sa_mask);
- sigaction(SIGALRM, &act_expire, 0);
+ sigaction(SIGHUP, &act_expire, 0);
sigaction(SIGTERM, &act_expire, 0);
sigaction(SIGINT, &act_expire, 0);
sigaction(SIGUSR1, &act_ignore, 0);
sigaction(SIGUSR2, &act_ignore, 0);
- if (!(display = XOpenDisplay(0)))
- die("Cannot open display");
+ if (!(display = XOpenDisplay(NULL)))
+ die("XOpenDisplay()");
- int screen = DefaultScreen(display);
- Visual *visual = DefaultVisual(display, screen);
- Colormap colormap = DefaultColormap(display, screen);
+ screen = DefaultScreen(display);
+ sw = DisplayWidth(display, screen);
+ sh = DisplayHeight(display, screen);
+ visual = DefaultVisual(display, screen);
+ colormap = DefaultColormap(display, screen);
- int screen_width = DisplayWidth(display, screen);
- int screen_height = DisplayHeight(display, screen);
+ XftColorAllocName(display, visual, colormap, font_color, &color[COLOR_FONT]);
+ XftColorAllocName(display, visual, colormap, background_color, &color[COLOR_BACKGROUND]);
+ XftColorAllocName(display, visual, colormap, border_color, &color[COLOR_BORDER]);
- XSetWindowAttributes attributes;
attributes.override_redirect = True;
- XftColor color;
- XftColorAllocName(display, visual, colormap, background_color, &color);
- attributes.background_pixel = color.pixel;
- XftColorAllocName(display, visual, colormap, border_color, &color);
- attributes.border_pixel = color.pixel;
-
- 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");
-
- XftFont *font = XftFontOpenName(display, screen, font_pattern);
-
- 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");
+ attributes.background_pixel = color[COLOR_BACKGROUND].pixel;
+ attributes.border_pixel = color[COLOR_BORDER].pixel;
+
+ body.len = 0;
+ body.width = w - 2 * pad;
+ body.size = 5;
+ body.lines = malloc(body.size * sizeof(char *));
+ if (!body.lines)
+ die("malloc()");
+
+ font = XftFontOpenName(display, screen, font_pattern);
+
+ for (i = 1; i < (size_t)argc; i++) {
+ for (eol = fontlen(argv[i]); eol; argv[i] += eol, body.len++, eol = fontlen(argv[i])) {
+ if (body.size <= body.len) {
+ body.lines = realloc(body.lines, (body.size += 5) * sizeof(char *));
+ if (!body.lines)
+ die("realloc()");
}
- lines[num_of_lines] = malloc((eol + 1) * sizeof(char));
- if (!lines[num_of_lines])
- die("malloc failed");
+ body.lines[body.len] = malloc((eol + 1) * sizeof(char));
+ if (!body.lines[body.len])
+ die("malloc()");
- strncpy(lines[num_of_lines], argv[i], eol);
- lines[num_of_lines][eol] = '\0';
+ strncpy(body.lines[body.len], argv[i], eol);
+ body.lines[body.len][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;
+ th = font->ascent - font->descent;
+ h = (body.len - 1) * lpad + body.len * th + 2 * pad;
if (corner == TOP_RIGHT || corner == BOTTOM_RIGHT)
- x = screen_width - width - border_size * 2 - pos_x;
+ x = sw - w - border * 2 - x;
if (corner == BOTTOM_LEFT || corner == BOTTOM_RIGHT)
- y = screen_height - height - border_size * 2 - pos_y;
+ y = sh - h - border * 2 - y;
- window = XCreateWindow(display, RootWindow(display, screen), x, y, width, height, border_size, DefaultDepth(display, screen),
+ window = XCreateWindow(display, RootWindow(display, screen), x, y, w, h, border, DefaultDepth(display, screen),
CopyFromParent, visual, CWOverrideRedirect | CWBackPixel | CWBorderPixel, &attributes);
- XftDraw *draw = XftDrawCreate(display, window, visual, colormap);
- XftColorAllocName(display, visual, colormap, font_color, &color);
+ draw = XftDrawCreate(display, window, visual, colormap);
XSelectInput(display, window, ExposureMask | ButtonPress);
XMapWindow(display, window);
- sem_t *mutex = sem_open("/herbe", O_CREAT, 0644, 1);
+ if ((mutex = sem_open(spath, O_CREAT, 0644, 1)) == SEM_FAILED)
+ die("sem_open()");
sem_wait(mutex);
sigaction(SIGUSR1, &act_expire, 0);
sigaction(SIGUSR2, &act_expire, 0);
- if (duration != 0)
+ if (duration <= 0)
alarm(duration);
- for (;;)
- {
+ for (;;) {
XEvent event;
XNextEvent(display, &event);
- if (event.type == Expose)
- {
+ if (event.type == Expose) {
XClearWindow(display, window);
- for (int i = 0; i < num_of_lines; i++)
- XftDrawStringUtf8(draw, &color, font, padding, line_spacing * i + text_height * (i + 1) + padding,
- (FcChar8 *)lines[i], strlen(lines[i]));
- }
- else if (event.type == ButtonPress)
- {
- if (event.xbutton.button == DISMISS_BUTTON)
- break;
- else if (event.xbutton.button == ACTION_BUTTON)
- {
- exit_code = EXIT_ACTION;
- break;
+ for (i = 0; i < body.len; i++)
+ XftDrawStringUtf8(draw, &color[COLOR_FONT], font, pad, lpad * i + th * (i + 1) + pad,
+ (FcChar8 *)body.lines[i], strlen(body.lines[i]));
+ } else if (event.type == ButtonPress) {
+ switch (event.xbutton.button) {
+ case DISMISS_BUTTON:
+ cleanup();
+ return EXIT_DISMISS;
+ case ACTION_BUTTON:
+ cleanup();
+ return EXIT_ACTION;
}
}
}
-
- 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);
-
- return exit_code;
}