JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
rearranged several stuff
[dwm.git] / client.c
1 /*
2  * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
3  * See LICENSE file for license details.
4  */
5
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <X11/Xatom.h>
10 #include <X11/Xutil.h>
11
12 #include "dwm.h"
13
14 void
15 ban(Client *c)
16 {
17         XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
18         XMoveWindow(dpy, c->title, c->tx + 2 * sw, c->ty);
19 }
20
21 static void
22 resizetitle(Client *c)
23 {
24         int i;
25
26         c->tw = 0;
27         for(i = 0; i < TLast; i++)
28                 if(c->tags[i])
29                         c->tw += textw(c->tags[i]);
30         c->tw += textw(c->name);
31         if(c->tw > c->w)
32                 c->tw = c->w + 2;
33         c->tx = c->x + c->w - c->tw + 2;
34         c->ty = c->y;
35         XMoveResizeWindow(dpy, c->title, c->tx, c->ty, c->tw, c->th);
36 }
37
38 void
39 settitle(Client *c)
40 {
41         XTextProperty name;
42         int n;
43         char **list = NULL;
44
45         name.nitems = 0;
46         c->name[0] = 0;
47         XGetTextProperty(dpy, c->win, &name, net_atom[NetWMName]);
48         if(!name.nitems)
49                 XGetWMName(dpy, c->win, &name);
50         if(!name.nitems)
51                 return;
52         if(name.encoding == XA_STRING)
53                 strncpy(c->name, (char *)name.value, sizeof(c->name));
54         else {
55                 if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
56                                 && n > 0 && *list)
57                 {
58                         strncpy(c->name, *list, sizeof(c->name));
59                         XFreeStringList(list);
60                 }
61         }
62         XFree(name.value);
63         resizetitle(c);
64 }
65
66 void
67 setsize(Client *c)
68 {
69         XSizeHints size;
70         long msize;
71         if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
72                 size.flags = PSize;
73         c->flags = size.flags;
74         if(c->flags & PBaseSize) {
75                 c->basew = size.base_width;
76                 c->baseh = size.base_height;
77         }
78         else
79                 c->basew = c->baseh = 0;
80         if(c->flags & PResizeInc) {
81                 c->incw = size.width_inc;
82                 c->inch = size.height_inc;
83         }
84         else
85                 c->incw = c->inch = 0;
86         if(c->flags & PMaxSize) {
87                 c->maxw = size.max_width;
88                 c->maxh = size.max_height;
89         }
90         else
91                 c->maxw = c->maxh = 0;
92         if(c->flags & PMinSize) {
93                 c->minw = size.min_width;
94                 c->minh = size.min_height;
95         }
96         else
97                 c->minw = c->minh = 0;
98         if(c->flags & PWinGravity)
99                 c->grav = size.win_gravity;
100         else
101                 c->grav = NorthWestGravity;
102 }
103
104 void
105 higher(Client *c)
106 {
107         XRaiseWindow(dpy, c->win);
108         XRaiseWindow(dpy, c->title);
109 }
110
111 void
112 lower(Client *c)
113 {
114         XLowerWindow(dpy, c->title);
115         XLowerWindow(dpy, c->win);
116 }
117
118 void
119 focus(Client *c)
120 {
121         Client *old = sel;
122         XEvent ev;
123
124         XFlush(dpy);
125         sel = c;
126         if(old && old != c)
127                 drawtitle(old);
128         drawtitle(c);
129         XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
130         XFlush(dpy);
131         while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
132 }
133
134 void
135 manage(Window w, XWindowAttributes *wa)
136 {
137         Client *c, **l;
138         XSetWindowAttributes twa;
139         Window trans;
140
141         c = emallocz(sizeof(Client));
142         c->win = w;
143         c->tx = c->x = wa->x;
144         c->ty = c->y = wa->y;
145         if(c->y < bh)
146                 c->ty = c->y += bh;
147         c->tw = c->w = wa->width;
148         c->h = wa->height;
149         c->th = bh;
150         c->border = 1;
151         c->proto = getproto(c->win);
152         setsize(c);
153         XSelectInput(dpy, c->win,
154                         StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
155         XGetTransientForHint(dpy, c->win, &trans);
156         twa.override_redirect = 1;
157         twa.background_pixmap = ParentRelative;
158         twa.event_mask = ExposureMask;
159
160         c->title = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
161                         0, DefaultDepth(dpy, screen), CopyFromParent,
162                         DefaultVisual(dpy, screen),
163                         CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
164
165         settitle(c);
166         settags(c);
167
168         for(l = &clients; *l; l = &(*l)->next);
169         c->next = *l; /* *l == nil */
170         *l = c;
171
172         XGrabButton(dpy, Button1, Mod1Mask, c->win, False, ButtonPressMask,
173                         GrabModeAsync, GrabModeSync, None, None);
174         XGrabButton(dpy, Button2, Mod1Mask, c->win, False, ButtonPressMask,
175                         GrabModeAsync, GrabModeSync, None, None);
176         XGrabButton(dpy, Button3, Mod1Mask, c->win, False, ButtonPressMask,
177                         GrabModeAsync, GrabModeSync, None, None);
178
179         if(!c->dofloat)
180                 c->dofloat = trans
181                         || ((c->maxw == c->minw) && (c->maxh == c->minh));
182
183         arrange(NULL);
184         /* mapping the window now prevents flicker */
185         if(c->tags[tsel]) {
186                 XMapRaised(dpy, c->win);
187                 XMapRaised(dpy, c->title);
188                 focus(c);
189         }
190         else {
191                 ban(c);
192                 XMapRaised(dpy, c->win);
193                 XMapRaised(dpy, c->title);
194         }
195 }
196
197 void
198 gravitate(Client *c, Bool invert)
199 {
200         int dx = 0, dy = 0;
201
202         switch(c->grav) {
203         case StaticGravity:
204         case NorthWestGravity:
205         case NorthGravity:
206         case NorthEastGravity:
207                 dy = c->border;
208                 break;
209         case EastGravity:
210         case CenterGravity:
211         case WestGravity:
212                 dy = -(c->h / 2) + c->border;
213                 break;
214         case SouthEastGravity:
215         case SouthGravity:
216         case SouthWestGravity:
217                 dy = -c->h;
218                 break;
219         default:
220                 break;
221         }
222
223         switch (c->grav) {
224         case StaticGravity:
225         case NorthWestGravity:
226         case WestGravity:
227         case SouthWestGravity:
228                 dx = c->border;
229                 break;
230         case NorthGravity:
231         case CenterGravity:
232         case SouthGravity:
233                 dx = -(c->w / 2) + c->border;
234                 break;
235         case NorthEastGravity:
236         case EastGravity:
237         case SouthEastGravity:
238                 dx = -(c->w + c->border);
239                 break;
240         default:
241                 break;
242         }
243
244         if(invert) {
245                 dx = -dx;
246                 dy = -dy;
247         }
248         c->x += dx;
249         c->y += dy;
250 }
251
252
253 void
254 resize(Client *c, Bool inc)
255 {
256         XConfigureEvent e;
257
258         if(inc) {
259                 if(c->incw)
260                         c->w -= (c->w - c->basew) % c->incw;
261                 if(c->inch)
262                         c->h -= (c->h - c->baseh) % c->inch;
263         }
264         if(c->x > sw) /* might happen on restart */
265                 c->x = sw - c->w;
266         if(c->y > sh)
267                 c->ty = c->y = sh - c->h;
268         if(c->minw && c->w < c->minw)
269                 c->w = c->minw;
270         if(c->minh && c->h < c->minh)
271                 c->h = c->minh;
272         if(c->maxw && c->w > c->maxw)
273                 c->w = c->maxw;
274         if(c->maxh && c->h > c->maxh)
275                 c->h = c->maxh;
276         resizetitle(c);
277         XSetWindowBorderWidth(dpy, c->win, 1);
278         XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
279         e.type = ConfigureNotify;
280         e.event = c->win;
281         e.window = c->win;
282         e.x = c->x;
283         e.y = c->y;
284         e.width = c->w;
285         e.height = c->h;
286         e.border_width = c->border;
287         e.above = None;
288         e.override_redirect = False;
289         XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&e);
290         XFlush(dpy);
291 }
292
293 static int
294 xerrordummy(Display *dsply, XErrorEvent *ee)
295 {
296         return 0;
297 }
298
299 void
300 unmanage(Client *c)
301 {
302         Client **l;
303
304         XGrabServer(dpy);
305         XSetErrorHandler(xerrordummy);
306
307         XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
308         XDestroyWindow(dpy, c->title);
309
310         for(l = &clients; *l && *l != c; l = &(*l)->next);
311         *l = c->next;
312         for(l = &clients; *l; l = &(*l)->next)
313                 if((*l)->revert == c)
314                         (*l)->revert = NULL;
315         if(sel == c)
316                 sel = sel->revert ? sel->revert : clients;
317
318         free(c);
319
320         XFlush(dpy);
321         XSetErrorHandler(xerror);
322         XUngrabServer(dpy);
323         arrange(NULL);
324         if(sel)
325                 focus(sel);
326 }
327
328 Client *
329 getctitle(Window w)
330 {
331         Client *c;
332         for(c = clients; c; c = c->next)
333                 if(c->title == w)
334                         return c;
335         return NULL;
336 }
337
338 Client *
339 getclient(Window w)
340 {
341         Client *c;
342         for(c = clients; c; c = c->next)
343                 if(c->win == w)
344                         return c;
345         return NULL;
346 }
347
348 void
349 zoom(Arg *arg)
350 {
351         Client **l, *c;
352
353         if(!sel)
354                 return;
355
356         if(sel == getnext(clients) && sel->next)  {
357                 if((c = getnext(sel->next)))
358                         sel = c;
359         }
360
361         for(l = &clients; *l && *l != sel; l = &(*l)->next);
362         *l = sel->next;
363
364         sel->next = clients; /* pop */
365         clients = sel;
366         arrange(NULL);
367         focus(sel);
368 }
369
370 void
371 maximize(Arg *arg)
372 {
373         if(!sel)
374                 return;
375         sel->x = sx;
376         sel->y = sy + bh;
377         sel->w = sw - 2 * sel->border;
378         sel->h = sh - 2 * sel->border - bh;
379         higher(sel);
380         resize(sel, False);
381 }
382
383 void
384 focusprev(Arg *arg)
385 {
386         Client *c;
387
388         if(!sel)
389                 return;
390
391         if((c = sel->revert && sel->revert->tags[tsel] ? sel->revert : NULL)) {
392                 higher(c);
393                 focus(c);
394         }
395 }
396
397 void
398 focusnext(Arg *arg)
399 {
400         Client *c;
401    
402         if(!sel)
403                 return;
404
405         if(!(c = getnext(sel->next)))
406                 c = getnext(clients);
407         if(c) {
408                 higher(c);
409                 c->revert = sel;
410                 focus(c);
411         }
412 }
413
414 void
415 killclient(Arg *arg)
416 {
417         if(!sel)
418                 return;
419         if(sel->proto & WM_PROTOCOL_DELWIN)
420                 sendevent(sel->win, wm_atom[WMProtocols], wm_atom[WMDelete]);
421         else
422                 XKillClient(dpy, sel->win);
423 }