remove games/actualfullscreenpatch use fullscreen compilation and add ewmhtags

This commit is contained in:
2026-07-02 22:42:48 +02:00
parent 5accaed254
commit 3f2aa9d37f
13 changed files with 760 additions and 824 deletions

View File

@@ -0,0 +1,161 @@
From e5f0eefa921e6bad1e6f75faced0c3ae519995b3 Mon Sep 17 00:00:00 2001
From: Ryan Kes <alrayyes@gmail.com>
Date: Thu, 28 Mar 2019 14:49:28 +0100
Subject: [PATCH] dwm-ewhmtags-6.2
---
dwm.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 48 insertions(+), 1 deletion(-)
diff --git a/dwm.c b/dwm.c
index 4465af1..92022a1 100644
--- a/dwm.c
+++ b/dwm.c
@@ -55,6 +55,7 @@
#define WIDTH(X) ((X)->w + 2 * (X)->bw)
#define HEIGHT(X) ((X)->h + 2 * (X)->bw)
#define TAGMASK ((1 << LENGTH(tags)) - 1)
+#define TAGSLENGTH (LENGTH(tags))
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
/* enums */
@@ -62,7 +63,7 @@ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
enum { SchemeNorm, SchemeSel }; /* color schemes */
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
- NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
+ NetWMWindowTypeDialog, NetClientList, NetDesktopNames, NetDesktopViewport, NetNumberOfDesktops, NetCurrentDesktop, NetLast }; /* EWMH atoms */
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
@@ -197,11 +198,15 @@ static void scan(void);
static int sendevent(Client *c, Atom proto);
static void sendmon(Client *c, Monitor *m);
static void setclientstate(Client *c, long state);
+static void setcurrentdesktop(void);
+static void setdesktopnames(void);
static void setfocus(Client *c);
static void setfullscreen(Client *c, int fullscreen);
static void setlayout(const Arg *arg);
static void setmfact(const Arg *arg);
+static void setnumdesktops(void);
static void setup(void);
+static void setviewport(void);
static void seturgent(Client *c, int urg);
static void showhide(Client *c);
static void sigchld(int unused);
@@ -216,6 +221,7 @@ static void toggleview(const Arg *arg);
static void unfocus(Client *c, int setfocus);
static void unmanage(Client *c, int destroyed);
static void unmapnotify(XEvent *e);
+static void updatecurrentdesktop(void);
static void updatebarpos(Monitor *m);
static void updatebars(void);
static void updateclientlist(void);
@@ -1431,6 +1437,16 @@ setclientstate(Client *c, long state)
XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
PropModeReplace, (unsigned char *)data, 2);
}
+void
+setcurrentdesktop(void){
+ long data[] = { 0 };
+ XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
+}
+void setdesktopnames(void){
+ XTextProperty text;
+ Xutf8TextListToTextProperty(dpy, tags, TAGSLENGTH, XUTF8StringStyle, &text);
+ XSetTextProperty(dpy, root, &text, netatom[NetDesktopNames]);
+}
int
sendevent(Client *c, Atom proto)
@@ -1457,6 +1473,12 @@ sendevent(Client *c, Atom proto)
return exists;
}
+void
+setnumdesktops(void){
+ long data[] = { TAGSLENGTH };
+ XChangeProperty(dpy, root, netatom[NetNumberOfDesktops], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
+}
+
void
setfocus(Client *c)
{
@@ -1562,6 +1584,10 @@ setup(void)
netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
+ netatom[NetDesktopViewport] = XInternAtom(dpy, "_NET_DESKTOP_VIEWPORT", False);
+ netatom[NetNumberOfDesktops] = XInternAtom(dpy, "_NET_NUMBER_OF_DESKTOPS", False);
+ netatom[NetCurrentDesktop] = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False);
+ netatom[NetDesktopNames] = XInternAtom(dpy, "_NET_DESKTOP_NAMES", False);
/* init cursors */
cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
cursor[CurResize] = drw_cur_create(drw, XC_sizing);
@@ -1584,6 +1610,10 @@ setup(void)
/* EWMH support per view */
XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
PropModeReplace, (unsigned char *) netatom, NetLast);
+ setnumdesktops();
+ setcurrentdesktop();
+ setdesktopnames();
+ setviewport();
XDeleteProperty(dpy, root, netatom[NetClientList]);
/* select events */
wa.cursor = cursor[CurNormal]->cursor;
@@ -1595,6 +1625,11 @@ setup(void)
grabkeys();
focus(NULL);
}
+void
+setviewport(void){
+ long data[] = { 0, 0 };
+ XChangeProperty(dpy, root, netatom[NetDesktopViewport], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 2);
+}
void
@@ -1732,6 +1767,7 @@ toggletag(const Arg *arg)
focus(NULL);
arrange(selmon);
}
+ updatecurrentdesktop();
}
void
@@ -1744,6 +1780,7 @@ toggleview(const Arg *arg)
focus(NULL);
arrange(selmon);
}
+ updatecurrentdesktop();
}
void
@@ -1846,6 +1883,15 @@ updateclientlist()
XA_WINDOW, 32, PropModeAppend,
(unsigned char *) &(c->win), 1);
}
+void updatecurrentdesktop(void){
+ long rawdata[] = { selmon->tagset[selmon->seltags] };
+ int i=0;
+ while(*rawdata >> i+1){
+ i++;
+ }
+ long data[] = { i };
+ XChangeProperty(dpy, root, netatom[NetCurrentDesktop], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
+}
int
updategeom(void)
@@ -2042,6 +2088,7 @@ view(const Arg *arg)
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
focus(NULL);
arrange(selmon);
+ updatecurrentdesktop();
}
Client *
--
2.21.0

View File

@@ -0,0 +1,357 @@
From 4d2fb76ca3024447fd06407bdc87c09e726f6c27 Mon Sep 17 00:00:00 2001
From: Bakkeby <bakkeby@gmail.com>
Date: Mon, 1 Jul 2024 22:14:32 +0200
Subject: [PATCH] Compilation of fullscreen patches for dwm.
This aims to provide a comprehensive fullscreen solution with the following features:
- toggle fullscreen for any window using a single keybinding rather than having
to rely on per-application keybindings
- the ability to have windows go fullscreen within the size and position the
window is currently in (fake fullscreen)
- allow a fullscreen window to be moved to an adjacent monitor while remaining
fullscreen
- make fullscreen windows lose fullscreen if another (e.g. new) window on the
same monitor receives focus, while still allowing dialog boxes to show while
in fullscreen
- allow seamless transition between the two fullscreen modes
The default keybindings are:
- MOD+f to make a window fullscreen
- MOD+Shift+f to make a window fake fullscreen
This incorporates, and expands on, the following patches:
- fakefullscreenclient
- togglefullscreen (a.k.a. actualfullscreen)
- tagmonfixfs
- losefullscreen
---
config.def.h | 5 +-
dwm.c | 176 ++++++++++++++++++++++++++++++++++++++++++---------
2 files changed, 148 insertions(+), 33 deletions(-)
diff --git a/config.def.h b/config.def.h
index a2ac963..5f28f2c 100644
--- a/config.def.h
+++ b/config.def.h
@@ -35,7 +35,6 @@ static const Rule rules[] = {
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
static const int nmaster = 1; /* number of clients in master area */
static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
-static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
static const Layout layouts[] = {
/* symbol arrange function */
@@ -75,10 +74,12 @@ static Key keys[] = {
{ MODKEY, XK_Tab, view, {0} },
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
- { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
+ { MODKEY, XK_e, setlayout, {.v = &layouts[1]} },
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
{ MODKEY, XK_space, setlayout, {0} },
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
+ { MODKEY, XK_f, togglefullscreen, {0} },
+ { MODKEY|ShiftMask, XK_f, togglefakefullscreen, {0} },
{ MODKEY, XK_0, view, {.ui = ~0 } },
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
{ MODKEY, XK_comma, focusmon, {.i = -1 } },
diff --git a/dwm.c b/dwm.c
index a96f33c..53f0bd4 100644
--- a/dwm.c
+++ b/dwm.c
@@ -93,6 +93,7 @@ struct Client {
int bw, oldbw;
unsigned int tags;
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
+ int fakefullscreen;
Client *next;
Client *snext;
Monitor *mon;
@@ -178,6 +179,7 @@ static void grabkeys(void);
static void incnmaster(const Arg *arg);
static void keypress(XEvent *e);
static void killclient(const Arg *arg);
+static void losefullscreen(Client *next);
static void manage(Window w, XWindowAttributes *wa);
static void mappingnotify(XEvent *e);
static void maprequest(XEvent *e);
@@ -211,7 +213,9 @@ static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
static void tile(Monitor *);
static void togglebar(const Arg *arg);
+static void togglefakefullscreen(const Arg *arg);
static void togglefloating(const Arg *arg);
+static void togglefullscreen(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unfocus(Client *c, int setfocus);
@@ -520,9 +524,12 @@ clientmessage(XEvent *e)
return;
if (cme->message_type == netatom[NetWMState]) {
if (cme->data.l[1] == netatom[NetWMFullscreen]
- || cme->data.l[2] == netatom[NetWMFullscreen])
+ || cme->data.l[2] == netatom[NetWMFullscreen]) {
+ if (c->fakefullscreen == 2 && c->isfullscreen)
+ c->fakefullscreen = 3;
setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD */
|| (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
+ }
} else if (cme->message_type == netatom[NetActiveWindow]) {
if (c != selmon->sel && !c->isurgent)
seturgent(c, 1);
@@ -566,7 +573,7 @@ configurenotify(XEvent *e)
updatebars();
for (m = mons; m; m = m->next) {
for (c = m->clients; c; c = c->next)
- if (c->isfullscreen)
+ if (c->isfullscreen && c->fakefullscreen != 1)
resizeclient(c, m->mx, m->my, m->mw, m->mh);
XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
}
@@ -789,8 +796,10 @@ focus(Client *c)
{
if (!c || !ISVISIBLE(c))
for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
- if (selmon->sel && selmon->sel != c)
+ if (selmon->sel && selmon->sel != c) {
+ losefullscreen(c);
unfocus(selmon->sel, 0);
+ }
if (c) {
if (c->mon != selmon)
selmon = c->mon;
@@ -838,7 +847,7 @@ focusstack(const Arg *arg)
{
Client *c = NULL, *i;
- if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen))
+ if (!selmon->sel || (selmon->sel->isfullscreen && selmon->sel->fakefullscreen != 1))
return;
if (arg->i > 0) {
for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
@@ -1018,6 +1027,16 @@ killclient(const Arg *arg)
}
}
+void
+losefullscreen(Client *next)
+{
+ Client *sel = selmon->sel;
+ if (!sel || !next)
+ return;
+ if (sel->isfullscreen && sel->fakefullscreen != 1 && ISVISIBLE(sel) && sel->mon == next->mon && !next->isfloating)
+ setfullscreen(sel, 0);
+}
+
void
manage(Window w, XWindowAttributes *wa)
{
@@ -1072,8 +1091,10 @@ manage(Window w, XWindowAttributes *wa)
(unsigned char *) &(c->win), 1);
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
setclientstate(c, NormalState);
- if (c->mon == selmon)
+ if (c->mon == selmon) {
+ losefullscreen(c);
unfocus(selmon->sel, 0);
+ }
c->mon->sel = c;
arrange(c->mon);
XMapWindow(dpy, c->win);
@@ -1147,7 +1168,7 @@ movemouse(const Arg *arg)
if (!(c = selmon->sel))
return;
- if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support moving fullscreen windows by mouse */
return;
restack(selmon);
ocx = c->x;
@@ -1302,7 +1323,7 @@ resizemouse(const Arg *arg)
if (!(c = selmon->sel))
return;
- if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support resizing fullscreen windows by mouse */
return;
restack(selmon);
ocx = c->x;
@@ -1476,29 +1497,79 @@ setfocus(Client *c)
void
setfullscreen(Client *c, int fullscreen)
{
- if (fullscreen && !c->isfullscreen) {
- XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
- PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
+ XEvent ev;
+ int savestate = 0, restorestate = 0, restorefakefullscreen = 0;
+
+ if ((c->fakefullscreen == 0 && fullscreen && !c->isfullscreen) // normal fullscreen
+ || (c->fakefullscreen == 2 && fullscreen)) // fake fullscreen --> actual fullscreen
+ savestate = 1; // go actual fullscreen
+ else if ((c->fakefullscreen == 0 && !fullscreen && c->isfullscreen) // normal fullscreen exit
+ || (c->fakefullscreen >= 2 && !fullscreen)) // fullscreen exit --> fake fullscreen
+ restorestate = 1; // go back into tiled
+
+ /* If leaving fullscreen and the window was previously fake fullscreen (2), then restore
+ * that while staying in fullscreen. The exception to this is if we are in said state, but
+ * the client itself disables fullscreen (3) then we let the client go out of fullscreen
+ * while keeping fake fullscreen enabled (as otherwise there will be a mismatch between the
+ * client and the window manager's perception of the client's fullscreen state). */
+ if (c->fakefullscreen == 2 && !fullscreen && c->isfullscreen) {
+ restorefakefullscreen = 1;
c->isfullscreen = 1;
- c->oldstate = c->isfloating;
+ fullscreen = 1;
+ }
+
+ if (fullscreen != c->isfullscreen) { // only send property change if necessary
+ if (fullscreen)
+ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
+ PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
+ else
+ XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
+ PropModeReplace, (unsigned char*)0, 0);
+ }
+
+ c->isfullscreen = fullscreen;
+
+ /* Some clients, e.g. firefox, will send a client message informing the window manager
+ * that it is going into fullscreen after receiving the above signal. This has the side
+ * effect of this function (setfullscreen) sometimes being called twice when toggling
+ * fullscreen on and off via the window manager as opposed to the application itself.
+ * To protect against obscure issues where the client settings are stored or restored
+ * when they are not supposed to we add an additional bit-lock on the old state so that
+ * settings can only be stored and restored in that precise order. */
+ if (savestate && !(c->oldstate & (1 << 1))) {
c->oldbw = c->bw;
+ c->oldstate = c->isfloating | (1 << 1);
c->bw = 0;
c->isfloating = 1;
resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
XRaiseWindow(dpy, c->win);
- } else if (!fullscreen && c->isfullscreen){
- XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
- PropModeReplace, (unsigned char*)0, 0);
- c->isfullscreen = 0;
- c->isfloating = c->oldstate;
+ } else if (restorestate && (c->oldstate & (1 << 1))) {
c->bw = c->oldbw;
- c->x = c->oldx;
- c->y = c->oldy;
- c->w = c->oldw;
- c->h = c->oldh;
+ c->isfloating = c->oldstate = c->oldstate & 1;
+ if (restorefakefullscreen || c->fakefullscreen == 3)
+ c->fakefullscreen = 1;
+ /* The client may have been moved to another monitor whilst in fullscreen which if tiled
+ * we address by doing a full arrange of tiled clients. If the client is floating then the
+ * height and width may be larger than the monitor's window area, so we cap that by
+ * ensuring max / min values. */
+ if (c->isfloating) {
+ c->x = MAX(c->mon->wx, c->oldx);
+ c->y = MAX(c->mon->wy, c->oldy);
+ c->w = MIN(c->mon->ww - c->x - 2*c->bw, c->oldw);
+ c->h = MIN(c->mon->wh - c->y - 2*c->bw, c->oldh);
+ resizeclient(c, c->x, c->y, c->w, c->h);
+ restack(c->mon);
+ } else
+ arrange(c->mon);
+ } else
resizeclient(c, c->x, c->y, c->w, c->h);
- arrange(c->mon);
- }
+
+ /* Exception: if the client was in actual fullscreen and we exit out to fake fullscreen
+ * mode, then the focus would sometimes drift to whichever window is under the mouse cursor
+ * at the time. To avoid this we ask X for all EnterNotify events and just ignore them.
+ */
+ if (!c->isfullscreen)
+ while (XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}
void
@@ -1669,9 +1740,19 @@ tag(const Arg *arg)
void
tagmon(const Arg *arg)
{
- if (!selmon->sel || !mons->next)
+ Client *c = selmon->sel;
+ if (!c || !mons->next)
return;
- sendmon(selmon->sel, dirtomon(arg->i));
+ if (c->isfullscreen) {
+ c->isfullscreen = 0;
+ sendmon(c, dirtomon(arg->i));
+ c->isfullscreen = 1;
+ if (c->fakefullscreen != 1) {
+ resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
+ XRaiseWindow(dpy, c->win);
+ }
+ } else
+ sendmon(c, dirtomon(arg->i));
}
void
@@ -1711,18 +1792,51 @@ togglebar(const Arg *arg)
arrange(selmon);
}
+void
+togglefakefullscreen(const Arg *arg)
+{
+ Client *c = selmon->sel;
+ if (!c)
+ return;
+
+ if (c->fakefullscreen != 1 && c->isfullscreen) { // exit fullscreen --> fake fullscreen
+ c->fakefullscreen = 2;
+ setfullscreen(c, 0);
+ } else if (c->fakefullscreen == 1) {
+ setfullscreen(c, 0);
+ c->fakefullscreen = 0;
+ } else {
+ c->fakefullscreen = 1;
+ setfullscreen(c, 1);
+ }
+}
+
void
togglefloating(const Arg *arg)
{
- if (!selmon->sel)
+ Client *c = selmon->sel;
+ if (!c)
return;
- if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
+ if (c->isfullscreen && c->fakefullscreen != 1) /* no support for fullscreen windows */
return;
- selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
- if (selmon->sel->isfloating)
- resize(selmon->sel, selmon->sel->x, selmon->sel->y,
- selmon->sel->w, selmon->sel->h, 0);
- arrange(selmon);
+ c->isfloating = !c->isfloating || c->isfixed;
+ if (c->isfloating)
+ resize(c, c->x, c->y, c->w, c->h, 0);
+ arrange(c->mon);
+}
+
+void
+togglefullscreen(const Arg *arg)
+{
+ Client *c = selmon->sel;
+ if (!c)
+ return;
+
+ if (c->fakefullscreen == 1) { // fake fullscreen --> fullscreen
+ c->fakefullscreen = 2;
+ setfullscreen(c, 1);
+ } else
+ setfullscreen(c, !c->isfullscreen);
}
void
--
2.45.2

View File

@@ -1,173 +0,0 @@
From d06cefd6e1f8b5cd9bdfe694b7dc16da1f00d83e Mon Sep 17 00:00:00 2001
From: Bakkeby <bakkeby@gmail.com>
Date: Mon, 1 Jul 2024 22:19:15 +0200
Subject: [PATCH] Game rule patch
This patch adds a rule identifying clients as a "game" such that
if the client is in fullscreen and it loses focus (e.g. by moving
to another tag) then it will automatically be minimized (set to
IconicState and unmapped).
When the client receives focus again (e.g. by going back to its
tag) then it will automaticaly be unminimized (set to NormalState
and mapped). This should address many of the black screen or window
is tiny after having moved to another tag and back again.
This may conflict with the awesomebar patch which skips hidden
(iconic) windows when selecting which client to focus on, i.e. it
would be there but minimized and will not automatically unminimize.
The function names are minimize and unminimize compared to the same
functions hide and show in the awesomebar patch. The name change is
due to two reasons; 1) because hide and show do something very
different compared to the showhide function and 2) because when
minimizing and unminimizing we do not want to trigger arrange or
a change in focus (which would affect the stacking order and thus
prevent the window receiving focus when we move back to the previous
tag).
---
config.def.h | 4 +++-
dwm.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 50 insertions(+), 1 deletion(-)
diff --git a/config.def.h b/config.def.h
index 9efa774..9df3c97 100644
--- a/config.def.h
+++ b/config.def.h
@@ -26,9 +26,11 @@ static const Rule rules[] = {
* WM_CLASS(STRING) = instance, class
* WM_NAME(STRING) = title
*/
- /* class instance title tags mask isfloating monitor */
+ /* class instance title tags mask isfloating monitor isgame */
{ "Gimp", NULL, NULL, 0, 1, -1 },
{ "Firefox", NULL, NULL, 1 << 8, 0, -1 },
+ { "Steam", NULL, NULL, 0, 0, -1, 1 },
+ { "steam_app",NULL, NULL, 0, 0, -1, 1 },
};
/* layout(s) */
diff --git a/dwm.c b/dwm.c
index 1443802..29de39a 100644
--- a/dwm.c
+++ b/dwm.c
@@ -50,6 +50,7 @@
#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
* MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
+#define MINIMIZED(C) ((getstate(C->win) == IconicState))
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
#define WIDTH(X) ((X)->w + 2 * (X)->bw)
#define HEIGHT(X) ((X)->h + 2 * (X)->bw)
@@ -92,6 +93,7 @@ struct Client {
int bw, oldbw;
unsigned int tags;
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
+ int isgame;
Client *next;
Client *snext;
Monitor *mon;
@@ -138,6 +140,7 @@ typedef struct {
unsigned int tags;
int isfloating;
int monitor;
+ int isgame;
} Rule;
/* function declarations */
@@ -180,6 +183,7 @@ static void killclient(const Arg *arg);
static void manage(Window w, XWindowAttributes *wa);
static void mappingnotify(XEvent *e);
static void maprequest(XEvent *e);
+static void minimize(Client *c);
static void monocle(Monitor *m);
static void motionnotify(XEvent *e);
static void movemouse(const Arg *arg);
@@ -215,6 +219,7 @@ static void toggleview(const Arg *arg);
static void unfocus(Client *c, int setfocus);
static void unmanage(Client *c, int destroyed);
static void unmapnotify(XEvent *e);
+static void unminimize(Client *c);
static void updatebarpos(Monitor *m);
static void updatebars(void);
static void updateclientlist(void);
@@ -298,6 +303,7 @@ applyrules(Client *c)
{
c->isfloating = r->isfloating;
c->tags |= r->tags;
+ c->isgame = r->isgame;
for (m = mons; m && m->num != r->monitor; m = m->next);
if (m)
c->mon = m;
@@ -1109,6 +1115,29 @@ maprequest(XEvent *e)
manage(ev->window, &wa);
}
+void
+minimize(Client *c)
+{
+ if (!c || MINIMIZED(c))
+ return;
+
+ Window w = c->win;
+ static XWindowAttributes ra, ca;
+
+ // more or less taken directly from blackbox's hide() function
+ XGrabServer(dpy);
+ XGetWindowAttributes(dpy, root, &ra);
+ XGetWindowAttributes(dpy, w, &ca);
+ // prevent UnmapNotify events
+ XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask);
+ XSelectInput(dpy, w, ca.your_event_mask & ~StructureNotifyMask);
+ XUnmapWindow(dpy, w);
+ setclientstate(c, IconicState);
+ XSelectInput(dpy, root, ra.your_event_mask);
+ XSelectInput(dpy, w, ca.your_event_mask);
+ XUngrabServer(dpy);
+}
+
void
monocle(Monitor *m)
{
@@ -1475,6 +1504,10 @@ setfocus(Client *c)
XA_WINDOW, 32, PropModeReplace,
(unsigned char *) &(c->win), 1);
}
+
+ if (c->isgame && c->isfullscreen)
+ unminimize(c);
+
sendevent(c, wmatom[WMTakeFocus]);
}
@@ -1766,6 +1799,10 @@ unfocus(Client *c, int setfocus)
{
if (!c)
return;
+
+ if (c->isgame && c->isfullscreen)
+ minimize(c);
+
grabbuttons(c, 0);
XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
if (setfocus) {
@@ -1814,6 +1851,16 @@ unmapnotify(XEvent *e)
}
}
+void
+unminimize(Client *c)
+{
+ if (!c || !MINIMIZED(c))
+ return;
+
+ XMapWindow(dpy, c->win);
+ setclientstate(c, NormalState);
+}
+
void
updatebars(void)
{
--
2.50.1