2 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
25 Copyright 1987, 1998 The Open Group
27 Permission to use, copy, modify, distribute, and sell this software and its
28 documentation for any purpose is hereby granted without fee, provided that
29 the above copyright notice appear in all copies and that both that
30 copyright notice and this permission notice appear in supporting
33 The above copyright notice and this permission notice shall be included
34 in all copies or substantial portions of the Software.
36 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
37 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
38 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
39 OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
40 HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
41 INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
42 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
43 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
44 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
46 Except as contained in this notice, the name of a copyright holder
47 shall not be used in advertising or otherwise to promote the sale, use
48 or other dealings in this Software without prior written authorization
49 of the copyright holder.
55 * xwininfo.c - MIT Project Athena, X Window system window
56 * information utility.
59 * This program will report all relevant information
60 * about a specific window.
62 * Author: Mark Lillibridge, MIT Project Athena
69 #include <xcb/xproto.h>
71 # include <xcb/xcb_icccm.h>
73 #include <xcb/shape.h>
90 /* Include routines to handle parsing defaults */
99 /* Once xcb-icccm's API is stable, this should be replaced by
100 xcb_size_hints_t & xcb_size_hints_flags_t */
102 /** User specified flags */
104 /** User-specified position */
106 /** User-specified size */
107 int32_t width, height;
108 /** Program-specified minimum size */
109 int32_t min_width, min_height;
110 /** Program-specified maximum size */
111 int32_t max_width, max_height;
112 /** Program-specified resize increments */
113 int32_t width_inc, height_inc;
114 /** Program-specified minimum aspect ratios */
115 int32_t min_aspect_num, min_aspect_den;
116 /** Program-specified maximum aspect ratios */
117 int32_t max_aspect_num, max_aspect_den;
118 /** Program-specified base size */
119 int32_t base_width, base_height;
120 /** Program-specified window gravity */
121 uint32_t win_gravity;
124 # define xcb_size_hints_t wm_size_hints_t
127 /** Marks which fields in this structure are defined */
129 /** Does this application rely on the window manager to get keyboard
133 int32_t initial_state;
134 /** Pixmap to be used as icon */
135 xcb_pixmap_t icon_pixmap;
136 /** Window to be used as icon */
137 xcb_window_t icon_window;
138 /** Initial position of icon */
139 int32_t icon_x, icon_y;
140 /** Icon mask bitmap */
141 xcb_pixmap_t icon_mask;
142 /* Identifier of related window group */
143 xcb_window_t window_group;
146 #define xcb_icccm_wm_hints_t wm_hints_t
149 /* xcb_size_hints_flags_t */
150 XCB_ICCCM_SIZE_HINT_US_POSITION = 1 << 0,
151 XCB_ICCCM_SIZE_HINT_US_SIZE = 1 << 1,
152 XCB_ICCCM_SIZE_HINT_P_POSITION = 1 << 2,
153 XCB_ICCCM_SIZE_HINT_P_SIZE = 1 << 3,
154 XCB_ICCCM_SIZE_HINT_P_MIN_SIZE = 1 << 4,
155 XCB_ICCCM_SIZE_HINT_P_MAX_SIZE = 1 << 5,
156 XCB_ICCCM_SIZE_HINT_P_RESIZE_INC = 1 << 6,
157 XCB_ICCCM_SIZE_HINT_P_ASPECT = 1 << 7,
158 XCB_ICCCM_SIZE_HINT_BASE_SIZE = 1 << 8,
159 XCB_ICCCM_SIZE_HINT_P_WIN_GRAVITY = 1 << 9,
161 XCB_ICCCM_WM_STATE_WITHDRAWN = 0,
162 XCB_ICCCM_WM_STATE_NORMAL = 1,
163 XCB_ICCCM_WM_STATE_ICONIC = 3,
165 XCB_ICCCM_WM_HINT_INPUT = (1L << 0),
166 XCB_ICCCM_WM_HINT_STATE = (1L << 1),
167 XCB_ICCCM_WM_HINT_ICON_PIXMAP = (1L << 2),
168 XCB_ICCCM_WM_HINT_ICON_WINDOW = (1L << 3),
169 XCB_ICCCM_WM_HINT_ICON_POSITION = (1L << 4),
170 XCB_ICCCM_WM_HINT_ICON_MASK = (1L << 5),
171 XCB_ICCCM_WM_HINT_WINDOW_GROUP = (1L << 6),
172 XCB_ICCCM_WM_HINT_X_URGENCY = (1L << 8)
175 /* Once xcb-icccm's API is stable, these should be replaced by calls to it */
176 # define GET_TEXT_PROPERTY(Dpy, Win, Atom) \
177 xcb_get_property (Dpy, False, Win, Atom, XCB_GET_PROPERTY_TYPE_ANY, 0, BUFSIZ)
178 # define xcb_icccm_get_wm_name(Dpy, Win) \
179 GET_TEXT_PROPERTY(Dpy, Win, XCB_ATOM_WM_NAME)
181 # define xcb_icccm_get_wm_class(Dpy, Win) \
182 xcb_get_property (Dpy, False, Win, XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 0, BUFSIZ)
183 # define xcb_icccm_get_wm_hints(Dpy, Win) \
184 xcb_get_property(Dpy, False, Win, XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 0, 9)
186 # define xcb_icccm_get_wm_size_hints(Dpy, Win, Atom) \
187 xcb_get_property (Dpy, False, Win, Atom, XCB_ATOM_WM_SIZE_HINTS, 0, 18)
188 # define xcb_icccm_get_wm_normal_hints(Dpy, Win) \
189 xcb_icccm_get_wm_size_hints(Dpy, Win, XCB_ATOM_WM_NORMAL_HINTS)
192 /* Possibly in xcb-emwh in the future? */
193 static xcb_atom_t atom_net_wm_name, atom_utf8_string;
194 static xcb_atom_t atom_net_wm_desktop, atom_net_wm_window_type,
195 atom_net_wm_state, atom_net_wm_pid, atom_net_frame_extents;
196 static xcb_get_property_cookie_t get_net_wm_name (xcb_connection_t *,
199 /* Information we keep track of for each window to allow prefetching/reusing */
203 /* cookies for requests we've sent */
204 xcb_get_geometry_cookie_t geometry_cookie;
205 xcb_get_property_cookie_t net_wm_name_cookie;
206 xcb_get_property_cookie_t wm_name_cookie;
207 xcb_get_property_cookie_t wm_class_cookie;
208 xcb_translate_coordinates_cookie_t trans_coords_cookie;
209 xcb_query_tree_cookie_t tree_cookie;
210 xcb_get_window_attributes_cookie_t attr_cookie;
211 xcb_get_property_cookie_t normal_hints_cookie;
212 xcb_get_property_cookie_t hints_cookie;
213 xcb_get_property_cookie_t wm_desktop_cookie;
214 xcb_get_property_cookie_t wm_window_type_cookie;
215 xcb_get_property_cookie_t wm_state_cookie;
216 xcb_get_property_cookie_t wm_pid_cookie;
217 xcb_get_property_cookie_t wm_client_machine_cookie;
218 xcb_get_property_cookie_t frame_extents_cookie;
219 xcb_get_property_cookie_t zoom_cookie;
221 /* cached results from previous requests */
222 xcb_get_geometry_reply_t * geometry;
223 xcb_get_window_attributes_reply_t * win_attributes;
224 xcb_size_hints_t * normal_hints;
227 static void scale_init (xcb_screen_t *scrn);
228 static char *nscale (int, int, int, char *, size_t);
229 static char *xscale (int);
230 static char *yscale (int);
231 static char *bscale (int);
232 int main (int, char **);
233 static const char *LookupL (long, const binding *);
234 static const char *Lookup (int, const binding *);
235 static void Display_Window_Id (struct wininfo *, Bool);
236 static void Display_Stats_Info (struct wininfo *);
237 static void Display_Bits_Info (struct wininfo *);
238 static void Display_Event_Mask (long);
239 static void Display_Events_Info (struct wininfo *);
240 static void Display_Tree_Info (struct wininfo *, int);
241 static void display_tree_info_1 (struct wininfo *, int, int);
242 static void Display_Hints (xcb_size_hints_t *);
243 static void Display_Size_Hints (struct wininfo *);
244 static void Display_Window_Shape (xcb_window_t);
245 static void Display_WM_Info (struct wininfo *);
246 static void wininfo_wipe (struct wininfo *);
248 static const char *window_id_format = "0x%lx";
251 static iconv_t iconv_from_utf8;
253 static const char *user_encoding;
254 static void print_utf8 (const char *, char *, size_t, const char *);
255 static void print_friendly_name (const char *, const char *, const char *);
257 static xcb_connection_t *dpy;
258 static xcb_screen_t *screen;
259 static xcb_generic_error_t *err;
262 static size_t strlcat (char *dst, const char *src, size_t dstsize)
264 size_t sd = strlen (dst);
265 size_t ss = strlen (src);
269 strcpy (dst + sd, src);
271 strncpy (dst + sd, src, dstsize-sd-1);
279 * Report the syntax for calling xwininfo:
285 "usage: %s [-options ...]\n\n"
286 "where options include:\n"
287 " -help print this message\n"
288 " -display host:dpy X server to contact\n"
289 " -root use the root window\n"
290 " -id windowid use the window with the specified id\n"
291 " -name windowname use the window with the specified name\n"
292 " -int print window id in decimal\n"
293 " -children print parent and child identifiers\n"
294 " -tree print children identifiers recursively\n"
295 " -stats print window geometry [DEFAULT]\n"
296 " -bits print window pixel information\n"
297 " -events print events selected for on window\n"
298 " -size print size hints\n"
299 " -wm print window manager hints\n"
300 " -shape print shape extents\n"
301 " -frame don't ignore window manager frames\n"
302 " -english print sizes in english units\n"
303 " -metric print sizes in metric units\n"
304 " -all -tree, -stats, -bits, -events, -wm, -size, -shape\n"
311 * pixel to inch, metric converter.
312 * Hacked in by Mark W. Eichin <eichin@athena> [eichin:19880619.1509EST]
314 * Simply put: replace the old numbers with string print calls.
315 * Returning a local string is ok, since we only ever get called to
316 * print one x and one y, so as long as they don't collide, they're
317 * fine. This is not meant to be a general purpose routine.
321 static int xp = 0, xmm = 0;
322 static int yp = 0, ymm = 0;
323 static int bp = 0, bmm = 0;
324 static int english = 0, metric = 0;
327 scale_init (xcb_screen_t *screen)
329 xp = screen->width_in_pixels;
330 yp = screen->height_in_pixels;
331 xmm = screen->width_in_millimeters;
332 ymm = screen->height_in_millimeters;
337 #define MILE (5280*12)
342 nscale (int n, int np, int nmm, char *nbuf, size_t nbufsize)
345 snprintf (nbuf, nbufsize, "%d", n);
347 if (metric||english) {
348 s = strlcat (nbuf, " (", nbufsize);
351 snprintf (nbuf+s, nbufsize-s, "%.2f mm%s",
352 ((double) n) * nmm/np , english ? "; " : "");
356 Bool printed_anything = False;
357 int mi, yar, ft, inr;
359 inch_frac = ((double) n)*(nmm/25.4)/np;
360 inr = (int)inch_frac;
361 inch_frac -= (double)inr;
366 snprintf (nbuf+s, nbufsize-s, "%d %s(?!?)",
367 mi, (mi == 1) ? "mile" : "miles");
368 printed_anything = True;
373 if (printed_anything)
374 strlcat (nbuf, ", ", nbufsize);
376 snprintf (nbuf+s, nbufsize-s, "%d %s",
377 yar, (yar==1) ? "yard" : "yards");
378 printed_anything = True;
383 if (printed_anything)
384 strlcat (nbuf, ", ", nbufsize);
386 snprintf (nbuf+s, nbufsize-s, "%d %s",
387 ft, (ft==1) ? "foot" : "feet");
388 printed_anything = True;
390 if (!printed_anything || inch_frac != 0.0 || inr != 0) {
391 if (printed_anything)
392 strlcat (nbuf, ", ", nbufsize);
394 snprintf (nbuf+s, nbufsize-s, "%.2f inches", inr+inch_frac);
397 strlcat (nbuf, ")", nbufsize);
402 static char xbuf[BUFSIZ];
406 return (nscale (x, xp, xmm, xbuf, sizeof(xbuf)));
409 static char ybuf[BUFSIZ];
413 return (nscale (y, yp, ymm, ybuf, sizeof(ybuf)));
416 static char bbuf[BUFSIZ];
420 return (nscale (b, bp, bmm, bbuf, sizeof(bbuf)));
423 /* end of pixel to inch, metric converter */
426 main (int argc, char **argv)
429 int tree = 0, stats = 0, bits = 0, events = 0, wm = 0, size = 0, shape = 0;
430 int frame = 0, children = 0;
432 xcb_window_t window = 0;
433 char *display_name = NULL;
434 const char *window_name = NULL;
435 struct wininfo wininfo;
436 struct wininfo *w = &wininfo;
438 program_name = argv[0];
440 if (!setlocale (LC_ALL, ""))
441 fprintf (stderr, "%s: can not set locale properly\n", program_name);
442 user_encoding = nl_langinfo (CODESET);
443 if (user_encoding == NULL)
444 user_encoding = "unknown encoding";
446 memset (w, 0, sizeof(struct wininfo));
448 /* Handle our command line arguments */
449 for (i = 1; i < argc; i++) {
450 if (!strcmp (argv[i], "-help"))
452 if (!strcmp (argv[i], "-display") || !strcmp (argv[i], "-d")) {
454 Fatal_Error("-display requires argument");
455 display_name = argv[i];
458 if (!strcmp (argv[i], "-root")) {
462 if (!strcmp (argv[i], "-id")) {
464 Fatal_Error("-id requires argument");
465 window = strtoul(argv[i], NULL, 0);
468 if (!strcmp (argv[i], "-name")) {
470 Fatal_Error("-name requires argument");
471 window_name = argv[i];
474 if (!strcmp (argv[i], "-int")) {
475 window_id_format = "%ld";
478 if (!strcmp (argv[i], "-children")) {
482 if (!strcmp (argv[i], "-tree")) {
486 if (!strcmp (argv[i], "-stats")) {
490 if (!strcmp (argv[i], "-bits")) {
494 if (!strcmp (argv[i], "-events")) {
498 if (!strcmp (argv[i], "-wm")) {
502 if (!strcmp (argv[i], "-frame")) {
506 if (!strcmp (argv[i], "-size")) {
510 if (!strcmp (argv[i], "-shape")) {
514 if (!strcmp (argv[i], "-english")) {
518 if (!strcmp (argv[i], "-metric")) {
522 if (!strcmp (argv[i], "-all")) {
523 tree = stats = bits = events = wm = size = shape = 1;
529 Setup_Display_And_Screen (display_name, &dpy, &screen);
531 /* preload atoms we may need later */
532 Intern_Atom (dpy, "_NET_WM_NAME");
533 Intern_Atom (dpy, "UTF8_STRING");
535 Intern_Atom (dpy, "_NET_WM_DESKTOP");
536 Intern_Atom (dpy, "_NET_WM_WINDOW_TYPE");
537 Intern_Atom (dpy, "_NET_WM_STATE");
538 Intern_Atom (dpy, "_NET_WM_PID");
539 Intern_Atom (dpy, "_NET_FRAME_EXTENTS");
541 /* initialize scaling data */
545 window = screen->root;
546 else if (window_name) {
547 window = Window_With_Name (dpy, screen->root, window_name);
549 Fatal_Error ("No window with name \"%s\" exists!", window_name);
552 /* If no window selected on command line, let user pick one the hard way */
555 "xwininfo: Please select the window about which you\n"
556 " would like information by clicking the\n"
557 " mouse in that window.\n");
558 Intern_Atom (dpy, "_NET_VIRTUAL_ROOTS");
559 Intern_Atom (dpy, "WM_STATE");
560 window = Select_Window (dpy, screen, !frame);
564 * Do the actual displaying as per parameters
566 if (!(children || tree || bits || events || wm || size))
570 * make sure that the window is valid
573 xcb_get_geometry_cookie_t gg_cookie =
574 xcb_get_geometry (dpy, window);
576 w->geometry = xcb_get_geometry_reply(dpy, gg_cookie, &err);
582 Print_X_Error (dpy, err);
584 snprintf (badid, sizeof(badid), window_id_format, window);
585 Fatal_Error ("No such window with id %s.", badid);
589 /* Send requests to prefetch data we'll need */
591 w->net_wm_name_cookie = get_net_wm_name (dpy, window);
592 w->wm_name_cookie = xcb_icccm_get_wm_name (dpy, window);
593 if (children || tree)
594 w->tree_cookie = xcb_query_tree (dpy, window);
596 w->trans_coords_cookie =
597 xcb_translate_coordinates (dpy, window, w->geometry->root,
598 -(w->geometry->border_width),
599 -(w->geometry->border_width));
601 if (stats || bits || events)
602 w->attr_cookie = xcb_get_window_attributes (dpy, window);
604 w->normal_hints_cookie = xcb_icccm_get_wm_normal_hints (dpy, window);
606 w->hints_cookie = xcb_icccm_get_wm_hints(dpy, window);
608 atom_net_wm_desktop = Get_Atom (dpy, "_NET_WM_DESKTOP");
609 if (atom_net_wm_desktop) {
610 w->wm_desktop_cookie = xcb_get_property
611 (dpy, False, window, atom_net_wm_desktop,
612 XCB_ATOM_CARDINAL, 0, 4);
615 atom_net_wm_window_type = Get_Atom (dpy, "_NET_WM_WINDOW_TYPE");
616 if (atom_net_wm_window_type) {
617 w->wm_window_type_cookie = xcb_get_property
618 (dpy, False, window, atom_net_wm_window_type,
619 XCB_ATOM_ATOM, 0, BUFSIZ);
622 atom_net_wm_state = Get_Atom (dpy, "_NET_WM_STATE");
623 if (atom_net_wm_state) {
624 w->wm_state_cookie = xcb_get_property
625 (dpy, False, window, atom_net_wm_state,
626 XCB_ATOM_ATOM, 0, BUFSIZ);
629 atom_net_wm_pid = Get_Atom (dpy, "_NET_WM_PID");
630 if (atom_net_wm_pid) {
631 w->wm_pid_cookie = xcb_get_property
632 (dpy, False, window, atom_net_wm_pid,
633 XCB_ATOM_CARDINAL, 0, BUFSIZ);
634 w->wm_client_machine_cookie = xcb_get_property
635 (dpy, False, window, XCB_ATOM_WM_CLIENT_MACHINE,
636 XCB_GET_PROPERTY_TYPE_ANY, 0, BUFSIZ);
639 atom_net_frame_extents = Get_Atom (dpy, "_NET_FRAME_EXTENTS");
640 if (atom_net_frame_extents) {
641 w->frame_extents_cookie = xcb_get_property
642 (dpy, False, window, atom_net_frame_extents,
643 XCB_ATOM_CARDINAL, 0, 4 * 4);
647 w->zoom_cookie = xcb_icccm_get_wm_size_hints (dpy, window,
648 XCB_ATOM_WM_ZOOM_HINTS);
651 printf ("\nxwininfo: Window id: ");
652 Display_Window_Id (w, True);
653 if (children || tree)
654 Display_Tree_Info (w, tree);
656 Display_Stats_Info (w);
658 Display_Bits_Info (w);
660 Display_Events_Info (w);
664 Display_Size_Hints (w);
666 Display_Window_Shape (window);
670 xcb_disconnect (dpy);
672 if (iconv_from_utf8 && (iconv_from_utf8 != (iconv_t) -1)) {
673 iconv_close (iconv_from_utf8);
679 /* Ensure win_attributes field is filled in */
680 static xcb_get_window_attributes_reply_t *
681 fetch_win_attributes (struct wininfo *w)
683 if (!w->win_attributes) {
685 xcb_get_window_attributes_reply (dpy, w->attr_cookie, &err);
687 if (!w->win_attributes) {
688 Print_X_Error (dpy, err);
689 Fatal_Error ("Can't get window attributes.");
692 return w->win_attributes;
695 #ifndef USE_XCB_ICCCM
697 wm_size_hints_reply (xcb_connection_t *dpy, xcb_get_property_cookie_t cookie,
698 wm_size_hints_t *hints_return, xcb_generic_error_t **err)
700 xcb_get_property_reply_t *prop = xcb_get_property_reply (dpy, cookie, err);
703 if (!prop || (prop->type != XCB_ATOM_WM_SIZE_HINTS) ||
704 (prop->format != 32)) {
709 memset (hints_return, 0, sizeof(wm_size_hints_t));
711 length = xcb_get_property_value_length(prop);
712 if (length > sizeof(wm_size_hints_t))
713 length = sizeof(wm_size_hints_t);
714 memcpy (hints_return, xcb_get_property_value (prop), length);
720 #define xcb_icccm_get_wm_normal_hints_reply wm_size_hints_reply
721 #define xcb_icccm_get_wm_size_hints_reply wm_size_hints_reply
726 /* Ensure normal_hints field is filled in */
727 static xcb_size_hints_t *
728 fetch_normal_hints (struct wininfo *w, xcb_size_hints_t *hints_return)
730 xcb_size_hints_t hints;
732 if (!w->normal_hints) {
733 if (xcb_icccm_get_wm_normal_hints_reply (dpy, w->normal_hints_cookie,
735 w->normal_hints = malloc (sizeof(xcb_size_hints_t));
737 memcpy(w->normal_hints, &hints, sizeof(xcb_size_hints_t));
740 if (hints_return && w->normal_hints)
741 memcpy(hints_return, w->normal_hints, sizeof(xcb_size_hints_t));
742 return w->normal_hints;
747 * Lookup: lookup a code in a table.
749 static char _lookup_buffer[100];
752 LookupL (long code, const binding *table)
754 const char *name = NULL;
756 while (table->name) {
757 if (table->code == code) {
765 snprintf (_lookup_buffer, sizeof(_lookup_buffer),
766 "unknown (code = %ld. = 0x%lx)", code, code);
767 name = _lookup_buffer;
774 Lookup (int code, const binding *table)
776 return LookupL ((long)code, table);
780 * Routine to display a window id in dec/hex with name if window has one
782 * Requires wininfo members initialized: window, wm_name_cookie
786 Display_Window_Id (struct wininfo *w, Bool newline_wanted)
789 xcb_icccm_get_text_property_reply_t wmn_reply;
790 uint8_t got_reply = False;
792 xcb_get_property_reply_t *prop;
793 const char *wm_name = NULL;
794 unsigned int wm_name_len = 0;
795 xcb_atom_t wm_name_encoding = XCB_NONE;
797 printf (window_id_format, w->window); /* print id # in hex/dec */
802 if (w->window == screen->root) {
803 printf (" (the root window)");
805 /* Get window name if any */
806 prop = xcb_get_property_reply (dpy, w->net_wm_name_cookie, NULL);
807 if (prop && (prop->type != XCB_NONE)) {
808 wm_name = xcb_get_property_value (prop);
809 wm_name_len = xcb_get_property_value_length (prop);
810 wm_name_encoding = prop->type;
811 } else { /* No _NET_WM_NAME, check WM_NAME */
813 got_reply = xcb_icccm_get_wm_name_reply (dpy, w->wm_name_cookie,
816 wm_name = wmn_reply.name;
817 wm_name_len = wmn_reply.name_len;
818 wm_name_encoding = wmn_reply.encoding;
821 prop = xcb_get_property_reply (dpy, w->wm_name_cookie, NULL);
822 if (prop && (prop->type != XCB_NONE)) {
823 wm_name = xcb_get_property_value (prop);
824 wm_name_len = xcb_get_property_value_length (prop);
825 wm_name_encoding = prop->type;
829 if (wm_name_len == 0) {
830 printf (" (has no name)");
832 if (wm_name_encoding == XCB_ATOM_STRING) {
833 printf (" \"%.*s\"", wm_name_len, wm_name);
834 } else if (wm_name_encoding == atom_utf8_string) {
835 print_utf8 (" \"", (char *) wm_name, wm_name_len, "\"");
837 /* Encodings we don't support, including COMPOUND_TEXT */
838 const char *enc_name = Get_Atom_Name (dpy, wm_name_encoding);
840 printf (" (name in unsupported encoding %s)", enc_name);
842 printf (" (name in unsupported encoding ATOM 0x%x)",
849 xcb_icccm_get_text_property_reply_wipe (&wmn_reply);
863 * Display Stats on window
865 static const binding _window_classes[] = {
866 { XCB_WINDOW_CLASS_INPUT_OUTPUT, "InputOutput" },
867 { XCB_WINDOW_CLASS_INPUT_ONLY, "InputOnly" },
870 static const binding _map_states[] = {
871 { XCB_MAP_STATE_UNMAPPED, "IsUnMapped" },
872 { XCB_MAP_STATE_UNVIEWABLE, "IsUnviewable" },
873 { XCB_MAP_STATE_VIEWABLE, "IsViewable" },
876 static const binding _backing_store_states[] = {
877 { XCB_BACKING_STORE_NOT_USEFUL, "NotUseful" },
878 { XCB_BACKING_STORE_WHEN_MAPPED,"WhenMapped" },
879 { XCB_BACKING_STORE_ALWAYS, "Always" },
882 static const binding _bit_gravity_states[] = {
883 { XCB_GRAVITY_BIT_FORGET, "ForgetGravity" },
884 { XCB_GRAVITY_NORTH_WEST, "NorthWestGravity" },
885 { XCB_GRAVITY_NORTH, "NorthGravity" },
886 { XCB_GRAVITY_NORTH_EAST, "NorthEastGravity" },
887 { XCB_GRAVITY_WEST, "WestGravity" },
888 { XCB_GRAVITY_CENTER, "CenterGravity" },
889 { XCB_GRAVITY_EAST, "EastGravity" },
890 { XCB_GRAVITY_SOUTH_WEST, "SouthWestGravity" },
891 { XCB_GRAVITY_SOUTH, "SouthGravity" },
892 { XCB_GRAVITY_SOUTH_EAST, "SouthEastGravity" },
893 { XCB_GRAVITY_STATIC, "StaticGravity" },
896 static const binding _window_gravity_states[] = {
897 { XCB_GRAVITY_WIN_UNMAP, "UnmapGravity" },
898 { XCB_GRAVITY_NORTH_WEST, "NorthWestGravity" },
899 { XCB_GRAVITY_NORTH, "NorthGravity" },
900 { XCB_GRAVITY_NORTH_EAST, "NorthEastGravity" },
901 { XCB_GRAVITY_WEST, "WestGravity" },
902 { XCB_GRAVITY_CENTER, "CenterGravity" },
903 { XCB_GRAVITY_EAST, "EastGravity" },
904 { XCB_GRAVITY_SOUTH_WEST, "SouthWestGravity" },
905 { XCB_GRAVITY_SOUTH, "SouthGravity" },
906 { XCB_GRAVITY_SOUTH_EAST, "SouthEastGravity" },
907 { XCB_GRAVITY_STATIC, "StaticGravity" },
910 static const binding _visual_classes[] = {
911 { XCB_VISUAL_CLASS_STATIC_GRAY, "StaticGray" },
912 { XCB_VISUAL_CLASS_GRAY_SCALE, "GrayScale" },
913 { XCB_VISUAL_CLASS_STATIC_COLOR,"StaticColor" },
914 { XCB_VISUAL_CLASS_PSEUDO_COLOR,"PseudoColor" },
915 { XCB_VISUAL_CLASS_TRUE_COLOR, "TrueColor" },
916 { XCB_VISUAL_CLASS_DIRECT_COLOR,"DirectColor" },
920 * Requires wininfo members initialized:
921 * window, geometry, attr_cookie, trans_coords_cookie, normal_hints_cookie
924 Display_Stats_Info (struct wininfo *w)
926 xcb_translate_coordinates_reply_t *trans_coords;
927 xcb_get_window_attributes_reply_t *win_attributes;
928 xcb_size_hints_t hints;
930 int dw = screen->width_in_pixels, dh = screen->height_in_pixels;
931 int rx, ry, xright, ybelow;
932 int showright = 0, showbelow = 0;
933 xcb_window_t wmframe, parent;
936 xcb_translate_coordinates_reply (dpy, w->trans_coords_cookie, NULL);
938 Fatal_Error ("Can't get translated coordinates.");
940 rx = (int16_t)trans_coords->dst_x;
941 ry = (int16_t)trans_coords->dst_y;
944 xright = (dw - rx - w->geometry->border_width * 2 -
946 ybelow = (dh - ry - w->geometry->border_width * 2 -
947 w->geometry->height);
951 printf (" Absolute upper-left X: %s\n", xscale (rx));
952 printf (" Absolute upper-left Y: %s\n", yscale (ry));
953 printf (" Relative upper-left X: %s\n", xscale (w->geometry->x));
954 printf (" Relative upper-left Y: %s\n", yscale (w->geometry->y));
955 printf (" Width: %s\n", xscale (w->geometry->width));
956 printf (" Height: %s\n", yscale (w->geometry->height));
957 printf (" Depth: %d\n", w->geometry->depth);
959 win_attributes = fetch_win_attributes (w);
961 printf (" Visual: 0x%lx\n", (unsigned long) win_attributes->visual);
964 xcb_depth_iterator_t depth_iter;
965 xcb_visualtype_t *visual_type = NULL;
967 depth_iter = xcb_screen_allowed_depths_iterator (screen);
968 for (; depth_iter.rem; xcb_depth_next (&depth_iter)) {
969 xcb_visualtype_iterator_t visual_iter;
971 visual_iter = xcb_depth_visuals_iterator (depth_iter.data);
972 for (; visual_iter.rem; xcb_visualtype_next (&visual_iter)) {
973 if (screen->root_visual == visual_iter.data->visual_id) {
974 visual_type = visual_iter.data;
980 printf (" Visual Class: %s\n", Lookup (visual_type->_class,
984 printf (" Border width: %s\n", bscale (w->geometry->border_width));
985 printf (" Class: %s\n",
986 Lookup (win_attributes->_class, _window_classes));
987 printf (" Colormap: 0x%lx (%sinstalled)\n",
988 (unsigned long) win_attributes->colormap,
989 win_attributes->map_is_installed ? "" : "not ");
990 printf (" Bit Gravity State: %s\n",
991 Lookup (win_attributes->bit_gravity, _bit_gravity_states));
992 printf (" Window Gravity State: %s\n",
993 Lookup (win_attributes->win_gravity, _window_gravity_states));
994 printf (" Backing Store State: %s\n",
995 Lookup (win_attributes->backing_store, _backing_store_states));
996 printf (" Save Under State: %s\n",
997 win_attributes->save_under ? "yes" : "no");
998 printf (" Map State: %s\n",
999 Lookup (win_attributes->map_state, _map_states));
1000 printf (" Override Redirect State: %s\n",
1001 win_attributes->override_redirect ? "yes" : "no");
1002 printf (" Corners: +%d+%d -%d+%d -%d-%d +%d-%d\n",
1003 rx, ry, xright, ry, xright, ybelow, rx, ybelow);
1006 * compute geometry string that would recreate window
1008 printf (" -geometry ");
1010 /* compute size in appropriate units */
1011 if (!fetch_normal_hints (w, &hints))
1014 if ((hints.flags & XCB_ICCCM_SIZE_HINT_P_RESIZE_INC) &&
1015 (hints.width_inc != 0) && (hints.height_inc != 0)) {
1017 (XCB_ICCCM_SIZE_HINT_BASE_SIZE|XCB_ICCCM_SIZE_HINT_P_MIN_SIZE)) {
1018 if (hints.flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE) {
1019 w->geometry->width -= hints.base_width;
1020 w->geometry->height -= hints.base_height;
1022 /* ICCCM says MinSize is default for BaseSize */
1023 w->geometry->width -= hints.min_width;
1024 w->geometry->height -= hints.min_height;
1027 printf ("%dx%d", w->geometry->width/hints.width_inc,
1028 w->geometry->height/hints.height_inc);
1030 printf ("%dx%d", w->geometry->width, w->geometry->height);
1032 if (!(hints.flags & XCB_ICCCM_SIZE_HINT_P_WIN_GRAVITY))
1033 hints.win_gravity = XCB_GRAVITY_NORTH_WEST; /* per ICCCM */
1034 /* find our window manager frame, if any */
1035 for (wmframe = parent = w->window; parent != 0 ; wmframe = parent) {
1036 xcb_query_tree_cookie_t qt_cookie;
1037 xcb_query_tree_reply_t *tree;
1039 qt_cookie = xcb_query_tree (dpy, wmframe);
1040 tree = xcb_query_tree_reply (dpy, qt_cookie, &err);
1042 Print_X_Error (dpy, err);
1043 Fatal_Error ("Can't query window tree.");
1045 parent = tree->parent;
1047 if (parent == w->geometry->root || !parent)
1050 if (wmframe != w->window) {
1051 /* WM reparented, so find edges of the frame */
1052 /* Only works for ICCCM-compliant WMs, and then only if the
1053 window has corner gravity. We would need to know the original width
1054 of the window to correctly handle the other gravities. */
1055 xcb_get_geometry_cookie_t geom_cookie;
1056 xcb_get_geometry_reply_t *frame_geometry;
1058 geom_cookie = xcb_get_geometry (dpy, wmframe);
1059 frame_geometry = xcb_get_geometry_reply (dpy, geom_cookie, &err);
1061 if (!frame_geometry) {
1062 Print_X_Error (dpy, err);
1063 Fatal_Error ("Can't get frame geometry.");
1065 switch (hints.win_gravity) {
1066 case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST:
1067 case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST:
1068 case XCB_GRAVITY_WEST:
1069 rx = frame_geometry->x;
1071 switch (hints.win_gravity) {
1072 case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST:
1073 case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST:
1074 case XCB_GRAVITY_EAST:
1075 xright = dw - frame_geometry->x - frame_geometry->width -
1076 (2 * frame_geometry->border_width);
1078 switch (hints.win_gravity) {
1079 case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST:
1080 case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST:
1081 case XCB_GRAVITY_NORTH:
1082 ry = frame_geometry->y;
1084 switch (hints.win_gravity) {
1085 case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST:
1086 case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST:
1087 case XCB_GRAVITY_SOUTH:
1088 ybelow = dh - frame_geometry->y - frame_geometry->height -
1089 (2 * frame_geometry->border_width);
1091 free (frame_geometry);
1093 /* If edge gravity, offer a corner on that edge (because the application
1094 programmer cares about that edge), otherwise offer upper left unless
1095 some other corner is close to an edge of the screen.
1096 (For corner gravity, assume gravity was set by XWMGeometry.
1097 For CenterGravity, it doesn't matter.) */
1098 if (hints.win_gravity == XCB_GRAVITY_EAST ||
1099 (abs (xright) <= 100 && abs (xright) < abs (rx)
1100 && hints.win_gravity != XCB_GRAVITY_WEST))
1102 if (hints.win_gravity == XCB_GRAVITY_SOUTH ||
1103 (abs (ybelow) <= 100 && abs (ybelow) < abs (ry)
1104 && hints.win_gravity != XCB_GRAVITY_NORTH))
1108 printf ("-%d", xright);
1112 printf ("-%d", ybelow);
1120 * Display bits info:
1122 static const binding _gravities[] = {
1123 /* WARNING: the first two of these have the same value - see code */
1124 { XCB_GRAVITY_WIN_UNMAP, "UnMapGravity" },
1125 { XCB_GRAVITY_BIT_FORGET, "ForgetGravity" },
1126 { XCB_GRAVITY_NORTH_WEST, "NorthWestGravity" },
1127 { XCB_GRAVITY_NORTH, "NorthGravity" },
1128 { XCB_GRAVITY_NORTH_EAST, "NorthEastGravity" },
1129 { XCB_GRAVITY_WEST, "WestGravity" },
1130 { XCB_GRAVITY_CENTER, "CenterGravity" },
1131 { XCB_GRAVITY_EAST, "EastGravity" },
1132 { XCB_GRAVITY_SOUTH_WEST, "SouthWestGravity" },
1133 { XCB_GRAVITY_SOUTH, "SouthGravity" },
1134 { XCB_GRAVITY_SOUTH_EAST, "SouthEastGravity" },
1135 { XCB_GRAVITY_STATIC, "StaticGravity" },
1138 static const binding _backing_store_hint[] = {
1139 { XCB_BACKING_STORE_NOT_USEFUL, "NotUseful" },
1140 { XCB_BACKING_STORE_WHEN_MAPPED,"WhenMapped" },
1141 { XCB_BACKING_STORE_ALWAYS, "Always" },
1144 static const binding _bool[] = {
1150 * Requires wininfo members initialized:
1151 * window, attr_cookie (or win_attributes)
1154 Display_Bits_Info (struct wininfo * w)
1156 xcb_get_window_attributes_reply_t *win_attributes
1157 = fetch_win_attributes (w);
1160 printf (" Bit gravity: %s\n",
1161 Lookup (win_attributes->bit_gravity, _gravities+1));
1162 printf (" Window gravity: %s\n",
1163 Lookup (win_attributes->win_gravity, _gravities));
1164 printf (" Backing-store hint: %s\n",
1165 Lookup (win_attributes->backing_store, _backing_store_hint));
1166 printf (" Backing-planes to be preserved: 0x%lx\n",
1167 (unsigned long) win_attributes->backing_planes);
1168 printf (" Backing pixel: %ld\n",
1169 (unsigned long) win_attributes->backing_pixel);
1170 printf (" Save-unders: %s\n",
1171 Lookup (win_attributes->save_under, _bool));
1176 * Routine to display all events in an event mask
1178 static const binding _event_mask_names[] = {
1179 { XCB_EVENT_MASK_KEY_PRESS, "KeyPress" },
1180 { XCB_EVENT_MASK_KEY_RELEASE, "KeyRelease" },
1181 { XCB_EVENT_MASK_BUTTON_PRESS, "ButtonPress" },
1182 { XCB_EVENT_MASK_BUTTON_RELEASE, "ButtonRelease" },
1183 { XCB_EVENT_MASK_ENTER_WINDOW, "EnterWindow" },
1184 { XCB_EVENT_MASK_LEAVE_WINDOW, "LeaveWindow" },
1185 { XCB_EVENT_MASK_POINTER_MOTION, "PointerMotion" },
1186 { XCB_EVENT_MASK_POINTER_MOTION_HINT, "PointerMotionHint" },
1187 { XCB_EVENT_MASK_BUTTON_1_MOTION, "Button1Motion" },
1188 { XCB_EVENT_MASK_BUTTON_2_MOTION, "Button2Motion" },
1189 { XCB_EVENT_MASK_BUTTON_3_MOTION, "Button3Motion" },
1190 { XCB_EVENT_MASK_BUTTON_4_MOTION, "Button4Motion" },
1191 { XCB_EVENT_MASK_BUTTON_5_MOTION, "Button5Motion" },
1192 { XCB_EVENT_MASK_BUTTON_MOTION, "ButtonMotion" },
1193 { XCB_EVENT_MASK_KEYMAP_STATE, "KeymapState" },
1194 { XCB_EVENT_MASK_EXPOSURE, "Exposure" },
1195 { XCB_EVENT_MASK_VISIBILITY_CHANGE, "VisibilityChange" },
1196 { XCB_EVENT_MASK_STRUCTURE_NOTIFY, "StructureNotify" },
1197 { XCB_EVENT_MASK_RESIZE_REDIRECT, "ResizeRedirect" },
1198 { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, "SubstructureNotify" },
1199 { XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, "SubstructureRedirect" },
1200 { XCB_EVENT_MASK_FOCUS_CHANGE, "FocusChange" },
1201 { XCB_EVENT_MASK_PROPERTY_CHANGE, "PropertyChange" },
1202 { XCB_EVENT_MASK_COLOR_MAP_CHANGE, "ColormapChange" },
1203 { XCB_EVENT_MASK_OWNER_GRAB_BUTTON, "OwnerGrabButton" },
1207 Display_Event_Mask (long mask)
1211 for (bit=0, bit_mask=1; bit < sizeof(long)*8; bit++, bit_mask <<= 1)
1212 if (mask & bit_mask)
1214 LookupL (bit_mask, _event_mask_names));
1219 * Display info on events
1221 * Requires wininfo members initialized:
1222 * window, attr_cookie (or win_attributes)
1225 Display_Events_Info (struct wininfo *w)
1227 xcb_get_window_attributes_reply_t *win_attributes
1228 = fetch_win_attributes (w);
1231 printf (" Someone wants these events:\n");
1232 Display_Event_Mask (win_attributes->all_event_masks);
1234 printf (" Do not propagate these events:\n");
1235 Display_Event_Mask (win_attributes->do_not_propagate_mask);
1237 printf (" Override redirection?: %s\n",
1238 Lookup (win_attributes->override_redirect, _bool));
1242 /* left out visual stuff */
1243 /* left out colormap */
1244 /* left out map_installed */
1248 * Display root, parent, and (recursively) children information
1249 * recurse - true to show children information
1251 * Requires wininfo members initialized: window, tree_cookie
1254 Display_Tree_Info (struct wininfo *w, int recurse)
1256 display_tree_info_1 (w, recurse, 0);
1260 * level - recursion level
1263 display_tree_info_1 (struct wininfo *w, int recurse, int level)
1266 unsigned int num_children;
1267 xcb_query_tree_reply_t *tree;
1269 tree = xcb_query_tree_reply (dpy, w->tree_cookie, &err);
1271 Print_X_Error (dpy, err);
1272 Fatal_Error ("Can't query window tree.");
1276 struct wininfo rw, pw;
1277 rw.window = tree->root;
1278 rw.net_wm_name_cookie = get_net_wm_name (dpy, rw.window);
1279 rw.wm_name_cookie = xcb_icccm_get_wm_name (dpy, rw.window);
1280 pw.window = tree->parent;
1281 pw.net_wm_name_cookie = get_net_wm_name (dpy, pw.window);
1282 pw.wm_name_cookie = xcb_icccm_get_wm_name (dpy, pw.window);
1286 printf (" Root window id: ");
1287 Display_Window_Id (&rw, True);
1288 printf (" Parent window id: ");
1289 Display_Window_Id (&pw, True);
1292 num_children = xcb_query_tree_children_length (tree);
1294 if (level == 0 || num_children > 0) {
1296 for (j = 0; j < level; j++) printf (" ");
1297 printf ("%d child%s%s\n", num_children, num_children == 1 ? "" : "ren",
1298 num_children ? ":" : ".");
1301 if (num_children > 0) {
1302 xcb_window_t *child_list = xcb_query_tree_children (tree);
1303 struct wininfo *children
1304 = calloc (num_children, sizeof(struct wininfo));
1306 if (children == NULL)
1307 Fatal_Error ("Failed to allocate memory in display_tree_info");
1309 for (i = (int)num_children - 1; i >= 0; i--) {
1310 struct wininfo *cw = &children[i];
1312 cw->window = child_list[i];
1313 cw->net_wm_name_cookie = get_net_wm_name (dpy, child_list[i]);
1314 cw->wm_name_cookie = xcb_icccm_get_wm_name (dpy, child_list[i]);
1315 cw->wm_class_cookie = xcb_icccm_get_wm_class (dpy, child_list[i]);
1316 cw->geometry_cookie = xcb_get_geometry (dpy, child_list[i]);
1317 cw->trans_coords_cookie = xcb_translate_coordinates
1318 (dpy, child_list[i], tree->root, 0, 0);
1320 cw->tree_cookie = xcb_query_tree (dpy, child_list[i]);
1324 for (i = (int)num_children - 1; i >= 0; i--) {
1325 struct wininfo *cw = &children[i];
1326 Bool got_wm_class = False;
1327 char *instance_name = NULL, *class_name = NULL;
1328 int instance_name_len, class_name_len;
1329 #ifdef USE_XCB_ICCCM
1330 xcb_icccm_get_wm_class_reply_t classhint;
1332 xcb_get_property_reply_t *classprop;
1334 xcb_get_geometry_reply_t *geometry;
1337 for (j = 0; j < level; j++) printf (" ");
1338 Display_Window_Id (cw, False);
1341 #ifdef USE_XCB_ICCCM
1342 if (xcb_icccm_get_wm_class_reply (dpy, cw->wm_class_cookie,
1343 &classhint, NULL)) {
1344 got_wm_class = True;
1345 instance_name = classhint.instance_name;
1346 class_name = classhint.class_name;
1347 instance_name_len = strlen(instance_name);
1348 class_name_len = strlen(class_name);
1351 classprop = xcb_get_property_reply
1352 (dpy, cw->wm_class_cookie, NULL);
1354 if (classprop->type == XCB_ATOM_STRING &&
1355 classprop->format == 8) {
1356 int proplen = xcb_get_property_value_length (classprop);
1358 instance_name = xcb_get_property_value (classprop);
1359 instance_name_len = strnlen (instance_name, proplen);
1360 if (instance_name_len < proplen) {
1361 class_name = instance_name + instance_name_len + 1;
1362 class_name_len = strnlen
1363 (class_name, proplen - (instance_name_len + 1));
1366 got_wm_class = True;
1375 printf ("\"%.*s\" ", instance_name_len, instance_name);
1380 printf ("\"%.*s\") ", class_name_len, class_name);
1382 printf ("(none)) ");
1384 #ifdef USE_XCB_ICCCM
1385 xcb_icccm_get_wm_class_reply_wipe (&classhint);
1392 geometry = xcb_get_geometry_reply(dpy, cw->geometry_cookie, &err);
1394 xcb_translate_coordinates_reply_t *trans_coords;
1396 printf (" %ux%u+%d+%d", geometry->width, geometry->height,
1397 geometry->x, geometry->y);
1399 trans_coords = xcb_translate_coordinates_reply
1400 (dpy, cw->trans_coords_cookie, &err);
1403 int16_t abs_x = (int16_t) trans_coords->dst_x;
1404 int16_t abs_y = (int16_t) trans_coords->dst_y;
1405 int border = geometry->border_width;
1407 printf (" +%d+%d", abs_x - border, abs_y - border);
1408 free (trans_coords);
1410 Print_X_Error (dpy, err);
1415 Print_X_Error (dpy, err);
1420 display_tree_info_1 (cw, 1, level+1);
1427 free (tree); /* includes storage for child_list[] */
1432 * Display a set of size hints
1435 Display_Hints (xcb_size_hints_t *hints)
1439 flags = hints->flags;
1441 if (flags & XCB_ICCCM_SIZE_HINT_US_POSITION)
1442 printf (" User supplied location: %s, %s\n",
1443 xscale (hints->x), yscale (hints->y));
1445 if (flags & XCB_ICCCM_SIZE_HINT_P_POSITION)
1446 printf (" Program supplied location: %s, %s\n",
1447 xscale (hints->x), yscale (hints->y));
1449 if (flags & XCB_ICCCM_SIZE_HINT_US_SIZE) {
1450 printf (" User supplied size: %s by %s\n",
1451 xscale (hints->width), yscale (hints->height));
1454 if (flags & XCB_ICCCM_SIZE_HINT_P_SIZE)
1455 printf (" Program supplied size: %s by %s\n",
1456 xscale (hints->width), yscale (hints->height));
1458 if (flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE)
1459 printf (" Program supplied minimum size: %s by %s\n",
1460 xscale (hints->min_width), yscale (hints->min_height));
1462 if (flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE)
1463 printf (" Program supplied maximum size: %s by %s\n",
1464 xscale (hints->max_width), yscale (hints->max_height));
1466 if (flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE) {
1467 printf (" Program supplied base size: %s by %s\n",
1468 xscale (hints->base_width), yscale (hints->base_height));
1471 if (flags & XCB_ICCCM_SIZE_HINT_P_RESIZE_INC) {
1472 printf (" Program supplied x resize increment: %s\n",
1473 xscale (hints->width_inc));
1474 printf (" Program supplied y resize increment: %s\n",
1475 yscale (hints->height_inc));
1476 if (hints->width_inc != 0 && hints->height_inc != 0) {
1477 if (flags & XCB_ICCCM_SIZE_HINT_US_SIZE)
1478 printf (" User supplied size in resize increments: %s by %s\n",
1479 (xscale (hints->width / hints->width_inc)),
1480 (yscale (hints->height / hints->height_inc)));
1481 if (flags & XCB_ICCCM_SIZE_HINT_P_SIZE)
1482 printf (" Program supplied size in resize increments: %s by %s\n",
1483 (xscale (hints->width / hints->width_inc)),
1484 (yscale (hints->height / hints->height_inc)));
1485 if (flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE)
1486 printf (" Program supplied minimum size in resize increments: %s by %s\n",
1487 xscale (hints->min_width / hints->width_inc), yscale (hints->min_height / hints->height_inc));
1488 if (flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE)
1489 printf (" Program supplied base size in resize increments: %s by %s\n",
1490 (xscale (hints->base_width / hints->width_inc)),
1491 (yscale (hints->base_height / hints->height_inc)));
1495 if (flags & XCB_ICCCM_SIZE_HINT_P_ASPECT) {
1496 printf (" Program supplied min aspect ratio: %s/%s\n",
1497 xscale (hints->min_aspect_num), yscale (hints->min_aspect_den));
1498 printf (" Program supplied max aspect ratio: %s/%s\n",
1499 xscale (hints->max_aspect_num), yscale (hints->max_aspect_den));
1502 if (flags & XCB_ICCCM_SIZE_HINT_P_WIN_GRAVITY) {
1503 printf (" Program supplied window gravity: %s\n",
1504 Lookup (hints->win_gravity, _gravities));
1510 * Display Size Hints info
1513 Display_Size_Hints (struct wininfo *w)
1515 xcb_size_hints_t hints;
1518 if (!fetch_normal_hints (w, &hints))
1519 printf (" No normal window size hints defined\n");
1521 printf (" Normal window size hints:\n");
1522 Display_Hints (&hints);
1525 if (!xcb_icccm_get_wm_size_hints_reply (dpy, w->zoom_cookie, &hints, NULL))
1526 printf (" No zoom window size hints defined\n");
1528 printf (" Zoom window size hints:\n");
1529 Display_Hints (&hints);
1535 Display_Window_Shape (xcb_window_t window)
1537 const xcb_query_extension_reply_t *shape_query;
1538 xcb_shape_query_extents_cookie_t extents_cookie;
1539 xcb_shape_query_extents_reply_t *extents;
1541 shape_query = xcb_get_extension_data (dpy, &xcb_shape_id);
1542 if (!shape_query->present)
1547 extents_cookie = xcb_shape_query_extents (dpy, window);
1548 extents = xcb_shape_query_extents_reply (dpy, extents_cookie, &err);
1552 Print_X_Error (dpy, err);
1555 printf (" No window shape defined\n");
1556 printf (" No border shape defined\n");
1561 if (!extents->bounding_shaped)
1562 printf (" No window shape defined\n");
1564 printf (" Window shape extents: %sx%s",
1565 xscale (extents->bounding_shape_extents_width),
1566 yscale (extents->bounding_shape_extents_height));
1568 xscale (extents->bounding_shape_extents_x),
1569 yscale (extents->bounding_shape_extents_y));
1571 if (!extents->clip_shaped)
1572 printf (" No border shape defined\n");
1574 printf (" Border shape extents: %sx%s",
1575 xscale (extents->clip_shape_extents_width),
1576 yscale (extents->clip_shape_extents_height));
1578 xscale (extents->clip_shape_extents_x),
1579 yscale (extents->clip_shape_extents_y));
1586 * Display Window Manager Info
1588 * Requires wininfo members initialized:
1589 * window, hints_cookie
1591 static const binding _state_hints[] = {
1592 { XCB_ICCCM_WM_STATE_WITHDRAWN, "Withdrawn State" },
1593 { XCB_ICCCM_WM_STATE_NORMAL, "Normal State" },
1594 { XCB_ICCCM_WM_STATE_ICONIC, "Iconic State" },
1595 /* xwininfo previously also reported the ZoomState & InactiveState,
1596 but ICCCM declared those obsolete long ago */
1599 #ifndef USE_XCB_ICCCM
1601 wm_hints_reply (xcb_connection_t *dpy, xcb_get_property_cookie_t cookie,
1602 wm_hints_t *hints_return, xcb_generic_error_t **err)
1604 xcb_get_property_reply_t *prop = xcb_get_property_reply (dpy, cookie, err);
1607 if (!prop || (prop->type != XCB_ATOM_WM_HINTS) || (prop->format != 32)) {
1612 memset (hints_return, 0, sizeof(wm_hints_t));
1614 length = xcb_get_property_value_length(prop);
1615 if (length > sizeof(wm_hints_t))
1616 length = sizeof(wm_hints_t);
1617 memcpy (hints_return, xcb_get_property_value (prop), length);
1623 #define xcb_icccm_get_wm_hints_reply wm_hints_reply
1627 Display_WM_Info (struct wininfo *w)
1629 xcb_icccm_wm_hints_t wmhints;
1631 xcb_get_property_reply_t *prop;
1635 if (!xcb_icccm_get_wm_hints_reply(dpy, w->hints_cookie, &wmhints, &err))
1637 printf (" No window manager hints defined\n");
1639 Print_X_Error (dpy, err);
1642 flags = wmhints.flags;
1644 printf (" Window manager hints:\n");
1646 if (flags & XCB_ICCCM_WM_HINT_INPUT)
1647 printf (" Client accepts input or input focus: %s\n",
1648 Lookup (wmhints.input, _bool));
1650 if (flags & XCB_ICCCM_WM_HINT_ICON_WINDOW) {
1652 iw.window = wmhints.icon_window;
1653 iw.net_wm_name_cookie = get_net_wm_name (dpy, iw.window);
1654 iw.wm_name_cookie = xcb_icccm_get_wm_name (dpy, iw.window);
1656 printf (" Icon window id: ");
1657 Display_Window_Id (&iw, True);
1660 if (flags & XCB_ICCCM_WM_HINT_ICON_POSITION)
1661 printf (" Initial icon position: %s, %s\n",
1662 xscale (wmhints.icon_x), yscale (wmhints.icon_y));
1664 if (flags & XCB_ICCCM_WM_HINT_STATE)
1665 printf (" Initial state is %s\n",
1666 Lookup (wmhints.initial_state, _state_hints));
1668 if (atom_net_wm_desktop) {
1669 prop = xcb_get_property_reply (dpy, w->wm_desktop_cookie, NULL);
1670 if (prop && (prop->type != XCB_NONE)) {
1671 uint32_t *desktop = xcb_get_property_value (prop);
1672 if (*desktop == 0xFFFFFFFF) {
1673 printf (" Displayed on all desktops\n");
1675 printf (" Displayed on desktop %d\n", *desktop);
1681 if (atom_net_wm_window_type) {
1682 prop = xcb_get_property_reply (dpy, w->wm_window_type_cookie,
1684 if (prop && (prop->type != XCB_NONE) && (prop->value_len > 0)) {
1685 xcb_atom_t *atoms = xcb_get_property_value (prop);
1686 int atom_count = prop->value_len;
1688 if (atom_count > 0) {
1689 printf (" Window type:\n");
1690 for (i = 0; i < atom_count; i++) {
1691 const char *atom_name = Get_Atom_Name (dpy, atoms[i]);
1694 print_friendly_name (" %s\n", atom_name,
1695 "_NET_WM_WINDOW_TYPE_");
1697 printf (" (unresolvable ATOM 0x%x)\n",
1706 if (atom_net_wm_state) {
1707 prop = xcb_get_property_reply (dpy, w->wm_state_cookie, NULL);
1708 if (prop && (prop->type != XCB_NONE) && (prop->value_len > 0)) {
1709 xcb_atom_t *atoms = xcb_get_property_value (prop);
1710 int atom_count = prop->value_len;
1712 if (atom_count > 0) {
1713 printf (" Window state:\n");
1714 for (i = 0; i < atom_count; i++) {
1715 const char *atom_name = Get_Atom_Name (dpy, atoms[i]);
1718 print_friendly_name (" %s\n", atom_name,
1721 printf (" (unresolvable ATOM 0x%x)\n",
1730 if (atom_net_wm_pid) {
1731 printf (" Process id: ");
1732 prop = xcb_get_property_reply (dpy, w->wm_pid_cookie, NULL);
1733 if (prop && (prop->type == XCB_ATOM_CARDINAL)) {
1734 uint32_t *pid = xcb_get_property_value (prop);
1735 printf ("%d", *pid);
1737 printf ("(unknown)");
1741 prop = xcb_get_property_reply (dpy, w->wm_client_machine_cookie, NULL);
1742 if (prop && (prop->type == XCB_ATOM_STRING)) {
1743 const char *hostname = xcb_get_property_value (prop);
1744 int hostname_len = xcb_get_property_value_length (prop);
1745 printf (" on host %.*s", hostname_len, hostname);
1751 if (atom_net_frame_extents) {
1752 prop = xcb_get_property_reply (dpy, w->frame_extents_cookie, NULL);
1753 if (prop && (prop->type == XCB_ATOM_CARDINAL)
1754 && (prop->value_len == 4)) {
1755 uint32_t *extents = xcb_get_property_value (prop);
1757 printf (" Frame extents: %d, %d, %d, %d\n",
1758 extents[0], extents[1], extents[2], extents[3]);
1764 /* Frees all members of a wininfo struct, but not the struct itself */
1766 wininfo_wipe (struct wininfo *w)
1769 free (w->win_attributes);
1770 free (w->normal_hints);
1773 /* Gets UTF-8 encoded EMWH property _NET_WM_NAME for a window */
1774 static xcb_get_property_cookie_t
1775 get_net_wm_name (xcb_connection_t *dpy, xcb_window_t win)
1777 if (!atom_net_wm_name)
1778 atom_net_wm_name = Get_Atom (dpy, "_NET_WM_NAME");
1780 if (!atom_utf8_string)
1781 atom_utf8_string = Get_Atom (dpy, "UTF8_STRING");
1783 if (atom_net_wm_name && atom_utf8_string)
1784 return xcb_get_property (dpy, False, win, atom_net_wm_name,
1785 atom_utf8_string, 0, BUFSIZ);
1787 xcb_get_property_cookie_t dummy = { 0 };
1792 /* [Copied from code added by Yang Zhao to xprop/xprop.c]
1794 * Validate a string as UTF-8 encoded according to RFC 3629
1796 * Simply, a unicode code point (up to 21-bits long) is encoded as follows:
1798 * Char. number range | UTF-8 octet sequence
1799 * (hexadecimal) | (binary)
1800 * --------------------+---------------------------------------------
1801 * 0000 0000-0000 007F | 0xxxxxxx
1802 * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
1803 * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
1804 * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
1806 * Validation is done left-to-right, and an error condition, if any, refers to
1807 * only the left-most problem in the string.
1810 * UTF8_VALID: Valid UTF-8 encoded string
1811 * UTF8_OVERLONG: Using more bytes than needed for a code point
1812 * UTF8_SHORT_TAIL: Not enough bytes in a multi-byte sequence
1813 * UTF8_LONG_TAIL: Too many bytes in a multi-byte sequence
1814 * UTF8_FORBIDDEN_VALUE: Forbidden prefix or code point outside 0x10FFFF
1816 #define UTF8_VALID 0
1817 #define UTF8_FORBIDDEN_VALUE 1
1818 #define UTF8_OVERLONG 2
1819 #define UTF8_SHORT_TAIL 3
1820 #define UTF8_LONG_TAIL 4
1822 is_valid_utf8 (const char *string, int len)
1824 unsigned long codepoint;
1829 for (i = 0; i < len; i++) {
1830 c = (unsigned char) string[i];
1832 /* Order of type check:
1833 * - Single byte code point
1834 * - Non-starting byte of multi-byte sequence
1835 * - Start of 2-byte sequence
1836 * - Start of 3-byte sequence
1837 * - Start of 4-byte sequence
1840 if (rem > 0) return UTF8_SHORT_TAIL;
1843 } else if ((c & 0xC0) == 0x80) {
1844 if (rem == 0) return UTF8_LONG_TAIL;
1846 codepoint |= (c & 0x3F) << (rem * 6);
1847 if (codepoint == 0) return UTF8_OVERLONG;
1848 } else if ((c & 0xE0) == 0xC0) {
1849 if (rem > 0) return UTF8_SHORT_TAIL;
1851 codepoint = (c & 0x1F) << 6;
1852 if (codepoint == 0) return UTF8_OVERLONG;
1853 } else if ((c & 0xF0) == 0xE0) {
1854 if (rem > 0) return UTF8_SHORT_TAIL;
1856 codepoint = (c & 0x0F) << 12;
1857 } else if ((c & 0xF8) == 0xF0) {
1858 if (rem > 0) return UTF8_SHORT_TAIL;
1860 codepoint = (c & 0x07) << 18;
1861 if (codepoint > 0x10FFFF) return UTF8_FORBIDDEN_VALUE;
1863 return UTF8_FORBIDDEN_VALUE;
1870 * Converts a UTF-8 encoded string to the current locale encoding,
1871 * if possible, and prints it, with prefix before and suffix after.
1872 * Length of the string is specified in bytes, or -1 for going until '\0'
1875 print_utf8 (const char *prefix, char *u8str, size_t length, const char *suffix)
1877 size_t inlen = length;
1880 inlen = strlen (u8str);
1883 if (is_valid_utf8 (u8str, inlen) != UTF8_VALID) {
1884 printf (" (invalid UTF8_STRING)");
1888 if (strcmp (user_encoding, "UTF-8") == 0) {
1889 /* Don't need to convert */
1890 printf ("%s", prefix);
1891 fwrite (u8str, 1, inlen, stdout);
1892 printf ("%s", suffix);
1897 if (!iconv_from_utf8) {
1898 iconv_from_utf8 = iconv_open (user_encoding, "UTF-8");
1901 if (iconv_from_utf8 != (iconv_t) -1) {
1904 char convbuf[BUFSIZ];
1907 printf ("%s", prefix);
1909 char *outp = convbuf;
1910 size_t outlen = sizeof(convbuf);
1912 convres = iconv (iconv_from_utf8, &inp, &inlen, &outp, &outlen);
1914 if ((convres == -1) && (errno == E2BIG)) {
1920 fwrite (convbuf, 1, sizeof(convbuf) - outlen, stdout);
1922 printf (" (failure in conversion from UTF8_STRING to %s)",
1926 printf ("%s", suffix);
1928 printf (" (can't load iconv conversion for UTF8_STRING to %s)",
1932 printf (" (can't convert UTF8_STRING to %s)", user_encoding);
1937 * Takes a string such as an atom name, strips the prefix, converts
1938 * underscores to spaces, lowercases all but the first letter of each word,
1942 print_friendly_name (const char *format, const char *string,
1945 const char *name_start = string;
1946 char *lowered_name, *n;
1947 int prefix_len = strlen (prefix);
1949 if (strncmp (name_start, prefix, prefix_len) == 0) {
1950 name_start += prefix_len;
1953 lowered_name = strdup (name_start);
1957 for (n = lowered_name ; *n != 0 ; n++) {
1967 name_start = lowered_name;
1970 printf (format, name_start);
1971 free (lowered_name);