commit - 7b13656e3ef0f51754993932e6c95f5a3d71f894
commit + 7bb4fd609f572b48d95a3328750a34a7add0916e
blob - c6c6d155c3a77956ad8ec22c5b60a818ede9a9ed
blob + ee6b7aad582c69a1d19eb4900b05e370dafcdfbf
--- bxnotify.c
+++ bxnotify.c
#define _POSIX_C_SOURCE 200809L
+#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
+#include <sys/file.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xft/Xft.h>
static TextBlock tb;
static int total_height;
static time_t start_time;
+static char reg_path[256];
/* Forward Declarations */
static void die(const char *fmt, ...);
static int measure_text(const char *text);
static void init_display(void);
static void calc_layout(void);
-static void setup(int win_h);
+static void init_reg_path(void);
+static int get_and_register_stack_y(int my_h);
+static void unregister_position(void);
+static void setup(int y, int win_h);
static void readstdin(void);
static void draw(void);
static void run(void);
readstdin();
init_display();
calc_layout();
- setup(total_height);
+ init_reg_path();
+ int y = get_and_register_stack_y(total_height);
+ setup(y, total_height);
start_time = time(NULL);
run();
static void
cleanup(void)
{
+ unregister_position();
+
for (int i = 0; i < tb.count; i++)
free(tb.lines[i]);
free(tb.lines);
}
static void
-setup(int win_h)
+init_reg_path(void)
{
+ char *home = getenv("HOME");
+ if (!home) die("bxnotify: HOME not set\n");
+ snprintf(reg_path, sizeof(reg_path), "%s/.local/tmp/bxnotify.reg", home);
+}
+
+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 */
+
+ /* Wait for exclusive lock - blocks until no other bxnotify is reading/writing */
+ flock(fd, LOCK_EX);
+
+ int my_y = WIN_Y;
+ int lowest_y = 0;
+
+ /* Store valid PIDs so we can rewrite the file cleanly */
+ char valid_lines[100][64];
+ int valid_count = 0;
+
+ /* Open the file descriptor as a FILE* for easy reading with fgets */
+ FILE *f = fdopen(fd, "r+");
+ if (f) {
+ char line[64];
+ int pid, y, h;
+
+ /* 1. Read existing entries and find the lowest Y */
+ while (fgets(line, sizeof(line), f) && valid_count < 100) {
+ if (sscanf(line, "%d %d %d", &pid, &y, &h) == 3) {
+ if (kill(pid, 0) == 0) { /* Process is still alive */
+ if ((y + h) > lowest_y)
+ lowest_y = y + h;
+ strcpy(valid_lines[valid_count++], line); /* Keep it */
+ }
+ }
+ }
+
+ /* 2. Calculate our Y position */
+ my_y = (lowest_y > 0) ? lowest_y + 16 : WIN_Y;
+
+ /* 3. Clear file and rewrite with valid PIDs + our new one */
+ ftruncate(fd, 0); /* Erase file contents */
+ fseek(f, 0, SEEK_SET); /* Move cursor back to start */
+
+ for (int i = 0; i < valid_count; i++) {
+ fputs(valid_lines[i], f);
+ }
+
+ fprintf(f, "%d %d %d\n", getpid(), my_y, my_h);
+ fflush(f);
+ fclose(f); /* This automatically closes the underlying fd and releases the lock */
+ } else {
+ close(fd); /* Fallback if fdopen failed */
+ }
+
+ /* Lock is automatically released when fd is closed by fclose() */
+ return my_y;
+}
+
+static void
+unregister_position(void)
+{
+ int fd = open(reg_path, O_RDWR | O_CREAT, 0644);
+ if (fd == -1) return;
+
+ flock(fd, LOCK_EX);
+
+ FILE *f = fdopen(fd, "r+");
+ if (f) {
+ char line[64];
+ char keep[100][64];
+ int count = 0;
+ int my_pid = getpid();
+
+ while (fgets(line, sizeof(line), f) && count < 100) {
+ int pid;
+ sscanf(line, "%d", &pid);
+ /* Keep if it's not ours AND process is alive */
+ if (pid != my_pid && kill(pid, 0) == 0) {
+ strcpy(keep[count++], line);
+ }
+ }
+
+ ftruncate(fd, 0);
+ fseek(f, 0, SEEK_SET);
+
+ for (int i = 0; i < count; i++)
+ fputs(keep[i], f);
+
+ fflush(f);
+ fclose(f);
+ } else {
+ close(fd);
+ }
+}
+
+static void
+setup(int y, int win_h)
+{
XSetWindowAttributes swa;
- int x, y;
int win_w = WIN_WIDTH + 2 * BORDER_WIDTH;
-
- x = DisplayWidth(dpy, screen) - win_w - WIN_X;
- y = WIN_Y;
-
+ int x = DisplayWidth(dpy, screen) - win_w - WIN_X;
+
swa.override_redirect = True;
swa.background_pixel = bg.pixel;
swa.border_pixel = 0;
xft_draw = XftDrawCreate(dpy, win, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen));
+ XClassHint ch = { "bxnotify", "Bxnotify" };
+ XSetClassHint(dpy, win, &ch);
+
XMapWindow(dpy, win);
}