JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
yet another simplification of dotile()
[dwm.git] / view.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
7 #define MINDIM                  100
8
9 /* static */
10
11 static Client *
12 minclient(void) {
13         Client *c, *min;
14
15         if((clients && clients->isfloat) || arrange == dofloat)
16                 return clients; /* don't touch floating order */
17         for(min = c = clients; c; c = c->next)
18                 if(c->weight < min->weight)
19                         min = c;
20         return min;
21 }
22
23 static Client *
24 nexttiled(Client *c) {
25         for(c = getnext(c); c && c->isfloat; c = getnext(c->next));
26         return c;
27 }
28
29 static void
30 reorder(void) {
31         Client *c, *newclients, *tail;
32
33         newclients = tail = NULL;
34         while((c = minclient())) {
35                 detach(c);
36                 if(tail) {
37                         c->prev = tail;
38                         tail->next = c;
39                         tail = c;
40                 }
41                 else
42                         tail = newclients = c;
43         }
44         clients = newclients;
45 }
46
47 static void
48 togglemax(Client *c)
49 {
50         XEvent ev;
51         if((c->ismax = !c->ismax)) {
52                 c->rx = c->x; c->x = sx;
53                 c->ry = c->y; c->y = bh;
54                 c->rw = c->w; c->w = sw - 2 * BORDERPX;
55                 c->rh = c->h; c->h = sh - bh - 2 * BORDERPX;
56         }
57         else {
58                 c->x = c->rx;
59                 c->y = c->ry;
60                 c->w = c->rw;
61                 c->h = c->rh;
62         }
63         resize(c, True, TopLeft);
64         while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
65 }
66
67 /* extern */
68
69 void (*arrange)(Arg *) = DEFMODE;
70 StackPos stackpos = STACKPOS;
71
72 void
73 detach(Client *c) {
74         if(c->prev)
75                 c->prev->next = c->next;
76         if(c->next)
77                 c->next->prev = c->prev;
78         if(c == clients)
79                 clients = c->next;
80         c->next = c->prev = NULL;
81 }
82
83 void
84 dofloat(Arg *arg) {
85         Client *c;
86
87         for(c = clients; c; c = c->next) {
88                 if(isvisible(c)) {
89                         resize(c, True, TopLeft);
90                 }
91                 else
92                         ban(c);
93         }
94         if(!sel || !isvisible(sel)) {
95                 for(c = stack; c && !isvisible(c); c = c->snext);
96                 focus(c);
97         }
98         restack();
99 }
100
101 /* This algorithm is based on a (M)aster area and a (S)tacking area.
102  * It supports following arrangements:
103  *      SSMMM   MMMMM   MMMSS
104  *      SSMMM   SSSSS   MMMSS
105  */
106 void
107 dotile(Arg *arg) {
108         int i, n, stackw, stackh, tw, th;
109         Client *c;
110
111         for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
112                 n++;
113
114         if(stackpos == StackBottom) {
115                 stackw = sw;
116                 stackh = sh - bh - master;
117         }
118         else {
119                 stackw = sw - master;
120                 stackh = sh - bh;
121         }
122
123         tw = stackw;
124         if(n > 1)
125                 th = stackh / (n - 1);
126         else
127                 th = stackh;
128
129         for(i = 0, c = clients; c; c = c->next) {
130                 if(isvisible(c)) {
131                         if(c->isfloat) {
132                                 resize(c, True, TopLeft);
133                                 continue;
134                         }
135                         c->ismax = False;
136                         c->x = sx;
137                         c->y = sy + bh;
138                         if(n == 1) { /* only 1 window */
139                                 c->w = sw - 2 * BORDERPX;
140                                 c->h = sh - 2 * BORDERPX - bh;
141                         }
142                         else if(i == 0) { /* master window */
143                                 if(stackpos == StackLeft)
144                                         c->x += stackw;
145                                 switch(stackpos) {
146                                 case StackLeft:
147                                 case StackRight:
148                                         c->w = master - 2 * BORDERPX;
149                                         c->h = sh - bh - 2 * BORDERPX;
150                                         break;
151                                 case StackBottom:
152                                         c->w = sw - 2 * BORDERPX;
153                                         c->h = master - 2 * BORDERPX;
154                                         break;
155                                 }
156                         }
157                         else {  /* tile window */
158                                 if(stackpos == StackRight)
159                                         c->x += master;
160                                 if(th > bh) {
161                                         switch(stackpos) {
162                                         case StackLeft:
163                                         case StackRight:
164                                                 c->y = sy + (i - 1) * th + bh;
165                                                 if(i + 1 == n)
166                                                         c->h = sh - c->y - 2 * BORDERPX;
167                                                 break;
168                                         case StackBottom:
169                                                 c->y = sy + master + (i - 1) * th + bh;
170                                                 if(i + 1 == n)
171                                                         c->h = sh - c->y - 2 * BORDERPX;
172                                                 break;
173                                         }
174                                         c->w = tw - 2 * BORDERPX;
175                                         c->h = th - 2 * BORDERPX;
176                                 }
177                                 else { /* fallback if th < bh */
178                                         if(stackpos == StackBottom)
179                                                 c->y += master;
180                                         c->w = stackw - 2 * BORDERPX;
181                                         c->h = stackh - 2 * BORDERPX;
182                                 }
183                         }
184                         resize(c, False, TopLeft);
185                         i++;
186                 }
187                 else
188                         ban(c);
189         }
190         if(!sel || !isvisible(sel)) {
191                 for(c = stack; c && !isvisible(c); c = c->snext);
192                 focus(c);
193         }
194         restack();
195 }
196
197 void
198 focusnext(Arg *arg) {
199         Client *c;
200    
201         if(!sel)
202                 return;
203
204         if(!(c = getnext(sel->next)))
205                 c = getnext(clients);
206         if(c) {
207                 focus(c);
208                 restack();
209         }
210 }
211
212 void
213 focusprev(Arg *arg) {
214         Client *c;
215
216         if(!sel)
217                 return;
218
219         if(!(c = getprev(sel->prev))) {
220                 for(c = clients; c && c->next; c = c->next);
221                 c = getprev(c);
222         }
223         if(c) {
224                 focus(c);
225                 restack();
226         }
227 }
228
229 Bool
230 isvisible(Client *c) {
231         unsigned int i;
232
233         for(i = 0; i < ntags; i++)
234                 if(c->tags[i] && seltag[i])
235                         return True;
236         return False;
237 }
238
239 void
240 resizecol(Arg *arg) {
241         int s;
242         unsigned int n;
243         Client *c;
244
245         for(n = 0, c = clients; c; c = c->next)
246                 if(isvisible(c) && !c->isfloat)
247                         n++;
248         if(!sel || sel->isfloat || n < 2 || (arrange == dofloat))
249                 return;
250
251         s = stackpos == StackBottom ? sh - bh : sw;
252         if(sel == getnext(clients)) {
253                 if(master + arg->i > s - MINDIM || master + arg->i < MINDIM)
254                         return;
255                 master += arg->i;
256         }
257         else {
258                 if(master - arg->i > s - MINDIM || master - arg->i < MINDIM)
259                         return;
260                 master -= arg->i;
261         }
262         arrange(NULL);
263 }
264
265 void
266 restack(void) {
267         Client *c;
268         XEvent ev;
269
270         if(!sel) {
271                 drawstatus();
272                 return;
273         }
274         if(sel->isfloat || arrange == dofloat) {
275                 XRaiseWindow(dpy, sel->win);
276                 XRaiseWindow(dpy, sel->twin);
277         }
278         if(arrange != dofloat) {
279                 if(!sel->isfloat) {
280                         XLowerWindow(dpy, sel->twin);
281                         XLowerWindow(dpy, sel->win);
282                 }
283                 for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
284                         if(c == sel)
285                                 continue;
286                         XLowerWindow(dpy, c->twin);
287                         XLowerWindow(dpy, c->win);
288                 }
289         }
290         drawall();
291         XSync(dpy, False);
292         while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
293 }
294
295 void
296 togglemode(Arg *arg) {
297         arrange = (arrange == dofloat) ? dotile : dofloat;
298         if(sel)
299                 arrange(NULL);
300         else
301                 drawstatus();
302 }
303
304 void
305 toggleview(Arg *arg) {
306         unsigned int i;
307
308         seltag[arg->i] = !seltag[arg->i];
309         for(i = 0; i < ntags && !seltag[i]; i++);
310         if(i == ntags)
311                 seltag[arg->i] = True; /* cannot toggle last view */
312         reorder();
313         arrange(NULL);
314 }
315
316 void
317 togglestackpos(Arg *arg) {
318         if(arrange == dofloat)
319                 return;
320         if(stackpos == StackBottom)
321                 stackpos = STACKPOS;
322         else
323                 stackpos = StackBottom;
324         master = ((stackpos == StackBottom ? sh - bh : sw) * MASTER) / 100;
325         arrange(NULL);
326 }
327
328 void
329 view(Arg *arg) {
330         unsigned int i;
331
332         for(i = 0; i < ntags; i++)
333                 seltag[i] = False;
334         seltag[arg->i] = True;
335         reorder();
336         arrange(NULL);
337 }
338
339 void
340 viewall(Arg *arg) {
341         unsigned int i;
342
343         for(i = 0; i < ntags; i++)
344                 seltag[i] = True;
345         reorder();
346         arrange(NULL);
347 }
348
349
350
351 void
352 zoom(Arg *arg) {
353         unsigned int n;
354         Client *c;
355
356         if(!sel)
357                 return;
358
359         if(sel->isfloat || (arrange == dofloat)) {
360                 togglemax(sel);
361                 return;
362         }
363
364         for(n = 0, c = clients; c; c = c->next)
365                 if(isvisible(c) && !c->isfloat)
366                         n++;
367         if(n < 2 || (arrange == dofloat))
368                 return;
369
370         if((c = sel) == nexttiled(clients))
371                 if(!(c = nexttiled(c->next)))
372                         return;
373         detach(c);
374         if(clients)
375                 clients->prev = c;
376         c->next = clients;
377         clients = c;
378         focus(c);
379         arrange(NULL);
380 }