-
Notifications
You must be signed in to change notification settings - Fork 1
/
dwm-fullscreen-compilation-6.2.diff
393 lines (376 loc) · 13 KB
/
dwm-fullscreen-compilation-6.2.diff
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
From b50a85db1f4f6208042c433c5c702f0f18569d13 Mon Sep 17 00:00:00 2001
From: bakkeby <bakkeby@gmail.com>
Date: Sat, 5 Sep 2020 14:32:26 +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 | 4 +-
dwm.c | 164 ++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 134 insertions(+), 34 deletions(-)
diff --git a/config.def.h b/config.def.h
index 1c0b587..5f28f2c 100644
--- a/config.def.h
+++ b/config.def.h
@@ -74,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 4465af1..5352547 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;
@@ -210,10 +211,12 @@ 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);
+static void unfocus(Client *c, int setfocus, Client *nextfocus);
static void unmanage(Client *c, int destroyed);
static void unmapnotify(XEvent *e);
static void updatebarpos(Monitor *m);
@@ -425,7 +428,7 @@ buttonpress(XEvent *e)
click = ClkRootWin;
/* focus monitor if necessary */
if ((m = wintomon(ev->window)) && m != selmon) {
- unfocus(selmon->sel, 1);
+ unfocus(selmon->sel, 1, NULL);
selmon = m;
focus(NULL);
}
@@ -519,9 +522,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);
@@ -565,7 +571,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);
}
@@ -754,7 +760,7 @@ drawbars(void)
void
enternotify(XEvent *e)
{
- Client *c;
+ Client *c, *sel;
Monitor *m;
XCrossingEvent *ev = &e->xcrossing;
@@ -763,8 +769,9 @@ enternotify(XEvent *e)
c = wintoclient(ev->window);
m = c ? c->mon : wintomon(ev->window);
if (m != selmon) {
- unfocus(selmon->sel, 1);
+ sel = selmon->sel;
selmon = m;
+ unfocus(sel, 1, c);
} else if (!c || c == selmon->sel)
return;
focus(c);
@@ -786,7 +793,7 @@ focus(Client *c)
if (!c || !ISVISIBLE(c))
for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
if (selmon->sel && selmon->sel != c)
- unfocus(selmon->sel, 0);
+ unfocus(selmon->sel, 0, c);
if (c) {
if (c->mon != selmon)
selmon = c->mon;
@@ -819,13 +826,15 @@ void
focusmon(const Arg *arg)
{
Monitor *m;
+ Client *sel;
if (!mons->next)
return;
if ((m = dirtomon(arg->i)) == selmon)
return;
- unfocus(selmon->sel, 0);
+ sel = selmon->sel;
selmon = m;
+ unfocus(sel, 0, NULL);
focus(NULL);
}
@@ -1069,7 +1078,7 @@ manage(Window w, XWindowAttributes *wa)
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)
- unfocus(selmon->sel, 0);
+ unfocus(selmon->sel, 0, c);
c->mon->sel = c;
arrange(c->mon);
XMapWindow(dpy, c->win);
@@ -1120,13 +1129,15 @@ motionnotify(XEvent *e)
{
static Monitor *mon = NULL;
Monitor *m;
+ Client *sel;
XMotionEvent *ev = &e->xmotion;
if (ev->window != root)
return;
if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
- unfocus(selmon->sel, 1);
+ sel = selmon->sel;
selmon = m;
+ unfocus(sel, 1, NULL);
focus(NULL);
}
mon = m;
@@ -1143,7 +1154,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;
@@ -1284,7 +1295,15 @@ resizeclient(Client *c, int x, int y, int w, int h)
wc.border_width = c->bw;
XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
configure(c);
- XSync(dpy, False);
+ if (c->fakefullscreen == 1)
+ /* Exception: if the client was in actual fullscreen and we exit out to fake fullscreen
+ * mode, then the focus would drift to whichever window is under the mouse cursor at the
+ * time. To avoid this we pass True to XSync which will make the X server disregard any
+ * other events in the queue thus cancelling the EnterNotify event that would otherwise
+ * have changed focus. */
+ XSync(dpy, True);
+ else
+ XSync(dpy, False);
}
void
@@ -1298,7 +1317,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;
@@ -1412,7 +1431,7 @@ sendmon(Client *c, Monitor *m)
{
if (c->mon == m)
return;
- unfocus(c, 1);
+ unfocus(c, 1, NULL);
detach(c);
detachstack(c);
c->mon = m;
@@ -1472,28 +1491,61 @@ 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);
+ int savestate = 0, restorestate = 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) {
+ c->fakefullscreen = 1;
c->isfullscreen = 1;
- c->oldstate = c->isfloating;
+ fullscreen = 1;
+ } else if (c->fakefullscreen == 3) // client exiting actual fullscreen
+ c->fakefullscreen = 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->isfloating = c->oldstate = c->oldstate & 1;
c->x = c->oldx;
c->y = c->oldy;
c->w = c->oldw;
c->h = c->oldh;
resizeclient(c, c->x, c->y, c->w, c->h);
- arrange(c->mon);
+ restack(c->mon);
}
}
@@ -1665,9 +1717,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
@@ -1705,18 +1767,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;
+ c->isfloating = !c->isfloating || c->isfixed;
if (selmon->sel->isfloating)
- resize(selmon->sel, selmon->sel->x, selmon->sel->y,
- selmon->sel->w, selmon->sel->h, 0);
- arrange(selmon);
+ 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
@@ -1747,10 +1842,13 @@ toggleview(const Arg *arg)
}
void
-unfocus(Client *c, int setfocus)
+unfocus(Client *c, int setfocus, Client *nextfocus)
{
if (!c)
return;
+ if (c->isfullscreen && ISVISIBLE(c) && c->mon == selmon && nextfocus && !nextfocus->isfloating)
+ if (c->fakefullscreen != 1)
+ setfullscreen(c, 0);
grabbuttons(c, 0);
XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
if (setfocus) {
--
2.19.1