all repos — dwm @ 47765f728614c348aa7dfc2eed6f754efc376922

fork of suckless dynamic window manager

screen.c (view raw)

  1/* See LICENSE file for copyright and license details. */
  2#include "dwm.h"
  3#include <regex.h>
  4#include <stdio.h>
  5#include <stdlib.h>
  6#include <string.h>
  7#include <X11/Xatom.h>
  8#include <X11/Xutil.h>
  9
 10/* static */
 11
 12typedef struct {
 13	const char *symbol;
 14	void (*arrange)(void);
 15} Layout;
 16
 17typedef struct {
 18	const char *prop;
 19	const char *tags;
 20	Bool isfloating;
 21} Rule;
 22
 23typedef struct {
 24	regex_t *propregex;
 25	regex_t *tagregex;
 26} Regs;
 27
 28TAGS
 29RULES
 30
 31static char prop[512];
 32static unsigned int nrules = 0;
 33static unsigned int nlayouts = 0;
 34static unsigned int ltidx = 0; /* default */
 35static Regs *regs = NULL;
 36
 37static unsigned int
 38idxoftag(const char *tag) {
 39	unsigned int i;
 40
 41	for(i = 0; i < ntags; i++)
 42		if(tags[i] == tag)
 43			return i;
 44	return 0;
 45}
 46
 47static void
 48floating(void) { /* default floating layout */
 49	Client *c;
 50
 51	for(c = clients; c; c = c->next)
 52		if(isvisible(c))
 53			resize(c, c->x, c->y, c->w, c->h, True);
 54}
 55
 56static void
 57setdwmprops(void) {
 58	unsigned int i;
 59
 60	for(i = 0; i < ntags && i < sizeof prop - 1; i++)
 61		prop[i] = seltags[i] ? '1' : '0';
 62	if(i < sizeof prop - 1)
 63		prop[i++] = (char)ltidx;
 64	prop[i] = '\0';
 65	XChangeProperty(dpy, root, dwmprops, XA_STRING, 8,
 66			PropModeReplace, (unsigned char *)prop, i);
 67}
 68
 69LAYOUTS
 70
 71/* extern */
 72
 73unsigned int blw = 0;
 74
 75void
 76applyrules(Client *c) {
 77	unsigned int i, j;
 78	regmatch_t tmp;
 79	Bool matched = False;
 80	XClassHint ch = { 0 };
 81
 82	/* rule matching */
 83	XGetClassHint(dpy, c->win, &ch);
 84	snprintf(prop, sizeof prop, "%s:%s:%s",
 85			ch.res_class ? ch.res_class : "",
 86			ch.res_name ? ch.res_name : "", c->name);
 87	for(i = 0; i < nrules; i++)
 88		if(regs[i].propregex && !regexec(regs[i].propregex, prop, 1, &tmp, 0)) {
 89			c->isfloating = rules[i].isfloating;
 90			for(j = 0; regs[i].tagregex && j < ntags; j++) {
 91				if(!regexec(regs[i].tagregex, tags[j], 1, &tmp, 0)) {
 92					matched = True;
 93					c->tags[j] = True;
 94				}
 95			}
 96		}
 97	if(ch.res_class)
 98		XFree(ch.res_class);
 99	if(ch.res_name)
100		XFree(ch.res_name);
101	if(!matched)
102		for(i = 0; i < ntags; i++)
103			c->tags[i] = seltags[i];
104}
105
106void
107arrange(void) {
108	Client *c;
109
110	for(c = clients; c; c = c->next)
111		if(isvisible(c))
112			unban(c);
113		else
114			ban(c);
115	layouts[ltidx].arrange();
116	focus(NULL);
117	restack();
118}
119
120void
121compileregs(void) {
122	unsigned int i;
123	regex_t *reg;
124
125	if(regs)
126		return;
127	nrules = sizeof rules / sizeof rules[0];
128	regs = emallocz(nrules * sizeof(Regs));
129	for(i = 0; i < nrules; i++) {
130		if(rules[i].prop) {
131			reg = emallocz(sizeof(regex_t));
132			if(regcomp(reg, rules[i].prop, REG_EXTENDED))
133				free(reg);
134			else
135				regs[i].propregex = reg;
136		}
137		if(rules[i].tags) {
138			reg = emallocz(sizeof(regex_t));
139			if(regcomp(reg, rules[i].tags, REG_EXTENDED))
140				free(reg);
141			else
142				regs[i].tagregex = reg;
143		}
144	}
145}
146
147void
148focusnext(const char *arg) {
149	Client *c;
150
151	if(!sel)
152		return;
153	for(c = sel->next; c && !isvisible(c); c = c->next);
154	if(!c)
155		for(c = clients; c && !isvisible(c); c = c->next);
156	if(c) {
157		focus(c);
158		restack();
159	}
160}
161
162void
163focusprev(const char *arg) {
164	Client *c;
165
166	if(!sel)
167		return;
168	for(c = sel->prev; c && !isvisible(c); c = c->prev);
169	if(!c) {
170		for(c = clients; c && c->next; c = c->next);
171		for(; c && !isvisible(c); c = c->prev);
172	}
173	if(c) {
174		focus(c);
175		restack();
176	}
177}
178
179const char *
180getsymbol(void)
181{
182	return layouts[ltidx].symbol;
183}
184
185void
186initlayouts(void) {
187	unsigned int i, w;
188
189	nlayouts = sizeof layouts / sizeof layouts[0];
190	for(blw = i = 0; i < nlayouts; i++) {
191		w = textw(layouts[i].symbol);
192		if(w > blw)
193			blw = w;
194	}
195}
196
197Bool
198isfloating(void) {
199	return layouts[ltidx].arrange == floating;
200}
201
202Bool
203isarrange(void (*func)())
204{
205	return func == layouts[ltidx].arrange;
206}
207
208Bool
209isvisible(Client *c) {
210	unsigned int i;
211
212	for(i = 0; i < ntags; i++)
213		if(c->tags[i] && seltags[i])
214			return True;
215	return False;
216}
217
218void
219getdwmprops(void) {
220	unsigned int i;
221
222	if(gettextprop(root, dwmprops, prop, sizeof prop)) {
223		for(i = 0; i < ntags && i < sizeof prop - 1 && prop[i] != '\0'; i++)
224			seltags[i] = prop[i] == '1';
225		if(i < sizeof prop - 1 && prop[i] != '\0') {
226			if(prop[i] < nlayouts)
227				ltidx = prop[i];
228		}
229	}
230}
231
232Client *
233nexttiled(Client *c) {
234	for(; c && (c->isfloating || !isvisible(c)); c = c->next);
235	return c;
236}
237
238void
239restack(void) {
240	Client *c;
241	XEvent ev;
242	XWindowChanges wc;
243
244	drawstatus();
245	if(!sel)
246		return;
247	if(sel->isfloating || isfloating())
248		XRaiseWindow(dpy, sel->win);
249	if(!isfloating()) {
250		wc.stack_mode = Below;
251		wc.sibling = barwin;
252		if(!sel->isfloating) {
253			XConfigureWindow(dpy, sel->win, CWSibling | CWStackMode, &wc);
254			wc.sibling = sel->win;
255		}
256		for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
257			if(c == sel)
258				continue;
259			XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc);
260			wc.sibling = c->win;
261		}
262	}
263	XSync(dpy, False);
264	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
265}
266
267void
268setlayout(const char *arg) {
269	int i;
270
271	if(!arg) {
272		if(++ltidx == nlayouts)
273			ltidx = 0;;
274	}
275	else {
276		i = atoi(arg);
277		if(i < 0 || i >= nlayouts)
278			return;
279		ltidx = i;
280	}
281	if(sel)
282		arrange();
283	else
284		drawstatus();
285	setdwmprops();
286}
287
288void
289tag(const char *arg) {
290	unsigned int i;
291
292	if(!sel)
293		return;
294	for(i = 0; i < ntags; i++)
295		sel->tags[i] = arg == NULL;
296	i = idxoftag(arg);
297	if(i >= 0 && i < ntags)
298		sel->tags[i] = True;
299	setprops(sel);
300	arrange();
301}
302
303void
304togglebar(const char *arg) {
305	if(bpos == BarOff)
306		bpos = (BARPOS == BarOff) ? BarTop : BARPOS;
307	else
308		bpos = BarOff;
309	updatebarpos();
310	arrange();
311}
312
313void
314togglefloating(const char *arg) {
315	if(!sel || isfloating())
316		return;
317	sel->isfloating = !sel->isfloating;
318	if(sel->isfloating) {
319		resize(sel, sel->x, sel->y, sel->w, sel->h, True);
320		setprops(sel);
321	}
322	arrange();
323}
324
325void
326togglemax(const char *arg) {
327	XEvent ev;
328
329	if(!sel || (!isfloating() && !sel->isfloating) || sel->isfixed)
330		return;
331	if((sel->ismax = !sel->ismax)) {
332		sel->rx = sel->x;
333		sel->ry = sel->y;
334		sel->rw = sel->w;
335		sel->rh = sel->h;
336		resize(sel, wax, way, waw - 2 * sel->border, wah - 2 * sel->border, True);
337	}
338	else
339		resize(sel, sel->rx, sel->ry, sel->rw, sel->rh, True);
340	drawstatus();
341	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
342}
343
344void
345toggletag(const char *arg) {
346	unsigned int i, j;
347
348	if(!sel)
349		return;
350	i = idxoftag(arg);
351	sel->tags[i] = !sel->tags[i];
352	for(j = 0; j < ntags && !sel->tags[j]; j++);
353	if(j == ntags)
354		sel->tags[i] = True;
355	setprops(sel);
356	arrange();
357}
358
359void
360toggleview(const char *arg) {
361	unsigned int i, j;
362
363	i = idxoftag(arg);
364	seltags[i] = !seltags[i];
365	for(j = 0; j < ntags && !seltags[j]; j++);
366	if(j == ntags)
367		seltags[i] = True; /* cannot toggle last view */
368	setdwmprops();
369	arrange();
370}
371
372void
373view(const char *arg) {
374	unsigned int i;
375
376	for(i = 0; i < ntags; i++)
377		seltags[i] = arg == NULL;
378	i = idxoftag(arg);
379	if(i >= 0 && i < ntags)
380		seltags[i] = True;
381	setdwmprops();
382	arrange();
383}