foxygit / sxbar Log in
commit 9831ea68f614d53127efea48602db3a3ed50d178
Author:     uint23 <abhinav.prsai@gmail.com>
AuthorDate: Sun Apr 20 18:27:16 2025 +0100
Commit:     uint23 <abhinav.prsai@gmail.com>
CommitDate: Sun Apr 20 18:27:16 2025 +0100

    i forgot to commit again oops
---
 Makefile     |  38 ++++++----
 src/config.h |  20 ++++-
 src/defs.h   |   4 +
 src/sxbar.c  | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 278 insertions(+), 22 deletions(-)

diff --git a/Makefile b/Makefile
index 15e6fec..65f5edc 100644
--- a/Makefile
+++ b/Makefile
@@ -1,27 +1,35 @@
-# Flags
 CC = gcc
-CFLAGS = -Wall -O2 -g `pkg-config --cflags x11 xft`
-LDFLAGS = `pkg-config --libs x11 xft`
+CFLAGS = -Wall -Wextra -O3 -g -Isrc -march=native -flto -s -Os
+LDFLAGS = -lX11

-# Dirs
 SRC_DIR = src
-OBJ_DIR = obj
-BIN = sxbar
-
-# Source and object files
 SRC = $(wildcard $(SRC_DIR)/*.c)
-OBJ = $(patsubst $(SRC_DIR)/%.c, $(OBJ_DIR)/%.o, $(SRC))
-
-.PHONY: all clean
+OBJ = $(SRC:.c=.o)
+BIN = sxbar
+PREFIX = /usr/local

 all: $(BIN)

 $(BIN): $(OBJ)
 	$(CC) -o $@ $^ $(LDFLAGS)

-$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
-	@mkdir -p $(OBJ_DIR)
-	$(CC) $(CFLAGS) -c $< -o $@
+$(SRC_DIR)/%.o: $(SRC_DIR)/%.c
+	$(CC) $(CFLAGS) -c -o $@ $<

 clean:
-	rm -rf $(OBJ_DIR) $(BIN)
+	rm -f $(SRC_DIR)/*.o $(BIN)
+
+install: all
+	@echo "Installing $(BIN) to $(DESTDIR)$(PREFIX)/bin..."
+	@mkdir -p $(DESTDIR)$(PREFIX)/bin
+	@install -m 755 $(BIN) $(DESTDIR)$(PREFIX)/bin/$(BIN)
+	@echo "Installation complete."
+
+uninstall:
+	@echo "Uninstalling $(BIN) from $(DESTDIR)$(PREFIX)/bin..."
+	@rm -f $(DESTDIR)$(PREFIX)/bin/$(BIN)
+	@echo "Uninstallation complete."
+
+clean-install: clean install
+
+.PHONY: all clean install uninstall clean-install
diff --git a/src/config.h b/src/config.h
index 0147897..d605e37 100644
--- a/src/config.h
+++ b/src/config.h
@@ -1,5 +1,17 @@
-
-#define BAR_HEIGHT		10
-#define BAR_VERT_PAD	10
-#define BAR_HORI_PAD	100
+#define BOTTOM_BAR		False
+#define BAR_HEIGHT		25
+#define BAR_VERT_PAD	15
+#define BAR_HORI_PAD	400
 #define BAR_BORDER		True
+#define BAR_BORDER_W	2
+
+#define BAR_COLOR_BG		"#56002e"
+#define BAR_COLOR_FG		"#ffffff"
+#define BAR_COLOR_BORDER	"#005577"
+#define BAR_FONT			"fixed"
+#define BAR_TEXT_PAD		10
+
+#define BAR_WS_HIGHLIGHT_LEFT	"["
+#define BAR_WS_HIGHLIGHT_RIGHT	"]"
+#define BAR_WS_PADDING			10
+#define BAR_WS_SPACING			10
diff --git a/src/defs.h b/src/defs.h
index 48a7b55..117c25a 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -1,6 +1,8 @@
 #ifndef DEFS_H
 #define DEFS_H

+#include <X11/Xlib.h>
+
 #define uint unsigned int
 #define ulong unsigned long
 #define u_char unsigned char
@@ -9,4 +11,6 @@
 #define SXBAR_AUTHOR	"(C) Abhinav Prasai 2025"
 #define SXBAR_LICINFO	"See LICENSE for more info"

+typedef void (*EventHandler)(XEvent *);
+
 #endif
diff --git a/src/sxbar.c b/src/sxbar.c
index 8c10d20..3f7ada6 100644
--- a/src/sxbar.c
+++ b/src/sxbar.c
@@ -1,22 +1,231 @@
 #include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
+#include <time.h>

+#include <X11/Xatom.h>
 #include <X11/Xlib.h>
+#include <X11/Xutil.h>

 #include "defs.h"

 static void create_win(void);
+static int get_current_workspace(void);
+static char** get_workspace_name(int *count);
+static void hdl_dummy(XEvent *xev);
+static void hdl_expose(XEvent *xev);
+static void hdl_property(XEvent *xev);
+static ulong parse_col(const char *hex);
+static void run(void);
 static void setup(void);
+static void xev_cases(XEvent *xev);

+static EventHandler evtable[LASTEvent];
+static XFontStruct *font;
 static Display *dpy;
-static Window root;
+static Window root, win;
+static GC gc;
 static uint scr;
+static ulong fg_col;
+static ulong bg_col;
+static ulong border_col;
+#include "config.h"

 static void
 create_win(void)
 {
-	ulong fg = WhitePixel(dpy, scr);
-	ulong bg = BlackPixel(dpy, scr);
+	int sw = DisplayWidth(dpy, scr);
+	int sh = DisplayHeight(dpy, scr);
+
+	int bw = BAR_BORDER ? BAR_BORDER_W : 0;
+	int w = sw - (2 * BAR_HORI_PAD);
+	int x = (sw - w) / 2;
+	int h = BAR_HEIGHT;
+	int y = BOTTOM_BAR ? sh - h - BAR_VERT_PAD - bw : BAR_VERT_PAD;
+
+	XSetWindowAttributes wa = {
+		.background_pixel = bg_col,
+		.border_pixel = border_col,
+		.event_mask = ExposureMask | ButtonPressMask
+	};
+
+	win = XCreateWindow(dpy, root,
+			x, y,
+			w, h,
+			bw,
+			CopyFromParent,
+			InputOutput,
+			DefaultVisual(dpy, scr),
+			CWBackPixel | CWBorderPixel | CWEventMask,
+			&wa);
+
+	Atom A_WM_TYPE = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
+	Atom A_WM_TYPE_DOCK = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
+	XChangeProperty(dpy, win, A_WM_TYPE, XA_ATOM, 32,
+			PropModeReplace,
+			(unsigned char *)&A_WM_TYPE_DOCK, 1);
+
+	Atom A_STRUT = XInternAtom(dpy, "_NET_WM_STRUT_PARTIAL", False);
+	long strut[12] = {0};
+
+	if (BOTTOM_BAR) {
+		strut[3] = h + bw;
+		strut[10] = x;
+		strut[11] = x + w - 1;
+	} else {
+		strut[2] = y + h + bw;
+		strut[8] = x;
+		strut[9] = x + w - 1;
+	}
+
+	XChangeProperty(dpy, win, A_STRUT, XA_CARDINAL, 32,
+			PropModeReplace,
+			(unsigned char *)strut, 12);
+
+	XMapRaised(dpy, win);
+
+	gc = XCreateGC(dpy, win, 0, NULL);
+	XSetForeground(dpy, gc, fg_col);
+	font = XLoadQueryFont(dpy, BAR_FONT);
+	if (!font)
+		errx(1, "could not load font");
+	XSetFont(dpy, gc, font->fid);
+}
+
+static int
+get_current_workspace(void)
+{
+	Atom actual_type;
+	int actual_format;
+	unsigned long nitems, bytes_after;
+	unsigned char *data = NULL;
+	Atom prop = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False);
+
+	if (XGetWindowProperty(dpy, root, prop, 0, 1, False,
+				XA_CARDINAL, &actual_type, &actual_format,
+				&nitems, &bytes_after, &data) == Success && data) {
+		int ws = *(unsigned long *)data;
+		XFree(data);
+		return ws;
+	}
+	return -1;
+}
+
+static char**
+get_workspace_name(int *count)
+{
+	Atom actual_type;
+	int actual_format;
+	unsigned long nitems, bytes_after;
+	unsigned char *data = NULL;
+
+	Atom prop = XInternAtom(dpy, "_NET_DESKTOP_NAMES", False);
+	Atom utf8 = XInternAtom(dpy, "UTF8_STRING", False);
+
+	if (XGetWindowProperty(dpy, root, prop, 0, (~0L), False,
+				utf8, &actual_type, &actual_format,
+				&nitems, &bytes_after, &data) == Success && data) {
+
+		char **names = NULL;
+		int n = 0;
+		char *p = (char *)data;
+		while (n < 32 && p < (char *)data + nitems) {
+			names = realloc(names, (n + 1) * sizeof(char *));
+			names[n++] = strdup(p);
+			p += strlen(p) + 1;
+		}
+		XFree(data);
+		*count = n;
+		return names;
+	}
+	*count = 0;
+	return NULL;
+}
+
+static void
+hdl_dummy(XEvent *xev)
+{
+	(void) xev;
+}
+
+static void
+hdl_expose(XEvent *xev)
+{
+	(void) xev;
+	XClearWindow(dpy, win);
+
+	int current_ws = get_current_workspace();
+	int name_count = 0;
+	char **names = get_workspace_name(&name_count);
+
+	uint text_y = (BAR_HEIGHT + font->ascent - font->descent) / 2;
+
+	uint text_x = BAR_TEXT_PAD;
+	if (names) {
+		for (int i = 0; i < name_count; ++i) {
+			char label[64];
+			if (i == current_ws)
+				snprintf(label, sizeof(label), "%s%s%s ",
+						BAR_WS_HIGHLIGHT_LEFT, names[i], BAR_WS_HIGHLIGHT_RIGHT);
+			else
+				snprintf(label, sizeof(label), "%s ", names[i]);
+
+			XDrawString(dpy, win, gc, text_x, text_y,
+					label, strlen(label));
+			text_x += XTextWidth(font, label, strlen(label)) + BAR_WS_SPACING;
+			free(names[i]);
+		}
+		free(names);
+	}
+
+	int bar_width = DisplayWidth(dpy, scr) - (2 * BAR_HORI_PAD);
+	int version_width = XTextWidth(font, SXBAR_VERSION, strlen(SXBAR_VERSION));
+	int version_x = bar_width - version_width - BAR_TEXT_PAD;
+
+	XDrawString(dpy, win, gc, version_x, text_y,
+			SXBAR_VERSION, strlen(SXBAR_VERSION));
+}
+
+static void
+hdl_property(XEvent *xev)
+{
+	if (xev->xproperty.atom == XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False)) {
+		XClearWindow(dpy, win);
+		XEvent expose;
+		expose.type = Expose;
+		evtable[Expose](&expose);
+	}
+}
+
+static ulong
+parse_col(const char *hex)
+{
+	XColor col;
+	Colormap cmap = DefaultColormap(dpy, DefaultScreen(dpy));
+
+	if (!XParseColor(dpy, cmap, hex, &col)) {
+		fprintf(stderr, "sxwm: cannot parse color %s\n", hex);
+		return WhitePixel(dpy, DefaultScreen(dpy));
+	}
+
+	if (!XAllocColor(dpy, cmap, &col)) {
+		fprintf(stderr, "sxwm: cannot allocate color %s\n", hex);
+		return WhitePixel(dpy, DefaultScreen(dpy));
+	}
+
+	return col.pixel;
+}
+
+static void
+run(void)
+{
+	XEvent xev;
+
+	for (;;) {
+		XNextEvent(dpy, &xev);
+		xev_cases(&xev);
+	}
 }

 static void
@@ -26,6 +235,27 @@ setup(void)
 		errx(0, "can't open display. quitting...");
 	root = XDefaultRootWindow(dpy);
 	scr = DefaultScreen(dpy);
+
+	for (int i = 0; i < LASTEvent; ++i)
+		evtable[i] = hdl_dummy;
+
+	evtable[Expose] = hdl_expose;
+	evtable[PropertyNotify] = hdl_property;
+
+	XSelectInput(dpy, root, PropertyChangeMask);
+	fg_col = parse_col(BAR_COLOR_FG);
+	bg_col = parse_col(BAR_COLOR_BG);
+	border_col = parse_col(BAR_COLOR_BORDER);
+	create_win();
+}
+
+static void
+xev_cases(XEvent *xev)
+{
+	if (xev->type >= 0 && xev->type < LASTEvent)
+		evtable[xev->type](xev);
+	else
+		printf("sxwm: invalid event type: %d\n", xev->type);
 }

 int
@@ -39,4 +269,6 @@ main(int ac, char **av)
 	}

 	setup();
+	run();
+	return 0;
 }