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