JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
fixed issue pointed out by Jukka
[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 /* static */
8
9 static Client *
10 minclient() {
11         Client *c, *min;
12
13         if((clients && clients->isfloat) || arrange == dofloat)
14                 return clients; /* don't touch floating order */
15         for(min = c = clients; c; c = c->next)
16                 if(c->weight < min->weight)
17                         min = c;
18         return min;
19 }
20
21 static void
22 reorder() {
23         Client *c, *newclients, *tail;
24
25         newclients = tail = NULL;
26         while((c = minclient())) {
27                 detach(c);
28                 if(tail) {
29                         c->prev = tail;
30                         tail->next = c;
31                         tail = c;
32                 }
33                 else
34                         tail = newclients = c;
35         }
36         clients = newclients;
37 }
38
39 static Client *
40 nexttiled(Client *c) {
41         for(c = getnext(c); c && c->isfloat; c = getnext(c->next));
42         return c;
43 }
44
45 /* extern */
46
47 void (*arrange)(Arg *) = DEFMODE;
48
49 void
50 detach(Client *c) {
51         if(c->prev)
52                 c->prev->next = c->next;
53         if(c->next)
54                 c->next->prev = c->prev;
55         if(c == clients)
56                 clients = c->next;
57         c->next = c->prev = NULL;
58 }
59
60 void
61 dofloat(Arg *arg) {
62         Client *c;
63
64         for(c = clients; c; c = c->next) {
65                 if(isvisible(c)) {
66                         resize(c, True, TopLeft);
67                 }
68                 else
69                         ban(c);
70         }
71         if(!sel || !isvisible(sel)) {
72                 for(c = stack; c && !isvisible(c); c = c->snext);
73                 focus(c);
74         }
75         restack();
76 }
77
78 void
79 dotile(Arg *arg) {
80         int h, i, n, w;
81         Client *c;
82
83         w = sw - mw;
84         for(n = 0, c = clients; c; c = c->next)
85                 if(isvisible(c) && !c->isfloat)
86                         n++;
87
88         if(n > 1)
89                 h = (sh - bh) / (n - 1);
90         else
91                 h = sh - bh;
92
93         for(i = 0, c = clients; c; c = c->next) {
94                 if(isvisible(c)) {
95                         if(c->isfloat) {
96                                 resize(c, True, TopLeft);
97                                 continue;
98                         }
99                         if(n == 1) {
100                                 c->x = sx;
101                                 c->y = sy + bh;
102                                 c->w = sw - 2;
103                                 c->h = sh - 2 - bh;
104                         }
105                         else if(i == 0) {
106                                 c->x = sx;
107                                 c->y = sy + bh;
108                                 c->w = mw - 2;
109                                 c->h = sh - 2 - bh;
110                         }
111                         else if(h > bh) {
112                                 c->x = sx + mw;
113                                 c->y = sy + (i - 1) * h + bh;
114                                 c->w = w - 2;
115                                 if(i + 1 == n)
116                                         c->h = sh - c->y - 2;
117                                 else
118                                         c->h = h - 2;
119                         }
120                         else { /* fallback if h < bh */
121                                 c->x = sx + mw;
122                                 c->y = sy + bh;
123                                 c->w = w - 2;
124                                 c->h = sh - 2 - bh;
125                         }
126                         resize(c, False, TopLeft);
127                         i++;
128                 }
129                 else
130                         ban(c);
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 focusnext(Arg *arg) {
141         Client *c;
142    
143         if(!sel)
144                 return;
145
146         if(!(c = getnext(sel->next)))
147                 c = getnext(clients);
148         if(c) {
149                 focus(c);
150                 restack();
151         }
152 }
153
154 void
155 focusprev(Arg *arg) {
156         Client *c;
157
158         if(!sel)
159                 return;
160
161         if(!(c = getprev(sel->prev))) {
162                 for(c = clients; c && c->next; c = c->next);
163                 c = getprev(c);
164         }
165         if(c) {
166                 focus(c);
167                 restack();
168         }
169 }
170
171 Bool
172 isvisible(Client *c) {
173         unsigned int i;
174
175         for(i = 0; i < ntags; i++)
176                 if(c->tags[i] && seltag[i])
177                         return True;
178         return False;
179 }
180
181 void
182 resizecol(Arg *arg) {
183         unsigned int n;
184         Client *c;
185
186         for(n = 0, c = clients; c; c = c->next)
187                 if(isvisible(c) && !c->isfloat)
188                         n++;
189         if(!sel || sel->isfloat || n < 2 || (arrange != dotile))
190                 return;
191
192         if(sel == getnext(clients)) {
193                 if(mw + arg->i > sw - 100 || mw + arg->i < 100)
194                         return;
195                 mw += arg->i;
196         }
197         else {
198                 if(mw - arg->i > sw - 100 || mw - arg->i < 100)
199                         return;
200                 mw -= arg->i;
201         }
202         arrange(NULL);
203 }
204
205 void
206 restack() {
207         Client *c;
208         XEvent ev;
209         
210         if(!sel) {
211                 drawstatus();
212                 return;
213         }
214         if(sel->isfloat || arrange == dofloat) {
215                 XRaiseWindow(dpy, sel->win);
216                 XRaiseWindow(dpy, sel->twin);
217         }
218         if(arrange != dofloat)
219                 for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
220                         XLowerWindow(dpy, c->twin);
221                         XLowerWindow(dpy, c->win);
222                 }
223         drawall();
224         XSync(dpy, False);
225         while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
226 }
227
228 void
229 togglemode(Arg *arg) {
230         arrange = (arrange == dofloat) ? dotile : dofloat;
231         if(sel)
232                 arrange(NULL);
233         else
234                 drawstatus();
235 }
236
237 void
238 toggleview(Arg *arg) {
239         unsigned int i;
240
241         seltag[arg->i] = !seltag[arg->i];
242         for(i = 0; i < ntags && !seltag[i]; i++);
243         if(i == ntags)
244                 seltag[arg->i] = True; /* cannot toggle last view */
245         reorder();
246         arrange(NULL);
247 }
248
249 void
250 view(Arg *arg) {
251         unsigned int i;
252
253         for(i = 0; i < ntags; i++)
254                 seltag[i] = False;
255         seltag[arg->i] = True;
256         reorder();
257         arrange(NULL);
258 }
259
260 void
261 viewall(Arg *arg) {
262         unsigned int i;
263
264         for(i = 0; i < ntags; i++)
265                 seltag[i] = True;
266         reorder();
267         arrange(NULL);
268 }
269
270 void
271 zoom(Arg *arg) {
272         int tmp;
273         unsigned int n;
274         Client *c;
275         XEvent ev;
276
277         if(!sel)
278                 return;
279
280         if(sel->isfloat || (arrange == dofloat)) {
281                 sel->x = sx;
282                 sel->y = bh;
283                 sel->w = sw;
284                 sel->h = sh - bh;
285                 resize(sel, True, TopLeft);
286                 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
287                 return;
288         }
289
290         for(n = 0, c = clients; c; c = c->next)
291                 if(isvisible(c) && !c->isfloat)
292                         n++;
293         if(n < 2 || (arrange != dotile))
294                 return;
295
296         if((c = sel) == nexttiled(clients))
297                 if(!(c = nexttiled(c->next)))
298                         return;
299         detach(c);
300         if(clients)
301                 clients->prev = c;
302         c->next = clients;
303         clients = c;
304         focus(c);
305         arrange(NULL);
306 }