Blob


1 /* Copyright (c) 1994-1996 David Hogan, see README for licence details */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <X11/X.h>
5 #include <X11/Xos.h>
6 #include <X11/Xlib.h>
7 #include <X11/Xutil.h>
8 #include <X11/Xatom.h>
9 #include <X11/extensions/shape.h>
10 #include "dat.h"
11 #include "fns.h"
13 int isNew;
15 int
16 manage(Client *c, int mapped)
17 {
18 int fixsize, dohide, doreshape, state;
19 long msize;
20 XClassHint class;
21 XWMHints *hints;
22 XSetWindowAttributes attrs;
24 trace("manage", c, 0);
25 XSelectInput(dpy, c->window, ColormapChangeMask | EnterWindowMask | PropertyChangeMask | FocusChangeMask);
27 /* Get loads of hints */
29 if (XGetClassHint(dpy, c->window, &class) != 0) { /* ``Success'' */
30 c->instance = class.res_name;
31 c->class = class.res_class;
32 c->is9term = 0;
33 if(isNew){
34 c->is9term = strstr(c->class, "term") || strstr(c->class, "Term");
35 isNew = 0;
36 }
37 }
38 else {
39 c->instance = 0;
40 c->class = 0;
41 c->is9term = 0;
42 }
43 c->iconname = getprop(c->window, XA_WM_ICON_NAME);
44 c->name = getprop(c->window, XA_WM_NAME);
45 setlabel(c);
47 hints = XGetWMHints(dpy, c->window);
48 if (XGetWMNormalHints(dpy, c->window, &c->size, &msize) == 0 || c->size.flags == 0)
49 c->size.flags = PSize; /* not specified - punt */
51 getcmaps(c);
52 getproto(c);
53 gettrans(c);
54 if (c->is9term)
55 c->hold = getiprop(c->window, _rio_hold_mode);
57 /* Figure out what to do with the window from hints */
59 if (!getstate(c->window, &state))
60 state = hints ? hints->initial_state : NormalState;
61 dohide = (state == IconicState);
63 fixsize = 0;
64 if ((c->size.flags & (USSize|PSize)))
65 fixsize = 1;
66 if ((c->size.flags & (PMinSize|PMaxSize)) == (PMinSize|PMaxSize) && c->size.min_width == c->size.max_width && c->size.min_height == c->size.max_height)
67 fixsize = 1;
68 doreshape = !mapped;
69 if (fixsize) {
70 if (c->size.flags & USPosition)
71 doreshape = 0;
72 if (dohide && (c->size.flags & PPosition))
73 doreshape = 0;
74 if (c->trans != None)
75 doreshape = 0;
76 }
77 if (c->is9term)
78 fixsize = 0;
79 if (c->size.flags & PBaseSize) {
80 c->min_dx = c->size.base_width;
81 c->min_dy = c->size.base_height;
82 }
83 else if (c->size.flags & PMinSize) {
84 c->min_dx = c->size.min_width;
85 c->min_dy = c->size.min_height;
86 }
87 else if (c->is9term) {
88 c->min_dx = 100;
89 c->min_dy = 50;
90 }
91 else
92 c->min_dx = c->min_dy = 0;
94 if (hints)
95 XFree(hints);
97 /* Now do it!!! */
99 if (doreshape) {
100 if(0) fprintf(stderr, "in doreshape is9term=%d fixsize=%d, x=%d, y=%d, min_dx=%d, min_dy=%d, dx=%d, dy=%d\n",
101 c->is9term, fixsize, c->x, c->y, c->min_dx, c->min_dy, c->dx, c->dy);
102 if (current && current->screen == c->screen)
103 cmapnofocus(c->screen);
104 if (!c->is9term && c->x==0 && c->y==0) {
105 static int nwin;
107 c->x = 20*nwin+BORDER;
108 c->y = 20*nwin+BORDER;
109 nwin++;
110 nwin %= 10;
113 if (c->is9term && !(fixsize ? drag(c, Button3) : sweep(c, Button3))) {
114 XKillClient(dpy, c->window);
115 rmclient(c);
116 if (current && current->screen == c->screen)
117 cmapfocus(current);
118 return 0;
120 } else
121 gravitate(c, 0);
124 attrs.border_pixel = c->screen->black;
125 attrs.background_pixel = c->screen->white;
126 attrs.colormap = c->screen->def_cmap;
127 c->parent = XCreateWindow(dpy, c->screen->root,
128 c->x - BORDER, c->y - BORDER,
129 c->dx + 2*BORDER, c->dy + 2*BORDER,
130 0,
131 c->screen->depth,
132 CopyFromParent,
133 c->screen->vis,
134 CWBackPixel | CWBorderPixel | CWColormap,
135 &attrs);
137 XSelectInput(dpy, c->parent, SubstructureRedirectMask | SubstructureNotifyMask|ButtonPressMask| PointerMotionMask|LeaveWindowMask);
138 if (mapped)
139 c->reparenting = 1;
140 if (doreshape && !fixsize)
141 XResizeWindow(dpy, c->window, c->dx, c->dy);
142 XSetWindowBorderWidth(dpy, c->window, 0);
144 /*
145 * To have something more than only a big white or black border
146 * XXX should replace this by a pattern in the white or black
147 * such that we can see the border also if all our
148 * windows are black and/or white
149 * (black (or white) border around black (or white) window
150 * is not very helpful.
151 */
152 if (c->screen->depth <= 8) {
153 XSetWindowBorderWidth(dpy, c->parent, 1);
156 XReparentWindow(dpy, c->window, c->parent, BORDER, BORDER);
157 #ifdef SHAPE
158 if (shape) {
159 XShapeSelectInput(dpy, c->window, ShapeNotifyMask);
160 ignore_badwindow = 1; /* magic */
161 setshape(c);
162 ignore_badwindow = 0;
164 #endif
165 XAddToSaveSet(dpy, c->window);
166 if (dohide)
167 hide(c);
168 else {
169 XMapWindow(dpy, c->window);
170 XMapWindow(dpy, c->parent);
171 XUnmapWindow(dpy, c->screen->sweepwin);
172 if (nostalgia || doreshape)
173 active(c);
174 else if (c->trans != None && current && current->window == c->trans)
175 active(c);
176 else
177 setactive(c, 0);
178 setstate(c, NormalState);
180 if (current && (current != c))
181 cmapfocus(current);
182 c->init = 1;
184 /*
185 * If we swept the window, let's send a resize event to the
186 * guy who just got resized. It's not clear whether the apps
187 * should notice their new size via other means. Try as I might,
188 * I can't find a way to have them notice during initdraw, so
189 * I solve the problem this way instead. -rsc
190 */
191 if(c->is9term)
192 sendconfig(c);
193 return 1;
196 void
197 scanwins(ScreenInfo *s)
199 unsigned int i, nwins;
200 Client *c;
201 Window dw1, dw2, *wins;
202 XWindowAttributes attr;
204 XQueryTree(dpy, s->root, &dw1, &dw2, &wins, &nwins);
205 for (i = 0; i < nwins; i++) {
206 XGetWindowAttributes(dpy, wins[i], &attr);
207 if (attr.override_redirect || wins[i] == s->menuwin)
208 continue;
209 c = getclient(wins[i], 1);
210 if (c != 0 && c->window == wins[i] && !c->init) {
211 c->x = attr.x;
212 c->y = attr.y;
213 c->dx = attr.width;
214 c->dy = attr.height;
215 c->border = attr.border_width;
216 c->screen = s;
217 c->parent = s->root;
218 if (attr.map_state == IsViewable)
219 manage(c, 1);
222 XFree((void *) wins); /* cast is to shut stoopid compiler up */
225 void
226 gettrans(Client *c)
228 Window trans;
230 trans = None;
231 if (XGetTransientForHint(dpy, c->window, &trans) != 0)
232 c->trans = trans;
233 else
234 c->trans = None;
237 void
238 withdraw(Client *c)
240 XUnmapWindow(dpy, c->parent);
241 gravitate(c, 1);
242 XReparentWindow(dpy, c->window, c->screen->root, c->x, c->y);
243 gravitate(c, 0);
244 XRemoveFromSaveSet(dpy, c->window);
245 setstate(c, WithdrawnState);
247 /* flush any errors */
248 ignore_badwindow = 1;
249 XSync(dpy, False);
250 ignore_badwindow = 0;
253 void
254 gravitate(Client *c, int invert)
256 int gravity, dx, dy, delta;
258 gravity = NorthWestGravity;
259 if (c->size.flags & PWinGravity)
260 gravity = c->size.win_gravity;
262 delta = c->border-BORDER;
263 switch (gravity) {
264 case NorthWestGravity:
265 dx = 0;
266 dy = 0;
267 break;
268 case NorthGravity:
269 dx = delta;
270 dy = 0;
271 break;
272 case NorthEastGravity:
273 dx = 2*delta;
274 dy = 0;
275 break;
276 case WestGravity:
277 dx = 0;
278 dy = delta;
279 break;
280 case CenterGravity:
281 case StaticGravity:
282 dx = delta;
283 dy = delta;
284 break;
285 case EastGravity:
286 dx = 2*delta;
287 dy = delta;
288 break;
289 case SouthWestGravity:
290 dx = 0;
291 dy = 2*delta;
292 break;
293 case SouthGravity:
294 dx = delta;
295 dy = 2*delta;
296 break;
297 case SouthEastGravity:
298 dx = 2*delta;
299 dy = 2*delta;
300 break;
301 default:
302 fprintf(stderr, "rio: bad window gravity %d for 0x%x\n", gravity, (int)c->window);
303 return;
305 dx += BORDER;
306 dy += BORDER;
307 if (invert) {
308 dx = -dx;
309 dy = -dy;
311 c->x += dx;
312 c->y += dy;
315 static void
316 installcmap(ScreenInfo *s, Colormap cmap)
318 if (cmap == None)
319 XInstallColormap(dpy, s->def_cmap);
320 else
321 XInstallColormap(dpy, cmap);
324 void
325 cmapfocus(Client *c)
327 int i, found;
328 Client *cc;
330 if (c == 0)
331 return;
332 else if (c->ncmapwins != 0) {
333 found = 0;
334 for (i = c->ncmapwins-1; i >= 0; i--) {
335 installcmap(c->screen, c->wmcmaps[i]);
336 if (c->cmapwins[i] == c->window)
337 found++;
339 if (!found)
340 installcmap(c->screen, c->cmap);
342 else if (c->trans != None && (cc = getclient(c->trans, 0)) != 0 && cc->ncmapwins != 0)
343 cmapfocus(cc);
344 else
345 installcmap(c->screen, c->cmap);
348 void
349 cmapnofocus(ScreenInfo *s)
351 installcmap(s, None);
354 void
355 getcmaps(Client *c)
357 int n, i;
358 Window *cw;
359 XWindowAttributes attr;
361 if (!c->init) {
362 ignore_badwindow = 1;
363 XGetWindowAttributes(dpy, c->window, &attr);
364 c->cmap = attr.colormap;
365 XSync(dpy, False);
366 ignore_badwindow = 0;
369 n = _getprop(c->window, wm_colormaps, XA_WINDOW, 100L, (void*)&cw);
370 if (c->ncmapwins != 0) {
371 XFree((char *)c->cmapwins);
372 free((char *)c->wmcmaps);
374 if (n <= 0) {
375 c->ncmapwins = 0;
376 return;
379 c->ncmapwins = n;
380 c->cmapwins = cw;
382 c->wmcmaps = (Colormap*)malloc(n*sizeof(Colormap));
383 for (i = 0; i < n; i++) {
384 if (cw[i] == c->window)
385 c->wmcmaps[i] = c->cmap;
386 else {
387 /* flush any errors (e.g., caused by mozilla tabs) */
388 ignore_badwindow = 1;
389 XSelectInput(dpy, cw[i], ColormapChangeMask);
390 XGetWindowAttributes(dpy, cw[i], &attr);
391 c->wmcmaps[i] = attr.colormap;
392 XSync(dpy, False);
393 ignore_badwindow = 0;
398 void
399 setlabel(Client *c)
401 char *label, *p;
403 if (c->iconname != 0)
404 label = c->iconname;
405 else if (c->name != 0)
406 label = c->name;
407 else if (c->instance != 0)
408 label = c->instance;
409 else if (c->class != 0)
410 label = c->class;
411 else
412 label = "no label";
413 if ((p = index(label, ':')) != 0)
414 *p = '\0';
415 c->label = label;
418 #ifdef SHAPE
419 void
420 setshape(Client *c)
422 int n, order;
423 XRectangle *rect;
425 /* don't try to add a border if the window is non-rectangular */
426 rect = XShapeGetRectangles(dpy, c->window, ShapeBounding, &n, &order);
427 if (n > 1)
428 XShapeCombineShape(dpy, c->parent, ShapeBounding, BORDER, BORDER,
429 c->window, ShapeBounding, ShapeSet);
430 XFree((void*)rect);
432 #endif
434 int
435 _getprop(Window w, Atom a, Atom type, long len, unsigned char **p)
437 Atom real_type;
438 int format;
439 unsigned long n, extra;
440 int status;
442 status = XGetWindowProperty(dpy, w, a, 0L, len, False, type, &real_type, &format, &n, &extra, p);
443 if (status != Success || *p == 0)
444 return -1;
445 if (n == 0)
446 XFree((void*) *p);
447 /* could check real_type, format, extra here... */
448 return n;
451 char *
452 getprop(Window w, Atom a)
454 unsigned char *p;
456 if (_getprop(w, a, XA_STRING, 100L, &p) <= 0)
457 return 0;
458 return (char *)p;
461 int
462 get1prop(Window w, Atom a, Atom type)
464 char **p, *x;
466 if (_getprop(w, a, type, 1L, (void*)&p) <= 0)
467 return 0;
468 x = *p;
469 XFree((void*) p);
470 return (int)x;
473 Window
474 getwprop(Window w, Atom a)
476 return get1prop(w, a, XA_WINDOW);
479 int
480 getiprop(Window w, Atom a)
482 return get1prop(w, a, XA_INTEGER);
485 void
486 setstate(Client *c, int state)
488 long data[2];
490 data[0] = (long) state;
491 data[1] = (long) None;
493 c->state = state;
494 XChangeProperty(dpy, c->window, wm_state, wm_state, 32,
495 PropModeReplace, (unsigned char *)data, 2);
498 int
499 getstate(Window w, int *state)
501 long *p = 0;
503 if (_getprop(w, wm_state, wm_state, 2L, (void*)&p) <= 0)
504 return 0;
506 *state = (int) *p;
507 XFree((char *) p);
508 return 1;
511 void
512 getproto(Client *c)
514 Atom *p;
515 int i;
516 long n;
517 Window w;
519 w = c->window;
520 c->proto = 0;
521 if ((n = _getprop(w, wm_protocols, XA_ATOM, 20L, (void*)&p)) <= 0)
522 return;
524 for (i = 0; i < n; i++)
525 if (p[i] == wm_delete)
526 c->proto |= Pdelete;
527 else if (p[i] == wm_take_focus)
528 c->proto |= Ptakefocus;
529 else if (p[i] == wm_lose_focus)
530 c->proto |= Plosefocus;
532 XFree((char *) p);