tmanage.c - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
tmanage.c (10084B) | |
--- | |
1 /* | |
2 * Window management. | |
3 */ | |
4 | |
5 /* Copyright (c) 1994-1996 David Hogan, see README for licence details */ | |
6 #include <stdio.h> | |
7 #include <stdlib.h> | |
8 #include <inttypes.h> | |
9 #include <X11/X.h> | |
10 #include <X11/Xos.h> | |
11 #include <X11/Xlib.h> | |
12 #include <X11/Xutil.h> | |
13 #include <X11/Xatom.h> | |
14 #include <X11/extensions/shape.h> | |
15 #include "dat.h" | |
16 #include "fns.h" | |
17 | |
18 int isNew; | |
19 | |
20 int | |
21 manage(Client *c, int mapped) | |
22 { | |
23 int fixsize, dohide, doreshape, state; | |
24 long msize; | |
25 XClassHint class; | |
26 XWMHints *hints; | |
27 XSetWindowAttributes attrs; | |
28 | |
29 trace("manage", c, 0); | |
30 XSelectInput(dpy, c->window, ColormapChangeMask | EnterWindowMas… | |
31 | |
32 /* Get loads of hints */ | |
33 | |
34 if(XGetClassHint(dpy, c->window, &class) != 0){ /* ``Succ… | |
35 c->instance = class.res_name; | |
36 c->class = class.res_class; | |
37 c->is9term = 0; | |
38 if(isNew){ | |
39 c->is9term = strstr(c->class, "term") || strstr(… | |
40 isNew = 0; | |
41 } | |
42 } | |
43 else { | |
44 c->instance = 0; | |
45 c->class = 0; | |
46 c->is9term = 0; | |
47 } | |
48 c->iconname = getprop(c->window, XA_WM_ICON_NAME); | |
49 c->name = getprop(c->window, XA_WM_NAME); | |
50 setlabel(c); | |
51 | |
52 hints = XGetWMHints(dpy, c->window); | |
53 if(XGetWMNormalHints(dpy, c->window, &c->size, &msize) == 0 || c… | |
54 c->size.flags = PSize; /* not specified -… | |
55 | |
56 getcmaps(c); | |
57 getproto(c); | |
58 gettrans(c); | |
59 if(c->is9term) | |
60 c->hold = getiprop(c->window, _rio_hold_mode); | |
61 | |
62 /* Figure out what to do with the window from hints */ | |
63 | |
64 if(!getstate(c->window, &state)) | |
65 state = hints ? hints->initial_state : NormalState; | |
66 dohide = (state == IconicState); | |
67 | |
68 fixsize = 0; | |
69 if((c->size.flags & (USSize|PSize))) | |
70 fixsize = 1; | |
71 if((c->size.flags & (PMinSize|PMaxSize)) == (PMinSize|PMaxSize) … | |
72 fixsize = 1; | |
73 doreshape = !mapped; | |
74 if(fixsize){ | |
75 if(c->size.flags & USPosition) | |
76 doreshape = 0; | |
77 if(dohide && (c->size.flags & PPosition)) | |
78 doreshape = 0; | |
79 if(c->trans != None) | |
80 doreshape = 0; | |
81 } | |
82 if(c->is9term) | |
83 fixsize = 0; | |
84 if(c->size.flags & PBaseSize){ | |
85 c->min_dx = c->size.base_width; | |
86 c->min_dy = c->size.base_height; | |
87 } | |
88 else if(c->size.flags & PMinSize){ | |
89 c->min_dx = c->size.min_width; | |
90 c->min_dy = c->size.min_height; | |
91 } | |
92 else if(c->is9term){ | |
93 c->min_dx = 100; | |
94 c->min_dy = 50; | |
95 } | |
96 else | |
97 c->min_dx = c->min_dy = 0; | |
98 | |
99 if(hints) | |
100 XFree(hints); | |
101 | |
102 /* Now do it!!! */ | |
103 | |
104 if(doreshape){ | |
105 if(0) fprintf(stderr, "in doreshape is9term=%d fixsize=%… | |
106 c->is9term, fixsize, c->x, c->y, c->min_… | |
107 if(current && current->screen == c->screen) | |
108 cmapnofocus(c->screen); | |
109 if(!c->is9term && c->x==0 && c->y==0){ | |
110 static int nwin; | |
111 | |
112 c->x = 20*nwin+BORDER; | |
113 c->y = 20*nwin+BORDER; | |
114 nwin++; | |
115 nwin %= 10; | |
116 } | |
117 | |
118 if(c->is9term && !(fixsize ? drag(c, Button3) : sweep(c,… | |
119 XKillClient(dpy, c->window); | |
120 rmclient(c); | |
121 if(current && current->screen == c->screen) | |
122 cmapfocus(current); | |
123 return 0; | |
124 } | |
125 } | |
126 | |
127 attrs.border_pixel = c->screen->black; | |
128 attrs.background_pixel = c->screen->white; | |
129 attrs.colormap = c->screen->def_cmap; | |
130 c->parent = XCreateWindow(dpy, c->screen->root, | |
131 c->x - BORDER, c->y - BORDER, | |
132 c->dx + 2*BORDER, c->dy + 2*BORDER, | |
133 0, | |
134 c->screen->depth, | |
135 CopyFromParent, | |
136 c->screen->vis, | |
137 CWBackPixel | CWBorderPixel | CWColormap, | |
138 &attrs); | |
139 | |
140 XSelectInput(dpy, c->parent, SubstructureRedirectMask | Substruc… | |
141 if(mapped) | |
142 c->reparenting = 1; | |
143 if(doreshape && !fixsize) | |
144 XResizeWindow(dpy, c->window, c->dx, c->dy); | |
145 XSetWindowBorderWidth(dpy, c->window, 0); | |
146 | |
147 /* | |
148 * To have something more than only a big white or black border | |
149 * XXX should replace this by a pattern in the white or black | |
150 * such that we can see the border also if all our | |
151 * windows are black and/or white | |
152 * (black (or white) border around black (or white) window | |
153 * is not very helpful. | |
154 */ | |
155 if(c->screen->depth <= 8){ | |
156 XSetWindowBorderWidth(dpy, c->parent, 1); | |
157 } | |
158 | |
159 XReparentWindow(dpy, c->window, c->parent, BORDER, BORDER); | |
160 #ifdef SHAPE | |
161 if(shape){ | |
162 XShapeSelectInput(dpy, c->window, ShapeNotifyMask); | |
163 ignore_badwindow = 1; /* magic */ | |
164 setshape(c); | |
165 ignore_badwindow = 0; | |
166 } | |
167 #endif | |
168 XAddToSaveSet(dpy, c->window); | |
169 if(dohide) | |
170 hide(c); | |
171 else { | |
172 XMapWindow(dpy, c->window); | |
173 XMapWindow(dpy, c->parent); | |
174 XUnmapWindow(dpy, c->screen->sweepwin); | |
175 if(nostalgia || doreshape) | |
176 active(c); | |
177 else if(c->trans != None && current && current->window =… | |
178 active(c); | |
179 else | |
180 setactive(c, 0); | |
181 setstate(c, NormalState); | |
182 } | |
183 if(current && (current != c)) | |
184 cmapfocus(current); | |
185 c->init = 1; | |
186 | |
187 /* | |
188 * If we swept the window, let's send a resize event to the | |
189 * guy who just got resized. It's not clear whether the apps | |
190 * should notice their new size via other means. Try as I might, | |
191 * I can't find a way to have them notice during initdraw, so | |
192 * I solve the problem this way instead. -rsc | |
193 */ | |
194 if(c->is9term) | |
195 sendconfig(c); | |
196 return 1; | |
197 } | |
198 | |
199 void | |
200 scanwins(ScreenInfo *s) | |
201 { | |
202 unsigned int i, nwins; | |
203 Client *c; | |
204 Window dw1, dw2, *wins; | |
205 XWindowAttributes attr; | |
206 | |
207 XQueryTree(dpy, s->root, &dw1, &dw2, &wins, &nwins); | |
208 for(i = 0; i < nwins; i++){ | |
209 XGetWindowAttributes(dpy, wins[i], &attr); | |
210 if(attr.override_redirect || wins[i] == s->menuwin) | |
211 continue; | |
212 c = getclient(wins[i], 1); | |
213 if(c != 0 && c->window == wins[i] && !c->init){ | |
214 c->x = attr.x; | |
215 c->y = attr.y; | |
216 c->dx = attr.width; | |
217 c->dy = attr.height; | |
218 c->border = attr.border_width; | |
219 c->screen = s; | |
220 c->parent = s->root; | |
221 if(attr.map_state == IsViewable) | |
222 manage(c, 1); | |
223 } | |
224 } | |
225 XFree((void *) wins); /* cast is to shut stoopid compiler… | |
226 } | |
227 | |
228 void | |
229 gettrans(Client *c) | |
230 { | |
231 Window trans; | |
232 | |
233 trans = None; | |
234 if(XGetTransientForHint(dpy, c->window, &trans) != 0) | |
235 c->trans = trans; | |
236 else | |
237 c->trans = None; | |
238 } | |
239 | |
240 void | |
241 withdraw(Client *c) | |
242 { | |
243 XUnmapWindow(dpy, c->parent); | |
244 XReparentWindow(dpy, c->window, c->screen->root, c->x, c->y); | |
245 XRemoveFromSaveSet(dpy, c->window); | |
246 setstate(c, WithdrawnState); | |
247 | |
248 /* flush any errors */ | |
249 ignore_badwindow = 1; | |
250 XSync(dpy, False); | |
251 ignore_badwindow = 0; | |
252 } | |
253 | |
254 static void | |
255 installcmap(ScreenInfo *s, Colormap cmap) | |
256 { | |
257 if(cmap == None) | |
258 XInstallColormap(dpy, s->def_cmap); | |
259 else | |
260 XInstallColormap(dpy, cmap); | |
261 } | |
262 | |
263 void | |
264 cmapfocus(Client *c) | |
265 { | |
266 int i, found; | |
267 Client *cc; | |
268 | |
269 if(c == 0) | |
270 return; | |
271 else if(c->ncmapwins != 0){ | |
272 found = 0; | |
273 for(i = c->ncmapwins-1; i >= 0; i--){ | |
274 installcmap(c->screen, c->wmcmaps[i]); | |
275 if(c->cmapwins[i] == c->window) | |
276 found++; | |
277 } | |
278 if(!found) | |
279 installcmap(c->screen, c->cmap); | |
280 } | |
281 else if(c->trans != None && (cc = getclient(c->trans, 0)) != 0 &… | |
282 cmapfocus(cc); | |
283 else | |
284 installcmap(c->screen, c->cmap); | |
285 } | |
286 | |
287 void | |
288 cmapnofocus(ScreenInfo *s) | |
289 { | |
290 installcmap(s, None); | |
291 } | |
292 | |
293 void | |
294 getcmaps(Client *c) | |
295 { | |
296 int n, i; | |
297 Window *cw; | |
298 XWindowAttributes attr; | |
299 | |
300 if(!c->init){ | |
301 ignore_badwindow = 1; | |
302 XGetWindowAttributes(dpy, c->window, &attr); | |
303 c->cmap = attr.colormap; | |
304 XSync(dpy, False); | |
305 ignore_badwindow = 0; | |
306 } | |
307 | |
308 n = _getprop(c->window, wm_colormaps, XA_WINDOW, 100L, (void*)&c… | |
309 if(c->ncmapwins != 0){ | |
310 XFree((char *)c->cmapwins); | |
311 free((char *)c->wmcmaps); | |
312 } | |
313 if(n <= 0){ | |
314 c->ncmapwins = 0; | |
315 return; | |
316 } | |
317 | |
318 c->ncmapwins = n; | |
319 c->cmapwins = cw; | |
320 | |
321 c->wmcmaps = (Colormap*)malloc(n*sizeof(Colormap)); | |
322 for(i = 0; i < n; i++){ | |
323 if(cw[i] == c->window) | |
324 c->wmcmaps[i] = c->cmap; | |
325 else { | |
326 /* flush any errors (e.g., caused by mozilla tab… | |
327 ignore_badwindow = 1; | |
328 XSelectInput(dpy, cw[i], ColormapChangeMask); | |
329 XGetWindowAttributes(dpy, cw[i], &attr); | |
330 c->wmcmaps[i] = attr.colormap; | |
331 XSync(dpy, False); | |
332 ignore_badwindow = 0; | |
333 } | |
334 } | |
335 } | |
336 | |
337 void | |
338 setlabel(Client *c) | |
339 { | |
340 char *label, *p; | |
341 | |
342 if(c->iconname != 0) | |
343 label = c->iconname; | |
344 else if(c->name != 0) | |
345 label = c->name; | |
346 else if(c->instance != 0) | |
347 label = c->instance; | |
348 else if(c->class != 0) | |
349 label = c->class; | |
350 else | |
351 label = "no label"; | |
352 if((p = index(label, ':')) != 0) | |
353 *p = '\0'; | |
354 c->label = label; | |
355 } | |
356 | |
357 #ifdef SHAPE | |
358 void | |
359 setshape(Client *c) | |
360 { | |
361 int n, order; | |
362 XRectangle *rect; | |
363 | |
364 /* don't try to add a border if the window is non-rectangular */ | |
365 rect = XShapeGetRectangles(dpy, c->window, ShapeBounding, &n, &o… | |
366 if(n > 1) | |
367 XShapeCombineShape(dpy, c->parent, ShapeBounding, BORDER… | |
368 c->window, ShapeBounding, ShapeSet); | |
369 XFree((void*)rect); | |
370 } | |
371 #endif | |
372 | |
373 int | |
374 _getprop(Window w, Atom a, Atom type, long len, unsigned char **p) | |
375 { | |
376 Atom real_type; | |
377 int format; | |
378 unsigned long n, extra; | |
379 int status; | |
380 | |
381 status = XGetWindowProperty(dpy, w, a, 0L, len, False, type, &re… | |
382 if(status != Success || *p == 0) | |
383 return -1; | |
384 if(n == 0) | |
385 XFree((void*) *p); | |
386 /* could check real_type, format, extra here... */ | |
387 return n; | |
388 } | |
389 | |
390 char * | |
391 getprop(Window w, Atom a) | |
392 { | |
393 unsigned char *p; | |
394 | |
395 if(_getprop(w, a, XA_STRING, 100L, &p) <= 0) | |
396 return 0; | |
397 return (char *)p; | |
398 } | |
399 | |
400 int | |
401 get1prop(Window w, Atom a, Atom type) | |
402 { | |
403 char **p, *x; | |
404 | |
405 if(_getprop(w, a, type, 1L, (void*)&p) <= 0) | |
406 return 0; | |
407 x = *p; | |
408 XFree((void*) p); | |
409 return (int)(uintptr_t)x; | |
410 } | |
411 | |
412 Window | |
413 getwprop(Window w, Atom a) | |
414 { | |
415 return get1prop(w, a, XA_WINDOW); | |
416 } | |
417 | |
418 int | |
419 getiprop(Window w, Atom a) | |
420 { | |
421 return get1prop(w, a, XA_INTEGER); | |
422 } | |
423 | |
424 void | |
425 setstate(Client *c, int state) | |
426 { | |
427 long data[2]; | |
428 | |
429 data[0] = (long) state; | |
430 data[1] = (long) None; | |
431 | |
432 c->state = state; | |
433 XChangeProperty(dpy, c->window, wm_state, wm_state, 32, | |
434 PropModeReplace, (unsigned char *)data, 2); | |
435 } | |
436 | |
437 int | |
438 getstate(Window w, int *state) | |
439 { | |
440 long *p = 0; | |
441 | |
442 if(_getprop(w, wm_state, wm_state, 2L, (void*)&p) <= 0) | |
443 return 0; | |
444 | |
445 *state = (int) *p; | |
446 XFree((char *) p); | |
447 return 1; | |
448 } | |
449 | |
450 void | |
451 getproto(Client *c) | |
452 { | |
453 Atom *p; | |
454 int i; | |
455 long n; | |
456 Window w; | |
457 | |
458 w = c->window; | |
459 c->proto = 0; | |
460 if((n = _getprop(w, wm_protocols, XA_ATOM, 20L, (void*)&p)) <= 0) | |
461 return; | |
462 | |
463 for(i = 0; i < n; i++) | |
464 if(p[i] == wm_delete) | |
465 c->proto |= Pdelete; | |
466 else if(p[i] == wm_take_focus) | |
467 c->proto |= Ptakefocus; | |
468 else if(p[i] == wm_lose_focus) | |
469 c->proto |= Plosefocus; | |
470 | |
471 XFree((char *) p); | |
472 } |