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);