JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
added missing arrange
[dwm.git] / tag.c
1 /*
2  * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
3  * See LICENSE file for license details.
4  */
5 #include "dwm.h"
6 #include <regex.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/types.h>
11 #include <X11/Xutil.h>
12
13
14 typedef struct {
15         const char *clpattern;
16         const char *tpattern;
17         Bool isfloat;
18 } Rule;
19
20 typedef struct {
21         regex_t *clregex;
22         regex_t *tregex;
23 } RReg;
24
25 /* static */
26
27 TAGS
28 RULES
29
30 static RReg *rreg = NULL;
31 static unsigned int len = 0;
32
33 void (*arrange)(Arg *) = DEFMODE;
34
35 /* extern */
36
37 void
38 dofloat(Arg *arg)
39 {
40         Client *c;
41
42         for(c = clients; c; c = c->next) {
43                 c->ismax = False;
44                 if(isvisible(c)) {
45                         resize(c, True, TopLeft);
46                 }
47                 else
48                         ban(c);
49         }
50         if((sel = getnext(clients))) {
51                 focus(sel);
52                 restack();
53         }
54         else
55                 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
56 }
57
58 void
59 dotile(Arg *arg)
60 {
61         int h, i, n, w;
62         Client *c;
63
64         w = sw - mw;
65         for(n = 0, c = clients; c; c = c->next)
66                 if(isvisible(c) && !c->isfloat)
67                         n++;
68
69         if(n > 1)
70                 h = (sh - bh) / (n - 1);
71         else
72                 h = sh - bh;
73
74         for(i = 0, c = clients; c; c = c->next) {
75                 c->ismax = False;
76                 if(isvisible(c)) {
77                         if(c->isfloat) {
78                                 resize(c, True, TopLeft);
79                                 continue;
80                         }
81                         if(n == 1) {
82                                 c->x = sx;
83                                 c->y = sy + bh;
84                                 c->w = sw - 2;
85                                 c->h = sh - 2 - bh;
86                         }
87                         else if(i == 0) {
88                                 c->x = sx;
89                                 c->y = sy + bh;
90                                 c->w = mw - 2;
91                                 c->h = sh - 2 - bh;
92                         }
93                         else if(h > bh) {
94                                 c->x = sx + mw;
95                                 c->y = sy + (i - 1) * h + bh;
96                                 c->w = w - 2;
97                                 if(i + 1 == n)
98                                         c->h = sh - c->y - 2;
99                                 else
100                                         c->h = h - 2;
101                         }
102                         else { /* fallback if h < bh */
103                                 c->x = sx + mw;
104                                 c->y = sy + bh;
105                                 c->w = w - 2;
106                                 c->h = sh - 2 - bh;
107                         }
108                         resize(c, False, TopLeft);
109                         i++;
110                 }
111                 else
112                         ban(c);
113         }
114         if((sel = getnext(clients)))
115                 focus(sel);
116         else
117                 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
118         restack();
119 }
120
121 Client *
122 getnext(Client *c)
123 {
124         for(; c && !isvisible(c); c = c->next);
125         return c;
126 }
127
128 Client *
129 getprev(Client *c)
130 {
131         for(; c && !isvisible(c); c = c->prev);
132         return c;
133 }
134
135 void
136 initrregs()
137 {
138         unsigned int i;
139         regex_t *reg;
140
141         if(rreg)
142                 return;
143         len = sizeof(rule) / sizeof(rule[0]);
144         rreg = emallocz(len * sizeof(RReg));
145
146         for(i = 0; i < len; i++) {
147                 if(rule[i].clpattern) {
148                         reg = emallocz(sizeof(regex_t));
149                         if(regcomp(reg, rule[i].clpattern, 0))
150                                 free(reg);
151                         else
152                                 rreg[i].clregex = reg;
153                 }
154                 if(rule[i].tpattern) {
155                         reg = emallocz(sizeof(regex_t));
156                         if(regcomp(reg, rule[i].tpattern, 0))
157                                 free(reg);
158                         else
159                                 rreg[i].tregex = reg;
160                 }
161         }
162 }
163
164 Bool
165 isvisible(Client *c)
166 {
167         unsigned int i;
168
169         for(i = 0; i < ntags; i++)
170                 if(c->tags[i] && seltag[i])
171                         return True;
172         return False;
173 }
174
175 void
176 restack()
177 {
178         static unsigned int nwins = 0;
179         static Window *wins = NULL;
180         unsigned int f, fi, m, mi, n;
181         Client *c;
182         XEvent ev;
183
184         for(f = 0, m = 0, c = clients; c; c = c->next)
185                 if(isvisible(c)) {
186                         if(c->isfloat || arrange == dofloat)
187                                 f++;
188                         else
189                                 m++;
190                 }
191         if(!(n = 2 * (f + m))) {
192                 drawstatus();
193                 return;
194         }
195         if(nwins < n) {
196                 nwins = n;
197                 wins = erealloc(wins, nwins * sizeof(Window));
198         }
199
200         fi = 0;
201         mi = 2 * f;
202         if(sel->isfloat || arrange == dofloat) {
203                 wins[fi++] = sel->title;
204                 wins[fi++] = sel->win;
205         }
206         else {
207                 wins[mi++] = sel->title;
208                 wins[mi++] = sel->win;
209         }
210         for(c = clients; c; c = c->next)
211                 if(isvisible(c) && c != sel) {
212                         if(c->isfloat || arrange == dofloat) {
213                                 wins[fi++] = c->title;
214                                 wins[fi++] = c->win;
215                         }
216                         else {
217                                 wins[mi++] = c->title;
218                                 wins[mi++] = c->win;
219                         }
220                 }
221         XRestackWindows(dpy, wins, n);
222         drawall();
223         XSync(dpy, False);
224         while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
225 }
226
227 void
228 settags(Client *c)
229 {
230         char classinst[256];
231         unsigned int i, j;
232         regmatch_t tmp;
233         Bool matched = False;
234         XClassHint ch;
235
236         if(XGetClassHint(dpy, c->win, &ch)) {
237                 snprintf(classinst, sizeof(classinst), "%s:%s",
238                                 ch.res_class ? ch.res_class : "",
239                                 ch.res_name ? ch.res_name : "");
240                 for(i = 0; !matched && i < len; i++)
241                         if(rreg[i].clregex && !regexec(rreg[i].clregex, classinst, 1, &tmp, 0)) {
242                                 c->isfloat = rule[i].isfloat;
243                                 for(j = 0; rreg[i].tregex && j < ntags; j++) {
244                                         if(!regexec(rreg[i].tregex, tags[j], 1, &tmp, 0)) {
245                                                 matched = True;
246                                                 c->tags[j] = True;
247                                         }
248                                 }
249                         }
250                 if(ch.res_class)
251                         XFree(ch.res_class);
252                 if(ch.res_name)
253                         XFree(ch.res_name);
254         }
255         if(!matched)
256                 for(i = 0; i < ntags; i++)
257                         c->tags[i] = seltag[i];
258 }
259
260 void
261 tag(Arg *arg)
262 {
263         unsigned int i;
264
265         if(!sel)
266                 return;
267
268         for(i = 0; i < ntags; i++)
269                 sel->tags[i] = False;
270         sel->tags[arg->i] = True;
271         settitle(sel);
272         arrange(NULL);
273 }
274
275 void
276 togglemode(Arg *arg)
277 {
278         arrange = arrange == dofloat ? dotile : dofloat;
279         arrange(NULL);
280 }
281
282 void
283 toggletag(Arg *arg)
284 {
285         unsigned int i;
286
287         if(!sel)
288                 return;
289
290         sel->tags[arg->i] = !sel->tags[arg->i];
291         for(i = 0; i < ntags && !sel->tags[i]; i++);
292         if(i == ntags)
293                 sel->tags[arg->i] = True;
294         settitle(sel);
295 }
296
297
298 void
299 toggleview(Arg *arg)
300 {
301         unsigned int i;
302
303         seltag[arg->i] = !seltag[arg->i];
304         for(i = 0; i < ntags && !seltag[i]; i++);
305         if(i == ntags)
306                 seltag[arg->i] = True; /* cannot toggle last view */
307         arrange(NULL);
308 }
309
310 void
311 view(Arg *arg)
312 {
313         unsigned int i;
314
315         for(i = 0; i < ntags; i++)
316                 seltag[i] = False;
317         seltag[arg->i] = True;
318         arrange(NULL);
319 }