all repos — dwm @ 64871a7045077bb2ec4cbcd62a74cabbe6b45096

fork of suckless dynamic window manager

view.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
 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
 62compileregexps(void) {
 63	unsigned int i;
 64	regex_t *reg;
 65
 66	if(regexps)
 67		return;
 68	len = sizeof rule / sizeof rule[0];
 69	regexps = emallocz(len * sizeof(Regexps));
 70	for(i = 0; i < len; i++) {
 71		if(rule[i].prop) {
 72			reg = emallocz(sizeof(regex_t));
 73			if(regcomp(reg, rule[i].prop, REG_EXTENDED))
 74				free(reg);
 75			else
 76				regexps[i].propregex = reg;
 77		}
 78		if(rule[i].tags) {
 79			reg = emallocz(sizeof(regex_t));
 80			if(regcomp(reg, rule[i].tags, REG_EXTENDED))
 81				free(reg);
 82			else
 83				regexps[i].tagregex = reg;
 84		}
 85	}
 86}
 87
 88void
 89dofloat(void) {
 90	Client *c;
 91
 92	for(c = clients; c; c = c->next) {
 93		if(isvisible(c)) {
 94			if(c->isbanned)
 95				XMoveWindow(dpy, c->win, c->x, c->y);
 96			c->isbanned = False;
 97			resize(c, c->x, c->y, c->w, c->h, True);
 98		}
 99		else {
100			c->isbanned = True;
101			XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
102		}
103	}
104	if(!sel || !isvisible(sel)) {
105		for(c = stack; c && !isvisible(c); c = c->snext);
106		focus(c);
107	}
108	restack();
109}
110void
111dotile(void) {
112	unsigned int i, n, nx, ny, nw, nh, mw, mh, tw, th;
113	Client *c;
114
115	for(n = 0, c = nextmanaged(clients); c; c = nextmanaged(c->next))
116		n++;
117	/* window geoms */
118	mh = (n > nmaster) ? wah / nmaster : wah / (n > 0 ? n : 1);
119	mw = (n > nmaster) ? (waw * master) / 1000 : waw;
120	th = (n > nmaster) ? wah / (n - nmaster) : 0;
121	tw = waw - mw;
122
123	for(i = 0, c = clients; c; c = c->next)
124		if(isvisible(c)) {
125			if(c->isbanned)
126				XMoveWindow(dpy, c->win, c->x, c->y);
127			c->isbanned = False;
128			if(c->isfloat)
129				continue;
130			c->ismax = False;
131			nx = wax;
132			ny = way;
133			if(i < nmaster) {
134				ny += i * mh;
135				nw = mw - 2 * BORDERPX;
136				nh = mh - 2 * BORDERPX;
137			}
138			else {  /* tile window */
139				nx += mw;
140				nw = tw - 2 * BORDERPX;
141				if(th > 2 * BORDERPX) {
142					ny += (i - nmaster) * th;
143					nh = th - 2 * BORDERPX;
144				}
145				else /* fallback if th <= 2 * BORDERPX */
146					nh = wah - 2 * BORDERPX;
147			}
148			resize(c, nx, ny, nw, nh, False);
149			i++;
150		}
151		else {
152			c->isbanned = True;
153			XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
154		}
155	if(!sel || !isvisible(sel)) {
156		for(c = stack; c && !isvisible(c); c = c->snext);
157		focus(c);
158	}
159	restack();
160}
161
162void
163incnmaster(Arg *arg) {
164	if((arrange == dofloat) || (nmaster + arg->i < 1)
165	|| (wah / (nmaster + arg->i) <= 2 * BORDERPX))
166		return;
167	nmaster += arg->i;
168	if(sel)
169		arrange();
170	else
171		drawstatus();
172}
173
174Bool
175isvisible(Client *c) {
176	unsigned int i;
177
178	for(i = 0; i < ntags; i++)
179		if(c->tags[i] && seltag[i])
180			return True;
181	return False;
182}
183
184void
185resizemaster(Arg *arg) {
186	if(arrange != dotile)
187		return;
188	if(arg->i == 0)
189		master = MASTER;
190	else {
191		if(waw * (master + arg->i) / 1000 >= waw - 2 * BORDERPX
192		|| waw * (master + arg->i) / 1000 <= 2 * BORDERPX)
193			return;
194		master += arg->i;
195	}
196	arrange();
197}
198
199void
200restack(void) {
201	Client *c;
202	XEvent ev;
203
204	drawstatus();
205	if(!sel)
206		return;
207	if(sel->isfloat || arrange == dofloat)
208		XRaiseWindow(dpy, sel->win);
209	if(arrange != dofloat) {
210		if(!sel->isfloat)
211			XLowerWindow(dpy, sel->win);
212		for(c = nextmanaged(clients); c; c = nextmanaged(c->next)) {
213			if(c == sel)
214				continue;
215			XLowerWindow(dpy, c->win);
216		}
217	}
218	XSync(dpy, False);
219	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
220}
221
222void
223settags(Client *c, Client *trans) {
224	char prop[512];
225	unsigned int i, j;
226	regmatch_t tmp;
227	Bool matched = trans != NULL;
228	XClassHint ch = { 0 };
229
230	if(matched)
231		for(i = 0; i < ntags; i++)
232			c->tags[i] = trans->tags[i];
233	else {
234		XGetClassHint(dpy, c->win, &ch);
235		snprintf(prop, sizeof prop, "%s:%s:%s",
236				ch.res_class ? ch.res_class : "",
237				ch.res_name ? ch.res_name : "", c->name);
238		for(i = 0; i < len; i++)
239			if(regexps[i].propregex && !regexec(regexps[i].propregex, prop, 1, &tmp, 0)) {
240				c->isfloat = rule[i].isfloat;
241				for(j = 0; regexps[i].tagregex && j < ntags; j++) {
242					if(!regexec(regexps[i].tagregex, tags[j], 1, &tmp, 0)) {
243						matched = True;
244						c->tags[j] = True;
245					}
246				}
247			}
248		if(ch.res_class)
249			XFree(ch.res_class);
250		if(ch.res_name)
251			XFree(ch.res_name);
252	}
253	if(!matched)
254		for(i = 0; i < ntags; i++)
255			c->tags[i] = seltag[i];
256}
257
258void
259tag(Arg *arg) {
260	unsigned int i;
261
262	if(!sel)
263		return;
264	for(i = 0; i < ntags; i++)
265		sel->tags[i] = (arg->i == -1) ? True : False;
266	if(arg->i >= 0 && arg->i < ntags)
267		sel->tags[arg->i] = True;
268	arrange();
269}
270
271void
272togglefloat(Arg *arg) {
273	if(!sel || arrange == dofloat)
274		return;
275	sel->isfloat = !sel->isfloat;
276	arrange();
277}
278
279void
280toggletag(Arg *arg) {
281	unsigned int i;
282
283	if(!sel)
284		return;
285	sel->tags[arg->i] = !sel->tags[arg->i];
286	for(i = 0; i < ntags && !sel->tags[i]; i++);
287	if(i == ntags)
288		sel->tags[arg->i] = True;
289	arrange();
290}
291
292void
293togglemode(Arg *arg) {
294	arrange = (arrange == dofloat) ? dotile : dofloat;
295	if(sel)
296		arrange();
297	else
298		drawstatus();
299}
300
301void
302toggleview(Arg *arg) {
303	unsigned int i;
304
305	seltag[arg->i] = !seltag[arg->i];
306	for(i = 0; i < ntags && !seltag[i]; i++);
307	if(i == ntags)
308		seltag[arg->i] = True; /* cannot toggle last view */
309	arrange();
310}
311
312void
313view(Arg *arg) {
314	unsigned int i;
315
316	for(i = 0; i < ntags; i++)
317		seltag[i] = (arg->i == -1) ? True : False;
318	if(arg->i >= 0 && arg->i < ntags)
319		seltag[arg->i] = True;
320	arrange();
321}
322
323void
324zoom(Arg *arg) {
325	unsigned int n;
326	Client *c;
327
328	if(!sel)
329		return;
330	if(sel->isfloat || (arrange == dofloat)) {
331		togglemax(sel);
332		return;
333	}
334	for(n = 0, c = nextmanaged(clients); c; c = nextmanaged(c->next))
335		n++;
336
337	if((c = sel) == nextmanaged(clients))
338		if(!(c = nextmanaged(c->next)))
339			return;
340	detach(c);
341	attach(c);
342	focus(c);
343	arrange();
344}