commit f04a5f5c2efc8b90ca3004c28f534b3cee737c2c from: Brett Fisher date: Mon Jun 1 23:06:33 2026 UTC bxnotify.c: Implement command-line configuration logic. - Convert hardcoded config.h macros into mutable global variables for runtime configuration. - Implement CLI option parsing using getopt(3) to support custom duration (-d), font (-f), foreground color (-F), background color (-B), border color (-C), and alignment (-a) at launch. - Update setup() and draw() to utilize runtime configuration variables instead of compile-time macros. - Retain config.def.h as the architectural source for default values. commit - c2ca3402b92d106af09010320b729704fb5c379b commit + f04a5f5c2efc8b90ca3004c28f534b3cee737c2c blob - 7e4e035b5bc8a122de59be66afa1586aa74232c2 blob + e148a4ee2d2e5c52dda8a64e7bf4698776d74e51 --- bxnotify.c +++ bxnotify.c @@ -39,6 +39,18 @@ static TextBlock tb; static int total_height; static time_t start_time; static char reg_path[256]; +/* Global runtime configuration (defaults from config.h) */ +static int cfg_width = WIN_WIDTH; +static int cfg_win_x = WIN_X; +static int cfg_win_y = WIN_Y; +static int cfg_padding = PADDING; +static int cfg_border_width = BORDER_WIDTH; +static int cfg_align = ALIGN; +static int cfg_duration = DURATION; +static const char *cfg_fg = FG_COLOR; +static const char *cfg_bg = BG_COLOR; +static const char *cfg_border = BORDER_COLOR; +static const char *cfg_font = FONT; /* Forward Declarations */ static void die(const char *fmt, ...); @@ -60,10 +72,23 @@ static void run(void); int main(int argc, char *argv[]) { + int opt; + while ((opt = getopt(argc, argv, "d:f:F:B:C:a:")) != -1) { + switch (opt) { + case 'd': cfg_duration = atoi(optarg); break; + case 'f': cfg_font = optarg; break; + case 'F': cfg_fg = optarg; break; + case 'B': cfg_bg = optarg; break; + case 'C': cfg_border = optarg; break; + case 'a': cfg_align = atoi(optarg); break; + default: + die("usage: bxnotify [-d duration] [-f font] [-F fg] [-B bg] [-a align]\n"); + } + } + argc -= optind; + argv += optind; + signal(SIGUSR1, sigusr1); - - /* TODO: parse cli flags, override config.h */ - readstdin(); init_display(); calc_layout(); @@ -168,7 +193,7 @@ init_display(void) screen = DefaultScreen(dpy); - if (!(font = XftFontOpenName(dpy, screen, FONT))) + if (!(font = XftFontOpenName(dpy, screen, cfg_font))) die("bxnotify: cannot load font\n"); } @@ -182,10 +207,10 @@ calc_layout(void) for (int i = 0; i < tb.count; i++) { char *line = tb.lines[i]; - while (measure_text(line) > WIN_WIDTH) { + while (measure_text(line) > cfg_width) { /* Find break point */ char *p = line + strlen(line); - while (p > line && measure_text(line) > WIN_WIDTH) { + while (p > line && measure_text(line) > cfg_width) { while (p > line && *p != ' ') p--; if (p == line) break; /* Cannot wrap, forced break */ *p = '\0'; @@ -205,7 +230,7 @@ calc_layout(void) free(tb.lines); tb.lines = wrapped; tb.count = wrapped_count; - total_height = (tb.count * line_h) + ((tb.count + 1) * PADDING) + (2 * BORDER_WIDTH); + total_height = (tb.count * line_h) + ((tb.count + 1) * cfg_padding) + (2 * cfg_border_width); } static void @@ -220,12 +245,12 @@ static int get_and_register_stack_y(int my_h) { int fd = open(reg_path, O_RDWR | O_CREAT, 0644); - if (fd == -1) return WIN_Y; /* Fallback if file fails to open */ + if (fd == -1) return cfg_win_y; /* Fallback if file fails to open */ /* Wait for exclusive lock - blocks until no other bxnotify is reading/writing */ flock(fd, LOCK_EX); - int my_y = WIN_Y; + int my_y = cfg_win_y; int lowest_y = 0; /* Store valid PIDs so we can rewrite the file cleanly */ @@ -250,7 +275,7 @@ get_and_register_stack_y(int my_h) } /* 2. Calculate our Y position */ - my_y = (lowest_y > 0) ? lowest_y + 16 : WIN_Y; + my_y = (lowest_y > 0) ? lowest_y + 16 : cfg_win_y; /* 3. Clear file and rewrite with valid PIDs + our new one */ ftruncate(fd, 0); /* Erase file contents */ @@ -344,8 +369,8 @@ static void setup(int y, int win_h) { XSetWindowAttributes swa; - int win_w = WIN_WIDTH + 2 * BORDER_WIDTH; - int x = DisplayWidth(dpy, screen) - win_w - WIN_X; + int win_w = cfg_width + 2 * cfg_border_width; + int x = DisplayWidth(dpy, screen) - win_w - cfg_win_x; swa.override_redirect = True; swa.background_pixel = bg.pixel; @@ -359,11 +384,11 @@ setup(int y, int win_h) &swa); /* Allocate colors and draw context... */ - if (!XftColorAllocName(dpy, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen), FG_COLOR, &fg)) + if (!XftColorAllocName(dpy, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen), cfg_fg, &fg)) die("bxnotify: cannot allocate fg color\n"); - if (!XftColorAllocName(dpy, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen), BG_COLOR, &bg)) + if (!XftColorAllocName(dpy, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen), cfg_bg, &bg)) die("bxnotify: cannot allocate bg color\n"); - if (!XftColorAllocName(dpy, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen), BORDER_COLOR, &border)) + if (!XftColorAllocName(dpy, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen), cfg_border, &border)) die("bxnotify: cannot allocate border color\n"); xft_draw = XftDrawCreate(dpy, win, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen)); @@ -382,21 +407,21 @@ draw(void) { int line_h = font->ascent + font->descent; /* Redraw background... */ - XftDrawRect(xft_draw, &border, 0, 0, WIN_WIDTH + 2 * BORDER_WIDTH, total_height); - XftDrawRect(xft_draw, &bg, BORDER_WIDTH, BORDER_WIDTH, WIN_WIDTH, total_height - 2 * BORDER_WIDTH); + XftDrawRect(xft_draw, &border, 0, 0, cfg_width + 2 * cfg_border_width, total_height); + XftDrawRect(xft_draw, &bg, cfg_border_width, cfg_border_width, cfg_width, total_height - 2 * cfg_border_width); for (int i = 0; i < tb.count; i++) { /* Calculate Y for this specific line */ - int y = PADDING + BORDER_WIDTH + (i * line_h) + font->ascent; + int y = cfg_padding + cfg_border_width + (i * line_h) + font->ascent; int x; XGlyphInfo ext; XftTextExtentsUtf8(dpy, font, (XftChar8 *)tb.lines[i], strlen(tb.lines[i]), &ext); - switch (ALIGN) { - case 0: x = BORDER_WIDTH + PADDING; break; - case 1: x = BORDER_WIDTH + (WIN_WIDTH - ext.width) / 2; break; - case 2: x = BORDER_WIDTH + (WIN_WIDTH - ext.width - PADDING); break; - default: x = BORDER_WIDTH + PADDING; break; + switch (cfg_align) { + case 0: x = cfg_border_width + cfg_padding; break; + case 1: x = cfg_border_width + (cfg_width - ext.width) / 2; break; + case 2: x = cfg_border_width + (cfg_width - ext.width - cfg_padding); break; + default: x = cfg_border_width + cfg_padding; break; } XftDrawStringUtf8(xft_draw, &fg, font, x, y, (XftChar8 *)tb.lines[i], strlen(tb.lines[i])); } @@ -426,7 +451,7 @@ run(void) } } /* Check duration timeout */ - if (DURATION > 0 && (time(NULL) - start_time) >= DURATION) + if (cfg_duration > 0 && (time(NULL) - start_time) >= cfg_duration) running = 0; struct timespec ts = {0, 10000000}; /* 10 milliseconds */