aewl

view client.c @ 541:08d3d329270a

using MASTER 600 again, it is definately better, and using urxvtc for the moment (it doesn't flickers on refreshes, but this is not because of Marc Lehmann, it is because of the original rxvt code)
author arg@mig29
date Thu, 26 Oct 2006 12:13:41 +0200
parents 651f2c868b31
children 722cffee3770
line source
1 /* (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
2 * See LICENSE file for license details.
3 */
4 #include "dwm.h"
5 #include <stdlib.h>
6 #include <string.h>
7 #include <X11/Xatom.h>
8 #include <X11/Xutil.h>
10 /* static functions */
12 static void
13 detachstack(Client *c) {
14 Client **tc;
15 for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
16 *tc = c->snext;
17 }
19 static void
20 grabbuttons(Client *c, Bool focused) {
21 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
23 if(focused) {
24 XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK,
25 GrabModeAsync, GrabModeSync, None, None);
26 XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK,
27 GrabModeAsync, GrabModeSync, None, None);
28 XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False, BUTTONMASK,
29 GrabModeAsync, GrabModeSync, None, None);
30 XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
31 GrabModeAsync, GrabModeSync, None, None);
33 XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK,
34 GrabModeAsync, GrabModeSync, None, None);
35 XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK,
36 GrabModeAsync, GrabModeSync, None, None);
37 XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False, BUTTONMASK,
38 GrabModeAsync, GrabModeSync, None, None);
39 XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
40 GrabModeAsync, GrabModeSync, None, None);
42 XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK,
43 GrabModeAsync, GrabModeSync, None, None);
44 XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK,
45 GrabModeAsync, GrabModeSync, None, None);
46 XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False, BUTTONMASK,
47 GrabModeAsync, GrabModeSync, None, None);
48 XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
49 GrabModeAsync, GrabModeSync, None, None);
50 }
51 else
52 XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK,
53 GrabModeAsync, GrabModeSync, None, None);
54 }
56 static int
57 xerrordummy(Display *dsply, XErrorEvent *ee) {
58 return 0;
59 }
61 /* extern functions */
63 void
64 ban(Client *c) {
65 XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
66 XMoveWindow(dpy, c->twin, c->tx + 2 * sw, c->ty);
67 }
69 void
70 configure(Client *c) {
71 XEvent synev;
73 synev.type = ConfigureNotify;
74 synev.xconfigure.display = dpy;
75 synev.xconfigure.event = c->win;
76 synev.xconfigure.window = c->win;
77 synev.xconfigure.x = c->x;
78 synev.xconfigure.y = c->y;
79 synev.xconfigure.width = c->w;
80 synev.xconfigure.height = c->h;
81 synev.xconfigure.border_width = c->border;
82 synev.xconfigure.above = None;
83 XSendEvent(dpy, c->win, True, NoEventMask, &synev);
84 }
86 void
87 focus(Client *c) {
88 Client *old;
90 if(!issel || (c && !isvisible(c)))
91 return;
92 if(!sel)
93 sel = c;
94 else if(sel != c) {
95 old = sel;
96 sel = c;
97 if(old) {
98 grabbuttons(old, False);
99 drawtitle(old);
100 }
101 }
102 if(c) {
103 detachstack(c);
104 c->snext = stack;
105 stack = c;
106 grabbuttons(c, True);
107 drawtitle(c);
108 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
109 }
110 else
111 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
112 }
114 Client *
115 getclient(Window w) {
116 Client *c;
118 for(c = clients; c; c = c->next)
119 if(c->win == w)
120 return c;
121 return NULL;
122 }
124 Client *
125 getctitle(Window w) {
126 Client *c;
128 for(c = clients; c; c = c->next)
129 if(c->twin == w)
130 return c;
131 return NULL;
132 }
134 void
135 gravitate(Client *c, Bool invert) {
136 int dx = 0, dy = 0;
138 switch(c->grav) {
139 default:
140 break;
141 case StaticGravity:
142 case NorthWestGravity:
143 case NorthGravity:
144 case NorthEastGravity:
145 dy = c->border;
146 break;
147 case EastGravity:
148 case CenterGravity:
149 case WestGravity:
150 dy = -(c->h / 2) + c->border;
151 break;
152 case SouthEastGravity:
153 case SouthGravity:
154 case SouthWestGravity:
155 dy = -(c->h);
156 break;
157 }
158 switch (c->grav) {
159 default:
160 break;
161 case StaticGravity:
162 case NorthWestGravity:
163 case WestGravity:
164 case SouthWestGravity:
165 dx = c->border;
166 break;
167 case NorthGravity:
168 case CenterGravity:
169 case SouthGravity:
170 dx = -(c->w / 2) + c->border;
171 break;
172 case NorthEastGravity:
173 case EastGravity:
174 case SouthEastGravity:
175 dx = -(c->w + c->border);
176 break;
177 }
178 if(invert) {
179 dx = -dx;
180 dy = -dy;
181 }
182 c->x += dx;
183 c->y += dy;
184 }
186 void
187 killclient(Arg *arg) {
188 if(!sel)
189 return;
190 if(sel->proto & PROTODELWIN)
191 sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]);
192 else
193 XKillClient(dpy, sel->win);
194 }
196 void
197 manage(Window w, XWindowAttributes *wa) {
198 Client *c;
199 Window trans;
200 XSetWindowAttributes twa;
202 c = emallocz(sizeof(Client));
203 c->tags = emallocz(ntags * sizeof(Bool));
204 c->win = w;
205 c->x = c->tx = wa->x;
206 c->y = c->ty = wa->y;
207 c->w = c->tw = wa->width;
208 c->h = wa->height;
209 c->th = bh;
210 c->border = 0;
211 updatesize(c);
212 if(c->x + c->w + 2 * BORDERPX > sw)
213 c->x = sw - c->w - 2 * BORDERPX;
214 if(c->x < sx)
215 c->x = sx;
216 if(c->y + c->h + 2 * BORDERPX > sh)
217 c->y = sh - c->h - 2 * BORDERPX;
218 if(c->h != sh && c->y < bh)
219 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;
227 c->twin = XCreateWindow(dpy, root, c->tx, c->ty, c->tw, c->th,
228 0, DefaultDepth(dpy, screen), CopyFromParent,
229 DefaultVisual(dpy, screen),
230 CWOverrideRedirect | CWBackPixmap | CWEventMask, &twa);
231 grabbuttons(c, False);
232 updatetitle(c);
233 settags(c, getclient(trans));
234 if(!c->isfloat)
235 c->isfloat = trans
236 || (c->maxw && c->minw &&
237 c->maxw == c->minw && c->maxh == c->minh);
238 resizetitle(c);
239 if(clients)
240 clients->prev = c;
241 c->next = clients;
242 c->snext = stack;
243 stack = clients = c;
244 ban(c);
245 XMapWindow(dpy, c->win);
246 XMapWindow(dpy, c->twin);
247 if(isvisible(c))
248 focus(c);
249 arrange();
250 }
252 void
253 resize(Client *c, Bool sizehints, Corner sticky) {
254 int bottom = c->y + c->h;
255 int right = c->x + c->w;
256 XWindowChanges wc;
258 if(sizehints) {
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 if(c->minw && c->w < c->minw)
264 c->w = c->minw;
265 if(c->minh && c->h < c->minh)
266 c->h = c->minh;
267 if(c->maxw && c->w > c->maxw)
268 c->w = c->maxw;
269 if(c->maxh && c->h > c->maxh)
270 c->h = c->maxh;
271 }
272 if(sticky == TopRight || sticky == BotRight)
273 c->x = right - c->w;
274 if(sticky == BotLeft || sticky == BotRight)
275 c->y = bottom - c->h;
276 /* offscreen appearance fixes */
277 if(c->x + c->w < sx)
278 c->x = sx;
279 if(c->y + c->h < bh)
280 c->y = bh;
281 if(c->x > sw)
282 c->x = sw - c->w;
283 if(c->y > sh)
284 c->y = sh - 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 = BORDERPX;
294 XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
295 configure(c);
296 XSync(dpy, False);
297 }
299 void
300 resizetitle(Client *c) {
301 c->tw = textw(c->name);
302 if(c->tw > c->w)
303 c->tw = c->w + 2 * BORDERPX;
304 c->tx = c->x + c->w - c->tw + 2 * BORDERPX;
305 c->ty = c->y;
306 if(isvisible(c))
307 XMoveResizeWindow(dpy, c->twin, c->tx, c->ty, c->tw, c->th);
308 else
309 XMoveResizeWindow(dpy, c->twin, c->tx + 2 * sw, c->ty, c->tw, c->th);
310 }
312 void
313 updatesize(Client *c) {
314 long msize;
315 XSizeHints size;
317 if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
318 size.flags = PSize;
319 c->flags = size.flags;
320 if(c->flags & PBaseSize) {
321 c->basew = size.base_width;
322 c->baseh = size.base_height;
323 }
324 else
325 c->basew = c->baseh = 0;
326 if(c->flags & PResizeInc) {
327 c->incw = size.width_inc;
328 c->inch = size.height_inc;
329 }
330 else
331 c->incw = c->inch = 0;
332 if(c->flags & PMaxSize) {
333 c->maxw = size.max_width;
334 c->maxh = size.max_height;
335 }
336 else
337 c->maxw = c->maxh = 0;
338 if(c->flags & PMinSize) {
339 c->minw = size.min_width;
340 c->minh = size.min_height;
341 }
342 else
343 c->minw = c->minh = 0;
344 if(c->flags & PWinGravity)
345 c->grav = size.win_gravity;
346 else
347 c->grav = NorthWestGravity;
348 }
350 void
351 updatetitle(Client *c) {
352 char **list = NULL;
353 int n;
354 XTextProperty name;
356 name.nitems = 0;
357 c->name[0] = 0;
358 XGetTextProperty(dpy, c->win, &name, netatom[NetWMName]);
359 if(!name.nitems)
360 XGetWMName(dpy, c->win, &name);
361 if(!name.nitems)
362 return;
363 if(name.encoding == XA_STRING)
364 strncpy(c->name, (char *)name.value, sizeof(c->name));
365 else {
366 if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
367 && n > 0 && *list)
368 {
369 strncpy(c->name, *list, sizeof(c->name));
370 XFreeStringList(list);
371 }
372 }
373 XFree(name.value);
374 }
376 void
377 unmanage(Client *c) {
378 Client *nc;
380 /* The server grab construct avoids race conditions. */
381 XGrabServer(dpy);
382 XSetErrorHandler(xerrordummy);
383 detach(c);
384 detachstack(c);
385 if(sel == c) {
386 for(nc = stack; nc && !isvisible(nc); nc = nc->snext);
387 focus(nc);
388 }
389 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
390 XDestroyWindow(dpy, c->twin);
391 free(c->tags);
392 free(c);
393 XSync(dpy, False);
394 XSetErrorHandler(xerror);
395 XUngrabServer(dpy);
396 arrange();
397 }