JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
removed the _DWM_PROPERTIES handling, reverted ban/unban to XMoveWindow(), and change...
[dwm.git] / screen.c
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
10 typedef struct {
11         const char *symbol;
12         void (*arrange)(void);
13 } Layout;
14
15 typedef struct {
16         const char *prop;
17         const char *tags;
18         Bool isfloating;
19 } Rule;
20
21 typedef struct {
22         regex_t *propregex;
23         regex_t *tagregex;
24 } Regs;
25
26 TAGS
27 RULES
28
29 static unsigned int nrules = 0;
30 static unsigned int nlayouts = 0;
31 static unsigned int ltidx = 0; /* default */
32 static Regs *regs = NULL;
33
34 static unsigned int
35 idxoftag(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
44 static void
45 floating(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
53 LAYOUTS
54
55 /* extern */
56
57 unsigned int blw = 0;
58
59 void
60 applyrules(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
91 void
92 arrange(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
105 void
106 compileregs(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
132 void
133 focusnext(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
147 void
148 focusprev(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
164 const char *
165 getsymbol(void)
166 {
167         return layouts[ltidx].symbol;
168 }
169
170 void
171 initlayouts(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
182 Bool
183 isfloating(void) {
184         return layouts[ltidx].arrange == floating;
185 }
186
187 Bool
188 isarrange(void (*func)())
189 {
190         return func == layouts[ltidx].arrange;
191 }
192
193 Bool
194 isvisible(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
203 Client *
204 nexttiled(Client *c) {
205         for(; c && (c->isfloating || !isvisible(c)); c = c->next);
206         return c;
207 }
208
209 void
210 restack(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
238 void
239 setlayout(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
260 void
261 tag(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
274 void
275 togglebar(const char *arg) {
276         if(bpos == BarOff)
277                 bpos = (BARPOS == BarOff) ? BarTop : BARPOS;
278         else
279                 bpos = BarOff;
280         updatebarpos();
281         arrange();
282 }
283
284 void
285 togglefloating(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
294 void
295 togglemax(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
313 void
314 toggletag(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
327 void
328 toggleview(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
339 void
340 updatebarpos(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
365 void
366 view(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 }