From a8f92b4e5b78b1d3999239ecc4a19da142b3ab81 Mon Sep 17 00:00:00 2001 From: Lucas de Sena Date: Sat, 10 Jan 2026 02:58:39 +0000 Subject: [PATCH] Make fullscreen work on GTK applications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit implements the _NET_SUPPORTING_WM_CHECK property, defined by the EWMH[1] (Extended Window Management Hints, aka wm-spec), which indicates that a EWMH-compliant window manager is running. A GTK application, when set to go fullscreen, first checks root window's _NET_SUPPORTING_WM_CHECK property to determine whether a EWMH-compliant window manager is running; and then checks the _NET_SUPPORTED property to determine the supported protocols. _NET_SUPPORTED was previously implemented, but _NET_SUPPORTING_WM_CHECK was not. This commit also fixes a misconception of the code related to screens. The code deals with two different, unrelated concepts of screens: the X11 screen, and the AmiWM screen. The X11 screen, created by the X server independently of whether a window manager is running, is a kind of “subdisplay”. A X11 display structure, which describes a connection to the X server, has one or more screens. Each X11 screen has its own root window and its own set of clients that are specific to it, and cannot move to another X11 screen. The user can even run two different window managers at the same time in the same display, given that each is run in a different X11 screen. Usually, there is only one X11 screen. The _NET_SUPPORTING_WM_CHECK and _NET_SUPPORTED properties must be set on the root window of each screen that AmiWM is managing. Previously, however, they were set everytime an AmiWM screen (a totally different concept) was realized. So, if i had 4 AmiWM screens configured in my ~/.amiwmrc file, setsupports() were called four times, even if i only have a single X11 screen. [1]: https://specifications.freedesktop.org/wm/latest/index.html --- icc.c | 17 ++++++++++++++--- icc.h | 2 +- main.c | 19 +++++++++++++++---- screen.c | 1 - 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/icc.c b/icc.c index bfa78d7..aeb739e 100644 --- a/icc.c +++ b/icc.c @@ -16,15 +16,17 @@ extern struct Library *XLibBase; extern void redraw(Client *, Window); +Atom utf8_string, net_wm_name; Atom wm_state, wm_change_state, wm_protocols, wm_delete, wm_take_focus; Atom wm_colormaps, wm_name, wm_normal_hints, wm_hints, wm_icon_name, wm_class; -Atom net_supported, net_wm_state, net_wm_state_fullscreen; +Atom net_supporting_wm_check, net_supported, net_wm_state, net_wm_state_fullscreen; Atom amiwm_screen, swm_vroot, amiwm_wflags, amiwm_appiconmsg, amiwm_appwindowmsg; extern Display *dpy; void init_atoms() { + utf8_string = XInternAtom(dpy, "UTF8_STRING", False); wm_state = XInternAtom(dpy, "WM_STATE", False); wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False); wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False); @@ -37,6 +39,8 @@ void init_atoms() wm_icon_name = XInternAtom(dpy, "WM_ICON_NAME", False); wm_class = XInternAtom(dpy, "WM_CLASS", False); net_supported = XInternAtom(dpy, "_NET_SUPPORTED", False); + net_supporting_wm_check = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False); + net_wm_name = XInternAtom(dpy, "_NET_WM_NAME", False); net_wm_state = XInternAtom(dpy, "_NET_WM_STATE", False); net_wm_state_fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); amiwm_screen = XInternAtom(dpy, "AMIWM_SCREEN", False); @@ -46,14 +50,21 @@ void init_atoms() amiwm_appwindowmsg = XInternAtom(dpy, "AMIWM_APPWINDOWMSG", False); } -void setsupports(Window root) +void setsupports(Window root, Window checkwin) { Atom atoms[] = { - net_wm_state_fullscreen + net_wm_state, + net_wm_state_fullscreen, }; XChangeProperty(dpy, root, net_supported, XA_ATOM, 32, PropModeReplace, (unsigned char *)atoms, sizeof(atoms)/sizeof(atoms[0])); + XChangeProperty(dpy, root, net_supporting_wm_check, XA_WINDOW, 32, + PropModeReplace, (void *)(Window[]){checkwin}, 1); + XChangeProperty(dpy, checkwin, net_supporting_wm_check, XA_WINDOW, 32, + PropModeReplace, (void *)(Window[]){checkwin}, 1); + XChangeProperty(dpy, checkwin, net_wm_name, utf8_string, 8, + PropModeReplace, (void *)"AmiWM", 5); } void setstringprop(Window w, Atom a, char *str) diff --git a/icc.h b/icc.h index ee507d8..227e4dc 100644 --- a/icc.h +++ b/icc.h @@ -6,7 +6,7 @@ #include "client.h" extern void init_atoms(void); -extern void setsupports(Window); +extern void setsupports(Window, Window); extern void sendcmessage(Window, Atom, long); extern void getproto(Client *c); extern void getwmstate(Client *c); diff --git a/main.c b/main.c index 77557cb..4777704 100644 --- a/main.c +++ b/main.c @@ -91,6 +91,7 @@ Scrn *dragscreen=NULL, *menuactive=NULL; static int d_offset=0; static fd_set master_fd_set; static int max_fd=0; +static Window *checkwins; char *free_screentitle=NULL; char *x_server=NULL; int shape_event_base, shape_error_base, shape_extn=0; @@ -857,11 +858,15 @@ static void update_clock(void *dontcare) void cleanup() { + int sc; extern void free_prefs(); struct coevent *e; flushmodules(); flushclients(); scr = get_front_scr(); + for(sc=0; checkwins!=NULL && scroot, checkwins[sc]); + if(!getscreenbyroot(root)) { char buf[64]; sprintf(buf, "Screen.%d", sc); - openscreen((sc? strdup(buf):"Workbench Screen"), RootWindow(dpy, sc)); + openscreen((sc? strdup(buf):"Workbench Screen"), root); } + } + } /* if(!front) openscreen("Workbench Screen", DefaultRootWindow(dpy)); diff --git a/screen.c b/screen.c index 60aefe0..ed02570 100644 --- a/screen.c +++ b/screen.c @@ -350,7 +350,6 @@ void realizescreens(void) XMapWindow(dpy, scr->inputbox); } - setsupports(scr->root); XSelectInput(dpy, scr->root, SubstructureNotifyMask|SubstructureRedirectMask| KeyPressMask|KeyReleaseMask|