-
Notifications
You must be signed in to change notification settings - Fork 30
/
dwm-renamedscratchpads-6.3.diff
357 lines (344 loc) · 12.2 KB
/
dwm-renamedscratchpads-6.3.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
From 278aab272d35cc26403901829fdaaf22f49747e5 Mon Sep 17 00:00:00 2001
From: Bakkeby <[email protected]>
Date: Fri, 28 Jun 2024 08:26:06 +0200
Subject: [PATCH] Named scratchpad variant
---
config.def.h | 17 ++++-
dwm.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 186 insertions(+), 6 deletions(-)
diff --git a/config.def.h b/config.def.h
index a2ac963..049b29f 100644
--- a/config.def.h
+++ b/config.def.h
@@ -12,10 +12,14 @@ static const char col_gray2[] = "#444444";
static const char col_gray3[] = "#bbbbbb";
static const char col_gray4[] = "#eeeeee";
static const char col_cyan[] = "#005577";
+static const char col_red[] = "#FF0000";
+static const char col_orange[] = "#FF8800";
static const char *colors[][3] = {
/* fg bg border */
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
+ [SchemeScratchSel] = { col_gray4, col_cyan, col_red },
+ [SchemeScratchNorm] = { col_gray4, col_cyan, col_orange },
};
/* tagging */
@@ -26,9 +30,10 @@ static const Rule rules[] = {
* WM_CLASS(STRING) = instance, class
* WM_NAME(STRING) = title
*/
- /* class instance title tags mask isfloating monitor */
- { "Gimp", NULL, NULL, 0, 1, -1 },
- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
+ /* class instance title tags mask isfloating monitor scratch key */
+ { "Gimp", NULL, NULL, 0, 1, -1, 0 },
+ { "firefox", NULL, NULL, 1 << 8, 0, -1, 0 },
+ { NULL, NULL, "scratchpad", 0, 1, -1, 's' },
};
/* layout(s) */
@@ -60,10 +65,16 @@ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn()
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
static const char *termcmd[] = { "st", NULL };
+/*First arg only serves to match against key in rules*/
+static const char *scratchpadcmd[] = {"s", "st", "-t", "scratchpad", NULL};
+
static Key keys[] = {
/* modifier key function argument */
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
+ { MODKEY, XK_g, togglescratch, {.v = scratchpadcmd } },
+ { MODKEY|ShiftMask, XK_g, removescratch, {.v = scratchpadcmd } },
+ { MODKEY|ControlMask, XK_g, setscratch, {.v = scratchpadcmd } },
{ MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_j, focusstack, {.i = +1 } },
{ MODKEY, XK_k, focusstack, {.i = -1 } },
diff --git a/dwm.c b/dwm.c
index a96f33c..c58c6ed 100644
--- a/dwm.c
+++ b/dwm.c
@@ -59,7 +59,7 @@
/* enums */
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
-enum { SchemeNorm, SchemeSel }; /* color schemes */
+enum { SchemeNorm, SchemeSel, SchemeScratchNorm, SchemeScratchSel }; /* color schemes */
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
@@ -93,6 +93,7 @@ struct Client {
int bw, oldbw;
unsigned int tags;
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
+ char scratchkey;
Client *next;
Client *snext;
Monitor *mon;
@@ -139,6 +140,7 @@ typedef struct {
unsigned int tags;
int isfloating;
int monitor;
+ const char scratchkey;
} Rule;
/* function declarations */
@@ -189,6 +191,7 @@ static void pop(Client *);
static void propertynotify(XEvent *e);
static void quit(const Arg *arg);
static Monitor *recttomon(int x, int y, int w, int h);
+static void removescratch(const Arg *arg);
static void resize(Client *c, int x, int y, int w, int h, int interact);
static void resizeclient(Client *c, int x, int y, int w, int h);
static void resizemouse(const Arg *arg);
@@ -202,16 +205,19 @@ 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 setscratch(const Arg *arg);
static void setup(void);
static void seturgent(Client *c, int urg);
static void showhide(Client *c);
static void sigchld(int unused);
static void spawn(const Arg *arg);
+static void spawnscratch(const Arg *arg);
static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
static void tile(Monitor *);
static void togglebar(const Arg *arg);
static void togglefloating(const Arg *arg);
+static void togglescratch(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unfocus(Client *c, int setfocus);
@@ -288,6 +294,7 @@ applyrules(Client *c)
/* rule matching */
c->isfloating = 0;
c->tags = 0;
+ c->scratchkey = 0;
XGetClassHint(dpy, c->win, &ch);
class = ch.res_class ? ch.res_class : broken;
instance = ch.res_name ? ch.res_name : broken;
@@ -300,6 +307,7 @@ applyrules(Client *c)
{
c->isfloating = r->isfloating;
c->tags |= r->tags;
+ c->scratchkey = r->scratchkey;
for (m = mons; m && m->num != r->monitor; m = m->next);
if (m)
c->mon = m;
@@ -309,6 +317,7 @@ applyrules(Client *c)
XFree(ch.res_class);
if (ch.res_name)
XFree(ch.res_name);
+
c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
}
@@ -799,7 +808,10 @@ focus(Client *c)
detachstack(c);
attachstack(c);
grabbuttons(c, 1);
- XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
+ if (c->scratchkey != 0)
+ XSetWindowBorder(dpy, c->win, scheme[SchemeScratchSel][ColBorder].pixel);
+ else
+ XSetWindowBorder(dpy, c->win, scheme[SchemeSel][ColBorder].pixel);
setfocus(c);
} else {
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
@@ -1269,6 +1281,15 @@ recttomon(int x, int y, int w, int h)
return r;
}
+void
+removescratch(const Arg *arg)
+{
+ Client *c = selmon->sel;
+ if (!c)
+ return;
+ c->scratchkey = 0;
+}
+
void
resize(Client *c, int x, int y, int w, int h, int interact)
{
@@ -1530,6 +1551,16 @@ setmfact(const Arg *arg)
arrange(selmon);
}
+void
+setscratch(const Arg *arg)
+{
+ Client *c = selmon->sel;
+ if (!c)
+ return;
+
+ c->scratchkey = ((char**)arg->v)[0][0];
+}
+
void
setup(void)
{
@@ -1626,6 +1657,9 @@ showhide(Client *c)
resize(c, c->x, c->y, c->w, c->h, 0);
showhide(c->snext);
} else {
+ /* optional: auto-hide scratchpads when moving to other tags */
+ if (c->scratchkey != 0 && !(c->tags & c->mon->tagset[c->mon->seltags]))
+ c->tags = 0;
/* hide clients bottom up */
showhide(c->snext);
XMoveWindow(dpy, c->win, WIDTH(c) * -2, c->y);
@@ -1656,6 +1690,19 @@ spawn(const Arg *arg)
}
}
+void spawnscratch(const Arg *arg)
+{
+ if (fork() == 0) {
+ if (dpy)
+ close(ConnectionNumber(dpy));
+ setsid();
+ execvp(((char **)arg->v)[1], ((char **)arg->v)+1);
+ fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[1]);
+ perror(" failed");
+ exit(EXIT_SUCCESS);
+ }
+}
+
void
tag(const Arg *arg)
{
@@ -1725,6 +1772,125 @@ togglefloating(const Arg *arg)
arrange(selmon);
}
+void
+togglescratch(const Arg *arg)
+{
+ Client *c, *next, *last = NULL, *found = NULL, *monclients = NULL;
+ Monitor *mon;
+ int scratchvisible = 0; // whether the scratchpads are currently visible or not
+ int multimonscratch = 0; // whether we have scratchpads that are placed on multiple monitors
+ int scratchmon = -1; // the monitor where the scratchpads exist
+ int numscratchpads = 0; // count of scratchpads
+
+ /* Looping through monitors and client's twice, the first time to work out whether we need
+ to move clients across from one monitor to another or not */
+ for (mon = mons; mon; mon = mon->next)
+ for (c = mon->clients; c; c = c->next) {
+ if (c->scratchkey != ((char**)arg->v)[0][0])
+ continue;
+ if (scratchmon != -1 && scratchmon != mon->num)
+ multimonscratch = 1;
+ if (c->mon->tagset[c->mon->seltags] & c->tags) // && !HIDDEN(c)
+ ++scratchvisible;
+ scratchmon = mon->num;
+ ++numscratchpads;
+ }
+
+ /* Now for the real deal. The logic should go like:
+ - hidden scratchpads will be shown
+ - shown scratchpads will be hidden, unless they are being moved to the current monitor
+ - the scratchpads will be moved to the current monitor if they all reside on the same monitor
+ - multiple scratchpads residing on separate monitors will be left in place
+ */
+ for (mon = mons; mon; mon = mon->next) {
+ for (c = mon->stack; c; c = next) {
+ next = c->snext;
+ if (c->scratchkey != ((char**)arg->v)[0][0])
+ continue;
+
+ /* awesomebar / wintitleactions compatibility, unhide scratchpad if hidden
+ if (HIDDEN(c)) {
+ XMapWindow(dpy, c->win);
+ setclientstate(c, NormalState);
+ }
+ */
+
+ /* Record the first found scratchpad client for focus purposes, but prioritise the
+ scratchpad on the current monitor if one exists */
+ if (!found || (mon == selmon && found->mon != selmon))
+ found = c;
+
+ /* If scratchpad clients reside on another monitor and we are moving them across then
+ as we are looping through monitors we could be moving a client to a monitor that has
+ not been processed yet, hence we could be processing a scratchpad twice. To avoid
+ this we detach them and add them to a temporary list (monclients) which is to be
+ processed later. */
+ if (!multimonscratch && c->mon != selmon) {
+ detach(c);
+ detachstack(c);
+ c->next = NULL;
+ /* Note that we are adding clients at the end of the list, this is to preserve the
+ order of clients as they were on the adjacent monitor (relevant when tiled) */
+ if (last)
+ last = last->next = c;
+ else
+ last = monclients = c;
+ } else if (scratchvisible == numscratchpads) {
+ c->tags = 0;
+ } else {
+ XSetWindowBorder(dpy, c->win, scheme[SchemeScratchNorm][ColBorder].pixel);
+ c->tags = c->mon->tagset[c->mon->seltags];
+ if (c->isfloating)
+ XRaiseWindow(dpy, c->win);
+ }
+ }
+ }
+
+ /* Attach moved scratchpad clients on the selected monitor */
+ for (c = monclients; c; c = next) {
+ next = c->next;
+ mon = c->mon;
+ c->mon = selmon;
+ c->tags = selmon->tagset[selmon->seltags];
+ /* Attach scratchpad clients from other monitors at the bottom of the stack */
+ if (selmon->clients) {
+ for (last = selmon->clients; last && last->next; last = last->next);
+ last->next = c;
+ } else
+ selmon->clients = c;
+ c->next = NULL;
+ attachstack(c);
+
+ /* Center floating scratchpad windows when moved from one monitor to another */
+ if (c->isfloating) {
+ if (c->w > selmon->ww)
+ c->w = selmon->ww - c->bw * 2;
+ if (c->h > selmon->wh)
+ c->h = selmon->wh - c->bw * 2;
+
+ if (numscratchpads > 1) {
+ c->x = c->mon->wx + (c->x - mon->wx) * ((double)(abs(c->mon->ww - WIDTH(c))) / MAX(abs(mon->ww - WIDTH(c)), 1));
+ c->y = c->mon->wy + (c->y - mon->wy) * ((double)(abs(c->mon->wh - HEIGHT(c))) / MAX(abs(mon->wh - HEIGHT(c)), 1));
+ } else if (c->x < c->mon->mx || c->x > c->mon->mx + c->mon->mw ||
+ c->y < c->mon->my || c->y > c->mon->my + c->mon->mh) {
+ c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
+ c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
+ }
+ resizeclient(c, c->x, c->y, c->w, c->h);
+ XRaiseWindow(dpy, c->win);
+ }
+ }
+
+ if (found) {
+ focus(ISVISIBLE(found) ? found : NULL);
+ arrange(NULL);
+ if (found->isfloating)
+ XRaiseWindow(dpy, found->win);
+ } else {
+ spawnscratch(arg);
+ }
+}
+
void
toggletag(const Arg *arg)
{
@@ -1758,7 +1924,10 @@ unfocus(Client *c, int setfocus)
if (!c)
return;
grabbuttons(c, 0);
- XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
+ if (c->scratchkey != 0)
+ XSetWindowBorder(dpy, c->win, scheme[SchemeScratchNorm][ColBorder].pixel);
+ else
+ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
if (setfocus) {
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
--
2.45.2