manage.c (10205B)
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 | EnterWindowMask | PropertyChangeMask | FocusChangeMask | KeyPressMask); 31 32 /* Get loads of hints */ 33 34 if(XGetClassHint(dpy, c->window, &class) != 0){ /* ``Success'' */ 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(c->class, "Term"); 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->size.flags == 0) 54 c->size.flags = PSize; /* not specified - punt */ 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) && c->size.min_width == c->size.max_width && c->size.min_height == c->size.max_height) 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=%d, x=%d, y=%d, min_dx=%d, min_dy=%d, dx=%d, dy=%d\n", 106 c->is9term, fixsize, c->x, c->y, c->min_dx, c->min_dy, c->dx, c->dy); 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, Button3))){ 119 ScreenInfo *screen = c->screen; 120 XKillClient(dpy, c->window); 121 rmclient(c); 122 if(current && current->screen == screen) 123 cmapfocus(current); 124 return 0; 125 } 126 } 127 128 attrs.border_pixel = c->screen->black; 129 attrs.background_pixel = c->screen->white; 130 attrs.colormap = c->screen->def_cmap; 131 c->parent = XCreateWindow(dpy, c->screen->root, 132 c->x - BORDER, c->y - BORDER, 133 c->dx + 2*BORDER, c->dy + 2*BORDER, 134 0, 135 c->screen->depth, 136 CopyFromParent, 137 c->screen->vis, 138 CWBackPixel | CWBorderPixel | CWColormap, 139 &attrs); 140 141 XSelectInput(dpy, c->parent, SubstructureRedirectMask | SubstructureNotifyMask|ButtonPressMask| PointerMotionMask|LeaveWindowMask|KeyPressMask); 142 if(mapped) 143 c->reparenting = 1; 144 if(doreshape && !fixsize) 145 XResizeWindow(dpy, c->window, c->dx, c->dy); 146 XSetWindowBorderWidth(dpy, c->window, 0); 147 148 /* 149 * To have something more than only a big white or black border 150 * XXX should replace this by a pattern in the white or black 151 * such that we can see the border also if all our 152 * windows are black and/or white 153 * (black (or white) border around black (or white) window 154 * is not very helpful. 155 */ 156 if(c->screen->depth <= 8){ 157 XSetWindowBorderWidth(dpy, c->parent, 1); 158 } 159 160 XReparentWindow(dpy, c->window, c->parent, BORDER, BORDER); 161 #ifdef SHAPE 162 if(shape){ 163 XShapeSelectInput(dpy, c->window, ShapeNotifyMask); 164 ignore_badwindow = 1; /* magic */ 165 setshape(c); 166 ignore_badwindow = 0; 167 } 168 #endif 169 XAddToSaveSet(dpy, c->window); 170 if(dohide) 171 hide(c); 172 else { 173 XMapWindow(dpy, c->window); 174 XMapWindow(dpy, c->parent); 175 XUnmapWindow(dpy, c->screen->sweepwin); 176 if(nostalgia || doreshape) 177 active(c); 178 else if(c->trans != None && current && current->window == c->trans) 179 active(c); 180 else 181 setactive(c, 0); 182 setstate(c, NormalState); 183 } 184 if(current && (current != c)) 185 cmapfocus(current); 186 c->init = 1; 187 188 /* 189 * If we swept the window, let's send a resize event to the 190 * guy who just got resized. It's not clear whether the apps 191 * should notice their new size via other means. Try as I might, 192 * I can't find a way to have them notice during initdraw, so 193 * I solve the problem this way instead. -rsc 194 */ 195 if(c->is9term) 196 sendconfig(c); 197 return 1; 198 } 199 200 void 201 scanwins(ScreenInfo *s) 202 { 203 unsigned int i, nwins; 204 Client *c; 205 Window dw1, dw2, *wins; 206 XWindowAttributes attr; 207 208 XQueryTree(dpy, s->root, &dw1, &dw2, &wins, &nwins); 209 for(i = 0; i < nwins; i++){ 210 XGetWindowAttributes(dpy, wins[i], &attr); 211 if(attr.override_redirect || wins[i] == s->menuwin) 212 continue; 213 c = getclient(wins[i], 1); 214 if(c != 0 && c->window == wins[i] && !c->init){ 215 c->x = attr.x; 216 c->y = attr.y; 217 c->dx = attr.width; 218 c->dy = attr.height; 219 c->border = attr.border_width; 220 c->screen = s; 221 c->parent = s->root; 222 if(attr.map_state == IsViewable) 223 manage(c, 1); 224 } 225 } 226 XFree((void *) wins); /* cast is to shut stoopid compiler up */ 227 } 228 229 void 230 gettrans(Client *c) 231 { 232 Window trans; 233 234 trans = None; 235 if(XGetTransientForHint(dpy, c->window, &trans) != 0) 236 c->trans = trans; 237 else 238 c->trans = None; 239 } 240 241 void 242 withdraw(Client *c) 243 { 244 XUnmapWindow(dpy, c->parent); 245 XReparentWindow(dpy, c->window, c->screen->root, c->x, c->y); 246 XRemoveFromSaveSet(dpy, c->window); 247 setstate(c, WithdrawnState); 248 249 /* flush any errors */ 250 ignore_badwindow = 1; 251 XSync(dpy, False); 252 ignore_badwindow = 0; 253 } 254 255 static void 256 installcmap(ScreenInfo *s, Colormap cmap) 257 { 258 if(cmap == None) 259 XInstallColormap(dpy, s->def_cmap); 260 else 261 XInstallColormap(dpy, cmap); 262 } 263 264 void 265 cmapfocus(Client *c) 266 { 267 int i, found; 268 Client *cc; 269 270 if(c == 0) 271 return; 272 else if(c->ncmapwins != 0){ 273 found = 0; 274 for(i = c->ncmapwins-1; i >= 0; i--){ 275 installcmap(c->screen, c->wmcmaps[i]); 276 if(c->cmapwins[i] == c->window) 277 found++; 278 } 279 if(!found) 280 installcmap(c->screen, c->cmap); 281 } 282 else if(c->trans != None && (cc = getclient(c->trans, 0)) != 0 && cc->ncmapwins != 0) 283 cmapfocus(cc); 284 else 285 installcmap(c->screen, c->cmap); 286 } 287 288 void 289 cmapnofocus(ScreenInfo *s) 290 { 291 installcmap(s, None); 292 } 293 294 void 295 getcmaps(Client *c) 296 { 297 int n, i; 298 Window *cw; 299 XWindowAttributes attr; 300 301 if(!c->init){ 302 ignore_badwindow = 1; 303 XGetWindowAttributes(dpy, c->window, &attr); 304 c->cmap = attr.colormap; 305 XSync(dpy, False); 306 ignore_badwindow = 0; 307 } 308 309 n = _getprop(c->window, wm_colormaps, XA_WINDOW, 100L, (void*)&cw); 310 if(c->ncmapwins != 0){ 311 XFree((char *)c->cmapwins); 312 free((char *)c->wmcmaps); 313 } 314 if(n <= 0){ 315 c->ncmapwins = 0; 316 return; 317 } 318 319 c->ncmapwins = n; 320 c->cmapwins = cw; 321 322 c->wmcmaps = (Colormap*)malloc(n*sizeof(Colormap)); 323 if (!c->wmcmaps){ 324 fprintf(stderr, "rio: Failed to allocate memory\n"); 325 exit(1); 326 } 327 328 for(i = 0; i < n; i++){ 329 if(cw[i] == c->window) 330 c->wmcmaps[i] = c->cmap; 331 else { 332 /* flush any errors (e.g., caused by mozilla tabs) */ 333 ignore_badwindow = 1; 334 XSelectInput(dpy, cw[i], ColormapChangeMask); 335 XGetWindowAttributes(dpy, cw[i], &attr); 336 c->wmcmaps[i] = attr.colormap; 337 XSync(dpy, False); 338 ignore_badwindow = 0; 339 } 340 } 341 } 342 343 void 344 setlabel(Client *c) 345 { 346 char *label, *p; 347 348 if(c->iconname != 0) 349 label = c->iconname; 350 else if(c->name != 0) 351 label = c->name; 352 else if(c->instance != 0) 353 label = c->instance; 354 else if(c->class != 0) 355 label = c->class; 356 else 357 label = "no label"; 358 if((p = index(label, ':')) != 0) 359 *p = '\0'; 360 c->label = label; 361 } 362 363 #ifdef SHAPE 364 void 365 setshape(Client *c) 366 { 367 int n, order; 368 XRectangle *rect; 369 370 /* don't try to add a border if the window is non-rectangular */ 371 rect = XShapeGetRectangles(dpy, c->window, ShapeBounding, &n, &order); 372 if(n > 1) 373 XShapeCombineShape(dpy, c->parent, ShapeBounding, BORDER, BORDER, 374 c->window, ShapeBounding, ShapeSet); 375 XFree((void*)rect); 376 } 377 #endif 378 379 int 380 _getprop(Window w, Atom a, Atom type, long len, unsigned char **p) 381 { 382 Atom real_type; 383 int format; 384 unsigned long n, extra; 385 int status; 386 387 status = XGetWindowProperty(dpy, w, a, 0L, len, False, type, &real_type, &format, &n, &extra, p); 388 if(status != Success || *p == 0) 389 return -1; 390 if(n == 0) 391 XFree((void*) *p); 392 /* could check real_type, format, extra here... */ 393 return n; 394 } 395 396 char * 397 getprop(Window w, Atom a) 398 { 399 unsigned char *p; 400 401 if(_getprop(w, a, XA_STRING, 100L, &p) <= 0) 402 return 0; 403 return (char *)p; 404 } 405 406 int 407 get1prop(Window w, Atom a, Atom type) 408 { 409 char **p, *x; 410 411 if(_getprop(w, a, type, 1L, (void*)&p) <= 0) 412 return 0; 413 x = *p; 414 XFree((void*) p); 415 return (int)(uintptr_t)x; 416 } 417 418 Window 419 getwprop(Window w, Atom a) 420 { 421 return get1prop(w, a, XA_WINDOW); 422 } 423 424 int 425 getiprop(Window w, Atom a) 426 { 427 return get1prop(w, a, XA_INTEGER); 428 } 429 430 void 431 setstate(Client *c, int state) 432 { 433 long data[2]; 434 435 data[0] = (long) state; 436 data[1] = (long) None; 437 438 c->state = state; 439 XChangeProperty(dpy, c->window, wm_state, wm_state, 32, 440 PropModeReplace, (unsigned char *)data, 2); 441 } 442 443 int 444 getstate(Window w, int *state) 445 { 446 long *p = 0; 447 448 if(_getprop(w, wm_state, wm_state, 2L, (void*)&p) <= 0) 449 return 0; 450 451 *state = (int) *p; 452 XFree((char *) p); 453 return 1; 454 } 455 456 void 457 getproto(Client *c) 458 { 459 Atom *p; 460 int i; 461 long n; 462 Window w; 463 464 w = c->window; 465 c->proto = 0; 466 if((n = _getprop(w, wm_protocols, XA_ATOM, 20L, (void*)&p)) <= 0) 467 return; 468 469 for(i = 0; i < n; i++) 470 if(p[i] == wm_delete) 471 c->proto |= Pdelete; 472 else if(p[i] == wm_take_focus) 473 c->proto |= Ptakefocus; 474 else if(p[i] == wm_lose_focus) 475 c->proto |= Plosefocus; 476 477 XFree((char *) p); 478 }