nyxwm

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 7c315b7dd2c51b9c7beb0ce2bcfe908007822a84
parent 8ab59734c11606b409f9ce8798dd628105c3ac2e
Author: nyangkosense <sebastian.michalk@protonmail.com>
Date:   Mon, 14 Oct 2024 15:02:17 +0000

init

Diffstat:
AMakefile | 29+++++++++++++++++++++++++++++
Ablocks.h | 11+++++++++++
Aconfig.def.h | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconfig.h | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anyxwm | 0
Anyxwm.c | 592+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anyxwm.h | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anyxwmblocks.c | 156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anyxwmblocks.h | 8++++++++
Aoutput.txt | 3+++
Arename.sh | 36++++++++++++++++++++++++++++++++++++
11 files changed, 1069 insertions(+), 0 deletions(-)

diff --git a/Makefile 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 @@ -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 @@ -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 @@ -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 Binary files differ. diff --git a/nyxwm.c 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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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."