nyxwm

Owner: IIIlllIIIllI URL: git@github.com:nyangkosense/nyxwm.git

init

Commit 7c315b7dd2c51b9c7beb0ce2bcfe908007822a84 by nyangkosense <sebastian.michalk@protonmail.com> on 2024-10-14 15:02:17 +0000
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..7ca6cfe
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,28 @@
+CC     ?= gcc
+CFLAGS += -std=c99 -Wall -Wextra -pedantic -Wold-style-declaration
+CFLAGS += -Wmissing-prototypes -Wno-unused-parameter
+CFLAGS += $(shell pkg-config --cflags freetype2 xft x11)
+LIBS   = $(shell pkg-config --libs x11 xft freetype2)
+LIBS  += -lm -pthread
+
+PREFIX ?= /usr
+BINDIR ?= $(PREFIX)/bin
+
+all: nyxwm
+
+config.h:
+	cp config.def.h config.h
+
+nyxwm: nyxwm.c nyxwmblocks.c nyxwm.h config.h blocks.h Makefile
+	$(CC) -O3 $(CFLAGS) -o $@ nyxwm.c nyxwmblocks.c $(LIBS)
+
+install: all
+	install -Dm755 nyxwm $(DESTDIR)$(BINDIR)/nyxwm
+
+uninstall:
+	rm -f $(DESTDIR)$(BINDIR)/nyxwm
+
+clean:
+	rm -f nyxwm *.o
+
+.PHONY: all install uninstall clean
\ No newline at end of file
diff --git a/blocks.h b/blocks.h
new file mode 100644
index 0000000..571526e
--- /dev/null
+++ b/blocks.h
@@ -0,0 +1,10 @@
+#include "nyxwm.h"
+
+static const Block blocks[] = {
+    /*Icon*/    /*Command*/                                                    /*Update Interval*/    /*Update Signal*/
+    {"", "date '+%b %d (%a) %I:%M%p'",                                         5,                     0},  // Changed %p to %P
+    {"", "curl -s 'wttr.in/?format=%C+%t'",                            3600,                  0},  // Update every hour
+};
+
+static char delim[] = "  ";
+static unsigned int delimLen = 5;
\ No newline at end of file
diff --git a/config.def.h b/config.def.h
new file mode 100644
index 0000000..885cbfa
--- /dev/null
+++ b/config.def.h
@@ -0,0 +1,56 @@
+#ifndef CONFIG_H
+#define CONFIG_H
+
+// stats bar
+#define BAR_HEIGHT 20
+#define FONT "monospace:size=10"
+#define BAR_COLOR "#333333"
+#define TEXT_COLOR "#FFFFFF"
+
+#define MOD Mod4Mask
+#define BORDER_COLOR "#ffffff"
+#define BORDER_WIDTH 1
+const char* menu[]    = {"dmenu_run",      0};
+const char* term[]    = {"st",             0};
+const char* scrot[]   = {"scr",            0};
+const char* briup[]   = {"bri", "10", "+", 0};
+const char* bridown[] = {"bri", "10", "-", 0};
+const char* voldown[] = {"amixer", "sset", "Master", "5%-",         0};
+const char* volup[]   = {"amixer", "sset", "Master", "5%+",         0};
+const char* volmute[] = {"amixer", "sset", "Master", "toggle",      0};
+const char* colors[]  = {"bud", "/home/goldie/Pictures/Wallpapers", 0};
+
+static struct key keys[] = {
+    {MOD,      XK_q,   win_kill,   {0}},
+    {MOD,      XK_c,   win_center, {0}},
+    {MOD,      XK_f,   win_fs,     {0}},
+
+    {Mod1Mask,           XK_Tab, win_next,   {0}},
+    {Mod1Mask|ShiftMask, XK_Tab, win_prev,   {0}},
+
+    {MOD, XK_d,      run, {.com = menu}},
+    {MOD, XK_w,      run, {.com = colors}},
+    {MOD, XK_p,      run, {.com = scrot}},
+    {MOD, XK_Return, run, {.com = term}},
+
+    {0,   XF86XK_AudioLowerVolume,  run, {.com = voldown}},
+    {0,   XF86XK_AudioRaiseVolume,  run, {.com = volup}},
+    {0,   XF86XK_AudioMute,         run, {.com = volmute}},
+    {0,   XF86XK_MonBrightnessUp,   run, {.com = briup}},
+    {0,   XF86XK_MonBrightnessDown, run, {.com = bridown}},
+
+    {MOD,           XK_1, ws_go,     {.i = 1}},
+    {MOD|ShiftMask, XK_1, win_to_ws, {.i = 1}},
+    {MOD,           XK_2, ws_go,     {.i = 2}},
+    {MOD|ShiftMask, XK_2, win_to_ws, {.i = 2}},
+    {MOD,           XK_3, ws_go,     {.i = 3}},
+    {MOD|ShiftMask, XK_3, win_to_ws, {.i = 3}},
+    {MOD,           XK_4, ws_go,     {.i = 4}},
+    {MOD|ShiftMask, XK_4, win_to_ws, {.i = 4}},
+    {MOD,           XK_5, ws_go,     {.i = 5}},
+    {MOD|ShiftMask, XK_5, win_to_ws, {.i = 5}},
+    {MOD,           XK_6, ws_go,     {.i = 6}},
+    {MOD|ShiftMask, XK_6, win_to_ws, {.i = 6}},
+};
+
+#endif
diff --git a/config.h b/config.h
new file mode 100644
index 0000000..0ac6358
--- /dev/null
+++ b/config.h
@@ -0,0 +1,62 @@
+#ifndef CONFIG_H
+#define CONFIG_H
+
+
+// stats bar
+#define BAR_HEIGHT 25
+#define FONT "Monospace:size=14"
+#define BAR_COLOR "#121212"
+#define TEXT_COLOR "#d0d0d0"
+
+// tray
+#define TRAY_ICON_SIZE 25
+#define TRAY_ICON_SPACING 4
+#define TRAY_PADDING 4
+
+#define MOD Mod4Mask
+#define BORDER_COLOR "#000000"
+#define BORDER_WIDTH 1
+const char* menu[]    = {"dmenu_run",      0};
+const char* term[]    = {"st",             0};
+const char* scrot[]   = {"scr",            0};
+const char* briup[]   = {"bri", "10", "+", 0};
+const char* bridown[] = {"bri", "10", "-", 0};
+const char* voldown[] = {"amixer", "sset", "Master", "5%-",         0};
+const char* volup[]   = {"amixer", "sset", "Master", "5%+",         0};
+const char* volmute[] = {"amixer", "sset", "Master", "toggle",      0};
+const char* colors[]  = {"bud", "/home/goldie/Pictures/Wallpapers", 0};
+
+static struct key keys[] = {
+    {MOD,      XK_q,   win_kill,   {0}},
+    {MOD,      XK_c,   win_center, {0}},
+    {MOD,      XK_f,   win_fs,     {0}},
+
+    {Mod1Mask,           XK_Tab, win_next,   {0}},
+    {Mod1Mask|ShiftMask, XK_Tab, win_prev,   {0}},
+
+    {MOD, XK_d,      run, {.com = menu}},
+    {MOD, XK_w,      run, {.com = colors}},
+    {MOD, XK_p,      run, {.com = scrot}},
+    {MOD, XK_Return, run, {.com = term}},
+
+    {0,   XF86XK_AudioLowerVolume,  run, {.com = voldown}},
+    {0,   XF86XK_AudioRaiseVolume,  run, {.com = volup}},
+    {0,   XF86XK_AudioMute,         run, {.com = volmute}},
+    {0,   XF86XK_MonBrightnessUp,   run, {.com = briup}},
+    {0,   XF86XK_MonBrightnessDown, run, {.com = bridown}},
+
+    {MOD,           XK_1, ws_go,     {.i = 1}},
+    {MOD|ShiftMask, XK_1, win_to_ws, {.i = 1}},
+    {MOD,           XK_2, ws_go,     {.i = 2}},
+    {MOD|ShiftMask, XK_2, win_to_ws, {.i = 2}},
+    {MOD,           XK_3, ws_go,     {.i = 3}},
+    {MOD|ShiftMask, XK_3, win_to_ws, {.i = 3}},
+    {MOD,           XK_4, ws_go,     {.i = 4}},
+    {MOD|ShiftMask, XK_4, win_to_ws, {.i = 4}},
+    {MOD,           XK_5, ws_go,     {.i = 5}},
+    {MOD|ShiftMask, XK_5, win_to_ws, {.i = 5}},
+    {MOD,           XK_6, ws_go,     {.i = 6}},
+    {MOD|ShiftMask, XK_6, win_to_ws, {.i = 6}},
+};
+
+#endif
diff --git a/nyxwm b/nyxwm
new file mode 100755
index 0000000..73bbe6a
Binary files /dev/null and b/nyxwm differ
diff --git a/nyxwm.c b/nyxwm.c
new file mode 100644
index 0000000..856e5ff
--- /dev/null
+++ b/nyxwm.c
@@ -0,0 +1,591 @@
+#include <X11/Xlib.h>
+#include <X11/XF86keysym.h>
+#include <X11/keysym.h>
+#include <X11/XKBlib.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <X11/Xproto.h> 
+#include <sys/wait.h>
+#include <sys/select.h>
+#include <errno.h>
+
+// new includes
+#include <X11/Xft/Xft.h>
+#include <time.h>
+
+#include "nyxwm.h"
+#include "config.h"
+#include "nyxwmblocks.h"
+
+#define DEBUG_LOG(msg, ...) do { \
+    time_t now = time(NULL); \
+    char timestr[20]; \
+    strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", localtime(&now)); \
+    fprintf(stderr, "[%s] DEBUG: " msg "\n", timestr, ##__VA_ARGS__); \
+} while(0)
+
+#define ERROR_LOG(msg, ...) do { \
+    time_t now = time(NULL); \
+    char timestr[20]; \
+    strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", localtime(&now)); \
+    fprintf(stderr, "[%s] ERROR: " msg ": %s\n", timestr, ##__VA_ARGS__, strerror(errno)); \
+} while(0)
+
+static client       *list = {0}, *ws_list[10] = {0}, *cur;
+static int          ws = 1, sw, sh, wx, wy, numlock = 0;
+static unsigned int ww, wh;
+static int          s;
+Display      *d;
+static XButtonEvent mouse;
+Window       root;
+Window bar;
+XftFont *xft_font;
+XftColor xft_color;
+XftDraw *xft_draw;
+Window systray;
+Window systray_icons[MAX_SYSTRAY_ICONS];
+int num_systray_icons;
+Atom xembed_atom;
+Atom manager_atom;
+Atom system_tray_opcode_atom;
+Atom system_tray_selection_atom;
+
+static void (*events[LASTEvent])(XEvent *e) = {
+    [ButtonPress]      = button_press,
+    [ButtonRelease]    = button_release,
+    [ConfigureRequest] = configure_request,
+    [KeyPress]         = key_press,
+    [MapRequest]       = map_request,
+    [MappingNotify]    = mapping_notify,
+    [DestroyNotify]    = notify_destroy,
+    [EnterNotify]      = notify_enter,
+    [MotionNotify]     = notify_motion
+};
+
+#include "config.h"
+
+unsigned long getcolor(const char *col) {
+    Colormap m = DefaultColormap(d, s);
+    XColor c;
+    return (!XAllocNamedColor(d, m, col, &c, &c))?0:c.pixel;
+}
+
+
+void runAutoStart(void) {
+    system("cd ~/.nyxwm; ./autostart_blocking.sh");
+    system("cd ~/.nyxwm; ./autostart.sh &");
+}
+
+void win_focus(client *c) {
+    cur = c;
+    XSetInputFocus(d, cur->w, RevertToParent, CurrentTime);
+}
+
+void notify_destroy(XEvent *e) {
+    win_del(e->xdestroywindow.window);
+
+    if (list) win_focus(list->prev);
+}
+
+void notify_enter(XEvent *e) {
+    while(XCheckTypedEvent(d, EnterNotify, e));
+	while(XCheckTypedWindowEvent(d, mouse.subwindow, MotionNotify, e));
+
+    for win if (c->w == e->xcrossing.window) win_focus(c);
+}
+
+void notify_motion(XEvent *e) {
+    if (!mouse.subwindow || cur->f) return;
+
+    while(XCheckTypedEvent(d, MotionNotify, e));
+
+    int xd = e->xbutton.x_root - mouse.x_root;
+    int yd = e->xbutton.y_root - mouse.y_root;
+
+    XMoveResizeWindow(d, mouse.subwindow,
+        wx + (mouse.button == 1 ? xd : 0),
+        wy + (mouse.button == 1 ? yd : 0),
+        MAX(1, ww + (mouse.button == 3 ? xd : 0)),
+        MAX(1, wh + (mouse.button == 3 ? yd : 0)));
+}
+
+void key_press(XEvent *e) {
+    KeySym keysym = XkbKeycodeToKeysym(d, e->xkey.keycode, 0, 0);
+
+    for (unsigned int i=0; i < sizeof(keys)/sizeof(*keys); ++i)
+        if (keys[i].keysym == keysym &&
+            mod_clean(keys[i].mod) == mod_clean(e->xkey.state))
+            keys[i].function(keys[i].arg);
+}
+
+void button_press(XEvent *e) {
+    if (!e->xbutton.subwindow) return;
+
+    win_size(e->xbutton.subwindow, &wx, &wy, &ww, &wh);
+    XRaiseWindow(d, e->xbutton.subwindow);
+    mouse = e->xbutton;
+}
+
+void button_release(XEvent *e) {
+    mouse.subwindow = 0;
+}
+
+void win_add(Window w) {
+    client *c;
+
+    if (!(c = (client *) calloc(1, sizeof(client))))
+        exit(1);
+
+    c->w = w;
+
+    if (list) {
+        list->prev->next = c;
+        c->prev          = list->prev;
+        list->prev       = c;
+        c->next          = list;
+
+    } else {
+        list = c;
+        list->prev = list->next = list;
+    }
+
+    ws_save(ws);
+}
+
+void win_del(Window w) {
+    client *x = 0;
+
+    for win if (c->w == w) x = c;
+
+    if (!list || !x)  return;
+    if (x->prev == x) list = 0;
+    if (list == x)    list = x->next;
+    if (x->next)      x->next->prev = x->prev;
+    if (x->prev)      x->prev->next = x->next;
+
+    free(x);
+    ws_save(ws);
+}
+
+void win_kill(const Arg arg) {
+    if (cur) XKillClient(d, cur->w);
+}
+
+void win_center(const Arg arg) {
+    if (!cur) return;
+
+    win_size(cur->w, &(int){0}, &(int){0}, &ww, &wh);
+    XMoveWindow(d, cur->w, (sw - ww) / 2, ((sh - BAR_HEIGHT) - wh) / 2 + BAR_HEIGHT);
+}
+
+
+void win_fs(const Arg arg) {
+    if (!cur) return;
+
+    if ((cur->f = cur->f ? 0 : 1)) {
+        win_size(cur->w, &cur->wx, &cur->wy, &cur->ww, &cur->wh);
+        int tray_width = num_systray_icons * (TRAY_ICON_SIZE + TRAY_ICON_SPACING) + TRAY_PADDING * 2;
+        if (num_systray_icons > 0) {
+            tray_width -= TRAY_ICON_SPACING;
+        }
+        XMoveResizeWindow(d, cur->w, 0, BAR_HEIGHT, sw - tray_width, sh - BAR_HEIGHT);
+    } else {
+        XMoveResizeWindow(d, cur->w, cur->wx, cur->wy, cur->ww, cur->wh);
+    }
+}
+
+void win_to_ws(const Arg arg) {
+    int tmp = ws;
+
+    if (arg.i == tmp) return;
+
+    ws_sel(arg.i);
+    win_add(cur->w);
+    ws_save(arg.i);
+
+    ws_sel(tmp);
+    win_del(cur->w);
+    XUnmapWindow(d, cur->w);
+    ws_save(tmp);
+
+    if (list) win_focus(list);
+}
+
+void win_prev(const Arg arg) {
+    if (!cur) return;
+
+    XRaiseWindow(d, cur->prev->w);
+    win_focus(cur->prev);
+}
+
+void win_next(const Arg arg) {
+    if (!cur) return;
+
+    XRaiseWindow(d, cur->next->w);
+    win_focus(cur->next);
+}
+
+void ws_go(const Arg arg) {
+    int tmp = ws;
+
+    if (arg.i == ws) return;
+
+    ws_save(ws);
+    ws_sel(arg.i);
+
+    for win XMapWindow(d, c->w);
+
+    ws_sel(tmp);
+
+    for win XUnmapWindow(d, c->w);
+
+    ws_sel(arg.i);
+
+    if (list) win_focus(list); else cur = 0;
+}
+
+void configure_request(XEvent *e) {
+    XConfigureRequestEvent *ev = &e->xconfigurerequest;
+
+    XConfigureWindow(d, ev->window, ev->value_mask, &(XWindowChanges) {
+        .x          = ev->x,
+        .y          = ev->y,
+        .width      = ev->width,
+        .height     = ev->height,
+        .sibling    = ev->above,
+        .stack_mode = ev->detail
+    });
+}
+
+void map_request(XEvent *e) {
+    Window w = e->xmaprequest.window;
+
+    XSelectInput(d, w, StructureNotifyMask|EnterWindowMask);
+    win_size(w, &wx, &wy, &ww, &wh);
+    win_add(w);
+    cur = list->prev;
+    XSetWindowBorder(d, w, getcolor(BORDER_COLOR));
+    XConfigureWindow(d, w, CWBorderWidth, &(XWindowChanges){.border_width = BORDER_WIDTH});
+    
+    if (wx + wy == 0) win_center((Arg){0});
+
+    XMapWindow(d, w);
+    win_focus(list->prev);
+}
+
+void mapping_notify(XEvent *e) {
+    XMappingEvent *ev = &e->xmapping;
+
+    if (ev->request == MappingKeyboard || ev->request == MappingModifier) {
+        XRefreshKeyboardMapping(ev);
+        input_grab(root);
+    }
+}
+
+void run(const Arg arg) {
+    if (fork() == 0) {
+        if (d) {
+            close(ConnectionNumber(d));
+        }
+        setsid();
+        execvp((char*)arg.com[0], (char**)arg.com);
+        fprintf(stderr, "nyxwm: execvp %s", ((char **)arg.com)[0]);
+        perror(" failed");
+        exit(0);
+    }
+}
+
+void input_grab(Window root) {
+    unsigned int i, j, modifiers[] = {0, LockMask, numlock, numlock|LockMask};
+    XModifierKeymap *modmap = XGetModifierMapping(d);
+    KeyCode code;
+
+    for (i = 0; i < 8; i++)
+        for (int k = 0; k < modmap->max_keypermod; k++)
+            if (modmap->modifiermap[i * modmap->max_keypermod + k]
+                == XKeysymToKeycode(d, 0xff7f))
+                numlock = (1 << i);
+
+    XUngrabKey(d, AnyKey, AnyModifier, root);
+
+    for (i = 0; i < sizeof(keys)/sizeof(*keys); i++)
+        if ((code = XKeysymToKeycode(d, keys[i].keysym)))
+            for (j = 0; j < sizeof(modifiers)/sizeof(*modifiers); j++)
+                XGrabKey(d, code, keys[i].mod | modifiers[j], root,
+                        True, GrabModeAsync, GrabModeAsync);
+
+    for (i = 1; i < 4; i += 2)
+        for (j = 0; j < sizeof(modifiers)/sizeof(*modifiers); j++)
+            XGrabButton(d, i, MOD | modifiers[j], root, True,
+                ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
+                GrabModeAsync, GrabModeAsync, 0, 0);
+
+    XFreeModifiermap(modmap);
+}
+
+void create_bar() {
+    XSetWindowAttributes attr = {
+        .override_redirect = True,
+        .background_pixel = getcolor(BAR_COLOR)
+    };
+    
+    int bar_width = sw - 2 * TRAY_PADDING; // Adjust if needed
+
+    bar = XCreateWindow(d, root, TRAY_PADDING, 0, bar_width, BAR_HEIGHT, 0,
+                        DefaultDepth(d, s), CopyFromParent,
+                        DefaultVisual(d, s),
+                        CWOverrideRedirect | CWBackPixel, &attr);;
+    
+    XMapWindow(d, bar);
+    
+    xft_font = XftFontOpenName(d, s, FONT);  // Use xft_font instead of font
+    XftColorAllocName(d, DefaultVisual(d, s), DefaultColormap(d, s), TEXT_COLOR, &xft_color);
+    xft_draw = XftDrawCreate(d, bar, DefaultVisual(d, s), DefaultColormap(d, s));
+}
+
+void draw_text(const char *text, int x, int y) {
+    XftDrawStringUtf8(xft_draw, &xft_color, xft_font, x, y, (XftChar8*)text, strlen(text));
+}
+
+void create_systray() {
+    XSetWindowAttributes attr;
+    attr.override_redirect = True;
+    attr.background_pixel = getcolor(BAR_COLOR);
+    systray = XCreateWindow(d, root, sw - TRAY_PADDING, 0, TRAY_PADDING * 2, BAR_HEIGHT, 0,
+                            DefaultDepth(d, s), CopyFromParent,
+                            DefaultVisual(d, s),
+                            CWOverrideRedirect | CWBackPixel, &attr);
+    XMapWindow(d, systray);
+
+    xembed_atom = XInternAtom(d, "_XEMBED", False);
+    manager_atom = XInternAtom(d, "MANAGER", False);
+    system_tray_opcode_atom = XInternAtom(d, "_NET_SYSTEM_TRAY_OPCODE", False);
+    system_tray_selection_atom = XInternAtom(d, "_NET_SYSTEM_TRAY_S0", False);
+
+    XSetSelectionOwner(d, system_tray_selection_atom, systray, CurrentTime);
+    if (XGetSelectionOwner(d, system_tray_selection_atom) == systray) {
+        XClientMessageEvent cm;
+        cm.type = ClientMessage;
+        cm.window = root;
+        cm.message_type = manager_atom;
+        cm.format = 32;
+        cm.data.l[0] = CurrentTime;
+        cm.data.l[1] = system_tray_selection_atom;
+        cm.data.l[2] = systray;
+        cm.data.l[3] = 0;
+        cm.data.l[4] = 0;
+        XSendEvent(d, root, False, StructureNotifyMask, (XEvent *)&cm);
+        printf("Systray created and manager message sent\n");
+    } else {
+        printf("Failed to acquire selection ownership for systray\n");
+    }
+}
+
+void handle_systray_request(XClientMessageEvent *cme) {
+    if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
+        Window icon = cme->data.l[2];
+        if (num_systray_icons < MAX_SYSTRAY_ICONS) {
+            XWindowAttributes wa;
+            if (XGetWindowAttributes(d, icon, &wa)) {
+                XReparentWindow(d, icon, systray, 
+                    TRAY_PADDING + num_systray_icons * (TRAY_ICON_SIZE + TRAY_ICON_SPACING), 
+                    (BAR_HEIGHT - TRAY_ICON_SIZE) / 2);
+                XResizeWindow(d, icon, TRAY_ICON_SIZE, TRAY_ICON_SIZE);
+                XMapRaised(d, icon);
+                systray_icons[num_systray_icons++] = icon;
+
+                XEvent ev;
+                ev.xclient.type = ClientMessage;
+                ev.xclient.window = icon;
+                ev.xclient.message_type = xembed_atom;
+                ev.xclient.format = 32;
+                ev.xclient.data.l[0] = CurrentTime;
+                ev.xclient.data.l[1] = XEMBED_EMBEDDED_NOTIFY;
+                ev.xclient.data.l[2] = 0;
+                ev.xclient.data.l[3] = systray;
+                ev.xclient.data.l[4] = 0;
+                XSendEvent(d, icon, False, NoEventMask, &ev);
+
+                XSync(d, False);
+                printf("Icon docked: %ld\n", icon);
+            } else {
+                printf("Failed to get window attributes for icon: %ld\n", icon);
+            }
+        } else {
+            printf("Maximum number of systray icons reached\n");
+        }
+    } else {
+        printf("Received unknown systray request: %ld\n", cme->data.l[1]);
+    }
+}
+
+void update_systray() {
+    static int prev_num_icons = 0;
+    static int prev_tray_width = 0;
+
+    int tray_width = num_systray_icons * (TRAY_ICON_SIZE + TRAY_ICON_SPACING) + TRAY_PADDING * 2;
+    if (num_systray_icons > 0) {
+        tray_width -= TRAY_ICON_SPACING;
+    }
+
+    if (num_systray_icons != prev_num_icons || tray_width != prev_tray_width) {
+        for (int i = 0; i < num_systray_icons; i++) {
+            XMoveResizeWindow(d, systray_icons[i],
+                TRAY_PADDING + i * (TRAY_ICON_SIZE + TRAY_ICON_SPACING),
+                (BAR_HEIGHT - TRAY_ICON_SIZE) / 2,
+                TRAY_ICON_SIZE, TRAY_ICON_SIZE);
+        }
+
+        XMoveResizeWindow(d, systray, 
+            sw - tray_width, 0,
+            tray_width, BAR_HEIGHT);
+
+        prev_num_icons = num_systray_icons;
+        prev_tray_width = tray_width;
+    }
+}
+
+void update_bar() {
+    static char prev_status[256] = {0};
+    char status[256];
+
+    run_nyxwmblocks(status, sizeof(status));
+
+    if (strcmp(status, prev_status) != 0) {
+        XClearWindow(d, bar);
+
+        // Calculate the actual width of the bar
+        int bar_width = sw - 2 * TRAY_PADDING; // Adjust if needed
+
+        // Calculate the width of the text
+        XGlyphInfo extents;
+        XftTextExtentsUtf8(d, xft_font, (XftChar8*)status, strlen(status), &extents);
+
+        // Calculate the starting x position to center the text
+        int x = (bar_width - extents.width) / 2;
+        int y = BAR_HEIGHT / 2 + xft_font->ascent / 2;
+
+        // Ensure x is not negative
+        x = (x < 10) ? 10 : x;
+
+        XftDrawStringUtf8(xft_draw, &xft_color, xft_font, x, y, (XftChar8*)status, strlen(status));
+        XFlush(d);
+        strcpy(prev_status, status);
+    }
+}
+
+int xerror(Display *dpy, XErrorEvent *ee) {
+    if (ee->error_code == BadAccess &&
+        ee->request_code == X_ChangeWindowAttributes) {
+        ERROR_LOG("Another window manager is already running");
+        exit(1);
+    }
+
+    char error_text[1024];
+    XGetErrorText(dpy, ee->error_code, error_text, sizeof(error_text));
+    ERROR_LOG("XError: request_code=%d, error_code=%d, error_text=%s", 
+              ee->request_code, ee->error_code, error_text);
+
+    return 0;
+}
+
+int main(void) {
+    DEBUG_LOG("Starting nyxwm");
+
+    if (!(d = XOpenDisplay(NULL))) {
+        ERROR_LOG("Cannot open display");
+        return 1;
+    }
+    DEBUG_LOG("Display opened successfully");
+
+    signal(SIGCHLD, SIG_IGN);
+    int (*prev_error_handler)(Display *, XErrorEvent *);
+    prev_error_handler = XSetErrorHandler(xerror);
+
+    s    = DefaultScreen(d);
+    root = RootWindow(d, s);
+    sw   = DisplayWidth(d, s);
+    sh   = DisplayHeight(d, s);
+
+    DEBUG_LOG("Screen info: s=%d, root=%lu, sw=%d, sh=%d", s, root, sw, sh);
+
+    if (XSelectInput(d, root, SubstructureRedirectMask | SubstructureNotifyMask) == BadWindow) {
+        ERROR_LOG("Failed to select input on root window");
+        return 1;
+    }
+    DEBUG_LOG("Input selected on root window");
+
+    XDefineCursor(d, root, XCreateFontCursor(d, 68));
+    DEBUG_LOG("Cursor defined");
+
+    input_grab(root);
+    DEBUG_LOG("Input grabbed");
+
+    create_bar();
+    DEBUG_LOG("Bar created");
+
+    create_systray();
+    DEBUG_LOG("Systray created");
+
+    runAutoStart();
+    DEBUG_LOG("Autostart run");
+
+    XEvent ev;
+    struct timeval tv;
+    fd_set fds;
+    int xfd = ConnectionNumber(d);
+
+    DEBUG_LOG("Entering main loop");
+
+    while (1) {
+        if (XPending(d)) {
+            XNextEvent(d, &ev);
+            DEBUG_LOG("Received event: type=%d", ev.type);
+
+            if (events[ev.type]) {
+                events[ev.type](&ev);
+            }
+
+            if (ev.type == ClientMessage && ev.xclient.message_type == system_tray_opcode_atom) {
+                handle_systray_request(&ev.xclient);
+            } else if (ev.type == DestroyNotify) {
+                for (int i = 0; i < num_systray_icons; i++) {
+                    if (systray_icons[i] == ev.xdestroywindow.window) {
+                        for (int j = i; j < num_systray_icons - 1; j++) {
+                            systray_icons[j] = systray_icons[j+1];
+                        }
+                        num_systray_icons--;
+                        break;
+                    }
+                }
+            }
+        } else {
+            FD_ZERO(&fds);
+            FD_SET(xfd, &fds);
+            tv.tv_usec = 100000;  // 100ms timeout
+            tv.tv_sec = 0;
+
+            int ready = select(xfd + 1, &fds, 0, 0, &tv);
+            if (ready == -1) {
+                if (errno != EINTR) {
+                    ERROR_LOG("select() failed");
+                }
+            } else if (ready == 0) {
+                // Timeout occurred, update bar and systray
+                update_bar();
+                update_systray();
+            }
+        }
+    }
+
+    // This part will likely never be reached
+    DEBUG_LOG("Exiting main loop");
+    XSetErrorHandler(prev_error_handler);
+    XCloseDisplay(d);
+    DEBUG_LOG("Display closed");
+
+    return 0;
+}
\ No newline at end of file
diff --git a/nyxwm.h b/nyxwm.h
new file mode 100644
index 0000000..9fc9ee4
--- /dev/null
+++ b/nyxwm.h
@@ -0,0 +1,115 @@
+#ifndef SOWM_H
+#define SOWM_H
+
+#include <X11/Xlib.h>
+#include <X11/Xft/Xft.h>
+#include <X11/Xatom.h>
+
+#define SYSTEM_TRAY_REQUEST_DOCK    0
+#define SYSTEM_TRAY_BEGIN_MESSAGE   1
+#define SYSTEM_TRAY_CANCEL_MESSAGE  2
+
+#define XEMBED_EMBEDDED_NOTIFY      0
+#define XEMBED_WINDOW_ACTIVATE      1
+#define XEMBED_WINDOW_DEACTIVATE    2
+#define XEMBED_REQUEST_FOCUS        3
+#define XEMBED_FOCUS_IN             4
+#define XEMBED_FOCUS_OUT            5
+#define XEMBED_FOCUS_NEXT           6
+#define XEMBED_FOCUS_PREV           7
+
+#define XEMBED_MODALITY_ON          10
+#define XEMBED_MODALITY_OFF         11
+#define XEMBED_REGISTER_ACCELERATOR 12
+#define XEMBED_UNREGISTER_ACCELERATOR 13
+#define XEMBED_ACTIVATE_ACCELERATOR 14
+
+#define MAX_SYSTRAY_ICONS 20
+#define BAR_HEIGHT 23
+
+#define win        (client *t=0, *c=list; c && t!=list->prev; t=c, c=c->next)
+#define ws_save(W) ws_list[W] = list
+#define ws_sel(W)  list = ws_list[ws = W]
+#define MAX(a, b)  ((a) > (b) ? (a) : (b))
+
+#define win_size(W, gx, gy, gw, gh) \
+    XGetGeometry(d, W, &(Window){0}, gx, gy, gw, gh, \
+                 &(unsigned int){0}, &(unsigned int){0})
+
+// Taken from DWM. Many thanks. https://git.suckless.org/dwm
+#define mod_clean(mask) (mask & ~(numlock|LockMask) & \
+        (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
+
+typedef struct {
+    char* icon;
+    char* command;
+    unsigned int interval;
+    unsigned int signal;
+} Block;
+
+typedef struct {
+    const char** com;
+    const int i;
+    const Window w;
+} Arg;
+
+struct key {
+    unsigned int mod;
+    KeySym keysym;
+    void (*function)(const Arg arg);
+    const Arg arg;
+};
+
+typedef struct client {
+    struct client *next, *prev;
+    int f, wx, wy;
+    unsigned int ww, wh;
+    Window w;
+} client;
+
+unsigned long getcolor(const char *col);
+void button_press(XEvent *e);
+void button_release(XEvent *e);
+void configure_request(XEvent *e);
+void input_grab(Window root);
+void key_press(XEvent *e);
+void map_request(XEvent *e);
+void mapping_notify(XEvent *e);
+void notify_destroy(XEvent *e);
+void notify_enter(XEvent *e);
+void notify_motion(XEvent *e);
+void run(const Arg arg);
+void runAutoStart(void);
+void win_add(Window w);
+void win_center(const Arg arg);
+void win_del(Window w);
+void win_fs(const Arg arg);
+void win_focus(client *c);
+void win_kill(const Arg arg);
+void win_prev(const Arg arg);
+void win_next(const Arg arg);
+void win_to_ws(const Arg arg);
+void ws_go(const Arg arg);
+void create_bar();
+void update_bar();
+void draw_text(const char *text, int x, int y);
+void create_systray();
+void handle_systray_request(XClientMessageEvent *cme);
+void update_systray();
+void run_nyxwmblocks();
+
+int xerror(Display *dpy, XErrorEvent *ee);
+
+extern Window bar;
+extern XftFont *xft_font;
+extern XftColor xft_color;
+extern XftDraw *xft_draw;
+extern Window systray;
+extern Window systray_icons[MAX_SYSTRAY_ICONS];
+extern int num_systray_icons;
+extern Atom xembed_atom;
+extern Atom manager_atom;
+extern Atom system_tray_opcode_atom;
+extern Atom system_tray_selection_atom;
+
+#endif
\ No newline at end of file
diff --git a/nyxwmblocks.c b/nyxwmblocks.c
new file mode 100644
index 0000000..cfe8e4d
--- /dev/null
+++ b/nyxwmblocks.c
@@ -0,0 +1,156 @@
+// nyxwmblocks.c
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <X11/Xlib.h>
+#include <X11/Xft/Xft.h>
+#include "nyxwm.h"
+#include "nyxwmblocks.h"
+#include "blocks.h"
+
+#define LENGTH(X) (sizeof(X) / sizeof (X[0]))
+#define CMDLENGTH 100
+#define MIN(a, b) ((a < b) ? a : b)
+#define STATUSLENGTH (LENGTH(blocks) * CMDLENGTH + 1)
+
+void getcmd(const Block *block, char *output);
+void getsigcmds(unsigned int signal);
+void getstatus(char *str);
+void setupsignals(void);
+void update_status(void);
+void statusloop(void);
+void termhandler(int signum);
+void pstdout(void);
+void sighandler(int signum);
+
+static char statusbar[LENGTH(blocks)][CMDLENGTH] = {0};
+static char statusstr[STATUSLENGTH];
+static int statusContinue = 1;
+
+extern Display *d;
+extern Window root;
+extern Window bar;
+extern XftDraw *xft_draw;
+extern XftColor xft_color;
+extern XftFont *xft_font;
+
+void getcmd(const Block *block, char *output) {
+    char tempstatus[CMDLENGTH] = {0};
+    strcpy(tempstatus, block->icon);
+    FILE *cmdf = popen(block->command, "r");
+    if (!cmdf)
+        return;
+    int i = strlen(block->icon);
+    if (fgets(tempstatus + i, CMDLENGTH - i, cmdf) != NULL) {
+        i = strlen(tempstatus);
+        if (i > 0 && tempstatus[i-1] == '\n') {
+            tempstatus[--i] = '\0';
+        }
+        if (delim[0] != '\0' && i + delimLen < CMDLENGTH) {
+            strncpy(tempstatus + i, delim, CMDLENGTH - i - 1);
+            tempstatus[CMDLENGTH - 1] = '\0';
+        }
+    }
+    strcpy(output, tempstatus);
+    pclose(cmdf);
+}
+
+void getcmds(int time)
+{
+    const Block* current;
+    for (unsigned int i = 0; i < LENGTH(blocks); i++) {
+        current = blocks + i;
+        if ((current->interval != 0 && time % current->interval == 0) || time == -1)
+            getcmd(current, statusbar[i]);
+    }
+}
+
+void getsigcmds(unsigned int signal)
+{
+    const Block *current;
+    for (unsigned int i = 0; i < LENGTH(blocks); i++) {
+        current = blocks + i;
+        if (current->signal == signal)
+            getcmd(current, statusbar[i]);
+    }
+}
+
+void setupsignals() {
+    for (unsigned int i = 0; i < LENGTH(blocks); i++) {
+        if (blocks[i].signal > 0)
+            signal(SIGRTMIN+blocks[i].signal, sighandler);
+    }
+}
+
+void getstatus(char *str)
+{
+    str[0] = '\0';
+    for (unsigned int i = 0; i < LENGTH(blocks); i++)
+        strcat(str, statusbar[i]);
+    str[strlen(str)-strlen(delim)] = '\0';
+}
+
+void update_status() {
+    if (!d || !bar || !xft_draw || !xft_font)
+        return;
+
+    getstatus(statusstr);
+
+    XClearWindow(d, bar);
+
+    int bar_width = DisplayWidth(d, DefaultScreen(d));
+    XGlyphInfo extents;
+    XftTextExtentsUtf8(d, xft_font, (XftChar8*)statusstr, strlen(statusstr), &extents);
+
+    int x = (bar_width - extents.width) / 2;
+    int y = BAR_HEIGHT / 2 + xft_font->ascent / 2;
+
+    // Ensure x is not negative and has a minimum padding
+    x = (x < 10) ? 10 : x;
+
+    XftDrawStringUtf8(xft_draw, &xft_color, xft_font, x, y, (XftChar8*)statusstr, strlen(statusstr));
+    XFlush(d);
+}
+
+void statusloop()
+{
+    setupsignals();
+    int i = 0;
+    getcmds(-1);
+    while (statusContinue) {
+        getcmds(i++);
+        update_status();
+        sleep(1.0);
+    }
+}
+
+void sighandler(int signum)
+{
+    getsigcmds(signum-SIGRTMIN);
+    update_status();
+}
+
+void termhandler(int signum) {
+    statusContinue = 0;
+    (void)signum;  // To avoid unused parameter warning
+}
+
+void pstdout()
+{
+    getstatus(statusstr);
+    printf("%s\n", statusstr);
+    fflush(stdout);
+}
+
+// This function should be called from nyxwm's main loop
+void run_nyxwmblocks(char *status, size_t size) {
+    static int time = 0;
+
+    getcmds(time);
+    getstatus(status);
+
+    time++;
+    if (time == 60) time = 0;  // Reset every minute to avoid potential overflow
+}
diff --git a/nyxwmblocks.h b/nyxwmblocks.h
new file mode 100644
index 0000000..4e0374e
--- /dev/null
+++ b/nyxwmblocks.h
@@ -0,0 +1,8 @@
+// nyxwmblocks.h
+#ifndef SOWMBLOCKS_H
+#define SOWMBLOCKS_H
+
+void run_nyxwmblocks(char *status, size_t size);
+
+#endif // SOWMBLOCKS_H
+
diff --git a/output.txt b/output.txt
new file mode 100644
index 0000000..17c80da
--- /dev/null
+++ b/output.txt
@@ -0,0 +1,3 @@
+rm -f nyxwm *.o
+cc -O3 -std=c99 -Wall -Wextra -pedantic -Wold-style-declaration -Wmissing-prototypes -Wno-unused-parameter -I/usr/include/freetype2 -I/usr/include/libpng16 -o nyxwm nyxwm.c -lX11 -lXft -lfreetype
+install -Dm755 nyxwm /usr/bin/nyxwm
diff --git a/rename.sh b/rename.sh
new file mode 100755
index 0000000..f9b077a
--- /dev/null
+++ b/rename.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+# Check if a new name is provided
+if [ "$#" -ne 1 ]; then
+    echo "Usage: $0 <new_name>"
+    echo "Example: $0 nyxwm"
+    exit 1
+fi
+
+NEW_NAME=$1
+OLD_NAME="nyxwm"
+
+# Function to rename files
+rename_files() {
+    find . -depth -name "*$OLD_NAME*" -execdir bash -c 'mv "$1" "${1//'$OLD_NAME'/'$NEW_NAME'}"' _ {} \;
+}
+
+# Function to replace content in files
+replace_content() {
+    grep -rl "$OLD_NAME" . | xargs sed -i "s/$OLD_NAME/$NEW_NAME/g"
+}
+
+# Rename files
+echo "Renaming files..."
+rename_files
+
+# Replace content in files
+echo "Replacing content in files..."
+replace_content
+
+# Update Makefile
+echo "Updating Makefile..."
+sed -i "s/$OLD_NAME/$NEW_NAME/g" Makefile
+
+echo "Renaming complete. Project renamed from $OLD_NAME to $NEW_NAME."
+echo "Please review the changes and update any remaining occurrences manually if necessary."