plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

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 }