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