93a8c66a4283b3870b6909ff6b6d8e97e873857a
[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                         if(n == 1) { /* only 1 window */
137                                 c->x = sx;
138                                 c->y = sy + bh;
139                                 c->w = sw - 2 * BORDERPX;
140                                 c->h = sh - 2 * BORDERPX - bh;
141                         }
142                         else if(i == 0) { /* master window */
143                                 c->x = sx;
144                                 if(stackpos == StackLeft)
145                                         c->x += stackw;
146                                 c->y = sy + bh;
147                                 switch(stackpos) {
148                                 case StackLeft:
149                                 case StackRight:
150                                         c->w = master - 2 * BORDERPX;
151                                         c->h = sh - bh - 2 * BORDERPX;
152                                         break;
153                                 case StackBottom:
154                                         c->w = sw - 2 * BORDERPX;
155                                         c->h = master - 2 * BORDERPX;
156                                         break;
157                                 }
158                         }
159                         else if(th > bh) { /* tile window */
160                                 c->x = sx;
161                                 if(stackpos == StackRight)
162                                         c->x += master;
163                                 c->w = tw - 2 * BORDERPX;
164                                 c->h = th - 2 * BORDERPX;
165                                 switch(stackpos) {
166                                 case StackLeft:
167                                 case StackRight:
168                                         c->y = sy + (i - 1) * th + bh;
169                                         if(i + 1 == n)
170                                                 c->h = sh - c->y - 2 * BORDERPX;
171                                         break;
172                                 case StackBottom:
173                                         c->y = sy + master + (i - 1) * th + bh;
174                                         if(i + 1 == n)
175                                                 c->h = sh - c->y - 2 * BORDERPX;
176                                         break;
177                                 }
178                         }
179                         else { /* fallback if th < bh */
180                                 c->x = sx;
181                                 if(stackpos == StackRight)
182                                         c->x += master;
183                                 c->y = sy + bh;
184                                 if(stackpos == StackBottom)
185                                         c->y += master;
186                                 c->w = stackw - 2 * BORDERPX;
187                                 c->h = stackh - 2 * BORDERPX;
188                         }
189                         resize(c, False, TopLeft);
190                         i++;
191                 }
192                 else
193                         ban(c);
194         }
195         if(!sel || !isvisible(sel)) {
196                 for(c = stack; c && !isvisible(c); c = c->snext);
197                 focus(c);
198         }
199         restack();
200 }
201
202 void
203 focusnext(Arg *arg) {
204         Client *c;
205    
206         if(!sel)
207                 return;
208
209         if(!(c = getnext(sel->next)))
210                 c = getnext(clients);
211         if(c) {
212                 focus(c);
213                 restack();
214         }
215 }
216
217 void
218 focusprev(Arg *arg) {
219         Client *c;
220
221         if(!sel)
222                 return;
223
224         if(!(c = getprev(sel->prev))) {
225                 for(c = clients; c && c->next; c = c->next);
226                 c = getprev(c);
227         }
228         if(c) {
229                 focus(c);
230                 restack();
231         }
232 }
233
234 Bool
235 isvisible(Client *c) {
236         unsigned int i;
237
238         for(i = 0; i < ntags; i++)
239                 if(c->tags[i] && seltag[i])
240                         return True;
241         return False;
242 }
243
244 void
245 resizecol(Arg *arg) {
246         int s;
247         unsigned int n;
248         Client *c;
249
250         for(n = 0, c = clients; c; c = c->next)
251                 if(isvisible(c) && !c->isfloat)
252                         n++;
253         if(!sel || sel->isfloat || n < 2 || (arrange == dofloat))
254                 return;
255
256         s = stackpos == StackBottom ? sh - bh : sw;
257         if(sel == getnext(clients)) {
258                 if(master + arg->i > s - MINDIM || master + arg->i < MINDIM)
259                         return;
260                 master += arg->i;
261         }
262         else {
263                 if(master - arg->i > s - MINDIM || master - arg->i < MINDIM)
264                         return;
265                 master -= arg->i;
266         }
267         arrange(NULL);
268 }
269
270 void
271 restack(void) {
272         Client *c;
273         XEvent ev;
274
275         if(!sel) {
276                 drawstatus();
277                 return;
278         }
279         if(sel->isfloat || arrange == dofloat) {
280                 XRaiseWindow(dpy, sel->win);
281                 XRaiseWindow(dpy, sel->twin);
282         }
283         if(arrange != dofloat) {
284                 if(!sel->isfloat) {
285                         XLowerWindow(dpy, sel->twin);
286                         XLowerWindow(dpy, sel->win);
287                 }
288                 for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
289                         if(c == sel)
290                                 continue;
291                         XLowerWindow(dpy, c->twin);
292                         XLowerWindow(dpy, c->win);
293                 }
294         }
295         drawall();
296         XSync(dpy, False);
297         while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
298 }
299
300 void
301 togglemode(Arg *arg) {
302         arrange = (arrange == dofloat) ? dotile : dofloat;
303         if(sel)
304                 arrange(NULL);
305         else
306                 drawstatus();
307 }
308
309 void
310 toggleview(Arg *arg) {
311         unsigned int i;
312
313         seltag[arg->i] = !seltag[arg->i];
314         for(i = 0; i < ntags && !seltag[i]; i++);
315         if(i == ntags)
316                 seltag[arg->i] = True; /* cannot toggle last view */
317         reorder();
318         arrange(NULL);
319 }
320
321 void
322 togglestackpos(Arg *arg) {
323         if(arrange == dofloat)
324                 return;
325         if(stackpos == StackBottom)
326                 stackpos = STACKPOS;
327         else
328                 stackpos = StackBottom;
329         master = ((stackpos == StackBottom ? sh - bh : sw) * MASTER) / 100;
330         arrange(NULL);
331 }
332
333 void
334 view(Arg *arg) {
335         unsigned int i;
336
337         for(i = 0; i < ntags; i++)
338                 seltag[i] = False;
339         seltag[arg->i] = True;
340         reorder();
341         arrange(NULL);
342 }
343
344 void
345 viewall(Arg *arg) {
346         unsigned int i;
347
348         for(i = 0; i < ntags; i++)
349                 seltag[i] = True;
350         reorder();
351         arrange(NULL);
352 }
353
354
355
356 void
357 zoom(Arg *arg) {
358         unsigned int n;
359         Client *c;
360
361         if(!sel)
362                 return;
363
364         if(sel->isfloat || (arrange == dofloat)) {
365                 togglemax(sel);
366                 return;
367         }
368
369         for(n = 0, c = clients; c; c = c->next)
370                 if(isvisible(c) && !c->isfloat)
371                         n++;
372         if(n < 2 || (arrange == dofloat))
373                 return;
374
375         if((c = sel) == nexttiled(clients))
376                 if(!(c = nexttiled(c->next)))
377                         return;
378         detach(c);
379         if(clients)
380                 clients->prev = c;
381         c->next = clients;
382         clients = c;
383         focus(c);
384         arrange(NULL);
385 }