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