xwininfo.c revision 863f95b1
1863f95b1Smrg/*
2863f95b1Smrg * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
3863f95b1Smrg *
4863f95b1Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5863f95b1Smrg * copy of this software and associated documentation files (the "Software"),
6863f95b1Smrg * to deal in the Software without restriction, including without limitation
7863f95b1Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8863f95b1Smrg * and/or sell copies of the Software, and to permit persons to whom the
9863f95b1Smrg * Software is furnished to do so, subject to the following conditions:
10863f95b1Smrg *
11863f95b1Smrg * The above copyright notice and this permission notice (including the next
12863f95b1Smrg * paragraph) shall be included in all copies or substantial portions of the
13863f95b1Smrg * Software.
14863f95b1Smrg *
15863f95b1Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16863f95b1Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17863f95b1Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18863f95b1Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19863f95b1Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20863f95b1Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21863f95b1Smrg * DEALINGS IN THE SOFTWARE.
22863f95b1Smrg */
23ff7e0accSmrg/*
24ff7e0accSmrg
25ff7e0accSmrgCopyright 1987, 1998  The Open Group
26ff7e0accSmrg
27ff7e0accSmrgPermission to use, copy, modify, distribute, and sell this software and its
28ff7e0accSmrgdocumentation for any purpose is hereby granted without fee, provided that
29ff7e0accSmrgthe above copyright notice appear in all copies and that both that
30ff7e0accSmrgcopyright notice and this permission notice appear in supporting
31ff7e0accSmrgdocumentation.
32ff7e0accSmrg
33ff7e0accSmrgThe above copyright notice and this permission notice shall be included
34ff7e0accSmrgin all copies or substantial portions of the Software.
35ff7e0accSmrg
36ff7e0accSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
37ff7e0accSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
38ff7e0accSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
39ff7e0accSmrgOF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
40ff7e0accSmrgHOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
41ff7e0accSmrgINDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
42ff7e0accSmrgFROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
43ff7e0accSmrgNEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
44ff7e0accSmrgWITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
45ff7e0accSmrg
46ff7e0accSmrgExcept as contained in this notice, the name of a copyright holder
47ff7e0accSmrgshall not be used in advertising or otherwise to promote the sale, use
48ff7e0accSmrgor other dealings in this Software without prior written authorization
49ff7e0accSmrgof the copyright holder.
50ff7e0accSmrg
51ff7e0accSmrg*/
52ff7e0accSmrg
53ff7e0accSmrg
54ff7e0accSmrg/*
55ff7e0accSmrg * xwininfo.c	- MIT Project Athena, X Window system window
56ff7e0accSmrg *		  information utility.
57ff7e0accSmrg *
58ff7e0accSmrg *
59ff7e0accSmrg *	This program will report all relevant information
60ff7e0accSmrg *	about a specific window.
61ff7e0accSmrg *
62ff7e0accSmrg *  Author:	Mark Lillibridge, MIT Project Athena
63ff7e0accSmrg *		16-Jun-87
64ff7e0accSmrg */
65ff7e0accSmrg
66ff7e0accSmrg#include "config.h"
67863f95b1Smrg
68863f95b1Smrg#include <xcb/xcb.h>
69863f95b1Smrg#include <xcb/xproto.h>
70863f95b1Smrg#ifdef USE_XCB_ICCCM
71863f95b1Smrg# include <xcb/xcb_icccm.h>
72ff7e0accSmrg#endif
73863f95b1Smrg#include <xcb/shape.h>
74863f95b1Smrg
75ff7e0accSmrg#include <stdio.h>
76ff7e0accSmrg#include <stdlib.h>
77863f95b1Smrg#include <string.h>
78863f95b1Smrg#include <locale.h>
79863f95b1Smrg#include <langinfo.h>
80863f95b1Smrg#ifdef HAVE_ICONV
81863f95b1Smrg# include <iconv.h>
82863f95b1Smrg#endif
83863f95b1Smrg#include <ctype.h>
84863f95b1Smrg#include <errno.h>
85863f95b1Smrg
86863f95b1Smrg#ifndef HAVE_STRNLEN
87863f95b1Smrg#include "strnlen.h"
88863f95b1Smrg#endif
89ff7e0accSmrg
90ff7e0accSmrg/* Include routines to handle parsing defaults */
91ff7e0accSmrg#include "dsimple.h"
92ff7e0accSmrg
93ff7e0accSmrgtypedef struct {
94863f95b1Smrg    long code;
95863f95b1Smrg    const char *name;
96ff7e0accSmrg} binding;
97ff7e0accSmrg
98863f95b1Smrg#ifndef USE_XCB_ICCCM
99863f95b1Smrg/* Once xcb-icccm's API is stable, this should be replaced by
100863f95b1Smrg   xcb_size_hints_t & xcb_size_hints_flags_t */
101863f95b1Smrgtypedef struct {
102863f95b1Smrg  /** User specified flags */
103863f95b1Smrg  uint32_t flags;
104863f95b1Smrg  /** User-specified position */
105863f95b1Smrg  int32_t x, y;
106863f95b1Smrg  /** User-specified size */
107863f95b1Smrg  int32_t width, height;
108863f95b1Smrg  /** Program-specified minimum size */
109863f95b1Smrg  int32_t min_width, min_height;
110863f95b1Smrg  /** Program-specified maximum size */
111863f95b1Smrg  int32_t max_width, max_height;
112863f95b1Smrg  /** Program-specified resize increments */
113863f95b1Smrg  int32_t width_inc, height_inc;
114863f95b1Smrg  /** Program-specified minimum aspect ratios */
115863f95b1Smrg  int32_t min_aspect_num, min_aspect_den;
116863f95b1Smrg  /** Program-specified maximum aspect ratios */
117863f95b1Smrg  int32_t max_aspect_num, max_aspect_den;
118863f95b1Smrg  /** Program-specified base size */
119863f95b1Smrg  int32_t base_width, base_height;
120863f95b1Smrg  /** Program-specified window gravity */
121863f95b1Smrg  uint32_t win_gravity;
122863f95b1Smrg} wm_size_hints_t;
123863f95b1Smrg
124863f95b1Smrg# define xcb_size_hints_t wm_size_hints_t
125863f95b1Smrg
126863f95b1Smrgtypedef struct {
127863f95b1Smrg  /** Marks which fields in this structure are defined */
128863f95b1Smrg  int32_t flags;
129863f95b1Smrg  /** Does this application rely on the window manager to get keyboard
130863f95b1Smrg      input? */
131863f95b1Smrg  uint32_t input;
132863f95b1Smrg  /** See below */
133863f95b1Smrg  int32_t initial_state;
134863f95b1Smrg  /** Pixmap to be used as icon */
135863f95b1Smrg  xcb_pixmap_t icon_pixmap;
136863f95b1Smrg  /** Window to be used as icon */
137863f95b1Smrg  xcb_window_t icon_window;
138863f95b1Smrg  /** Initial position of icon */
139863f95b1Smrg  int32_t icon_x, icon_y;
140863f95b1Smrg  /** Icon mask bitmap */
141863f95b1Smrg  xcb_pixmap_t icon_mask;
142863f95b1Smrg  /* Identifier of related window group */
143863f95b1Smrg  xcb_window_t window_group;
144863f95b1Smrg} wm_hints_t;
145863f95b1Smrg
146863f95b1Smrg#define xcb_wm_hints_t wm_hints_t
147863f95b1Smrg
148863f95b1Smrgenum {
149863f95b1Smrg  /* xcb_size_hints_flags_t */
150863f95b1Smrg  XCB_SIZE_HINT_US_POSITION = 1 << 0,
151863f95b1Smrg  XCB_SIZE_HINT_US_SIZE = 1 << 1,
152863f95b1Smrg  XCB_SIZE_HINT_P_POSITION = 1 << 2,
153863f95b1Smrg  XCB_SIZE_HINT_P_SIZE = 1 << 3,
154863f95b1Smrg  XCB_SIZE_HINT_P_MIN_SIZE = 1 << 4,
155863f95b1Smrg  XCB_SIZE_HINT_P_MAX_SIZE = 1 << 5,
156863f95b1Smrg  XCB_SIZE_HINT_P_RESIZE_INC = 1 << 6,
157863f95b1Smrg  XCB_SIZE_HINT_P_ASPECT = 1 << 7,
158863f95b1Smrg  XCB_SIZE_HINT_BASE_SIZE = 1 << 8,
159863f95b1Smrg  XCB_SIZE_HINT_P_WIN_GRAVITY = 1 << 9,
160863f95b1Smrg  /* xcb_wm_state_t */
161863f95b1Smrg  XCB_WM_STATE_WITHDRAWN = 0,
162863f95b1Smrg  XCB_WM_STATE_NORMAL = 1,
163863f95b1Smrg  XCB_WM_STATE_ICONIC = 3,
164863f95b1Smrg  /* xcb_wm_t */
165863f95b1Smrg  XCB_WM_HINT_INPUT = (1L << 0),
166863f95b1Smrg  XCB_WM_HINT_STATE = (1L << 1),
167863f95b1Smrg  XCB_WM_HINT_ICON_PIXMAP = (1L << 2),
168863f95b1Smrg  XCB_WM_HINT_ICON_WINDOW = (1L << 3),
169863f95b1Smrg  XCB_WM_HINT_ICON_POSITION = (1L << 4),
170863f95b1Smrg  XCB_WM_HINT_ICON_MASK = (1L << 5),
171863f95b1Smrg  XCB_WM_HINT_WINDOW_GROUP = (1L << 6),
172863f95b1Smrg  XCB_WM_HINT_X_URGENCY = (1L << 8)
173863f95b1Smrg};
174863f95b1Smrg
175863f95b1Smrg/* Once xcb-icccm's API is stable, these should be replaced by calls to it */
176863f95b1Smrg# define GET_TEXT_PROPERTY(Dpy, Win, Atom) \
177863f95b1Smrg    xcb_get_property (Dpy, False, Win, Atom, XCB_GET_PROPERTY_TYPE_ANY, 0, BUFSIZ)
178863f95b1Smrg# define xcb_get_wm_name(Dpy, Win)	GET_TEXT_PROPERTY(Dpy, Win, XCB_ATOM_WM_NAME)
179863f95b1Smrg
180863f95b1Smrg# define xcb_get_wm_class(Dpy, Win) \
181863f95b1Smrg    xcb_get_property (Dpy, False, Win, XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 0, BUFSIZ)
182863f95b1Smrg# define xcb_get_wm_hints(Dpy, Win) \
183863f95b1Smrg    xcb_get_property(Dpy, False, Win, XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 0, 9)
184863f95b1Smrg
185863f95b1Smrg# define xcb_get_wm_size_hints(Dpy, Win, Atom) \
186863f95b1Smrg    xcb_get_property (Dpy, False, Win, Atom, XCB_ATOM_WM_SIZE_HINTS, 0, 18)
187863f95b1Smrg# define xcb_get_wm_normal_hints(Dpy, Win) \
188863f95b1Smrg    xcb_get_wm_size_hints(Dpy, Win, XCB_ATOM_WM_NORMAL_HINTS)
189863f95b1Smrg#endif
190863f95b1Smrg
191863f95b1Smrg/* Possibly in xcb-emwh in the future? */
192863f95b1Smrgstatic xcb_atom_t atom_net_wm_name, atom_utf8_string;
193863f95b1Smrgstatic xcb_atom_t atom_net_wm_desktop, atom_net_wm_window_type,
194863f95b1Smrg    atom_net_wm_state, atom_net_wm_pid, atom_net_frame_extents;
195863f95b1Smrgstatic xcb_get_property_cookie_t get_net_wm_name (xcb_connection_t *,
196863f95b1Smrg						  xcb_window_t);
197863f95b1Smrg
198863f95b1Smrg/* Information we keep track of for each window to allow prefetching/reusing */
199863f95b1Smrgstruct wininfo {
200863f95b1Smrg    xcb_window_t			window;
201863f95b1Smrg
202863f95b1Smrg    /* cookies for requests we've sent */
203863f95b1Smrg    xcb_get_geometry_cookie_t		geometry_cookie;
204863f95b1Smrg    xcb_get_property_cookie_t		net_wm_name_cookie;
205863f95b1Smrg    xcb_get_property_cookie_t		wm_name_cookie;
206863f95b1Smrg    xcb_get_property_cookie_t		wm_class_cookie;
207863f95b1Smrg    xcb_translate_coordinates_cookie_t	trans_coords_cookie;
208863f95b1Smrg    xcb_query_tree_cookie_t		tree_cookie;
209863f95b1Smrg    xcb_get_window_attributes_cookie_t	attr_cookie;
210863f95b1Smrg    xcb_get_property_cookie_t		normal_hints_cookie;
211863f95b1Smrg    xcb_get_property_cookie_t		hints_cookie;
212863f95b1Smrg    xcb_get_property_cookie_t		wm_desktop_cookie;
213863f95b1Smrg    xcb_get_property_cookie_t		wm_window_type_cookie;
214863f95b1Smrg    xcb_get_property_cookie_t		wm_state_cookie;
215863f95b1Smrg    xcb_get_property_cookie_t		wm_pid_cookie;
216863f95b1Smrg    xcb_get_property_cookie_t		wm_client_machine_cookie;
217863f95b1Smrg    xcb_get_property_cookie_t		frame_extents_cookie;
218863f95b1Smrg    xcb_get_property_cookie_t		zoom_cookie;
219863f95b1Smrg
220863f95b1Smrg    /* cached results from previous requests */
221863f95b1Smrg    xcb_get_geometry_reply_t *		geometry;
222863f95b1Smrg    xcb_get_window_attributes_reply_t *	win_attributes;
223863f95b1Smrg    xcb_size_hints_t *			normal_hints;
224863f95b1Smrg};
225863f95b1Smrg
226863f95b1Smrgstatic void scale_init (xcb_screen_t *scrn);
227863f95b1Smrgstatic char *nscale (int, int, int, char *, size_t);
228863f95b1Smrgstatic char *xscale (int);
229863f95b1Smrgstatic char *yscale (int);
230863f95b1Smrgstatic char *bscale (int);
231863f95b1Smrgint main (int, char **);
232863f95b1Smrgstatic const char *LookupL (long, const binding *);
233863f95b1Smrgstatic const char *Lookup (int, const binding *);
234863f95b1Smrgstatic void Display_Window_Id (struct wininfo *, Bool);
235863f95b1Smrgstatic void Display_Stats_Info (struct wininfo *);
236863f95b1Smrgstatic void Display_Bits_Info (struct wininfo *);
237863f95b1Smrgstatic void Display_Event_Mask (long);
238863f95b1Smrgstatic void Display_Events_Info (struct wininfo *);
239863f95b1Smrgstatic void Display_Tree_Info (struct wininfo *, int);
240863f95b1Smrgstatic void display_tree_info_1 (struct wininfo *, int, int);
241863f95b1Smrgstatic void Display_Hints (xcb_size_hints_t *);
242863f95b1Smrgstatic void Display_Size_Hints (struct wininfo *);
243863f95b1Smrgstatic void Display_Window_Shape (xcb_window_t);
244863f95b1Smrgstatic void Display_WM_Info (struct wininfo *);
245863f95b1Smrgstatic void wininfo_wipe (struct wininfo *);
246863f95b1Smrg
247863f95b1Smrgstatic const char *window_id_format = "0x%lx";
248863f95b1Smrg
249863f95b1Smrg#ifdef HAVE_ICONV
250863f95b1Smrgstatic iconv_t iconv_from_utf8;
251863f95b1Smrg#endif
252863f95b1Smrgstatic const char *user_encoding;
253863f95b1Smrgstatic void print_utf8 (const char *, char *, size_t, const char *);
254863f95b1Smrgstatic void print_friendly_name (const char *, const char *, const char *);
255863f95b1Smrg
256863f95b1Smrgstatic xcb_connection_t *dpy;
257863f95b1Smrgstatic xcb_screen_t *screen;
258863f95b1Smrgstatic xcb_generic_error_t *err;
259ff7e0accSmrg
260ff7e0accSmrg#ifndef HAVE_STRLCAT
261863f95b1Smrgstatic size_t strlcat (char *dst, const char *src, size_t dstsize)
262ff7e0accSmrg{
263863f95b1Smrg    size_t sd = strlen (dst);
264863f95b1Smrg    size_t ss = strlen (src);
265ff7e0accSmrg    size_t s = sd + ss;
266863f95b1Smrg
267ff7e0accSmrg    if (s < dstsize) {
268863f95b1Smrg	strcpy (dst + sd, src);
269ff7e0accSmrg    } else {
270863f95b1Smrg	strncpy (dst + sd, src, dstsize-sd-1);
271ff7e0accSmrg	dst[dstsize] = '\0';
272ff7e0accSmrg    }
273ff7e0accSmrg    return s;
274ff7e0accSmrg}
275ff7e0accSmrg#endif
276ff7e0accSmrg
277ff7e0accSmrg/*
278ff7e0accSmrg * Report the syntax for calling xwininfo:
279ff7e0accSmrg */
280ff7e0accSmrgvoid
281863f95b1Smrgusage (void)
282ff7e0accSmrg{
283ff7e0accSmrg    fprintf (stderr,
284863f95b1Smrg	     "usage:  %s [-options ...]\n\n"
285863f95b1Smrg	     "where options include:\n"
286863f95b1Smrg	     "    -help                print this message\n"
287863f95b1Smrg	     "    -display host:dpy    X server to contact\n"
288863f95b1Smrg	     "    -root                use the root window\n"
289863f95b1Smrg	     "    -id windowid         use the window with the specified id\n"
290863f95b1Smrg	     "    -name windowname     use the window with the specified name\n"
291863f95b1Smrg	     "    -int                 print window id in decimal\n"
292863f95b1Smrg	     "    -children            print parent and child identifiers\n"
293863f95b1Smrg	     "    -tree                print children identifiers recursively\n"
294863f95b1Smrg	     "    -stats               print window geometry [DEFAULT]\n"
295863f95b1Smrg	     "    -bits                print window pixel information\n"
296863f95b1Smrg	     "    -events              print events selected for on window\n"
297863f95b1Smrg	     "    -size                print size hints\n"
298863f95b1Smrg	     "    -wm                  print window manager hints\n"
299863f95b1Smrg	     "    -shape               print shape extents\n"
300863f95b1Smrg	     "    -frame               don't ignore window manager frames\n"
301863f95b1Smrg	     "    -english             print sizes in english units\n"
302863f95b1Smrg	     "    -metric              print sizes in metric units\n"
303863f95b1Smrg	     "    -all                 -tree, -stats, -bits, -events, -wm, -size, -shape\n"
304863f95b1Smrg	     "\n",
305863f95b1Smrg	     program_name);
306ff7e0accSmrg    exit (1);
307ff7e0accSmrg}
308ff7e0accSmrg
309ff7e0accSmrg/*
310ff7e0accSmrg * pixel to inch, metric converter.
311ff7e0accSmrg * Hacked in by Mark W. Eichin <eichin@athena> [eichin:19880619.1509EST]
312ff7e0accSmrg *
313ff7e0accSmrg * Simply put: replace the old numbers with string print calls.
314ff7e0accSmrg * Returning a local string is ok, since we only ever get called to
315ff7e0accSmrg * print one x and one y, so as long as they don't collide, they're
316ff7e0accSmrg * fine. This is not meant to be a general purpose routine.
317ff7e0accSmrg *
318ff7e0accSmrg */
319ff7e0accSmrg
320863f95b1Smrgstatic int xp = 0, xmm = 0;
321863f95b1Smrgstatic int yp = 0, ymm = 0;
322863f95b1Smrgstatic int bp = 0, bmm = 0;
323ff7e0accSmrgstatic int english = 0, metric = 0;
324ff7e0accSmrg
325ff7e0accSmrgstatic void
326863f95b1Smrgscale_init (xcb_screen_t *screen)
327ff7e0accSmrg{
328863f95b1Smrg    xp = screen->width_in_pixels;
329863f95b1Smrg    yp = screen->height_in_pixels;
330863f95b1Smrg    xmm = screen->width_in_millimeters;
331863f95b1Smrg    ymm = screen->height_in_millimeters;
332863f95b1Smrg    bp  = xp  + yp;
333863f95b1Smrg    bmm = xmm + ymm;
334ff7e0accSmrg}
335ff7e0accSmrg
336ff7e0accSmrg#define MILE (5280*12)
337ff7e0accSmrg#define YARD (3*12)
338ff7e0accSmrg#define FOOT (12)
339ff7e0accSmrg
340ff7e0accSmrgstatic char *
341863f95b1Smrgnscale (int n, int np, int nmm, char *nbuf, size_t nbufsize)
342ff7e0accSmrg{
343ff7e0accSmrg    int s;
344863f95b1Smrg    snprintf (nbuf, nbufsize, "%d", n);
345863f95b1Smrg
346ff7e0accSmrg    if (metric||english) {
347863f95b1Smrg	s = strlcat (nbuf, " (", nbufsize);
348ff7e0accSmrg
349ff7e0accSmrg	if (metric) {
350863f95b1Smrg	    snprintf (nbuf+s, nbufsize-s, "%.2f mm%s",
351863f95b1Smrg		      ((double) n) * nmm/np , english ? "; " : "");
352ff7e0accSmrg	}
353ff7e0accSmrg	if (english) {
354ff7e0accSmrg	    double inch_frac;
355ff7e0accSmrg	    Bool printed_anything = False;
356ff7e0accSmrg	    int mi, yar, ft, inr;
357ff7e0accSmrg
358ff7e0accSmrg	    inch_frac = ((double) n)*(nmm/25.4)/np;
359ff7e0accSmrg	    inr = (int)inch_frac;
360ff7e0accSmrg	    inch_frac -= (double)inr;
361ff7e0accSmrg	    if (inr >= MILE) {
362ff7e0accSmrg		mi = inr/MILE;
363ff7e0accSmrg		inr %= MILE;
364863f95b1Smrg		s = strlen (nbuf);
365863f95b1Smrg		snprintf (nbuf+s, nbufsize-s, "%d %s(?!?)",
366863f95b1Smrg			  mi, (mi == 1) ? "mile" : "miles");
367ff7e0accSmrg		printed_anything = True;
368ff7e0accSmrg	    }
369ff7e0accSmrg	    if (inr >= YARD) {
370ff7e0accSmrg		yar = inr/YARD;
371ff7e0accSmrg		inr %= YARD;
372ff7e0accSmrg		if (printed_anything)
373863f95b1Smrg		    strlcat (nbuf, ", ", nbufsize);
374863f95b1Smrg		s = strlen (nbuf);
375863f95b1Smrg		snprintf (nbuf+s, nbufsize-s, "%d %s",
376863f95b1Smrg			 yar, (yar==1) ? "yard" : "yards");
377ff7e0accSmrg		printed_anything = True;
378ff7e0accSmrg	    }
379ff7e0accSmrg	    if (inr >= FOOT) {
380ff7e0accSmrg		ft = inr/FOOT;
381ff7e0accSmrg		inr  %= FOOT;
382ff7e0accSmrg		if (printed_anything)
383863f95b1Smrg		    strlcat (nbuf, ", ", nbufsize);
384863f95b1Smrg		s = strlen (nbuf);
385863f95b1Smrg		snprintf (nbuf+s, nbufsize-s, "%d %s",
386863f95b1Smrg			 ft, (ft==1) ? "foot" : "feet");
387ff7e0accSmrg		printed_anything = True;
388ff7e0accSmrg	    }
389ff7e0accSmrg	    if (!printed_anything || inch_frac != 0.0 || inr != 0) {
390ff7e0accSmrg		if (printed_anything)
391863f95b1Smrg		    strlcat (nbuf, ", ", nbufsize);
392863f95b1Smrg		s = strlen (nbuf);
393863f95b1Smrg		snprintf (nbuf+s, nbufsize-s, "%.2f inches", inr+inch_frac);
394ff7e0accSmrg	    }
395ff7e0accSmrg	}
396ff7e0accSmrg	strlcat (nbuf, ")", nbufsize);
397ff7e0accSmrg    }
398863f95b1Smrg    return (nbuf);
399863f95b1Smrg}
400863f95b1Smrg
401ff7e0accSmrgstatic char xbuf[BUFSIZ];
402ff7e0accSmrgstatic char *
403863f95b1Smrgxscale (int x)
404ff7e0accSmrg{
405863f95b1Smrg    return (nscale (x, xp, xmm, xbuf, sizeof(xbuf)));
406ff7e0accSmrg}
407ff7e0accSmrg
408ff7e0accSmrgstatic char ybuf[BUFSIZ];
409ff7e0accSmrgstatic char *
410863f95b1Smrgyscale (int y)
411ff7e0accSmrg{
412863f95b1Smrg    return (nscale (y, yp, ymm, ybuf, sizeof(ybuf)));
413ff7e0accSmrg}
414ff7e0accSmrg
415ff7e0accSmrgstatic char bbuf[BUFSIZ];
416ff7e0accSmrgstatic char *
417863f95b1Smrgbscale (int b)
418ff7e0accSmrg{
419863f95b1Smrg    return (nscale (b, bp, bmm, bbuf, sizeof(bbuf)));
420ff7e0accSmrg}
421ff7e0accSmrg
422ff7e0accSmrg/* end of pixel to inch, metric converter */
423ff7e0accSmrg
424863f95b1Smrgint
425863f95b1Smrgmain (int argc, char **argv)
426ff7e0accSmrg{
427863f95b1Smrg    register int i;
428863f95b1Smrg    int tree = 0, stats = 0, bits = 0, events = 0, wm = 0, size = 0, shape = 0;
429863f95b1Smrg    int frame = 0, children = 0;
430863f95b1Smrg    int use_root = 0;
431863f95b1Smrg    xcb_window_t window = 0;
432863f95b1Smrg    char *display_name = NULL;
433863f95b1Smrg    const char *window_name = NULL;
434863f95b1Smrg    struct wininfo wininfo;
435863f95b1Smrg    struct wininfo *w = &wininfo;
436863f95b1Smrg
437863f95b1Smrg    program_name = argv[0];
438863f95b1Smrg
439863f95b1Smrg    if (!setlocale (LC_ALL, ""))
440863f95b1Smrg	fprintf (stderr, "%s: can not set locale properly\n", program_name);
441863f95b1Smrg    user_encoding = nl_langinfo (CODESET);
442863f95b1Smrg    if (user_encoding == NULL)
443863f95b1Smrg	user_encoding = "unknown encoding";
444863f95b1Smrg
445863f95b1Smrg    memset (w, 0, sizeof(struct wininfo));
446863f95b1Smrg
447863f95b1Smrg    /* Handle our command line arguments */
448863f95b1Smrg    for (i = 1; i < argc; i++) {
449863f95b1Smrg	if (!strcmp (argv[i], "-help"))
450863f95b1Smrg	    usage ();
451863f95b1Smrg	if (!strcmp (argv[i], "-display") || !strcmp (argv[i], "-d")) {
452863f95b1Smrg	    if (++i >= argc)
453863f95b1Smrg		Fatal_Error("-display requires argument");
454863f95b1Smrg	    display_name = argv[i];
455863f95b1Smrg	    continue;
456863f95b1Smrg	}
457863f95b1Smrg	if (!strcmp (argv[i], "-root")) {
458863f95b1Smrg	    use_root = 1;
459863f95b1Smrg	    continue;
460863f95b1Smrg	}
461863f95b1Smrg	if (!strcmp (argv[i], "-id")) {
462863f95b1Smrg	    if (++i >= argc)
463863f95b1Smrg		Fatal_Error("-id requires argument");
464863f95b1Smrg	    window = strtoul(argv[i], NULL, 0);
465863f95b1Smrg	    continue;
466863f95b1Smrg	}
467863f95b1Smrg	if (!strcmp (argv[i], "-name")) {
468863f95b1Smrg	    if (++i >= argc)
469863f95b1Smrg		Fatal_Error("-name requires argument");
470863f95b1Smrg	    window_name = argv[i];
471863f95b1Smrg	    continue;
472863f95b1Smrg	}
473863f95b1Smrg	if (!strcmp (argv[i], "-int")) {
474863f95b1Smrg	    window_id_format = "%ld";
475863f95b1Smrg	    continue;
476863f95b1Smrg	}
477863f95b1Smrg	if (!strcmp (argv[i], "-children")) {
478863f95b1Smrg	    children = 1;
479863f95b1Smrg	    continue;
480863f95b1Smrg	}
481863f95b1Smrg	if (!strcmp (argv[i], "-tree")) {
482863f95b1Smrg	    tree = 1;
483863f95b1Smrg	    continue;
484863f95b1Smrg	}
485863f95b1Smrg	if (!strcmp (argv[i], "-stats")) {
486863f95b1Smrg	    stats = 1;
487863f95b1Smrg	    continue;
488863f95b1Smrg	}
489863f95b1Smrg	if (!strcmp (argv[i], "-bits")) {
490863f95b1Smrg	    bits = 1;
491863f95b1Smrg	    continue;
492863f95b1Smrg	}
493863f95b1Smrg	if (!strcmp (argv[i], "-events")) {
494863f95b1Smrg	    events = 1;
495863f95b1Smrg	    continue;
496863f95b1Smrg	}
497863f95b1Smrg	if (!strcmp (argv[i], "-wm")) {
498863f95b1Smrg	    wm = 1;
499863f95b1Smrg	    continue;
500863f95b1Smrg	}
501863f95b1Smrg	if (!strcmp (argv[i], "-frame")) {
502863f95b1Smrg	    frame = 1;
503863f95b1Smrg	    continue;
504863f95b1Smrg	}
505863f95b1Smrg	if (!strcmp (argv[i], "-size")) {
506863f95b1Smrg	    size = 1;
507863f95b1Smrg	    continue;
508863f95b1Smrg	}
509863f95b1Smrg	if (!strcmp (argv[i], "-shape")) {
510863f95b1Smrg	    shape = 1;
511863f95b1Smrg	    continue;
512863f95b1Smrg	}
513863f95b1Smrg	if (!strcmp (argv[i], "-english")) {
514863f95b1Smrg	    english = 1;
515863f95b1Smrg	    continue;
516863f95b1Smrg	}
517863f95b1Smrg	if (!strcmp (argv[i], "-metric")) {
518863f95b1Smrg	    metric = 1;
519863f95b1Smrg	    continue;
520863f95b1Smrg	}
521863f95b1Smrg	if (!strcmp (argv[i], "-all")) {
522863f95b1Smrg	    tree = stats = bits = events = wm = size = shape = 1;
523863f95b1Smrg	    continue;
524863f95b1Smrg	}
525863f95b1Smrg	usage ();
526863f95b1Smrg    }
527ff7e0accSmrg
528863f95b1Smrg    Setup_Display_And_Screen (display_name, &dpy, &screen);
529863f95b1Smrg
530863f95b1Smrg    /* preload atoms we may need later */
531863f95b1Smrg    Intern_Atom (dpy, "_NET_WM_NAME");
532863f95b1Smrg    Intern_Atom (dpy, "UTF8_STRING");
533863f95b1Smrg    if (wm) {
534863f95b1Smrg	Intern_Atom (dpy, "_NET_WM_DESKTOP");
535863f95b1Smrg	Intern_Atom (dpy, "_NET_WM_WINDOW_TYPE");
536863f95b1Smrg	Intern_Atom (dpy, "_NET_WM_STATE");
537863f95b1Smrg	Intern_Atom (dpy, "_NET_WM_PID");
538863f95b1Smrg	Intern_Atom (dpy, "_NET_FRAME_EXTENTS");
539863f95b1Smrg    }
540863f95b1Smrg    /* initialize scaling data */
541863f95b1Smrg    scale_init(screen);
542863f95b1Smrg
543863f95b1Smrg    if (use_root)
544863f95b1Smrg	window = screen->root;
545863f95b1Smrg    else if (window_name) {
546863f95b1Smrg	window = Window_With_Name (dpy, screen->root, window_name);
547863f95b1Smrg	if (!window)
548863f95b1Smrg	    Fatal_Error ("No window with name \"%s\" exists!", window_name);
549863f95b1Smrg    }
550ff7e0accSmrg
551863f95b1Smrg    /* If no window selected on command line, let user pick one the hard way */
552863f95b1Smrg    if (!window) {
553863f95b1Smrg	printf ("\n"
554863f95b1Smrg		"xwininfo: Please select the window about which you\n"
555863f95b1Smrg		"          would like information by clicking the\n"
556863f95b1Smrg		"          mouse in that window.\n");
557863f95b1Smrg	Intern_Atom (dpy, "_NET_VIRTUAL_ROOTS");
558863f95b1Smrg	Intern_Atom (dpy, "WM_STATE");
559863f95b1Smrg	window = Select_Window (dpy, screen, !frame);
560863f95b1Smrg    }
561ff7e0accSmrg
562863f95b1Smrg    /*
563863f95b1Smrg     * Do the actual displaying as per parameters
564863f95b1Smrg     */
565863f95b1Smrg    if (!(children || tree || bits || events || wm || size))
566863f95b1Smrg	stats = 1;
567ff7e0accSmrg
568863f95b1Smrg    /*
569863f95b1Smrg     * make sure that the window is valid
570863f95b1Smrg     */
571863f95b1Smrg    {
572863f95b1Smrg	xcb_get_geometry_cookie_t gg_cookie =
573863f95b1Smrg	    xcb_get_geometry (dpy, window);
574ff7e0accSmrg
575863f95b1Smrg	w->geometry = xcb_get_geometry_reply(dpy, gg_cookie, &err);
576ff7e0accSmrg
577863f95b1Smrg	if (!w->geometry) {
578863f95b1Smrg	    char badid[20];
579863f95b1Smrg
580863f95b1Smrg	    if (err)
581863f95b1Smrg		Print_X_Error (dpy, err);
582863f95b1Smrg
583863f95b1Smrg	    snprintf (badid, sizeof(badid), window_id_format, window);
584863f95b1Smrg	    Fatal_Error ("No such window with id %s.", badid);
585863f95b1Smrg	}
586ff7e0accSmrg    }
587863f95b1Smrg
588863f95b1Smrg    /* Send requests to prefetch data we'll need */
589863f95b1Smrg    w->window = window;
590863f95b1Smrg    w->net_wm_name_cookie = get_net_wm_name (dpy, window);
591863f95b1Smrg    w->wm_name_cookie = xcb_get_wm_name (dpy, window);
592863f95b1Smrg    if (children || tree)
593863f95b1Smrg	w->tree_cookie = xcb_query_tree (dpy, window);
594863f95b1Smrg    if (stats) {
595863f95b1Smrg	w->trans_coords_cookie =
596863f95b1Smrg	    xcb_translate_coordinates (dpy, window, w->geometry->root,
597863f95b1Smrg				       -(w->geometry->border_width),
598863f95b1Smrg				       -(w->geometry->border_width));
599ff7e0accSmrg    }
600863f95b1Smrg    if (stats || bits || events)
601863f95b1Smrg	w->attr_cookie = xcb_get_window_attributes (dpy, window);
602863f95b1Smrg    if (stats || size)
603863f95b1Smrg	w->normal_hints_cookie = xcb_get_wm_normal_hints (dpy, window);
604863f95b1Smrg    if (wm) {
605863f95b1Smrg	w->hints_cookie = xcb_get_wm_hints(dpy, window);
606863f95b1Smrg
607863f95b1Smrg	atom_net_wm_desktop = Get_Atom (dpy, "_NET_WM_DESKTOP");
608863f95b1Smrg	if (atom_net_wm_desktop) {
609863f95b1Smrg	    w->wm_desktop_cookie = xcb_get_property
610863f95b1Smrg		(dpy, False, window, atom_net_wm_desktop,
611863f95b1Smrg		 XCB_ATOM_CARDINAL, 0, 4);
612863f95b1Smrg	}
613863f95b1Smrg
614863f95b1Smrg	atom_net_wm_window_type	= Get_Atom (dpy, "_NET_WM_WINDOW_TYPE");
615863f95b1Smrg	if (atom_net_wm_window_type) {
616863f95b1Smrg	    w->wm_window_type_cookie = xcb_get_property
617863f95b1Smrg		(dpy, False, window, atom_net_wm_window_type,
618863f95b1Smrg		 XCB_ATOM_ATOM, 0, BUFSIZ);
619863f95b1Smrg	}
620863f95b1Smrg
621863f95b1Smrg	atom_net_wm_state = Get_Atom (dpy, "_NET_WM_STATE");
622863f95b1Smrg	if (atom_net_wm_state) {
623863f95b1Smrg	    w->wm_state_cookie = xcb_get_property
624863f95b1Smrg		(dpy, False, window, atom_net_wm_state,
625863f95b1Smrg		 XCB_ATOM_ATOM, 0, BUFSIZ);
626863f95b1Smrg	}
627863f95b1Smrg
628863f95b1Smrg	atom_net_wm_pid	= Get_Atom (dpy, "_NET_WM_PID");
629863f95b1Smrg	if (atom_net_wm_pid) {
630863f95b1Smrg	    w->wm_pid_cookie = xcb_get_property
631863f95b1Smrg		(dpy, False, window, atom_net_wm_pid,
632863f95b1Smrg		 XCB_ATOM_CARDINAL, 0, BUFSIZ);
633863f95b1Smrg	    w->wm_client_machine_cookie = xcb_get_property
634863f95b1Smrg		(dpy, False, window, XCB_ATOM_WM_CLIENT_MACHINE,
635863f95b1Smrg		 XCB_GET_PROPERTY_TYPE_ANY, 0, BUFSIZ);
636863f95b1Smrg	}
637863f95b1Smrg
638863f95b1Smrg	atom_net_frame_extents = Get_Atom (dpy, "_NET_FRAME_EXTENTS");
639863f95b1Smrg	if (atom_net_frame_extents) {
640863f95b1Smrg	    w->frame_extents_cookie = xcb_get_property
641863f95b1Smrg		(dpy, False, window, atom_net_frame_extents,
642863f95b1Smrg		 XCB_ATOM_CARDINAL, 0, 4 * 4);
643863f95b1Smrg	}
644ff7e0accSmrg    }
645863f95b1Smrg    if (size)
646863f95b1Smrg	w->zoom_cookie = xcb_get_wm_size_hints (dpy, window,
647863f95b1Smrg						XCB_ATOM_WM_ZOOM_HINTS);
648863f95b1Smrg    xcb_flush (dpy);
649863f95b1Smrg
650863f95b1Smrg    printf ("\nxwininfo: Window id: ");
651863f95b1Smrg    Display_Window_Id (w, True);
652863f95b1Smrg    if (children || tree)
653863f95b1Smrg	Display_Tree_Info (w, tree);
654863f95b1Smrg    if (stats)
655863f95b1Smrg	Display_Stats_Info (w);
656863f95b1Smrg    if (bits)
657863f95b1Smrg	Display_Bits_Info (w);
658863f95b1Smrg    if (events)
659863f95b1Smrg	Display_Events_Info (w);
660863f95b1Smrg    if (wm)
661863f95b1Smrg	Display_WM_Info (w);
662863f95b1Smrg    if (size)
663863f95b1Smrg	Display_Size_Hints (w);
664863f95b1Smrg    if (shape)
665863f95b1Smrg	Display_Window_Shape (window);
666863f95b1Smrg    printf ("\n");
667863f95b1Smrg
668863f95b1Smrg    wininfo_wipe (w);
669863f95b1Smrg    xcb_disconnect (dpy);
670863f95b1Smrg#ifdef HAVE_ICONV
671863f95b1Smrg    if (iconv_from_utf8 && (iconv_from_utf8 != (iconv_t) -1)) {
672863f95b1Smrg	iconv_close (iconv_from_utf8);
673ff7e0accSmrg    }
674863f95b1Smrg#endif
675863f95b1Smrg    exit (0);
676863f95b1Smrg}
677863f95b1Smrg
678863f95b1Smrg/* Ensure win_attributes field is filled in */
679863f95b1Smrgstatic xcb_get_window_attributes_reply_t *
680863f95b1Smrgfetch_win_attributes (struct wininfo *w)
681863f95b1Smrg{
682863f95b1Smrg    if (!w->win_attributes) {
683863f95b1Smrg	w->win_attributes =
684863f95b1Smrg	    xcb_get_window_attributes_reply (dpy, w->attr_cookie, &err);
685863f95b1Smrg
686863f95b1Smrg	if (!w->win_attributes) {
687863f95b1Smrg	    Print_X_Error (dpy, err);
688863f95b1Smrg	    Fatal_Error ("Can't get window attributes.");
689863f95b1Smrg	}
690ff7e0accSmrg    }
691863f95b1Smrg    return w->win_attributes;
692863f95b1Smrg}
693863f95b1Smrg
694863f95b1Smrg#ifndef USE_XCB_ICCCM
695863f95b1Smrgstatic Bool
696863f95b1Smrgwm_size_hints_reply (xcb_connection_t *dpy, xcb_get_property_cookie_t cookie,
697863f95b1Smrg		     wm_size_hints_t *hints_return, xcb_generic_error_t **err)
698863f95b1Smrg{
699863f95b1Smrg    xcb_get_property_reply_t *prop = xcb_get_property_reply (dpy, cookie, err);
700863f95b1Smrg    int length;
701863f95b1Smrg
702863f95b1Smrg    if (!prop || (prop->type != XCB_ATOM_WM_SIZE_HINTS) ||
703863f95b1Smrg	(prop->format != 32)) {
704863f95b1Smrg	free (prop);
705863f95b1Smrg	return False;
706ff7e0accSmrg    }
707863f95b1Smrg
708863f95b1Smrg    memset (hints_return, 0, sizeof(wm_size_hints_t));
709863f95b1Smrg
710863f95b1Smrg    length = xcb_get_property_value_length(prop);
711863f95b1Smrg    if (length > sizeof(wm_size_hints_t))
712863f95b1Smrg	length = sizeof(wm_size_hints_t);
713863f95b1Smrg    memcpy (hints_return, xcb_get_property_value (prop), length);
714863f95b1Smrg
715863f95b1Smrg    free (prop);
716863f95b1Smrg    return True;
717863f95b1Smrg}
718863f95b1Smrg
719863f95b1Smrg#define xcb_get_wm_normal_hints_reply wm_size_hints_reply
720863f95b1Smrg#define xcb_get_wm_size_hints_reply wm_size_hints_reply
721863f95b1Smrg#endif
722863f95b1Smrg
723863f95b1Smrg
724863f95b1Smrg
725863f95b1Smrg/* Ensure normal_hints field is filled in */
726863f95b1Smrgstatic xcb_size_hints_t *
727863f95b1Smrgfetch_normal_hints (struct wininfo *w, xcb_size_hints_t *hints_return)
728863f95b1Smrg{
729863f95b1Smrg    xcb_size_hints_t hints;
730863f95b1Smrg
731863f95b1Smrg    if (!w->normal_hints) {
732863f95b1Smrg	if (xcb_get_wm_normal_hints_reply (dpy, w->normal_hints_cookie,
733863f95b1Smrg					   &hints, NULL)) {
734863f95b1Smrg	    w->normal_hints = malloc (sizeof(xcb_size_hints_t));
735863f95b1Smrg	    if (w->normal_hints)
736863f95b1Smrg		memcpy(w->normal_hints, &hints, sizeof(xcb_size_hints_t));
737863f95b1Smrg	}
738ff7e0accSmrg    }
739863f95b1Smrg    if (hints_return && w->normal_hints)
740863f95b1Smrg	memcpy(hints_return, w->normal_hints, sizeof(xcb_size_hints_t));
741863f95b1Smrg    return w->normal_hints;
742ff7e0accSmrg}
743ff7e0accSmrg
744ff7e0accSmrg
745ff7e0accSmrg/*
746ff7e0accSmrg * Lookup: lookup a code in a table.
747ff7e0accSmrg */
748ff7e0accSmrgstatic char _lookup_buffer[100];
749ff7e0accSmrg
750ff7e0accSmrgstatic const char *
751863f95b1SmrgLookupL (long code, const binding *table)
752ff7e0accSmrg{
753863f95b1Smrg    const char *name = NULL;
754ff7e0accSmrg
755863f95b1Smrg    while (table->name) {
756863f95b1Smrg	if (table->code == code) {
757863f95b1Smrg	    name = table->name;
758863f95b1Smrg	    break;
759ff7e0accSmrg	}
760863f95b1Smrg	table++;
761863f95b1Smrg    }
762ff7e0accSmrg
763863f95b1Smrg    if (name == NULL) {
764863f95b1Smrg	snprintf (_lookup_buffer, sizeof(_lookup_buffer),
765863f95b1Smrg		  "unknown (code = %ld. = 0x%lx)", code, code);
766863f95b1Smrg	name = _lookup_buffer;
767863f95b1Smrg    }
768863f95b1Smrg
769863f95b1Smrg    return (name);
770ff7e0accSmrg}
771ff7e0accSmrg
772ff7e0accSmrgstatic const char *
773863f95b1SmrgLookup (int code, const binding *table)
774ff7e0accSmrg{
775863f95b1Smrg    return LookupL ((long)code, table);
776ff7e0accSmrg}
777ff7e0accSmrg
778ff7e0accSmrg/*
779ff7e0accSmrg * Routine to display a window id in dec/hex with name if window has one
780863f95b1Smrg *
781863f95b1Smrg * Requires wininfo members initialized: window, wm_name_cookie
782ff7e0accSmrg */
783ff7e0accSmrg
784ff7e0accSmrgstatic void
785863f95b1SmrgDisplay_Window_Id (struct wininfo *w, Bool newline_wanted)
786ff7e0accSmrg{
787863f95b1Smrg#ifdef USE_XCB_ICCCM
788863f95b1Smrg    xcb_get_text_property_reply_t wmn_reply;
789ff7e0accSmrg#endif
790863f95b1Smrg    xcb_get_property_reply_t *prop;
791863f95b1Smrg    uint8_t got_reply = False;
792863f95b1Smrg    const char *wm_name = NULL;
793863f95b1Smrg    unsigned int wm_name_len = 0;
794863f95b1Smrg    xcb_atom_t wm_name_encoding = XCB_NONE;
795ff7e0accSmrg
796863f95b1Smrg    printf (window_id_format, w->window);      /* print id # in hex/dec */
797863f95b1Smrg
798863f95b1Smrg    if (!w->window) {
799863f95b1Smrg	printf (" (none)");
800ff7e0accSmrg    } else {
801863f95b1Smrg	if (w->window == screen->root) {
802863f95b1Smrg	    printf (" (the root window)");
803ff7e0accSmrg	}
804863f95b1Smrg	/* Get window name if any */
805863f95b1Smrg	prop = xcb_get_property_reply (dpy, w->net_wm_name_cookie, NULL);
806863f95b1Smrg	if (prop && (prop->type != XCB_NONE)) {
807863f95b1Smrg	    wm_name = xcb_get_property_value (prop);
808863f95b1Smrg	    wm_name_len = xcb_get_property_value_length (prop);
809863f95b1Smrg	    wm_name_encoding = prop->type;
810863f95b1Smrg	    got_reply = True;
811ff7e0accSmrg	}
812863f95b1Smrg
813863f95b1Smrg	if (!got_reply) { /* No _NET_WM_NAME, check WM_NAME */
814863f95b1Smrg#ifdef USE_XCB_ICCCM
815863f95b1Smrg	    got_reply = xcb_get_wm_name_reply (dpy, w->wm_name_cookie,
816863f95b1Smrg					       &wmn_reply, NULL);
817863f95b1Smrg	    if (got_reply) {
818863f95b1Smrg		wm_name = wmn_reply.name;
819863f95b1Smrg		wm_name_len = wmn_reply.name_len;
820863f95b1Smrg		wm_name_encoding = wmn_reply.encoding;
821863f95b1Smrg	    }
822ff7e0accSmrg#else
823863f95b1Smrg	    prop = xcb_get_property_reply (dpy, w->wm_name_cookie, NULL);
824863f95b1Smrg	    if (prop && (prop->type != XCB_NONE)) {
825863f95b1Smrg		wm_name = xcb_get_property_value (prop);
826863f95b1Smrg		wm_name_len = xcb_get_property_value_length (prop);
827863f95b1Smrg		wm_name_encoding = prop->type;
828863f95b1Smrg		got_reply = True;
829863f95b1Smrg	    }
830863f95b1Smrg#endif
831ff7e0accSmrg	}
832863f95b1Smrg	if (!got_reply || wm_name_len == 0) {
833863f95b1Smrg	    printf (" (has no name)");
834863f95b1Smrg        } else {
835863f95b1Smrg	    if (wm_name_encoding == XCB_ATOM_STRING) {
836863f95b1Smrg		printf (" \"%.*s\"", wm_name_len, wm_name);
837863f95b1Smrg	    } else if (wm_name_encoding == atom_utf8_string) {
838863f95b1Smrg		print_utf8 (" \"", (char *) wm_name, wm_name_len,  "\"");
839863f95b1Smrg	    } else {
840863f95b1Smrg		/* Encodings we don't support, including COMPOUND_TEXT */
841863f95b1Smrg		const char *enc_name = Get_Atom_Name (dpy, wm_name_encoding);
842863f95b1Smrg		if (enc_name) {
843863f95b1Smrg		    printf (" (name in unsupported encoding %s)", enc_name);
844863f95b1Smrg		} else {
845863f95b1Smrg		    printf (" (name in unsupported encoding ATOM 0x%x)",
846863f95b1Smrg			    wm_name_encoding);
847863f95b1Smrg		}
848863f95b1Smrg	    }
849863f95b1Smrg	}
850863f95b1Smrg#ifdef USE_XCB_ICCCM
851863f95b1Smrg	if (got_reply)
852863f95b1Smrg	    xcb_get_text_property_reply_wipe (&wmn_reply);
853863f95b1Smrg#else
854863f95b1Smrg	free (prop);
855ff7e0accSmrg#endif
856ff7e0accSmrg    }
857ff7e0accSmrg
858ff7e0accSmrg    if (newline_wanted)
859863f95b1Smrg	printf ("\n");
860ff7e0accSmrg
861ff7e0accSmrg    return;
862ff7e0accSmrg}
863ff7e0accSmrg
864ff7e0accSmrg
865ff7e0accSmrg/*
866ff7e0accSmrg * Display Stats on window
867ff7e0accSmrg */
868ff7e0accSmrgstatic const binding _window_classes[] = {
869863f95b1Smrg	{ XCB_WINDOW_CLASS_INPUT_OUTPUT, "InputOutput" },
870863f95b1Smrg	{ XCB_WINDOW_CLASS_INPUT_ONLY, "InputOnly" },
87110998002Smrg        { 0, NULL } };
872ff7e0accSmrg
873ff7e0accSmrgstatic const binding _map_states[] = {
874863f95b1Smrg	{ XCB_MAP_STATE_UNMAPPED,	"IsUnMapped" },
875863f95b1Smrg	{ XCB_MAP_STATE_UNVIEWABLE,	"IsUnviewable" },
876863f95b1Smrg	{ XCB_MAP_STATE_VIEWABLE,	"IsViewable" },
87710998002Smrg	{ 0, NULL } };
878ff7e0accSmrg
879ff7e0accSmrgstatic const binding _backing_store_states[] = {
880863f95b1Smrg	{ XCB_BACKING_STORE_NOT_USEFUL, "NotUseful" },
881863f95b1Smrg	{ XCB_BACKING_STORE_WHEN_MAPPED,"WhenMapped" },
882863f95b1Smrg	{ XCB_BACKING_STORE_ALWAYS,	"Always" },
88310998002Smrg	{ 0, NULL } };
884ff7e0accSmrg
885ff7e0accSmrgstatic const binding _bit_gravity_states[] = {
886863f95b1Smrg	{ XCB_GRAVITY_BIT_FORGET,	"ForgetGravity" },
887863f95b1Smrg	{ XCB_GRAVITY_NORTH_WEST,	"NorthWestGravity" },
888863f95b1Smrg	{ XCB_GRAVITY_NORTH,		"NorthGravity" },
889863f95b1Smrg	{ XCB_GRAVITY_NORTH_EAST,	"NorthEastGravity" },
890863f95b1Smrg	{ XCB_GRAVITY_WEST,		"WestGravity" },
891863f95b1Smrg	{ XCB_GRAVITY_CENTER,		"CenterGravity" },
892863f95b1Smrg	{ XCB_GRAVITY_EAST,		"EastGravity" },
893863f95b1Smrg	{ XCB_GRAVITY_SOUTH_WEST,	"SouthWestGravity" },
894863f95b1Smrg	{ XCB_GRAVITY_SOUTH,		"SouthGravity" },
895863f95b1Smrg	{ XCB_GRAVITY_SOUTH_EAST,	"SouthEastGravity" },
896863f95b1Smrg	{ XCB_GRAVITY_STATIC,		"StaticGravity" },
89710998002Smrg	{ 0, NULL }};
898ff7e0accSmrg
899ff7e0accSmrgstatic const binding _window_gravity_states[] = {
900863f95b1Smrg	{ XCB_GRAVITY_WIN_UNMAP,	"UnmapGravity" },
901863f95b1Smrg	{ XCB_GRAVITY_NORTH_WEST,	"NorthWestGravity" },
902863f95b1Smrg	{ XCB_GRAVITY_NORTH,		"NorthGravity" },
903863f95b1Smrg	{ XCB_GRAVITY_NORTH_EAST,	"NorthEastGravity" },
904863f95b1Smrg	{ XCB_GRAVITY_WEST,		"WestGravity" },
905863f95b1Smrg	{ XCB_GRAVITY_CENTER,		"CenterGravity" },
906863f95b1Smrg	{ XCB_GRAVITY_EAST,		"EastGravity" },
907863f95b1Smrg	{ XCB_GRAVITY_SOUTH_WEST,	"SouthWestGravity" },
908863f95b1Smrg	{ XCB_GRAVITY_SOUTH,		"SouthGravity" },
909863f95b1Smrg	{ XCB_GRAVITY_SOUTH_EAST,	"SouthEastGravity" },
910863f95b1Smrg	{ XCB_GRAVITY_STATIC,		"StaticGravity" },
91110998002Smrg	{ 0, NULL }};
912ff7e0accSmrg
913ff7e0accSmrgstatic const binding _visual_classes[] = {
914863f95b1Smrg	{ XCB_VISUAL_CLASS_STATIC_GRAY,	"StaticGray" },
915863f95b1Smrg	{ XCB_VISUAL_CLASS_GRAY_SCALE,	"GrayScale" },
916863f95b1Smrg	{ XCB_VISUAL_CLASS_STATIC_COLOR,"StaticColor" },
917863f95b1Smrg	{ XCB_VISUAL_CLASS_PSEUDO_COLOR,"PseudoColor" },
918863f95b1Smrg	{ XCB_VISUAL_CLASS_TRUE_COLOR,	"TrueColor" },
919863f95b1Smrg	{ XCB_VISUAL_CLASS_DIRECT_COLOR,"DirectColor" },
92010998002Smrg	{ 0, NULL }};
921ff7e0accSmrg
922863f95b1Smrg/*
923863f95b1Smrg * Requires wininfo members initialized:
924863f95b1Smrg *   window, geometry, attr_cookie, trans_coords_cookie, normal_hints_cookie
925863f95b1Smrg */
926ff7e0accSmrgstatic void
927863f95b1SmrgDisplay_Stats_Info (struct wininfo *w)
928ff7e0accSmrg{
929863f95b1Smrg    xcb_translate_coordinates_reply_t *trans_coords;
930863f95b1Smrg    xcb_get_window_attributes_reply_t *win_attributes;
931863f95b1Smrg    xcb_size_hints_t hints;
932863f95b1Smrg
933863f95b1Smrg    int dw = screen->width_in_pixels, dh = screen->height_in_pixels;
934863f95b1Smrg    int rx, ry, xright, ybelow;
935863f95b1Smrg    int showright = 0, showbelow = 0;
936863f95b1Smrg    xcb_window_t wmframe, parent;
937863f95b1Smrg
938863f95b1Smrg    trans_coords =
939863f95b1Smrg	xcb_translate_coordinates_reply (dpy, w->trans_coords_cookie, NULL);
940863f95b1Smrg    if (!trans_coords)
941863f95b1Smrg	Fatal_Error ("Can't get translated coordinates.");
942863f95b1Smrg
943863f95b1Smrg    rx = (int16_t)trans_coords->dst_x;
944863f95b1Smrg    ry = (int16_t)trans_coords->dst_y;
945863f95b1Smrg    free (trans_coords);
946863f95b1Smrg
947863f95b1Smrg    xright = (dw - rx - w->geometry->border_width * 2 -
948863f95b1Smrg	      w->geometry->width);
949863f95b1Smrg    ybelow = (dh - ry - w->geometry->border_width * 2 -
950863f95b1Smrg	      w->geometry->height);
951863f95b1Smrg
952863f95b1Smrg
953863f95b1Smrg    printf ("\n");
954863f95b1Smrg    printf ("  Absolute upper-left X:  %s\n", xscale (rx));
955863f95b1Smrg    printf ("  Absolute upper-left Y:  %s\n", yscale (ry));
956863f95b1Smrg    printf ("  Relative upper-left X:  %s\n", xscale (w->geometry->x));
957863f95b1Smrg    printf ("  Relative upper-left Y:  %s\n", yscale (w->geometry->y));
958863f95b1Smrg    printf ("  Width: %s\n", xscale (w->geometry->width));
959863f95b1Smrg    printf ("  Height: %s\n", yscale (w->geometry->height));
960863f95b1Smrg    printf ("  Depth: %d\n", w->geometry->depth);
961863f95b1Smrg
962863f95b1Smrg    win_attributes = fetch_win_attributes (w);
963863f95b1Smrg
964863f95b1Smrg    printf ("  Visual: 0x%lx\n", (unsigned long) win_attributes->visual);
965863f95b1Smrg    if (screen)
966863f95b1Smrg    {
967863f95b1Smrg	xcb_depth_iterator_t depth_iter;
968863f95b1Smrg	xcb_visualtype_t  *visual_type = NULL;
969863f95b1Smrg
970863f95b1Smrg	depth_iter = xcb_screen_allowed_depths_iterator (screen);
971863f95b1Smrg	for (; depth_iter.rem; xcb_depth_next (&depth_iter)) {
972863f95b1Smrg	    xcb_visualtype_iterator_t visual_iter;
973863f95b1Smrg
974863f95b1Smrg	    visual_iter = xcb_depth_visuals_iterator (depth_iter.data);
975863f95b1Smrg	    for (; visual_iter.rem; xcb_visualtype_next (&visual_iter)) {
976863f95b1Smrg		if (screen->root_visual == visual_iter.data->visual_id) {
977863f95b1Smrg		    visual_type = visual_iter.data;
978863f95b1Smrg		    break;
979863f95b1Smrg		}
980863f95b1Smrg	    }
981863f95b1Smrg	}
982863f95b1Smrg	if (visual_type)
983863f95b1Smrg	    printf ("  Visual Class: %s\n", Lookup (visual_type->_class,
984863f95b1Smrg						    _visual_classes));
985863f95b1Smrg    }
986863f95b1Smrg
987863f95b1Smrg    printf ("  Border width: %s\n", bscale (w->geometry->border_width));
988863f95b1Smrg    printf ("  Class: %s\n",
989863f95b1Smrg	    Lookup (win_attributes->_class, _window_classes));
990863f95b1Smrg    printf ("  Colormap: 0x%lx (%sinstalled)\n",
991863f95b1Smrg	    (unsigned long) win_attributes->colormap,
992863f95b1Smrg	    win_attributes->map_is_installed ? "" : "not ");
993863f95b1Smrg    printf ("  Bit Gravity State: %s\n",
994863f95b1Smrg	    Lookup (win_attributes->bit_gravity, _bit_gravity_states));
995863f95b1Smrg    printf ("  Window Gravity State: %s\n",
996863f95b1Smrg	    Lookup (win_attributes->win_gravity, _window_gravity_states));
997863f95b1Smrg    printf ("  Backing Store State: %s\n",
998863f95b1Smrg	    Lookup (win_attributes->backing_store, _backing_store_states));
999863f95b1Smrg    printf ("  Save Under State: %s\n",
1000863f95b1Smrg	    win_attributes->save_under ? "yes" : "no");
1001863f95b1Smrg    printf ("  Map State: %s\n",
1002863f95b1Smrg	    Lookup (win_attributes->map_state, _map_states));
1003863f95b1Smrg    printf ("  Override Redirect State: %s\n",
1004863f95b1Smrg	    win_attributes->override_redirect ? "yes" : "no");
1005863f95b1Smrg    printf ("  Corners:  +%d+%d  -%d+%d  -%d-%d  +%d-%d\n",
1006863f95b1Smrg	    rx, ry, xright, ry, xright, ybelow, rx, ybelow);
1007863f95b1Smrg
1008863f95b1Smrg    /*
1009863f95b1Smrg     * compute geometry string that would recreate window
1010863f95b1Smrg     */
1011863f95b1Smrg    printf ("  -geometry ");
1012863f95b1Smrg
1013863f95b1Smrg    /* compute size in appropriate units */
1014863f95b1Smrg    if (!fetch_normal_hints (w, &hints))
1015863f95b1Smrg	hints.flags = 0;
1016863f95b1Smrg
1017863f95b1Smrg    if ((hints.flags & XCB_SIZE_HINT_P_RESIZE_INC)  &&
1018863f95b1Smrg	(hints.width_inc != 0)  && (hints.height_inc != 0)) {
1019863f95b1Smrg	if (hints.flags & (XCB_SIZE_HINT_BASE_SIZE|XCB_SIZE_HINT_P_MIN_SIZE)) {
1020863f95b1Smrg	    if (hints.flags & XCB_SIZE_HINT_BASE_SIZE) {
1021863f95b1Smrg		w->geometry->width -= hints.base_width;
1022863f95b1Smrg		w->geometry->height -= hints.base_height;
1023863f95b1Smrg	    } else {
1024863f95b1Smrg		/* ICCCM says MinSize is default for BaseSize */
1025863f95b1Smrg		w->geometry->width -= hints.min_width;
1026863f95b1Smrg		w->geometry->height -= hints.min_height;
1027863f95b1Smrg	    }
1028863f95b1Smrg	}
1029863f95b1Smrg	printf ("%dx%d", w->geometry->width/hints.width_inc,
1030863f95b1Smrg		w->geometry->height/hints.height_inc);
1031863f95b1Smrg    } else
1032863f95b1Smrg	printf ("%dx%d", w->geometry->width, w->geometry->height);
1033863f95b1Smrg
1034863f95b1Smrg    if (!(hints.flags & XCB_SIZE_HINT_P_WIN_GRAVITY))
1035863f95b1Smrg	hints.win_gravity = XCB_GRAVITY_NORTH_WEST; /* per ICCCM */
1036863f95b1Smrg    /* find our window manager frame, if any */
1037863f95b1Smrg    for (wmframe = parent = w->window; parent != 0 ; wmframe = parent) {
1038863f95b1Smrg	xcb_query_tree_cookie_t qt_cookie;
1039863f95b1Smrg	xcb_query_tree_reply_t *tree;
1040863f95b1Smrg
1041863f95b1Smrg	qt_cookie = xcb_query_tree (dpy, wmframe);
1042863f95b1Smrg	tree = xcb_query_tree_reply (dpy, qt_cookie, &err);
1043863f95b1Smrg	if (!tree) {
1044863f95b1Smrg	    Print_X_Error (dpy, err);
1045863f95b1Smrg	    Fatal_Error ("Can't query window tree.");
1046863f95b1Smrg	}
1047863f95b1Smrg	parent = tree->parent;
1048863f95b1Smrg	free (tree);
1049863f95b1Smrg	if (parent == w->geometry->root || !parent)
1050863f95b1Smrg	    break;
1051863f95b1Smrg    }
1052863f95b1Smrg    if (wmframe != w->window) {
1053863f95b1Smrg	/* WM reparented, so find edges of the frame */
1054863f95b1Smrg	/* Only works for ICCCM-compliant WMs, and then only if the
1055863f95b1Smrg	   window has corner gravity.  We would need to know the original width
1056863f95b1Smrg	   of the window to correctly handle the other gravities. */
1057863f95b1Smrg	xcb_get_geometry_cookie_t geom_cookie;
1058863f95b1Smrg	xcb_get_geometry_reply_t *frame_geometry;
1059863f95b1Smrg
1060863f95b1Smrg	geom_cookie = xcb_get_geometry (dpy, wmframe);
1061863f95b1Smrg	frame_geometry = xcb_get_geometry_reply (dpy, geom_cookie, &err);
1062863f95b1Smrg
1063863f95b1Smrg	if (!frame_geometry) {
1064863f95b1Smrg	    Print_X_Error (dpy, err);
1065863f95b1Smrg	    Fatal_Error ("Can't get frame geometry.");
1066863f95b1Smrg	}
1067863f95b1Smrg	switch (hints.win_gravity) {
1068863f95b1Smrg	    case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST:
1069863f95b1Smrg	    case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST:
1070863f95b1Smrg	    case XCB_GRAVITY_WEST:
1071863f95b1Smrg		rx = frame_geometry->x;
1072863f95b1Smrg	}
1073863f95b1Smrg	switch (hints.win_gravity) {
1074863f95b1Smrg	    case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST:
1075863f95b1Smrg	    case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST:
1076863f95b1Smrg	    case XCB_GRAVITY_EAST:
1077863f95b1Smrg		xright = dw - frame_geometry->x - frame_geometry->width -
1078863f95b1Smrg		    (2 * frame_geometry->border_width);
1079863f95b1Smrg	}
1080863f95b1Smrg	switch (hints.win_gravity) {
1081863f95b1Smrg	    case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST:
1082863f95b1Smrg	    case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST:
1083863f95b1Smrg	    case XCB_GRAVITY_NORTH:
1084863f95b1Smrg		ry = frame_geometry->y;
1085863f95b1Smrg	}
1086863f95b1Smrg	switch (hints.win_gravity) {
1087863f95b1Smrg	    case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST:
1088863f95b1Smrg	    case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST:
1089863f95b1Smrg	    case XCB_GRAVITY_SOUTH:
1090863f95b1Smrg		ybelow = dh - frame_geometry->y - frame_geometry->height -
1091863f95b1Smrg		    (2 * frame_geometry->border_width);
1092863f95b1Smrg	}
1093863f95b1Smrg	free (frame_geometry);
1094863f95b1Smrg    }
1095863f95b1Smrg    /* If edge gravity, offer a corner on that edge (because the application
1096863f95b1Smrg       programmer cares about that edge), otherwise offer upper left unless
1097863f95b1Smrg       some other corner is close to an edge of the screen.
1098863f95b1Smrg       (For corner gravity, assume gravity was set by XWMGeometry.
1099863f95b1Smrg       For CenterGravity, it doesn't matter.) */
1100863f95b1Smrg    if (hints.win_gravity == XCB_GRAVITY_EAST  ||
1101863f95b1Smrg	(abs (xright) <= 100  &&  abs (xright) < abs (rx)
1102863f95b1Smrg	 &&  hints.win_gravity != XCB_GRAVITY_WEST))
1103863f95b1Smrg	showright = 1;
1104863f95b1Smrg    if (hints.win_gravity == XCB_GRAVITY_SOUTH  ||
1105863f95b1Smrg	(abs (ybelow) <= 100  &&  abs (ybelow) < abs (ry)
1106863f95b1Smrg	 &&  hints.win_gravity != XCB_GRAVITY_NORTH))
1107863f95b1Smrg	showbelow = 1;
1108863f95b1Smrg
1109863f95b1Smrg    if (showright)
1110863f95b1Smrg	printf ("-%d", xright);
1111863f95b1Smrg    else
1112863f95b1Smrg	printf ("+%d", rx);
1113863f95b1Smrg    if (showbelow)
1114863f95b1Smrg	printf ("-%d", ybelow);
1115863f95b1Smrg    else
1116863f95b1Smrg	printf ("+%d", ry);
1117863f95b1Smrg    printf ("\n");
1118ff7e0accSmrg}
1119ff7e0accSmrg
1120ff7e0accSmrg
1121ff7e0accSmrg/*
1122ff7e0accSmrg * Display bits info:
1123ff7e0accSmrg */
1124ff7e0accSmrgstatic const binding _gravities[] = {
1125863f95b1Smrg    /* WARNING: the first two of these have the same value - see code */
1126863f95b1Smrg	{ XCB_GRAVITY_WIN_UNMAP,	"UnMapGravity" },
1127863f95b1Smrg	{ XCB_GRAVITY_BIT_FORGET,	"ForgetGravity" },
1128863f95b1Smrg	{ XCB_GRAVITY_NORTH_WEST,	"NorthWestGravity" },
1129863f95b1Smrg	{ XCB_GRAVITY_NORTH,		"NorthGravity" },
1130863f95b1Smrg	{ XCB_GRAVITY_NORTH_EAST,	"NorthEastGravity" },
1131863f95b1Smrg	{ XCB_GRAVITY_WEST,		"WestGravity" },
1132863f95b1Smrg	{ XCB_GRAVITY_CENTER,		"CenterGravity" },
1133863f95b1Smrg	{ XCB_GRAVITY_EAST,		"EastGravity" },
1134863f95b1Smrg	{ XCB_GRAVITY_SOUTH_WEST,	"SouthWestGravity" },
1135863f95b1Smrg	{ XCB_GRAVITY_SOUTH,		"SouthGravity" },
1136863f95b1Smrg	{ XCB_GRAVITY_SOUTH_EAST,	"SouthEastGravity" },
1137863f95b1Smrg	{ XCB_GRAVITY_STATIC,		"StaticGravity" },
113810998002Smrg	{ 0, NULL } };
1139ff7e0accSmrg
1140ff7e0accSmrgstatic const binding _backing_store_hint[] = {
1141863f95b1Smrg	{ XCB_BACKING_STORE_NOT_USEFUL, "NotUseful" },
1142863f95b1Smrg	{ XCB_BACKING_STORE_WHEN_MAPPED,"WhenMapped" },
1143863f95b1Smrg	{ XCB_BACKING_STORE_ALWAYS,	"Always" },
114410998002Smrg	{ 0, NULL } };
1145ff7e0accSmrg
1146ff7e0accSmrgstatic const binding _bool[] = {
1147ff7e0accSmrg	{ 0, "No" },
1148ff7e0accSmrg	{ 1, "Yes" },
114910998002Smrg	{ 0, NULL } };
1150ff7e0accSmrg
1151863f95b1Smrg/*
1152863f95b1Smrg * Requires wininfo members initialized:
1153863f95b1Smrg *   window, attr_cookie (or win_attributes)
1154863f95b1Smrg */
1155ff7e0accSmrgstatic void
1156863f95b1SmrgDisplay_Bits_Info (struct wininfo * w)
1157ff7e0accSmrg{
1158863f95b1Smrg    xcb_get_window_attributes_reply_t *win_attributes
1159863f95b1Smrg	= fetch_win_attributes (w);
1160863f95b1Smrg
1161863f95b1Smrg    printf ("\n");
1162863f95b1Smrg    printf ("  Bit gravity: %s\n",
1163863f95b1Smrg	    Lookup (win_attributes->bit_gravity, _gravities+1));
1164863f95b1Smrg    printf ("  Window gravity: %s\n",
1165863f95b1Smrg	    Lookup (win_attributes->win_gravity, _gravities));
1166863f95b1Smrg    printf ("  Backing-store hint: %s\n",
1167863f95b1Smrg	    Lookup (win_attributes->backing_store, _backing_store_hint));
1168863f95b1Smrg    printf ("  Backing-planes to be preserved: 0x%lx\n",
1169863f95b1Smrg	    (unsigned long) win_attributes->backing_planes);
1170863f95b1Smrg    printf ("  Backing pixel: %ld\n",
1171863f95b1Smrg	    (unsigned long) win_attributes->backing_pixel);
1172863f95b1Smrg    printf ("  Save-unders: %s\n",
1173863f95b1Smrg	    Lookup (win_attributes->save_under, _bool));
1174ff7e0accSmrg}
1175ff7e0accSmrg
1176ff7e0accSmrg
1177ff7e0accSmrg/*
1178ff7e0accSmrg * Routine to display all events in an event mask
1179ff7e0accSmrg */
1180ff7e0accSmrgstatic const binding _event_mask_names[] = {
1181863f95b1Smrg	{ XCB_EVENT_MASK_KEY_PRESS,		"KeyPress" },
1182863f95b1Smrg	{ XCB_EVENT_MASK_KEY_RELEASE,		"KeyRelease" },
1183863f95b1Smrg	{ XCB_EVENT_MASK_BUTTON_PRESS,		"ButtonPress" },
1184863f95b1Smrg	{ XCB_EVENT_MASK_BUTTON_RELEASE,	"ButtonRelease" },
1185863f95b1Smrg	{ XCB_EVENT_MASK_ENTER_WINDOW,		"EnterWindow" },
1186863f95b1Smrg	{ XCB_EVENT_MASK_LEAVE_WINDOW,		"LeaveWindow" },
1187863f95b1Smrg	{ XCB_EVENT_MASK_POINTER_MOTION,	"PointerMotion" },
1188863f95b1Smrg	{ XCB_EVENT_MASK_POINTER_MOTION_HINT,	"PointerMotionHint" },
1189863f95b1Smrg	{ XCB_EVENT_MASK_BUTTON_1_MOTION,	"Button1Motion" },
1190863f95b1Smrg	{ XCB_EVENT_MASK_BUTTON_2_MOTION,	"Button2Motion" },
1191863f95b1Smrg	{ XCB_EVENT_MASK_BUTTON_3_MOTION,	"Button3Motion" },
1192863f95b1Smrg	{ XCB_EVENT_MASK_BUTTON_4_MOTION,	"Button4Motion" },
1193863f95b1Smrg	{ XCB_EVENT_MASK_BUTTON_5_MOTION,	"Button5Motion" },
1194863f95b1Smrg	{ XCB_EVENT_MASK_BUTTON_MOTION,		"ButtonMotion" },
1195863f95b1Smrg	{ XCB_EVENT_MASK_KEYMAP_STATE,		"KeymapState" },
1196863f95b1Smrg	{ XCB_EVENT_MASK_EXPOSURE,		"Exposure" },
1197863f95b1Smrg	{ XCB_EVENT_MASK_VISIBILITY_CHANGE,	"VisibilityChange" },
1198863f95b1Smrg	{ XCB_EVENT_MASK_STRUCTURE_NOTIFY,	"StructureNotify" },
1199863f95b1Smrg	{ XCB_EVENT_MASK_RESIZE_REDIRECT,	"ResizeRedirect" },
1200863f95b1Smrg	{ XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,	"SubstructureNotify" },
1201863f95b1Smrg	{ XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,	"SubstructureRedirect" },
1202863f95b1Smrg	{ XCB_EVENT_MASK_FOCUS_CHANGE,		"FocusChange" },
1203863f95b1Smrg	{ XCB_EVENT_MASK_PROPERTY_CHANGE,	"PropertyChange" },
1204863f95b1Smrg	{ XCB_EVENT_MASK_COLOR_MAP_CHANGE,	"ColormapChange" },
1205863f95b1Smrg	{ XCB_EVENT_MASK_OWNER_GRAB_BUTTON,	"OwnerGrabButton" },
120610998002Smrg	{ 0, NULL } };
1207ff7e0accSmrg
1208ff7e0accSmrgstatic void
1209863f95b1SmrgDisplay_Event_Mask (long mask)
1210ff7e0accSmrg{
1211863f95b1Smrg    long bit, bit_mask;
1212ff7e0accSmrg
1213863f95b1Smrg    for (bit=0, bit_mask=1; bit < sizeof(long)*8; bit++, bit_mask <<= 1)
1214863f95b1Smrg	if (mask & bit_mask)
1215863f95b1Smrg	    printf ("      %s\n",
1216863f95b1Smrg		    LookupL (bit_mask, _event_mask_names));
1217ff7e0accSmrg}
1218ff7e0accSmrg
1219ff7e0accSmrg
1220ff7e0accSmrg/*
1221ff7e0accSmrg * Display info on events
1222863f95b1Smrg *
1223863f95b1Smrg * Requires wininfo members initialized:
1224863f95b1Smrg *   window, attr_cookie (or win_attributes)
1225ff7e0accSmrg */
1226ff7e0accSmrgstatic void
1227863f95b1SmrgDisplay_Events_Info (struct wininfo *w)
1228ff7e0accSmrg{
1229863f95b1Smrg    xcb_get_window_attributes_reply_t *win_attributes
1230863f95b1Smrg	= fetch_win_attributes (w);
1231ff7e0accSmrg
1232863f95b1Smrg    printf ("\n");
1233863f95b1Smrg    printf ("  Someone wants these events:\n");
1234863f95b1Smrg    Display_Event_Mask (win_attributes->all_event_masks);
1235ff7e0accSmrg
1236863f95b1Smrg    printf ("  Do not propagate these events:\n");
1237863f95b1Smrg    Display_Event_Mask (win_attributes->do_not_propagate_mask);
1238ff7e0accSmrg
1239863f95b1Smrg    printf ("  Override redirection?: %s\n",
1240863f95b1Smrg	    Lookup (win_attributes->override_redirect, _bool));
1241ff7e0accSmrg}
1242ff7e0accSmrg
1243ff7e0accSmrg
1244ff7e0accSmrg  /* left out visual stuff */
1245ff7e0accSmrg  /* left out colormap */
1246ff7e0accSmrg  /* left out map_installed */
1247ff7e0accSmrg
1248ff7e0accSmrg
1249ff7e0accSmrg/*
1250ff7e0accSmrg * Display root, parent, and (recursively) children information
1251ff7e0accSmrg * recurse - true to show children information
1252863f95b1Smrg *
1253863f95b1Smrg * Requires wininfo members initialized: window, tree_cookie
1254ff7e0accSmrg */
1255ff7e0accSmrgstatic void
1256863f95b1SmrgDisplay_Tree_Info (struct wininfo *w, int recurse)
1257ff7e0accSmrg{
1258863f95b1Smrg    display_tree_info_1 (w, recurse, 0);
1259ff7e0accSmrg}
1260ff7e0accSmrg
1261ff7e0accSmrg/*
1262ff7e0accSmrg * level - recursion level
1263ff7e0accSmrg */
1264ff7e0accSmrgstatic void
1265863f95b1Smrgdisplay_tree_info_1 (struct wininfo *w, int recurse, int level)
1266ff7e0accSmrg{
1267863f95b1Smrg    int i, j;
1268863f95b1Smrg    unsigned int num_children;
1269863f95b1Smrg    xcb_query_tree_reply_t *tree;
1270863f95b1Smrg
1271863f95b1Smrg    tree = xcb_query_tree_reply (dpy, w->tree_cookie, &err);
1272863f95b1Smrg    if (!tree) {
1273863f95b1Smrg	Print_X_Error (dpy, err);
1274863f95b1Smrg	Fatal_Error ("Can't query window tree.");
1275863f95b1Smrg    }
1276ff7e0accSmrg
1277863f95b1Smrg    if (level == 0) {
1278863f95b1Smrg	struct wininfo rw, pw;
1279863f95b1Smrg	rw.window = tree->root;
1280863f95b1Smrg	rw.net_wm_name_cookie = get_net_wm_name (dpy, rw.window);
1281863f95b1Smrg	rw.wm_name_cookie = xcb_get_wm_name (dpy, rw.window);
1282863f95b1Smrg	pw.window = tree->parent;
1283863f95b1Smrg	pw.net_wm_name_cookie = get_net_wm_name (dpy, pw.window);
1284863f95b1Smrg	pw.wm_name_cookie = xcb_get_wm_name (dpy, pw.window);
1285863f95b1Smrg	xcb_flush (dpy);
1286863f95b1Smrg
1287863f95b1Smrg	printf ("\n");
1288863f95b1Smrg	printf ("  Root window id: ");
1289863f95b1Smrg	Display_Window_Id (&rw, True);
1290863f95b1Smrg	printf ("  Parent window id: ");
1291863f95b1Smrg	Display_Window_Id (&pw, True);
1292863f95b1Smrg    }
1293863f95b1Smrg
1294863f95b1Smrg    num_children = xcb_query_tree_children_length (tree);
1295ff7e0accSmrg
1296863f95b1Smrg    if (level == 0  ||  num_children > 0) {
1297863f95b1Smrg	printf ("     ");
1298863f95b1Smrg	for (j = 0; j < level; j++) printf ("   ");
1299863f95b1Smrg	printf ("%d child%s%s\n", num_children, num_children == 1 ? "" : "ren",
1300863f95b1Smrg		num_children ? ":" : ".");
1301863f95b1Smrg    }
1302863f95b1Smrg
1303863f95b1Smrg    if (num_children > 0) {
1304863f95b1Smrg	xcb_window_t *child_list = xcb_query_tree_children (tree);
1305863f95b1Smrg	struct wininfo *children
1306863f95b1Smrg	    = calloc (num_children, sizeof(struct wininfo));
1307863f95b1Smrg
1308863f95b1Smrg	if (children == NULL)
1309863f95b1Smrg	    Fatal_Error ("Failed to allocate memory in display_tree_info");
1310863f95b1Smrg
1311863f95b1Smrg	for (i = (int)num_children - 1; i >= 0; i--) {
1312863f95b1Smrg	    struct wininfo *cw = &children[i];
1313863f95b1Smrg
1314863f95b1Smrg	    cw->window = child_list[i];
1315863f95b1Smrg	    cw->net_wm_name_cookie = get_net_wm_name (dpy, child_list[i]);
1316863f95b1Smrg	    cw->wm_name_cookie = xcb_get_wm_name (dpy, child_list[i]);
1317863f95b1Smrg	    cw->wm_class_cookie = xcb_get_wm_class (dpy, child_list[i]);
1318863f95b1Smrg	    cw->geometry_cookie = xcb_get_geometry (dpy, child_list[i]);
1319863f95b1Smrg	    cw->trans_coords_cookie = xcb_translate_coordinates
1320863f95b1Smrg		(dpy, child_list[i], tree->root, 0, 0);
1321863f95b1Smrg	    if (recurse)
1322863f95b1Smrg		cw->tree_cookie = xcb_query_tree (dpy, child_list[i]);
1323ff7e0accSmrg	}
1324863f95b1Smrg	xcb_flush (dpy);
1325863f95b1Smrg
1326863f95b1Smrg	for (i = (int)num_children - 1; i >= 0; i--) {
1327863f95b1Smrg	    struct wininfo *cw = &children[i];
1328863f95b1Smrg	    Bool got_wm_class = False;
1329863f95b1Smrg	    char *instance_name = NULL, *class_name = NULL;
1330863f95b1Smrg	    int instance_name_len, class_name_len;
1331863f95b1Smrg#ifdef USE_XCB_ICCCM
1332863f95b1Smrg	    xcb_get_wm_class_reply_t classhint;
1333863f95b1Smrg#else
1334863f95b1Smrg	    xcb_get_property_reply_t *classprop;
1335863f95b1Smrg#endif
1336863f95b1Smrg	    xcb_get_geometry_reply_t *geometry;
1337863f95b1Smrg
1338863f95b1Smrg	    printf ("     ");
1339863f95b1Smrg	    for (j = 0; j < level; j++) printf ("   ");
1340863f95b1Smrg	    Display_Window_Id (cw, False);
1341863f95b1Smrg	    printf (": (");
1342863f95b1Smrg
1343863f95b1Smrg#ifdef USE_XCB_ICCCM
1344863f95b1Smrg	    if (xcb_get_wm_class_reply (dpy, cw->wm_class_cookie,
1345863f95b1Smrg					&classhint, NULL)) {
1346863f95b1Smrg		got_wm_class = True;
1347863f95b1Smrg		instance_name = classhint.instance_name;
1348863f95b1Smrg		class_name = classhint.class_name;
1349863f95b1Smrg		instance_name_len = strlen(instance_name);
1350863f95b1Smrg		class_name_len = strlen(class_name);
1351863f95b1Smrg	    }
1352863f95b1Smrg#else
1353863f95b1Smrg	    classprop = xcb_get_property_reply
1354863f95b1Smrg		(dpy, cw->wm_class_cookie, NULL);
1355863f95b1Smrg	    if (classprop) {
1356863f95b1Smrg		if (classprop->type == XCB_ATOM_STRING &&
1357863f95b1Smrg		    classprop->format == 8) {
1358863f95b1Smrg		    int proplen = xcb_get_property_value_length (classprop);
1359863f95b1Smrg
1360863f95b1Smrg		    instance_name = xcb_get_property_value (classprop);
1361863f95b1Smrg		    instance_name_len = strnlen (instance_name, proplen);
1362863f95b1Smrg		    if (instance_name_len < proplen) {
1363863f95b1Smrg			class_name = instance_name + instance_name_len + 1;
1364863f95b1Smrg			class_name_len = strnlen
1365863f95b1Smrg			    (class_name, proplen - (instance_name_len + 1));
1366863f95b1Smrg		    } else
1367863f95b1Smrg			class_name_len = 0;
1368863f95b1Smrg		    got_wm_class = True;
1369863f95b1Smrg		}
1370863f95b1Smrg		else
1371863f95b1Smrg		    free (classprop);
1372863f95b1Smrg	    }
1373863f95b1Smrg#endif
1374863f95b1Smrg
1375863f95b1Smrg	    if (got_wm_class) {
1376863f95b1Smrg		if (instance_name)
1377863f95b1Smrg		    printf ("\"%.*s\" ", instance_name_len, instance_name);
1378863f95b1Smrg		else
1379863f95b1Smrg		    printf ("(none) ");
1380863f95b1Smrg
1381863f95b1Smrg		if (class_name)
1382863f95b1Smrg		    printf ("\"%.*s\") ",  class_name_len, class_name);
1383863f95b1Smrg		else
1384863f95b1Smrg		    printf ("(none)) ");
1385863f95b1Smrg
1386863f95b1Smrg#ifdef USE_XCB_ICCCM
1387863f95b1Smrg		xcb_get_wm_class_reply_wipe (&classhint);
1388863f95b1Smrg#else
1389863f95b1Smrg		free (classprop);
1390863f95b1Smrg#endif
1391863f95b1Smrg	    } else
1392863f95b1Smrg		printf (") ");
1393863f95b1Smrg
1394863f95b1Smrg	    geometry = xcb_get_geometry_reply(dpy, cw->geometry_cookie, &err);
1395863f95b1Smrg	    if (geometry) {
1396863f95b1Smrg		xcb_translate_coordinates_reply_t *trans_coords;
1397863f95b1Smrg
1398863f95b1Smrg		printf (" %ux%u+%d+%d", geometry->width, geometry->height,
1399863f95b1Smrg					geometry->x, geometry->y);
1400863f95b1Smrg
1401863f95b1Smrg		trans_coords = xcb_translate_coordinates_reply
1402863f95b1Smrg		    (dpy, cw->trans_coords_cookie, &err);
1403863f95b1Smrg
1404863f95b1Smrg		if (trans_coords) {
1405863f95b1Smrg		    int16_t abs_x = (int16_t) trans_coords->dst_x;
1406863f95b1Smrg		    int16_t abs_y = (int16_t) trans_coords->dst_y;
1407863f95b1Smrg		    int border = geometry->border_width;
1408863f95b1Smrg
1409863f95b1Smrg		    printf ("  +%d+%d", abs_x - border, abs_y - border);
1410863f95b1Smrg		    free (trans_coords);
1411863f95b1Smrg		} else if (err) {
1412863f95b1Smrg		    Print_X_Error (dpy, err);
1413863f95b1Smrg		}
1414863f95b1Smrg
1415863f95b1Smrg		free (geometry);
1416863f95b1Smrg	    } else if (err) {
1417863f95b1Smrg		Print_X_Error (dpy, err);
1418863f95b1Smrg	    }
1419863f95b1Smrg	    printf ("\n");
1420863f95b1Smrg
1421863f95b1Smrg	    if (recurse)
1422863f95b1Smrg		display_tree_info_1 (cw, 1, level+1);
1423863f95b1Smrg
1424863f95b1Smrg	    wininfo_wipe (cw);
1425863f95b1Smrg	}
1426863f95b1Smrg	free (children);
1427ff7e0accSmrg    }
1428ff7e0accSmrg
1429863f95b1Smrg    free (tree); /* includes storage for child_list[] */
1430ff7e0accSmrg}
1431ff7e0accSmrg
1432ff7e0accSmrg
1433ff7e0accSmrg/*
1434ff7e0accSmrg * Display a set of size hints
1435ff7e0accSmrg */
1436ff7e0accSmrgstatic void
1437863f95b1SmrgDisplay_Hints (xcb_size_hints_t *hints)
1438ff7e0accSmrg{
1439863f95b1Smrg    long flags;
1440ff7e0accSmrg
1441863f95b1Smrg    flags = hints->flags;
1442ff7e0accSmrg
1443863f95b1Smrg    if (flags & XCB_SIZE_HINT_US_POSITION)
1444863f95b1Smrg	printf ("      User supplied location: %s, %s\n",
1445863f95b1Smrg		xscale (hints->x), yscale (hints->y));
1446ff7e0accSmrg
1447863f95b1Smrg    if (flags & XCB_SIZE_HINT_P_POSITION)
1448863f95b1Smrg	printf ("      Program supplied location: %s, %s\n",
1449863f95b1Smrg		xscale (hints->x), yscale (hints->y));
1450ff7e0accSmrg
1451863f95b1Smrg    if (flags & XCB_SIZE_HINT_US_SIZE) {
1452863f95b1Smrg	printf ("      User supplied size: %s by %s\n",
1453863f95b1Smrg		xscale (hints->width), yscale (hints->height));
1454863f95b1Smrg    }
1455ff7e0accSmrg
1456863f95b1Smrg    if (flags & XCB_SIZE_HINT_P_SIZE)
1457863f95b1Smrg	printf ("      Program supplied size: %s by %s\n",
1458863f95b1Smrg		xscale (hints->width), yscale (hints->height));
1459ff7e0accSmrg
1460863f95b1Smrg    if (flags & XCB_SIZE_HINT_P_MIN_SIZE)
1461863f95b1Smrg	printf ("      Program supplied minimum size: %s by %s\n",
1462863f95b1Smrg		xscale (hints->min_width), yscale (hints->min_height));
1463ff7e0accSmrg
1464863f95b1Smrg    if (flags & XCB_SIZE_HINT_P_MAX_SIZE)
1465863f95b1Smrg	printf ("      Program supplied maximum size: %s by %s\n",
1466863f95b1Smrg		xscale (hints->max_width), yscale (hints->max_height));
1467ff7e0accSmrg
1468863f95b1Smrg    if (flags & XCB_SIZE_HINT_BASE_SIZE) {
1469863f95b1Smrg	printf ("      Program supplied base size: %s by %s\n",
1470863f95b1Smrg		xscale (hints->base_width), yscale (hints->base_height));
1471863f95b1Smrg    }
1472863f95b1Smrg
1473863f95b1Smrg    if (flags & XCB_SIZE_HINT_P_RESIZE_INC) {
1474863f95b1Smrg	printf ("      Program supplied x resize increment: %s\n",
1475863f95b1Smrg		xscale (hints->width_inc));
1476863f95b1Smrg	printf ("      Program supplied y resize increment: %s\n",
1477863f95b1Smrg		yscale (hints->height_inc));
1478863f95b1Smrg	if (hints->width_inc != 0 && hints->height_inc != 0) {
1479863f95b1Smrg	    if (flags & XCB_SIZE_HINT_US_SIZE)
1480863f95b1Smrg		printf ("      User supplied size in resize increments:  %s by %s\n",
1481863f95b1Smrg			(xscale (hints->width / hints->width_inc)),
1482863f95b1Smrg			(yscale (hints->height / hints->height_inc)));
1483863f95b1Smrg	    if (flags & XCB_SIZE_HINT_P_SIZE)
1484863f95b1Smrg		printf ("      Program supplied size in resize increments:  %s by %s\n",
1485863f95b1Smrg			(xscale (hints->width / hints->width_inc)),
1486863f95b1Smrg			(yscale (hints->height / hints->height_inc)));
1487863f95b1Smrg	    if (flags & XCB_SIZE_HINT_P_MIN_SIZE)
1488863f95b1Smrg		printf ("      Program supplied minimum size in resize increments: %s by %s\n",
1489863f95b1Smrg			xscale (hints->min_width / hints->width_inc), yscale (hints->min_height / hints->height_inc));
1490863f95b1Smrg	    if (flags & XCB_SIZE_HINT_BASE_SIZE)
1491863f95b1Smrg		printf ("      Program supplied base size in resize increments:  %s by %s\n",
1492863f95b1Smrg			(xscale (hints->base_width / hints->width_inc)),
1493863f95b1Smrg			(yscale (hints->base_height / hints->height_inc)));
1494ff7e0accSmrg	}
1495863f95b1Smrg    }
1496863f95b1Smrg
1497863f95b1Smrg    if (flags & XCB_SIZE_HINT_P_ASPECT) {
1498863f95b1Smrg	printf ("      Program supplied min aspect ratio: %s/%s\n",
1499863f95b1Smrg		xscale (hints->min_aspect_num), yscale (hints->min_aspect_den));
1500863f95b1Smrg	printf ("      Program supplied max aspect ratio: %s/%s\n",
1501863f95b1Smrg		xscale (hints->max_aspect_num), yscale (hints->max_aspect_den));
1502863f95b1Smrg    }
1503863f95b1Smrg
1504863f95b1Smrg    if (flags & XCB_SIZE_HINT_P_WIN_GRAVITY) {
1505863f95b1Smrg	printf ("      Program supplied window gravity: %s\n",
1506863f95b1Smrg		Lookup (hints->win_gravity, _gravities));
1507863f95b1Smrg    }
1508ff7e0accSmrg}
1509ff7e0accSmrg
1510ff7e0accSmrg
1511ff7e0accSmrg/*
1512ff7e0accSmrg * Display Size Hints info
1513ff7e0accSmrg */
1514ff7e0accSmrgstatic void
1515863f95b1SmrgDisplay_Size_Hints (struct wininfo *w)
1516ff7e0accSmrg{
1517863f95b1Smrg    xcb_size_hints_t hints;
1518ff7e0accSmrg
1519863f95b1Smrg    printf ("\n");
1520863f95b1Smrg    if (!fetch_normal_hints (w, &hints))
1521863f95b1Smrg	printf ("  No normal window size hints defined\n");
1522863f95b1Smrg    else {
1523863f95b1Smrg	printf ("  Normal window size hints:\n");
1524863f95b1Smrg	Display_Hints (&hints);
1525863f95b1Smrg    }
1526863f95b1Smrg
1527863f95b1Smrg    if (!xcb_get_wm_size_hints_reply (dpy, w->zoom_cookie, &hints, NULL))
1528863f95b1Smrg	printf ("  No zoom window size hints defined\n");
1529863f95b1Smrg    else {
1530863f95b1Smrg	printf ("  Zoom window size hints:\n");
1531863f95b1Smrg	Display_Hints (&hints);
1532863f95b1Smrg    }
1533ff7e0accSmrg}
1534ff7e0accSmrg
1535ff7e0accSmrg
1536ff7e0accSmrgstatic void
1537863f95b1SmrgDisplay_Window_Shape (xcb_window_t window)
1538ff7e0accSmrg{
1539863f95b1Smrg    const xcb_query_extension_reply_t *shape_query;
1540863f95b1Smrg    xcb_shape_query_extents_cookie_t extents_cookie;
1541863f95b1Smrg    xcb_shape_query_extents_reply_t *extents;
1542ff7e0accSmrg
1543863f95b1Smrg    shape_query = xcb_get_extension_data (dpy, &xcb_shape_id);
1544863f95b1Smrg    if (!shape_query->present)
1545ff7e0accSmrg	return;
1546ff7e0accSmrg
1547863f95b1Smrg    printf ("\n");
1548863f95b1Smrg
1549863f95b1Smrg    extents_cookie = xcb_shape_query_extents (dpy, window);
1550863f95b1Smrg    extents = xcb_shape_query_extents_reply (dpy, extents_cookie, &err);
1551863f95b1Smrg
1552863f95b1Smrg    if (!extents) {
1553863f95b1Smrg	if (err)
1554863f95b1Smrg	    Print_X_Error (dpy, err);
1555863f95b1Smrg	else
1556863f95b1Smrg	{
1557863f95b1Smrg	    printf ("  No window shape defined\n");
1558863f95b1Smrg	    printf ("  No border shape defined\n");
1559863f95b1Smrg	}
1560863f95b1Smrg	return;
1561863f95b1Smrg    }
1562863f95b1Smrg
1563863f95b1Smrg    if (!extents->bounding_shaped)
1564863f95b1Smrg	printf ("  No window shape defined\n");
1565ff7e0accSmrg    else {
1566863f95b1Smrg	printf ("  Window shape extents:  %sx%s",
1567863f95b1Smrg		xscale (extents->bounding_shape_extents_width),
1568863f95b1Smrg		yscale (extents->bounding_shape_extents_height));
1569863f95b1Smrg	printf ("+%s+%s\n",
1570863f95b1Smrg		xscale (extents->bounding_shape_extents_x),
1571863f95b1Smrg		yscale (extents->bounding_shape_extents_y));
1572ff7e0accSmrg    }
1573863f95b1Smrg    if (!extents->clip_shaped)
1574863f95b1Smrg	printf ("  No border shape defined\n");
1575ff7e0accSmrg    else {
1576863f95b1Smrg	printf ("  Border shape extents:  %sx%s",
1577863f95b1Smrg		xscale (extents->clip_shape_extents_width),
1578863f95b1Smrg		yscale (extents->clip_shape_extents_height));
1579863f95b1Smrg	printf ("+%s+%s\n",
1580863f95b1Smrg		xscale (extents->clip_shape_extents_x),
1581863f95b1Smrg		yscale (extents->clip_shape_extents_y));
1582ff7e0accSmrg    }
1583863f95b1Smrg
1584863f95b1Smrg    free (extents);
1585ff7e0accSmrg}
1586ff7e0accSmrg
1587ff7e0accSmrg/*
1588ff7e0accSmrg * Display Window Manager Info
1589863f95b1Smrg *
1590863f95b1Smrg * Requires wininfo members initialized:
1591863f95b1Smrg *   window, hints_cookie
1592ff7e0accSmrg */
1593ff7e0accSmrgstatic const binding _state_hints[] = {
1594863f95b1Smrg	{ XCB_WM_STATE_WITHDRAWN, "Withdrawn State" },
1595863f95b1Smrg	{ XCB_WM_STATE_NORMAL, "Normal State" },
1596863f95b1Smrg	{ XCB_WM_STATE_ICONIC, "Iconic State" },
1597863f95b1Smrg/* xwininfo previously also reported the ZoomState & InactiveState,
1598863f95b1Smrg   but ICCCM declared those obsolete long ago */
159910998002Smrg	{ 0, NULL } };
1600ff7e0accSmrg
1601863f95b1Smrg#ifndef USE_XCB_ICCCM
1602863f95b1Smrgstatic Bool
1603863f95b1Smrgwm_hints_reply (xcb_connection_t *dpy, xcb_get_property_cookie_t cookie,
1604863f95b1Smrg		wm_hints_t *hints_return, xcb_generic_error_t **err)
1605863f95b1Smrg{
1606863f95b1Smrg    xcb_get_property_reply_t *prop = xcb_get_property_reply (dpy, cookie, err);
1607863f95b1Smrg    int length;
1608863f95b1Smrg
1609863f95b1Smrg    if (!prop || (prop->type != XCB_ATOM_WM_HINTS) || (prop->format != 32)) {
1610863f95b1Smrg	free (prop);
1611863f95b1Smrg	return False;
1612863f95b1Smrg    }
1613863f95b1Smrg
1614863f95b1Smrg    memset (hints_return, 0, sizeof(wm_hints_t));
1615863f95b1Smrg
1616863f95b1Smrg    length = xcb_get_property_value_length(prop);
1617863f95b1Smrg    if (length > sizeof(wm_hints_t))
1618863f95b1Smrg	length = sizeof(wm_hints_t);
1619863f95b1Smrg    memcpy (hints_return, xcb_get_property_value (prop), length);
1620863f95b1Smrg
1621863f95b1Smrg    free (prop);
1622863f95b1Smrg    return True;
1623863f95b1Smrg}
1624863f95b1Smrg
1625863f95b1Smrg#define xcb_get_wm_hints_reply wm_hints_reply
1626863f95b1Smrg#endif
1627863f95b1Smrg
1628ff7e0accSmrgstatic void
1629863f95b1SmrgDisplay_WM_Info (struct wininfo *w)
1630ff7e0accSmrg{
1631863f95b1Smrg    xcb_wm_hints_t wmhints;
1632863f95b1Smrg    long flags;
1633863f95b1Smrg    xcb_get_property_reply_t *prop;
1634863f95b1Smrg    int i;
1635863f95b1Smrg
1636863f95b1Smrg    printf ("\n");
1637863f95b1Smrg    if (!xcb_get_wm_hints_reply(dpy, w->hints_cookie, &wmhints, &err))
1638863f95b1Smrg    {
1639863f95b1Smrg	printf ("  No window manager hints defined\n");
1640863f95b1Smrg	if (err)
1641863f95b1Smrg	    Print_X_Error (dpy, err);
1642863f95b1Smrg	flags = 0;
1643863f95b1Smrg    } else
1644863f95b1Smrg	flags = wmhints.flags;
1645863f95b1Smrg
1646863f95b1Smrg    printf ("  Window manager hints:\n");
1647863f95b1Smrg
1648863f95b1Smrg    if (flags & XCB_WM_HINT_INPUT)
1649863f95b1Smrg	printf ("      Client accepts input or input focus: %s\n",
1650863f95b1Smrg		Lookup (wmhints.input, _bool));
1651863f95b1Smrg
1652863f95b1Smrg    if (flags & XCB_WM_HINT_ICON_WINDOW) {
1653863f95b1Smrg	struct wininfo iw;
1654863f95b1Smrg	iw.window = wmhints.icon_window;
1655863f95b1Smrg	iw.net_wm_name_cookie = get_net_wm_name (dpy, iw.window);
1656863f95b1Smrg	iw.wm_name_cookie = xcb_get_wm_name (dpy, iw.window);
1657863f95b1Smrg
1658863f95b1Smrg	printf ("      Icon window id: ");
1659863f95b1Smrg	Display_Window_Id (&iw, True);
1660863f95b1Smrg    }
1661863f95b1Smrg
1662863f95b1Smrg    if (flags & XCB_WM_HINT_ICON_POSITION)
1663863f95b1Smrg	printf ("      Initial icon position: %s, %s\n",
1664863f95b1Smrg		xscale (wmhints.icon_x), yscale (wmhints.icon_y));
1665863f95b1Smrg
1666863f95b1Smrg    if (flags & XCB_WM_HINT_STATE)
1667863f95b1Smrg	printf ("      Initial state is %s\n",
1668863f95b1Smrg		Lookup (wmhints.initial_state, _state_hints));
1669863f95b1Smrg
1670863f95b1Smrg    if (atom_net_wm_desktop) {
1671863f95b1Smrg	prop = xcb_get_property_reply (dpy, w->wm_desktop_cookie, NULL);
1672863f95b1Smrg	if (prop && (prop->type != XCB_NONE)) {
1673863f95b1Smrg	    uint32_t *desktop = xcb_get_property_value (prop);
1674863f95b1Smrg	    if (*desktop == 0xFFFFFFFF) {
1675863f95b1Smrg		printf ("      Displayed on all desktops\n");
1676863f95b1Smrg	    } else {
1677863f95b1Smrg		printf ("      Displayed on desktop %d\n", *desktop);
1678863f95b1Smrg	    }
1679ff7e0accSmrg	}
1680863f95b1Smrg	free (prop);
1681863f95b1Smrg    }
1682ff7e0accSmrg
1683863f95b1Smrg    if (atom_net_wm_window_type) {
1684863f95b1Smrg	prop = xcb_get_property_reply (dpy, w->wm_window_type_cookie,
1685863f95b1Smrg				       NULL);
1686863f95b1Smrg	if (prop && (prop->type != XCB_NONE) && (prop->value_len > 0)) {
1687863f95b1Smrg	    xcb_atom_t *atoms = xcb_get_property_value (prop);
1688863f95b1Smrg	    int atom_count = prop->value_len;
1689863f95b1Smrg
1690863f95b1Smrg	    if (atom_count > 0) {
1691863f95b1Smrg		printf ("      Window type:\n");
1692863f95b1Smrg		for (i = 0; i < atom_count; i++) {
1693863f95b1Smrg		    const char *atom_name = Get_Atom_Name (dpy, atoms[i]);
1694863f95b1Smrg
1695863f95b1Smrg		    if (atom_name) {
1696863f95b1Smrg			print_friendly_name ("          %s\n", atom_name,
1697863f95b1Smrg					     "_NET_WM_WINDOW_TYPE_");
1698863f95b1Smrg		    } else {
1699863f95b1Smrg			printf ("          (unresolvable ATOM 0x%x)\n",
1700863f95b1Smrg				atoms[i]);
1701863f95b1Smrg		    }
1702863f95b1Smrg		}
1703863f95b1Smrg	    }
1704863f95b1Smrg	}
1705863f95b1Smrg	free (prop);
1706863f95b1Smrg    }
1707863f95b1Smrg
1708863f95b1Smrg    if (atom_net_wm_state) {
1709863f95b1Smrg	prop = xcb_get_property_reply (dpy, w->wm_state_cookie, NULL);
1710863f95b1Smrg	if (prop && (prop->type != XCB_NONE) && (prop->value_len > 0)) {
1711863f95b1Smrg	    xcb_atom_t *atoms = xcb_get_property_value (prop);
1712863f95b1Smrg	    int atom_count = prop->value_len;
1713863f95b1Smrg
1714863f95b1Smrg	    if (atom_count > 0) {
1715863f95b1Smrg		printf ("      Window state:\n");
1716863f95b1Smrg		for (i = 0; i < atom_count; i++) {
1717863f95b1Smrg		    const char *atom_name = Get_Atom_Name (dpy, atoms[i]);
1718863f95b1Smrg
1719863f95b1Smrg		    if (atom_name) {
1720863f95b1Smrg			print_friendly_name ("          %s\n", atom_name,
1721863f95b1Smrg					     "_NET_WM_STATE_");
1722863f95b1Smrg		    } else {
1723863f95b1Smrg			printf ("          (unresolvable ATOM 0x%x)\n",
1724863f95b1Smrg				atoms[i]);
1725863f95b1Smrg		    }
1726863f95b1Smrg		}
1727863f95b1Smrg	    }
1728863f95b1Smrg	}
1729863f95b1Smrg	free (prop);
1730863f95b1Smrg    }
1731ff7e0accSmrg
1732863f95b1Smrg    if (atom_net_wm_pid) {
1733863f95b1Smrg	printf ("      Process id: ");
1734863f95b1Smrg	prop = xcb_get_property_reply (dpy, w->wm_pid_cookie, NULL);
1735863f95b1Smrg	if (prop && (prop->type == XCB_ATOM_CARDINAL)) {
1736863f95b1Smrg	    uint32_t *pid = xcb_get_property_value (prop);
1737863f95b1Smrg	    printf ("%d", *pid);
1738863f95b1Smrg	} else {
1739863f95b1Smrg	    printf ("(unknown)");
1740863f95b1Smrg	}
1741863f95b1Smrg	free (prop);
1742ff7e0accSmrg
1743863f95b1Smrg	prop = xcb_get_property_reply (dpy, w->wm_client_machine_cookie, NULL);
1744863f95b1Smrg	if (prop && (prop->type == XCB_ATOM_STRING)) {
1745863f95b1Smrg	    const char *hostname = xcb_get_property_value (prop);
1746863f95b1Smrg	    int hostname_len = xcb_get_property_value_length (prop);
1747863f95b1Smrg	    printf (" on host %.*s", hostname_len, hostname);
1748ff7e0accSmrg	}
1749863f95b1Smrg	printf ("\n");
1750863f95b1Smrg	free (prop);
1751863f95b1Smrg    }
1752863f95b1Smrg
1753863f95b1Smrg    if (atom_net_frame_extents) {
1754863f95b1Smrg	prop = xcb_get_property_reply (dpy, w->frame_extents_cookie, NULL);
1755863f95b1Smrg	if (prop && (prop->type == XCB_ATOM_CARDINAL)
1756863f95b1Smrg	    && (prop->value_len == 4)) {
1757863f95b1Smrg	    uint32_t *extents = xcb_get_property_value (prop);
1758863f95b1Smrg
1759863f95b1Smrg	    printf ("      Frame extents: %d, %d, %d, %d\n",
1760863f95b1Smrg		    extents[0], extents[1], extents[2], extents[3]);
1761863f95b1Smrg	}
1762863f95b1Smrg	free (prop);
1763863f95b1Smrg    }
1764863f95b1Smrg}
1765863f95b1Smrg
1766863f95b1Smrg/* Frees all members of a wininfo struct, but not the struct itself */
1767863f95b1Smrgstatic void
1768863f95b1Smrgwininfo_wipe (struct wininfo *w)
1769863f95b1Smrg{
1770863f95b1Smrg    free (w->geometry);
1771863f95b1Smrg    free (w->win_attributes);
1772863f95b1Smrg    free (w->normal_hints);
1773863f95b1Smrg}
1774863f95b1Smrg
1775863f95b1Smrg/* Gets UTF-8 encoded EMWH property _NET_WM_NAME for a window */
1776863f95b1Smrgstatic xcb_get_property_cookie_t
1777863f95b1Smrgget_net_wm_name (xcb_connection_t *dpy, xcb_window_t win)
1778863f95b1Smrg{
1779863f95b1Smrg    if (!atom_net_wm_name)
1780863f95b1Smrg	atom_net_wm_name = Get_Atom (dpy, "_NET_WM_NAME");
1781863f95b1Smrg
1782863f95b1Smrg    if (!atom_utf8_string)
1783863f95b1Smrg	atom_utf8_string = Get_Atom (dpy, "UTF8_STRING");
1784863f95b1Smrg
1785863f95b1Smrg    if (atom_net_wm_name && atom_utf8_string)
1786863f95b1Smrg	return xcb_get_property (dpy, False, win, atom_net_wm_name,
1787863f95b1Smrg				 atom_utf8_string, 0, BUFSIZ);
1788863f95b1Smrg    else {
1789863f95b1Smrg	xcb_get_property_cookie_t dummy = { 0 };
1790863f95b1Smrg	return dummy;
1791863f95b1Smrg    }
1792863f95b1Smrg}
1793863f95b1Smrg
1794863f95b1Smrg/* [Copied from code added by Yang Zhao to xprop/xprop.c]
1795863f95b1Smrg *
1796863f95b1Smrg * Validate a string as UTF-8 encoded according to RFC 3629
1797863f95b1Smrg *
1798863f95b1Smrg * Simply, a unicode code point (up to 21-bits long) is encoded as follows:
1799863f95b1Smrg *
1800863f95b1Smrg *    Char. number range  |        UTF-8 octet sequence
1801863f95b1Smrg *       (hexadecimal)    |              (binary)
1802863f95b1Smrg *    --------------------+---------------------------------------------
1803863f95b1Smrg *    0000 0000-0000 007F | 0xxxxxxx
1804863f95b1Smrg *    0000 0080-0000 07FF | 110xxxxx 10xxxxxx
1805863f95b1Smrg *    0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
1806863f95b1Smrg *    0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
1807863f95b1Smrg *
1808863f95b1Smrg * Validation is done left-to-right, and an error condition, if any, refers to
1809863f95b1Smrg * only the left-most problem in the string.
1810863f95b1Smrg *
1811863f95b1Smrg * Return values:
1812863f95b1Smrg *   UTF8_VALID: Valid UTF-8 encoded string
1813863f95b1Smrg *   UTF8_OVERLONG: Using more bytes than needed for a code point
1814863f95b1Smrg *   UTF8_SHORT_TAIL: Not enough bytes in a multi-byte sequence
1815863f95b1Smrg *   UTF8_LONG_TAIL: Too many bytes in a multi-byte sequence
1816863f95b1Smrg *   UTF8_FORBIDDEN_VALUE: Forbidden prefix or code point outside 0x10FFFF
1817863f95b1Smrg */
1818863f95b1Smrg#define UTF8_VALID 0
1819863f95b1Smrg#define UTF8_FORBIDDEN_VALUE 1
1820863f95b1Smrg#define UTF8_OVERLONG 2
1821863f95b1Smrg#define UTF8_SHORT_TAIL 3
1822863f95b1Smrg#define UTF8_LONG_TAIL 4
1823863f95b1Smrgstatic int
1824863f95b1Smrgis_valid_utf8 (const char *string, int len)
1825863f95b1Smrg{
1826863f95b1Smrg    unsigned long codepoint;
1827863f95b1Smrg    int rem, i;
1828863f95b1Smrg    unsigned char c;
1829863f95b1Smrg
1830863f95b1Smrg    rem = 0;
1831863f95b1Smrg    for (i = 0; i < len; i++) {
1832863f95b1Smrg	c = (unsigned char) string[i];
1833863f95b1Smrg
1834863f95b1Smrg	/* Order of type check:
1835863f95b1Smrg	 *   - Single byte code point
1836863f95b1Smrg	 *   - Non-starting byte of multi-byte sequence
1837863f95b1Smrg	 *   - Start of 2-byte sequence
1838863f95b1Smrg	 *   - Start of 3-byte sequence
1839863f95b1Smrg	 *   - Start of 4-byte sequence
1840863f95b1Smrg	 */
1841863f95b1Smrg	if (!(c & 0x80)) {
1842863f95b1Smrg	    if (rem > 0) return UTF8_SHORT_TAIL;
1843863f95b1Smrg	    rem = 0;
1844863f95b1Smrg	    codepoint = c;
1845863f95b1Smrg	} else if ((c & 0xC0) == 0x80) {
1846863f95b1Smrg	    if (rem == 0) return UTF8_LONG_TAIL;
1847863f95b1Smrg	    rem--;
1848863f95b1Smrg	    codepoint |= (c & 0x3F) << (rem * 6);
1849863f95b1Smrg	    if (codepoint == 0) return UTF8_OVERLONG;
1850863f95b1Smrg	} else if ((c & 0xE0) == 0xC0) {
1851863f95b1Smrg	    if (rem > 0) return UTF8_SHORT_TAIL;
1852863f95b1Smrg	    rem = 1;
1853863f95b1Smrg	    codepoint = (c & 0x1F) << 6;
1854863f95b1Smrg	    if (codepoint == 0) return UTF8_OVERLONG;
1855863f95b1Smrg	} else if ((c & 0xF0) == 0xE0) {
1856863f95b1Smrg	    if (rem > 0) return UTF8_SHORT_TAIL;
1857863f95b1Smrg	    rem = 2;
1858863f95b1Smrg	    codepoint = (c & 0x0F) << 12;
1859863f95b1Smrg	} else if ((c & 0xF8) == 0xF0) {
1860863f95b1Smrg	    if (rem > 0) return UTF8_SHORT_TAIL;
1861863f95b1Smrg	    rem = 3;
1862863f95b1Smrg	    codepoint = (c & 0x07) << 18;
1863863f95b1Smrg	    if (codepoint > 0x10FFFF) return UTF8_FORBIDDEN_VALUE;
1864863f95b1Smrg	} else
1865863f95b1Smrg	    return UTF8_FORBIDDEN_VALUE;
1866863f95b1Smrg    }
1867ff7e0accSmrg
1868863f95b1Smrg    return UTF8_VALID;
1869863f95b1Smrg}
1870863f95b1Smrg
1871863f95b1Smrg/*
1872863f95b1Smrg * Converts a UTF-8 encoded string to the current locale encoding,
1873863f95b1Smrg * if possible, and prints it, with prefix before and suffix after.
1874863f95b1Smrg * Length of the string is specified in bytes, or -1 for going until '\0'
1875863f95b1Smrg */
1876863f95b1Smrgstatic void
1877863f95b1Smrgprint_utf8 (const char *prefix, char *u8str, size_t length, const char *suffix)
1878863f95b1Smrg{
1879863f95b1Smrg    size_t inlen = length;
1880863f95b1Smrg
1881863f95b1Smrg    if (inlen < 0) {
1882863f95b1Smrg	inlen = strlen (u8str);
1883863f95b1Smrg    }
1884863f95b1Smrg
1885863f95b1Smrg    if (is_valid_utf8 (u8str, inlen) != UTF8_VALID) {
1886863f95b1Smrg	printf (" (invalid UTF8_STRING)");
1887863f95b1Smrg	return;
1888863f95b1Smrg    }
1889863f95b1Smrg
1890863f95b1Smrg    if (strcmp (user_encoding, "UTF-8") == 0) {
1891863f95b1Smrg	/* Don't need to convert */
1892863f95b1Smrg	printf ("%s", prefix);
1893863f95b1Smrg	fwrite (u8str, 1, inlen, stdout);
1894863f95b1Smrg	printf ("%s", suffix);
1895863f95b1Smrg	return;
1896863f95b1Smrg    }
1897863f95b1Smrg
1898863f95b1Smrg#ifdef HAVE_ICONV
1899863f95b1Smrg    if (!iconv_from_utf8) {
1900863f95b1Smrg	iconv_from_utf8 = iconv_open (user_encoding, "UTF-8");
1901863f95b1Smrg    }
1902863f95b1Smrg
1903863f95b1Smrg    if (iconv_from_utf8 != (iconv_t) -1) {
1904863f95b1Smrg	Bool done = True;
1905863f95b1Smrg	char *inp = u8str;
1906863f95b1Smrg	char convbuf[BUFSIZ];
1907863f95b1Smrg	int convres;
1908863f95b1Smrg
1909863f95b1Smrg	printf ("%s", prefix);
1910863f95b1Smrg	do {
1911863f95b1Smrg	    char *outp = convbuf;
1912863f95b1Smrg	    size_t outlen = sizeof(convbuf);
1913863f95b1Smrg
1914863f95b1Smrg	    convres = iconv (iconv_from_utf8, &inp, &inlen, &outp, &outlen);
1915ff7e0accSmrg
1916863f95b1Smrg	    if ((convres == -1) && (errno == E2BIG)) {
1917863f95b1Smrg		done = False;
1918863f95b1Smrg		convres = 0;
1919863f95b1Smrg	    }
1920863f95b1Smrg
1921863f95b1Smrg	    if (convres == 0) {
1922863f95b1Smrg		fwrite (convbuf, 1, sizeof(convbuf) - outlen, stdout);
1923863f95b1Smrg	    } else {
1924863f95b1Smrg		printf (" (failure in conversion from UTF8_STRING to %s)",
1925863f95b1Smrg			user_encoding);
1926863f95b1Smrg	    }
1927863f95b1Smrg	} while (!done);
1928863f95b1Smrg	printf ("%s", suffix);
1929863f95b1Smrg    } else {
1930863f95b1Smrg	printf (" (can't load iconv conversion for UTF8_STRING to %s)",
1931863f95b1Smrg		user_encoding);
1932863f95b1Smrg    }
1933863f95b1Smrg#else
1934863f95b1Smrg    printf (" (can't convert UTF8_STRING to %s)", user_encoding);
1935863f95b1Smrg#endif
1936863f95b1Smrg}
1937863f95b1Smrg
1938863f95b1Smrg/*
1939863f95b1Smrg * Takes a string such as an atom name, strips the prefix, converts
1940863f95b1Smrg * underscores to spaces, lowercases all but the first letter of each word,
1941863f95b1Smrg * and prints it.
1942863f95b1Smrg */
1943863f95b1Smrgstatic void
1944863f95b1Smrgprint_friendly_name (const char *format, const char *string,
1945863f95b1Smrg		     const char *prefix)
1946863f95b1Smrg{
1947863f95b1Smrg    const char *name_start = string;
1948863f95b1Smrg    char *lowered_name, *n;
1949863f95b1Smrg    int prefix_len = strlen (prefix);
1950863f95b1Smrg
1951863f95b1Smrg    if (strncmp (name_start, prefix, prefix_len) == 0) {
1952863f95b1Smrg	name_start += prefix_len;
1953863f95b1Smrg    }
1954863f95b1Smrg
1955863f95b1Smrg    lowered_name = strdup (name_start);
1956863f95b1Smrg    if (lowered_name) {
1957863f95b1Smrg	Bool first = True;
1958863f95b1Smrg
1959863f95b1Smrg	for (n = lowered_name ; *n != 0 ; n++) {
1960863f95b1Smrg	    if (*n == '_') {
1961863f95b1Smrg		*n = ' ';
1962863f95b1Smrg		first = True;
1963863f95b1Smrg	    } else if (first) {
1964863f95b1Smrg		first = False;
1965863f95b1Smrg	    } else {
1966863f95b1Smrg		*n = tolower(*n);
1967863f95b1Smrg	    }
1968863f95b1Smrg	}
1969863f95b1Smrg	name_start = lowered_name;
1970863f95b1Smrg    }
1971ff7e0accSmrg
1972863f95b1Smrg    printf (format, name_start);
1973863f95b1Smrg    free (lowered_name);
1974ff7e0accSmrg}
1975