plan9port/src/cmd/rio/manage.c

527 lines
11 KiB
C
Raw Normal View History

2004-03-21 04:27:28 +00:00
/* Copyright (c) 1994-1996 David Hogan, see README for licence details */
#include <stdio.h>
#include <stdlib.h>
2004-03-21 04:27:28 +00:00
#include <X11/X.h>
#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/extensions/shape.h>
#include "dat.h"
#include "fns.h"
int isNew;
2004-03-21 04:27:28 +00:00
int
manage(Client *c, int mapped)
{
int fixsize, dohide, doreshape, state;
long msize;
XClassHint class;
XWMHints *hints;
2004-03-30 05:01:53 +00:00
XSetWindowAttributes attrs;
2004-03-21 04:27:28 +00:00
trace("manage", c, 0);
XSelectInput(dpy, c->window, ColormapChangeMask | EnterWindowMask | PropertyChangeMask | FocusChangeMask);
/* Get loads of hints */
if (XGetClassHint(dpy, c->window, &class) != 0) { /* ``Success'' */
c->instance = class.res_name;
c->class = class.res_class;
c->is9term = 0;
if(isNew){
c->is9term = strstr(c->class, "term") || strstr(c->class, "Term");
isNew = 0;
}
2004-03-21 04:27:28 +00:00
}
else {
c->instance = 0;
c->class = 0;
c->is9term = 0;
}
c->iconname = getprop(c->window, XA_WM_ICON_NAME);
c->name = getprop(c->window, XA_WM_NAME);
setlabel(c);
hints = XGetWMHints(dpy, c->window);
if (XGetWMNormalHints(dpy, c->window, &c->size, &msize) == 0 || c->size.flags == 0)
c->size.flags = PSize; /* not specified - punt */
getcmaps(c);
getproto(c);
gettrans(c);
if (c->is9term)
2004-04-19 19:35:17 +00:00
c->hold = getiprop(c->window, _rio_hold_mode);
2004-03-21 04:27:28 +00:00
/* Figure out what to do with the window from hints */
if (!getstate(c->window, &state))
state = hints ? hints->initial_state : NormalState;
dohide = (state == IconicState);
fixsize = 0;
if ((c->size.flags & (USSize|PSize)))
fixsize = 1;
if ((c->size.flags & (PMinSize|PMaxSize)) == (PMinSize|PMaxSize) && c->size.min_width == c->size.max_width && c->size.min_height == c->size.max_height)
fixsize = 1;
doreshape = !mapped;
if (fixsize) {
if (c->size.flags & USPosition)
doreshape = 0;
if (dohide && (c->size.flags & PPosition))
doreshape = 0;
if (c->trans != None)
doreshape = 0;
}
if (c->is9term)
fixsize = 0;
if (c->size.flags & PBaseSize) {
c->min_dx = c->size.base_width;
c->min_dy = c->size.base_height;
}
else if (c->size.flags & PMinSize) {
c->min_dx = c->size.min_width;
c->min_dy = c->size.min_height;
}
else if (c->is9term) {
c->min_dx = 100;
c->min_dy = 50;
}
else
c->min_dx = c->min_dy = 0;
if (hints)
XFree(hints);
/* Now do it!!! */
if (doreshape) {
2004-04-05 21:02:10 +00:00
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",
c->is9term, fixsize, c->x, c->y, c->min_dx, c->min_dy, c->dx, c->dy);
2004-03-21 04:27:28 +00:00
if (current && current->screen == c->screen)
cmapnofocus(c->screen);
if (!c->is9term && c->x==0 && c->y==0) {
static int nwin;
c->x = 20*nwin+BORDER;
c->y = 20*nwin+BORDER;
nwin++;
nwin %= 10;
}
if (c->is9term && !(fixsize ? drag(c, Button3) : sweep(c, Button3))) {
2004-03-21 04:27:28 +00:00
XKillClient(dpy, c->window);
rmclient(c);
if (current && current->screen == c->screen)
cmapfocus(current);
return 0;
}
2004-04-05 22:01:23 +00:00
} else
2004-03-21 04:27:28 +00:00
gravitate(c, 0);
2004-04-05 22:01:23 +00:00
2004-03-30 05:01:53 +00:00
attrs.border_pixel = c->screen->black;
attrs.background_pixel = c->screen->white;
attrs.colormap = c->screen->def_cmap;
c->parent = XCreateWindow(dpy, c->screen->root,
2004-03-21 04:27:28 +00:00
c->x - BORDER, c->y - BORDER,
c->dx + 2*BORDER, c->dy + 2*BORDER,
0,
2004-03-30 05:01:53 +00:00
c->screen->depth,
CopyFromParent,
c->screen->vis,
CWBackPixel | CWBorderPixel | CWColormap,
&attrs);
XSelectInput(dpy, c->parent, SubstructureRedirectMask | SubstructureNotifyMask|ButtonPressMask| PointerMotionMask|LeaveWindowMask);
2004-03-21 04:27:28 +00:00
if (mapped)
c->reparenting = 1;
if (doreshape && !fixsize)
XResizeWindow(dpy, c->window, c->dx, c->dy);
XSetWindowBorderWidth(dpy, c->window, 0);
2004-03-30 05:01:53 +00:00
/*
* To have something more than only a big white or black border
* XXX should replace this by a pattern in the white or black
* such that we can see the border also if all our
* windows are black and/or white
* (black (or white) border around black (or white) window
* is not very helpful.
*/
if (c->screen->depth <= 8) {
XSetWindowBorderWidth(dpy, c->parent, 1);
}
2004-03-30 05:01:53 +00:00
2004-03-21 04:27:28 +00:00
XReparentWindow(dpy, c->window, c->parent, BORDER, BORDER);
#ifdef SHAPE
if (shape) {
XShapeSelectInput(dpy, c->window, ShapeNotifyMask);
ignore_badwindow = 1; /* magic */
setshape(c);
ignore_badwindow = 0;
}
#endif
XAddToSaveSet(dpy, c->window);
if (dohide)
hide(c);
else {
XMapWindow(dpy, c->window);
XMapWindow(dpy, c->parent);
XUnmapWindow(dpy, c->screen->sweepwin);
if (nostalgia || doreshape)
active(c);
else if (c->trans != None && current && current->window == c->trans)
active(c);
else
setactive(c, 0);
setstate(c, NormalState);
}
if (current && (current != c))
cmapfocus(current);
c->init = 1;
2004-03-30 05:01:53 +00:00
/*
* If we swept the window, let's send a resize event to the
* guy who just got resized. It's not clear whether the apps
* should notice their new size via other means. Try as I might,
* I can't find a way to have them notice during initdraw, so
* I solve the problem this way instead. -rsc
*/
if(c->is9term)
sendconfig(c);
2004-03-21 04:27:28 +00:00
return 1;
}
void
scanwins(ScreenInfo *s)
{
unsigned int i, nwins;
Client *c;
Window dw1, dw2, *wins;
XWindowAttributes attr;
XQueryTree(dpy, s->root, &dw1, &dw2, &wins, &nwins);
for (i = 0; i < nwins; i++) {
XGetWindowAttributes(dpy, wins[i], &attr);
if (attr.override_redirect || wins[i] == s->menuwin)
continue;
c = getclient(wins[i], 1);
if (c != 0 && c->window == wins[i] && !c->init) {
c->x = attr.x;
c->y = attr.y;
c->dx = attr.width;
c->dy = attr.height;
c->border = attr.border_width;
c->screen = s;
c->parent = s->root;
if (attr.map_state == IsViewable)
manage(c, 1);
}
}
XFree((void *) wins); /* cast is to shut stoopid compiler up */
}
void
gettrans(Client *c)
{
Window trans;
trans = None;
if (XGetTransientForHint(dpy, c->window, &trans) != 0)
c->trans = trans;
else
c->trans = None;
}
void
withdraw(Client *c)
{
XUnmapWindow(dpy, c->parent);
gravitate(c, 1);
XReparentWindow(dpy, c->window, c->screen->root, c->x, c->y);
gravitate(c, 0);
XRemoveFromSaveSet(dpy, c->window);
setstate(c, WithdrawnState);
/* flush any errors */
ignore_badwindow = 1;
XSync(dpy, False);
ignore_badwindow = 0;
}
void
gravitate(Client *c, int invert)
{
int gravity, dx, dy, delta;
gravity = NorthWestGravity;
if (c->size.flags & PWinGravity)
gravity = c->size.win_gravity;
delta = c->border-BORDER;
switch (gravity) {
case NorthWestGravity:
dx = 0;
dy = 0;
break;
case NorthGravity:
dx = delta;
dy = 0;
break;
case NorthEastGravity:
dx = 2*delta;
dy = 0;
break;
case WestGravity:
dx = 0;
dy = delta;
break;
case CenterGravity:
case StaticGravity:
dx = delta;
dy = delta;
break;
case EastGravity:
dx = 2*delta;
dy = delta;
break;
case SouthWestGravity:
dx = 0;
dy = 2*delta;
break;
case SouthGravity:
dx = delta;
dy = 2*delta;
break;
case SouthEastGravity:
dx = 2*delta;
dy = 2*delta;
break;
default:
2004-04-19 19:35:17 +00:00
fprintf(stderr, "rio: bad window gravity %d for 0x%x\n", gravity, (int)c->window);
2004-03-21 04:27:28 +00:00
return;
}
dx += BORDER;
dy += BORDER;
if (invert) {
dx = -dx;
dy = -dy;
}
c->x += dx;
c->y += dy;
}
static void
installcmap(ScreenInfo *s, Colormap cmap)
{
if (cmap == None)
XInstallColormap(dpy, s->def_cmap);
else
XInstallColormap(dpy, cmap);
}
void
cmapfocus(Client *c)
{
int i, found;
Client *cc;
if (c == 0)
return;
else if (c->ncmapwins != 0) {
found = 0;
for (i = c->ncmapwins-1; i >= 0; i--) {
installcmap(c->screen, c->wmcmaps[i]);
if (c->cmapwins[i] == c->window)
found++;
}
if (!found)
installcmap(c->screen, c->cmap);
}
else if (c->trans != None && (cc = getclient(c->trans, 0)) != 0 && cc->ncmapwins != 0)
cmapfocus(cc);
else
installcmap(c->screen, c->cmap);
}
void
cmapnofocus(ScreenInfo *s)
{
installcmap(s, None);
}
void
getcmaps(Client *c)
{
int n, i;
Window *cw;
XWindowAttributes attr;
if (!c->init) {
XGetWindowAttributes(dpy, c->window, &attr);
c->cmap = attr.colormap;
}
n = _getprop(c->window, wm_colormaps, XA_WINDOW, 100L, (void*)&cw);
2004-03-21 04:27:28 +00:00
if (c->ncmapwins != 0) {
XFree((char *)c->cmapwins);
free((char *)c->wmcmaps);
}
if (n <= 0) {
c->ncmapwins = 0;
return;
}
c->ncmapwins = n;
c->cmapwins = cw;
c->wmcmaps = (Colormap*)malloc(n*sizeof(Colormap));
for (i = 0; i < n; i++) {
if (cw[i] == c->window)
c->wmcmaps[i] = c->cmap;
else {
XSelectInput(dpy, cw[i], ColormapChangeMask);
XGetWindowAttributes(dpy, cw[i], &attr);
c->wmcmaps[i] = attr.colormap;
}
}
}
void
setlabel(Client *c)
{
char *label, *p;
if (c->iconname != 0)
label = c->iconname;
else if (c->name != 0)
label = c->name;
else if (c->instance != 0)
label = c->instance;
else if (c->class != 0)
label = c->class;
else
label = "no label";
if ((p = index(label, ':')) != 0)
*p = '\0';
c->label = label;
}
#ifdef SHAPE
void
setshape(Client *c)
{
int n, order;
XRectangle *rect;
/* don't try to add a border if the window is non-rectangular */
rect = XShapeGetRectangles(dpy, c->window, ShapeBounding, &n, &order);
if (n > 1)
XShapeCombineShape(dpy, c->parent, ShapeBounding, BORDER, BORDER,
c->window, ShapeBounding, ShapeSet);
XFree((void*)rect);
}
#endif
int
_getprop(Window w, Atom a, Atom type, long len, unsigned char **p)
{
Atom real_type;
int format;
unsigned long n, extra;
int status;
status = XGetWindowProperty(dpy, w, a, 0L, len, False, type, &real_type, &format, &n, &extra, p);
if (status != Success || *p == 0)
return -1;
if (n == 0)
XFree((void*) *p);
/* could check real_type, format, extra here... */
return n;
}
char *
getprop(Window w, Atom a)
{
unsigned char *p;
if (_getprop(w, a, XA_STRING, 100L, &p) <= 0)
return 0;
return (char *)p;
}
int
get1prop(Window w, Atom a, Atom type)
{
char **p, *x;
if (_getprop(w, a, type, 1L, (void*)&p) <= 0)
2004-03-21 04:27:28 +00:00
return 0;
x = *p;
XFree((void*) p);
return (int)x;
}
Window
getwprop(Window w, Atom a)
{
return get1prop(w, a, XA_WINDOW);
}
int
getiprop(Window w, Atom a)
{
return get1prop(w, a, XA_INTEGER);
}
void
setstate(Client *c, int state)
{
long data[2];
data[0] = (long) state;
data[1] = (long) None;
c->state = state;
XChangeProperty(dpy, c->window, wm_state, wm_state, 32,
PropModeReplace, (unsigned char *)data, 2);
}
int
getstate(Window w, int *state)
{
long *p = 0;
if (_getprop(w, wm_state, wm_state, 2L, (void*)&p) <= 0)
2004-03-21 04:27:28 +00:00
return 0;
*state = (int) *p;
XFree((char *) p);
return 1;
}
void
getproto(Client *c)
{
Atom *p;
int i;
long n;
Window w;
w = c->window;
c->proto = 0;
if ((n = _getprop(w, wm_protocols, XA_ATOM, 20L, (void*)&p)) <= 0)
2004-03-21 04:27:28 +00:00
return;
for (i = 0; i < n; i++)
if (p[i] == wm_delete)
c->proto |= Pdelete;
else if (p[i] == wm_take_focus)
c->proto |= Ptakefocus;
2004-03-30 05:01:53 +00:00
else if (p[i] == wm_lose_focus)
c->proto |= Plosefocus;
2004-03-21 04:27:28 +00:00
XFree((char *) p);
}