Mercurial > hg > index.fcgi > dwm > dwm-3.6.1-10pba
comparison client.c @ 2:de6bb7885c97
add right-click eventon layout icon to go to previous layout
author | pang@hit-nxdomain.opendns.com |
---|---|
date | Tue, 24 Mar 2009 12:52:45 -0700 |
parents | |
children | a54de16f8277 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:b28d4f5cbf01 |
---|---|
1 /* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com> | |
2 * See LICENSE file for license details. | |
3 */ | |
4 #include "dwm.h" | |
5 #include <stdio.h> | |
6 #include <stdlib.h> | |
7 #include <string.h> | |
8 #include <X11/Xatom.h> | |
9 #include <X11/Xutil.h> | |
10 | |
11 /* static */ | |
12 | |
13 static void | |
14 attachstack(Client *c) { | |
15 c->snext = stack; | |
16 stack = c; | |
17 } | |
18 | |
19 static void | |
20 detachstack(Client *c) { | |
21 Client **tc; | |
22 | |
23 for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext); | |
24 *tc = c->snext; | |
25 } | |
26 | |
27 static void | |
28 grabbuttons(Client *c, Bool focused) { | |
29 XUngrabButton(dpy, AnyButton, AnyModifier, c->win); | |
30 | |
31 if(focused) { | |
32 XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK, | |
33 GrabModeAsync, GrabModeSync, None, None); | |
34 XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK, | |
35 GrabModeAsync, GrabModeSync, None, None); | |
36 XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False, BUTTONMASK, | |
37 GrabModeAsync, GrabModeSync, None, None); | |
38 XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK, | |
39 GrabModeAsync, GrabModeSync, None, None); | |
40 | |
41 XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK, | |
42 GrabModeAsync, GrabModeSync, None, None); | |
43 XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK, | |
44 GrabModeAsync, GrabModeSync, None, None); | |
45 XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False, BUTTONMASK, | |
46 GrabModeAsync, GrabModeSync, None, None); | |
47 XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK, | |
48 GrabModeAsync, GrabModeSync, None, None); | |
49 | |
50 XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK, | |
51 GrabModeAsync, GrabModeSync, None, None); | |
52 XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK, | |
53 GrabModeAsync, GrabModeSync, None, None); | |
54 XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False, BUTTONMASK, | |
55 GrabModeAsync, GrabModeSync, None, None); | |
56 XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK, | |
57 GrabModeAsync, GrabModeSync, None, None); | |
58 } | |
59 else | |
60 XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK, | |
61 GrabModeAsync, GrabModeSync, None, None); | |
62 } | |
63 | |
64 static Bool | |
65 isprotodel(Client *c) { | |
66 int i, n; | |
67 Atom *protocols; | |
68 Bool ret = False; | |
69 | |
70 if(XGetWMProtocols(dpy, c->win, &protocols, &n)) { | |
71 for(i = 0; !ret && i < n; i++) | |
72 if(protocols[i] == wmatom[WMDelete]) | |
73 ret = True; | |
74 XFree(protocols); | |
75 } | |
76 return ret; | |
77 } | |
78 | |
79 static void | |
80 setclientstate(Client *c, long state) { | |
81 long data[] = {state, None}; | |
82 | |
83 XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32, | |
84 PropModeReplace, (unsigned char *)data, 2); | |
85 } | |
86 | |
87 static void | |
88 togglemax(Client *c) { | |
89 XEvent ev; | |
90 | |
91 if(c->isfixed) | |
92 return; | |
93 if((c->ismax = !c->ismax)) { | |
94 c->rx = c->x; | |
95 c->ry = c->y; | |
96 c->rw = c->w; | |
97 c->rh = c->h; | |
98 resize(c, wax, way, waw - 2 * BORDERPX, wah - 2 * BORDERPX, True); | |
99 } | |
100 else | |
101 resize(c, c->rx, c->ry, c->rw, c->rh, True); | |
102 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); | |
103 } | |
104 | |
105 static int | |
106 xerrordummy(Display *dsply, XErrorEvent *ee) { | |
107 return 0; | |
108 } | |
109 | |
110 /* extern */ | |
111 | |
112 void | |
113 attach(Client *c) { | |
114 if(clients) | |
115 clients->prev = c; | |
116 c->next = clients; | |
117 clients = c; | |
118 } | |
119 | |
120 void | |
121 configure(Client *c) { | |
122 XConfigureEvent ce; | |
123 | |
124 ce.type = ConfigureNotify; | |
125 ce.display = dpy; | |
126 ce.event = c->win; | |
127 ce.window = c->win; | |
128 ce.x = c->x; | |
129 ce.y = c->y; | |
130 ce.width = c->w; | |
131 ce.height = c->h; | |
132 ce.border_width = c->border; | |
133 ce.above = None; | |
134 ce.override_redirect = False; | |
135 XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce); | |
136 } | |
137 | |
138 void | |
139 detach(Client *c) { | |
140 if(c->prev) | |
141 c->prev->next = c->next; | |
142 if(c->next) | |
143 c->next->prev = c->prev; | |
144 if(c == clients) | |
145 clients = c->next; | |
146 c->next = c->prev = NULL; | |
147 } | |
148 | |
149 void | |
150 focus(Client *c) { | |
151 if(c && !isvisible(c)) | |
152 return; | |
153 if(sel && sel != c) { | |
154 grabbuttons(sel, False); | |
155 XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]); | |
156 } | |
157 if(c) { | |
158 detachstack(c); | |
159 attachstack(c); | |
160 grabbuttons(c, True); | |
161 } | |
162 sel = c; | |
163 drawstatus(); | |
164 if(!selscreen) | |
165 return; | |
166 if(c) { | |
167 XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]); | |
168 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); | |
169 } | |
170 else | |
171 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); | |
172 } | |
173 | |
174 void | |
175 killclient(Arg *arg) { | |
176 if(!sel) | |
177 return; | |
178 if(isprotodel(sel)) | |
179 sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]); | |
180 else | |
181 XKillClient(dpy, sel->win); | |
182 } | |
183 | |
184 void | |
185 manage(Window w, XWindowAttributes *wa) { | |
186 Client *c, *t; | |
187 Window trans; | |
188 XWindowChanges wc; | |
189 | |
190 c = emallocz(sizeof(Client)); | |
191 c->tags = emallocz(ntags * sizeof(Bool)); | |
192 c->win = w; | |
193 c->x = wa->x; | |
194 c->y = wa->y; | |
195 c->w = wa->width; | |
196 c->h = wa->height; | |
197 if(c->w == sw && c->h == sh) { | |
198 c->border = 0; | |
199 c->x = sx; | |
200 c->y = sy; | |
201 } | |
202 else { | |
203 c->border = BORDERPX; | |
204 if(c->x > wax + waw && c-> w < waw) | |
205 c->x = wax + waw - c->w - 2 * c->border; | |
206 if(c->y > way + wah && c-> h < wah) | |
207 c->y = way + wah - c->h - 2 * c->border; | |
208 if(c->x < wax && c->w < waw) | |
209 c->x = wax; | |
210 if(c->y < way && c->h < wah) | |
211 c->y = way; | |
212 } | |
213 XSelectInput(dpy, w, | |
214 StructureNotifyMask | PropertyChangeMask | EnterWindowMask); | |
215 XGetTransientForHint(dpy, w, &trans); | |
216 grabbuttons(c, False); | |
217 wc.border_width = c->border; | |
218 XConfigureWindow(dpy, w, CWBorderWidth, &wc); | |
219 XSetWindowBorder(dpy, w, dc.norm[ColBorder]); | |
220 configure(c); /* propagates border_width, if size doesn't change */ | |
221 updatetitle(c); | |
222 for(t = clients; t && t->win != trans; t = t->next); | |
223 settags(c, t); | |
224 if(!c->isversatile) | |
225 c->isversatile = (t != NULL) || c->isfixed; | |
226 attach(c); | |
227 attachstack(c); | |
228 c->isbanned = True; | |
229 XMoveWindow(dpy, w, c->x + 2 * sw, c->y); | |
230 XMapWindow(dpy, w); | |
231 setclientstate(c, NormalState); | |
232 if(isvisible(c)) | |
233 focus(c); | |
234 updatesizehints(c); | |
235 lt->arrange(); | |
236 } | |
237 | |
238 void | |
239 resize(Client *c, int x, int y, int w, int h, Bool sizehints) { | |
240 float actual, dx, dy, max, min; | |
241 XWindowChanges wc; | |
242 | |
243 if(w <= 0 || h <= 0) | |
244 return; | |
245 if(sizehints) { | |
246 if(c->minw && w < c->minw) | |
247 w = c->minw; | |
248 if(c->minh && h < c->minh) | |
249 h = c->minh; | |
250 if(c->maxw && w > c->maxw) | |
251 w = c->maxw; | |
252 if(c->maxh && h > c->maxh) | |
253 h = c->maxh; | |
254 /* inspired by algorithm from fluxbox */ | |
255 if(c->minay > 0 && c->maxay && (h - c->baseh) > 0) { | |
256 dx = (float)(w - c->basew); | |
257 dy = (float)(h - c->baseh); | |
258 min = (float)(c->minax) / (float)(c->minay); | |
259 max = (float)(c->maxax) / (float)(c->maxay); | |
260 actual = dx / dy; | |
261 if(max > 0 && min > 0 && actual > 0) { | |
262 if(actual < min) { | |
263 dy = (dx * min + dy) / (min * min + 1); | |
264 dx = dy * min; | |
265 w = (int)dx + c->basew; | |
266 h = (int)dy + c->baseh; | |
267 } | |
268 else if(actual > max) { | |
269 dy = (dx * min + dy) / (max * max + 1); | |
270 dx = dy * min; | |
271 w = (int)dx + c->basew; | |
272 h = (int)dy + c->baseh; | |
273 } | |
274 } | |
275 } | |
276 if(c->incw) | |
277 w -= (w - c->basew) % c->incw; | |
278 if(c->inch) | |
279 h -= (h - c->baseh) % c->inch; | |
280 } | |
281 if(w == sw && h == sh) | |
282 c->border = 0; | |
283 else | |
284 c->border = BORDERPX; | |
285 /* offscreen appearance fixes */ | |
286 if(x > sw) | |
287 x = sw - w - 2 * c->border; | |
288 if(y > sh) | |
289 y = sh - h - 2 * c->border; | |
290 if(x + w + 2 * c->border < sx) | |
291 x = sx; | |
292 if(y + h + 2 * c->border < sy) | |
293 y = sy; | |
294 /* if(c->x != x || c->y != y || c->w != w || c->h != h) { */ | |
295 c->x = wc.x = x; | |
296 c->y = wc.y = y; | |
297 c->w = wc.width = w; | |
298 c->h = wc.height = h; | |
299 wc.border_width = c->border; | |
300 XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc); | |
301 configure(c); | |
302 XSync(dpy, False); | |
303 /* } */ | |
304 } | |
305 | |
306 void | |
307 toggleversatile(Arg *arg) { | |
308 if(!sel || lt->arrange == versatile) | |
309 return; | |
310 sel->isversatile = !sel->isversatile; | |
311 lt->arrange(); | |
312 } | |
313 | |
314 void | |
315 updatesizehints(Client *c) { | |
316 long msize; | |
317 XSizeHints size; | |
318 | |
319 if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags) | |
320 size.flags = PSize; | |
321 c->flags = size.flags; | |
322 if(c->flags & PBaseSize) { | |
323 c->basew = size.base_width; | |
324 c->baseh = size.base_height; | |
325 } | |
326 else | |
327 c->basew = c->baseh = 0; | |
328 if(c->flags & PResizeInc) { | |
329 c->incw = size.width_inc; | |
330 c->inch = size.height_inc; | |
331 } | |
332 else | |
333 c->incw = c->inch = 0; | |
334 if(c->flags & PMaxSize) { | |
335 c->maxw = size.max_width; | |
336 c->maxh = size.max_height; | |
337 } | |
338 else | |
339 c->maxw = c->maxh = 0; | |
340 if(c->flags & PMinSize) { | |
341 c->minw = size.min_width; | |
342 c->minh = size.min_height; | |
343 } | |
344 else | |
345 c->minw = c->minh = 0; | |
346 if(c->flags & PAspect) { | |
347 c->minax = size.min_aspect.x; | |
348 c->minay = size.min_aspect.y; | |
349 c->maxax = size.max_aspect.x; | |
350 c->maxay = size.max_aspect.y; | |
351 } | |
352 else | |
353 c->minax = c->minay = c->maxax = c->maxay = 0; | |
354 c->isfixed = (c->maxw && c->minw && c->maxh && c->minh | |
355 && c->maxw == c->minw && c->maxh == c->minh); | |
356 } | |
357 | |
358 void | |
359 updatetitle(Client *c) { | |
360 char **list = NULL; | |
361 int n; | |
362 XTextProperty name; | |
363 | |
364 name.nitems = 0; | |
365 c->name[0] = 0; | |
366 XGetTextProperty(dpy, c->win, &name, netatom[NetWMName]); | |
367 if(!name.nitems) | |
368 XGetWMName(dpy, c->win, &name); | |
369 if(!name.nitems) | |
370 return; | |
371 if(name.encoding == XA_STRING) | |
372 strncpy(c->name, (char *)name.value, sizeof c->name); | |
373 else { | |
374 if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success | |
375 && n > 0 && *list) | |
376 { | |
377 strncpy(c->name, *list, sizeof c->name); | |
378 XFreeStringList(list); | |
379 } | |
380 } | |
381 XFree(name.value); | |
382 } | |
383 | |
384 void | |
385 unmanage(Client *c) { | |
386 Client *nc; | |
387 | |
388 /* The server grab construct avoids race conditions. */ | |
389 XGrabServer(dpy); | |
390 XSetErrorHandler(xerrordummy); | |
391 detach(c); | |
392 detachstack(c); | |
393 if(sel == c) { | |
394 for(nc = stack; nc && !isvisible(nc); nc = nc->snext); | |
395 focus(nc); | |
396 } | |
397 XUngrabButton(dpy, AnyButton, AnyModifier, c->win); | |
398 setclientstate(c, WithdrawnState); | |
399 free(c->tags); | |
400 free(c); | |
401 XSync(dpy, False); | |
402 XSetErrorHandler(xerror); | |
403 XUngrabServer(dpy); | |
404 lt->arrange(); | |
405 } | |
406 | |
407 void | |
408 zoom(Arg *arg) { | |
409 unsigned int n; | |
410 Client *c; | |
411 | |
412 if(!sel) | |
413 return; | |
414 if(sel->isversatile || (lt->arrange == versatile)) { | |
415 togglemax(sel); | |
416 return; | |
417 } | |
418 for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next)) | |
419 n++; | |
420 if((c = sel) == nexttiled(clients)) | |
421 if(!(c = nexttiled(c->next))) | |
422 return; | |
423 detach(c); | |
424 attach(c); | |
425 focus(c); | |
426 lt->arrange(); | |
427 } | |
428 | |
429 Client * | |
430 prevtiled(Client *c) { | |
431 for(; c && (c->isversatile || !isvisible(c)); c = c->prev); | |
432 return c; | |
433 } | |
434 | |
435 void | |
436 pushup(Arg *arg) { | |
437 Client *c; | |
438 | |
439 if(!sel || sel->isversatile) | |
440 return; | |
441 if((c = prevtiled(sel->prev))) { | |
442 /* attach before c */ | |
443 detach(sel); | |
444 sel->next = c; | |
445 sel->prev = c->prev; | |
446 c->prev = sel; | |
447 if(sel->prev) | |
448 sel->prev->next = sel; | |
449 else | |
450 clients = sel; | |
451 } else { | |
452 /* move to the end */ | |
453 for(c = sel; c->next; c = c->next); | |
454 detach(sel); | |
455 sel->prev = c; | |
456 c->next = sel; | |
457 } | |
458 focus(sel); | |
459 lt->arrange(); | |
460 } | |
461 | |
462 void | |
463 pushdown(Arg *arg) { | |
464 Client *c; | |
465 | |
466 if(!sel || sel->isversatile) | |
467 return; | |
468 if((c = nexttiled(sel->next))) { | |
469 /* attach after c */ | |
470 detach(sel); | |
471 sel->prev = c; | |
472 sel->next = c->next; | |
473 c->next = sel; | |
474 if(sel->next) | |
475 sel->next->prev = sel; | |
476 } else { | |
477 /* move to the front */ | |
478 detach(sel); | |
479 attach(sel); | |
480 } | |
481 focus(sel); | |
482 lt->arrange(); | |
483 } | |
484 | |
485 void | |
486 moveresize(Arg *arg) { | |
487 int x, y, w, h, nx, ny, nw, nh, ox, oy, ow, oh; | |
488 char xAbs, yAbs, wAbs, hAbs; | |
489 int mx, my, dx, dy, nmx, nmy; | |
490 unsigned int dui; | |
491 Window dummy; | |
492 | |
493 if (lt->arrange != versatile) | |
494 if (!sel || !sel->isversatile || !arg) | |
495 return; | |
496 if(sscanf(arg->cmd, "%d%c %d%c %d%c %d%c", &x, &xAbs, &y, &yAbs, &w, &wAbs, &h, &hAbs) != 8) | |
497 return; | |
498 nx = xAbs == 'X' ? x : sel->x + x; | |
499 ny = yAbs == 'Y' ? y : sel->y + y; | |
500 nw = wAbs == 'W' ? w : sel->w + w; | |
501 nh = hAbs == 'H' ? h : sel->h + h; | |
502 | |
503 ox = sel->x; | |
504 oy = sel->y; | |
505 ow = sel->w; | |
506 oh = sel->h; | |
507 | |
508 Bool xqp = XQueryPointer(dpy, root, &dummy, &dummy, &mx, &my, &dx, &dy, &dui); | |
509 resize(sel, nx, ny, nw, nh, True); | |
510 if (xqp && ox <= mx && (ox + ow) >= mx && oy <= my && (oy + oh) >= my) | |
511 { | |
512 nmx = mx-ox+sel->w-ow-1 < 0 ? 0 : mx-ox+sel->w-ow-1; | |
513 nmy = my-oy+sel->h-oh-1 < 0 ? 0 : my-oy+sel->h-oh-1; | |
514 XWarpPointer(dpy, None, sel->win, 0, 0, 0, 0, nmx, nmy); | |
515 } | |
516 } | |
517 |