2019-12-02 18:23:00 +00:00
|
|
|
#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;
|
2021-02-26 18:01:22 +00:00
|
|
|
struct Rectangle {
|
|
|
|
struct {
|
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
} min, max;
|
2019-12-02 18:23:00 +00:00
|
|
|
};
|
|
|
|
#define Dx(r) ((r).max.x - (r).min.x)
|
|
|
|
#define Dy(r) ((r).max.y - (r).min.y)
|
|
|
|
|
|
|
|
typedef struct Win Win;
|
2021-02-26 18:01:22 +00:00
|
|
|
struct Win {
|
|
|
|
Window xw;
|
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
int dx;
|
|
|
|
int dy;
|
|
|
|
char* class;
|
|
|
|
char* instance;
|
|
|
|
char* name;
|
|
|
|
char* iconname;
|
2019-12-02 18:23:00 +00:00
|
|
|
};
|
|
|
|
|
2021-02-26 18:01:22 +00:00
|
|
|
Display* dpy;
|
2019-12-02 18:23:00 +00:00
|
|
|
Window root;
|
|
|
|
|
2021-02-26 18:01:22 +00:00
|
|
|
Win* w;
|
2019-12-02 18:23:00 +00:00
|
|
|
int nw;
|
|
|
|
|
|
|
|
void getinfo(void);
|
|
|
|
void listwindows(void);
|
|
|
|
int parsewinsize(char*, Rectangle*, int*, int*, int*);
|
|
|
|
void shove(char*, char*);
|
|
|
|
|
2021-02-26 19:50:23 +00:00
|
|
|
void usage(void) {
|
2021-02-26 18:01:22 +00:00
|
|
|
fprint(2, "usage: xshove [window rectangle]\n");
|
|
|
|
exits("usage");
|
2019-12-02 18:23:00 +00:00
|
|
|
}
|
|
|
|
|
2021-02-26 19:50:23 +00:00
|
|
|
void main(int argc, char** argv) {
|
2021-02-26 18:01:22 +00:00
|
|
|
int screen;
|
2019-12-02 18:23:00 +00:00
|
|
|
|
2021-02-26 18:01:22 +00:00
|
|
|
screen = 0;
|
|
|
|
ARGBEGIN {
|
2021-02-26 19:50:23 +00:00
|
|
|
case 's':
|
|
|
|
screen = atoi(EARGF(usage()));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usage();
|
|
|
|
break;
|
2021-02-26 18:01:22 +00:00
|
|
|
}
|
|
|
|
ARGEND
|
2019-12-02 18:23:00 +00:00
|
|
|
|
2021-02-26 18:01:22 +00:00
|
|
|
dpy = XOpenDisplay("");
|
2021-02-26 19:50:23 +00:00
|
|
|
if (dpy == nil)
|
|
|
|
sysfatal("open display: %r");
|
2021-02-26 18:01:22 +00:00
|
|
|
|
|
|
|
root = RootWindow(dpy, screen);
|
|
|
|
getinfo();
|
|
|
|
|
|
|
|
if (argc == 0) {
|
|
|
|
listwindows();
|
|
|
|
exits(0);
|
|
|
|
}
|
2021-02-26 19:50:23 +00:00
|
|
|
if (argc != 2)
|
|
|
|
usage();
|
2021-02-26 18:01:22 +00:00
|
|
|
shove(argv[0], argv[1]);
|
|
|
|
exits(0);
|
2019-12-02 18:23:00 +00:00
|
|
|
}
|
|
|
|
|
2021-02-26 19:50:23 +00:00
|
|
|
char* getproperty(Window w, Atom a) {
|
2021-02-26 18:01:22 +00:00
|
|
|
uchar* p;
|
|
|
|
int fmt;
|
|
|
|
Atom type;
|
|
|
|
ulong n, dummy;
|
2019-12-02 18:23:00 +00:00
|
|
|
|
2021-02-26 18:01:22 +00:00
|
|
|
n = 100;
|
|
|
|
p = nil;
|
|
|
|
XGetWindowProperty(
|
2021-02-26 19:50:23 +00:00
|
|
|
dpy,
|
|
|
|
w,
|
|
|
|
a,
|
|
|
|
0,
|
|
|
|
100L,
|
|
|
|
0,
|
|
|
|
AnyPropertyType,
|
|
|
|
&type,
|
|
|
|
&fmt,
|
|
|
|
&n,
|
|
|
|
&dummy,
|
|
|
|
&p);
|
|
|
|
if (p == nil || *p == 0)
|
|
|
|
return nil;
|
2021-02-26 18:01:22 +00:00
|
|
|
return strdup((char*)p);
|
2019-12-02 18:23:00 +00:00
|
|
|
}
|
|
|
|
|
2021-02-26 19:50:23 +00:00
|
|
|
Window findname(Window w) {
|
2021-02-26 18:01:22 +00:00
|
|
|
int i;
|
|
|
|
uint nxwin;
|
|
|
|
Window dw1, dw2, *xwin;
|
2019-12-02 18:23:00 +00:00
|
|
|
|
2021-02-26 19:50:23 +00:00
|
|
|
if (getproperty(w, XA_WM_NAME))
|
|
|
|
return w;
|
|
|
|
if (!XQueryTree(dpy, w, &dw1, &dw2, &xwin, &nxwin))
|
|
|
|
return 0;
|
2021-02-26 18:01:22 +00:00
|
|
|
for (i = 0; i < nxwin; i++)
|
2021-02-26 19:50:23 +00:00
|
|
|
if ((w = findname(xwin[i])) != 0)
|
|
|
|
return w;
|
2021-02-26 18:01:22 +00:00
|
|
|
return 0;
|
2019-12-02 18:23:00 +00:00
|
|
|
}
|
|
|
|
|
2021-02-26 19:50:23 +00:00
|
|
|
void getinfo(void) {
|
2021-02-26 18:01:22 +00:00
|
|
|
int i;
|
|
|
|
uint nxwin;
|
|
|
|
Window dw1, dw2, *xwin;
|
|
|
|
XClassHint class;
|
|
|
|
XWindowAttributes attr;
|
2019-12-02 18:23:00 +00:00
|
|
|
|
2021-02-26 19:50:23 +00:00
|
|
|
if (!XQueryTree(dpy, root, &dw1, &dw2, &xwin, &nxwin))
|
|
|
|
return;
|
2021-02-26 18:01:22 +00:00
|
|
|
w = mallocz(nxwin * sizeof w[0], 1);
|
2021-02-26 19:50:23 +00:00
|
|
|
if (w == 0)
|
|
|
|
sysfatal("malloc: %r");
|
2021-02-26 18:01:22 +00:00
|
|
|
|
|
|
|
Win* ww = w;
|
|
|
|
for (i = 0; i < nxwin; i++) {
|
|
|
|
memset(&attr, 0, sizeof attr);
|
|
|
|
xwin[i] = findname(xwin[i]);
|
2021-02-26 19:50:23 +00:00
|
|
|
if (xwin[i] == 0)
|
|
|
|
continue;
|
2021-02-26 18:01:22 +00:00
|
|
|
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;
|
|
|
|
}
|
2019-12-02 18:23:00 +00:00
|
|
|
|
2021-02-26 19:50:23 +00:00
|
|
|
void listwindows(void) {
|
2021-02-26 18:01:22 +00:00
|
|
|
int i;
|
2019-12-02 18:23:00 +00:00
|
|
|
|
2021-02-26 18:01:22 +00:00
|
|
|
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);
|
|
|
|
}
|
2019-12-02 18:23:00 +00:00
|
|
|
}
|
|
|
|
|
2021-02-26 19:50:23 +00:00
|
|
|
void shove(char* name, char* geom) {
|
2021-02-26 18:01:22 +00:00
|
|
|
int i;
|
|
|
|
int isdelta, havemin, havesize;
|
|
|
|
int old, new;
|
|
|
|
Rectangle r;
|
2019-12-02 18:23:00 +00:00
|
|
|
|
2021-02-26 18:01:22 +00:00
|
|
|
if (parsewinsize(geom, &r, &isdelta, &havemin, &havesize) < 0)
|
|
|
|
sysfatal("bad window spec: %s", name);
|
2019-12-02 18:23:00 +00:00
|
|
|
|
2021-02-26 18:01:22 +00:00
|
|
|
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;
|
2019-12-02 18:23:00 +00:00
|
|
|
|
2021-02-26 18:01:22 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2019-12-02 18:23:00 +00:00
|
|
|
}
|
|
|
|
|
2021-02-26 19:50:23 +00:00
|
|
|
int parsewinsize(
|
|
|
|
char* s, Rectangle* r, int* isdelta, int* havemin, int* havesize) {
|
2021-02-26 18:01:22 +00:00
|
|
|
char c, *os;
|
|
|
|
int i, j, k, l;
|
2019-12-02 18:23:00 +00:00
|
|
|
|
2021-02-26 18:01:22 +00:00
|
|
|
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);
|
2021-02-26 19:50:23 +00:00
|
|
|
if (!isdigit((uchar)*s))
|
|
|
|
goto oops;
|
2021-02-26 18:01:22 +00:00
|
|
|
i = strtol(s, &s, 0);
|
|
|
|
if (*s == 'x') {
|
|
|
|
s++;
|
2021-02-26 19:50:23 +00:00
|
|
|
if (!isdigit((uchar)*s))
|
|
|
|
goto oops;
|
2021-02-26 18:01:22 +00:00
|
|
|
j = strtol(s, &s, 0);
|
|
|
|
r->max.x = i;
|
|
|
|
r->max.y = j;
|
|
|
|
*havesize = 1;
|
2021-02-26 19:50:23 +00:00
|
|
|
if (*s == 0)
|
|
|
|
return 0;
|
|
|
|
if (*s != '@')
|
|
|
|
goto oops;
|
2019-12-02 18:23:00 +00:00
|
|
|
|
2021-02-26 18:01:22 +00:00
|
|
|
s++;
|
2021-02-26 19:50:23 +00:00
|
|
|
if (!isdigit((uchar)*s))
|
|
|
|
goto oops;
|
2021-02-26 18:01:22 +00:00
|
|
|
i = strtol(s, &s, 0);
|
2021-02-26 19:50:23 +00:00
|
|
|
if (*s != ',' && *s != ' ')
|
|
|
|
goto oops;
|
2021-02-26 18:01:22 +00:00
|
|
|
s++;
|
2021-02-26 19:50:23 +00:00
|
|
|
if (!isdigit((uchar)*s))
|
|
|
|
goto oops;
|
2021-02-26 18:01:22 +00:00
|
|
|
j = strtol(s, &s, 0);
|
2021-02-26 19:50:23 +00:00
|
|
|
if (*s != 0)
|
|
|
|
goto oops;
|
2021-02-26 18:01:22 +00:00
|
|
|
r->min.x += i;
|
|
|
|
r->max.x += i;
|
|
|
|
r->min.y += j;
|
|
|
|
r->max.y += j;
|
|
|
|
*havesize = 1;
|
|
|
|
*havemin = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
2019-12-02 18:23:00 +00:00
|
|
|
|
2021-02-26 18:01:22 +00:00
|
|
|
c = *s;
|
2021-02-26 19:50:23 +00:00
|
|
|
if (c != ' ' && c != ',')
|
|
|
|
goto oops;
|
2021-02-26 18:01:22 +00:00
|
|
|
s++;
|
2021-02-26 19:50:23 +00:00
|
|
|
if (!isdigit((uchar)*s))
|
|
|
|
goto oops;
|
2021-02-26 18:01:22 +00:00
|
|
|
j = strtol(s, &s, 0);
|
|
|
|
if (*s == 0) {
|
|
|
|
r->min.x = i;
|
|
|
|
r->min.y = j;
|
|
|
|
*havemin = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
2021-02-26 19:50:23 +00:00
|
|
|
if (*s != c)
|
|
|
|
goto oops;
|
2021-02-26 18:01:22 +00:00
|
|
|
s++;
|
2021-02-26 19:50:23 +00:00
|
|
|
if (!isdigit((uchar)*s))
|
|
|
|
goto oops;
|
2021-02-26 18:01:22 +00:00
|
|
|
k = strtol(s, &s, 0);
|
2021-02-26 19:50:23 +00:00
|
|
|
if (*s != c)
|
|
|
|
goto oops;
|
2021-02-26 18:01:22 +00:00
|
|
|
s++;
|
2021-02-26 19:50:23 +00:00
|
|
|
if (!isdigit((uchar)*s))
|
|
|
|
goto oops;
|
2021-02-26 18:01:22 +00:00
|
|
|
l = strtol(s, &s, 0);
|
2021-02-26 19:50:23 +00:00
|
|
|
if (*s != 0)
|
|
|
|
goto oops;
|
2021-02-26 18:01:22 +00:00
|
|
|
r->min.x = i;
|
|
|
|
r->min.y = j;
|
|
|
|
r->max.x = k;
|
|
|
|
r->max.y = l;
|
|
|
|
*havemin = 1;
|
|
|
|
*havesize = 1;
|
|
|
|
return 0;
|
2019-12-02 18:23:00 +00:00
|
|
|
|
|
|
|
oops:
|
2021-02-26 18:01:22 +00:00
|
|
|
werrstr("bad syntax in window size '%s'", os);
|
|
|
|
return -1;
|
2019-12-02 18:23:00 +00:00
|
|
|
}
|