all repos — dwm @ b2f895166af45b5d84abab90032bd3cc75391dc8

fork of suckless dynamic window manager

screen.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 *prop;
 20	const char *tags;
 21	Bool isfloat;
 22} Rule;
 23
 24typedef struct {
 25	regex_t *propregex;
 26	regex_t *tagregex;
 27} Regexps;
 28
 29TAGS
 30RULES
 31
 32static Regexps *regexps = NULL;
 33static unsigned int len = 0;
 34
 35/* extern */
 36
 37void
 38compileregexps(void) {
 39	unsigned int i;
 40	regex_t *reg;
 41
 42	if(regexps)
 43		return;
 44	len = sizeof rule / sizeof rule[0];
 45	regexps = emallocz(len * sizeof(Regexps));
 46	for(i = 0; i < len; i++) {
 47		if(rule[i].prop) {
 48			reg = emallocz(sizeof(regex_t));
 49			if(regcomp(reg, rule[i].prop, REG_EXTENDED))
 50				free(reg);
 51			else
 52				regexps[i].propregex = reg;
 53		}
 54		if(rule[i].tags) {
 55			reg = emallocz(sizeof(regex_t));
 56			if(regcomp(reg, rule[i].tags, REG_EXTENDED))
 57				free(reg);
 58			else
 59				regexps[i].tagregex = reg;
 60		}
 61	}
 62}
 63
 64void
 65dofloat(void) {
 66	Client *c;
 67
 68	for(c = clients; c; c = c->next) {
 69		if(isvisible(c)) {
 70			if(c->isbanned)
 71				XMoveWindow(dpy, c->win, c->x, c->y);
 72			c->isbanned = False;
 73			resize(c, c->x, c->y, c->w, c->h, True);
 74		}
 75		else {
 76			c->isbanned = True;
 77			XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
 78		}
 79	}
 80	if(!sel || !isvisible(sel)) {
 81		for(c = stack; c && !isvisible(c); c = c->snext);
 82		focus(c);
 83	}
 84	restack();
 85}
 86
 87void
 88dotile(void) {
 89	unsigned int i, n, nx, ny, nw, nh, mw, mh, tw, th;
 90	Client *c;
 91
 92	for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
 93		n++;
 94	/* window geoms */
 95	mh = (n > nmaster) ? wah / nmaster : wah / (n > 0 ? n : 1);
 96	mw = (n > nmaster) ? (waw * master) / 1000 : waw;
 97	th = (n > nmaster) ? wah / (n - nmaster) : 0;
 98	tw = waw - mw;
 99
100	for(i = 0, c = clients; c; c = c->next)
101		if(isvisible(c)) {
102			if(c->isbanned)
103				XMoveWindow(dpy, c->win, c->x, c->y);
104			c->isbanned = False;
105			if(c->isfloat)
106				continue;
107			c->ismax = False;
108			nx = wax;
109			ny = way;
110			if(i < nmaster) {
111				ny += i * mh;
112				nw = mw - 2 * BORDERPX;
113				nh = mh - 2 * BORDERPX;
114			}
115			else {  /* tile window */
116				nx += mw;
117				nw = tw - 2 * BORDERPX;
118				if(th > 2 * BORDERPX) {
119					ny += (i - nmaster) * th;
120					nh = th - 2 * BORDERPX;
121				}
122				else /* fallback if th <= 2 * BORDERPX */
123					nh = wah - 2 * BORDERPX;
124			}
125			resize(c, nx, ny, nw, nh, False);
126			i++;
127		}
128		else {
129			c->isbanned = True;
130			XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
131		}
132	if(!sel || !isvisible(sel)) {
133		for(c = stack; c && !isvisible(c); c = c->snext);
134		focus(c);
135	}
136	restack();
137}
138
139void
140incnmaster(Arg *arg) {
141	if((arrange == dofloat) || (nmaster + arg->i < 1)
142	|| (wah / (nmaster + arg->i) <= 2 * BORDERPX))
143		return;
144	nmaster += arg->i;
145	if(sel)
146		arrange();
147	else
148		drawstatus();
149}
150
151Bool
152isvisible(Client *c) {
153	unsigned int i;
154
155	for(i = 0; i < ntags; i++)
156		if(c->tags[i] && seltag[i])
157			return True;
158	return False;
159}
160
161void
162resizemaster(Arg *arg) {
163	if(arrange != dotile)
164		return;
165	if(arg->i == 0)
166		master = MASTER;
167	else {
168		if(waw * (master + arg->i) / 1000 >= waw - 2 * BORDERPX
169		|| waw * (master + arg->i) / 1000 <= 2 * BORDERPX)
170			return;
171		master += arg->i;
172	}
173	arrange();
174}
175
176void
177restack(void) {
178	Client *c;
179	XEvent ev;
180
181	drawstatus();
182	if(!sel)
183		return;
184	if(sel->isfloat || arrange == dofloat)
185		XRaiseWindow(dpy, sel->win);
186	if(arrange != dofloat) {
187		if(!sel->isfloat)
188			XLowerWindow(dpy, sel->win);
189		for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
190			if(c == sel)
191				continue;
192			XLowerWindow(dpy, c->win);
193		}
194	}
195	XSync(dpy, False);
196	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
197}
198
199void
200settags(Client *c, Client *trans) {
201	char prop[512];
202	unsigned int i, j;
203	regmatch_t tmp;
204	Bool matched = trans != NULL;
205	XClassHint ch = { 0 };
206
207	if(matched)
208		for(i = 0; i < ntags; i++)
209			c->tags[i] = trans->tags[i];
210	else {
211		XGetClassHint(dpy, c->win, &ch);
212		snprintf(prop, sizeof prop, "%s:%s:%s",
213				ch.res_class ? ch.res_class : "",
214				ch.res_name ? ch.res_name : "", c->name);
215		for(i = 0; i < len; i++)
216			if(regexps[i].propregex && !regexec(regexps[i].propregex, prop, 1, &tmp, 0)) {
217				c->isfloat = rule[i].isfloat;
218				for(j = 0; regexps[i].tagregex && j < ntags; j++) {
219					if(!regexec(regexps[i].tagregex, tags[j], 1, &tmp, 0)) {
220						matched = True;
221						c->tags[j] = True;
222					}
223				}
224			}
225		if(ch.res_class)
226			XFree(ch.res_class);
227		if(ch.res_name)
228			XFree(ch.res_name);
229	}
230	if(!matched)
231		for(i = 0; i < ntags; i++)
232			c->tags[i] = seltag[i];
233}
234
235void
236tag(Arg *arg) {
237	unsigned int i;
238
239	if(!sel)
240		return;
241	for(i = 0; i < ntags; i++)
242		sel->tags[i] = (arg->i == -1) ? True : False;
243	if(arg->i >= 0 && arg->i < ntags)
244		sel->tags[arg->i] = True;
245	arrange();
246}
247
248void
249togglefloat(Arg *arg) {
250	if(!sel || arrange == dofloat)
251		return;
252	sel->isfloat = !sel->isfloat;
253	arrange();
254}
255
256void
257toggletag(Arg *arg) {
258	unsigned int i;
259
260	if(!sel)
261		return;
262	sel->tags[arg->i] = !sel->tags[arg->i];
263	for(i = 0; i < ntags && !sel->tags[i]; i++);
264	if(i == ntags)
265		sel->tags[arg->i] = True;
266	arrange();
267}
268
269void
270togglemode(Arg *arg) {
271	arrange = (arrange == dofloat) ? dotile : dofloat;
272	if(sel)
273		arrange();
274	else
275		drawstatus();
276}
277
278void
279toggleview(Arg *arg) {
280	unsigned int i;
281
282	seltag[arg->i] = !seltag[arg->i];
283	for(i = 0; i < ntags && !seltag[i]; i++);
284	if(i == ntags)
285		seltag[arg->i] = True; /* cannot toggle last view */
286	arrange();
287}
288
289void
290view(Arg *arg) {
291	unsigned int i;
292
293	for(i = 0; i < ntags; i++)
294		seltag[i] = (arg->i == -1) ? True : False;
295	if(arg->i >= 0 && arg->i < ntags)
296		seltag[arg->i] = True;
297	arrange();
298}