autolinux


Logs | Files | LICENSE | LICENSE | GitLab


1
commit a84c91b50526654f64c83bef6b9453917518e444
2
Author: Connor Etherington <[email protected]>
3
Date:   Thu Dec 22 00:48:34 2022 +0200
4
5
    Auto-Commit Update 22.12.2022 - 00:48:34
6
---
7
 AutoLinux-DWM.desktop |    6 +
8
 AutoLinux.c           | 2951 +++++++++++++++++++++++++++++++++++++++++++++++++
9
 LICENSE               |   39 +
10
 Makefile              |   49 +
11
 PKGBUILD              |   29 +
12
 config.h              |  417 +++++++
13
 config.mk             |   39 +
14
 drw.c                 |  424 +++++++
15
 drw.h                 |   57 +
16
 patch/bar_ltsymbol.c  |   17 +
17
 patch/bar_ltsymbol.h  |    3 +
18
 patch/bar_status.c    |   19 +
19
 patch/bar_status.h    |    3 +
20
 patch/bar_tags.c      |   55 +
21
 patch/bar_tags.h      |    3 +
22
 patch/bar_wintitle.c  |   31 +
23
 patch/bar_wintitle.h  |    3 +
24
 patch/include.c       |    5 +
25
 patch/include.h       |    5 +
26
 shiftview.c           |   64 ++
27
 transient.c           |   42 +
28
 util.c                |   35 +
29
 util.h                |    8 +
30
 vanitygaps.c          |  542 +++++++++
31
 24 files changed, 4846 insertions(+)
32
33
diff --git a/AutoLinux-DWM.desktop b/AutoLinux-DWM.desktop
34
new file mode 100644
35
index 0000000..7a498cc
36
--- /dev/null
37
+++ b/AutoLinux-DWM.desktop
38
@@ -0,0 +1,6 @@
39
+[Desktop Entry]
40
+Name=AutoLinux-AutoLinux
41
+Comment=Dynamic Window Manager
42
+Exec=AutoLinux
43
+Icon=AutoLinux
44
+Type=Application
45
diff --git a/AutoLinux.c b/AutoLinux.c
46
new file mode 100644
47
index 0000000..da95f4a
48
--- /dev/null
49
+++ b/AutoLinux.c
50
@@ -0,0 +1,2951 @@
51
+/* See LICENSE file for copyright and license details.
52
+ *
53
+ * dynamic window manager is designed like any other X client as well. It is
54
+ * driven through handling X events. In contrast to other X clients, a window
55
+ * manager selects for SubstructureRedirectMask on the root window, to receive
56
+ * events about window (dis-)appearance. Only one X connection at a time is
57
+ * allowed to select for this event mask.
58
+ *
59
+ * The event handlers of AutoLinux are organized in an array which is accessed
60
+ * whenever a new event has been fetched. This allows event dispatching
61
+ * in O(1) time.
62
+ *
63
+ * Each child of the root window is called a client, except windows which have
64
+ * set the override_redirect flag. Clients are organized in a linked client
65
+ * list on each monitor, the focus history is remembered through a stack list
66
+ * on each monitor. Each client contains a bit array to indicate the tags of a
67
+ * client.
68
+ *
69
+ * Keys and tagging rules are organized as arrays and defined in config.h.
70
+ *
71
+ * To understand everything else, start reading main().
72
+ */
73
+#include <errno.h>
74
+#include <locale.h>
75
+#include <signal.h>
76
+#include <stdarg.h>
77
+#include <stdio.h>
78
+#include <stdlib.h>
79
+#include <string.h>
80
+#include <unistd.h>
81
+#include <sys/types.h>
82
+#include <sys/wait.h>
83
+#include <X11/cursorfont.h>
84
+#include <X11/keysym.h>
85
+#include <X11/Xatom.h>
86
+#include <X11/Xlib.h>
87
+#include <X11/Xproto.h>
88
+#include <X11/Xutil.h>
89
+#include <X11/Xresource.h>
90
+#ifdef XINERAMA
91
+#include <X11/extensions/Xinerama.h>
92
+#endif /* XINERAMA */
93
+#include <X11/Xft/Xft.h>
94
+#include <X11/Xlib-xcb.h>
95
+#include <xcb/res.h>
96
+
97
+#include "drw.h"
98
+#include "util.h"
99
+
100
+/* macros */
101
+#define BARRULES                20
102
+#define BUTTONMASK              (ButtonPressMask|ButtonReleaseMask)
103
+#define CLEANMASK(mask)         (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
104
+#define GETINC(X)               ((X) - 2000)
105
+#define INC(X)                  ((X) + 2000)
106
+#define INTERSECT(x,y,w,h,m)    (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
107
+                               * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
108
+#define ISINC(X)                ((X) > 1000 && (X) < 3000)
109
+#define ISVISIBLE(C)            ((C->tags & C->mon->tagset[C->mon->seltags]) || C->issticky)
110
+#define PREVSEL                 3000
111
+#define LENGTH(X)               (sizeof X / sizeof X[0])
112
+#define MOUSEMASK               (BUTTONMASK|PointerMotionMask)
113
+#define MOD(N,M)                ((N)%(M) < 0 ? (N)%(M) + (M) : (N)%(M))
114
+#define WIDTH(X)                ((X)->w + 2 * (X)->bw)
115
+#define HEIGHT(X)               ((X)->h + 2 * (X)->bw)
116
+#define NUMTAGS			(LENGTH(tags) + LENGTH(scratchpads))
117
+#define TAGMASK			((1 << NUMTAGS) - 1)
118
+#define SPTAG(i)		((1 << LENGTH(tags)) << (i))
119
+#define SPTAGMASK		(((1 << LENGTH(scratchpads))-1) << LENGTH(tags))
120
+#define TEXTW(X)                (drw_fontset_getwidth(drw, (X)) + lrpad)
121
+#define TRUNC(X,A,B)            (MAX((A), MIN((X), (B))))
122
+
123
+/* enums */
124
+enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
125
+enum { SchemeNorm, SchemeSel }; /* color schemes */
126
+enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
127
+       NetWMFullscreen, NetActiveWindow, NetWMWindowType,
128
+       NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
129
+enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
130
+enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
131
+       ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
132
+enum {
133
+	BAR_ALIGN_LEFT,
134
+	BAR_ALIGN_CENTER,
135
+	BAR_ALIGN_RIGHT,
136
+	BAR_ALIGN_LEFT_LEFT,
137
+	BAR_ALIGN_LEFT_RIGHT,
138
+	BAR_ALIGN_LEFT_CENTER,
139
+	BAR_ALIGN_NONE,
140
+	BAR_ALIGN_RIGHT_LEFT,
141
+	BAR_ALIGN_RIGHT_RIGHT,
142
+	BAR_ALIGN_RIGHT_CENTER,
143
+	BAR_ALIGN_LAST
144
+}; /* bar alignment */
145
+
146
+typedef union {
147
+	int i;
148
+	unsigned int ui;
149
+	float f;
150
+	const void *v;
151
+} Arg;
152
+
153
+typedef struct Monitor Monitor;
154
+typedef struct Bar Bar;
155
+struct Bar {
156
+	Window win;
157
+	Monitor *mon;
158
+	Bar *next;
159
+	int idx;
160
+	int topbar;
161
+	int bx, by, bw, bh; /* bar geometry */
162
+	int w[BARRULES]; // module width
163
+	int x[BARRULES]; // module position
164
+};
165
+
166
+typedef struct {
167
+	int max_width;
168
+} BarWidthArg;
169
+
170
+typedef struct {
171
+	int x;
172
+	int w;
173
+} BarDrawArg;
174
+
175
+typedef struct {
176
+	int rel_x;
177
+	int rel_y;
178
+	int rel_w;
179
+	int rel_h;
180
+} BarClickArg;
181
+
182
+typedef struct {
183
+	int monitor;
184
+	int bar;
185
+	int alignment; // see bar alignment enum
186
+	int (*widthfunc)(Bar *bar, BarWidthArg *a);
187
+	int (*drawfunc)(Bar *bar, BarDrawArg *a);
188
+	int (*clickfunc)(Bar *bar, Arg *arg, BarClickArg *a);
189
+	char *name; // for debugging
190
+	int x, w; // position, width for internal use
191
+} BarRule;
192
+
193
+typedef struct {
194
+	unsigned int click;
195
+	unsigned int mask;
196
+	unsigned int button;
197
+	void (*func)(const Arg *arg);
198
+	const Arg arg;
199
+} Button;
200
+
201
+typedef struct Client Client;
202
+struct Client {
203
+	char name[256];
204
+	float mina, maxa;
205
+	int x, y, w, h;
206
+	int oldx, oldy, oldw, oldh;
207
+	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
208
+	int bw, oldbw;
209
+	unsigned int tags;
210
+	int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, isterminal, noswallow, issticky;
211
+	pid_t pid;
212
+	Client *next;
213
+	Client *snext;
214
+	Client *swallowing;
215
+	Monitor *mon;
216
+	Window win;
217
+};
218
+
219
+typedef struct {
220
+	unsigned int mod;
221
+	KeySym keysym;
222
+	void (*func)(const Arg *);
223
+	const Arg arg;
224
+} Key;
225
+
226
+typedef struct {
227
+	const char *symbol;
228
+	void (*arrange)(Monitor *);
229
+} Layout;
230
+
231
+struct Monitor {
232
+	char ltsymbol[16];
233
+	float mfact;
234
+	int nmaster;
235
+	int num;
236
+	int mx, my, mw, mh;   /* screen size */
237
+	int wx, wy, ww, wh;   /* window area  */
238
+	int gappih;           /* horizontal gap between windows */
239
+	int gappiv;           /* vertical gap between windows */
240
+	int gappoh;           /* horizontal outer gaps */
241
+	int gappov;           /* vertical outer gaps */
242
+	unsigned int seltags;
243
+	unsigned int sellt;
244
+	unsigned int tagset[2];
245
+	int showbar;
246
+	Client *clients;
247
+	Client *sel;
248
+	Client *stack;
249
+	Monitor *next;
250
+	Bar *bar;
251
+	const Layout *lt[2];
252
+};
253
+
254
+typedef struct {
255
+	const char *class;
256
+	const char *instance;
257
+	const char *title;
258
+	unsigned int tags;
259
+	int isfloating;
260
+	int isterminal;
261
+	int noswallow;
262
+	int monitor;
263
+} Rule;
264
+
265
+/* Xresources preferences */
266
+enum resource_type {
267
+	STRING = 0,
268
+	INTEGER = 1,
269
+	FLOAT = 2
270
+};
271
+
272
+typedef struct {
273
+	char *name;
274
+	enum resource_type type;
275
+	void *dst;
276
+} ResourcePref;
277
+
278
+/* function declarations */
279
+static void applyrules(Client *c);
280
+static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
281
+static void arrange(Monitor *m);
282
+static void arrangemon(Monitor *m);
283
+static void attach(Client *c);
284
+static void attachstack(Client *c);
285
+static void buttonpress(XEvent *e);
286
+static void checkotherwm(void);
287
+static void cleanup(void);
288
+static void cleanupmon(Monitor *mon);
289
+static void clientmessage(XEvent *e);
290
+static void configure(Client *c);
291
+static void configurenotify(XEvent *e);
292
+static void configurerequest(XEvent *e);
293
+static void copyvalidchars(char *text, char *rawtext);
294
+static Monitor *createmon(void);
295
+static void destroynotify(XEvent *e);
296
+static void detach(Client *c);
297
+static void detachstack(Client *c);
298
+static Monitor *dirtomon(int dir);
299
+static void drawbar(Monitor *m);
300
+static void drawbars(void);
301
+static void drawbarwin(Bar *bar);
302
+static void enternotify(XEvent *e);
303
+static void expose(XEvent *e);
304
+static void focus(Client *c);
305
+static void focusin(XEvent *e);
306
+static void focusmon(const Arg *arg);
307
+static void focusstack(const Arg *arg);
308
+static Atom getatomprop(Client *c, Atom prop);
309
+static int getrootptr(int *x, int *y);
310
+static long getstate(Window w);
311
+static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
312
+static void grabbuttons(Client *c, int focused);
313
+static void grabkeys(void);
314
+static void incnmaster(const Arg *arg);
315
+static void keypress(XEvent *e);
316
+static void killclient(const Arg *arg);
317
+static void manage(Window w, XWindowAttributes *wa);
318
+static void mappingnotify(XEvent *e);
319
+static void maprequest(XEvent *e);
320
+static void monocle(Monitor *m);
321
+static void motionnotify(XEvent *e);
322
+static void movemouse(const Arg *arg);
323
+static Client *nexttiled(Client *c);
324
+static void pop(Client *);
325
+static void propertynotify(XEvent *e);
326
+static void pushstack(const Arg *arg);
327
+static void quit(const Arg *arg);
328
+static Monitor *recttomon(int x, int y, int w, int h);
329
+static void resize(Client *c, int x, int y, int w, int h, int interact);
330
+static void resizeclient(Client *c, int x, int y, int w, int h);
331
+static void resizemouse(const Arg *arg);
332
+static void restack(Monitor *m);
333
+static void run(void);
334
+static void runAutostart(void);
335
+static void scan(void);
336
+static void scratchpad_hide ();
337
+static _Bool scratchpad_last_showed_is_killed (void);
338
+static void scratchpad_remove ();
339
+static void scratchpad_show ();
340
+static void scratchpad_show_client (Client * c);
341
+static void scratchpad_show_first (void);
342
+static int sendevent(Client *c, Atom proto);
343
+static void sendmon(Client *c, Monitor *m);
344
+static void setclientstate(Client *c, long state);
345
+static void setfocus(Client *c);
346
+static void setfullscreen(Client *c, int fullscreen);
347
+static void setlayout(const Arg *arg);
348
+static void setmfact(const Arg *arg);
349
+static void setup(void);
350
+static void seturgent(Client *c, int urg);
351
+static void showhide(Client *c);
352
+static void sigchld(int unused);
353
+#ifndef __OpenBSD__
354
+static int getAutoLinuxblockspid();
355
+static void sigAutoLinuxblocks(const Arg *arg);
356
+#endif
357
+static void sighup(int unused);
358
+static void sigterm(int unused);
359
+static void spawn(const Arg *arg);
360
+static int stackpos(const Arg *arg);
361
+static void tag(const Arg *arg);
362
+static void tagmon(const Arg *arg);
363
+static void togglebar(const Arg *arg);
364
+static void togglefloating(const Arg *arg);
365
+static void togglescratch(const Arg *arg);
366
+static void togglesticky(const Arg *arg);
367
+static void togglefullscr(const Arg *arg);
368
+static void toggletag(const Arg *arg);
369
+static void toggleview(const Arg *arg);
370
+static void unfocus(Client *c, int setfocus);
371
+static void unmanage(Client *c, int destroyed);
372
+static void unmapnotify(XEvent *e);
373
+static void updatebarpos(Monitor *m);
374
+static void updatebars(void);
375
+static void updateclientlist(void);
376
+static int updategeom(void);
377
+static void updatenumlockmask(void);
378
+static void updatesizehints(Client *c);
379
+static void updatestatus(void);
380
+static void updatetitle(Client *c);
381
+static void updatewindowtype(Client *c);
382
+static void updatewmhints(Client *c);
383
+static void view(const Arg *arg);
384
+static Client *wintoclient(Window w);
385
+static Monitor *wintomon(Window w);
386
+static int xerror(Display *dpy, XErrorEvent *ee);
387
+static int xerrordummy(Display *dpy, XErrorEvent *ee);
388
+static int xerrorstart(Display *dpy, XErrorEvent *ee);
389
+static int leftrotatebits(const int n, const unsigned int d);
390
+static int rightrotatebits(const int n, const unsigned int d);
391
+static void rightrotview(const Arg *arg);
392
+static void leftrotview(const Arg *arg);
393
+static void zoom(const Arg *arg);
394
+static void load_xresources(void);
395
+static void resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst);
396
+
397
+static pid_t getparentprocess(pid_t p);
398
+static int isdescprocess(pid_t p, pid_t c);
399
+static Client *swallowingclient(Window w);
400
+static Client *termforwin(const Client *c);
401
+static pid_t winpid(Window w);
402
+
403
+#include "patch/include.h"
404
+/* variables */
405
+static const char broken[] = "broken";
406
+static char stext[256];
407
+static char rawstext[256];
408
+static int AutoLinuxblockssig;
409
+pid_t AutoLinuxblockspid = 0;
410
+static int screen;
411
+static int sw, sh;           /* X display screen geometry width, height */
412
+static int bh;               /* bar geometry */
413
+static int lrpad;            /* sum of left and right padding for text */
414
+static int vp;               /* vertical padding for bar */
415
+static int sp;               /* side padding for bar */
416
+static int (*xerrorxlib)(Display *, XErrorEvent *);
417
+static unsigned int numlockmask = 0;
418
+static void (*handler[LASTEvent]) (XEvent *) = {
419
+	[ButtonPress] = buttonpress,
420
+	[ClientMessage] = clientmessage,
421
+	[ConfigureRequest] = configurerequest,
422
+	[ConfigureNotify] = configurenotify,
423
+	[DestroyNotify] = destroynotify,
424
+	[EnterNotify] = enternotify,
425
+	[Expose] = expose,
426
+	[FocusIn] = focusin,
427
+	[KeyPress] = keypress,
428
+	[MappingNotify] = mappingnotify,
429
+	[MapRequest] = maprequest,
430
+	[MotionNotify] = motionnotify,
431
+	[PropertyNotify] = propertynotify,
432
+	[UnmapNotify] = unmapnotify
433
+};
434
+static Atom wmatom[WMLast], netatom[NetLast];
435
+static int restart = 0;
436
+static int running = 1;
437
+static Cur *cursor[CurLast];
438
+static Clr **scheme;
439
+static Display *dpy;
440
+static Drw *drw;
441
+static Monitor *mons, *selmon;
442
+static Window root, wmcheckwin;
443
+
444
+/* scratchpad */
445
+# define SCRATCHPAD_MASK (1u << sizeof tags / sizeof * tags)
446
+static Client * scratchpad_last_showed = NULL;
447
+
448
+static xcb_connection_t *xcon;
449
+
450
+/* configuration, allows nested code to access above variables */
451
+#include "config.h"
452
+
453
+#include "patch/include.c"
454
+
455
+/* compile-time check if all tags fit into an unsigned int bit array. */
456
+struct NumTags { char limitexceeded[LENGTH(tags) > 30 ? -1 : 1]; };
457
+
458
+/* function implementations */
459
+void
460
+applyrules(Client *c)
461
+{
462
+	const char *class, *instance;
463
+	unsigned int i;
464
+	const Rule *r;
465
+	Monitor *m;
466
+	XClassHint ch = { NULL, NULL };
467
+
468
+	/* rule matching */
469
+	c->isfloating = 0;
470
+	c->tags = 0;
471
+	XGetClassHint(dpy, c->win, &ch);
472
+	class    = ch.res_class ? ch.res_class : broken;
473
+	instance = ch.res_name  ? ch.res_name  : broken;
474
+
475
+	for (i = 0; i < LENGTH(rules); i++) {
476
+		r = &rules[i];
477
+		if ((!r->title || strstr(c->name, r->title))
478
+		&& (!r->class || strstr(class, r->class))
479
+		&& (!r->instance || strstr(instance, r->instance)))
480
+		{
481
+			c->isterminal = r->isterminal;
482
+			c->isfloating = r->isfloating;
483
+			c->noswallow  = r->noswallow;
484
+			c->tags |= r->tags;
485
+			if ((r->tags & SPTAGMASK) && r->isfloating) {
486
+				c->x = c->mon->wx + (c->mon->ww / 2 - WIDTH(c) / 2);
487
+				c->y = c->mon->wy + (c->mon->wh / 2 - HEIGHT(c) / 2);
488
+			}
489
+
490
+			for (m = mons; m && m->num != r->monitor; m = m->next);
491
+			if (m)
492
+				c->mon = m;
493
+		}
494
+	}
495
+	if (ch.res_class)
496
+		XFree(ch.res_class);
497
+	if (ch.res_name)
498
+		XFree(ch.res_name);
499
+	if (c->tags != SCRATCHPAD_MASK)
500
+		c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : c->mon->tagset[c->mon->seltags];
501
+}
502
+
503
+int
504
+applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact)
505
+{
506
+	int baseismin;
507
+	Monitor *m = c->mon;
508
+
509
+	/* set minimum possible */
510
+	*w = MAX(1, *w);
511
+	*h = MAX(1, *h);
512
+	if (interact) {
513
+		if (*x > sw)
514
+			*x = sw - WIDTH(c);
515
+		if (*y > sh)
516
+			*y = sh - HEIGHT(c);
517
+		if (*x + *w + 2 * c->bw < 0)
518
+			*x = 0;
519
+		if (*y + *h + 2 * c->bw < 0)
520
+			*y = 0;
521
+	} else {
522
+		if (*x >= m->wx + m->ww)
523
+			*x = m->wx + m->ww - WIDTH(c);
524
+		if (*y >= m->wy + m->wh)
525
+			*y = m->wy + m->wh - HEIGHT(c);
526
+		if (*x + *w + 2 * c->bw <= m->wx)
527
+			*x = m->wx;
528
+		if (*y + *h + 2 * c->bw <= m->wy)
529
+			*y = m->wy;
530
+	}
531
+	if (*h < bh)
532
+		*h = bh;
533
+	if (*w < bh)
534
+		*w = bh;
535
+	if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
536
+		/* see last two sentences in ICCCM 4.1.2.3 */
537
+		baseismin = c->basew == c->minw && c->baseh == c->minh;
538
+		if (!baseismin) { /* temporarily remove base dimensions */
539
+			*w -= c->basew;
540
+			*h -= c->baseh;
541
+		}
542
+		/* adjust for aspect limits */
543
+		if (c->mina > 0 && c->maxa > 0) {
544
+			if (c->maxa < (float)*w / *h)
545
+				*w = *h * c->maxa + 0.5;
546
+			else if (c->mina < (float)*h / *w)
547
+				*h = *w * c->mina + 0.5;
548
+		}
549
+		if (baseismin) { /* increment calculation requires this */
550
+			*w -= c->basew;
551
+			*h -= c->baseh;
552
+		}
553
+		/* adjust for increment value */
554
+		if (c->incw)
555
+			*w -= *w % c->incw;
556
+		if (c->inch)
557
+			*h -= *h % c->inch;
558
+		/* restore base dimensions */
559
+		*w = MAX(*w + c->basew, c->minw);
560
+		*h = MAX(*h + c->baseh, c->minh);
561
+		if (c->maxw)
562
+			*w = MIN(*w, c->maxw);
563
+		if (c->maxh)
564
+			*h = MIN(*h, c->maxh);
565
+	}
566
+	return *x != c->x || *y != c->y || *w != c->w || *h != c->h;
567
+}
568
+
569
+void
570
+arrange(Monitor *m)
571
+{
572
+	if (m)
573
+		showhide(m->stack);
574
+	else for (m = mons; m; m = m->next)
575
+		showhide(m->stack);
576
+	if (m) {
577
+		arrangemon(m);
578
+		restack(m);
579
+	} else for (m = mons; m; m = m->next)
580
+		arrangemon(m);
581
+}
582
+
583
+void
584
+arrangemon(Monitor *m)
585
+{
586
+	strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol);
587
+	if (m->lt[m->sellt]->arrange)
588
+		m->lt[m->sellt]->arrange(m);
589
+}
590
+
591
+void
592
+attach(Client *c)
593
+{
594
+	c->next = c->mon->clients;
595
+	c->mon->clients = c;
596
+}
597
+
598
+void
599
+attachstack(Client *c)
600
+{
601
+	c->snext = c->mon->stack;
602
+	c->mon->stack = c;
603
+}
604
+
605
+void
606
+swallow(Client *p, Client *c)
607
+{
608
+	if (c->noswallow || c->isterminal)
609
+		return;
610
+	if (!swallowfloating && c->isfloating)
611
+		return;
612
+
613
+	detach(c);
614
+	detachstack(c);
615
+
616
+	setclientstate(c, WithdrawnState);
617
+	XUnmapWindow(dpy, p->win);
618
+
619
+	p->swallowing = c;
620
+	c->mon = p->mon;
621
+
622
+	Window w = p->win;
623
+	p->win = c->win;
624
+	c->win = w;
625
+	updatetitle(p);
626
+
627
+	XWindowChanges wc;
628
+	wc.border_width = p->bw;
629
+	XConfigureWindow(dpy, p->win, CWBorderWidth, &wc);
630
+	XMoveResizeWindow(dpy, p->win, p->x, p->y, p->w, p->h);
631
+	XSetWindowBorder(dpy, p->win, scheme[SchemeNorm][ColBorder].pixel);
632
+
633
+	arrange(p->mon);
634
+	configure(p);
635
+	updateclientlist();
636
+}
637
+
638
+void
639
+unswallow(Client *c)
640
+{
641
+	c->win = c->swallowing->win;
642
+
643
+	free(c->swallowing);
644
+	c->swallowing = NULL;
645
+
646
+	/* unfullscreen the client */
647
+	setfullscreen(c, 0);
648
+	updatetitle(c);
649
+	arrange(c->mon);
650
+	XMapWindow(dpy, c->win);
651
+
652
+	XWindowChanges wc;
653
+	wc.border_width = c->bw;
654
+	XConfigureWindow(dpy, c->win, CWBorderWidth, &wc);
655
+	XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
656
+	XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel);
657
+
658
+	setclientstate(c, NormalState);
659
+	focus(NULL);
660
+	arrange(c->mon);
661
+}
662
+
663
+void
664
+buttonpress(XEvent *e)
665
+{
666
+	int click, i, r, mi;
667
+	Arg arg = {0};
668
+	Client *c;
669
+	Monitor *m;
670
+	Bar *bar;
671
+	XButtonPressedEvent *ev = &e->xbutton;
672
+	const BarRule *br;
673
+	BarClickArg carg = { 0, 0, 0, 0 };
674
+
675
+	click = ClkRootWin;
676
+	/* focus monitor if necessary */
677
+	if ((m = wintomon(ev->window)) && m != selmon
678
+	) {
679
+		unfocus(selmon->sel, 1);
680
+		selmon = m;
681
+		focus(NULL);
682
+	}
683
+
684
+	for (mi = 0, m = mons; m && m != selmon; m = m->next, mi++); // get the monitor index
685
+	for (bar = selmon->bar; bar; bar = bar->next) {
686
+		if (ev->window == bar->win) {
687
+			for (r = 0; r < LENGTH(barrules); r++) {
688
+				br = &barrules[r];
689
+				if (br->bar != bar->idx || (br->monitor == 'A' && m != selmon) || br->clickfunc == NULL)
690
+					continue;
691
+				if (br->monitor != 'A' && br->monitor != -1 && br->monitor != mi)
692
+					continue;
693
+				if (bar->x[r] <= ev->x && ev->x <= bar->x[r] + bar->w[r]) {
694
+					carg.rel_x = ev->x - bar->x[r];
695
+					carg.rel_y = ev->y;
696
+					carg.rel_w = bar->w[r];
697
+					carg.rel_h = bar->bh;
698
+					click = br->clickfunc(bar, &arg, &carg);
699
+					if (click < 0)
700
+						return;
701
+					break;
702
+				}
703
+			}
704
+			break;
705
+		}
706
+	}
707
+
708
+	if (click == ClkRootWin && (c = wintoclient(ev->window))) {
709
+		focus(c);
710
+		restack(selmon);
711
+		XAllowEvents(dpy, ReplayPointer, CurrentTime);
712
+		click = ClkClientWin;
713
+	}
714
+
715
+	for (i = 0; i < LENGTH(buttons); i++) {
716
+		if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
717
+				&& CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) {
718
+			buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
719
+		}
720
+	}
721
+}
722
+
723
+void
724
+checkotherwm(void)
725
+{
726
+	xerrorxlib = XSetErrorHandler(xerrorstart);
727
+	/* this causes an error if some other window manager is running */
728
+	XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask);
729
+	XSync(dpy, False);
730
+	XSetErrorHandler(xerror);
731
+	XSync(dpy, False);
732
+}
733
+
734
+void
735
+cleanup(void)
736
+{
737
+	Arg a = {.ui = ~0};
738
+	Layout foo = { "", NULL };
739
+	Monitor *m;
740
+	size_t i;
741
+
742
+	view(&a);
743
+	selmon->lt[selmon->sellt] = &foo;
744
+	for (m = mons; m; m = m->next)
745
+		while (m->stack)
746
+			unmanage(m->stack, 0);
747
+	XUngrabKey(dpy, AnyKey, AnyModifier, root);
748
+	while (mons)
749
+		cleanupmon(mons);
750
+	for (i = 0; i < CurLast; i++)
751
+		drw_cur_free(drw, cursor[i]);
752
+	for (i = 0; i < LENGTH(colors); i++)
753
+		free(scheme[i]);
754
+	XDestroyWindow(dpy, wmcheckwin);
755
+	drw_free(drw);
756
+	XSync(dpy, False);
757
+	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
758
+	XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
759
+}
760
+
761
+void
762
+cleanupmon(Monitor *mon)
763
+{
764
+	Monitor *m;
765
+	Bar *bar;
766
+
767
+	if (mon == mons)
768
+		mons = mons->next;
769
+	else {
770
+		for (m = mons; m && m->next != mon; m = m->next);
771
+		m->next = mon->next;
772
+	}
773
+	for (bar = mon->bar; bar; bar = mon->bar) {
774
+		XUnmapWindow(dpy, bar->win);
775
+		XDestroyWindow(dpy, bar->win);
776
+		mon->bar = bar->next;
777
+		free(bar);
778
+	}
779
+	free(mon);
780
+}
781
+
782
+void
783
+clientmessage(XEvent *e)
784
+{
785
+	XClientMessageEvent *cme = &e->xclient;
786
+	Client *c = wintoclient(cme->window);
787
+
788
+	if (!c)
789
+		return;
790
+	if (cme->message_type == netatom[NetWMState]) {
791
+		if (cme->data.l[1] == netatom[NetWMFullscreen]
792
+		|| cme->data.l[2] == netatom[NetWMFullscreen])
793
+			setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD    */
794
+				|| (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
795
+	} else if (cme->message_type == netatom[NetActiveWindow]) {
796
+		if (c != selmon->sel && !c->isurgent)
797
+			seturgent(c, 1);
798
+	}
799
+}
800
+
801
+void
802
+configure(Client *c)
803
+{
804
+	XConfigureEvent ce;
805
+
806
+	ce.type = ConfigureNotify;
807
+	ce.display = dpy;
808
+	ce.event = c->win;
809
+	ce.window = c->win;
810
+	ce.x = c->x;
811
+	ce.y = c->y;
812
+	ce.width = c->w;
813
+	ce.height = c->h;
814
+	ce.border_width = c->bw;
815
+	ce.above = None;
816
+	ce.override_redirect = False;
817
+	XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
818
+}
819
+
820
+void
821
+configurenotify(XEvent *e)
822
+{
823
+	Monitor *m;
824
+	Bar *bar;
825
+	Client *c;
826
+	XConfigureEvent *ev = &e->xconfigure;
827
+	int dirty;
828
+
829
+	/* TODO: updategeom handling sucks, needs to be simplified */
830
+	if (ev->window == root) {
831
+		dirty = (sw != ev->width || sh != ev->height);
832
+		sw = ev->width;
833
+		sh = ev->height;
834
+		if (updategeom() || dirty) {
835
+			drw_resize(drw, sw, bh);
836
+			updatebars();
837
+			for (m = mons; m; m = m->next) {
838
+				for (c = m->clients; c; c = c->next)
839
+					if (c->isfullscreen)
840
+						resizeclient(c, m->mx, m->my, m->mw, m->mh);
841
+				for (bar = m->bar; bar; bar = bar->next)
842
+					XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh);
843
+			}
844
+			focus(NULL);
845
+			arrange(NULL);
846
+		}
847
+	}
848
+}
849
+
850
+void
851
+configurerequest(XEvent *e)
852
+{
853
+	Client *c;
854
+	Monitor *m;
855
+	XConfigureRequestEvent *ev = &e->xconfigurerequest;
856
+	XWindowChanges wc;
857
+
858
+	if ((c = wintoclient(ev->window))) {
859
+		if (ev->value_mask & CWBorderWidth)
860
+			c->bw = ev->border_width;
861
+		else if (c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
862
+			m = c->mon;
863
+			if (ev->value_mask & CWX) {
864
+				c->oldx = c->x;
865
+				c->x = m->mx + ev->x;
866
+			}
867
+			if (ev->value_mask & CWY) {
868
+				c->oldy = c->y;
869
+				c->y = m->my + ev->y;
870
+			}
871
+			if (ev->value_mask & CWWidth) {
872
+				c->oldw = c->w;
873
+				c->w = ev->width;
874
+			}
875
+			if (ev->value_mask & CWHeight) {
876
+				c->oldh = c->h;
877
+				c->h = ev->height;
878
+			}
879
+			if ((c->x + c->w) > m->mx + m->mw && c->isfloating)
880
+				c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */
881
+			if ((c->y + c->h) > m->my + m->mh && c->isfloating)
882
+				c->y = m->my + (m->mh / 2 - HEIGHT(c) / 2); /* center in y direction */
883
+			if ((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
884
+				configure(c);
885
+			if (ISVISIBLE(c))
886
+				XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
887
+		} else
888
+			configure(c);
889
+	} else {
890
+		wc.x = ev->x;
891
+		wc.y = ev->y;
892
+		wc.width = ev->width;
893
+		wc.height = ev->height;
894
+		wc.border_width = ev->border_width;
895
+		wc.sibling = ev->above;
896
+		wc.stack_mode = ev->detail;
897
+		XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
898
+	}
899
+	XSync(dpy, False);
900
+}
901
+
902
+void
903
+copyvalidchars(char *text, char *rawtext)
904
+{
905
+	int i = -1, j = 0;
906
+
907
+	while(rawtext[++i]) {
908
+		if ((unsigned char)rawtext[i] >= ' ') {
909
+			text[j++] = rawtext[i];
910
+		}
911
+	}
912
+	text[j] = '\0';
913
+}
914
+
915
+Monitor *
916
+createmon(void)
917
+{
918
+	Monitor *m, *mon;
919
+	int i, n, mi, max_bars = 2, istopbar = topbar;
920
+
921
+	const BarRule *br;
922
+	Bar *bar;
923
+
924
+	m = ecalloc(1, sizeof(Monitor));
925
+	m->tagset[0] = m->tagset[1] = 1;
926
+	m->mfact = mfact;
927
+	m->nmaster = nmaster;
928
+	m->showbar = showbar;
929
+	m->gappih = gappih;
930
+	m->gappiv = gappiv;
931
+	m->gappoh = gappoh;
932
+	m->gappov = gappov;
933
+
934
+	for (mi = 0, mon = mons; mon; mon = mon->next, mi++); // monitor index
935
+	m->lt[0] = &layouts[0];
936
+	m->lt[1] = &layouts[1 % LENGTH(layouts)];
937
+	strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
938
+
939
+	/* Derive the number of bars for this monitor based on bar rules */
940
+	for (n = -1, i = 0; i < LENGTH(barrules); i++) {
941
+		br = &barrules[i];
942
+		if (br->monitor == 'A' || br->monitor == -1 || br->monitor == mi)
943
+			n = MAX(br->bar, n);
944
+	}
945
+
946
+	for (i = 0; i <= n && i < max_bars; i++) {
947
+		bar = ecalloc(1, sizeof(Bar));
948
+		bar->mon = m;
949
+		bar->idx = i;
950
+		bar->next = m->bar;
951
+		bar->topbar = istopbar;
952
+		m->bar = bar;
953
+		istopbar = !istopbar;
954
+	}
955
+
956
+	return m;
957
+}
958
+
959
+void
960
+destroynotify(XEvent *e)
961
+{
962
+	Client *c;
963
+	XDestroyWindowEvent *ev = &e->xdestroywindow;
964
+
965
+	if ((c = wintoclient(ev->window)))
966
+		unmanage(c, 1);
967
+
968
+	else if ((c = swallowingclient(ev->window)))
969
+		unmanage(c->swallowing, 1);
970
+}
971
+
972
+void
973
+detach(Client *c)
974
+{
975
+	Client **tc;
976
+
977
+	for (tc = &c->mon->clients; *tc && *tc != c; tc = &(*tc)->next);
978
+	*tc = c->next;
979
+}
980
+
981
+void
982
+detachstack(Client *c)
983
+{
984
+	Client **tc, *t;
985
+
986
+	for (tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext);
987
+	*tc = c->snext;
988
+
989
+	if (c == c->mon->sel) {
990
+		for (t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext);
991
+		c->mon->sel = t;
992
+	}
993
+}
994
+
995
+Monitor *
996
+dirtomon(int dir)
997
+{
998
+	Monitor *m = NULL;
999
+