URI:
       tmanage.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR 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 | 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                         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 | SubstructureNotifyMask|ButtonPressMask| PointerMotionMask|LeaveWindowMask|KeyPressMask);
          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 == c->trans)
          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 up */
          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 && cc->ncmapwins != 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*)&cw);
          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 tabs) */
          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, &order);
          366         if(n > 1)
          367                 XShapeCombineShape(dpy, c->parent, ShapeBounding, BORDER, 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, &real_type, &format, &n, &extra, p);
          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 }