JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
b475d35d12e44e68ccc55d0e8a8320ca9859b55d
[dwm.git] / layout.c
1 /* See LICENSE file for copyright and license details. */
2 #include "dwm.h"
3 #include <stdio.h>
4 #include <stdlib.h>
5
6 unsigned int blw = 0;
7 Layout *lt = NULL;
8
9 /* static */
10
11 static double hratio = HRATIO;
12 static double vratio = VRATIO;
13 static unsigned int nlayouts = 0;
14 static unsigned int nmaster = NMASTER;
15
16 static double /* simple pow() */
17 spow(double x, double y)
18 {
19         if(y == 0)
20                 return 1;
21         while(--y)
22                 x *= x;
23         return x;
24 }
25
26 static void
27 tile(void) {
28         double mscale = 0, tscale = 0, sum = 0;
29         unsigned int i, n, nx, ny, nw, nh, mw, tw;
30         Client *c;
31
32         for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
33                 n++;
34
35         mw = (n <= nmaster) ? waw :  waw / (1 + hratio);
36         tw = waw - mw;
37
38         if(n > 0) {
39                 if(n < nmaster) {
40                         for(i = 0; i < n; i++)
41                                 sum += spow(vratio, i);
42                         mscale = wah / sum;
43                 }
44                 else {
45                         for(i = 0; i < nmaster; i++)
46                                 sum += spow(vratio, i);
47                         mscale = wah / sum;
48                         for(sum = 0, i = 0; i < (n - nmaster); i++)
49                                 sum += spow(vratio, i);
50                         tscale = wah / sum;
51                 }
52         }
53         nx = wax;
54         ny = way;
55         for(i = 0, c = clients; c; c = c->next)
56                 if(isvisible(c)) {
57                         unban(c);
58                         if(c->isfloating)
59                                 continue;
60                         c->ismax = False;
61                         if(i < nmaster) { /* master window */
62                                 nw = mw - 2 * c->border;
63                                 if(i + 1 == n || i + 1 == nmaster)
64                                         nh = (way + wah) - ny - (2 * c->border);
65                                 else
66                                         nh = (mscale * spow(vratio, i)) - (2 * c->border);
67                         }
68                         else { /* tile window */
69                                 if(i == nmaster) {
70                                         ny = way;
71                                         nx = wax + mw;
72                                 }
73                                 nw = tw - 2 * c->border;
74                                 if(i + 1 == n)
75                                         nh = (way + wah) - ny - (2 * c->border);
76                                 else
77                                         nh = (tscale * spow(vratio, i - nmaster)) - (2 * c->border);
78                         }
79                         if(nh < bh) {
80                                 nh = bh;
81                                 ny = way + wah - nh;
82                         }
83                         resize(c, nx, ny, nw, nh, False);
84                         ny += nh;
85                         i++;
86                 }
87                 else
88                         ban(c);
89         focus(NULL);
90         restack();
91 }
92
93 LAYOUTS
94
95 static void
96 incratio(const char *arg, double *ratio, double def) {
97         double delta;
98
99         if(lt->arrange != tile)
100                 return;
101         if(!arg)
102                 *ratio = def;
103         else {
104                 if(1 == sscanf(arg, "%lf", &delta)) {
105                         if(delta + (*ratio) < .1 || delta + (*ratio) > 1.9)
106                                 return;
107                         *ratio += delta;
108                 }
109         }
110         lt->arrange();
111 }
112
113 /* extern */
114
115 void
116 floating(void) {
117         Client *c;
118
119         for(c = clients; c; c = c->next)
120                 if(isvisible(c)) {
121                         unban(c);
122                         resize(c, c->x, c->y, c->w, c->h, True);
123                 }
124                 else
125                         ban(c);
126         focus(NULL);
127         restack();
128 }
129
130 void
131 focusclient(const char *arg) {
132         Client *c;
133    
134         if(!sel || !arg)
135                 return;
136         if(atoi(arg) < 0) {
137                 for(c = sel->prev; c && !isvisible(c); c = c->prev);
138                 if(!c) {
139                         for(c = clients; c && c->next; c = c->next);
140                         for(; c && !isvisible(c); c = c->prev);
141                 }
142         }
143         else {
144                 for(c = sel->next; c && !isvisible(c); c = c->next);
145                 if(!c)
146                         for(c = clients; c && !isvisible(c); c = c->next);
147         }
148         if(c) {
149                 focus(c);
150                 restack();
151         }
152 }
153
154 void
155 inchratio(const char *arg) {
156         incratio(arg, &hratio, HRATIO);
157 }
158
159 void
160 incvratio(const char *arg) {
161         incratio(arg, &vratio, VRATIO);
162 }
163
164 void
165 incnmaster(const char *arg) {
166         int i;
167
168         if(!arg)
169                 nmaster = NMASTER;
170         else {
171                 i = atoi(arg);
172                 if((lt->arrange != tile) || (nmaster + i < 1)
173                 || (wah / (nmaster + i) <= 2 * BORDERPX))
174                         return;
175                 nmaster += i;
176         }
177         if(sel)
178                 lt->arrange();
179         else
180                 drawstatus();
181 }
182
183 void
184 initlayouts(void) {
185         unsigned int i, w;
186
187         lt = &layout[0];
188         nlayouts = sizeof layout / sizeof layout[0];
189         for(blw = i = 0; i < nlayouts; i++) {
190                 w = textw(layout[i].symbol);
191                 if(w > blw)
192                         blw = w;
193         }
194 }
195
196 Client *
197 nexttiled(Client *c) {
198         for(; c && (c->isfloating || !isvisible(c)); c = c->next);
199         return c;
200 }
201
202 void
203 restack(void) {
204         Client *c;
205         XEvent ev;
206         XWindowChanges wc;
207
208         drawstatus();
209         if(!sel)
210                 return;
211         if(sel->isfloating || lt->arrange == floating)
212                 XRaiseWindow(dpy, sel->win);
213         if(lt->arrange != floating) {
214                 wc.stack_mode = Below;
215                 wc.sibling = barwin;
216                 if(!sel->isfloating) {
217                         XConfigureWindow(dpy, sel->win, CWSibling | CWStackMode, &wc);
218                         wc.sibling = sel->win;
219                 }
220                 for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
221                         if(c == sel)
222                                 continue;
223                         XConfigureWindow(dpy, c->win, CWSibling | CWStackMode, &wc);
224                         wc.sibling = c->win;
225                 }
226         }
227         XSync(dpy, False);
228         while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
229 }
230
231 void
232 setlayout(const char *arg) {
233         int i;
234
235         if(!arg) {
236                 lt++;
237                 if(lt == layout + nlayouts)
238                         lt = layout;
239         }
240         else {
241                 i = atoi(arg);
242                 if(i < 0 || i >= nlayouts)
243                         return;
244                 lt = &layout[i];
245         }
246         if(sel)
247                 lt->arrange();
248         else
249                 drawstatus();
250 }
251
252 void
253 togglebar(const char *arg) {
254         if(bpos == BarOff)
255                 bpos = (BARPOS == BarOff) ? BarTop : BARPOS;
256         else
257                 bpos = BarOff;
258         updatebarpos();
259         lt->arrange();
260 }
261
262 void
263 togglemax(const char *arg) {
264         XEvent ev;
265
266         if(!sel || (lt->arrange != floating && !sel->isfloating) || sel->isfixed)
267                 return;
268         if((sel->ismax = !sel->ismax)) {
269                 sel->rx = sel->x;
270                 sel->ry = sel->y;
271                 sel->rw = sel->w;
272                 sel->rh = sel->h;
273                 resize(sel, wax, way, waw - 2 * sel->border, wah - 2 * sel->border, True);
274         }
275         else
276                 resize(sel, sel->rx, sel->ry, sel->rw, sel->rh, True);
277         drawstatus();
278         while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
279 }
280
281 void
282 zoom(const char *arg) {
283         Client *c;
284
285         if(!sel || lt->arrange == floating || sel->isfloating)
286                 return;
287         if((c = sel) == nexttiled(clients))
288                 if(!(c = nexttiled(c->next)))
289                         return;
290         detach(c);
291         attach(c);
292         focus(c);
293         lt->arrange();
294 }