Commit Diff


commit - 7b13656e3ef0f51754993932e6c95f5a3d71f894
commit + 7bb4fd609f572b48d95a3328750a34a7add0916e
blob - c6c6d155c3a77956ad8ec22c5b60a818ede9a9ed
blob + ee6b7aad582c69a1d19eb4900b05e370dafcdfbf
--- bxnotify.c
+++ bxnotify.c
@@ -6,6 +6,7 @@
 
 #define _POSIX_C_SOURCE 200809L 
 
+#include <fcntl.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -13,6 +14,7 @@
 #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>
@@ -35,6 +37,7 @@ static int running = 1;
 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, ...);
@@ -43,7 +46,10 @@ static void sigusr1(int sig);
 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);
@@ -58,7 +64,9 @@ main(int argc, char *argv[])
     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();
@@ -80,6 +88,8 @@ die(const char *fmt, ...)
 static void
 cleanup(void)
 {
+    unregister_position();
+
     for (int i = 0; i < tb.count; i++)
         free(tb.lines[i]);
     free(tb.lines);
@@ -185,15 +195,112 @@ calc_layout(void)
 }
 
 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;
@@ -215,6 +322,9 @@ setup(int win_h)
 
     xft_draw = XftDrawCreate(dpy, win, DefaultVisual(dpy, screen), DefaultColormap(dpy, screen));
 
+    XClassHint ch = { "bxnotify", "Bxnotify" };
+    XSetClassHint(dpy, win, &ch);
+
     XMapWindow(dpy, win);
 }