JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
4e97f0985c60d3ddd8bf01137cf3a75fb6325739
[dwm.git] / screen.c
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
12 void (*arrange)(void) = DEFMODE;
13 unsigned int master = MASTER;
14 unsigned int nmaster = NMASTER;
15
16 /* static */
17
18 typedef struct {
19         const char *prop;
20         const char *tags;
21         Bool isfloat;
22 } Rule;
23
24 typedef struct {
25         regex_t *propregex;
26         regex_t *tagregex;
27 } Regexps;
28
29 TAGS
30 RULES
31
32 static Regexps *regexps = NULL;
33 static unsigned int len = 0;
34
35 /* extern */
36
37 void
38 compileregexps(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
64 void
65 dofloat(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
87 void
88 dotile(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
139 void
140 incnmaster(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
151 Bool
152 isvisible(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
161 void
162 resizemaster(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
176 void
177 restack(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
199 void
200 settags(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
235 void
236 tag(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
248 void
249 togglefloat(Arg *arg) {
250         if(!sel || arrange == dofloat)
251                 return;
252         sel->isfloat = !sel->isfloat;
253         arrange();
254 }
255
256 void
257 toggletag(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
269 void
270 togglemode(Arg *arg) {
271         arrange = (arrange == dofloat) ? dotile : dofloat;
272         if(sel)
273                 arrange();
274         else
275                 drawstatus();
276 }
277
278 void
279 toggleview(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
289 void
290 view(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 }