11 |
11 |
12 #include "dwm.h" |
12 #include "dwm.h" |
13 |
13 |
14 static void (*arrange)(Arg *) = floating; |
14 static void (*arrange)(Arg *) = floating; |
15 |
15 |
|
16 static void |
|
17 center(Client *c) |
|
18 { |
|
19 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w / 2, c->h / 2); |
|
20 } |
|
21 |
16 static Client * |
22 static Client * |
17 next(Client *c) |
23 next(Client *c) |
18 { |
24 { |
19 for(c = c->next; c && !c->tags[tsel]; c = c->next); |
25 for(; c && !c->tags[tsel]; c = c->next); |
20 return c; |
26 return c; |
21 } |
27 } |
22 |
28 |
23 static Client * |
29 void |
24 prev(Client *c) |
30 zoom(Arg *arg) |
25 { |
31 { |
26 for(c = c->prev; c && !c->tags[tsel]; c = c->prev); |
32 Client **l; |
27 return c; |
33 |
|
34 if(!sel) |
|
35 return; |
|
36 |
|
37 for(l = &clients; *l && *l != sel; l = &(*l)->next); |
|
38 *l = sel->next; |
|
39 |
|
40 sel->next = clients; /* pop */ |
|
41 clients = sel; |
|
42 arrange(NULL); |
|
43 center(sel); |
|
44 focus(sel); |
28 } |
45 } |
29 |
46 |
30 void |
47 void |
31 max(Arg *arg) |
48 max(Arg *arg) |
32 { |
49 { |
33 if(!csel) |
50 if(!sel) |
34 return; |
51 return; |
35 csel->x = sx; |
52 sel->x = sx; |
36 csel->y = sy; |
53 sel->y = sy; |
37 csel->w = sw - 2 * csel->border; |
54 sel->w = sw - 2 * sel->border; |
38 csel->h = sh - 2 * csel->border; |
55 sel->h = sh - 2 * sel->border; |
39 craise(csel); |
56 craise(sel); |
40 resize(csel); |
57 resize(sel); |
41 discard_events(EnterWindowMask); |
58 discard_events(EnterWindowMask); |
42 } |
59 } |
43 |
60 |
44 void |
61 void |
|
62 view(Arg *arg) |
|
63 { |
|
64 tsel = arg->i; |
|
65 arrange(NULL); |
|
66 } |
|
67 |
|
68 void |
45 tag(Arg *arg) |
69 tag(Arg *arg) |
46 { |
70 { |
47 if(!csel) |
71 int i, n; |
48 return; |
72 if(!sel) |
49 |
73 return; |
50 if(arg->i == tsel) |
74 |
51 return; |
75 if(arg->i == tsel) { |
52 |
76 for(n = i = 0; i < TLast; i++) |
53 if(csel->tags[arg->i]) |
77 if(sel->tags[i]) |
54 csel->tags[arg->i] = NULL; /* toggle tag */ |
78 n++; |
55 else |
79 if(n < 2) |
56 csel->tags[arg->i] = tags[arg->i]; |
80 return; |
|
81 } |
|
82 |
|
83 if(sel->tags[arg->i]) |
|
84 sel->tags[arg->i] = NULL; /* toggle tag */ |
|
85 else |
|
86 sel->tags[arg->i] = tags[arg->i]; |
57 arrange(NULL); |
87 arrange(NULL); |
58 } |
88 } |
59 |
89 |
|
90 static void |
|
91 ban_client(Client *c) |
|
92 { |
|
93 XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y); |
|
94 XMoveWindow(dpy, c->title, c->tx + 2 * sw, c->ty); |
|
95 } |
|
96 |
60 void |
97 void |
61 floating(Arg *arg) |
98 floating(Arg *arg) |
62 { |
99 { |
63 Client *c; |
100 Client *c; |
64 |
101 |
65 arrange = floating; |
102 arrange = floating; |
66 if(!csel) |
103 for(c = clients; c; c = c->next) { |
67 return; |
104 if(c->tags[tsel]) |
68 for(c = csel; c; c = next(c)) |
105 resize(c); |
69 resize(c); |
106 else |
|
107 ban_client(c); |
|
108 } |
|
109 if(sel && !sel->tags[tsel]) { |
|
110 if((sel = next(clients))) { |
|
111 craise(sel); |
|
112 focus(sel); |
|
113 } |
|
114 } |
70 discard_events(EnterWindowMask); |
115 discard_events(EnterWindowMask); |
71 } |
116 } |
72 |
117 |
73 void |
118 void |
74 tiling(Arg *arg) |
119 tiling(Arg *arg) |
76 Client *c; |
121 Client *c; |
77 int n, cols, rows, gw, gh, i, j; |
122 int n, cols, rows, gw, gh, i, j; |
78 float rt, fd; |
123 float rt, fd; |
79 |
124 |
80 arrange = tiling; |
125 arrange = tiling; |
81 if(!csel) |
126 for(n = 0, c = clients; c; c = next(c->next), n++); |
82 return; |
127 if(n) { |
83 for(n = 0, c = csel; c; c = next(c), n++); |
128 rt = sqrt(n); |
84 rt = sqrt(n); |
129 if(modff(rt, &fd) < 0.5) |
85 if(modff(rt, &fd) < 0.5) |
130 rows = floor(rt); |
86 rows = floor(rt); |
131 else |
87 else |
132 rows = ceil(rt); |
88 rows = ceil(rt); |
133 if(rows * rows < n) |
89 if(rows * rows < n) |
134 cols = rows + 1; |
90 cols = rows + 1; |
135 else |
91 else |
136 cols = rows; |
92 cols = rows; |
137 |
93 |
138 gw = (sw - 2) / cols; |
94 gw = (sw - 2) / cols; |
139 gh = (sh - 2) / rows; |
95 gh = (sh - 2) / rows; |
140 } |
96 |
141 else |
97 for(i = j = 0, c = csel; c; c = next(c)) { |
142 cols = rows = gw = gh = 0; |
98 c->x = i * gw; |
143 |
99 c->y = j * gh; |
144 for(i = j = 0, c = clients; c; c = c->next) { |
100 c->w = gw; |
145 if(c->tags[tsel]) { |
101 c->h = gh; |
146 c->x = i * gw; |
102 resize(c); |
147 c->y = j * gh; |
103 if(++i == cols) { |
148 c->w = gw; |
104 j++; |
149 c->h = gh; |
105 i = 0; |
150 resize(c); |
|
151 if(++i == cols) { |
|
152 j++; |
|
153 i = 0; |
|
154 } |
106 } |
155 } |
|
156 else |
|
157 ban_client(c); |
|
158 } |
|
159 if(sel && !sel->tags[tsel]) { |
|
160 if((sel = next(clients))) { |
|
161 craise(sel); |
|
162 focus(sel); |
|
163 } |
107 } |
164 } |
108 discard_events(EnterWindowMask); |
165 discard_events(EnterWindowMask); |
109 } |
166 } |
110 |
167 |
111 void |
168 void |
112 prevc(Arg *arg) |
169 prevc(Arg *arg) |
113 { |
170 { |
114 Client *c; |
171 Client *c; |
115 |
172 |
116 if(!csel) |
173 if(!sel) |
117 return; |
174 return; |
118 |
175 |
119 if(!(c = prev(csel))) |
176 if((c = sel->revert && sel->revert->tags[tsel] ? sel->revert : NULL)) { |
120 c = prev(cend); |
177 craise(c); |
|
178 center(c); |
|
179 focus(c); |
|
180 } |
|
181 } |
|
182 |
|
183 void |
|
184 nextc(Arg *arg) |
|
185 { |
|
186 Client *c; |
|
187 |
|
188 if(!sel) |
|
189 return; |
|
190 |
|
191 if(!(c = next(sel->next))) |
|
192 c = next(clients); |
121 if(c) { |
193 if(c) { |
122 craise(c); |
194 craise(c); |
123 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w / 2, c->h / 2); |
195 center(c); |
|
196 c->revert = sel; |
124 focus(c); |
197 focus(c); |
125 } |
198 } |
126 } |
199 } |
127 |
200 |
128 void |
201 void |
129 nextc(Arg *arg) |
|
130 { |
|
131 Client *c; |
|
132 |
|
133 if(!csel) |
|
134 return; |
|
135 |
|
136 if(!(c = next(csel))) |
|
137 c = next(cstart); |
|
138 |
|
139 if(c) { |
|
140 craise(c); |
|
141 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w / 2, c->h / 2); |
|
142 focus(c); |
|
143 } |
|
144 } |
|
145 |
|
146 void |
|
147 ckill(Arg *arg) |
202 ckill(Arg *arg) |
148 { |
203 { |
149 Client *c = csel; |
204 if(!sel) |
150 |
205 return; |
151 if(!c) |
206 if(sel->proto & WM_PROTOCOL_DELWIN) |
152 return; |
207 send_message(sel->win, wm_atom[WMProtocols], wm_atom[WMDelete]); |
153 if(c->proto & WM_PROTOCOL_DELWIN) |
208 else |
154 send_message(c->win, wm_atom[WMProtocols], wm_atom[WMDelete]); |
209 XKillClient(dpy, sel->win); |
155 else |
|
156 XKillClient(dpy, c->win); |
|
157 } |
210 } |
158 |
211 |
159 static void |
212 static void |
160 resize_title(Client *c) |
213 resize_title(Client *c) |
161 { |
214 { |
254 } |
307 } |
255 |
308 |
256 void |
309 void |
257 focus(Client *c) |
310 focus(Client *c) |
258 { |
311 { |
259 if(csel && csel != c) { |
312 if(sel && sel != c) { |
260 XSetWindowBorder(dpy, csel->win, dc.bg); |
313 XSetWindowBorder(dpy, sel->win, dc.bg); |
261 XMapWindow(dpy, csel->title); |
314 XMapWindow(dpy, sel->title); |
262 draw_client(csel); |
315 draw_client(sel); |
263 } |
316 } |
264 csel = c; |
317 sel = c; |
265 XUnmapWindow(dpy, c->title); |
318 XUnmapWindow(dpy, c->title); |
266 XSetWindowBorder(dpy, c->win, dc.fg); |
319 XSetWindowBorder(dpy, c->win, dc.fg); |
267 draw_client(c); |
320 draw_client(c); |
268 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); |
321 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); |
269 XFlush(dpy); |
322 XFlush(dpy); |
271 } |
324 } |
272 |
325 |
273 void |
326 void |
274 manage(Window w, XWindowAttributes *wa) |
327 manage(Window w, XWindowAttributes *wa) |
275 { |
328 { |
276 Client *c; |
329 Client *c, **l; |
277 XSetWindowAttributes twa; |
330 XSetWindowAttributes twa; |
278 |
331 |
279 c = emallocz(sizeof(Client)); |
332 c = emallocz(sizeof(Client)); |
280 c->win = w; |
333 c->win = w; |
281 c->tx = c->x = wa->x; |
334 c->tx = c->x = wa->x; |
282 c->ty = c->y = wa->y; |
335 c->ty = c->y = wa->y; |
283 c->tw = c->w = wa->width; |
336 c->tw = c->w = wa->width; |
284 c->h = wa->height; |
337 c->h = wa->height; |
285 c->th = th; |
338 c->th = th; |
286 c->border = 1; |
339 c->border = 1; |
|
340 c->proto = win_proto(c->win); |
287 update_size(c); |
341 update_size(c); |
288 XSelectInput(dpy, c->win, |
342 XSelectInput(dpy, c->win, |
289 StructureNotifyMask | PropertyChangeMask | EnterWindowMask); |
343 StructureNotifyMask | PropertyChangeMask | EnterWindowMask); |
290 XGetTransientForHint(dpy, c->win, &c->trans); |
344 XGetTransientForHint(dpy, c->win, &c->trans); |
291 twa.override_redirect = 1; |
345 twa.override_redirect = 1; |
298 DefaultVisual(dpy, screen), |
352 DefaultVisual(dpy, screen), |
299 CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa); |
353 CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa); |
300 |
354 |
301 update_name(c); |
355 update_name(c); |
302 |
356 |
303 if(!cstart) |
357 for(l = &clients; *l; l = &(*l)->next); |
304 cstart = cend = c; |
358 c->next = *l; /* *l == nil */ |
305 else { |
359 *l = c; |
306 cend->next = c; |
|
307 c->prev = cend; |
|
308 cend = c; |
|
309 } |
|
310 |
360 |
311 XSetWindowBorderWidth(dpy, c->win, 1); |
361 XSetWindowBorderWidth(dpy, c->win, 1); |
312 XMapRaised(dpy, c->win); |
362 XMapRaised(dpy, c->win); |
313 XMapRaised(dpy, c->title); |
363 XMapRaised(dpy, c->title); |
314 XGrabButton(dpy, Button1, Mod1Mask, c->win, False, ButtonPressMask, |
364 XGrabButton(dpy, Button1, Mod1Mask, c->win, False, ButtonPressMask, |
316 XGrabButton(dpy, Button2, Mod1Mask, c->win, False, ButtonPressMask, |
366 XGrabButton(dpy, Button2, Mod1Mask, c->win, False, ButtonPressMask, |
317 GrabModeAsync, GrabModeSync, None, None); |
367 GrabModeAsync, GrabModeSync, None, None); |
318 XGrabButton(dpy, Button3, Mod1Mask, c->win, False, ButtonPressMask, |
368 XGrabButton(dpy, Button3, Mod1Mask, c->win, False, ButtonPressMask, |
319 GrabModeAsync, GrabModeSync, None, None); |
369 GrabModeAsync, GrabModeSync, None, None); |
320 arrange(NULL); |
370 arrange(NULL); |
321 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w / 2, c->h / 2); |
371 center(c); |
322 focus(c); |
372 focus(c); |
323 } |
373 } |
324 |
374 |
325 void |
375 void |
326 gravitate(Client *c, Bool invert) |
376 gravitate(Client *c, Bool invert) |
418 } |
468 } |
419 |
469 |
420 void |
470 void |
421 unmanage(Client *c) |
471 unmanage(Client *c) |
422 { |
472 { |
|
473 Client **l; |
|
474 |
423 XGrabServer(dpy); |
475 XGrabServer(dpy); |
424 XSetErrorHandler(dummy_error_handler); |
476 XSetErrorHandler(dummy_error_handler); |
425 |
477 |
426 XUngrabButton(dpy, AnyButton, AnyModifier, c->win); |
478 XUngrabButton(dpy, AnyButton, AnyModifier, c->win); |
427 XDestroyWindow(dpy, c->title); |
479 XDestroyWindow(dpy, c->title); |
428 |
480 |
429 if(c->prev) { |
481 for(l = &clients; *l && *l != c; l = &(*l)->next); |
430 c->prev->next = c->next; |
482 *l = c->next; |
431 if(csel == c) |
483 for(l = &clients; *l; l = &(*l)->next) |
432 csel = c->prev; |
484 if((*l)->revert == c) |
433 } |
485 (*l)->revert = NULL; |
434 if(c->next) { |
486 if(sel == c) |
435 c->next->prev = c->prev; |
487 sel = sel->revert ? sel->revert : clients; |
436 if(csel == c) |
|
437 csel = c->next; |
|
438 } |
|
439 if(cstart == c) |
|
440 cstart = c->next; |
|
441 if(cend == c) |
|
442 cend = c->prev; |
|
443 |
488 |
444 free(c); |
489 free(c); |
445 |
490 |
446 XFlush(dpy); |
491 XFlush(dpy); |
447 XSetErrorHandler(error_handler); |
492 XSetErrorHandler(error_handler); |
448 XUngrabServer(dpy); |
493 XUngrabServer(dpy); |
449 arrange(NULL); |
494 arrange(NULL); |
450 if(csel) |
495 if(sel) |
451 focus(csel); |
496 focus(sel); |
452 } |
497 } |
453 |
498 |
454 Client * |
499 Client * |
455 gettitle(Window w) |
500 gettitle(Window w) |
456 { |
501 { |
457 Client *c; |
502 Client *c; |
458 for(c = cstart; c; c = c->next) |
503 for(c = clients; c; c = c->next) |
459 if(c->title == w) |
504 if(c->title == w) |
460 return c; |
505 return c; |
461 return NULL; |
506 return NULL; |
462 } |
507 } |
463 |
508 |
464 Client * |
509 Client * |
465 getclient(Window w) |
510 getclient(Window w) |
466 { |
511 { |
467 Client *c; |
512 Client *c; |
468 for(c = cstart; c; c = c->next) |
513 for(c = clients; c; c = c->next) |
469 if(c->win == w) |
514 if(c->win == w) |
470 return c; |
515 return c; |
471 return NULL; |
516 return NULL; |
472 } |
517 } |
473 |
518 |
474 void |
519 void |
475 draw_client(Client *c) |
520 draw_client(Client *c) |
476 { |
521 { |
477 int i; |
522 int i; |
478 if(c == csel) |
523 if(c == sel) |
479 return; |
524 return; |
480 |
525 |
481 dc.x = dc.y = 0; |
526 dc.x = dc.y = 0; |
482 dc.h = c->th; |
527 dc.h = c->th; |
483 |
528 |