dwm-meillo

view client.c @ 384:126e78129f1d

configurenotify remembers max geom now, and restores this if necessary, however it accepts to touch the max size on configurerequest, this shouldn't break fillscreen apps (tested with mplayer)
author Anselm R. Garbe <arg@10kloc.org>
date Tue, 29 Aug 2006 17:31:55 +0200
parents 83576f5f0a90
children 052657ff2e7b
line source
1 /*
2 * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
3 * See LICENSE file for license details.
4 */
5 #include "dwm.h"
6 #include <stdlib.h>
7 #include <string.h>
8 #include <X11/Xatom.h>
9 #include <X11/Xutil.h>
11 /* static functions */
13 static void
14 grabbuttons(Client *c, Bool focus)
15 {
16 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
18 if(focus) {
19 XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK,
20 GrabModeAsync, GrabModeSync, None, None);
21 XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK,
22 GrabModeAsync, GrabModeSync, None, None);
23 XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False, BUTTONMASK,
24 GrabModeAsync, GrabModeSync, None, None);
25 XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
26 GrabModeAsync, GrabModeSync, None, None);
28 XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK,
29 GrabModeAsync, GrabModeSync, None, None);
30 XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK,
31 GrabModeAsync, GrabModeSync, None, None);
32 XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False, BUTTONMASK,
33 GrabModeAsync, GrabModeSync, None, None);
34 XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
35 GrabModeAsync, GrabModeSync, None, None);
37 XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK,
38 GrabModeAsync, GrabModeSync, None, None);
39 XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK,
40 GrabModeAsync, GrabModeSync, None, None);
41 XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False, BUTTONMASK,
42 GrabModeAsync, GrabModeSync, None, None);
43 XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
44 GrabModeAsync, GrabModeSync, None, None);
45 }
46 else
47 XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK,
48 GrabModeAsync, GrabModeSync, None, None);
50 }
52 static void
53 resizetitle(Client *c)
54 {
55 c->tw = textw(c->name);
56 if(c->tw > c->w)
57 c->tw = c->w + 2;
58 c->tx = c->x + c->w - c->tw + 2;
59 c->ty = c->y;
60 if(isvisible(c))
61 XMoveResizeWindow(dpy, c->twin, c->tx, c->ty, c->tw, c->th);
62 else
63 XMoveResizeWindow(dpy, c->twin, c->tx + 2 * sw, c->ty, c->tw, c->th);
65 }
67 static int
68 xerrordummy(Display *dsply, XErrorEvent *ee)
69 {
70 return 0;
71 }
73 /* extern functions */
75 void
76 ban(Client *c)
77 {
78 XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
79 XMoveWindow(dpy, c->twin, c->tx + 2 * sw, c->ty);
80 }
82 void
83 focus(Client *c)
84 {
85 Client *old = sel;
87 if(!issel)
88 return;
89 if(!sel)
90 sel = c;
91 else if(sel != c) {
92 if(sel->ismax)
93 togglemax(NULL);
94 sel = c;
95 grabbuttons(old, False);
96 drawtitle(old);
97 }
98 grabbuttons(c, True);
99 drawtitle(c);
100 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
101 }
103 Client *
104 getclient(Window w)
105 {
106 Client *c;
108 for(c = clients; c; c = c->next)
109 if(c->win == w)
110 return c;
111 return NULL;
112 }
114 Client *
115 getctitle(Window w)
116 {
117 Client *c;
119 for(c = clients; c; c = c->next)
120 if(c->twin == w)
121 return c;
122 return NULL;
123 }
125 void
126 gravitate(Client *c, Bool invert)
127 {
128 int dx = 0, dy = 0;
130 switch(c->grav) {
131 default:
132 break;
133 case StaticGravity:
134 case NorthWestGravity:
135 case NorthGravity:
136 case NorthEastGravity:
137 dy = c->border;
138 break;
139 case EastGravity:
140 case CenterGravity:
141 case WestGravity:
142 dy = -(c->h / 2) + c->border;
143 break;
144 case SouthEastGravity:
145 case SouthGravity:
146 case SouthWestGravity:
147 dy = -(c->h);
148 break;
149 }
151 switch (c->grav) {
152 default:
153 break;
154 case StaticGravity:
155 case NorthWestGravity:
156 case WestGravity:
157 case SouthWestGravity:
158 dx = c->border;
159 break;
160 case NorthGravity:
161 case CenterGravity:
162 case SouthGravity:
163 dx = -(c->w / 2) + c->border;
164 break;
165 case NorthEastGravity:
166 case EastGravity:
167 case SouthEastGravity:
168 dx = -(c->w + c->border);
169 break;
170 }
172 if(invert) {
173 dx = -dx;
174 dy = -dy;
175 }
176 c->x += dx;
177 c->y += dy;
178 }
180 void
181 killclient(Arg *arg)
182 {
183 if(!sel)
184 return;
185 if(sel->proto & PROTODELWIN)
186 sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]);
187 else
188 XKillClient(dpy, sel->win);
189 }
191 void
192 manage(Window w, XWindowAttributes *wa)
193 {
194 unsigned int i;
195 Client *c, *tc;
196 Window trans;
197 XSetWindowAttributes twa;
199 c = emallocz(sizeof(Client));
200 c->tags = emallocz(ntags * sizeof(Bool));
201 c->win = w;
202 c->x = c->tx = wa->x;
203 c->y = c->ty = wa->y;
204 c->w = c->tw = wa->width;
205 c->h = wa->height;
206 c->th = bh;
208 c->border = 0;
209 setsize(c);
211 if(c->x + c->w + 2 > sw)
212 c->x = sw - c->w - 2;
213 if(c->x < 0)
214 c->x = 0;
215 if(c->y + c->h + 2 > sh)
216 c->y = sh - c->h - 2;
217 if(c->h != sh && c->y < bh)
218 c->y = bh;
220 c->proto = getproto(c->win);
221 XSelectInput(dpy, c->win,
222 StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
223 XGetTransientForHint(dpy, c->win, &trans);
224 twa.override_redirect = 1;
225 twa.background_pixmap = ParentRelative;
226 twa.event_mask = ExposureMask | EnterWindowMask;
228 c->twin = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
229 0, DefaultDepth(dpy, screen), CopyFromParent,
230 DefaultVisual(dpy, screen),
231 CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
233 grabbuttons(c, False);
234 if((tc = getclient(trans))) /* inherit tags */
235 for(i = 0; i < ntags; i++)
236 c->tags[i] = tc->tags[i];
237 else
238 settags(c);
239 if(!c->isfloat)
240 c->isfloat = trans
241 || (c->maxw && c->minw &&
242 c->maxw == c->minw && c->maxh == c->minh);
244 if(clients)
245 clients->prev = c;
246 c->next = clients;
247 clients = c;
249 settitle(c);
250 if(isvisible(c))
251 sel = c;
252 arrange(NULL);
253 XMapWindow(dpy, c->win);
254 XMapWindow(dpy, c->twin);
255 if(isvisible(c))
256 focus(c);
257 }
259 void
260 resize(Client *c, Bool sizehints, Corner sticky)
261 {
262 int bottom = c->y + c->h;
263 int right = c->x + c->w;
264 XWindowChanges wc;
266 if(sizehints) {
267 if(c->incw)
268 c->w -= (c->w - c->basew) % c->incw;
269 if(c->inch)
270 c->h -= (c->h - c->baseh) % c->inch;
271 if(c->minw && c->w < c->minw)
272 c->w = c->minw;
273 if(c->minh && c->h < c->minh)
274 c->h = c->minh;
275 if(c->maxw && c->w > c->maxw)
276 c->w = c->maxw;
277 if(c->maxh && c->h > c->maxh)
278 c->h = c->maxh;
279 }
280 if(sticky == TopRight || sticky == BotRight)
281 c->x = right - c->w;
282 if(sticky == BotLeft || sticky == BotRight)
283 c->y = bottom - c->h;
285 resizetitle(c);
286 wc.x = c->x;
287 wc.y = c->y;
288 wc.width = c->w;
289 wc.height = c->h;
290 if(c->w == sw && c->h == sh)
291 wc.border_width = 0;
292 else
293 wc.border_width = 1;
294 XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
295 XSync(dpy, False);
296 }
298 void
299 setsize(Client *c)
300 {
301 long msize;
302 XSizeHints size;
304 if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
305 size.flags = PSize;
306 c->flags = size.flags;
307 if(c->flags & PBaseSize) {
308 c->basew = size.base_width;
309 c->baseh = size.base_height;
310 }
311 else
312 c->basew = c->baseh = 0;
313 if(c->flags & PResizeInc) {
314 c->incw = size.width_inc;
315 c->inch = size.height_inc;
316 }
317 else
318 c->incw = c->inch = 0;
319 if(c->flags & PMaxSize) {
320 c->maxw = size.max_width;
321 c->maxh = size.max_height;
322 }
323 else
324 c->maxw = c->maxh = 0;
325 if(c->flags & PMinSize) {
326 c->minw = size.min_width;
327 c->minh = size.min_height;
328 }
329 else
330 c->minw = c->minh = 0;
331 if(c->flags & PWinGravity)
332 c->grav = size.win_gravity;
333 else
334 c->grav = NorthWestGravity;
335 }
337 void
338 settitle(Client *c)
339 {
340 char **list = NULL;
341 int n;
342 XTextProperty name;
344 name.nitems = 0;
345 c->name[0] = 0;
346 XGetTextProperty(dpy, c->win, &name, netatom[NetWMName]);
347 if(!name.nitems)
348 XGetWMName(dpy, c->win, &name);
349 if(!name.nitems)
350 return;
351 if(name.encoding == XA_STRING)
352 strncpy(c->name, (char *)name.value, sizeof(c->name));
353 else {
354 if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
355 && n > 0 && *list)
356 {
357 strncpy(c->name, *list, sizeof(c->name));
358 XFreeStringList(list);
359 }
360 }
361 XFree(name.value);
362 resizetitle(c);
363 }
365 void
366 togglemax(Arg *arg)
367 {
368 int ox, oy, ow, oh;
369 XEvent ev;
371 if(!sel)
372 return;
374 if((sel->ismax = !sel->ismax)) {
375 ox = sel->x;
376 oy = sel->y;
377 ow = sel->w;
378 oh = sel->h;
379 sel->x = sx;
380 sel->y = sy + bh;
381 sel->w = sw - 2;
382 sel->h = sh - 2 - bh;
384 restack();
385 resize(sel, arrange == dofloat, TopLeft);
387 sel->x = ox;
388 sel->y = oy;
389 sel->w = ow;
390 sel->h = oh;
391 }
392 else
393 resize(sel, False, TopLeft);
394 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
395 }
397 void
398 unmanage(Client *c)
399 {
400 Client *tc;
401 Window trans;
402 XGrabServer(dpy);
403 XSetErrorHandler(xerrordummy);
405 XGetTransientForHint(dpy, c->win, &trans);
407 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
408 XDestroyWindow(dpy, c->twin);
410 detach(c);
411 if(sel == c) {
412 if(trans && (tc = getclient(trans)) && isvisible(tc))
413 sel = tc;
414 else
415 sel = getnext(clients);
416 }
417 free(c->tags);
418 free(c);
420 XSync(dpy, False);
421 XSetErrorHandler(xerror);
422 XUngrabServer(dpy);
423 if(sel)
424 focus(sel);
425 arrange(NULL);
426 }