1 /* $Id: xwit.c,v 3.4 97/10/20 18:32:49 dd Exp $ */
2 /*
3 * Pop up or iconify the current xterm window (using its WINDOW_ID in the env)
4 * or a given window id or a list of window matching names. etc...
5 * A miscellany of trivial functions.
6 *
7 * Copyright 1991 CETIA
8 * Permission to use, copy, modify, distribute, and sell this software and its
9 * documentation for any purpose is hereby granted without fee, provided that
10 * the above copyright notice appear in all copies and that both that
11 * copyright notice and this permission notice appear in supporting
12 * documentation, and that the name of CETIA not be used in advertising or
13 * publicity pertaining to distribution of the software without specific,
14 * written prior permission. CETIA makes no representations about the
15 * suitability of this software for any purpose. It is provided "as is"
16 * without express or implied warranty.
17 *
18 * CETIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL CETIA
20 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
21 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
22 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
23 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 *
25 * Original by Mark M Martin. cetia 93/08/13 r1.6 mmm@cetia.fr
26 *
27 * This version by David DiGiacomo, david@slack.com.
28 */
29 #include <X11/Xatom.h>
30 #include <X11/Xos.h>
31 #include <X11/Xlib.h>
32 #include <X11/Xutil.h>
33 #include <X11/Xproto.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <limits.h>
37 #include <sys/time.h>
38 #include "dsimple.h"
39 #include "ClientWin.h"
40
41 /* note: called by dsimple.c code, must be global */
42 void
usage()43 usage()
44 {
45 static char Revision[] = "$Revision: 3.4 $";
46 char *rbeg, *rend;
47
48 for (rbeg = Revision; *rbeg; rbeg++) {
49 if (*rbeg == ' ') {
50 break;
51 }
52 }
53 if (*rbeg) {
54 for (rend = ++rbeg; *rend; rend++) {
55 if (*rend == ' ') {
56 *rend = 0;
57 break;
58 }
59 }
60 fprintf(stderr, "%s version %s\n\n",
61 program_name, rbeg);
62 }
63
64 fprintf(stderr,
65 "usage: %s -display <display> -sync\n\
66 -pop -focus -iconify -unmap -print \n\
67 -raise -lower -opposite -[un]circulate\n\
68 -resize w h -rows r -columns c -[r]move x y\n\
69 -[r]warp x y -colormap <colormapid> -[no]save\n\
70 -name <name> -iconname <name> -property <lookfor>\n\
71 -bitmap <file> -mask <file> -[r]iconmove x y\n\
72 -[no]backingstore -[no]saveunder\n\
73 -[no]keyrepeat keycode ... keycode - keycode\n\
74 -id <windowid> -root -current -select -all\n\
75 -names <initialsubstrings>... [must be last]\n",
76 program_name);
77 exit(2);
78 }
79
80 enum functions {
81 pop, focus, icon, unmap, colormap,
82 print,
83 raise, lower, opposite, circulate, uncirculate,
84 move, rmove, warp, rwarp,
85 resize, save, nosave,
86 keyrepeat, nokeyrepeat,
87 name, iconname,
88 rows, columns,
89 iconbitmap, iconmove, riconmove,
90 F_winattr,
91 lastfunc
92 };
93 static long function;
94 #define FBIT(func) (1 << (func))
95
96 /* options that don't need a window */
97 #define NOWINDOW \
98 (FBIT(save) | FBIT(nosave) | \
99 FBIT(keyrepeat) | FBIT(nokeyrepeat) | \
100 FBIT(rwarp))
101
102 static enum winidmode {
103 WID_none,
104 WID_env,
105 WID_num,
106 WID_root,
107 WID_select,
108 WID_curr,
109 WID_names,
110 } Winidmode;
111
112 static Window root;
113 static int tox, toy;
114 static int Gright, Gbottom;
115 static int towidth, toheight, warpx, warpy;
116 static Colormap cmap;
117 static char **names; /* list of names to avoid */
118 static int numnames;
119 static int keys[256];
120 static char *wmname;
121 static char *wmiconname;
122 static int Giconx, Gicony;
123 static int nrows;
124 static int ncolumns;
125 static int nbuffer;
126 static char *bitmapname;
127 static char *maskname;
128 static int Gbs, Gsu;
129
130 /* set if we found a window to act on*/
131 static int Gwinfound;
132
133 /* forward declarations */
134 static void doit(Window);
135
136 /*
137 * sleep for given millisecs for those without usleep
138 */
139 static void
mssleep(int ms)140 mssleep(int ms)
141 {
142 struct timeval tv;
143 tv.tv_sec = ms/1000;
144 tv.tv_usec = (ms%1000)*1000;
145 select(0,NULL,NULL,NULL,&tv);
146 }
147
148 static Atom property = XA_WM_NAME;
149
MyFetchName(Display * display,Window w,unsigned char ** name)150 static Bool MyFetchName(Display *display, Window w, unsigned char **name)
151 {
152 Atom returnedType;
153 int returnedFormat;
154 unsigned long number;
155 unsigned long bytesAfterReturn;
156 unsigned char *data;
157
158 if( Success != XGetWindowProperty(display, w, property,
159 0, (long)BUFSIZ, False,
160 XA_STRING,
161 &returnedType, &returnedFormat,
162 &number, &bytesAfterReturn, &data)) {
163 *name = NULL;
164 return False;
165 } else if( returnedType != XA_STRING || returnedFormat != 8 ) {
166 if(data)
167 XFree(data);
168 *name = NULL;
169 return False;
170 } else {
171 *name = data;
172 return (data!=NULL)?True:False;
173 }
174 }
175
176
177 /* See if the given atom of the _NET_* family is supported on the
178 display. */
179
HasNetAtom(Display * dpy,Atom atom)180 static Bool HasNetAtom(Display *dpy, Atom atom)
181 {
182 static Atom *atoms;
183 static unsigned long n_atoms = -1;
184 int i;
185
186 if (n_atoms == -1) {
187 Atom type;
188 int format;
189 unsigned long bytes_after;
190
191 n_atoms = 0;
192 XGetWindowProperty (dpy, RootWindow (dpy, screen),
193 XInternAtom(dpy, "_NET_SUPPORTED", True),
194 0, LONG_MAX, False, XA_ATOM, &type, &format,
195 &n_atoms, &bytes_after, (void *)&atoms);
196
197 if (type != XA_ATOM)
198 return False;
199 }
200
201 if (atoms == NULL)
202 return False;
203
204 for (i = 0; i < n_atoms; i++)
205 if (atoms[i] == atom)
206 return True;
207 return False;
208 }
209
210 /*
211 * find all windows below this and if name matches call doit on it
212 */
213 static void
downtree(Window top)214 downtree(Window top)
215 {
216 Window *child, dummy;
217 unsigned int children, i;
218 char **cpp;
219 unsigned char *name;
220 if (XQueryTree(dpy, top, &dummy, &dummy, &child, &children)==0)
221 Fatal_Error("XQueryTree failed");
222 for (i=0; i<children; i++)
223 if(MyFetchName (dpy, child[i], &name)){
224 for(cpp = names;*cpp!=0;cpp++)
225 if(strncmp(*cpp, (char*)name, strlen(*cpp))==0){
226 doit(child[i]);
227 break;
228 }
229 XFree(name);
230 } else
231 downtree(child[i]); /* dont go down if found a name */
232 if(child)XFree((char *)child);
233 }
234
235
236 /*
237 * [un]set autorepeat for individual keys
238 */
239 static void
setrepeat(void)240 setrepeat(void)
241 {
242 unsigned long value_mask;
243 XKeyboardControl values;
244 int i;
245
246 value_mask = KBKey|KBAutoRepeatMode;
247 values.auto_repeat_mode = (function & FBIT(keyrepeat)) ?
248 AutoRepeatModeOn : AutoRepeatModeOff;
249
250 for(i=0;i<256;i++)
251 if(keys[i]){
252 values.key = i;
253 XChangeKeyboardControl(dpy, value_mask, &values);
254 }
255 }
256
257 /*
258 * get window position, compensating for decorations
259 * (based on xwininfo.c)
260 */
261 static void
getpos(Window window,int * xp,int * yp)262 getpos(Window window, int *xp, int *yp)
263 {
264 XWindowAttributes attributes;
265 int rx, ry;
266 Window junkwin;
267
268 if (XGetWindowAttributes(dpy, window, &attributes) == 0)
269 Fatal_Error("XGetWindowAttributes(0x%x)", window);
270
271 (void) XTranslateCoordinates(dpy, window, attributes.root,
272 -attributes.border_width, -attributes.border_width,
273 &rx, &ry, &junkwin);
274
275 *xp = rx - attributes.x;
276 *yp = ry - attributes.y;
277 }
278
279 /*
280 * get window size
281 */
282 static void
getsize(Window window,int * wp,int * hp)283 getsize(Window window, int *wp, int *hp)
284 {
285 XWindowAttributes attributes;
286
287 if (XGetWindowAttributes(dpy, window, &attributes) == 0)
288 Fatal_Error("XGetWindowAttributes(0x%x)", window);
289
290 *wp = attributes.width;
291 *hp = attributes.height;
292 }
293
294 /*
295 * set window position
296 */
297 static void
domove(Window window,int x,int y,int right,int bottom)298 domove(Window window, int x, int y, int right, int bottom)
299 {
300 XWindowChanges values;
301 unsigned int value_mask;
302
303 if (right || bottom) {
304 XWindowAttributes win_attr, frame_attr;
305 Window wmframe;
306
307 if (XGetWindowAttributes(dpy, window, &win_attr) == 0)
308 Fatal_Error("XGetWindowAttributes(0x%x)", window);
309
310 /* find our window manager frame, if any */
311 for (wmframe = window; ; ) {
312 Status status;
313 Window wroot, parent;
314 Window *childlist;
315 unsigned int ujunk;
316
317 status = XQueryTree(dpy, wmframe,
318 &wroot, &parent, &childlist, &ujunk);
319 if (parent == wroot || !parent || !status)
320 break;
321 wmframe = parent;
322 if (status && childlist)
323 XFree((char *) childlist);
324 }
325
326 #ifndef FVWM2
327 /*
328 * Norman R. McBride <norm@city.ac.uk> reports that
329 * this code doesn't work with fvwm2, and I don't have
330 * a fix yet, sorry. - DD
331 */
332 if (wmframe != window) {
333 if (!XGetWindowAttributes(dpy, wmframe, &frame_attr))
334 Fatal_Error("XGetWindowAttributes(0x%x)",
335 wmframe);
336
337 win_attr.width = frame_attr.width;
338 win_attr.height = frame_attr.height;
339 win_attr.border_width +=
340 frame_attr.border_width;
341 }
342 #endif /* !FVWM2 */
343
344 if (right)
345 x += DisplayWidth(dpy, screen) -
346 win_attr.width -
347 win_attr.border_width;
348
349 if (bottom)
350 y += DisplayHeight(dpy, screen) -
351 win_attr.height -
352 win_attr.border_width;
353 }
354
355 values.x = x;
356 values.y = y;
357 value_mask = CWX | CWY;
358
359 if (XReconfigureWMWindow(dpy, window, screen,
360 value_mask, &values) == 0)
361 Fatal_Error("move failed");
362 }
363
364 /*
365 * dump some intresting window data
366 */
367 static void
doprint(Window window)368 doprint(Window window)
369 {
370 XWindowAttributes attributes;
371 unsigned char *name;
372
373 if( MyFetchName(dpy,window,&name) ) {
374 if (XGetWindowAttributes(dpy, window, &attributes) == 0)
375 Fatal_Error("XGetWindowAttributes(0x%x)", window);
376
377 printf("0x%x: x=%d y=%d w=%d h=%d d=%d ",
378 (int)window,
379 attributes.x,attributes.y,
380 attributes.width,attributes.height,
381 attributes.depth);
382 putchar('\'');
383 while( *name != '\0' ) {
384 if( *name >= ' ' && ((*name)&0x80)== 0 ) {
385 putchar(*name);
386 } else
387 printf("\\%03hho",*name);
388 name++;
389 }
390 putchar('\'');
391 putchar('\n');
392 }
393 }
394
395 /*
396 * set window size
397 */
398 static void
doresize(Window window,int w,int h)399 doresize(Window window, int w, int h)
400 {
401 XWindowChanges values;
402 unsigned int value_mask;
403 int try;
404 int nw, nh;
405
406 values.width = w;
407 values.height = h;
408 value_mask = CWWidth | CWHeight;
409
410 for (try = 0; try < 2; try++) {
411 if (XReconfigureWMWindow(dpy, window, screen, value_mask, &values) == 0)
412 Fatal_Error("resize: XReconfigureWMWindow");
413
414 getsize(window, &nw, &nh);
415 if (values.width == nw && values.height == nh)
416 return;
417
418 /* give window manager a couple of chances to react */
419 mssleep(100);
420 getsize(window, &nw, &nh);
421 if (values.width == nw && values.height == nh)
422 return;
423
424 mssleep(400);
425 getsize(window, &nw, &nh);
426 if (values.width == nw && values.height == nh)
427 return;
428 }
429
430 /* last chance */
431 values.width += values.width - nw;
432 values.height += values.height - nh;
433 if (XReconfigureWMWindow(dpy, window, screen, value_mask, &values) == 0)
434 Fatal_Error("resize: XReconfigureWMWindow 2");
435 }
436
437 /*
438 * set row/column size
439 */
440 static void
rcresize(enum functions what,Window window)441 rcresize(enum functions what, Window window)
442 {
443 XSizeHints *hints;
444 long supplied;
445 int w, h;
446
447 if (!(what & FBIT(rows)) || !(what & FBIT(columns)))
448 getsize(window, &w, &h);
449
450 if (!(hints = XAllocSizeHints()))
451 Fatal_Error("XAllocSizeHints");
452
453 if (XGetWMNormalHints(dpy, window, hints, &supplied) == 0)
454 Fatal_Error("XGetWMNormalHints");
455
456 if (!(supplied & PBaseSize) || !(supplied & PResizeInc))
457 Fatal_Error("missing PBaseSize and/or PResizeInc hint");
458
459 if (what & FBIT(columns))
460 w = hints->base_width + hints->width_inc * ncolumns;
461
462 if (what & FBIT(rows))
463 h = hints->base_height + hints->height_inc * nrows;
464
465 doresize(window, w, h);
466
467 XFree(hints);
468 }
469
470 static void
loadbitmap(Window window,const char * file,Pixmap * pmp)471 loadbitmap(Window window, const char *file, Pixmap *pmp)
472 {
473 unsigned int w, h;
474 int xhot, yhot;
475
476 if (XReadBitmapFile(dpy, window, file,
477 &w, &h, pmp, &xhot, &yhot) != BitmapSuccess)
478 Fatal_Error("XReadBitmapFile failed");
479 }
480
481 static void
setbitmap(Window window)482 setbitmap(Window window)
483 {
484 static XWMHints *hints;
485 static Pixmap bitmap_pm;
486 static Pixmap mask_pm;
487 XWMHints *ohints;
488
489 if (!hints) {
490 if (!(hints = XAllocWMHints()) ||
491 !(ohints = XAllocWMHints()))
492 Fatal_Error("XAllocWMHints");
493
494 if (bitmapname) {
495 loadbitmap(window, bitmapname, &bitmap_pm);
496 hints->flags |= IconPixmapHint;
497 hints->icon_pixmap = bitmap_pm;
498 }
499
500 if (maskname) {
501 loadbitmap(window, maskname, &mask_pm);
502 hints->flags |= IconMaskHint;
503 hints->icon_mask = mask_pm;
504 }
505
506 XSetCloseDownMode(dpy, RetainTemporary);
507 }
508
509 if ((ohints = XGetWMHints(dpy, window)) != NULL ) {
510 if (ohints->icon_pixmap && hints->icon_pixmap)
511 XFreePixmap(dpy, ohints->icon_pixmap);
512 if (ohints->icon_mask && hints->icon_mask)
513 XFreePixmap(dpy, ohints->icon_mask);
514 XFree(ohints);
515 }
516
517 XSetWMHints(dpy, window, hints);
518 }
519
520 static void
setwinattr(Window window)521 setwinattr(Window window)
522 {
523 XSetWindowAttributes swa;
524 unsigned long valuemask;
525
526 valuemask = 0;
527
528 if (Gbs) {
529 valuemask |= CWBackingStore | CWBackingPlanes;
530 swa.backing_store = Gbs > 0 ? Always : NotUseful;
531 swa.backing_planes = ~0L;
532 }
533 if (Gsu) {
534 valuemask |= CWSaveUnder;
535 swa.save_under = Gsu > 0;
536 }
537
538 XChangeWindowAttributes(dpy, window, valuemask, &swa);
539 }
540
541 /*
542 * iconify the given window, or map and raise it, or whatever
543 */
544 static void
doit(Window window)545 doit(Window window)
546 {
547 XWindowChanges values;
548 unsigned int value_mask;
549 XWMHints *wmhp;
550 enum functions f;
551 int i = 0;
552
553 Gwinfound = 1;
554
555 f = function;
556 for (i = 0; i < lastfunc; i++) {
557 if ((f & FBIT(i)) == 0)
558 continue;
559
560 switch (i) {
561 case warp:
562 XWarpPointer(dpy, None, window, 0, 0, 0, 0,
563 warpx, warpy);
564 break;
565 case rwarp:
566 XWarpPointer(dpy, None, None, 0, 0, 0, 0,
567 warpx, warpy);
568 break;
569 case move:
570 domove(window, tox, toy, Gright, Gbottom);
571 break;
572 case rmove:
573 getpos(window, &values.x, &values.y);
574 values.x += tox;
575 values.y += toy;
576 value_mask = CWX | CWY;
577 if (XReconfigureWMWindow(dpy, window, screen,
578 value_mask, &values) == 0)
579 Fatal_Error("rmove failed");
580 break;
581 case resize:
582 doresize(window, towidth, toheight);
583 break;
584 case colormap:
585 XSetWindowColormap(dpy, window, cmap);
586 break;
587 case print:
588 doprint(window);
589 break;
590 case pop:
591 XMapRaised(dpy, window);
592 break;
593 case focus: {
594 static XClientMessageEvent event;
595
596 if (event.type == 0) {
597 event.type = ClientMessage;
598 event.message_type =
599 XInternAtom(dpy, "_NET_ACTIVE_WINDOW", True);
600 event.format = 32;
601 event.data.l[0] = 1;
602 event.data.l[1] = CurrentTime;
603 }
604
605 /* if no _NET_ACTIVE_WINDOW, the wm is oldschool... */
606 if (event.message_type == 0
607 || !HasNetAtom (dpy, event.message_type))
608 XSetInputFocus(dpy, window, CurrentTime, RevertToNone);
609 else {
610 event.window = window;
611 event.data.l[2] = root;
612 if (XSendEvent(dpy, root, (Bool) False,
613 SubstructureRedirectMask,
614 (XEvent *) & event) == 0)
615 Fatal_Error("send event failed");
616 }
617 break;
618 }
619 case raise:
620 values.stack_mode = Above;
621 value_mask = CWStackMode;
622 XConfigureWindow(dpy, window, value_mask, &values);
623 break;
624 case lower:
625 values.stack_mode = Below;
626 value_mask = CWStackMode;
627 XConfigureWindow(dpy, window, value_mask, &values);
628 break;
629 case opposite:
630 values.stack_mode = Opposite;
631 value_mask = CWStackMode;
632 XConfigureWindow(dpy, window, value_mask, &values);
633 break;
634 case circulate:
635 XCirculateSubwindowsUp(dpy, window);
636 break;
637 case uncirculate:
638 XCirculateSubwindowsDown(dpy, window);
639 break;
640 case unmap:
641 XUnmapWindow(dpy, window);
642 break;
643 case icon:
644 #if iconify_by_sending_client_message
645 static XClientMessageEvent event;
646
647 if (event.type == 0) {
648 event.type = ClientMessage;
649 #ifdef XA_WM_CHANGE_STATE
650 event.message_type = XA_WM_CHANGE_STATE;
651 #else
652 event.message_type =
653 XInternAtom(dpy, "WM_CHANGE_STATE", True);
654 if (event.message_type == 0)
655 Fatal_Error("no WM_CHANGE_STATE atom");
656 #endif
657 event.format = 32;
658 event.data.l[0] = IconicState;
659 }
660
661 event.window = window;
662 if (XSendEvent(dpy, root, (Bool) False,
663 SubstructureRedirectMask | SubstructureNotifyMask,
664 (XEvent *) & event) == 0)
665 Fatal_Error("send event failed");
666 #else /* iconify_by_sending_client_message */
667 if (XIconifyWindow(dpy, window, screen) == 0)
668 Fatal_Error("iconify failed");
669 #endif /* iconify_by_sending_client_message */
670 break;
671 case save:
672 XForceScreenSaver(dpy, ScreenSaverActive);
673 break;
674 case nosave:
675 XForceScreenSaver(dpy, ScreenSaverReset);
676 break;
677 case keyrepeat:
678 case nokeyrepeat:
679 setrepeat();
680 break;
681 case name:
682 XStoreName(dpy, window, wmname);
683 break;
684 case iconname:
685 XSetIconName(dpy, window, wmiconname);
686 break;
687 case rows:
688 /* don't do it twice */
689 if (f & FBIT(columns))
690 break;
691 /* fall through */
692 case columns:
693 rcresize(f, window);
694 break;
695 case iconbitmap:
696 setbitmap(window);
697 break;
698 case iconmove:
699 wmhp = XGetWMHints(dpy, window);
700 if (wmhp == 0)
701 Fatal_Error("no WM_HINTS");
702 wmhp->flags |= IconPositionHint;
703 wmhp->icon_x = Giconx;
704 wmhp->icon_y = Gicony;
705 XSetWMHints(dpy, window, wmhp);
706 XFree(wmhp);
707 break;
708 case riconmove:
709 wmhp = XGetWMHints(dpy, window);
710 if (wmhp == 0)
711 Fatal_Error("no WM_HINTS");
712 if (wmhp->flags & IconPositionHint) {
713 wmhp->icon_x += Giconx;
714 wmhp->icon_y += Gicony;
715 XSetWMHints(dpy, window, wmhp);
716 }
717 else
718 Fatal_Error("no current icon position");
719 XFree(wmhp);
720 break;
721 case F_winattr:
722 setwinattr(window);
723 break;
724 }
725 }
726 }
727
728 /* based on xwininfo.c */
729 static Window
xwit_select_window(Display * dpy,int current)730 xwit_select_window(Display *dpy, int current)
731 {
732 Window window = None;
733 Window wroot;
734 int dummyi;
735 unsigned int dummy;
736
737 if (current) {
738 XQueryPointer(dpy, RootWindow(dpy, screen),
739 &wroot, &window,
740 &dummyi, &dummyi, &dummyi, &dummyi, &dummy);
741 }
742 else {
743 printf("\n");
744 printf("%s: select window by clicking the mouse\n",
745 program_name);
746 (void) fflush(stdout);
747 window = Select_Window(dpy);
748 }
749 if (window) {
750 if (XGetGeometry(dpy, window, &wroot, &dummyi, &dummyi,
751 &dummy, &dummy, &dummy, &dummy) &&
752 window != wroot)
753 window = XmuClientWindow(dpy, window);
754 }
755 return window;
756 }
757
758 static Window
getxid(const char * s)759 getxid(const char *s)
760 {
761 XID id;
762
763 if (sscanf(s, "0x%lx", &id) == 1)
764 return id;
765 if (sscanf(s, "%ld", &id) == 1)
766 return id;
767 Fatal_Error("Invalid ID format: %s", s);
768 /* NOTREACHED */
769 return -1;
770 }
771
772 static int
matchopt(const char * key,int nargs,int * argc,char ** argv)773 matchopt(const char *key, int nargs, int *argc, char **argv)
774 {
775 int enough = 0;
776 int match = 1;
777 char *ap;
778 const char *kp;
779
780 ap = *argv;
781 if (*ap == '-')
782 ap++;
783
784 for (kp = key; *kp; kp++, ap++) {
785 if (*kp == '*') {
786 enough = 1;
787 ap--;
788 continue;
789 }
790 if (*ap == 0) {
791 match = enough;
792 break;
793 }
794 if (*ap != *kp) {
795 match = 0;
796 break;
797 }
798 }
799
800 if (match) {
801 if (argc[0] <= nargs) {
802 char option[32];
803 int dash, skip;
804
805 strncpy(option, *argv, sizeof option - 1);
806 option[sizeof option - 1] = 0;
807
808 dash = *argv[0] == '-';
809
810 for (ap = option; *ap; ap++)
811 /* nothing */ ;
812 skip = ap - option - dash;
813 enough = 0;
814
815 for (kp = key; *kp && skip--; kp++) {
816 if (*kp == '*')
817 skip++;
818 }
819 for (; *kp; kp++) {
820 if (*kp == '*')
821 continue;
822 if (enough == 0) {
823 *ap++ = '(';
824 enough = 1;
825 }
826 *ap++ = *kp;
827 }
828 if (enough)
829 *ap++ = ')';
830 *ap = 0;
831
832 fprintf(stderr,
833 "%s: option %s needs %d argument%s\n\n",
834 program_name, option,
835 nargs, nargs > 1 ? "s" : "");
836 usage();
837 }
838 argc[0] -= nargs;
839 }
840 return match;
841 }
842
843 static void
FetchBuffer(Display * dpy,int nbuf)844 FetchBuffer(Display *dpy, int nbuf)
845 {
846 char *buf;
847 int size;
848
849 buf = XFetchBuffer(dpy, &size, nbuf);
850
851 if( size == 0 )
852 fprintf( stderr, "Could not fetch cutbuffer %d\n", nbuf );
853 else
854 fwrite( buf, 1, size, stdout );
855 }
856
857 static void
StoreBuffer(Display * dpy,int nbuf)858 StoreBuffer(Display *dpy, int nbuf)
859 {
860 char *buf = NULL;
861 int bufsize, nread, total=0;
862
863 bufsize = 10;
864 buf = malloc( bufsize );
865 while( (nread=read(0,buf+total,bufsize-total)) > 0 )
866 {
867 total+=nread;
868 bufsize *= 2;
869 buf = realloc( buf, bufsize );
870 }
871 XStoreBuffer(dpy, buf, total, nbuf);
872 free(buf);
873 }
874
875 char *allwindows[] = {""};
876
877 int
main(int argc,char * argv[])878 main(int argc, char *argv[])
879 {
880 Window window = 0;
881 int *pargc = &argc;
882
883 program_name = argv[0] + strlen(argv[0]);
884 while (program_name != argv[0] && program_name[-1] != '/')
885 program_name--;
886
887 Setup_Display_And_Screen(pargc, argv);
888
889 Winidmode = WID_env;
890
891 while (argv++, --argc > 0) {
892 /* argv[0] = next argument */
893 /* argc = # of arguments left */
894 if (matchopt("a*ll", 0, pargc, argv)) {
895 Winidmode = WID_names;
896 names = allwindows;
897 numnames = 1;
898 }
899 else if (matchopt("ba*ckingstore", 0, pargc, argv) ||
900 matchopt("bs", 0, pargc, argv)) {
901 function |= FBIT(F_winattr);
902 Gbs = 1;
903 }
904 else if (matchopt("b*itmap", 1, pargc, argv)) {
905 function |= FBIT(iconbitmap);
906 bitmapname = *++argv;
907 }
908 else if (matchopt("colo*rmap", 1, pargc, argv) ||
909 matchopt("cm*ap", 1, pargc, argv)) {
910 function |= FBIT(colormap);
911 cmap = (Colormap) getxid(*++argv);
912 }
913 else if (matchopt("co*lumns", 1, pargc, argv)) {
914 function |= FBIT(columns);
915 ncolumns = atoi(*++argv);
916 }
917 else if (matchopt("store*buffer", 1, pargc, argv)) {
918 nbuffer = atoi(*++argv);
919 StoreBuffer( dpy, nbuffer );
920 }
921 else if (matchopt("fetch*buffer", 1, pargc, argv)) {
922 nbuffer = atoi(*++argv);
923 FetchBuffer( dpy, nbuffer );
924 }
925 else if (matchopt("c*urrent", 0, pargc, argv)) {
926 Winidmode = WID_curr;
927 }
928 else if (matchopt("iconm*ove", 2, pargc, argv)) {
929 function |= FBIT(iconmove);
930 Giconx = atoi(argv[1]);
931 Gicony = atoi(argv[2]);
932 argv += 2;
933 }
934 else if (matchopt("iconn*ame", 1, pargc, argv) ||
935 matchopt("in*ame", 1, pargc, argv)) {
936 function |= FBIT(iconname);
937 wmiconname = *++argv;
938 }
939 else if (matchopt("id", 1, pargc, argv)) {
940 Winidmode = WID_num;
941 window = (Window) getxid(*++argv);
942 }
943 else if (matchopt("i*conify", 0, pargc, argv)) {
944 function |= FBIT(icon);
945 }
946 else if (matchopt("k*eyrepeat", 1, pargc, argv) ||
947 matchopt("nok*eyrepeat", 1, pargc, argv)) {
948 int i;
949
950 function |= argv[0][1] == 'n' ?
951 FBIT(nokeyrepeat) : FBIT(keyrepeat);
952
953 i = atoi(*++argv);
954 if (i < 0)
955 usage();
956
957 while (1) {
958 keys[i & 0xff] = 1;
959 if (argc <= 0)
960 break;
961 if (strcmp(argv[0], "-") == 0) {
962 int from = i;
963
964 argc--, argv++;
965 if (argc < 0 || (i = atoi(argv[0])) <= 0)
966 usage();
967 while (from <= i)
968 keys[from++ & 0xff] = 1;
969 argc--, argv++;
970 if (argc <= 0)
971 break;
972 }
973 if ((i = atoi(argv[0])) <= 0)
974 break;
975 argc--, argv++;
976 }
977 }
978 else if (matchopt("li*st", 1, pargc, argv) ||
979 matchopt("names", 1, pargc, argv)) {
980 Winidmode = WID_names;
981 /* take rest of arg list */
982 names = ++argv;
983 numnames = argc;
984 argc = 0;
985 }
986 else if (matchopt("l*abel", 1, pargc, argv)) {
987 function |= FBIT(name);
988 wmname = *++argv;
989 }
990 else if (matchopt("ma*sk", 1, pargc, argv)) {
991 function |= FBIT(iconbitmap);
992 maskname = *++argv;
993 }
994 else if (matchopt("m*ove", 2, pargc, argv)) {
995 function |= FBIT(move);
996 Gright = (argv[1][0] == '-');
997 Gbottom = (argv[2][0] == '-');
998 tox = atoi(argv[1]);
999 toy = atoi(argv[2]);
1000 argv += 2;
1001 }
1002 else if (matchopt("noba*ckingstore", 0, pargc, argv) ||
1003 matchopt("nobs", 0, pargc, argv)) {
1004 function |= FBIT(F_winattr);
1005 Gbs = -1;
1006 }
1007 else if (matchopt("nosaveu*nder", 0, pargc, argv) ||
1008 matchopt("nosu", 0, pargc, argv)) {
1009 function |= FBIT(F_winattr);
1010 Gsu = -1;
1011 }
1012 else if (matchopt("nos*ave", 0, pargc, argv)) {
1013 function |= FBIT(nosave);
1014 }
1015 else if (matchopt("n*ame", 1, pargc, argv)) {
1016 function |= FBIT(name);
1017 wmname = *++argv;
1018 }
1019 else if (matchopt("o*pen", 0, pargc, argv)) {
1020 function |= FBIT(pop);
1021 }
1022 else if (matchopt("p*op", 0, pargc, argv)) {
1023 function |= FBIT(pop);
1024 }
1025 else if (matchopt("pr*int", 0, pargc, argv)) {
1026 function |= FBIT(print);
1027 }
1028 else if (matchopt("f*ocus", 0, pargc, argv)) {
1029 function |= FBIT(focus);
1030 }
1031 else if (matchopt("ra*ise", 0, pargc, argv)) {
1032 function |= FBIT(raise);
1033 }
1034 else if (matchopt("lo*wer", 0, pargc, argv)) {
1035 function |= FBIT(lower);
1036 }
1037 else if (matchopt("op*posite", 0, pargc, argv)) {
1038 function |= FBIT(opposite);
1039 }
1040 else if (matchopt("cir*culate", 0, pargc, argv)) {
1041 function |= FBIT(circulate);
1042 }
1043 else if (matchopt("uncir*culate", 0, pargc, argv)) {
1044 function |= FBIT(uncirculate);
1045 }
1046 else if (matchopt("ri*conmove", 2, pargc, argv)) {
1047 function |= FBIT(riconmove);
1048 Giconx = atoi(argv[1]);
1049 Gicony = atoi(argv[2]);
1050 argv += 2;
1051 }
1052 else if (matchopt("rm*ove", 2, pargc, argv)) {
1053 function |= FBIT(rmove);
1054 tox = atoi(argv[1]);
1055 toy = atoi(argv[2]);
1056 argv += 2;
1057 }
1058 else if (matchopt("roo*t", 0, pargc, argv)) {
1059 Winidmode = WID_root;
1060 }
1061 else if (matchopt("ro*ws", 1, pargc, argv)) {
1062 function |= FBIT(rows);
1063 nrows = atoi(*++argv);
1064 }
1065 else if (matchopt("rw*arp", 2, pargc, argv)) {
1066 function |= FBIT(rwarp);
1067 warpx = atoi(argv[1]);
1068 warpy = atoi(argv[2]);
1069 argv += 2;
1070 }
1071 else if (matchopt("r*esize", 2, pargc, argv)) {
1072 function |= FBIT(resize);
1073 towidth = atoi(argv[1]);
1074 toheight = atoi(argv[2]);
1075 argv += 2;
1076 }
1077 else if (matchopt("saveu*nder", 0, pargc, argv) ||
1078 matchopt("su", 0, pargc, argv)) {
1079 function |= FBIT(F_winattr);
1080 Gsu = argv[0][1] == 1;
1081 }
1082 else if (matchopt("se*lect", 0, pargc, argv)) {
1083 Winidmode = WID_select;
1084 }
1085 else if (matchopt("sy*nc", 0, pargc, argv)) {
1086 XSynchronize(dpy, True);
1087 }
1088 else if (matchopt("s*ave", 0, pargc, argv)) {
1089 function |= FBIT(save);
1090 }
1091 else if (matchopt("un*map", 0, pargc, argv)) {
1092 function |= FBIT(unmap);
1093 }
1094 else if (matchopt("w*arp", 2, pargc, argv)) {
1095 function |= FBIT(warp);
1096 warpx = atoi(argv[1]);
1097 warpy = atoi(argv[2]);
1098 argv += 2;
1099 } else if(matchopt("prop*erty",1, pargc,argv)) {
1100 property = XInternAtom(dpy,argv[1],False);
1101 if( None == property ) {
1102 Fatal_Error("Unknown atom %s",argv[1]);
1103 }
1104 argv++;
1105 }
1106 else
1107 usage();
1108 }
1109
1110 /* default function: pop */
1111 if (function == 0)
1112 function = FBIT(pop);
1113
1114 if ((function & ~NOWINDOW) == 0)
1115 Winidmode = WID_none;
1116
1117 root = DefaultRootWindow(dpy);
1118
1119 switch (Winidmode) {
1120 case WID_env:
1121 {
1122 char *s;
1123
1124 s = getenv("WINDOWID");
1125 if (s != 0)
1126 window = (Window) getxid(s);
1127 else {
1128 /* no WINDOWID, use window under cursor */
1129 window = xwit_select_window(dpy, 1);
1130 if (window == None)
1131 Fatal_Error("WINDOWID not set");
1132 }
1133 }
1134 break;
1135 case WID_root:
1136 window = root;
1137 break;
1138 case WID_curr:
1139 window = xwit_select_window(dpy, 1);
1140 break;
1141 case WID_select:
1142 window = xwit_select_window(dpy, 0);
1143 break;
1144 default:
1145 break;
1146 }
1147
1148 switch (Winidmode) {
1149 case WID_none:
1150 doit((Window) 0);
1151 break;
1152 case WID_names:
1153 downtree(root);
1154 break;
1155 default:
1156 if (!window)
1157 Fatal_Error("no window selected");
1158 doit(window);
1159 break;
1160 }
1161
1162 XSync(dpy, True);
1163 (void) XCloseDisplay(dpy);
1164 return(!Gwinfound);
1165 }
1166
1167