git.strcat.st

/strcat/wm.git/ - summarytreelogarchivereleases

subject
refactor; replace EWMH patch with a optional extra module
commit
a675faf3a4e4baa90622778a239f0e67fd1e2ca4
date
2026-04-28T17:07:14Z
message
 Changes to be committed:
	modified:   Makefile
	modified:   README.md
	new file:   extras/ewmh/ewmh.c
	new file:   extras/ewmh/ewmh.h
	new file:   extras/ewmh/ewmh_stub.c
	deleted:    patches/ewmh.patch
	modified:   wm.c

diff
 Makefile                |   8 ++-
 README.md               |   6 +-
 extras/ewmh/ewmh.c      |  92 +++++++++++++++++++++++++++++++
 extras/ewmh/ewmh.h      |  12 ++++
 extras/ewmh/ewmh_stub.c |  37 +++++++++++++
 patches/ewmh.patch      | 142 ------------------------------------------------
 wm.c                    |  12 +++-
 7 files changed, 164 insertions(+), 145 deletions(-)

diff --git a/Makefile b/Makefile
index ca08907..e6ddddb 100644
--- a/Makefile
+++ b/Makefile
@@ -2,11 +2,17 @@ CFLAGS   = -std=c89 -Wall -Wextra -Werror -pedantic
 CPPFLAGS = -I/usr/X11R6/include
 LDFLAGS  = -L/usr/X11R6/lib
 LDLIBS   = -lX11
+ENABLE_EWMH ?= 0
+
+WM_EXTRAS = extras/ewmh/ewmh_stub.c
+ifeq ($(ENABLE_EWMH),1)
+WM_EXTRAS = extras/ewmh/ewmh.c
+endif
 
 all: wm wmc
 
 wm: wm.c
-	cc $(CPPFLAGS) $(CFLAGS) -o wm wm.c $(LDFLAGS) $(LDLIBS)
+	cc $(CPPFLAGS) $(CFLAGS) -o wm wm.c $(WM_EXTRAS) $(LDFLAGS) $(LDLIBS)
 
 wmc: wmc.c
 	cc $(CPPFLAGS) $(CFLAGS) -o wmc wmc.c $(LDFLAGS) $(LDLIBS)
diff --git a/README.md b/README.md
index 34ac0d5..e12a4a2 100644
--- a/README.md
+++ b/README.md
@@ -2,4 +2,8 @@ window manager - rock bottom of the x11 desktop minimalist pipeline
 
 [FYI](https://wayland.fyi) wayland is still way more minimal ;p
 
-[tinywm](http://incise.org/tinywm.html) fork
\ No newline at end of file
+[tinywm](http://incise.org/tinywm.html) fork
+
+Build:
+- `make`
+- `make ENABLE_EWMH=1` to include EWMH integration from `extras/ewmh/ewmh.c`
diff --git a/extras/ewmh/ewmh.c b/extras/ewmh/ewmh.c
new file mode 100644
index 0000000..8bc8b78
--- /dev/null
+++ b/extras/ewmh/ewmh.c
@@ -0,0 +1,92 @@
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+#include "ewmh.h"
+
+#define num_workspaces 9
+
+static Atom net_supported, net_number_of_desktops, net_current_desktop;
+static Atom net_active_window, net_client_list, net_wm_desktop;
+static Atom net_supporting_wm_check, net_wm_name, utf8_string;
+static Window wm_check_window;
+
+static void
+set_cardinal(Display *display, Window window, Atom atom, unsigned long value)
+{
+	XChangeProperty(display, window, atom, XA_CARDINAL, 32, PropModeReplace,
+	    (unsigned char *)&value, 1);
+}
+
+static void
+set_window(Display *display, Window window, Atom atom, Window value)
+{
+	XChangeProperty(display, window, atom, XA_WINDOW, 32, PropModeReplace,
+	    (unsigned char *)&value, 1);
+}
+
+void
+ewmh_init(Display *display, Window root_window)
+{
+	Atom supported[7];
+	char wm_name[] = "wm";
+
+	net_supported = XInternAtom(display, "_NET_SUPPORTED", False);
+	net_number_of_desktops = XInternAtom(display, "_NET_NUMBER_OF_DESKTOPS", False);
+	net_current_desktop = XInternAtom(display, "_NET_CURRENT_DESKTOP", False);
+	net_active_window = XInternAtom(display, "_NET_ACTIVE_WINDOW", False);
+	net_client_list = XInternAtom(display, "_NET_CLIENT_LIST", False);
+	net_wm_desktop = XInternAtom(display, "_NET_WM_DESKTOP", False);
+	net_supporting_wm_check = XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False);
+	net_wm_name = XInternAtom(display, "_NET_WM_NAME", False);
+	utf8_string = XInternAtom(display, "UTF8_STRING", False);
+	wm_check_window = XCreateSimpleWindow(display, root_window, 0, 0, 1, 1, 0, 0, 0);
+	set_window(display, root_window, net_supporting_wm_check, wm_check_window);
+	set_window(display, wm_check_window, net_supporting_wm_check, wm_check_window);
+	XChangeProperty(display, wm_check_window, net_wm_name, utf8_string, 8,
+	    PropModeReplace, (unsigned char *)wm_name, (int)(sizeof(wm_name) - 1));
+	supported[0] = net_number_of_desktops;
+	supported[1] = net_current_desktop;
+	supported[2] = net_active_window;
+	supported[3] = net_client_list;
+	supported[4] = net_wm_desktop;
+	supported[5] = net_supporting_wm_check;
+	supported[6] = net_wm_name;
+	XChangeProperty(display, root_window, net_supported, XA_ATOM, 32,
+	    PropModeReplace, (unsigned char *)supported, 7);
+	set_cardinal(display, root_window, net_number_of_desktops, num_workspaces);
+	set_cardinal(display, root_window, net_current_desktop, 0);
+	set_window(display, root_window, net_active_window, None);
+}
+
+void
+ewmh_set_current_desktop(Display *display, Window root_window, int current_workspace)
+{
+	set_cardinal(display, root_window, net_current_desktop,
+	    (unsigned long)current_workspace);
+}
+
+void
+ewmh_set_active_window(Display *display, Window root_window, Window window)
+{
+	set_window(display, root_window, net_active_window, window);
+}
+
+void
+ewmh_sync(Display *display, Window root_window,
+    Window *windows, int *window_workspace, int window_count)
+{
+	unsigned long desktop;
+	int i;
+
+	if (window_count > 0)
+	    XChangeProperty(display, root_window, net_client_list, XA_WINDOW, 32,
+	        PropModeReplace, (unsigned char *)windows, window_count);
+	else
+	    XDeleteProperty(display, root_window, net_client_list);
+
+	for (i = 0; i < window_count; i++) {
+	    desktop = (unsigned long)window_workspace[i];
+	    XChangeProperty(display, windows[i], net_wm_desktop, XA_CARDINAL, 32,
+	        PropModeReplace, (unsigned char *)&desktop, 1);
+	}
+}
diff --git a/extras/ewmh/ewmh.h b/extras/ewmh/ewmh.h
new file mode 100644
index 0000000..a307b91
--- /dev/null
+++ b/extras/ewmh/ewmh.h
@@ -0,0 +1,12 @@
+#ifndef EWMH_H
+#define EWMH_H
+
+#include <X11/Xlib.h>
+
+void ewmh_init(Display *display, Window root_window);
+void ewmh_set_current_desktop(Display *display, Window root_window, int current_workspace);
+void ewmh_set_active_window(Display *display, Window root_window, Window window);
+void ewmh_sync(Display *display, Window root_window,
+    Window *windows, int *window_workspace, int window_count);
+
+#endif
diff --git a/extras/ewmh/ewmh_stub.c b/extras/ewmh/ewmh_stub.c
new file mode 100644
index 0000000..0ac0f0d
--- /dev/null
+++ b/extras/ewmh/ewmh_stub.c
@@ -0,0 +1,37 @@
+#include <X11/Xlib.h>
+
+#include "ewmh.h"
+
+void
+ewmh_init(Display *display, Window root_window)
+{
+	(void)display;
+	(void)root_window;
+}
+
+void
+ewmh_set_current_desktop(Display *display, Window root_window, int current_workspace)
+{
+	(void)display;
+	(void)root_window;
+	(void)current_workspace;
+}
+
+void
+ewmh_set_active_window(Display *display, Window root_window, Window window)
+{
+	(void)display;
+	(void)root_window;
+	(void)window;
+}
+
+void
+ewmh_sync(Display *display, Window root_window,
+    Window *windows, int *window_workspace, int window_count)
+{
+	(void)display;
+	(void)root_window;
+	(void)windows;
+	(void)window_workspace;
+	(void)window_count;
+}
diff --git a/patches/ewmh.patch b/patches/ewmh.patch
deleted file mode 100644
index df861a6..0000000
--- a/patches/ewmh.patch
+++ /dev/null
@@ -1,142 +0,0 @@
---- a/wm.c
-+++ b/wm.c
-@@ -1,13 +1,19 @@
- #include <X11/Xlib.h>
-+#include <X11/Xatom.h>
- 
- #define max_val(a, b) ((a) > (b) ? (a) : (b))
- #define mod_key Mod1Mask
- #define max_windows 4096
- #define cmd_workspace 1
- #define cmd_move 2
-+#define num_workspaces 9
- 
- static Window windows[max_windows];
- static int window_workspace[max_windows], window_count, current_workspace;
-+static Atom net_supported, net_number_of_desktops, net_current_desktop;
-+static Atom net_active_window, net_client_list, net_wm_desktop;
-+static Atom net_supporting_wm_check, net_wm_name, utf8_string;
-+static Window wm_check_window;
- 
- static int
- get_window_index(Window window)
-@@ -54,6 +60,72 @@
- }
- 
- static void
-+set_cardinal(Display *display, Window window, Atom atom, unsigned long value)
-+{
-+	XChangeProperty(display, window, atom, XA_CARDINAL, 32, PropModeReplace,
-+	    (unsigned char *)&value, 1);
-+}
-+
-+static void
-+set_window(Display *display, Window window, Atom atom, Window value)
-+{
-+	XChangeProperty(display, window, atom, XA_WINDOW, 32, PropModeReplace,
-+	    (unsigned char *)&value, 1);
-+}
-+
-+static void
-+ewmh_init(Display *display, Window root_window)
-+{
-+	Atom supported[7];
-+	char wm_name[] = "wm";
-+
-+	net_supported = XInternAtom(display, "_NET_SUPPORTED", False);
-+	net_number_of_desktops = XInternAtom(display, "_NET_NUMBER_OF_DESKTOPS", False);
-+	net_current_desktop = XInternAtom(display, "_NET_CURRENT_DESKTOP", False);
-+	net_active_window = XInternAtom(display, "_NET_ACTIVE_WINDOW", False);
-+	net_client_list = XInternAtom(display, "_NET_CLIENT_LIST", False);
-+	net_wm_desktop = XInternAtom(display, "_NET_WM_DESKTOP", False);
-+	net_supporting_wm_check = XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False);
-+	net_wm_name = XInternAtom(display, "_NET_WM_NAME", False);
-+	utf8_string = XInternAtom(display, "UTF8_STRING", False);
-+	wm_check_window = XCreateSimpleWindow(display, root_window, 0, 0, 1, 1, 0, 0, 0);
-+	set_window(display, root_window, net_supporting_wm_check, wm_check_window);
-+	set_window(display, wm_check_window, net_supporting_wm_check, wm_check_window);
-+	XChangeProperty(display, wm_check_window, net_wm_name, utf8_string, 8,
-+	    PropModeReplace, (unsigned char *)wm_name, (int)(sizeof(wm_name) - 1));
-+	supported[0] = net_number_of_desktops;
-+	supported[1] = net_current_desktop;
-+	supported[2] = net_active_window;
-+	supported[3] = net_client_list;
-+	supported[4] = net_wm_desktop;
-+	supported[5] = net_supporting_wm_check;
-+	supported[6] = net_wm_name;
-+	XChangeProperty(display, root_window, net_supported, XA_ATOM, 32,
-+	    PropModeReplace, (unsigned char *)supported, 7);
-+	set_cardinal(display, root_window, net_number_of_desktops, num_workspaces);
-+	set_cardinal(display, root_window, net_current_desktop, 0);
-+	set_window(display, root_window, net_active_window, None);
-+}
-+
-+static void
-+ewmh_sync(Display *display, Window root_window)
-+{
-+	unsigned long desktop;
-+	int i;
-+
-+	if (window_count > 0)
-+	    XChangeProperty(display, root_window, net_client_list, XA_WINDOW, 32,
-+	        PropModeReplace, (unsigned char *)windows, window_count);
-+	else
-+	    XDeleteProperty(display, root_window, net_client_list);
-+	for (i = 0; i < window_count; i++) {
-+	    desktop = (unsigned long)window_workspace[i];
-+	    XChangeProperty(display, windows[i], net_wm_desktop, XA_CARDINAL, 32,
-+	        PropModeReplace, (unsigned char *)&desktop, 1);
-+	}
-+}
-+
-+static void
- show_workspace(Display *display, Window root_window)
- {
- 	Window root_return, parent, *children;
-@@ -97,6 +169,8 @@
- 	control_atom = XInternAtom(display, "_WM_CTL", False);
- 	XSelectInput(display, root_window, SubstructureNotifyMask);
- 	track_windows(display, root_window);
-+	ewmh_init(display, root_window);
-+	ewmh_sync(display, root_window);
- 
- 	XGrabButton(display, 1, mod_key, root_window, True, ButtonPressMask, GrabModeAsync,
- 	    GrabModeAsync, None, None);
-@@ -107,29 +181,36 @@
- 	    XNextEvent(display, &event);
- 	    if (event.type == ClientMessage && event.xclient.message_type == control_atom) {
- 	        i = (int)event.xclient.data.l[1];
--	        if (i >= 0 && i < 9) {
-+	        if (i >= 0 && i < num_workspaces) {
- 	            if (event.xclient.data.l[0] == cmd_workspace && i != current_workspace) {
- 	                track_windows(display, root_window);
- 	                current_workspace = i;
- 	                show_workspace(display, root_window);
-+	                set_cardinal(display, root_window, net_current_desktop,
-+	                    (unsigned long)current_workspace);
-+	                ewmh_sync(display, root_window);
- 	            } else if (event.xclient.data.l[0] == cmd_move) {
- 	                XGetInputFocus(display, &focused_window, &j);
- 	                if (!is_root_child(display, root_window, focused_window))
- 	                    continue;
-+	                set_window(display, root_window, net_active_window, focused_window);
- 	                j = get_window_index(focused_window);
- 	                if (j >= 0) {
- 	                    window_workspace[j] = i;
- 	                    if (i != current_workspace)
- 	                        XUnmapWindow(display, focused_window);
-+	                    ewmh_sync(display, root_window);
- 	                }
- 	            }
- 	        }
- 	    } else if (event.type == ButtonPress && event.xbutton.subwindow != None) {
- 	        drag_window = event.xbutton.subwindow;
-+	        set_window(display, root_window, net_active_window, drag_window);
- 	        XSetInputFocus(display, drag_window, RevertToPointerRoot, CurrentTime);
- 	        j = get_window_index(drag_window);
- 	        if (j >= 0)
- 	            window_workspace[j] = current_workspace;
-+	        ewmh_sync(display, root_window);
- 	        XGrabPointer(display, drag_window, True,
- 	            PointerMotionMask | ButtonReleaseMask,
- 	            GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
diff --git a/wm.c b/wm.c
index 1348f96..8148249 100644
--- a/wm.c
+++ b/wm.c
@@ -1,10 +1,12 @@
 #include <X11/Xlib.h>
+#include "extras/ewmh/ewmh.h"
 
 #define max_val(a, b) ((a) > (b) ? (a) : (b))
 #define mod_key Mod1Mask
 #define max_windows 4096
 #define cmd_workspace 1
 #define cmd_move 2
+#define num_workspaces 9
 
 static Window windows[max_windows];
 static int window_workspace[max_windows], window_count, current_workspace;
@@ -97,6 +99,8 @@ main(void)
 	control_atom = XInternAtom(display, "_WM_CTL", False);
 	XSelectInput(display, root_window, SubstructureNotifyMask);
 	track_windows(display, root_window);
+	ewmh_init(display, root_window);
+	ewmh_sync(display, root_window, windows, window_workspace, window_count);
 
 	XGrabButton(display, 1, mod_key, root_window, True, ButtonPressMask, GrabModeAsync,
 	    GrabModeAsync, None, None);
@@ -107,29 +111,35 @@ main(void)
 	    XNextEvent(display, &event);
 	    if (event.type == ClientMessage && event.xclient.message_type == control_atom) {
 	        i = (int)event.xclient.data.l[1];
-	        if (i >= 0 && i < 9) {
+	        if (i >= 0 && i < num_workspaces) {
 	            if (event.xclient.data.l[0] == cmd_workspace && i != current_workspace) {
 	                track_windows(display, root_window);
 	                current_workspace = i;
 	                show_workspace(display, root_window);
+	                ewmh_set_current_desktop(display, root_window, current_workspace);
+	                ewmh_sync(display, root_window, windows, window_workspace, window_count);
 	            } else if (event.xclient.data.l[0] == cmd_move) {
 	                XGetInputFocus(display, &focused_window, &j);
 	                if (!is_root_child(display, root_window, focused_window))
 	                    continue;
+	                ewmh_set_active_window(display, root_window, focused_window);
 	                j = get_window_index(focused_window);
 	                if (j >= 0) {
 	                    window_workspace[j] = i;
 	                    if (i != current_workspace)
 	                        XUnmapWindow(display, focused_window);
+	                    ewmh_sync(display, root_window, windows, window_workspace, window_count);
 	                }
 	            }
 	        }
 	    } else if (event.type == ButtonPress && event.xbutton.subwindow != None) {
 	        drag_window = event.xbutton.subwindow;
+	        ewmh_set_active_window(display, root_window, drag_window);
 	        XSetInputFocus(display, drag_window, RevertToPointerRoot, CurrentTime);
 	        j = get_window_index(drag_window);
 	        if (j >= 0)
 	            window_workspace[j] = current_workspace;
+	        ewmh_sync(display, root_window, windows, window_workspace, window_count);
 	        XGrabPointer(display, drag_window, True,
 	            PointerMotionMask | ButtonReleaseMask,
 	            GrabModeAsync, GrabModeAsync, None, None, CurrentTime);