commit - 78a11878fa94c94014b7a0364319fb5025821916
commit + 3b54925cbf35d15232908b7ff996ef354d5b4fab
blob - 1b19669b48acd0d65bfc6423ef3f8ff04efbe10b
blob + 0812932392a17514093d9fe4d36951657c2a5705
--- bxwm.c
+++ bxwm.c
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
-#include <unistd.h>
+#include <errno.h>
#include <signal.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <poll.h>
+#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include "config.h"
+#define SOCKET_SUFFIX "/.local/tmp/bxwm.sock"
+
/* Layout types */
enum { FLOAT, CENTER, LEFT_HALF, RIGHT_HALF, SMALL, MAXIMIZE };
static unsigned long unfocus_pixel;
static int curws = INITIAL_WORKSPACE;
static int ws_focus_idx[NUM_WORKSPACES] = {-1}; /* Index of last focused per WS */
+static int server_fd;
+static char socket_path[256];
+static int running;
/* EWMH atoms */
static Atom net_supported, net_number_of_desktops, net_current_desktop;
/* Forward function declarations */
static void logmsg(const char *fmt, ...);
-static void run(void);
-static void cleanup(int status);
+int socket_init(void);
static void setup(void);
+static void handle_socket_command(int fd);
+static void cleanup(int status);
static int xerror(Display *dpy, XErrorEvent *ee);
static void update_workarea(void);
static void manage(Window w);
static void unmanage(Window w);
static void update_client_list(void);
-int
-main(void) {
- signal(SIGTERM, cleanup);
- dpy = XOpenDisplay(NULL);
- if (!dpy) {
- fprintf(stderr, "bxwm: cannot open display '%s'\n", XDisplayName(NULL));
- return 1;
- }
+int
+main(int argc, char *argv[])
+{
+ (void)argc;
+ (void)argv;
+
+ XEvent ev;
+
+ // 1. Initial setup
+ if (!(dpy = XOpenDisplay(NULL))) exit(1);
root = DefaultRootWindow(dpy);
+
+ // 2. Initialize Socket and Poll
+ server_fd = socket_init();
+ int x_fd = ConnectionNumber(dpy);
+
+ struct pollfd fds[2];
+ fds[0].fd = x_fd;
+ fds[0].events = POLLIN;
+ fds[1].fd = server_fd;
+ fds[1].events = POLLIN;
+
+ // 3. User configuration/setup (key grabs, etc)
setup();
- run();
+
+ /* Cache keycodes */
+ KeyCode kcodes[11];
+ KeyCode ws_codes[10];
+ int i, w;
+
+ for (i = 0; i < 11; i++)
+ kcodes[i] = XKeysymToKeycode(dpy, XStringToKeysym(
+ i == 0 ? "Return" :
+ i == 1 ? "Q" :
+ i == 2 ? "C" :
+ i == 3 ? "H" :
+ i == 4 ? "L" :
+ i == 5 ? "S" :
+ i == 6 ? "M" :
+ i == 7 ? "J" :
+ i == 8 ? "K" :
+ i == 9 ? "X" : "P"));
+
+ for (w = 0; w < 10; w++) {
+ KeySym ks = (w == 9) ? XK_0 : (XK_1 + w);
+ ws_codes[w] = XKeysymToKeycode(dpy, ks);
+ }
+
+ running = 1;
+
+ // 4. Main Loop
+ while (running) {
+ if (poll(fds, 2, -1) < 0) {
+ if (errno == EINTR) continue;
+ break;
+ }
+
+ // Handle X11 events
+ if (fds[0].revents & POLLIN) {
+ while (XPending(dpy)) {
+ XNextEvent(dpy, &ev);
+ if (ev.type == KeyPress) {
+ /* Workspace view keys */
+ for (w = 0; w < 10; w++) {
+ if (ev.xkey.keycode == ws_codes[w] &&
+ (ev.xkey.state & Mod4Mask) &&
+ !(ev.xkey.state & ShiftMask)) {
+ view(w);
+ goto processed;
+ }
+ }
+ /* Workspace move keys */
+ for (w = 0; w < 10; w++) {
+ if (ev.xkey.keycode == ws_codes[w] &&
+ (ev.xkey.state & (Mod4Mask | ShiftMask)) ==
+ (Mod4Mask | ShiftMask)) {
+ movetows(w);
+ goto processed;
+ }
+ }
+ /* Action keys */
+ for (i = 0; i < 11; i++) {
+ if (ev.xkey.keycode == kcodes[i]) {
+ switch (i) {
+ case 0:
+ if ((ev.xkey.state & (ShiftMask | Mod1Mask)) == (ShiftMask | Mod1Mask))
+ spawn(TERMINAL);
+ break;
+ case 1:
+ if ((ev.xkey.state & (ControlMask | ShiftMask)) == (ControlMask | ShiftMask))
+ cleanup(0);
+ break;
+ case 2:
+ if ((ev.xkey.state & (ControlMask | Mod1Mask)) == (ControlMask | Mod1Mask))
+ center_window(focused_client);
+ break;
+ case 3:
+ if ((ev.xkey.state & (ControlMask | Mod1Mask)) == (ControlMask | Mod1Mask))
+ left_half_window(focused_client);
+ break;
+ case 4:
+ if ((ev.xkey.state & (ControlMask | Mod1Mask)) == (ControlMask | Mod1Mask))
+ right_half_window(focused_client);
+ break;
+ case 5:
+ if ((ev.xkey.state & (ControlMask | Mod1Mask)) == (ControlMask | Mod1Mask))
+ small_window(focused_client);
+ break;
+ case 6:
+ if ((ev.xkey.state & (ControlMask | Mod1Mask)) == (ControlMask | Mod1Mask))
+ maximize_window(focused_client);
+ break;
+ case 7:
+ if ((ev.xkey.state & (ControlMask | Mod1Mask)) == (ControlMask | Mod1Mask))
+ focus_next();
+ break;
+ case 8:
+ if ((ev.xkey.state & (ControlMask | Mod1Mask)) == (ControlMask | Mod1Mask))
+ focus_prev();
+ break;
+ case 9:
+ if ((ev.xkey.state & (ControlMask | Mod1Mask)) == (ControlMask | Mod1Mask))
+ close_window(focused_client);
+ break;
+ case 10:
+ if ((ev.xkey.state & (ShiftMask | Mod1Mask)) == (ShiftMask | Mod1Mask))
+ spawn(LAUNCHPROGRAM);
+ break;
+ }
+ goto processed;
+ }
+ }
+ processed:;
+ } else if (ev.type == MapRequest) {
+ manage(ev.xmaprequest.window);
+ } else if (ev.type == DestroyNotify) {
+ unmanage(ev.xdestroywindow.window);
+ } else if (ev.type == PropertyNotify) {
+ if (ev.xproperty.atom == net_wm_strut_partial) {
+ update_workarea();
+ }
+ }
+ }
+ }
+
+ // Handle socket commands
+ if (fds[1].revents & POLLIN) {
+ handle_socket_command(server_fd);
+ }
+ }
+
+ // 5. Final Cleanup
cleanup(0);
+ close(server_fd);
+ XCloseDisplay(dpy);
return 0;
}
static void logmsg(const char *fmt, ...) { (void)fmt; }
#endif
+int socket_init(void) {
+ struct sockaddr_un addr;
+ int server_fd;
+ char socket_path[256];
+
+ // Build the socket path
+ char *home = getenv("HOME");
+ if (home == NULL) {
+ fprintf(stderr, "bxwm: HOME not set\n");
+ exit(1);
+ }
+ snprintf(socket_path, sizeof(socket_path), "%s%s", home, SOCKET_SUFFIX);
+
+ // Remove stale socket from previous session
+ unlink(socket_path);
+
+ // Create the socket
+ server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (server_fd < 0) {
+ perror("bxwm: socket");
+ exit(1);
+ }
+
+ // Bind the socket to the path
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
+
+ if (bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ perror("bxwm: bind");
+ close(server_fd);
+ exit(1);
+ }
+
+ // Listen for incoming connections
+ if (listen(server_fd, 5) < 0) {
+ perror("bxwm: listen");
+ close(server_fd);
+ unlink(socket_path);
+ exit(1);
+ }
+
+ return server_fd;
+}
+
static void
setup(void) {
XSetWindowAttributes wa;
}
static void
-run(void) {
- XEvent ev;
- KeyCode kcodes[11];
- KeyCode ws_codes[10];
- int i, w;
-
- /* Cache keycodes */
- for (i = 0; i < 11; i++)
- kcodes[i] = XKeysymToKeycode(dpy, XStringToKeysym(
- i == 0 ? "Return" :
- i == 1 ? "Q" :
- i == 2 ? "C" :
- i == 3 ? "H" :
- i == 4 ? "L" :
- i == 5 ? "S" :
- i == 6 ? "M" :
- i == 7 ? "J" :
- i == 8 ? "K" :
- i == 9 ? "X" : "P"));
-
- for (w = 0; w < 10; w++) {
- KeySym ks = (w == 9) ? XK_0 : (XK_1 + w);
- ws_codes[w] = XKeysymToKeycode(dpy, ks);
- }
-
- for (;;) {
- XNextEvent(dpy, &ev);
- if (ev.type == KeyPress) {
- /* Workspace view keys (Super+Shift+1..0) */
- for (w = 0; w < 10; w++) {
- if (ev.xkey.keycode == ws_codes[w] &&
- (ev.xkey.state & Mod4Mask) &&
- !(ev.xkey.state & ShiftMask)) {
- view(w);
- goto processed;
- }
- }
- /* Workspace move keys (Super+Shift+1..0) */
- for (w = 0; w < 10; w++) {
- if (ev.xkey.keycode == ws_codes[w] &&
- (ev.xkey.state & (Mod4Mask | ShiftMask)) ==
- (Mod4Mask | ShiftMask)) {
- movetows(w);
- goto processed;
- }
- }
- /* Existing key handling */
- for (i = 0; i < 11; i++) {
- if (ev.xkey.keycode == kcodes[i]) {
- switch (i) {
- case 0:
- if ((ev.xkey.state & (ShiftMask | Mod1Mask)) == (ShiftMask | Mod1Mask))
- spawn(TERMINAL);
- break;
- case 1:
- if ((ev.xkey.state & (ControlMask | ShiftMask)) == (ControlMask | ShiftMask))
- cleanup(0);
- break;
- case 2:
- if ((ev.xkey.state & (ControlMask | Mod1Mask)) == (ControlMask | Mod1Mask))
- center_window(focused_client);
- break;
- case 3:
- if ((ev.xkey.state & (ControlMask | Mod1Mask)) == (ControlMask | Mod1Mask))
- left_half_window(focused_client);
- break;
- case 4:
- if ((ev.xkey.state & (ControlMask | Mod1Mask)) == (ControlMask | Mod1Mask))
- right_half_window(focused_client);
- break;
- case 5:
- if ((ev.xkey.state & (ControlMask | Mod1Mask)) == (ControlMask | Mod1Mask))
- small_window(focused_client);
- break;
- case 6:
- if ((ev.xkey.state & (ControlMask | Mod1Mask)) == (ControlMask | Mod1Mask))
- maximize_window(focused_client);
- break;
- case 7:
- if ((ev.xkey.state & (ControlMask | Mod1Mask)) == (ControlMask | Mod1Mask))
- focus_next();
- break;
- case 8:
- if ((ev.xkey.state & (ControlMask | Mod1Mask)) == (ControlMask | Mod1Mask))
- focus_prev();
- break;
- case 9:
- if ((ev.xkey.state & (ControlMask | Mod1Mask)) == (ControlMask | Mod1Mask))
- close_window(focused_client);
- break;
- case 10:
- if ((ev.xkey.state & (ShiftMask | Mod1Mask)) == (ShiftMask | Mod1Mask))
- spawn(LAUNCHPROGRAM);
- break;
- }
- goto processed;
- }
- }
- processed:;
- } else if (ev.type == MapRequest) {
- manage(ev.xmaprequest.window);
- } else if (ev.type == DestroyNotify) {
- unmanage(ev.xdestroywindow.window);
- } else if (ev.type == PropertyNotify) {
- if (ev.xproperty.atom == net_wm_strut_partial) {
- update_workarea();
- }
- }
- }
-}
-
-static void
update_client_list(void) {
Window *wins = NULL;
unsigned int i;
arrange();
}
+static void
+handle_socket_command(int server_fd)
+{
+ int client_fd = accept(server_fd, NULL, NULL);
+ if (client_fd < 0) return;
-static void
+ char buffer[256];
+ memset(buffer, 0, sizeof(buffer));
+
+ if (read(client_fd, buffer, sizeof(buffer) - 1) > 0) {
+ buffer[strcspn(buffer, "\n")] = '\0';
+ fprintf(stderr, "bxwm: socket received '%s'\n", buffer);
+
+ // Map command strings to functions
+ if (strcmp(buffer, "center_window") == 0) {
+ center_window(focused_client);
+ } else if (strcmp(buffer, "left_half") == 0) {
+ left_half_window(focused_client);
+ } else if (strcmp(buffer, "right_half") == 0) {
+ right_half_window(focused_client);
+ } else if (strcmp(buffer, "small_window") == 0) {
+ small_window(focused_client);
+ } else if (strcmp(buffer, "maximize_window") == 0) {
+ maximize_window(focused_client);
+ } else if (strcmp(buffer, "focus_next") == 0) {
+ focus_next();
+ } else if (strcmp(buffer, "focus_prev") == 0) {
+ focus_prev();
+ } else if (strcmp(buffer, "close_window") == 0) {
+ close_window(focused_client);
+ } else if (strcmp(buffer, "spawn_terminal") == 0) {
+ spawn(TERMINAL);
+ } else if (strcmp(buffer, "spawn_launcher") == 0) {
+ spawn(LAUNCHPROGRAM);
+ } else if (strcmp(buffer, "quit") == 0) {
+ running = 0;
+ } else if (strncmp(buffer, "view ", 5) == 0) {
+ int ws = atoi(buffer + 5);
+ if (ws >= 0 && ws <= 9)
+ view(ws);
+ } else if (strncmp(buffer, "movetows ", 9) == 0) {
+ int ws = atoi(buffer + 9);
+ if (ws >= 0 && ws <= 9)
+ movetows(ws);
+ }
+ }
+ XSync(dpy, False);
+ close(client_fd);
+}
+
+static void
cleanup(int status) {
if (dpy) {
if (clients)
free(clients);
XCloseDisplay(dpy);
}
+ unlink(socket_path);
+ close(server_fd);
fprintf(stderr, "bxwm: exit\n");
exit(status);
}