| #include <u.h> |
| #include <X11/X.h> |
| #include <X11/Xatom.h> |
| #include <X11/Xlib.h> |
| #include <X11/Xutil.h> |
| #include <libc.h> |
| #include <ctype.h> |
| |
| AUTOLIB(X11); |
| |
| typedef struct Rectangle Rectangle; |
| struct Rectangle |
| { |
| struct { |
| int x; |
| int y; |
| } min, max; |
| }; |
| #define Dx(r) ((r).max.x - (r).min.x) |
| #define Dy(r) ((r).max.y - (r).min.y) |
| |
| typedef struct Win Win; |
| struct Win |
| { |
| Window xw; |
| int x; |
| int y; |
| int dx; |
| int dy; |
| char *class; |
| char *instance; |
| char *name; |
| char *iconname; |
| }; |
| |
| Display *dpy; |
| Window root; |
| |
| Win *w; |
| int nw; |
| |
| void getinfo(void); |
| void listwindows(void); |
| int parsewinsize(char*, Rectangle*, int*, int*, int*); |
| void shove(char*, char*); |
| |
| void |
| usage(void) |
| { |
| fprint(2, "usage: xshove [window rectangle]\n"); |
| exits("usage"); |
| } |
| |
| void |
| main(int argc, char **argv) |
| { |
| int screen; |
| |
| screen = 0; |
| ARGBEGIN{ |
| case 's': |
| screen = atoi(EARGF(usage())); |
| break; |
| default: |
| usage(); |
| break; |
| }ARGEND |
| |
| dpy = XOpenDisplay(""); |
| if(dpy == nil) |
| sysfatal("open display: %r"); |
| |
| root = RootWindow(dpy, screen); |
| getinfo(); |
| |
| if(argc == 0){ |
| listwindows(); |
| exits(0); |
| } |
| if(argc != 2) |
| usage(); |
| shove(argv[0], argv[1]); |
| exits(0); |
| } |
| |
| char* |
| getproperty(Window w, Atom a) |
| { |
| uchar *p; |
| int fmt; |
| Atom type; |
| ulong n, dummy; |
| |
| n = 100; |
| p = nil; |
| XGetWindowProperty(dpy, w, a, 0, 100L, 0, |
| AnyPropertyType, &type, &fmt, |
| &n, &dummy, &p); |
| if(p == nil || *p == 0) |
| return nil; |
| return strdup((char*)p); |
| } |
| |
| Window |
| findname(Window w) |
| { |
| int i; |
| uint nxwin; |
| Window dw1, dw2, *xwin; |
| |
| if(getproperty(w, XA_WM_NAME)) |
| return w; |
| if(!XQueryTree(dpy, w, &dw1, &dw2, &xwin, &nxwin)) |
| return 0; |
| for(i=0; i<nxwin; i++) |
| if((w = findname(xwin[i])) != 0) |
| return w; |
| return 0; |
| } |
| |
| void |
| getinfo(void) |
| { |
| int i; |
| uint nxwin; |
| Window dw1, dw2, *xwin; |
| XClassHint class; |
| XWindowAttributes attr; |
| |
| if(!XQueryTree(dpy, root, &dw1, &dw2, &xwin, &nxwin)) |
| return; |
| w = mallocz(nxwin*sizeof w[0], 1); |
| if(w == 0) |
| sysfatal("malloc: %r"); |
| |
| Win *ww = w; |
| for(i=0; i<nxwin; i++){ |
| memset(&attr, 0, sizeof attr); |
| xwin[i] = findname(xwin[i]); |
| if(xwin[i] == 0) |
| continue; |
| XGetWindowAttributes(dpy, xwin[i], &attr); |
| if(attr.width <= 0 || attr.override_redirect || attr.map_state != IsViewable) |
| continue; |
| ww->xw = xwin[i]; |
| ww->x = attr.x; |
| ww->y = attr.y; |
| ww->dx = attr.width; |
| ww->dy = attr.height; |
| XTranslateCoordinates(dpy, ww->xw, root, 0, 0, &ww->x, &ww->y, &dw1); |
| if(XGetClassHint(dpy, ww->xw, &class)){ |
| ww->class = strdup(class.res_class); |
| ww->instance = strdup(class.res_name); |
| } |
| ww->iconname = getproperty(ww->xw, XA_WM_ICON_NAME); |
| ww->name = getproperty(ww->xw, XA_WM_NAME); |
| ww++; |
| } |
| nw = ww - w; |
| } |
| |
| void |
| listwindows(void) |
| { |
| int i; |
| |
| for(i=0; i<nw; i++){ |
| Win *ww = &w[i]; |
| char rect[50]; |
| snprint(rect, sizeof rect, "%d,%d,%d,%d", ww->x, ww->y, ww->x+ww->dx, ww->y+ww->dy); |
| print("%08x %-20s %-10s %s\n", |
| (uint)ww->xw, |
| rect, |
| ww->instance, |
| ww->class); |
| } |
| } |
| |
| void |
| shove(char *name, char *geom) |
| { |
| int i; |
| int isdelta, havemin, havesize; |
| int old, new; |
| Rectangle r; |
| |
| if(parsewinsize(geom, &r, &isdelta, &havemin, &havesize) < 0) |
| sysfatal("bad window spec: %s", name); |
| |
| old = 0; |
| new = 1; |
| if(isdelta){ |
| old = 1; |
| new = isdelta; |
| } |
| for(i=0; i<nw; i++){ |
| Win *ww = &w[i]; |
| if(ww->instance && strstr(ww->instance, name) |
| || ww->class && strstr(ww->class, name)){ |
| int value_mask; |
| XWindowChanges e; |
| |
| memset(&e, 0, sizeof e); |
| if(havemin){ |
| e.x = old*ww->x + new*r.min.x; |
| e.y = old*ww->y + new*r.min.y; |
| }else{ |
| e.x = ww->x; |
| e.y = ww->y; |
| } |
| if(havesize){ |
| e.width = old*ww->dx + new*Dx(r); |
| e.height = old*ww->dy + new*Dy(r); |
| }else{ |
| e.width = ww->dx; |
| e.height = ww->dy; |
| } |
| value_mask = CWX | CWY | CWWidth | CWHeight; |
| XConfigureWindow(dpy, ww->xw, value_mask, &e); |
| XFlush(dpy); |
| } |
| } |
| } |
| |
| int |
| parsewinsize(char *s, Rectangle *r, int *isdelta, int *havemin, int *havesize) |
| { |
| char c, *os; |
| int i, j, k, l; |
| |
| os = s; |
| if(*s == '-'){ |
| s++; |
| *isdelta = -1; |
| }else if(*s == '+'){ |
| s++; |
| *isdelta = 1; |
| }else |
| *isdelta = 0; |
| *havemin = 0; |
| *havesize = 0; |
| memset(r, 0, sizeof *r); |
| if(!isdigit((uchar)*s)) |
| goto oops; |
| i = strtol(s, &s, 0); |
| if(*s == 'x'){ |
| s++; |
| if(!isdigit((uchar)*s)) |
| goto oops; |
| j = strtol(s, &s, 0); |
| r->max.x = i; |
| r->max.y = j; |
| *havesize = 1; |
| if(*s == 0) |
| return 0; |
| if(*s != '@') |
| goto oops; |
| |
| s++; |
| if(!isdigit((uchar)*s)) |
| goto oops; |
| i = strtol(s, &s, 0); |
| if(*s != ',' && *s != ' ') |
| goto oops; |
| s++; |
| if(!isdigit((uchar)*s)) |
| goto oops; |
| j = strtol(s, &s, 0); |
| if(*s != 0) |
| goto oops; |
| r->min.x += i; |
| r->max.x += i; |
| r->min.y += j; |
| r->max.y += j; |
| *havesize = 1; |
| *havemin = 1; |
| return 0; |
| } |
| |
| c = *s; |
| if(c != ' ' && c != ',') |
| goto oops; |
| s++; |
| if(!isdigit((uchar)*s)) |
| goto oops; |
| j = strtol(s, &s, 0); |
| if(*s == 0){ |
| r->min.x = i; |
| r->min.y = j; |
| *havemin = 1; |
| return 0; |
| } |
| if(*s != c) |
| goto oops; |
| s++; |
| if(!isdigit((uchar)*s)) |
| goto oops; |
| k = strtol(s, &s, 0); |
| if(*s != c) |
| goto oops; |
| s++; |
| if(!isdigit((uchar)*s)) |
| goto oops; |
| l = strtol(s, &s, 0); |
| if(*s != 0) |
| goto oops; |
| r->min.x = i; |
| r->min.y = j; |
| r->max.x = k; |
| r->max.y = l; |
| *havemin = 1; |
| *havesize = 1; |
| return 0; |
| |
| oops: |
| werrstr("bad syntax in window size '%s'", os); |
| return -1; |
| } |