xwininfo.c revision 10998002
1/* $XdotOrg: $ */
2/* $Xorg: xwininfo.c,v 1.4 2001/02/09 02:06:04 xorgcvs Exp $ */
3/*
4
5Copyright 1987, 1998  The Open Group
6Copyright 1999 Sun Microsystems, Inc.
7
8Permission to use, copy, modify, distribute, and sell this software and its
9documentation for any purpose is hereby granted without fee, provided that
10the above copyright notice appear in all copies and that both that
11copyright notice and this permission notice appear in supporting
12documentation.
13
14The above copyright notice and this permission notice shall be included
15in all copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
20OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
22INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
23FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
24NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
25WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26
27Except as contained in this notice, the name of a copyright holder
28shall not be used in advertising or otherwise to promote the sale, use
29or other dealings in this Software without prior written authorization
30of the copyright holder.
31
32*/
33/* $XFree86: xc/programs/xwininfo/xwininfo.c,v 1.9 2003/09/09 22:08:25 herrb Exp $ */
34
35
36/*
37 * xwininfo.c	- MIT Project Athena, X Window system window
38 *		  information utility.
39 *
40 *
41 *	This program will report all relevant information
42 *	about a specific window.
43 *
44 *  Author:	Mark Lillibridge, MIT Project Athena
45 *		16-Jun-87
46 */
47
48#include "config.h"
49#include <X11/Xlib.h>
50#include <X11/Xutil.h>
51#include <X11/Xatom.h>
52#include <X11/Xos.h>
53#include <X11/extensions/shape.h>
54#ifndef NO_I18N
55#include <X11/Xlocale.h>
56#endif
57#include <stdio.h>
58#include <stdlib.h>
59
60/* Include routines to handle parsing defaults */
61#include "dsimple.h"
62
63typedef struct {
64	long code;
65	const char *name;
66} binding;
67
68static void scale_init(void);
69static char *nscale(int, int, int, char *, size_t);
70static char *xscale(int);
71static char *yscale(int);
72static char *bscale(int);
73static int bad_window_handler(Display *, XErrorEvent *);
74int main(int, char **);
75static const char *LookupL(long, const binding *);
76static const char *Lookup(int, const binding *);
77static void Display_Window_Id(Window, int);
78static void Display_Stats_Info(Window);
79static void Display_Bits_Info(Window);
80static void Display_Event_Mask(long);
81static void Display_Events_Info(Window);
82static void Display_Tree_Info(Window, int);
83static void display_tree_info_1(Window, int, int);
84static void Display_Hints(XSizeHints *);
85static void Display_Size_Hints(Window);
86static void Display_Window_Shape(Window);
87static void Display_WM_Info(Window);
88
89static char *window_id_format = "0x%lx";
90
91#ifndef HAVE_STRLCAT
92static size_t strlcat(char *dst, const char *src, size_t dstsize)
93{
94    size_t sd = strlen(dst);
95    size_t ss = strlen(src);
96    size_t s = sd + ss;
97
98    if (s < dstsize) {
99	strcpy(dst + sd, src);
100    } else {
101	strncpy(dst + sd, src, dstsize-sd-1);
102	dst[dstsize] = '\0';
103    }
104    return s;
105}
106#endif
107
108/*
109 * Report the syntax for calling xwininfo:
110 */
111void
112usage(void)
113{
114    fprintf (stderr,
115	"usage:  %s [-options ...]\n\n", program_name);
116    fprintf (stderr,
117	"where options include:\n");
118    fprintf (stderr,
119	"    -help                print this message\n");
120    fprintf (stderr,
121	"    -display host:dpy    X server to contact\n");
122    fprintf (stderr,
123	"    -root                use the root window\n");
124    fprintf (stderr,
125	"    -id windowid         use the window with the specified id\n");
126    fprintf (stderr,
127	"    -name windowname     use the window with the specified name\n");
128    fprintf (stderr,
129	"    -int                 print window id in decimal\n");
130    fprintf (stderr,
131	"    -children            print parent and child identifiers\n");
132    fprintf (stderr,
133	"    -tree                print children identifiers recursively\n");
134    fprintf (stderr,
135	"    -stats               print window geometry [DEFAULT]\n");
136    fprintf (stderr,
137	"    -bits                print window pixel information\n");
138    fprintf (stderr,
139	"    -events              print events selected for on window\n");
140    fprintf (stderr,
141	"    -size                print size hints\n");
142    fprintf (stderr,
143	"    -wm                  print window manager hints\n");
144    fprintf (stderr,
145	"    -shape               print shape extents\n");
146    fprintf (stderr,
147	"    -frame               don't ignore window manager frames\n");
148    fprintf (stderr,
149	"    -english             print sizes in english units\n");
150    fprintf (stderr,
151	"    -metric              print sizes in metric units\n");
152    fprintf (stderr,
153	"    -all                 -tree, -stats, -bits, -events, -wm, -size, -shape\n");
154    fprintf (stderr,
155	"\n");
156    exit (1);
157}
158
159/*
160 * pixel to inch, metric converter.
161 * Hacked in by Mark W. Eichin <eichin@athena> [eichin:19880619.1509EST]
162 *
163 * Simply put: replace the old numbers with string print calls.
164 * Returning a local string is ok, since we only ever get called to
165 * print one x and one y, so as long as they don't collide, they're
166 * fine. This is not meant to be a general purpose routine.
167 *
168 */
169
170#define getdsp(var,fn) var = fn(dpy, DefaultScreen(dpy))
171static int xp=0, xmm=0;
172static int yp=0, ymm=0;
173static int bp=0, bmm=0;
174static int english = 0, metric = 0;
175
176static void
177scale_init(void)
178{
179  getdsp(yp,  DisplayHeight);
180  getdsp(ymm, DisplayHeightMM);
181  getdsp(xp,  DisplayWidth);
182  getdsp(xmm, DisplayWidthMM);
183  bp  = xp  + yp;
184  bmm = xmm + ymm;
185}
186
187#define MILE (5280*12)
188#define YARD (3*12)
189#define FOOT (12)
190
191static char *
192nscale(int n, int np, int nmm, char *nbuf, size_t nbufsize)
193{
194    int s;
195    snprintf(nbuf, nbufsize, "%d", n);
196
197    if (metric||english) {
198	s = strlcat(nbuf, " (", nbufsize);
199
200	if (metric) {
201	    snprintf(nbuf+s, nbufsize-s, "%.2f mm%s",
202		     ((double) n)*nmm/np, english ? "; " : "");
203	}
204	if (english) {
205	    double inch_frac;
206	    Bool printed_anything = False;
207	    int mi, yar, ft, inr;
208
209	    inch_frac = ((double) n)*(nmm/25.4)/np;
210	    inr = (int)inch_frac;
211	    inch_frac -= (double)inr;
212	    if (inr >= MILE) {
213		mi = inr/MILE;
214		inr %= MILE;
215		s = strlen(nbuf);
216		snprintf(nbuf+s, nbufsize-s, "%d %s(?!?)",
217			 mi, (mi==1) ? "mile" : "miles");
218		printed_anything = True;
219	    }
220	    if (inr >= YARD) {
221		yar = inr/YARD;
222		inr %= YARD;
223		if (printed_anything)
224		    strlcat(nbuf, ", ", nbufsize);
225		s = strlen(nbuf);
226		snprintf(nbuf+s, nbufsize-s, "%d %s",
227			yar, (yar==1) ? "yard" : "yards");
228		printed_anything = True;
229	    }
230	    if (inr >= FOOT) {
231		ft = inr/FOOT;
232		inr  %= FOOT;
233		if (printed_anything)
234		    strlcat(nbuf, ", ", nbufsize);
235		s = strlen(nbuf);
236		snprintf(nbuf+s, nbufsize-s, "%d %s",
237			ft, (ft==1) ? "foot" : "feet");
238		printed_anything = True;
239	    }
240	    if (!printed_anything || inch_frac != 0.0 || inr != 0) {
241		if (printed_anything)
242		    strlcat(nbuf, ", ", nbufsize);
243		s = strlen(nbuf);
244		snprintf(nbuf+s, nbufsize-s, "%.2f inches", inr+inch_frac);
245	    }
246	}
247	strlcat (nbuf, ")", nbufsize);
248    }
249    return(nbuf);
250}
251
252static char xbuf[BUFSIZ];
253static char *
254xscale(int x)
255{
256  if(!xp) {
257    scale_init();
258  }
259  return(nscale(x, xp, xmm, xbuf, sizeof(xbuf)));
260}
261
262static char ybuf[BUFSIZ];
263static char *
264yscale(int y)
265{
266  if(!yp) {
267    scale_init();
268  }
269  return(nscale(y, yp, ymm, ybuf, sizeof(ybuf)));
270}
271
272static char bbuf[BUFSIZ];
273static char *
274bscale(int b)
275{
276  if(!bp) {
277    scale_init();
278  }
279  return(nscale(b, bp, bmm, bbuf, sizeof(bbuf)));
280}
281
282/* end of pixel to inch, metric converter */
283
284/* This handler is enabled when we are checking
285   to see if the -id the user specified is valid. */
286
287/* ARGSUSED */
288static int
289bad_window_handler(Display *disp, XErrorEvent *err)
290{
291    char badid[20];
292
293    snprintf(badid, sizeof(badid), window_id_format, err->resourceid);
294    Fatal_Error("No such window with id %s.", badid);
295    exit (1);
296    return 0;
297}
298
299
300int
301main(int argc, char **argv)
302{
303  register int i;
304  int tree = 0, stats = 0, bits = 0, events = 0, wm = 0, size  = 0, shape = 0;
305  int frame = 0, children = 0;
306  Window window;
307
308  INIT_NAME;
309
310#ifndef NO_I18N
311  {
312     char *lc;
313     lc = setlocale(LC_ALL, "");
314     if(!lc)
315        fprintf(stderr, "can not set locale properly\n");
316  }
317#endif
318
319  /* Open display, handle command line arguments */
320  Setup_Display_And_Screen(&argc, argv);
321
322  /* Get window selected on command line, if any */
323  window = Select_Window_Args(&argc, argv);
324
325  /* Handle our command line arguments */
326  for (i = 1; i < argc; i++) {
327    if (!strcmp(argv[i], "-help"))
328      usage();
329    if (!strcmp(argv[i], "-int")) {
330      window_id_format = "%ld";
331      continue;
332    }
333    if (!strcmp(argv[i], "-children")) {
334      children = 1;
335      continue;
336    }
337    if (!strcmp(argv[i], "-tree")) {
338      tree = 1;
339      continue;
340    }
341    if (!strcmp(argv[i], "-stats")) {
342      stats = 1;
343      continue;
344    }
345    if (!strcmp(argv[i], "-bits")) {
346      bits = 1;
347      continue;
348    }
349    if (!strcmp(argv[i], "-events")) {
350      events = 1;
351      continue;
352    }
353    if (!strcmp(argv[i], "-wm")) {
354      wm = 1;
355      continue;
356    }
357    if (!strcmp(argv[i], "-frame")) {
358      frame = 1;
359      continue;
360    }
361    if (!strcmp(argv[i], "-size")) {
362      size = 1;
363      continue;
364    }
365    if (!strcmp(argv[i], "-shape")) {
366      shape = 1;
367      continue;
368    }
369    if (!strcmp(argv[i], "-english")) {
370      english = 1;
371      continue;
372    }
373    if (!strcmp(argv[i], "-metric")) {
374      metric = 1;
375      continue;
376    }
377    if (!strcmp(argv[i], "-all")) {
378      tree = stats = bits = events = wm = size = shape = 1;
379      continue;
380    }
381    usage();
382  }
383
384  /* If no window selected on command line, let user pick one the hard way */
385  if (!window) {
386	  printf("\n");
387	  printf("xwininfo: Please select the window about which you\n");
388	  printf("          would like information by clicking the\n");
389	  printf("          mouse in that window.\n");
390	  window = Select_Window(dpy, !frame);
391  }
392
393  /*
394   * Do the actual displaying as per parameters
395   */
396  if (!(children || tree || bits || events || wm || size))
397    stats = 1;
398
399  /*
400   * make sure that the window is valid
401   */
402  {
403    Window root;
404    int x, y;
405    unsigned width, height, bw, depth;
406    XErrorHandler old_handler;
407
408    old_handler = XSetErrorHandler(bad_window_handler);
409    XGetGeometry (dpy, window, &root, &x, &y, &width, &height, &bw, &depth);
410    XSync (dpy, False);
411    (void) XSetErrorHandler(old_handler);
412  }
413
414  printf("\nxwininfo: Window id: ");
415  Display_Window_Id(window, True);
416  if (children || tree)
417    Display_Tree_Info(window, tree);
418  if (stats)
419    Display_Stats_Info(window);
420  if (bits)
421    Display_Bits_Info(window);
422  if (events)
423    Display_Events_Info(window);
424  if (wm)
425    Display_WM_Info(window);
426  if (size)
427    Display_Size_Hints(window);
428  if (shape)
429    Display_Window_Shape(window);
430  printf("\n");
431  exit(0);
432}
433
434
435/*
436 * Lookup: lookup a code in a table.
437 */
438static char _lookup_buffer[100];
439
440static const char *
441LookupL(long code, const binding *table)
442{
443	const char *name;
444
445	snprintf(_lookup_buffer, sizeof(_lookup_buffer),
446		 "unknown (code = %ld. = 0x%lx)", code, code);
447	name = _lookup_buffer;
448
449	while (table->name) {
450		if (table->code == code) {
451			name = table->name;
452			break;
453		}
454		table++;
455	}
456
457	return(name);
458}
459
460static const char *
461Lookup(int code, const binding *table)
462{
463    return LookupL((long)code, table);
464}
465
466/*
467 * Routine to display a window id in dec/hex with name if window has one
468 */
469
470static void
471Display_Window_Id(Window window, Bool newline_wanted)
472{
473#ifdef NO_I18N
474    char *win_name;
475#else
476    XTextProperty tp;
477#endif
478
479    printf(window_id_format, window);         /* print id # in hex/dec */
480
481    if (!window) {
482	printf(" (none)");
483    } else {
484	if (window == RootWindow(dpy, screen)) {
485	    printf(" (the root window)");
486	}
487#ifdef NO_I18N
488	if (!XFetchName(dpy, window, &win_name)) { /* Get window name if any */
489	    printf(" (has no name)");
490	} else if (win_name) {
491	    printf(" \"%s\"", win_name);
492	    XFree(win_name);
493	}
494#else
495	if (!XGetWMName(dpy, window, &tp)) { /* Get window name if any */
496	    printf(" (has no name)");
497        } else if (tp.nitems > 0) {
498            printf(" \"");
499            {
500                int count = 0, i, ret;
501                char **list = NULL;
502                ret = XmbTextPropertyToTextList(dpy, &tp, &list, &count);
503                if((ret == Success || ret > 0) && list != NULL){
504                    for(i=0; i<count; i++)
505                        printf("%s", list[i]);
506                    XFreeStringList(list);
507                } else {
508                    printf("%s", tp.value);
509                }
510            }
511            printf("\"");
512	}
513#endif
514	else
515	    printf(" (has no name)");
516    }
517
518    if (newline_wanted)
519	printf("\n");
520
521    return;
522}
523
524
525/*
526 * Display Stats on window
527 */
528static const binding _window_classes[] = {
529	{ InputOutput, "InputOutput" },
530	{ InputOnly, "InputOnly" },
531        { 0, NULL } };
532
533static const binding _map_states[] = {
534	{ IsUnmapped, "IsUnMapped" },
535	{ IsUnviewable, "IsUnviewable" },
536	{ IsViewable, "IsViewable" },
537	{ 0, NULL } };
538
539static const binding _backing_store_states[] = {
540	{ NotUseful, "NotUseful" },
541	{ WhenMapped, "WhenMapped" },
542	{ Always, "Always" },
543	{ 0, NULL } };
544
545static const binding _bit_gravity_states[] = {
546	{ ForgetGravity, "ForgetGravity" },
547	{ NorthWestGravity, "NorthWestGravity" },
548	{ NorthGravity, "NorthGravity" },
549	{ NorthEastGravity, "NorthEastGravity" },
550	{ WestGravity, "WestGravity" },
551	{ CenterGravity, "CenterGravity" },
552	{ EastGravity, "EastGravity" },
553	{ SouthWestGravity, "SouthWestGravity" },
554	{ SouthGravity, "SouthGravity" },
555	{ SouthEastGravity, "SouthEastGravity" },
556	{ StaticGravity, "StaticGravity" },
557	{ 0, NULL }};
558
559static const binding _window_gravity_states[] = {
560	{ UnmapGravity, "UnmapGravity" },
561	{ NorthWestGravity, "NorthWestGravity" },
562	{ NorthGravity, "NorthGravity" },
563	{ NorthEastGravity, "NorthEastGravity" },
564	{ WestGravity, "WestGravity" },
565	{ CenterGravity, "CenterGravity" },
566	{ EastGravity, "EastGravity" },
567	{ SouthWestGravity, "SouthWestGravity" },
568	{ SouthGravity, "SouthGravity" },
569	{ SouthEastGravity, "SouthEastGravity" },
570	{ StaticGravity, "StaticGravity" },
571	{ 0, NULL }};
572
573static const binding _visual_classes[] = {
574	{ StaticGray, "StaticGray" },
575	{ GrayScale, "GrayScale" },
576	{ StaticColor, "StaticColor" },
577	{ PseudoColor, "PseudoColor" },
578	{ TrueColor, "TrueColor" },
579	{ DirectColor, "DirectColor" },
580	{ 0, NULL }};
581
582static void
583Display_Stats_Info(Window window)
584{
585  XWindowAttributes win_attributes;
586  XVisualInfo vistemplate, *vinfo;
587  XSizeHints hints;
588  int dw = DisplayWidth (dpy, screen), dh = DisplayHeight (dpy, screen);
589  int rx, ry, xright, ybelow;
590  int showright = 0, showbelow = 0;
591  Status status;
592  Window wmframe;
593  int junk;
594  long longjunk;
595  Window junkwin;
596
597  if (!XGetWindowAttributes(dpy, window, &win_attributes))
598    Fatal_Error("Can't get window attributes.");
599  vistemplate.visualid = XVisualIDFromVisual(win_attributes.visual);
600  vinfo = XGetVisualInfo(dpy, VisualIDMask, &vistemplate, &junk);
601
602  (void) XTranslateCoordinates (dpy, window, win_attributes.root,
603				-win_attributes.border_width,
604				-win_attributes.border_width,
605				&rx, &ry, &junkwin);
606
607  xright = (dw - rx - win_attributes.border_width * 2 -
608	    win_attributes.width);
609  ybelow = (dh - ry - win_attributes.border_width * 2 -
610	    win_attributes.height);
611
612  printf("\n");
613  printf("  Absolute upper-left X:  %s\n", xscale(rx));
614  printf("  Absolute upper-left Y:  %s\n", yscale(ry));
615  printf("  Relative upper-left X:  %s\n", xscale(win_attributes.x));
616  printf("  Relative upper-left Y:  %s\n", yscale(win_attributes.y));
617  printf("  Width: %s\n", xscale(win_attributes.width));
618  printf("  Height: %s\n", yscale(win_attributes.height));
619  printf("  Depth: %d\n", win_attributes.depth);
620  printf("  Visual: 0x%lx\n", vinfo->visualid);
621  printf("  Visual Class: %s\n", Lookup(vinfo->class, _visual_classes));
622  printf("  Border width: %s\n", bscale(win_attributes.border_width));
623  printf("  Class: %s\n",
624  	 Lookup(win_attributes.class, _window_classes));
625  printf("  Colormap: 0x%lx (%sinstalled)\n",
626	 win_attributes.colormap, win_attributes.map_installed ? "" : "not ");
627  printf("  Bit Gravity State: %s\n",
628  	 Lookup(win_attributes.bit_gravity, _bit_gravity_states));
629  printf("  Window Gravity State: %s\n",
630  	 Lookup(win_attributes.win_gravity, _window_gravity_states));
631  printf("  Backing Store State: %s\n",
632  	 Lookup(win_attributes.backing_store, _backing_store_states));
633  printf("  Save Under State: %s\n",
634  	 win_attributes.save_under ? "yes" : "no");
635  printf("  Map State: %s\n",
636	 Lookup(win_attributes.map_state, _map_states));
637  printf("  Override Redirect State: %s\n",
638  	 win_attributes.override_redirect ? "yes" : "no");
639  printf("  Corners:  +%d+%d  -%d+%d  -%d-%d  +%d-%d\n",
640	 rx, ry, xright, ry, xright, ybelow, rx, ybelow);
641
642  XFree(vinfo);
643
644  /*
645   * compute geometry string that would recreate window
646   */
647  printf("  -geometry ");
648
649  /* compute size in appropriate units */
650  status = XGetWMNormalHints(dpy, window, &hints, &longjunk);
651  if (status  &&  hints.flags & PResizeInc  &&
652              hints.width_inc != 0  &&  hints.height_inc != 0) {
653      if (hints.flags & (PBaseSize|PMinSize)) {
654	  if (hints.flags & PBaseSize) {
655	      win_attributes.width -= hints.base_width;
656	      win_attributes.height -= hints.base_height;
657	  } else {
658	      /* ICCCM says MinSize is default for BaseSize */
659	      win_attributes.width -= hints.min_width;
660	      win_attributes.height -= hints.min_height;
661	  }
662      }
663      printf("%dx%d", win_attributes.width/hints.width_inc,
664	     win_attributes.height/hints.height_inc);
665  } else
666      printf("%dx%d", win_attributes.width, win_attributes.height);
667
668  if (!(hints.flags&PWinGravity))
669      hints.win_gravity = NorthWestGravity; /* per ICCCM */
670  /* find our window manager frame, if any */
671  wmframe = window;
672  while (True) {
673      Window root, parent;
674      Window *childlist;
675      unsigned int ujunk;
676
677      status = XQueryTree(dpy, wmframe, &root, &parent, &childlist, &ujunk);
678      if (parent == root || !parent || !status)
679	  break;
680      wmframe = parent;
681      if (status && childlist)
682	  XFree((char *)childlist);
683  }
684  if (wmframe != window) {
685      /* WM reparented, so find edges of the frame */
686      /* Only works for ICCCM-compliant WMs, and then only if the
687         window has corner gravity.  We would need to know the original width
688	 of the window to correctly handle the other gravities. */
689
690      XWindowAttributes frame_attr;
691
692      if (!XGetWindowAttributes(dpy, wmframe, &frame_attr))
693	  Fatal_Error("Can't get frame attributes.");
694      switch (hints.win_gravity) {
695	case NorthWestGravity: case SouthWestGravity:
696	case NorthEastGravity: case SouthEastGravity:
697	case WestGravity:
698	  rx = frame_attr.x;
699      }
700      switch (hints.win_gravity) {
701	case NorthWestGravity: case SouthWestGravity:
702	case NorthEastGravity: case SouthEastGravity:
703	case EastGravity:
704	  xright = dw - frame_attr.x - frame_attr.width -
705	      2*frame_attr.border_width;
706      }
707      switch (hints.win_gravity) {
708	case NorthWestGravity: case SouthWestGravity:
709	case NorthEastGravity: case SouthEastGravity:
710	case NorthGravity:
711	  ry = frame_attr.y;
712      }
713      switch (hints.win_gravity) {
714	case NorthWestGravity: case SouthWestGravity:
715	case NorthEastGravity: case SouthEastGravity:
716	case SouthGravity:
717	  ybelow = dh - frame_attr.y - frame_attr.height -
718	      2*frame_attr.border_width;
719      }
720  }
721  /* If edge gravity, offer a corner on that edge (because the application
722     programmer cares about that edge), otherwise offer upper left unless
723     some other corner is close to an edge of the screen.
724     (For corner gravity, assume gravity was set by XWMGeometry.
725     For CenterGravity, it doesn't matter.) */
726  if (hints.win_gravity == EastGravity  ||
727      (abs(xright) <= 100  &&  abs(xright) < abs(rx)
728        &&  hints.win_gravity != WestGravity))
729      showright = 1;
730  if (hints.win_gravity == SouthGravity  ||
731      (abs(ybelow) <= 100  &&  abs(ybelow) < abs(ry)
732        &&  hints.win_gravity != NorthGravity))
733      showbelow = 1;
734
735  if (showright)
736      printf("-%d", xright);
737  else
738      printf("+%d", rx);
739  if (showbelow)
740      printf("-%d", ybelow);
741  else
742      printf("+%d", ry);
743  printf("\n");
744}
745
746
747/*
748 * Display bits info:
749 */
750static const binding _gravities[] = {
751	{ UnmapGravity, "UnMapGravity" },      /* WARNING: both of these have*/
752	{ ForgetGravity, "ForgetGravity" },    /* the same value - see code */
753	{ NorthWestGravity, "NorthWestGravity" },
754	{ NorthGravity, "NorthGravity" },
755	{ NorthEastGravity, "NorthEastGravity" },
756	{ WestGravity, "WestGravity" },
757	{ CenterGravity, "CenterGravity" },
758	{ EastGravity, "EastGravity" },
759	{ SouthWestGravity, "SouthWestGravity" },
760	{ SouthGravity, "SouthGravity" },
761	{ SouthEastGravity, "SouthEastGravity" },
762	{ StaticGravity, "StaticGravity" },
763	{ 0, NULL } };
764
765static const binding _backing_store_hint[] = {
766	{ NotUseful, "NotUseful" },
767	{ WhenMapped, "WhenMapped" },
768	{ Always, "Always" },
769	{ 0, NULL } };
770
771static const binding _bool[] = {
772	{ 0, "No" },
773	{ 1, "Yes" },
774	{ 0, NULL } };
775
776static void
777Display_Bits_Info(Window window)
778{
779  XWindowAttributes win_attributes;
780
781  if (!XGetWindowAttributes(dpy, window, &win_attributes))
782    Fatal_Error("Can't get window attributes.");
783
784  printf("\n");
785  printf("  Bit gravity: %s\n",
786	 Lookup(win_attributes.bit_gravity, _gravities+1));
787  printf("  Window gravity: %s\n",
788	 Lookup(win_attributes.win_gravity, _gravities));
789  printf("  Backing-store hint: %s\n",
790	 Lookup(win_attributes.backing_store, _backing_store_hint));
791  printf("  Backing-planes to be preserved: 0x%lx\n",
792	 win_attributes.backing_planes);
793  printf("  Backing pixel: %ld\n", win_attributes.backing_pixel);
794  printf("  Save-unders: %s\n",
795	 Lookup(win_attributes.save_under, _bool));
796}
797
798
799/*
800 * Routine to display all events in an event mask
801 */
802static const binding _event_mask_names[] = {
803	{ KeyPressMask, "KeyPress" },
804	{ KeyReleaseMask, "KeyRelease" },
805	{ ButtonPressMask, "ButtonPress" },
806	{ ButtonReleaseMask, "ButtonRelease" },
807	{ EnterWindowMask, "EnterWindow" },
808	{ LeaveWindowMask, "LeaveWindow" },
809	{ PointerMotionMask, "PointerMotion" },
810	{ PointerMotionHintMask, "PointerMotionHint" },
811	{ Button1MotionMask, "Button1Motion" },
812	{ Button2MotionMask, "Button2Motion" },
813	{ Button3MotionMask, "Button3Motion" },
814	{ Button4MotionMask, "Button4Motion" },
815	{ Button5MotionMask, "Button5Motion" },
816	{ ButtonMotionMask, "ButtonMotion" },
817	{ KeymapStateMask, "KeymapState" },
818	{ ExposureMask, "Exposure" },
819	{ VisibilityChangeMask, "VisibilityChange" },
820	{ StructureNotifyMask, "StructureNotify" },
821	{ ResizeRedirectMask, "ResizeRedirect" },
822	{ SubstructureNotifyMask, "SubstructureNotify" },
823	{ SubstructureRedirectMask, "SubstructureRedirect" },
824	{ FocusChangeMask, "FocusChange" },
825	{ PropertyChangeMask, "PropertyChange" },
826	{ ColormapChangeMask, "ColormapChange" },
827	{ OwnerGrabButtonMask, "OwnerGrabButton" },
828	{ 0, NULL } };
829
830static void
831Display_Event_Mask(long mask)
832{
833  long bit, bit_mask;
834
835  for (bit=0, bit_mask=1; bit<sizeof(long)*8; bit++, bit_mask <<= 1)
836    if (mask & bit_mask)
837      printf("      %s\n",
838	     LookupL(bit_mask, _event_mask_names));
839}
840
841
842/*
843 * Display info on events
844 */
845static void
846Display_Events_Info(Window window)
847{
848  XWindowAttributes win_attributes;
849
850  if (!XGetWindowAttributes(dpy, window, &win_attributes))
851    Fatal_Error("Can't get window attributes.");
852
853  printf("\n");
854  printf("  Someone wants these events:\n");
855  Display_Event_Mask(win_attributes.all_event_masks);
856
857  printf("  Do not propagate these events:\n");
858  Display_Event_Mask(win_attributes.do_not_propagate_mask);
859
860  printf("  Override redirection?: %s\n",
861	 Lookup(win_attributes.override_redirect, _bool));
862}
863
864
865  /* left out visual stuff */
866  /* left out colormap */
867  /* left out map_installed */
868
869
870/*
871 * Display root, parent, and (recursively) children information
872 * recurse - true to show children information
873 */
874static void
875Display_Tree_Info(Window window, int recurse)
876{
877    display_tree_info_1(window, recurse, 0);
878}
879
880/*
881 * level - recursion level
882 */
883static void
884display_tree_info_1(Window window, int recurse, int level)
885{
886  int i, j;
887  int rel_x, rel_y, abs_x, abs_y;
888  unsigned int width, height, border, depth;
889  Window root_win, parent_win;
890  unsigned int num_children;
891  Window *child_list;
892  XClassHint classhint;
893
894  if (!XQueryTree(dpy, window, &root_win, &parent_win, &child_list,
895		  &num_children))
896    Fatal_Error("Can't query window tree.");
897
898  if (level == 0) {
899    printf("\n");
900    printf("  Root window id: ");
901    Display_Window_Id(root_win, True);
902    printf("  Parent window id: ");
903    Display_Window_Id(parent_win, True);
904  }
905
906  if (level == 0  ||  num_children > 0) {
907    printf("     ");
908    for (j=0; j<level; j++) printf("   ");
909    printf("%d child%s%s\n", num_children, num_children == 1 ? "" : "ren",
910	   num_children ? ":" : ".");
911  }
912
913  for (i = (int)num_children - 1; i >= 0; i--) {
914    printf("     ");
915    for (j=0; j<level; j++) printf("   ");
916    Display_Window_Id(child_list[i], False);
917    printf(": (");
918    if(XGetClassHint(dpy, child_list[i], &classhint)) {
919	if(classhint.res_name) {
920	    printf("\"%s\" ", classhint.res_name);
921	    XFree(classhint.res_name);
922	} else
923	    printf("(none) ");
924	if(classhint.res_class) {
925	    printf("\"%s\") ", classhint.res_class);
926	    XFree(classhint.res_class);
927	} else
928	    printf("(none)) ");
929    } else
930	printf(") ");
931
932    if (XGetGeometry(dpy, child_list[i], &root_win,
933		     &rel_x, &rel_y, &width, &height, &border, &depth)) {
934	Window child;
935
936	printf (" %ux%u+%d+%d", width, height, rel_x, rel_y);
937	if (XTranslateCoordinates (dpy, child_list[i], root_win,
938				   0 ,0, &abs_x, &abs_y, &child)) {
939	    printf ("  +%d+%d", abs_x - border, abs_y - border);
940	}
941    }
942    printf("\n");
943
944    if (recurse)
945	display_tree_info_1(child_list[i], 1, level+1);
946  }
947
948  if (child_list) XFree((char *)child_list);
949}
950
951
952/*
953 * Display a set of size hints
954 */
955static void
956Display_Hints(XSizeHints *hints)
957{
958	long flags;
959
960	flags = hints->flags;
961
962	if (flags & USPosition)
963	  printf("      User supplied location: %s, %s\n",
964		 xscale(hints->x), yscale(hints->y));
965
966	if (flags & PPosition)
967	  printf("      Program supplied location: %s, %s\n",
968		 xscale(hints->x), yscale(hints->y));
969
970	if (flags & USSize) {
971	  printf("      User supplied size: %s by %s\n",
972		 xscale(hints->width), yscale(hints->height));
973	}
974
975	if (flags & PSize)
976	  printf("      Program supplied size: %s by %s\n",
977		 xscale(hints->width), yscale(hints->height));
978
979	if (flags & PMinSize)
980	  printf("      Program supplied minimum size: %s by %s\n",
981		 xscale(hints->min_width), yscale(hints->min_height));
982
983	if (flags & PMaxSize)
984	  printf("      Program supplied maximum size: %s by %s\n",
985		 xscale(hints->max_width), yscale(hints->max_height));
986
987	if (flags & PBaseSize) {
988	  printf("      Program supplied base size: %s by %s\n",
989		 xscale(hints->base_width), yscale(hints->base_height));
990	}
991
992	if (flags & PResizeInc) {
993	  printf("      Program supplied x resize increment: %s\n",
994		 xscale(hints->width_inc));
995	  printf("      Program supplied y resize increment: %s\n",
996		 yscale(hints->height_inc));
997	  if (hints->width_inc != 0 && hints->height_inc != 0) {
998	      if (flags & USSize)
999		  printf("      User supplied size in resize increments:  %s by %s\n",
1000			 (xscale(hints->width / hints->width_inc)),
1001			 (yscale(hints->height / hints->height_inc)));
1002	      if (flags & PSize)
1003		  printf("      Program supplied size in resize increments:  %s by %s\n",
1004			 (xscale(hints->width / hints->width_inc)),
1005			 (yscale(hints->height / hints->height_inc)));
1006	      if (flags & PMinSize)
1007		  printf("      Program supplied minimum size in resize increments: %s by %s\n",
1008			 xscale(hints->min_width / hints->width_inc), yscale(hints->min_height / hints->height_inc));
1009	      if (flags & PBaseSize)
1010		  printf("      Program supplied base size in resize increments:  %s by %s\n",
1011			 (xscale(hints->base_width / hints->width_inc)),
1012			 (yscale(hints->base_height / hints->height_inc)));
1013	  }
1014        }
1015
1016	if (flags & PAspect) {
1017	  printf("      Program supplied min aspect ratio: %s/%s\n",
1018		 xscale(hints->min_aspect.x), yscale(hints->min_aspect.y));
1019	  printf("      Program supplied max aspect ratio: %s/%s\n",
1020		 xscale(hints->max_aspect.x), yscale(hints->max_aspect.y));
1021        }
1022
1023	if (flags & PWinGravity) {
1024	  printf("      Program supplied window gravity: %s\n",
1025		 Lookup(hints->win_gravity, _gravities));
1026	}
1027}
1028
1029
1030/*
1031 * Display Size Hints info
1032 */
1033static void
1034Display_Size_Hints(Window window)
1035{
1036	XSizeHints *hints = XAllocSizeHints();
1037	long supplied;
1038
1039	printf("\n");
1040	if (!XGetWMNormalHints(dpy, window, hints, &supplied))
1041	    printf("  No normal window size hints defined\n");
1042	else {
1043	    printf("  Normal window size hints:\n");
1044	    hints->flags &= supplied;
1045	    Display_Hints(hints);
1046	}
1047
1048	if (!XGetWMSizeHints(dpy, window, hints, &supplied, XA_WM_ZOOM_HINTS))
1049	    printf("  No zoom window size hints defined\n");
1050	else {
1051	    printf("  Zoom window size hints:\n");
1052	    hints->flags &= supplied;
1053	    Display_Hints(hints);
1054	}
1055	XFree((char *)hints);
1056}
1057
1058
1059static void
1060Display_Window_Shape (Window window)
1061{
1062    Bool    ws, bs;
1063    int	    xws, yws, xbs, ybs;
1064    unsigned int wws, hws, wbs, hbs;
1065
1066    if (!XShapeQueryExtension (dpy, &bs, &ws))
1067	return;
1068
1069    printf("\n");
1070    XShapeQueryExtents (dpy, window, &ws, &xws, &yws, &wws, &hws,
1071				     &bs, &xbs, &ybs, &wbs, &hbs);
1072    if (!ws)
1073	  printf("  No window shape defined\n");
1074    else {
1075	  printf("  Window shape extents:  %sx%s",
1076		 xscale(wws), yscale(hws));
1077	  printf("+%s+%s\n", xscale(xws), yscale(yws));
1078    }
1079    if (!bs)
1080	  printf("  No border shape defined\n");
1081    else {
1082	  printf("  Border shape extents:  %sx%s",
1083		 xscale(wbs), yscale(hbs));
1084	  printf("+%s+%s\n", xscale(xbs), yscale(ybs));
1085    }
1086}
1087
1088/*
1089 * Display Window Manager Info
1090 */
1091static const binding _state_hints[] = {
1092	{ DontCareState, "Don't Care State" },
1093	{ NormalState, "Normal State" },
1094	{ ZoomState, "Zoomed State" },
1095	{ IconicState, "Iconic State" },
1096	{ InactiveState, "Inactive State" },
1097	{ 0, NULL } };
1098
1099static void
1100Display_WM_Info(Window window)
1101{
1102        XWMHints *wmhints;
1103	long flags;
1104
1105	wmhints = XGetWMHints(dpy, window);
1106	printf("\n");
1107	if (!wmhints) {
1108		printf("  No window manager hints defined\n");
1109		return;
1110	}
1111	flags = wmhints->flags;
1112
1113	printf("  Window manager hints:\n");
1114
1115	if (flags & InputHint)
1116	  printf("      Client accepts input or input focus: %s\n",
1117		 Lookup(wmhints->input, _bool));
1118
1119	if (flags & IconWindowHint) {
1120		printf("      Icon window id: ");
1121		Display_Window_Id(wmhints->icon_window, True);
1122	}
1123
1124	if (flags & IconPositionHint)
1125	  printf("      Initial icon position: %s, %s\n",
1126		 xscale(wmhints->icon_x), yscale(wmhints->icon_y));
1127
1128	if (flags & StateHint)
1129	  printf("      Initial state is %s\n",
1130		 Lookup(wmhints->initial_state, _state_hints));
1131
1132	XFree(wmhints);
1133}
1134