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