xshove.c (5419B)
1 #include <u.h> 2 #include <X11/X.h> 3 #include <X11/Xatom.h> 4 #include <X11/Xlib.h> 5 #include <X11/Xutil.h> 6 #include <libc.h> 7 #include <ctype.h> 8 9 AUTOLIB(X11); 10 11 typedef struct Rectangle Rectangle; 12 struct Rectangle 13 { 14 struct { 15 int x; 16 int y; 17 } min, max; 18 }; 19 #define Dx(r) ((r).max.x - (r).min.x) 20 #define Dy(r) ((r).max.y - (r).min.y) 21 22 typedef struct Win Win; 23 struct Win 24 { 25 Window xw; 26 int x; 27 int y; 28 int dx; 29 int dy; 30 char *idstr; 31 char *class; 32 char *instance; 33 char *name; 34 char *iconname; 35 }; 36 37 Display *dpy; 38 Window root; 39 40 Win *w; 41 int nw; 42 43 void getinfo(void); 44 void listwindows(void); 45 int parsewinsize(char*, Rectangle*, int*, int*, int*); 46 void shove(char*, char*); 47 48 void 49 usage(void) 50 { 51 fprint(2, "usage: xshove [window rectangle]\n"); 52 exits("usage"); 53 } 54 55 void 56 main(int argc, char **argv) 57 { 58 int screen; 59 60 screen = 0; 61 ARGBEGIN{ 62 case 's': 63 screen = atoi(EARGF(usage())); 64 break; 65 default: 66 usage(); 67 break; 68 }ARGEND 69 70 dpy = XOpenDisplay(""); 71 if(dpy == nil) 72 sysfatal("open display: %r"); 73 74 root = RootWindow(dpy, screen); 75 getinfo(); 76 77 if(argc == 0){ 78 listwindows(); 79 exits(0); 80 } 81 if(argc != 2) 82 usage(); 83 shove(argv[0], argv[1]); 84 exits(0); 85 } 86 87 char* 88 getproperty(Window w, Atom a) 89 { 90 uchar *p; 91 int fmt; 92 Atom type; 93 ulong n, dummy; 94 95 n = 100; 96 p = nil; 97 XGetWindowProperty(dpy, w, a, 0, 100L, 0, 98 AnyPropertyType, &type, &fmt, 99 &n, &dummy, &p); 100 if(p == nil || *p == 0) 101 return nil; 102 return strdup((char*)p); 103 } 104 105 Window 106 findname(Window w) 107 { 108 int i; 109 uint nxwin; 110 Window dw1, dw2, *xwin; 111 112 if(getproperty(w, XA_WM_NAME)) 113 return w; 114 if(!XQueryTree(dpy, w, &dw1, &dw2, &xwin, &nxwin)) 115 return 0; 116 for(i=0; i<nxwin; i++) 117 if((w = findname(xwin[i])) != 0) 118 return w; 119 return 0; 120 } 121 122 void 123 getinfo(void) 124 { 125 int i; 126 uint nxwin; 127 Window dw1, dw2, *xwin; 128 XClassHint class; 129 XWindowAttributes attr; 130 131 if(!XQueryTree(dpy, root, &dw1, &dw2, &xwin, &nxwin)) 132 return; 133 w = mallocz(nxwin*sizeof w[0], 1); 134 if(w == 0) 135 sysfatal("malloc: %r"); 136 137 Win *ww = w; 138 for(i=0; i<nxwin; i++){ 139 memset(&attr, 0, sizeof attr); 140 xwin[i] = findname(xwin[i]); 141 if(xwin[i] == 0) 142 continue; 143 XGetWindowAttributes(dpy, xwin[i], &attr); 144 if(attr.width <= 0 || attr.override_redirect || attr.map_state != IsViewable) 145 continue; 146 ww->xw = xwin[i]; 147 char idstr[9]; 148 snprint(idstr, sizeof(idstr), "%08x", (uint)ww->xw); 149 ww->idstr = strdup(idstr); 150 ww->x = attr.x; 151 ww->y = attr.y; 152 ww->dx = attr.width; 153 ww->dy = attr.height; 154 XTranslateCoordinates(dpy, ww->xw, root, 0, 0, &ww->x, &ww->y, &dw1); 155 if(XGetClassHint(dpy, ww->xw, &class)){ 156 ww->class = strdup(class.res_class); 157 ww->instance = strdup(class.res_name); 158 } 159 ww->iconname = getproperty(ww->xw, XA_WM_ICON_NAME); 160 ww->name = getproperty(ww->xw, XA_WM_NAME); 161 ww++; 162 } 163 nw = ww - w; 164 } 165 166 void 167 listwindows(void) 168 { 169 int i; 170 171 for(i=0; i<nw; i++){ 172 Win *ww = &w[i]; 173 char rect[50]; 174 snprint(rect, sizeof rect, "%d,%d,%d,%d", ww->x, ww->y, ww->x+ww->dx, ww->y+ww->dy); 175 print("%08x %-20s %-10s %s\n", 176 (uint)ww->xw, 177 rect, 178 ww->instance, 179 ww->class); 180 } 181 } 182 183 void 184 shove(char *name, char *geom) 185 { 186 int i; 187 int isdelta, havemin, havesize; 188 int old, new; 189 Rectangle r; 190 191 if(parsewinsize(geom, &r, &isdelta, &havemin, &havesize) < 0) 192 sysfatal("bad window spec: %s", name); 193 194 old = 0; 195 new = 1; 196 if(isdelta){ 197 old = 1; 198 new = isdelta; 199 } 200 for(i=0; i<nw; i++){ 201 Win *ww = &w[i]; 202 if(ww->instance && strstr(ww->instance, name) 203 || ww->class && strstr(ww->class, name) 204 || ww->idstr && strstr(ww->idstr, name)){ 205 int value_mask; 206 XWindowChanges e; 207 208 memset(&e, 0, sizeof e); 209 if(havemin){ 210 e.x = old*ww->x + new*r.min.x; 211 e.y = old*ww->y + new*r.min.y; 212 }else{ 213 e.x = ww->x; 214 e.y = ww->y; 215 } 216 if(havesize){ 217 e.width = old*ww->dx + new*Dx(r); 218 e.height = old*ww->dy + new*Dy(r); 219 }else{ 220 e.width = ww->dx; 221 e.height = ww->dy; 222 } 223 value_mask = CWX | CWY | CWWidth | CWHeight; 224 XConfigureWindow(dpy, ww->xw, value_mask, &e); 225 XFlush(dpy); 226 } 227 } 228 } 229 230 int 231 parsewinsize(char *s, Rectangle *r, int *isdelta, int *havemin, int *havesize) 232 { 233 char c, *os; 234 int i, j, k, l; 235 236 os = s; 237 if(*s == '-'){ 238 s++; 239 *isdelta = -1; 240 }else if(*s == '+'){ 241 s++; 242 *isdelta = 1; 243 }else 244 *isdelta = 0; 245 *havemin = 0; 246 *havesize = 0; 247 memset(r, 0, sizeof *r); 248 if(!isdigit((uchar)*s)) 249 goto oops; 250 i = strtol(s, &s, 0); 251 if(*s == 'x'){ 252 s++; 253 if(!isdigit((uchar)*s)) 254 goto oops; 255 j = strtol(s, &s, 0); 256 r->max.x = i; 257 r->max.y = j; 258 *havesize = 1; 259 if(*s == 0) 260 return 0; 261 if(*s != '@') 262 goto oops; 263 264 s++; 265 if(!isdigit((uchar)*s)) 266 goto oops; 267 i = strtol(s, &s, 0); 268 if(*s != ',' && *s != ' ') 269 goto oops; 270 s++; 271 if(!isdigit((uchar)*s)) 272 goto oops; 273 j = strtol(s, &s, 0); 274 if(*s != 0) 275 goto oops; 276 r->min.x += i; 277 r->max.x += i; 278 r->min.y += j; 279 r->max.y += j; 280 *havesize = 1; 281 *havemin = 1; 282 return 0; 283 } 284 285 c = *s; 286 if(c != ' ' && c != ',') 287 goto oops; 288 s++; 289 if(!isdigit((uchar)*s)) 290 goto oops; 291 j = strtol(s, &s, 0); 292 if(*s == 0){ 293 r->min.x = i; 294 r->min.y = j; 295 *havemin = 1; 296 return 0; 297 } 298 if(*s != c) 299 goto oops; 300 s++; 301 if(!isdigit((uchar)*s)) 302 goto oops; 303 k = strtol(s, &s, 0); 304 if(*s != c) 305 goto oops; 306 s++; 307 if(!isdigit((uchar)*s)) 308 goto oops; 309 l = strtol(s, &s, 0); 310 if(*s != 0) 311 goto oops; 312 r->min.x = i; 313 r->min.y = j; 314 r->max.x = k; 315 r->max.y = l; 316 *havemin = 1; 317 *havesize = 1; 318 return 0; 319 320 oops: 321 werrstr("bad syntax in window size '%s'", os); 322 return -1; 323 }