all repos — dwm @ 4cdbd523e5f02f7cf392dda8690f95ce6eaff9dd

fork of suckless dynamic window manager

manage.c (view raw)

  1/* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com>
  2 * See LICENSE file for license details.
  3 */
  4#include "dwm.h"
  5#include <regex.h>
  6#include <stdio.h>
  7#include <stdlib.h>
  8#include <string.h>
  9#include <sys/types.h>
 10#include <X11/Xutil.h>
 11
 12void (*arrange)(void) = DEFMODE;
 13unsigned int master = MASTER;
 14unsigned int nmaster = NMASTER;
 15
 16/* static */
 17
 18typedef struct {
 19	const char *clpattern;
 20	const char *tpattern;
 21	Bool isfloat;
 22} Rule;
 23
 24typedef struct {
 25	regex_t *clregex;
 26	regex_t *tregex;
 27} RReg;
 28
 29TAGS
 30RULES
 31
 32static RReg *rreg = NULL;
 33static unsigned int len = 0;
 34
 35static Client *
 36nextmanaged(Client *c) {
 37	for(; c && (c->isfloat || !isvisible(c)); c = c->next);
 38	return c;
 39}
 40
 41static void
 42togglemax(Client *c) {
 43	XEvent ev;
 44
 45	if(c->isfixed)
 46		return;
 47	if((c->ismax = !c->ismax)) {
 48		c->rx = c->x;
 49		c->ry = c->y;
 50		c->rw = c->w;
 51		c->rh = c->h;
 52		resize(c, wax, way, waw - 2 * BORDERPX, wah - 2 * BORDERPX, True);
 53	}
 54	else
 55		resize(c, c->rx, c->ry, c->rw, c->rh, True);
 56	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
 57}
 58
 59/* extern */
 60
 61void
 62attach(Client *c) {
 63	if(clients)
 64		clients->prev = c;
 65	c->next = clients;
 66	clients = c;
 67}
 68
 69void
 70attachstack(Client *c) {
 71	c->snext = stack;
 72	stack = c;
 73}
 74
 75void
 76compileregexps(void) {
 77	unsigned int i;
 78	regex_t *reg;
 79
 80	if(rreg)
 81		return;
 82	len = sizeof rule / sizeof rule[0];
 83	rreg = emallocz(len * sizeof(RReg));
 84	for(i = 0; i < len; i++) {
 85		if(rule[i].clpattern) {
 86			reg = emallocz(sizeof(regex_t));
 87			if(regcomp(reg, rule[i].clpattern, REG_EXTENDED))
 88				free(reg);
 89			else
 90				rreg[i].clregex = reg;
 91		}
 92		if(rule[i].tpattern) {
 93			reg = emallocz(sizeof(regex_t));
 94			if(regcomp(reg, rule[i].tpattern, REG_EXTENDED))
 95				free(reg);
 96			else
 97				rreg[i].tregex = reg;
 98		}
 99	}
100}
101
102void
103detach(Client *c) {
104	if(c->prev)
105		c->prev->next = c->next;
106	if(c->next)
107		c->next->prev = c->prev;
108	if(c == clients)
109		clients = c->next;
110	c->next = c->prev = NULL;
111}
112
113void
114detachstack(Client *c) {
115	Client **tc;
116	for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
117	*tc = c->snext;
118}
119
120void
121dofloat(void) {
122	Client *c;
123
124	for(c = clients; c; c = c->next) {
125		if(isvisible(c)) {
126			if(c->isbanned)
127				XMoveWindow(dpy, c->win, c->x, c->y);
128			c->isbanned = False;
129			resize(c, c->x, c->y, c->w, c->h, True);
130		}
131		else {
132			c->isbanned = True;
133			XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
134		}
135	}
136	if(!sel || !isvisible(sel)) {
137		for(c = stack; c && !isvisible(c); c = c->snext);
138		focus(c);
139	}
140	restack();
141}
142void
143dotile(void) {
144	unsigned int i, n, nx, ny, nw, nh, mw, mh, tw, th;
145	Client *c;
146
147	for(n = 0, c = nextmanaged(clients); c; c = nextmanaged(c->next))
148		n++;
149	/* window geoms */
150	mh = (n > nmaster) ? wah / nmaster : wah / (n > 0 ? n : 1);
151	mw = (n > nmaster) ? (waw * master) / 1000 : waw;
152	th = (n > nmaster) ? wah / (n - nmaster) : 0;
153	tw = waw - mw;
154
155	for(i = 0, c = clients; c; c = c->next)
156		if(isvisible(c)) {
157			if(c->isbanned)
158				XMoveWindow(dpy, c->win, c->x, c->y);
159			c->isbanned = False;
160			if(c->isfloat)
161				continue;
162			c->ismax = False;
163			nx = wax;
164			ny = way;
165			if(i < nmaster) {
166				ny += i * mh;
167				nw = mw - 2 * BORDERPX;
168				nh = mh - 2 * BORDERPX;
169			}
170			else {  /* tile window */
171				nx += mw;
172				nw = tw - 2 * BORDERPX;
173				if(th > 2 * BORDERPX) {
174					ny += (i - nmaster) * th;
175					nh = th - 2 * BORDERPX;
176				}
177				else /* fallback if th <= 2 * BORDERPX */
178					nh = wah - 2 * BORDERPX;
179			}
180			resize(c, nx, ny, nw, nh, False);
181			i++;
182		}
183		else {
184			c->isbanned = True;
185			XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
186		}
187	if(!sel || !isvisible(sel)) {
188		for(c = stack; c && !isvisible(c); c = c->snext);
189		focus(c);
190	}
191	restack();
192}
193
194void
195focusnext(Arg *arg) {
196	Client *c;
197   
198	if(!sel)
199		return;
200	for(c = sel->next; c && !isvisible(c); c = c->next);
201	if(!c)
202		for(c = clients; c && !isvisible(c); c = c->next);
203	if(c) {
204		focus(c);
205		restack();
206	}
207}
208
209void
210focusprev(Arg *arg) {
211	Client *c;
212
213	if(!sel)
214		return;
215	for(c = sel->prev; c && !isvisible(c); c = c->prev);
216	if(!c) {
217		for(c = clients; c && c->next; c = c->next);
218		for(; c && !isvisible(c); c = c->prev);
219	}
220	if(c) {
221		focus(c);
222		restack();
223	}
224}
225
226Client *
227getclient(Window w) {
228	Client *c;
229
230	for(c = clients; c; c = c->next)
231		if(c->win == w)
232			return c;
233	return NULL;
234}
235
236void
237incnmaster(Arg *arg) {
238	if((arrange == dofloat) || (nmaster + arg->i < 1)
239	|| (wah / (nmaster + arg->i) <= 2 * BORDERPX))
240		return;
241	nmaster += arg->i;
242	if(sel)
243		arrange();
244	else
245		drawstatus();
246}
247
248Bool
249isvisible(Client *c) {
250	unsigned int i;
251
252	for(i = 0; i < ntags; i++)
253		if(c->tags[i] && seltag[i])
254			return True;
255	return False;
256}
257
258void
259resizemaster(Arg *arg) {
260	if(arrange != dotile)
261		return;
262	if(arg->i == 0)
263		master = MASTER;
264	else {
265		if(waw * (master + arg->i) / 1000 >= waw - 2 * BORDERPX
266		|| waw * (master + arg->i) / 1000 <= 2 * BORDERPX)
267			return;
268		master += arg->i;
269	}
270	arrange();
271}
272
273void
274restack(void) {
275	Client *c;
276	XEvent ev;
277
278	drawstatus();
279	if(!sel)
280		return;
281	if(sel->isfloat || arrange == dofloat)
282		XRaiseWindow(dpy, sel->win);
283	if(arrange != dofloat) {
284		if(!sel->isfloat)
285			XLowerWindow(dpy, sel->win);
286		for(c = nextmanaged(clients); c; c = nextmanaged(c->next)) {
287			if(c == sel)
288				continue;
289			XLowerWindow(dpy, c->win);
290		}
291	}
292	XSync(dpy, False);
293	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
294}
295
296void
297settags(Client *c, Client *trans) {
298	char prop[512];
299	unsigned int i, j;
300	regmatch_t tmp;
301	Bool matched = trans != NULL;
302	XClassHint ch = { 0 };
303
304	if(matched)
305		for(i = 0; i < ntags; i++)
306			c->tags[i] = trans->tags[i];
307	else {
308		XGetClassHint(dpy, c->win, &ch);
309		snprintf(prop, sizeof prop, "%s:%s:%s",
310				ch.res_class ? ch.res_class : "",
311				ch.res_name ? ch.res_name : "", c->name);
312		for(i = 0; i < len; i++)
313			if(rreg[i].clregex && !regexec(rreg[i].clregex, prop, 1, &tmp, 0)) {
314				c->isfloat = rule[i].isfloat;
315				for(j = 0; rreg[i].tregex && j < ntags; j++) {
316					if(!regexec(rreg[i].tregex, tags[j], 1, &tmp, 0)) {
317						matched = True;
318						c->tags[j] = True;
319					}
320				}
321			}
322		if(ch.res_class)
323			XFree(ch.res_class);
324		if(ch.res_name)
325			XFree(ch.res_name);
326	}
327	if(!matched)
328		for(i = 0; i < ntags; i++)
329			c->tags[i] = seltag[i];
330}
331
332void
333tag(Arg *arg) {
334	unsigned int i;
335
336	if(!sel)
337		return;
338	for(i = 0; i < ntags; i++)
339		sel->tags[i] = (arg->i == -1) ? True : False;
340	if(arg->i >= 0 && arg->i < ntags)
341		sel->tags[arg->i] = True;
342	arrange();
343}
344
345void
346togglefloat(Arg *arg) {
347	if(!sel || arrange == dofloat)
348		return;
349	sel->isfloat = !sel->isfloat;
350	arrange();
351}
352
353void
354toggletag(Arg *arg) {
355	unsigned int i;
356
357	if(!sel)
358		return;
359	sel->tags[arg->i] = !sel->tags[arg->i];
360	for(i = 0; i < ntags && !sel->tags[i]; i++);
361	if(i == ntags)
362		sel->tags[arg->i] = True;
363	arrange();
364}
365
366void
367togglemode(Arg *arg) {
368	arrange = (arrange == dofloat) ? dotile : dofloat;
369	if(sel)
370		arrange();
371	else
372		drawstatus();
373}
374
375void
376toggleview(Arg *arg) {
377	unsigned int i;
378
379	seltag[arg->i] = !seltag[arg->i];
380	for(i = 0; i < ntags && !seltag[i]; i++);
381	if(i == ntags)
382		seltag[arg->i] = True; /* cannot toggle last view */
383	arrange();
384}
385
386void
387view(Arg *arg) {
388	unsigned int i;
389
390	for(i = 0; i < ntags; i++)
391		seltag[i] = (arg->i == -1) ? True : False;
392	if(arg->i >= 0 && arg->i < ntags)
393		seltag[arg->i] = True;
394	arrange();
395}
396
397void
398zoom(Arg *arg) {
399	unsigned int n;
400	Client *c;
401
402	if(!sel)
403		return;
404	if(sel->isfloat || (arrange == dofloat)) {
405		togglemax(sel);
406		return;
407	}
408	for(n = 0, c = nextmanaged(clients); c; c = nextmanaged(c->next))
409		n++;
410
411	if((c = sel) == nextmanaged(clients))
412		if(!(c = nextmanaged(c->next)))
413			return;
414	detach(c);
415	attach(c);
416	focus(c);
417	arrange();
418}