all repos — dwm @ cdbc84b9a87c427b3d0a202475b0f5aae315fb90

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