Commit Diff


commit - d1acfe2d63ab7a6725d3dec52228bab42cbc232a
commit + c243e7413d92458368975c45ee74d5f45aec5337
blob - e538039175d1b279091cc78e378c882c07cefa0f
blob + 711c03363990f9fabb4fefa46e01655a51784b0f
--- bxnotify.c
+++ bxnotify.c
@@ -4,19 +4,15 @@
  * See LICENSE.md and README.md for details.
 */
 
-/*
- * bxnotify.c
- *
- * A very basic X notification tool, a.k.a. Brett's X notifier.
- * See LICENSE.md and README.md for details.
- */
+#define _POSIX_C_SOURCE 200809L 
 
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <signal.h>
+#include <time.h>
 #include <unistd.h>
-
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include <X11/Xft/Xft.h>
@@ -28,10 +24,11 @@ static Display *dpy;
 static int screen;
 static Window win;
 static XftFont *font;
-static XftDraw *draw;
+static XftDraw *xft_draw;
 static XftColor fg, bg, border;
 static int running = 1;
 static char text[1024];
+static time_t start_time;
 
 /* Forward Declarations */
 static void die(const char *fmt, ...);
@@ -45,17 +42,19 @@ static void run(void);
 int
 main(int argc, char *argv[])
 {
+    signal(SIGUSR1, sigusr1);
+
     /* TODO: parse cli flags, override config.h */
 
     readstdin();
     setup();
+    start_time = time(NULL);
     run();
     cleanup();
 
     return 0;
 }
 
-/* implementations */
 
 static void
 die(const char *fmt, ...)
@@ -70,7 +69,7 @@ die(const char *fmt, ...)
 static void
 cleanup(void)
 {
-    if (draw)   XftDrawDestroy(draw);
+    if (draw)   XftDrawDestroy(xft_draw);
     if (font)   XftFontClose(dpy, font);
     if (win)    XDestroyWindow(dpy, win);
     if (dpy)    XCloseDisplay(dpy);
@@ -86,24 +85,129 @@ sigusr1(int sig)
 static void
 setup(void)
 {
-    /* TODO: open display, create window, allocate colors, font */
+    XSetWindowAttributes swa;
+    int x, y, height;
+
+    /* open display */
+    if (!(dpy = XOpenDisplay(NULL)))
+        die("bxnotify: cannot open display\n");
+
+    screen = DefaultScreen(dpy);
+
+    /* load font first — needed for height calculation */
+    if (!(font = XftFontOpenName(dpy, screen, FONT)))
+        die("bxnotify: cannot load font\n");
+
+    /* auto-height: font ascent + descent + padding top/bottom */
+    height = font->ascent + font->descent + PADDING * 2;
+
+    /* position: top-right, below bxbar */
+    int win_w = WIN_WIDTH + 2 * BORDER_WIDTH;
+    int win_h = height + 2 * BORDER_WIDTH;
+
+    x = DisplayWidth(dpy, screen) - win_w - WIN_X;
+    y = WIN_Y;
+
+    /* create window — override_redirect so bxwm ignores it */
+    swa.override_redirect = True;
+    swa.background_pixel = bg.pixel;
+    swa.border_pixel = 0;
+    swa.event_mask = ExposureMask;
+
+    win = XCreateWindow(dpy, RootWindow(dpy, screen), x, y,
+                        win_w, win_h, 0, /* border_width = 0 */
+                        CopyFromParent, CopyFromParent, CopyFromParent,
+                        CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWEventMask,
+                        &swa);
+
+    /* allocate colors */
+    if (!XftColorAllocName(dpy, DefaultVisual(dpy, screen),
+                           DefaultColormap(dpy, screen), FG_COLOR, &fg))
+        die("bxnotify: cannot allocate fg color\n");
+    if (!XftColorAllocName(dpy, DefaultVisual(dpy, screen),
+                           DefaultColormap(dpy, screen), BG_COLOR, &bg))
+        die("bxnotify: cannot allocate bg color\n");
+    if (!XftColorAllocName(dpy, DefaultVisual(dpy, screen),
+                           DefaultColormap(dpy, screen), BORDER_COLOR, &border))
+        die("bxnotify: cannot allocate border color\n");
+
+    /* create draw context */
+    xft_draw = XftDrawCreate(dpy, win, DefaultVisual(dpy, screen),
+                         DefaultColormap(dpy, screen));
+
+    XMapWindow(dpy, win);
 }
 
 static void
 readstdin(void)
 {
-    /* TODO: read from stdin into text[], handle EOF */
+    if (fgets(text, sizeof(text), stdin) == NULL) {
+        die("bxnotify: no input received\n");
+    }
+    /* remove trailing newline */
+    text[strcspn(text, "\n")] = '\0';
 }
 
 static void
 draw(void)
 {
-    /* TODO: clear, render text, calculate auto-height */
+    int height = font->ascent + font->descent + PADDING * 2;
+    int win_w = WIN_WIDTH + 2 * BORDER_WIDTH;
+    int win_h = height + 2 * BORDER_WIDTH;
+    int x, y;
+    XGlyphInfo ext;
+
+    /* draw border (full window) */
+    XftDrawRect(xft_draw, &border, 0, 0, win_w, win_h);
+
+    /* draw background (inner area) */
+    XftDrawRect(xft_draw, &bg, BORDER_WIDTH, BORDER_WIDTH, WIN_WIDTH, height);
+
+    switch (ALIGN) {
+        case 0: /* left */
+            x = PADDING;
+            break;
+        case 1: /* center */
+            XftTextExtentsUtf8(dpy, font, (XftChar8 *)text, strlen(text), &ext);
+            x = (WIN_WIDTH - ext.width) / 2;
+            break;
+        case 2: /* right */
+            XftTextExtentsUtf8(dpy, font, (XftChar8 *)text, strlen(text), &ext);
+            x = WIN_WIDTH - ext.width - PADDING;
+            break;
+    }
+
+    y = (height - (font->ascent + font->descent)) / 2 + font->ascent;
+
+    /* offset text into inner content area */
+    x += BORDER_WIDTH;
+    y += BORDER_WIDTH;
+
+    XftDrawStringUtf8(xft_draw, &fg, font, x, y,
+                      (XftChar8 *)text, strlen(text));
+
+    XFlush(dpy);
 }
 
 static void
 run(void)
 {
-    /* TODO: event loop with timeout, handle Expose and SIGUSR1 */
+    XEvent ev;
+
+    while (running) {
+        if (XPending(dpy)) {
+            XNextEvent(dpy, &ev);
+            if (ev.type == Expose)
+                draw();
+        }
+
+        /* check duration timeout */
+        if (DURATION > 0 && (time(NULL) - start_time) >= DURATION)
+            running = 0;
+
+        struct timespec ts = {0, 10000000};  /* 10 milliseconds */
+        nanosleep(&ts, NULL);
+
+    }
 }
 
blob - 2081eb4e59110ab690aadabb746ffbc8d873a4b5
blob + 41948ebe97c4a51534ff71c4bd789dff0584823d
--- config.def.h
+++ config.def.h
@@ -4,21 +4,15 @@
  * See LICENSE.md and README.md for details.
  */
 
-/* 
- * config.def.h for bxnotify
- *
- * A very basic X notification tool, a.k.a. Brett's X notifier.
- * See LICENSE.md and README.md for details.
- */
-
 #define WIN_WIDTH       480
 #define WIN_X           0       /* Offset from right edge of screen */
-#define WIN_Y           36      /* Below bxbar (BAR_HEIGHT 32 + PADDING 4) */
+#define WIN_Y           33      /* Below bxbar (BAR_HEIGHT 32 + PADDING 4) */
 #define PADDING         6
 #define BORDER_WIDTH    2
 #define BORDER_COLOR    "#555555"
 #define FG_COLOR        "#ffffff"
 #define BG_COLOR        "#000000"
 #define FONT            "monospace:size=14"
+#define ALIGN  0        /* 0 = left, 1 = center, 2 = right */
 #define DURATION        5       /* Seconds, 0 = persist until dismissed */