aewl
view client.c @ 63:f14858218641
searching for a better way to discard enter notifies
author | Anselm R. Garbe <garbeam@wmii.de> |
---|---|
date | Fri, 14 Jul 2006 13:03:53 +0200 |
parents | 0a4b066ce254 |
children | 50450aa24a46 |
line source
1 /*
2 * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
3 * See LICENSE file for license details.
4 */
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <X11/Xatom.h>
10 #include <X11/Xutil.h>
12 #include "dwm.h"
14 void (*arrange)(Arg *) = tiling;
16 static Rule rule[] = {
17 /* class instance tags floating */
18 { "Firefox-bin", "Gecko", { [Twww] = "www" }, False },
19 };
21 static Client *
22 next(Client *c)
23 {
24 for(; c && !c->tags[tsel]; c = c->next);
25 return c;
26 }
28 void
29 zoom(Arg *arg)
30 {
31 Client **l;
33 if(!sel)
34 return;
36 if(sel == next(clients))
37 sel = next(sel->next);
39 for(l = &clients; *l && *l != sel; l = &(*l)->next);
40 *l = sel->next;
42 sel->next = clients; /* pop */
43 clients = sel;
44 arrange(NULL);
45 focus(sel);
46 }
48 void
49 max(Arg *arg)
50 {
51 if(!sel)
52 return;
53 sel->x = sx;
54 sel->y = sy + bh;
55 sel->w = sw - 2 * sel->border;
56 sel->h = sh - 2 * sel->border - bh;
57 craise(sel);
58 resize(sel, False);
59 }
61 void
62 view(Arg *arg)
63 {
64 Client *c;
66 tsel = arg->i;
67 arrange(NULL);
69 for(c = clients; c; c = next(c->next))
70 draw_client(c);
71 draw_bar();
72 }
74 void
75 tappend(Arg *arg)
76 {
77 if(!sel)
78 return;
80 sel->tags[arg->i] = tags[arg->i];
81 arrange(NULL);
82 }
84 void
85 ttrunc(Arg *arg)
86 {
87 int i;
88 if(!sel)
89 return;
91 for(i = 0; i < TLast; i++)
92 sel->tags[i] = NULL;
93 tappend(arg);
94 }
96 static void
97 ban_client(Client *c)
98 {
99 XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
100 XMoveWindow(dpy, c->title, c->tx + 2 * sw, c->ty);
101 }
103 void
104 floating(Arg *arg)
105 {
106 Client *c;
108 arrange = floating;
109 for(c = clients; c; c = c->next) {
110 if(c->tags[tsel])
111 resize(c, True);
112 else
113 ban_client(c);
114 }
115 if(sel && !sel->tags[tsel]) {
116 if((sel = next(clients))) {
117 craise(sel);
118 focus(sel);
119 }
120 }
121 }
123 void
124 tiling(Arg *arg)
125 {
126 Client *c;
127 int n, i, w, h;
129 w = sw - mw;
130 arrange = tiling;
131 for(n = 0, c = clients; c; c = c->next)
132 if(c->tags[tsel] && !c->floating)
133 n++;
135 if(n > 1)
136 h = (sh - bh) / (n - 1);
137 else
138 h = sh - bh;
140 for(i = 0, c = clients; c; c = c->next) {
141 if(c->tags[tsel]) {
142 if(c->floating) {
143 craise(c);
144 resize(c, True);
145 continue;
146 }
147 if(n == 1) {
148 c->x = sx;
149 c->y = sy + bh;
150 c->w = sw - 2 * c->border;
151 c->h = sh - 2 * c->border - bh;
152 }
153 else if(i == 0) {
154 c->x = sx;
155 c->y = sy + bh;
156 c->w = mw - 2 * c->border;
157 c->h = sh - 2 * c->border - bh;
158 }
159 else {
160 c->x = sx + mw;
161 c->y = sy + (i - 1) * h + bh;
162 c->w = w - 2 * c->border;
163 c->h = h - 2 * c->border;
164 }
165 resize(c, False);
166 i++;
167 }
168 else
169 ban_client(c);
170 }
171 if(!sel || (sel && !sel->tags[tsel])) {
172 if((sel = next(clients))) {
173 craise(sel);
174 focus(sel);
175 }
176 }
177 }
179 void
180 prevc(Arg *arg)
181 {
182 Client *c;
184 if(!sel)
185 return;
187 if((c = sel->revert && sel->revert->tags[tsel] ? sel->revert : NULL)) {
188 craise(c);
189 focus(c);
190 }
191 }
193 void
194 nextc(Arg *arg)
195 {
196 Client *c;
198 if(!sel)
199 return;
201 if(!(c = next(sel->next)))
202 c = next(clients);
203 if(c) {
204 craise(c);
205 c->revert = sel;
206 focus(c);
207 }
208 }
210 void
211 ckill(Arg *arg)
212 {
213 if(!sel)
214 return;
215 if(sel->proto & WM_PROTOCOL_DELWIN)
216 send_message(sel->win, wm_atom[WMProtocols], wm_atom[WMDelete]);
217 else
218 XKillClient(dpy, sel->win);
219 }
221 static void
222 resize_title(Client *c)
223 {
224 int i;
226 c->tw = 0;
227 for(i = 0; i < TLast; i++)
228 if(c->tags[i])
229 c->tw += textw(c->tags[i]) + dc.font.height;
230 c->tw += textw(c->name) + dc.font.height;
231 if(c->tw > c->w)
232 c->tw = c->w + 2;
233 c->tx = c->x + c->w - c->tw + 2;
234 c->ty = c->y;
235 XMoveResizeWindow(dpy, c->title, c->tx, c->ty, c->tw, c->th);
236 }
238 void
239 update_name(Client *c)
240 {
241 XTextProperty name;
242 int n;
243 char **list = NULL;
245 name.nitems = 0;
246 c->name[0] = 0;
247 XGetTextProperty(dpy, c->win, &name, net_atom[NetWMName]);
248 if(!name.nitems)
249 XGetWMName(dpy, c->win, &name);
250 if(!name.nitems)
251 return;
252 if(name.encoding == XA_STRING)
253 strncpy(c->name, (char *)name.value, sizeof(c->name));
254 else {
255 if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
256 && n > 0 && *list)
257 {
258 strncpy(c->name, *list, sizeof(c->name));
259 XFreeStringList(list);
260 }
261 }
262 XFree(name.value);
263 resize_title(c);
264 }
266 void
267 update_size(Client *c)
268 {
269 XSizeHints size;
270 long msize;
271 if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
272 size.flags = PSize;
273 c->flags = size.flags;
274 if(c->flags & PBaseSize) {
275 c->basew = size.base_width;
276 c->baseh = size.base_height;
277 }
278 else
279 c->basew = c->baseh = 0;
280 if(c->flags & PResizeInc) {
281 c->incw = size.width_inc;
282 c->inch = size.height_inc;
283 }
284 else
285 c->incw = c->inch = 0;
286 if(c->flags & PMaxSize) {
287 c->maxw = size.max_width;
288 c->maxh = size.max_height;
289 }
290 else
291 c->maxw = c->maxh = 0;
292 if(c->flags & PMinSize) {
293 c->minw = size.min_width;
294 c->minh = size.min_height;
295 }
296 else
297 c->minw = c->minh = 0;
298 if(c->flags & PWinGravity)
299 c->grav = size.win_gravity;
300 else
301 c->grav = NorthWestGravity;
302 }
304 void
305 craise(Client *c)
306 {
307 XRaiseWindow(dpy, c->win);
308 XRaiseWindow(dpy, c->title);
309 }
311 void
312 lower(Client *c)
313 {
314 XLowerWindow(dpy, c->title);
315 XLowerWindow(dpy, c->win);
316 }
318 void
319 focus(Client *c)
320 {
321 Client *old = sel;
322 XEvent ev;
324 XFlush(dpy);
325 sel = c;
326 if(old && old != c)
327 draw_client(old);
328 draw_client(c);
329 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
330 XFlush(dpy);
331 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
332 }
334 static void
335 init_tags(Client *c)
336 {
337 XClassHint ch;
338 static unsigned int len = rule ? sizeof(rule) / sizeof(rule[0]) : 0;
339 unsigned int i, j;
340 Bool matched = False;
342 if(!len) {
343 c->tags[tsel] = tags[tsel];
344 return;
345 }
347 if(XGetClassHint(dpy, c->win, &ch)) {
348 if(ch.res_class && ch.res_name) {
349 for(i = 0; i < len; i++)
350 if(!strncmp(rule[i].class, ch.res_class, sizeof(rule[i].class))
351 && !strncmp(rule[i].instance, ch.res_name, sizeof(rule[i].instance)))
352 {
353 for(j = 0; j < TLast; j++)
354 c->tags[j] = rule[i].tags[j];
355 c->floating = rule[i].floating;
356 matched = True;
357 break;
358 }
359 }
360 if(ch.res_class)
361 XFree(ch.res_class);
362 if(ch.res_name)
363 XFree(ch.res_name);
364 }
366 if(!matched)
367 c->tags[tsel] = tags[tsel];
368 }
370 void
371 manage(Window w, XWindowAttributes *wa)
372 {
373 Client *c, **l;
374 XSetWindowAttributes twa;
375 Window trans;
377 c = emallocz(sizeof(Client));
378 c->win = w;
379 c->tx = c->x = wa->x;
380 c->ty = c->y = wa->y;
381 if(c->y < bh)
382 c->ty = c->y += bh;
383 c->tw = c->w = wa->width;
384 c->h = wa->height;
385 c->th = bh;
386 c->border = 1;
387 c->proto = win_proto(c->win);
388 update_size(c);
389 XSelectInput(dpy, c->win,
390 StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
391 XGetTransientForHint(dpy, c->win, &trans);
392 twa.override_redirect = 1;
393 twa.background_pixmap = ParentRelative;
394 twa.event_mask = ExposureMask;
396 c->title = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
397 0, DefaultDepth(dpy, screen), CopyFromParent,
398 DefaultVisual(dpy, screen),
399 CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
401 update_name(c);
402 init_tags(c);
404 for(l = &clients; *l; l = &(*l)->next);
405 c->next = *l; /* *l == nil */
406 *l = c;
408 XGrabButton(dpy, Button1, Mod1Mask, c->win, False, ButtonPressMask,
409 GrabModeAsync, GrabModeSync, None, None);
410 XGrabButton(dpy, Button2, Mod1Mask, c->win, False, ButtonPressMask,
411 GrabModeAsync, GrabModeSync, None, None);
412 XGrabButton(dpy, Button3, Mod1Mask, c->win, False, ButtonPressMask,
413 GrabModeAsync, GrabModeSync, None, None);
415 if(!c->floating)
416 c->floating = trans
417 || ((c->maxw == c->minw) && (c->maxh == c->minh));
419 arrange(NULL);
420 /* mapping the window now prevents flicker */
421 if(c->tags[tsel]) {
422 XMapRaised(dpy, c->win);
423 XMapRaised(dpy, c->title);
424 focus(c);
425 }
426 else {
427 ban_client(c);
428 XMapRaised(dpy, c->win);
429 XMapRaised(dpy, c->title);
430 }
431 }
433 void
434 gravitate(Client *c, Bool invert)
435 {
436 int dx = 0, dy = 0;
438 switch(c->grav) {
439 case StaticGravity:
440 case NorthWestGravity:
441 case NorthGravity:
442 case NorthEastGravity:
443 dy = c->border;
444 break;
445 case EastGravity:
446 case CenterGravity:
447 case WestGravity:
448 dy = -(c->h / 2) + c->border;
449 break;
450 case SouthEastGravity:
451 case SouthGravity:
452 case SouthWestGravity:
453 dy = -c->h;
454 break;
455 default:
456 break;
457 }
459 switch (c->grav) {
460 case StaticGravity:
461 case NorthWestGravity:
462 case WestGravity:
463 case SouthWestGravity:
464 dx = c->border;
465 break;
466 case NorthGravity:
467 case CenterGravity:
468 case SouthGravity:
469 dx = -(c->w / 2) + c->border;
470 break;
471 case NorthEastGravity:
472 case EastGravity:
473 case SouthEastGravity:
474 dx = -(c->w + c->border);
475 break;
476 default:
477 break;
478 }
480 if(invert) {
481 dx = -dx;
482 dy = -dy;
483 }
484 c->x += dx;
485 c->y += dy;
486 }
489 void
490 resize(Client *c, Bool inc)
491 {
492 XConfigureEvent e;
494 if(inc) {
495 if(c->incw)
496 c->w -= (c->w - c->basew) % c->incw;
497 if(c->inch)
498 c->h -= (c->h - c->baseh) % c->inch;
499 }
500 if(c->minw && c->w < c->minw)
501 c->w = c->minw;
502 if(c->minh && c->h < c->minh)
503 c->h = c->minh;
504 if(c->maxw && c->w > c->maxw)
505 c->w = c->maxw;
506 if(c->maxh && c->h > c->maxh)
507 c->h = c->maxh;
508 resize_title(c);
509 XSetWindowBorderWidth(dpy, c->win, 1);
510 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
511 e.type = ConfigureNotify;
512 e.event = c->win;
513 e.window = c->win;
514 e.x = c->x;
515 e.y = c->y;
516 e.width = c->w;
517 e.height = c->h;
518 e.border_width = c->border;
519 e.above = None;
520 e.override_redirect = False;
521 XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&e);
522 XFlush(dpy);
523 }
525 static int
526 dummy_error_handler(Display *dsply, XErrorEvent *err)
527 {
528 return 0;
529 }
531 void
532 unmanage(Client *c)
533 {
534 Client **l;
536 XGrabServer(dpy);
537 XSetErrorHandler(dummy_error_handler);
539 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
540 XDestroyWindow(dpy, c->title);
542 for(l = &clients; *l && *l != c; l = &(*l)->next);
543 *l = c->next;
544 for(l = &clients; *l; l = &(*l)->next)
545 if((*l)->revert == c)
546 (*l)->revert = NULL;
547 if(sel == c)
548 sel = sel->revert ? sel->revert : clients;
550 free(c);
552 XFlush(dpy);
553 XSetErrorHandler(error_handler);
554 XUngrabServer(dpy);
555 arrange(NULL);
556 if(sel)
557 focus(sel);
558 }
560 Client *
561 gettitle(Window w)
562 {
563 Client *c;
564 for(c = clients; c; c = c->next)
565 if(c->title == w)
566 return c;
567 return NULL;
568 }
570 Client *
571 getclient(Window w)
572 {
573 Client *c;
574 for(c = clients; c; c = c->next)
575 if(c->win == w)
576 return c;
577 return NULL;
578 }
580 void
581 draw_client(Client *c)
582 {
583 int i;
584 if(c == sel) {
585 draw_bar();
586 XUnmapWindow(dpy, c->title);
587 XSetWindowBorder(dpy, c->win, dc.fg);
588 return;
589 }
591 XSetWindowBorder(dpy, c->win, dc.bg);
592 XMapWindow(dpy, c->title);
594 dc.x = dc.y = 0;
596 dc.w = 0;
597 for(i = 0; i < TLast; i++) {
598 if(c->tags[i]) {
599 dc.x += dc.w;
600 dc.w = textw(c->tags[i]) + dc.font.height;
601 drawtext(c->tags[i], True);
602 }
603 }
604 dc.x += dc.w;
605 dc.w = textw(c->name) + dc.font.height;
606 drawtext(c->name, True);
607 XCopyArea(dpy, dc.drawable, c->title, dc.gc,
608 0, 0, c->tw, c->th, 0, 0);
609 XFlush(dpy);
610 }