From f45beb0d921ecc3f14f9e41ceccc05bf9f274822 Mon Sep 17 00:00:00 2001 From: Daniel Guihot Date: Wed, 16 Sep 2026 05:20:00 +1000 Subject: [PATCH] unmapfullscreen: unmap hidden fullscreen clients showhide() normally hides windows by moving them off-screen. Some games and Wine builds do not recover from that state when the tag returns. Unmap fullscreen clients when hidden and map them when shown instead. Suppress StructureNotifyMask and SubstructureNotifyMask while unmapping so dwm does not mistake its own UnmapNotify for a withdrawn client. Map before restoring input focus, and preserve normal off-screen hiding when a hidden client leaves fullscreen. --- dwm.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/dwm.c b/dwm.c index 53b393e..f1c2d9f 100644 --- a/dwm.c +++ b/dwm.c @@ -91,7 +91,8 @@ struct Client { int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid; int bw, oldbw; unsigned int tags; - int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; + int isfixed, isfloating, isurgent, neverfocus, oldstate; + int isfullscreen, isunmapped; Client *next; Client *snext; Monitor *mon; @@ -214,6 +215,7 @@ static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); static void unfocus(Client *c, int setfocus); static void unmanage(Client *c, int destroyed); +static void unmapclient(Client *c); static void unmapnotify(XEvent *e); static void updatebarpos(Monitor *m); static void updatebars(void); @@ -1084,7 +1086,8 @@ manage(Window w, XWindowAttributes *wa) unfocus(selmon->sel, 0); c->mon->sel = c; arrange(c->mon); - XMapWindow(dpy, c->win); + if (ISVISIBLE(c) || !c->isfullscreen) + XMapWindow(dpy, c->win); focus(NULL); } @@ -1490,8 +1493,11 @@ setfullscreen(Client *c, int fullscreen) c->oldbw = c->bw; c->bw = 0; c->isfloating = 1; + if (!ISVISIBLE(c)) + unmapclient(c); resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh); - XRaiseWindow(dpy, c->win); + if (ISVISIBLE(c)) + XRaiseWindow(dpy, c->win); } else if (!fullscreen && c->isfullscreen){ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32, PropModeReplace, (unsigned char*)0, 0); @@ -1634,13 +1640,27 @@ showhide(Client *c) if (ISVISIBLE(c)) { /* show clients top down */ XMoveWindow(dpy, c->win, c->x, c->y); + if (c->isunmapped) { + XMapWindow(dpy, c->win); + c->isunmapped = 0; + if (c == selmon->sel) + setfocus(c); + } if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen) resize(c, c->x, c->y, c->w, c->h, 0); showhide(c->snext); } else { /* hide clients bottom up */ showhide(c->snext); - XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y); + if (c->isfullscreen) + unmapclient(c); + else { + XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y); + if (c->isunmapped) { + XMapWindow(dpy, c->win); + c->isunmapped = 0; + } + } } } @@ -1801,6 +1821,31 @@ unmanage(Client *c, int destroyed) arrange(m); } +void +unmapclient(Client *c) +{ + XWindowAttributes ca, ra; + + XGrabServer(dpy); + if (!XGetWindowAttributes(dpy, root, &ra) + || !XGetWindowAttributes(dpy, c->win, &ca)) { + XUngrabServer(dpy); + return; + } + if (ca.map_state == IsUnmapped) { + c->isunmapped = 1; + XUngrabServer(dpy); + return; + } + XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask); + XSelectInput(dpy, c->win, ca.your_event_mask & ~StructureNotifyMask); + XUnmapWindow(dpy, c->win); + c->isunmapped = 1; + XSelectInput(dpy, root, ra.your_event_mask); + XSelectInput(dpy, c->win, ca.your_event_mask); + XUngrabServer(dpy); +} + void unmapnotify(XEvent *e) { -- 2.55.0