diff options
Diffstat (limited to 'apps/xwininfo/xwininfo.c')
-rw-r--r-- | apps/xwininfo/xwininfo.c | 3955 |
1 files changed, 1983 insertions, 1972 deletions
diff --git a/apps/xwininfo/xwininfo.c b/apps/xwininfo/xwininfo.c index b0c13fd13..bb9469956 100644 --- a/apps/xwininfo/xwininfo.c +++ b/apps/xwininfo/xwininfo.c @@ -1,1972 +1,1983 @@ -/* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ -/* - -Copyright 1987, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL -INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING -FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION -WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -Except as contained in this notice, the name of a copyright holder -shall not be used in advertising or otherwise to promote the sale, use -or other dealings in this Software without prior written authorization -of the copyright holder. - -*/ - - -/* - * xwininfo.c - MIT Project Athena, X Window system window - * information utility. - * - * - * This program will report all relevant information - * about a specific window. - * - * Author: Mark Lillibridge, MIT Project Athena - * 16-Jun-87 - */ - -#include "config.h" - -#include <xcb/xcb.h> -#include <xcb/xproto.h> -#ifdef USE_XCB_ICCCM -# include <xcb/xcb_icccm.h> -#endif -#include <xcb/shape.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <locale.h> -#include <langinfo.h> -#ifdef HAVE_ICONV -# include <iconv.h> -#endif -#include <ctype.h> -#include <errno.h> - -#ifndef HAVE_STRNLEN -#include "strnlen.h" -#endif - -/* Include routines to handle parsing defaults */ -#include "dsimple.h" - -typedef struct { - long code; - const char *name; -} binding; - -#ifndef USE_XCB_ICCCM -/* Once xcb-icccm's API is stable, this should be replaced by - xcb_size_hints_t & xcb_size_hints_flags_t */ -typedef struct { - /** User specified flags */ - uint32_t flags; - /** User-specified position */ - int32_t x, y; - /** User-specified size */ - int32_t width, height; - /** Program-specified minimum size */ - int32_t min_width, min_height; - /** Program-specified maximum size */ - int32_t max_width, max_height; - /** Program-specified resize increments */ - int32_t width_inc, height_inc; - /** Program-specified minimum aspect ratios */ - int32_t min_aspect_num, min_aspect_den; - /** Program-specified maximum aspect ratios */ - int32_t max_aspect_num, max_aspect_den; - /** Program-specified base size */ - int32_t base_width, base_height; - /** Program-specified window gravity */ - uint32_t win_gravity; -} wm_size_hints_t; - -# define xcb_size_hints_t wm_size_hints_t - -typedef struct { - /** Marks which fields in this structure are defined */ - int32_t flags; - /** Does this application rely on the window manager to get keyboard - input? */ - uint32_t input; - /** See below */ - int32_t initial_state; - /** Pixmap to be used as icon */ - xcb_pixmap_t icon_pixmap; - /** Window to be used as icon */ - xcb_window_t icon_window; - /** Initial position of icon */ - int32_t icon_x, icon_y; - /** Icon mask bitmap */ - xcb_pixmap_t icon_mask; - /* Identifier of related window group */ - xcb_window_t window_group; -} wm_hints_t; - -#define xcb_icccm_wm_hints_t wm_hints_t - -enum { - /* xcb_size_hints_flags_t */ - XCB_ICCCM_SIZE_HINT_US_POSITION = 1 << 0, - XCB_ICCCM_SIZE_HINT_US_SIZE = 1 << 1, - XCB_ICCCM_SIZE_HINT_P_POSITION = 1 << 2, - XCB_ICCCM_SIZE_HINT_P_SIZE = 1 << 3, - XCB_ICCCM_SIZE_HINT_P_MIN_SIZE = 1 << 4, - XCB_ICCCM_SIZE_HINT_P_MAX_SIZE = 1 << 5, - XCB_ICCCM_SIZE_HINT_P_RESIZE_INC = 1 << 6, - XCB_ICCCM_SIZE_HINT_P_ASPECT = 1 << 7, - XCB_ICCCM_SIZE_HINT_BASE_SIZE = 1 << 8, - XCB_ICCCM_SIZE_HINT_P_WIN_GRAVITY = 1 << 9, - /* xcb_wm_state_t */ - XCB_ICCCM_WM_STATE_WITHDRAWN = 0, - XCB_ICCCM_WM_STATE_NORMAL = 1, - XCB_ICCCM_WM_STATE_ICONIC = 3, - /* xcb_wm_t */ - XCB_ICCCM_WM_HINT_INPUT = (1L << 0), - XCB_ICCCM_WM_HINT_STATE = (1L << 1), - XCB_ICCCM_WM_HINT_ICON_PIXMAP = (1L << 2), - XCB_ICCCM_WM_HINT_ICON_WINDOW = (1L << 3), - XCB_ICCCM_WM_HINT_ICON_POSITION = (1L << 4), - XCB_ICCCM_WM_HINT_ICON_MASK = (1L << 5), - XCB_ICCCM_WM_HINT_WINDOW_GROUP = (1L << 6), - XCB_ICCCM_WM_HINT_X_URGENCY = (1L << 8) -}; - -/* Once xcb-icccm's API is stable, these should be replaced by calls to it */ -# define GET_TEXT_PROPERTY(Dpy, Win, Atom) \ - xcb_get_property (Dpy, False, Win, Atom, XCB_GET_PROPERTY_TYPE_ANY, 0, BUFSIZ) -# define xcb_icccm_get_wm_name(Dpy, Win) \ - GET_TEXT_PROPERTY(Dpy, Win, XCB_ATOM_WM_NAME) - -# define xcb_icccm_get_wm_class(Dpy, Win) \ - xcb_get_property (Dpy, False, Win, XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 0, BUFSIZ) -# define xcb_icccm_get_wm_hints(Dpy, Win) \ - xcb_get_property(Dpy, False, Win, XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 0, 9) - -# define xcb_icccm_get_wm_size_hints(Dpy, Win, Atom) \ - xcb_get_property (Dpy, False, Win, Atom, XCB_ATOM_WM_SIZE_HINTS, 0, 18) -# define xcb_icccm_get_wm_normal_hints(Dpy, Win) \ - xcb_icccm_get_wm_size_hints(Dpy, Win, XCB_ATOM_WM_NORMAL_HINTS) -#endif - -/* Possibly in xcb-emwh in the future? */ -static xcb_atom_t atom_net_wm_name, atom_utf8_string; -static xcb_atom_t atom_net_wm_desktop, atom_net_wm_window_type, - atom_net_wm_state, atom_net_wm_pid, atom_net_frame_extents; -static xcb_get_property_cookie_t get_net_wm_name (xcb_connection_t *, - xcb_window_t); - -/* Information we keep track of for each window to allow prefetching/reusing */ -struct wininfo { - xcb_window_t window; - - /* cookies for requests we've sent */ - xcb_get_geometry_cookie_t geometry_cookie; - xcb_get_property_cookie_t net_wm_name_cookie; - xcb_get_property_cookie_t wm_name_cookie; - xcb_get_property_cookie_t wm_class_cookie; - xcb_translate_coordinates_cookie_t trans_coords_cookie; - xcb_query_tree_cookie_t tree_cookie; - xcb_get_window_attributes_cookie_t attr_cookie; - xcb_get_property_cookie_t normal_hints_cookie; - xcb_get_property_cookie_t hints_cookie; - xcb_get_property_cookie_t wm_desktop_cookie; - xcb_get_property_cookie_t wm_window_type_cookie; - xcb_get_property_cookie_t wm_state_cookie; - xcb_get_property_cookie_t wm_pid_cookie; - xcb_get_property_cookie_t wm_client_machine_cookie; - xcb_get_property_cookie_t frame_extents_cookie; - xcb_get_property_cookie_t zoom_cookie; - - /* cached results from previous requests */ - xcb_get_geometry_reply_t * geometry; - xcb_get_window_attributes_reply_t * win_attributes; - xcb_size_hints_t * normal_hints; -}; - -static void scale_init (xcb_screen_t *scrn); -static char *nscale (int, int, int, char *, size_t); -static char *xscale (int); -static char *yscale (int); -static char *bscale (int); -int main (int, char **); -static const char *LookupL (long, const binding *); -static const char *Lookup (int, const binding *); -static void Display_Window_Id (struct wininfo *, Bool); -static void Display_Stats_Info (struct wininfo *); -static void Display_Bits_Info (struct wininfo *); -static void Display_Event_Mask (long); -static void Display_Events_Info (struct wininfo *); -static void Display_Tree_Info (struct wininfo *, int); -static void display_tree_info_1 (struct wininfo *, int, int); -static void Display_Hints (xcb_size_hints_t *); -static void Display_Size_Hints (struct wininfo *); -static void Display_Window_Shape (xcb_window_t); -static void Display_WM_Info (struct wininfo *); -static void wininfo_wipe (struct wininfo *); - -static const char *window_id_format = "0x%lx"; - -#ifdef HAVE_ICONV -static iconv_t iconv_from_utf8; -#endif -static const char *user_encoding; -static void print_utf8 (const char *, char *, size_t, const char *); -static void print_friendly_name (const char *, const char *, const char *); - -static xcb_connection_t *dpy; -static xcb_screen_t *screen; -static xcb_generic_error_t *err; - -#ifndef HAVE_STRLCAT -static size_t strlcat (char *dst, const char *src, size_t dstsize) -{ - size_t sd = strlen (dst); - size_t ss = strlen (src); - size_t s = sd + ss; - - if (s < dstsize) { - strcpy (dst + sd, src); - } else { - strncpy (dst + sd, src, dstsize-sd-1); - dst[dstsize] = '\0'; - } - return s; -} -#endif - -/* - * Report the syntax for calling xwininfo: - */ -static void -usage (void) -{ - fprintf (stderr, - "usage: %s [-options ...]\n\n" - "where options include:\n" - " -help print this message\n" - " -display host:dpy X server to contact\n" - " -root use the root window\n" - " -id windowid use the window with the specified id\n" - " -name windowname use the window with the specified name\n" - " -int print window id in decimal\n" - " -children print parent and child identifiers\n" - " -tree print children identifiers recursively\n" - " -stats print window geometry [DEFAULT]\n" - " -bits print window pixel information\n" - " -events print events selected for on window\n" - " -size print size hints\n" - " -wm print window manager hints\n" - " -shape print shape extents\n" - " -frame don't ignore window manager frames\n" - " -english print sizes in english units\n" - " -metric print sizes in metric units\n" - " -all -tree, -stats, -bits, -events, -wm, -size, -shape\n" - "\n", - program_name); - exit (1); -} - -/* - * pixel to inch, metric converter. - * Hacked in by Mark W. Eichin <eichin@athena> [eichin:19880619.1509EST] - * - * Simply put: replace the old numbers with string print calls. - * Returning a local string is ok, since we only ever get called to - * print one x and one y, so as long as they don't collide, they're - * fine. This is not meant to be a general purpose routine. - * - */ - -static int xp = 0, xmm = 0; -static int yp = 0, ymm = 0; -static int bp = 0, bmm = 0; -static int english = 0, metric = 0; - -static void -scale_init (xcb_screen_t *screen) -{ - xp = screen->width_in_pixels; - yp = screen->height_in_pixels; - xmm = screen->width_in_millimeters; - ymm = screen->height_in_millimeters; - bp = xp + yp; - bmm = xmm + ymm; -} - -#define MILE (5280*12) -#define YARD (3*12) -#define FOOT (12) - -static char * -nscale (int n, int np, int nmm, char *nbuf, size_t nbufsize) -{ - int s; - snprintf (nbuf, nbufsize, "%d", n); - - if (metric||english) { - s = strlcat (nbuf, " (", nbufsize); - - if (metric) { - snprintf (nbuf+s, nbufsize-s, "%.2f mm%s", - ((double) n) * nmm/np , english ? "; " : ""); - } - if (english) { - double inch_frac; - Bool printed_anything = False; - int mi, yar, ft, inr; - - inch_frac = ((double) n)*(nmm/25.4)/np; - inr = (int)inch_frac; - inch_frac -= (double)inr; - if (inr >= MILE) { - mi = inr/MILE; - inr %= MILE; - s = strlen (nbuf); - snprintf (nbuf+s, nbufsize-s, "%d %s(?!?)", - mi, (mi == 1) ? "mile" : "miles"); - printed_anything = True; - } - if (inr >= YARD) { - yar = inr/YARD; - inr %= YARD; - if (printed_anything) - strlcat (nbuf, ", ", nbufsize); - s = strlen (nbuf); - snprintf (nbuf+s, nbufsize-s, "%d %s", - yar, (yar==1) ? "yard" : "yards"); - printed_anything = True; - } - if (inr >= FOOT) { - ft = inr/FOOT; - inr %= FOOT; - if (printed_anything) - strlcat (nbuf, ", ", nbufsize); - s = strlen (nbuf); - snprintf (nbuf+s, nbufsize-s, "%d %s", - ft, (ft==1) ? "foot" : "feet"); - printed_anything = True; - } - if (!printed_anything || inch_frac != 0.0 || inr != 0) { - if (printed_anything) - strlcat (nbuf, ", ", nbufsize); - s = strlen (nbuf); - snprintf (nbuf+s, nbufsize-s, "%.2f inches", inr+inch_frac); - } - } - strlcat (nbuf, ")", nbufsize); - } - return (nbuf); -} - -static char xbuf[BUFSIZ]; -static char * -xscale (int x) -{ - return (nscale (x, xp, xmm, xbuf, sizeof(xbuf))); -} - -static char ybuf[BUFSIZ]; -static char * -yscale (int y) -{ - return (nscale (y, yp, ymm, ybuf, sizeof(ybuf))); -} - -static char bbuf[BUFSIZ]; -static char * -bscale (int b) -{ - return (nscale (b, bp, bmm, bbuf, sizeof(bbuf))); -} - -/* end of pixel to inch, metric converter */ - -int -main (int argc, char **argv) -{ - register int i; - int tree = 0, stats = 0, bits = 0, events = 0, wm = 0, size = 0, shape = 0; - int frame = 0, children = 0; - int use_root = 0; - xcb_window_t window = 0; - char *display_name = NULL; - const char *window_name = NULL; - struct wininfo wininfo; - struct wininfo *w = &wininfo; - - program_name = argv[0]; - - if (!setlocale (LC_ALL, "")) - fprintf (stderr, "%s: can not set locale properly\n", program_name); - user_encoding = nl_langinfo (CODESET); - if (user_encoding == NULL) - user_encoding = "unknown encoding"; - - memset (w, 0, sizeof(struct wininfo)); - - /* Handle our command line arguments */ - for (i = 1; i < argc; i++) { - if (!strcmp (argv[i], "-help")) - usage (); - if (!strcmp (argv[i], "-display") || !strcmp (argv[i], "-d")) { - if (++i >= argc) - Fatal_Error("-display requires argument"); - display_name = argv[i]; - continue; - } - if (!strcmp (argv[i], "-root")) { - use_root = 1; - continue; - } - if (!strcmp (argv[i], "-id")) { - if (++i >= argc) - Fatal_Error("-id requires argument"); - window = strtoul(argv[i], NULL, 0); - continue; - } - if (!strcmp (argv[i], "-name")) { - if (++i >= argc) - Fatal_Error("-name requires argument"); - window_name = argv[i]; - continue; - } - if (!strcmp (argv[i], "-int")) { - window_id_format = "%ld"; - continue; - } - if (!strcmp (argv[i], "-children")) { - children = 1; - continue; - } - if (!strcmp (argv[i], "-tree")) { - tree = 1; - continue; - } - if (!strcmp (argv[i], "-stats")) { - stats = 1; - continue; - } - if (!strcmp (argv[i], "-bits")) { - bits = 1; - continue; - } - if (!strcmp (argv[i], "-events")) { - events = 1; - continue; - } - if (!strcmp (argv[i], "-wm")) { - wm = 1; - continue; - } - if (!strcmp (argv[i], "-frame")) { - frame = 1; - continue; - } - if (!strcmp (argv[i], "-size")) { - size = 1; - continue; - } - if (!strcmp (argv[i], "-shape")) { - shape = 1; - continue; - } - if (!strcmp (argv[i], "-english")) { - english = 1; - continue; - } - if (!strcmp (argv[i], "-metric")) { - metric = 1; - continue; - } - if (!strcmp (argv[i], "-all")) { - tree = stats = bits = events = wm = size = shape = 1; - continue; - } - usage (); - } - - Setup_Display_And_Screen (display_name, &dpy, &screen); - - /* preload atoms we may need later */ - Intern_Atom (dpy, "_NET_WM_NAME"); - Intern_Atom (dpy, "UTF8_STRING"); - if (wm) { - Intern_Atom (dpy, "_NET_WM_DESKTOP"); - Intern_Atom (dpy, "_NET_WM_WINDOW_TYPE"); - Intern_Atom (dpy, "_NET_WM_STATE"); - Intern_Atom (dpy, "_NET_WM_PID"); - Intern_Atom (dpy, "_NET_FRAME_EXTENTS"); - } - /* initialize scaling data */ - scale_init(screen); - - if (use_root) - window = screen->root; - else if (window_name) { - window = Window_With_Name (dpy, screen->root, window_name); - if (!window) - Fatal_Error ("No window with name \"%s\" exists!", window_name); - } - - /* If no window selected on command line, let user pick one the hard way */ - if (!window) { - printf ("\n" - "xwininfo: Please select the window about which you\n" - " would like information by clicking the\n" - " mouse in that window.\n"); - Intern_Atom (dpy, "_NET_VIRTUAL_ROOTS"); - Intern_Atom (dpy, "WM_STATE"); - window = Select_Window (dpy, screen, !frame); - } - - /* - * Do the actual displaying as per parameters - */ - if (!(children || tree || bits || events || wm || size)) - stats = 1; - - /* - * make sure that the window is valid - */ - { - xcb_get_geometry_cookie_t gg_cookie = - xcb_get_geometry (dpy, window); - - w->geometry = xcb_get_geometry_reply(dpy, gg_cookie, &err); - - if (!w->geometry) { - char badid[20]; - - if (err) - Print_X_Error (dpy, err); - - snprintf (badid, sizeof(badid), window_id_format, window); - Fatal_Error ("No such window with id %s.", badid); - } - } - - /* Send requests to prefetch data we'll need */ - w->window = window; - w->net_wm_name_cookie = get_net_wm_name (dpy, window); - w->wm_name_cookie = xcb_icccm_get_wm_name (dpy, window); - if (children || tree) - w->tree_cookie = xcb_query_tree (dpy, window); - if (stats) { - w->trans_coords_cookie = - xcb_translate_coordinates (dpy, window, w->geometry->root, - -(w->geometry->border_width), - -(w->geometry->border_width)); - } - if (stats || bits || events) - w->attr_cookie = xcb_get_window_attributes (dpy, window); - if (stats || size) - w->normal_hints_cookie = xcb_icccm_get_wm_normal_hints (dpy, window); - if (wm) { - w->hints_cookie = xcb_icccm_get_wm_hints(dpy, window); - - atom_net_wm_desktop = Get_Atom (dpy, "_NET_WM_DESKTOP"); - if (atom_net_wm_desktop) { - w->wm_desktop_cookie = xcb_get_property - (dpy, False, window, atom_net_wm_desktop, - XCB_ATOM_CARDINAL, 0, 4); - } - - atom_net_wm_window_type = Get_Atom (dpy, "_NET_WM_WINDOW_TYPE"); - if (atom_net_wm_window_type) { - w->wm_window_type_cookie = xcb_get_property - (dpy, False, window, atom_net_wm_window_type, - XCB_ATOM_ATOM, 0, BUFSIZ); - } - - atom_net_wm_state = Get_Atom (dpy, "_NET_WM_STATE"); - if (atom_net_wm_state) { - w->wm_state_cookie = xcb_get_property - (dpy, False, window, atom_net_wm_state, - XCB_ATOM_ATOM, 0, BUFSIZ); - } - - atom_net_wm_pid = Get_Atom (dpy, "_NET_WM_PID"); - if (atom_net_wm_pid) { - w->wm_pid_cookie = xcb_get_property - (dpy, False, window, atom_net_wm_pid, - XCB_ATOM_CARDINAL, 0, BUFSIZ); - w->wm_client_machine_cookie = xcb_get_property - (dpy, False, window, XCB_ATOM_WM_CLIENT_MACHINE, - XCB_GET_PROPERTY_TYPE_ANY, 0, BUFSIZ); - } - - atom_net_frame_extents = Get_Atom (dpy, "_NET_FRAME_EXTENTS"); - if (atom_net_frame_extents) { - w->frame_extents_cookie = xcb_get_property - (dpy, False, window, atom_net_frame_extents, - XCB_ATOM_CARDINAL, 0, 4 * 4); - } - } - if (size) - w->zoom_cookie = xcb_icccm_get_wm_size_hints (dpy, window, - XCB_ATOM_WM_ZOOM_HINTS); - xcb_flush (dpy); - - printf ("\nxwininfo: Window id: "); - Display_Window_Id (w, True); - if (children || tree) - Display_Tree_Info (w, tree); - if (stats) - Display_Stats_Info (w); - if (bits) - Display_Bits_Info (w); - if (events) - Display_Events_Info (w); - if (wm) - Display_WM_Info (w); - if (size) - Display_Size_Hints (w); - if (shape) - Display_Window_Shape (window); - printf ("\n"); - - wininfo_wipe (w); - xcb_disconnect (dpy); -#ifdef HAVE_ICONV - if (iconv_from_utf8 && (iconv_from_utf8 != (iconv_t) -1)) { - iconv_close (iconv_from_utf8); - } -#endif - exit (0); -} - -/* Ensure win_attributes field is filled in */ -static xcb_get_window_attributes_reply_t * -fetch_win_attributes (struct wininfo *w) -{ - if (!w->win_attributes) { - w->win_attributes = - xcb_get_window_attributes_reply (dpy, w->attr_cookie, &err); - - if (!w->win_attributes) { - Print_X_Error (dpy, err); - Fatal_Error ("Can't get window attributes."); - } - } - return w->win_attributes; -} - -#ifndef USE_XCB_ICCCM -static Bool -wm_size_hints_reply (xcb_connection_t *dpy, xcb_get_property_cookie_t cookie, - wm_size_hints_t *hints_return, xcb_generic_error_t **err) -{ - xcb_get_property_reply_t *prop = xcb_get_property_reply (dpy, cookie, err); - int length; - - if (!prop || (prop->type != XCB_ATOM_WM_SIZE_HINTS) || - (prop->format != 32)) { - free (prop); - return False; - } - - memset (hints_return, 0, sizeof(wm_size_hints_t)); - - length = xcb_get_property_value_length(prop); - if (length > sizeof(wm_size_hints_t)) - length = sizeof(wm_size_hints_t); - memcpy (hints_return, xcb_get_property_value (prop), length); - - free (prop); - return True; -} - -#define xcb_icccm_get_wm_normal_hints_reply wm_size_hints_reply -#define xcb_icccm_get_wm_size_hints_reply wm_size_hints_reply -#endif - - - -/* Ensure normal_hints field is filled in */ -static xcb_size_hints_t * -fetch_normal_hints (struct wininfo *w, xcb_size_hints_t *hints_return) -{ - xcb_size_hints_t hints; - - if (!w->normal_hints) { - if (xcb_icccm_get_wm_normal_hints_reply (dpy, w->normal_hints_cookie, - &hints, NULL)) { - w->normal_hints = malloc (sizeof(xcb_size_hints_t)); - if (w->normal_hints) - memcpy(w->normal_hints, &hints, sizeof(xcb_size_hints_t)); - } - } - if (hints_return && w->normal_hints) - memcpy(hints_return, w->normal_hints, sizeof(xcb_size_hints_t)); - return w->normal_hints; -} - - -/* - * Lookup: lookup a code in a table. - */ -static char _lookup_buffer[100]; - -static const char * -LookupL (long code, const binding *table) -{ - const char *name = NULL; - - while (table->name) { - if (table->code == code) { - name = table->name; - break; - } - table++; - } - - if (name == NULL) { - snprintf (_lookup_buffer, sizeof(_lookup_buffer), - "unknown (code = %ld. = 0x%lx)", code, code); - name = _lookup_buffer; - } - - return (name); -} - -static const char * -Lookup (int code, const binding *table) -{ - return LookupL ((long)code, table); -} - -/* - * Routine to display a window id in dec/hex with name if window has one - * - * Requires wininfo members initialized: window, wm_name_cookie - */ - -static void -Display_Window_Id (struct wininfo *w, Bool newline_wanted) -{ -#ifdef USE_XCB_ICCCM - xcb_icccm_get_text_property_reply_t wmn_reply; - uint8_t got_reply = False; -#endif - xcb_get_property_reply_t *prop; - const char *wm_name = NULL; - unsigned int wm_name_len = 0; - xcb_atom_t wm_name_encoding = XCB_NONE; - - printf (window_id_format, w->window); /* print id # in hex/dec */ - - if (!w->window) { - printf (" (none)"); - } else { - if (w->window == screen->root) { - printf (" (the root window)"); - } - /* Get window name if any */ - prop = xcb_get_property_reply (dpy, w->net_wm_name_cookie, NULL); - if (prop && (prop->type != XCB_NONE)) { - wm_name = xcb_get_property_value (prop); - wm_name_len = xcb_get_property_value_length (prop); - wm_name_encoding = prop->type; - } else { /* No _NET_WM_NAME, check WM_NAME */ -#ifdef USE_XCB_ICCCM - got_reply = xcb_icccm_get_wm_name_reply (dpy, w->wm_name_cookie, - &wmn_reply, NULL); - if (got_reply) { - wm_name = wmn_reply.name; - wm_name_len = wmn_reply.name_len; - wm_name_encoding = wmn_reply.encoding; - } -#else - prop = xcb_get_property_reply (dpy, w->wm_name_cookie, NULL); - if (prop && (prop->type != XCB_NONE)) { - wm_name = xcb_get_property_value (prop); - wm_name_len = xcb_get_property_value_length (prop); - wm_name_encoding = prop->type; - } -#endif - } - if (wm_name_len == 0) { - printf (" (has no name)"); - } else { - if (wm_name_encoding == XCB_ATOM_STRING) { - printf (" \"%.*s\"", wm_name_len, wm_name); - } else if (wm_name_encoding == atom_utf8_string) { - print_utf8 (" \"", (char *) wm_name, wm_name_len, "\""); - } else { - /* Encodings we don't support, including COMPOUND_TEXT */ - const char *enc_name = Get_Atom_Name (dpy, wm_name_encoding); - if (enc_name) { - printf (" (name in unsupported encoding %s)", enc_name); - } else { - printf (" (name in unsupported encoding ATOM 0x%x)", - wm_name_encoding); - } - } - } -#ifdef USE_XCB_ICCCM - if (got_reply) - xcb_icccm_get_text_property_reply_wipe (&wmn_reply); -#else - free (prop); -#endif - } - - if (newline_wanted) - printf ("\n"); - - return; -} - - -/* - * Display Stats on window - */ -static const binding _window_classes[] = { - { XCB_WINDOW_CLASS_INPUT_OUTPUT, "InputOutput" }, - { XCB_WINDOW_CLASS_INPUT_ONLY, "InputOnly" }, - { 0, NULL } }; - -static const binding _map_states[] = { - { XCB_MAP_STATE_UNMAPPED, "IsUnMapped" }, - { XCB_MAP_STATE_UNVIEWABLE, "IsUnviewable" }, - { XCB_MAP_STATE_VIEWABLE, "IsViewable" }, - { 0, NULL } }; - -static const binding _backing_store_states[] = { - { XCB_BACKING_STORE_NOT_USEFUL, "NotUseful" }, - { XCB_BACKING_STORE_WHEN_MAPPED,"WhenMapped" }, - { XCB_BACKING_STORE_ALWAYS, "Always" }, - { 0, NULL } }; - -static const binding _bit_gravity_states[] = { - { XCB_GRAVITY_BIT_FORGET, "ForgetGravity" }, - { XCB_GRAVITY_NORTH_WEST, "NorthWestGravity" }, - { XCB_GRAVITY_NORTH, "NorthGravity" }, - { XCB_GRAVITY_NORTH_EAST, "NorthEastGravity" }, - { XCB_GRAVITY_WEST, "WestGravity" }, - { XCB_GRAVITY_CENTER, "CenterGravity" }, - { XCB_GRAVITY_EAST, "EastGravity" }, - { XCB_GRAVITY_SOUTH_WEST, "SouthWestGravity" }, - { XCB_GRAVITY_SOUTH, "SouthGravity" }, - { XCB_GRAVITY_SOUTH_EAST, "SouthEastGravity" }, - { XCB_GRAVITY_STATIC, "StaticGravity" }, - { 0, NULL }}; - -static const binding _window_gravity_states[] = { - { XCB_GRAVITY_WIN_UNMAP, "UnmapGravity" }, - { XCB_GRAVITY_NORTH_WEST, "NorthWestGravity" }, - { XCB_GRAVITY_NORTH, "NorthGravity" }, - { XCB_GRAVITY_NORTH_EAST, "NorthEastGravity" }, - { XCB_GRAVITY_WEST, "WestGravity" }, - { XCB_GRAVITY_CENTER, "CenterGravity" }, - { XCB_GRAVITY_EAST, "EastGravity" }, - { XCB_GRAVITY_SOUTH_WEST, "SouthWestGravity" }, - { XCB_GRAVITY_SOUTH, "SouthGravity" }, - { XCB_GRAVITY_SOUTH_EAST, "SouthEastGravity" }, - { XCB_GRAVITY_STATIC, "StaticGravity" }, - { 0, NULL }}; - -static const binding _visual_classes[] = { - { XCB_VISUAL_CLASS_STATIC_GRAY, "StaticGray" }, - { XCB_VISUAL_CLASS_GRAY_SCALE, "GrayScale" }, - { XCB_VISUAL_CLASS_STATIC_COLOR,"StaticColor" }, - { XCB_VISUAL_CLASS_PSEUDO_COLOR,"PseudoColor" }, - { XCB_VISUAL_CLASS_TRUE_COLOR, "TrueColor" }, - { XCB_VISUAL_CLASS_DIRECT_COLOR,"DirectColor" }, - { 0, NULL }}; - -/* - * Requires wininfo members initialized: - * window, geometry, attr_cookie, trans_coords_cookie, normal_hints_cookie - */ -static void -Display_Stats_Info (struct wininfo *w) -{ - xcb_translate_coordinates_reply_t *trans_coords; - xcb_get_window_attributes_reply_t *win_attributes; - xcb_size_hints_t hints; - - int dw = screen->width_in_pixels, dh = screen->height_in_pixels; - int rx, ry, xright, ybelow; - int showright = 0, showbelow = 0; - xcb_window_t wmframe, parent; - - trans_coords = - xcb_translate_coordinates_reply (dpy, w->trans_coords_cookie, NULL); - if (!trans_coords) - Fatal_Error ("Can't get translated coordinates."); - - rx = (int16_t)trans_coords->dst_x; - ry = (int16_t)trans_coords->dst_y; - free (trans_coords); - - xright = (dw - rx - w->geometry->border_width * 2 - - w->geometry->width); - ybelow = (dh - ry - w->geometry->border_width * 2 - - w->geometry->height); - - - printf ("\n"); - printf (" Absolute upper-left X: %s\n", xscale (rx)); - printf (" Absolute upper-left Y: %s\n", yscale (ry)); - printf (" Relative upper-left X: %s\n", xscale (w->geometry->x)); - printf (" Relative upper-left Y: %s\n", yscale (w->geometry->y)); - printf (" Width: %s\n", xscale (w->geometry->width)); - printf (" Height: %s\n", yscale (w->geometry->height)); - printf (" Depth: %d\n", w->geometry->depth); - - win_attributes = fetch_win_attributes (w); - - printf (" Visual: 0x%lx\n", (unsigned long) win_attributes->visual); - if (screen) - { - xcb_depth_iterator_t depth_iter; - xcb_visualtype_t *visual_type = NULL; - - depth_iter = xcb_screen_allowed_depths_iterator (screen); - for (; depth_iter.rem; xcb_depth_next (&depth_iter)) { - xcb_visualtype_iterator_t visual_iter; - - visual_iter = xcb_depth_visuals_iterator (depth_iter.data); - for (; visual_iter.rem; xcb_visualtype_next (&visual_iter)) { - if (screen->root_visual == visual_iter.data->visual_id) { - visual_type = visual_iter.data; - break; - } - } - } - if (visual_type) - printf (" Visual Class: %s\n", Lookup (visual_type->_class, - _visual_classes)); - } - - printf (" Border width: %s\n", bscale (w->geometry->border_width)); - printf (" Class: %s\n", - Lookup (win_attributes->_class, _window_classes)); - printf (" Colormap: 0x%lx (%sinstalled)\n", - (unsigned long) win_attributes->colormap, - win_attributes->map_is_installed ? "" : "not "); - printf (" Bit Gravity State: %s\n", - Lookup (win_attributes->bit_gravity, _bit_gravity_states)); - printf (" Window Gravity State: %s\n", - Lookup (win_attributes->win_gravity, _window_gravity_states)); - printf (" Backing Store State: %s\n", - Lookup (win_attributes->backing_store, _backing_store_states)); - printf (" Save Under State: %s\n", - win_attributes->save_under ? "yes" : "no"); - printf (" Map State: %s\n", - Lookup (win_attributes->map_state, _map_states)); - printf (" Override Redirect State: %s\n", - win_attributes->override_redirect ? "yes" : "no"); - printf (" Corners: +%d+%d -%d+%d -%d-%d +%d-%d\n", - rx, ry, xright, ry, xright, ybelow, rx, ybelow); - - /* - * compute geometry string that would recreate window - */ - printf (" -geometry "); - - /* compute size in appropriate units */ - if (!fetch_normal_hints (w, &hints)) - hints.flags = 0; - - if ((hints.flags & XCB_ICCCM_SIZE_HINT_P_RESIZE_INC) && - (hints.width_inc != 0) && (hints.height_inc != 0)) { - if (hints.flags & - (XCB_ICCCM_SIZE_HINT_BASE_SIZE|XCB_ICCCM_SIZE_HINT_P_MIN_SIZE)) { - if (hints.flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE) { - w->geometry->width -= hints.base_width; - w->geometry->height -= hints.base_height; - } else { - /* ICCCM says MinSize is default for BaseSize */ - w->geometry->width -= hints.min_width; - w->geometry->height -= hints.min_height; - } - } - printf ("%dx%d", w->geometry->width/hints.width_inc, - w->geometry->height/hints.height_inc); - } else - printf ("%dx%d", w->geometry->width, w->geometry->height); - - if (!(hints.flags & XCB_ICCCM_SIZE_HINT_P_WIN_GRAVITY)) - hints.win_gravity = XCB_GRAVITY_NORTH_WEST; /* per ICCCM */ - /* find our window manager frame, if any */ - for (wmframe = parent = w->window; parent != 0 ; wmframe = parent) { - xcb_query_tree_cookie_t qt_cookie; - xcb_query_tree_reply_t *tree; - - qt_cookie = xcb_query_tree (dpy, wmframe); - tree = xcb_query_tree_reply (dpy, qt_cookie, &err); - if (!tree) { - Print_X_Error (dpy, err); - Fatal_Error ("Can't query window tree."); - } - parent = tree->parent; - free (tree); - if (parent == w->geometry->root || !parent) - break; - } - if (wmframe != w->window) { - /* WM reparented, so find edges of the frame */ - /* Only works for ICCCM-compliant WMs, and then only if the - window has corner gravity. We would need to know the original width - of the window to correctly handle the other gravities. */ - xcb_get_geometry_cookie_t geom_cookie; - xcb_get_geometry_reply_t *frame_geometry; - - geom_cookie = xcb_get_geometry (dpy, wmframe); - frame_geometry = xcb_get_geometry_reply (dpy, geom_cookie, &err); - - if (!frame_geometry) { - Print_X_Error (dpy, err); - Fatal_Error ("Can't get frame geometry."); - } - switch (hints.win_gravity) { - case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST: - case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST: - case XCB_GRAVITY_WEST: - rx = frame_geometry->x; - } - switch (hints.win_gravity) { - case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST: - case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST: - case XCB_GRAVITY_EAST: - xright = dw - frame_geometry->x - frame_geometry->width - - (2 * frame_geometry->border_width); - } - switch (hints.win_gravity) { - case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST: - case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST: - case XCB_GRAVITY_NORTH: - ry = frame_geometry->y; - } - switch (hints.win_gravity) { - case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST: - case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST: - case XCB_GRAVITY_SOUTH: - ybelow = dh - frame_geometry->y - frame_geometry->height - - (2 * frame_geometry->border_width); - } - free (frame_geometry); - } - /* If edge gravity, offer a corner on that edge (because the application - programmer cares about that edge), otherwise offer upper left unless - some other corner is close to an edge of the screen. - (For corner gravity, assume gravity was set by XWMGeometry. - For CenterGravity, it doesn't matter.) */ - if (hints.win_gravity == XCB_GRAVITY_EAST || - (abs (xright) <= 100 && abs (xright) < abs (rx) - && hints.win_gravity != XCB_GRAVITY_WEST)) - showright = 1; - if (hints.win_gravity == XCB_GRAVITY_SOUTH || - (abs (ybelow) <= 100 && abs (ybelow) < abs (ry) - && hints.win_gravity != XCB_GRAVITY_NORTH)) - showbelow = 1; - - if (showright) - printf ("-%d", xright); - else - printf ("+%d", rx); - if (showbelow) - printf ("-%d", ybelow); - else - printf ("+%d", ry); - printf ("\n"); -} - - -/* - * Display bits info: - */ -static const binding _gravities[] = { - /* WARNING: the first two of these have the same value - see code */ - { XCB_GRAVITY_WIN_UNMAP, "UnMapGravity" }, - { XCB_GRAVITY_BIT_FORGET, "ForgetGravity" }, - { XCB_GRAVITY_NORTH_WEST, "NorthWestGravity" }, - { XCB_GRAVITY_NORTH, "NorthGravity" }, - { XCB_GRAVITY_NORTH_EAST, "NorthEastGravity" }, - { XCB_GRAVITY_WEST, "WestGravity" }, - { XCB_GRAVITY_CENTER, "CenterGravity" }, - { XCB_GRAVITY_EAST, "EastGravity" }, - { XCB_GRAVITY_SOUTH_WEST, "SouthWestGravity" }, - { XCB_GRAVITY_SOUTH, "SouthGravity" }, - { XCB_GRAVITY_SOUTH_EAST, "SouthEastGravity" }, - { XCB_GRAVITY_STATIC, "StaticGravity" }, - { 0, NULL } }; - -static const binding _backing_store_hint[] = { - { XCB_BACKING_STORE_NOT_USEFUL, "NotUseful" }, - { XCB_BACKING_STORE_WHEN_MAPPED,"WhenMapped" }, - { XCB_BACKING_STORE_ALWAYS, "Always" }, - { 0, NULL } }; - -static const binding _bool[] = { - { 0, "No" }, - { 1, "Yes" }, - { 0, NULL } }; - -/* - * Requires wininfo members initialized: - * window, attr_cookie (or win_attributes) - */ -static void -Display_Bits_Info (struct wininfo * w) -{ - xcb_get_window_attributes_reply_t *win_attributes - = fetch_win_attributes (w); - - printf ("\n"); - printf (" Bit gravity: %s\n", - Lookup (win_attributes->bit_gravity, _gravities+1)); - printf (" Window gravity: %s\n", - Lookup (win_attributes->win_gravity, _gravities)); - printf (" Backing-store hint: %s\n", - Lookup (win_attributes->backing_store, _backing_store_hint)); - printf (" Backing-planes to be preserved: 0x%lx\n", - (unsigned long) win_attributes->backing_planes); - printf (" Backing pixel: %ld\n", - (unsigned long) win_attributes->backing_pixel); - printf (" Save-unders: %s\n", - Lookup (win_attributes->save_under, _bool)); -} - - -/* - * Routine to display all events in an event mask - */ -static const binding _event_mask_names[] = { - { XCB_EVENT_MASK_KEY_PRESS, "KeyPress" }, - { XCB_EVENT_MASK_KEY_RELEASE, "KeyRelease" }, - { XCB_EVENT_MASK_BUTTON_PRESS, "ButtonPress" }, - { XCB_EVENT_MASK_BUTTON_RELEASE, "ButtonRelease" }, - { XCB_EVENT_MASK_ENTER_WINDOW, "EnterWindow" }, - { XCB_EVENT_MASK_LEAVE_WINDOW, "LeaveWindow" }, - { XCB_EVENT_MASK_POINTER_MOTION, "PointerMotion" }, - { XCB_EVENT_MASK_POINTER_MOTION_HINT, "PointerMotionHint" }, - { XCB_EVENT_MASK_BUTTON_1_MOTION, "Button1Motion" }, - { XCB_EVENT_MASK_BUTTON_2_MOTION, "Button2Motion" }, - { XCB_EVENT_MASK_BUTTON_3_MOTION, "Button3Motion" }, - { XCB_EVENT_MASK_BUTTON_4_MOTION, "Button4Motion" }, - { XCB_EVENT_MASK_BUTTON_5_MOTION, "Button5Motion" }, - { XCB_EVENT_MASK_BUTTON_MOTION, "ButtonMotion" }, - { XCB_EVENT_MASK_KEYMAP_STATE, "KeymapState" }, - { XCB_EVENT_MASK_EXPOSURE, "Exposure" }, - { XCB_EVENT_MASK_VISIBILITY_CHANGE, "VisibilityChange" }, - { XCB_EVENT_MASK_STRUCTURE_NOTIFY, "StructureNotify" }, - { XCB_EVENT_MASK_RESIZE_REDIRECT, "ResizeRedirect" }, - { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, "SubstructureNotify" }, - { XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, "SubstructureRedirect" }, - { XCB_EVENT_MASK_FOCUS_CHANGE, "FocusChange" }, - { XCB_EVENT_MASK_PROPERTY_CHANGE, "PropertyChange" }, - { XCB_EVENT_MASK_COLOR_MAP_CHANGE, "ColormapChange" }, - { XCB_EVENT_MASK_OWNER_GRAB_BUTTON, "OwnerGrabButton" }, - { 0, NULL } }; - -static void -Display_Event_Mask (long mask) -{ - long bit, bit_mask; - - for (bit=0, bit_mask=1; bit < sizeof(long)*8; bit++, bit_mask <<= 1) - if (mask & bit_mask) - printf (" %s\n", - LookupL (bit_mask, _event_mask_names)); -} - - -/* - * Display info on events - * - * Requires wininfo members initialized: - * window, attr_cookie (or win_attributes) - */ -static void -Display_Events_Info (struct wininfo *w) -{ - xcb_get_window_attributes_reply_t *win_attributes - = fetch_win_attributes (w); - - printf ("\n"); - printf (" Someone wants these events:\n"); - Display_Event_Mask (win_attributes->all_event_masks); - - printf (" Do not propagate these events:\n"); - Display_Event_Mask (win_attributes->do_not_propagate_mask); - - printf (" Override redirection?: %s\n", - Lookup (win_attributes->override_redirect, _bool)); -} - - - /* left out visual stuff */ - /* left out colormap */ - /* left out map_installed */ - - -/* - * Display root, parent, and (recursively) children information - * recurse - true to show children information - * - * Requires wininfo members initialized: window, tree_cookie - */ -static void -Display_Tree_Info (struct wininfo *w, int recurse) -{ - display_tree_info_1 (w, recurse, 0); -} - -/* - * level - recursion level - */ -static void -display_tree_info_1 (struct wininfo *w, int recurse, int level) -{ - int i, j; - unsigned int num_children; - xcb_query_tree_reply_t *tree; - - tree = xcb_query_tree_reply (dpy, w->tree_cookie, &err); - if (!tree) { - Print_X_Error (dpy, err); - Fatal_Error ("Can't query window tree."); - } - - if (level == 0) { - struct wininfo rw, pw; - rw.window = tree->root; - rw.net_wm_name_cookie = get_net_wm_name (dpy, rw.window); - rw.wm_name_cookie = xcb_icccm_get_wm_name (dpy, rw.window); - pw.window = tree->parent; - pw.net_wm_name_cookie = get_net_wm_name (dpy, pw.window); - pw.wm_name_cookie = xcb_icccm_get_wm_name (dpy, pw.window); - xcb_flush (dpy); - - printf ("\n"); - printf (" Root window id: "); - Display_Window_Id (&rw, True); - printf (" Parent window id: "); - Display_Window_Id (&pw, True); - } - - num_children = xcb_query_tree_children_length (tree); - - if (level == 0 || num_children > 0) { - printf (" "); - for (j = 0; j < level; j++) printf (" "); - printf ("%d child%s%s\n", num_children, num_children == 1 ? "" : "ren", - num_children ? ":" : "."); - } - - if (num_children > 0) { - xcb_window_t *child_list = xcb_query_tree_children (tree); - struct wininfo *children - = calloc (num_children, sizeof(struct wininfo)); - - if (children == NULL) - Fatal_Error ("Failed to allocate memory in display_tree_info"); - - for (i = (int)num_children - 1; i >= 0; i--) { - struct wininfo *cw = &children[i]; - - cw->window = child_list[i]; - cw->net_wm_name_cookie = get_net_wm_name (dpy, child_list[i]); - cw->wm_name_cookie = xcb_icccm_get_wm_name (dpy, child_list[i]); - cw->wm_class_cookie = xcb_icccm_get_wm_class (dpy, child_list[i]); - cw->geometry_cookie = xcb_get_geometry (dpy, child_list[i]); - cw->trans_coords_cookie = xcb_translate_coordinates - (dpy, child_list[i], tree->root, 0, 0); - if (recurse) - cw->tree_cookie = xcb_query_tree (dpy, child_list[i]); - } - xcb_flush (dpy); - - for (i = (int)num_children - 1; i >= 0; i--) { - struct wininfo *cw = &children[i]; - Bool got_wm_class = False; - char *instance_name = NULL, *class_name = NULL; - int instance_name_len, class_name_len; -#ifdef USE_XCB_ICCCM - xcb_icccm_get_wm_class_reply_t classhint; -#else - xcb_get_property_reply_t *classprop; -#endif - xcb_get_geometry_reply_t *geometry; - - printf (" "); - for (j = 0; j < level; j++) printf (" "); - Display_Window_Id (cw, False); - printf (": ("); - -#ifdef USE_XCB_ICCCM - if (xcb_icccm_get_wm_class_reply (dpy, cw->wm_class_cookie, - &classhint, NULL)) { - got_wm_class = True; - instance_name = classhint.instance_name; - class_name = classhint.class_name; - instance_name_len = strlen(instance_name); - class_name_len = strlen(class_name); - } -#else - classprop = xcb_get_property_reply - (dpy, cw->wm_class_cookie, NULL); - if (classprop) { - if (classprop->type == XCB_ATOM_STRING && - classprop->format == 8) { - int proplen = xcb_get_property_value_length (classprop); - - instance_name = xcb_get_property_value (classprop); - instance_name_len = strnlen (instance_name, proplen); - if (instance_name_len < proplen) { - class_name = instance_name + instance_name_len + 1; - class_name_len = strnlen - (class_name, proplen - (instance_name_len + 1)); - } else - class_name_len = 0; - got_wm_class = True; - } - else - free (classprop); - } -#endif - - if (got_wm_class) { - if (instance_name) - printf ("\"%.*s\" ", instance_name_len, instance_name); - else - printf ("(none) "); - - if (class_name) - printf ("\"%.*s\") ", class_name_len, class_name); - else - printf ("(none)) "); - -#ifdef USE_XCB_ICCCM - xcb_icccm_get_wm_class_reply_wipe (&classhint); -#else - free (classprop); -#endif - } else - printf (") "); - - geometry = xcb_get_geometry_reply(dpy, cw->geometry_cookie, &err); - if (geometry) { - xcb_translate_coordinates_reply_t *trans_coords; - - printf (" %ux%u+%d+%d", geometry->width, geometry->height, - geometry->x, geometry->y); - - trans_coords = xcb_translate_coordinates_reply - (dpy, cw->trans_coords_cookie, &err); - - if (trans_coords) { - int16_t abs_x = (int16_t) trans_coords->dst_x; - int16_t abs_y = (int16_t) trans_coords->dst_y; - int border = geometry->border_width; - - printf (" +%d+%d", abs_x - border, abs_y - border); - free (trans_coords); - } else if (err) { - Print_X_Error (dpy, err); - } - - free (geometry); - } else if (err) { - Print_X_Error (dpy, err); - } - printf ("\n"); - - if (recurse) - display_tree_info_1 (cw, 1, level+1); - - wininfo_wipe (cw); - } - free (children); - } - - free (tree); /* includes storage for child_list[] */ -} - - -/* - * Display a set of size hints - */ -static void -Display_Hints (xcb_size_hints_t *hints) -{ - long flags; - - flags = hints->flags; - - if (flags & XCB_ICCCM_SIZE_HINT_US_POSITION) - printf (" User supplied location: %s, %s\n", - xscale (hints->x), yscale (hints->y)); - - if (flags & XCB_ICCCM_SIZE_HINT_P_POSITION) - printf (" Program supplied location: %s, %s\n", - xscale (hints->x), yscale (hints->y)); - - if (flags & XCB_ICCCM_SIZE_HINT_US_SIZE) { - printf (" User supplied size: %s by %s\n", - xscale (hints->width), yscale (hints->height)); - } - - if (flags & XCB_ICCCM_SIZE_HINT_P_SIZE) - printf (" Program supplied size: %s by %s\n", - xscale (hints->width), yscale (hints->height)); - - if (flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) - printf (" Program supplied minimum size: %s by %s\n", - xscale (hints->min_width), yscale (hints->min_height)); - - if (flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE) - printf (" Program supplied maximum size: %s by %s\n", - xscale (hints->max_width), yscale (hints->max_height)); - - if (flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE) { - printf (" Program supplied base size: %s by %s\n", - xscale (hints->base_width), yscale (hints->base_height)); - } - - if (flags & XCB_ICCCM_SIZE_HINT_P_RESIZE_INC) { - printf (" Program supplied x resize increment: %s\n", - xscale (hints->width_inc)); - printf (" Program supplied y resize increment: %s\n", - yscale (hints->height_inc)); - if (hints->width_inc != 0 && hints->height_inc != 0) { - if (flags & XCB_ICCCM_SIZE_HINT_US_SIZE) - printf (" User supplied size in resize increments: %s by %s\n", - (xscale (hints->width / hints->width_inc)), - (yscale (hints->height / hints->height_inc))); - if (flags & XCB_ICCCM_SIZE_HINT_P_SIZE) - printf (" Program supplied size in resize increments: %s by %s\n", - (xscale (hints->width / hints->width_inc)), - (yscale (hints->height / hints->height_inc))); - if (flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE) - printf (" Program supplied minimum size in resize increments: %s by %s\n", - xscale (hints->min_width / hints->width_inc), yscale (hints->min_height / hints->height_inc)); - if (flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE) - printf (" Program supplied base size in resize increments: %s by %s\n", - (xscale (hints->base_width / hints->width_inc)), - (yscale (hints->base_height / hints->height_inc))); - } - } - - if (flags & XCB_ICCCM_SIZE_HINT_P_ASPECT) { - printf (" Program supplied min aspect ratio: %s/%s\n", - xscale (hints->min_aspect_num), yscale (hints->min_aspect_den)); - printf (" Program supplied max aspect ratio: %s/%s\n", - xscale (hints->max_aspect_num), yscale (hints->max_aspect_den)); - } - - if (flags & XCB_ICCCM_SIZE_HINT_P_WIN_GRAVITY) { - printf (" Program supplied window gravity: %s\n", - Lookup (hints->win_gravity, _gravities)); - } -} - - -/* - * Display Size Hints info - */ -static void -Display_Size_Hints (struct wininfo *w) -{ - xcb_size_hints_t hints; - - printf ("\n"); - if (!fetch_normal_hints (w, &hints)) - printf (" No normal window size hints defined\n"); - else { - printf (" Normal window size hints:\n"); - Display_Hints (&hints); - } - - if (!xcb_icccm_get_wm_size_hints_reply (dpy, w->zoom_cookie, &hints, NULL)) - printf (" No zoom window size hints defined\n"); - else { - printf (" Zoom window size hints:\n"); - Display_Hints (&hints); - } -} - - -static void -Display_Window_Shape (xcb_window_t window) -{ - const xcb_query_extension_reply_t *shape_query; - xcb_shape_query_extents_cookie_t extents_cookie; - xcb_shape_query_extents_reply_t *extents; - - shape_query = xcb_get_extension_data (dpy, &xcb_shape_id); - if (!shape_query->present) - return; - - printf ("\n"); - - extents_cookie = xcb_shape_query_extents (dpy, window); - extents = xcb_shape_query_extents_reply (dpy, extents_cookie, &err); - - if (!extents) { - if (err) - Print_X_Error (dpy, err); - else - { - printf (" No window shape defined\n"); - printf (" No border shape defined\n"); - } - return; - } - - if (!extents->bounding_shaped) - printf (" No window shape defined\n"); - else { - printf (" Window shape extents: %sx%s", - xscale (extents->bounding_shape_extents_width), - yscale (extents->bounding_shape_extents_height)); - printf ("+%s+%s\n", - xscale (extents->bounding_shape_extents_x), - yscale (extents->bounding_shape_extents_y)); - } - if (!extents->clip_shaped) - printf (" No border shape defined\n"); - else { - printf (" Border shape extents: %sx%s", - xscale (extents->clip_shape_extents_width), - yscale (extents->clip_shape_extents_height)); - printf ("+%s+%s\n", - xscale (extents->clip_shape_extents_x), - yscale (extents->clip_shape_extents_y)); - } - - free (extents); -} - -/* - * Display Window Manager Info - * - * Requires wininfo members initialized: - * window, hints_cookie - */ -static const binding _state_hints[] = { - { XCB_ICCCM_WM_STATE_WITHDRAWN, "Withdrawn State" }, - { XCB_ICCCM_WM_STATE_NORMAL, "Normal State" }, - { XCB_ICCCM_WM_STATE_ICONIC, "Iconic State" }, -/* xwininfo previously also reported the ZoomState & InactiveState, - but ICCCM declared those obsolete long ago */ - { 0, NULL } }; - -#ifndef USE_XCB_ICCCM -static Bool -wm_hints_reply (xcb_connection_t *dpy, xcb_get_property_cookie_t cookie, - wm_hints_t *hints_return, xcb_generic_error_t **err) -{ - xcb_get_property_reply_t *prop = xcb_get_property_reply (dpy, cookie, err); - int length; - - if (!prop || (prop->type != XCB_ATOM_WM_HINTS) || (prop->format != 32)) { - free (prop); - return False; - } - - memset (hints_return, 0, sizeof(wm_hints_t)); - - length = xcb_get_property_value_length(prop); - if (length > sizeof(wm_hints_t)) - length = sizeof(wm_hints_t); - memcpy (hints_return, xcb_get_property_value (prop), length); - - free (prop); - return True; -} - -#define xcb_icccm_get_wm_hints_reply wm_hints_reply -#endif - -static void -Display_WM_Info (struct wininfo *w) -{ - xcb_icccm_wm_hints_t wmhints; - long flags; - xcb_get_property_reply_t *prop; - int i; - - printf ("\n"); - if (!xcb_icccm_get_wm_hints_reply(dpy, w->hints_cookie, &wmhints, &err)) - { - printf (" No window manager hints defined\n"); - if (err) - Print_X_Error (dpy, err); - flags = 0; - } else - flags = wmhints.flags; - - printf (" Window manager hints:\n"); - - if (flags & XCB_ICCCM_WM_HINT_INPUT) - printf (" Client accepts input or input focus: %s\n", - Lookup (wmhints.input, _bool)); - - if (flags & XCB_ICCCM_WM_HINT_ICON_WINDOW) { - struct wininfo iw; - iw.window = wmhints.icon_window; - iw.net_wm_name_cookie = get_net_wm_name (dpy, iw.window); - iw.wm_name_cookie = xcb_icccm_get_wm_name (dpy, iw.window); - - printf (" Icon window id: "); - Display_Window_Id (&iw, True); - } - - if (flags & XCB_ICCCM_WM_HINT_ICON_POSITION) - printf (" Initial icon position: %s, %s\n", - xscale (wmhints.icon_x), yscale (wmhints.icon_y)); - - if (flags & XCB_ICCCM_WM_HINT_STATE) - printf (" Initial state is %s\n", - Lookup (wmhints.initial_state, _state_hints)); - - if (atom_net_wm_desktop) { - prop = xcb_get_property_reply (dpy, w->wm_desktop_cookie, NULL); - if (prop && (prop->type != XCB_NONE)) { - uint32_t *desktop = xcb_get_property_value (prop); - if (*desktop == 0xFFFFFFFF) { - printf (" Displayed on all desktops\n"); - } else { - printf (" Displayed on desktop %d\n", *desktop); - } - } - free (prop); - } - - if (atom_net_wm_window_type) { - prop = xcb_get_property_reply (dpy, w->wm_window_type_cookie, - NULL); - if (prop && (prop->type != XCB_NONE) && (prop->value_len > 0)) { - xcb_atom_t *atoms = xcb_get_property_value (prop); - int atom_count = prop->value_len; - - if (atom_count > 0) { - printf (" Window type:\n"); - for (i = 0; i < atom_count; i++) { - const char *atom_name = Get_Atom_Name (dpy, atoms[i]); - - if (atom_name) { - print_friendly_name (" %s\n", atom_name, - "_NET_WM_WINDOW_TYPE_"); - } else { - printf (" (unresolvable ATOM 0x%x)\n", - atoms[i]); - } - } - } - } - free (prop); - } - - if (atom_net_wm_state) { - prop = xcb_get_property_reply (dpy, w->wm_state_cookie, NULL); - if (prop && (prop->type != XCB_NONE) && (prop->value_len > 0)) { - xcb_atom_t *atoms = xcb_get_property_value (prop); - int atom_count = prop->value_len; - - if (atom_count > 0) { - printf (" Window state:\n"); - for (i = 0; i < atom_count; i++) { - const char *atom_name = Get_Atom_Name (dpy, atoms[i]); - - if (atom_name) { - print_friendly_name (" %s\n", atom_name, - "_NET_WM_STATE_"); - } else { - printf (" (unresolvable ATOM 0x%x)\n", - atoms[i]); - } - } - } - } - free (prop); - } - - if (atom_net_wm_pid) { - printf (" Process id: "); - prop = xcb_get_property_reply (dpy, w->wm_pid_cookie, NULL); - if (prop && (prop->type == XCB_ATOM_CARDINAL)) { - uint32_t *pid = xcb_get_property_value (prop); - printf ("%d", *pid); - } else { - printf ("(unknown)"); - } - free (prop); - - prop = xcb_get_property_reply (dpy, w->wm_client_machine_cookie, NULL); - if (prop && (prop->type == XCB_ATOM_STRING)) { - const char *hostname = xcb_get_property_value (prop); - int hostname_len = xcb_get_property_value_length (prop); - printf (" on host %.*s", hostname_len, hostname); - } - printf ("\n"); - free (prop); - } - - if (atom_net_frame_extents) { - prop = xcb_get_property_reply (dpy, w->frame_extents_cookie, NULL); - if (prop && (prop->type == XCB_ATOM_CARDINAL) - && (prop->value_len == 4)) { - uint32_t *extents = xcb_get_property_value (prop); - - printf (" Frame extents: %d, %d, %d, %d\n", - extents[0], extents[1], extents[2], extents[3]); - } - free (prop); - } -} - -/* Frees all members of a wininfo struct, but not the struct itself */ -static void -wininfo_wipe (struct wininfo *w) -{ - free (w->geometry); - free (w->win_attributes); - free (w->normal_hints); -} - -/* Gets UTF-8 encoded EMWH property _NET_WM_NAME for a window */ -static xcb_get_property_cookie_t -get_net_wm_name (xcb_connection_t *dpy, xcb_window_t win) -{ - if (!atom_net_wm_name) - atom_net_wm_name = Get_Atom (dpy, "_NET_WM_NAME"); - - if (!atom_utf8_string) - atom_utf8_string = Get_Atom (dpy, "UTF8_STRING"); - - if (atom_net_wm_name && atom_utf8_string) - return xcb_get_property (dpy, False, win, atom_net_wm_name, - atom_utf8_string, 0, BUFSIZ); - else { - xcb_get_property_cookie_t dummy = { 0 }; - return dummy; - } -} - -/* [Copied from code added by Yang Zhao to xprop/xprop.c] - * - * Validate a string as UTF-8 encoded according to RFC 3629 - * - * Simply, a unicode code point (up to 21-bits long) is encoded as follows: - * - * Char. number range | UTF-8 octet sequence - * (hexadecimal) | (binary) - * --------------------+--------------------------------------------- - * 0000 0000-0000 007F | 0xxxxxxx - * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx - * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx - * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - * - * Validation is done left-to-right, and an error condition, if any, refers to - * only the left-most problem in the string. - * - * Return values: - * UTF8_VALID: Valid UTF-8 encoded string - * UTF8_OVERLONG: Using more bytes than needed for a code point - * UTF8_SHORT_TAIL: Not enough bytes in a multi-byte sequence - * UTF8_LONG_TAIL: Too many bytes in a multi-byte sequence - * UTF8_FORBIDDEN_VALUE: Forbidden prefix or code point outside 0x10FFFF - */ -#define UTF8_VALID 0 -#define UTF8_FORBIDDEN_VALUE 1 -#define UTF8_OVERLONG 2 -#define UTF8_SHORT_TAIL 3 -#define UTF8_LONG_TAIL 4 -static int -is_valid_utf8 (const char *string, int len) -{ - unsigned long codepoint; - int rem, i; - unsigned char c; - - rem = 0; - for (i = 0; i < len; i++) { - c = (unsigned char) string[i]; - - /* Order of type check: - * - Single byte code point - * - Non-starting byte of multi-byte sequence - * - Start of 2-byte sequence - * - Start of 3-byte sequence - * - Start of 4-byte sequence - */ - if (!(c & 0x80)) { - if (rem > 0) return UTF8_SHORT_TAIL; - rem = 0; - codepoint = c; - } else if ((c & 0xC0) == 0x80) { - if (rem == 0) return UTF8_LONG_TAIL; - rem--; - codepoint |= (c & 0x3F) << (rem * 6); - if (codepoint == 0) return UTF8_OVERLONG; - } else if ((c & 0xE0) == 0xC0) { - if (rem > 0) return UTF8_SHORT_TAIL; - rem = 1; - codepoint = (c & 0x1F) << 6; - if (codepoint == 0) return UTF8_OVERLONG; - } else if ((c & 0xF0) == 0xE0) { - if (rem > 0) return UTF8_SHORT_TAIL; - rem = 2; - codepoint = (c & 0x0F) << 12; - } else if ((c & 0xF8) == 0xF0) { - if (rem > 0) return UTF8_SHORT_TAIL; - rem = 3; - codepoint = (c & 0x07) << 18; - if (codepoint > 0x10FFFF) return UTF8_FORBIDDEN_VALUE; - } else - return UTF8_FORBIDDEN_VALUE; - } - - return UTF8_VALID; -} - -/* - * Converts a UTF-8 encoded string to the current locale encoding, - * if possible, and prints it, with prefix before and suffix after. - * Length of the string is specified in bytes, or -1 for going until '\0' - */ -static void -print_utf8 (const char *prefix, char *u8str, size_t length, const char *suffix) -{ - size_t inlen = length; - - if (inlen < 0) { - inlen = strlen (u8str); - } - - if (is_valid_utf8 (u8str, inlen) != UTF8_VALID) { - printf (" (invalid UTF8_STRING)"); - return; - } - - if (strcmp (user_encoding, "UTF-8") == 0) { - /* Don't need to convert */ - printf ("%s", prefix); - fwrite (u8str, 1, inlen, stdout); - printf ("%s", suffix); - return; - } - -#ifdef HAVE_ICONV - if (!iconv_from_utf8) { - iconv_from_utf8 = iconv_open (user_encoding, "UTF-8"); - } - - if (iconv_from_utf8 != (iconv_t) -1) { - Bool done = True; - char *inp = u8str; - char convbuf[BUFSIZ]; - int convres; - - printf ("%s", prefix); - do { - char *outp = convbuf; - size_t outlen = sizeof(convbuf); - - convres = iconv (iconv_from_utf8, &inp, &inlen, &outp, &outlen); - - if ((convres == -1) && (errno == E2BIG)) { - done = False; - convres = 0; - } - - if (convres == 0) { - fwrite (convbuf, 1, sizeof(convbuf) - outlen, stdout); - } else { - printf (" (failure in conversion from UTF8_STRING to %s)", - user_encoding); - } - } while (!done); - printf ("%s", suffix); - } else { - printf (" (can't load iconv conversion for UTF8_STRING to %s)", - user_encoding); - } -#else - printf (" (can't convert UTF8_STRING to %s)", user_encoding); -#endif -} - -/* - * Takes a string such as an atom name, strips the prefix, converts - * underscores to spaces, lowercases all but the first letter of each word, - * and prints it. - */ -static void -print_friendly_name (const char *format, const char *string, - const char *prefix) -{ - const char *name_start = string; - char *lowered_name, *n; - int prefix_len = strlen (prefix); - - if (strncmp (name_start, prefix, prefix_len) == 0) { - name_start += prefix_len; - } - - lowered_name = strdup (name_start); - if (lowered_name) { - Bool first = True; - - for (n = lowered_name ; *n != 0 ; n++) { - if (*n == '_') { - *n = ' '; - first = True; - } else if (first) { - first = False; - } else { - *n = tolower(*n); - } - } - name_start = lowered_name; - } - - printf (format, name_start); - free (lowered_name); -} +/*
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+/*
+
+Copyright 1987, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
+INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
+FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder
+shall not be used in advertising or otherwise to promote the sale, use
+or other dealings in this Software without prior written authorization
+of the copyright holder.
+
+*/
+
+
+/*
+ * xwininfo.c - MIT Project Athena, X Window system window
+ * information utility.
+ *
+ *
+ * This program will report all relevant information
+ * about a specific window.
+ *
+ * Author: Mark Lillibridge, MIT Project Athena
+ * 16-Jun-87
+ */
+
+#include "config.h"
+
+#include <xcb/xcb.h>
+#include <xcb/xproto.h>
+#ifdef USE_XCB_ICCCM
+# include <xcb/xcb_icccm.h>
+#endif
+#include <xcb/shape.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <locale.h>
+#ifndef _MSC_VER
+#include <langinfo.h>
+#endif
+#ifdef HAVE_ICONV
+# include <iconv.h>
+#endif
+#include <ctype.h>
+#include <errno.h>
+
+#ifndef HAVE_STRNLEN
+#include "strnlen.h"
+#endif
+
+/* Include routines to handle parsing defaults */
+#include "dsimple.h"
+
+typedef struct {
+ long code;
+ const char *name;
+} binding;
+
+#ifndef USE_XCB_ICCCM
+/* Once xcb-icccm's API is stable, this should be replaced by
+ xcb_size_hints_t & xcb_size_hints_flags_t */
+typedef struct {
+ /** User specified flags */
+ uint32_t flags;
+ /** User-specified position */
+ int32_t x, y;
+ /** User-specified size */
+ int32_t width, height;
+ /** Program-specified minimum size */
+ int32_t min_width, min_height;
+ /** Program-specified maximum size */
+ int32_t max_width, max_height;
+ /** Program-specified resize increments */
+ int32_t width_inc, height_inc;
+ /** Program-specified minimum aspect ratios */
+ int32_t min_aspect_num, min_aspect_den;
+ /** Program-specified maximum aspect ratios */
+ int32_t max_aspect_num, max_aspect_den;
+ /** Program-specified base size */
+ int32_t base_width, base_height;
+ /** Program-specified window gravity */
+ uint32_t win_gravity;
+} wm_size_hints_t;
+
+# define xcb_size_hints_t wm_size_hints_t
+
+typedef struct {
+ /** Marks which fields in this structure are defined */
+ int32_t flags;
+ /** Does this application rely on the window manager to get keyboard
+ input? */
+ uint32_t input;
+ /** See below */
+ int32_t initial_state;
+ /** Pixmap to be used as icon */
+ xcb_pixmap_t icon_pixmap;
+ /** Window to be used as icon */
+ xcb_window_t icon_window;
+ /** Initial position of icon */
+ int32_t icon_x, icon_y;
+ /** Icon mask bitmap */
+ xcb_pixmap_t icon_mask;
+ /* Identifier of related window group */
+ xcb_window_t window_group;
+} wm_hints_t;
+
+#define xcb_icccm_wm_hints_t wm_hints_t
+
+enum {
+ /* xcb_size_hints_flags_t */
+ XCB_ICCCM_SIZE_HINT_US_POSITION = 1 << 0,
+ XCB_ICCCM_SIZE_HINT_US_SIZE = 1 << 1,
+ XCB_ICCCM_SIZE_HINT_P_POSITION = 1 << 2,
+ XCB_ICCCM_SIZE_HINT_P_SIZE = 1 << 3,
+ XCB_ICCCM_SIZE_HINT_P_MIN_SIZE = 1 << 4,
+ XCB_ICCCM_SIZE_HINT_P_MAX_SIZE = 1 << 5,
+ XCB_ICCCM_SIZE_HINT_P_RESIZE_INC = 1 << 6,
+ XCB_ICCCM_SIZE_HINT_P_ASPECT = 1 << 7,
+ XCB_ICCCM_SIZE_HINT_BASE_SIZE = 1 << 8,
+ XCB_ICCCM_SIZE_HINT_P_WIN_GRAVITY = 1 << 9,
+ /* xcb_wm_state_t */
+ XCB_ICCCM_WM_STATE_WITHDRAWN = 0,
+ XCB_ICCCM_WM_STATE_NORMAL = 1,
+ XCB_ICCCM_WM_STATE_ICONIC = 3,
+ /* xcb_wm_t */
+ XCB_ICCCM_WM_HINT_INPUT = (1L << 0),
+ XCB_ICCCM_WM_HINT_STATE = (1L << 1),
+ XCB_ICCCM_WM_HINT_ICON_PIXMAP = (1L << 2),
+ XCB_ICCCM_WM_HINT_ICON_WINDOW = (1L << 3),
+ XCB_ICCCM_WM_HINT_ICON_POSITION = (1L << 4),
+ XCB_ICCCM_WM_HINT_ICON_MASK = (1L << 5),
+ XCB_ICCCM_WM_HINT_WINDOW_GROUP = (1L << 6),
+ XCB_ICCCM_WM_HINT_X_URGENCY = (1L << 8)
+};
+
+/* Once xcb-icccm's API is stable, these should be replaced by calls to it */
+# define GET_TEXT_PROPERTY(Dpy, Win, Atom) \
+ xcb_get_property (Dpy, False, Win, Atom, XCB_GET_PROPERTY_TYPE_ANY, 0, BUFSIZ)
+# define xcb_icccm_get_wm_name(Dpy, Win) \
+ GET_TEXT_PROPERTY(Dpy, Win, XCB_ATOM_WM_NAME)
+
+# define xcb_icccm_get_wm_class(Dpy, Win) \
+ xcb_get_property (Dpy, False, Win, XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 0, BUFSIZ)
+# define xcb_icccm_get_wm_hints(Dpy, Win) \
+ xcb_get_property(Dpy, False, Win, XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 0, 9)
+
+# define xcb_icccm_get_wm_size_hints(Dpy, Win, Atom) \
+ xcb_get_property (Dpy, False, Win, Atom, XCB_ATOM_WM_SIZE_HINTS, 0, 18)
+# define xcb_icccm_get_wm_normal_hints(Dpy, Win) \
+ xcb_icccm_get_wm_size_hints(Dpy, Win, XCB_ATOM_WM_NORMAL_HINTS)
+#endif
+
+/* Possibly in xcb-emwh in the future? */
+static xcb_atom_t atom_net_wm_name, atom_utf8_string;
+static xcb_atom_t atom_net_wm_desktop, atom_net_wm_window_type,
+ atom_net_wm_state, atom_net_wm_pid, atom_net_frame_extents;
+static xcb_get_property_cookie_t get_net_wm_name (xcb_connection_t *,
+ xcb_window_t);
+
+/* Information we keep track of for each window to allow prefetching/reusing */
+struct wininfo {
+ xcb_window_t window;
+
+ /* cookies for requests we've sent */
+ xcb_get_geometry_cookie_t geometry_cookie;
+ xcb_get_property_cookie_t net_wm_name_cookie;
+ xcb_get_property_cookie_t wm_name_cookie;
+ xcb_get_property_cookie_t wm_class_cookie;
+ xcb_translate_coordinates_cookie_t trans_coords_cookie;
+ xcb_query_tree_cookie_t tree_cookie;
+ xcb_get_window_attributes_cookie_t attr_cookie;
+ xcb_get_property_cookie_t normal_hints_cookie;
+ xcb_get_property_cookie_t hints_cookie;
+ xcb_get_property_cookie_t wm_desktop_cookie;
+ xcb_get_property_cookie_t wm_window_type_cookie;
+ xcb_get_property_cookie_t wm_state_cookie;
+ xcb_get_property_cookie_t wm_pid_cookie;
+ xcb_get_property_cookie_t wm_client_machine_cookie;
+ xcb_get_property_cookie_t frame_extents_cookie;
+ xcb_get_property_cookie_t zoom_cookie;
+
+ /* cached results from previous requests */
+ xcb_get_geometry_reply_t * geometry;
+ xcb_get_window_attributes_reply_t * win_attributes;
+ xcb_size_hints_t * normal_hints;
+};
+
+static void scale_init (xcb_screen_t *scrn);
+static char *nscale (int, int, int, char *, size_t);
+static char *xscale (int);
+static char *yscale (int);
+static char *bscale (int);
+int main (int, char **);
+static const char *LookupL (long, const binding *);
+static const char *Lookup (int, const binding *);
+static void Display_Window_Id (struct wininfo *, Bool);
+static void Display_Stats_Info (struct wininfo *);
+static void Display_Bits_Info (struct wininfo *);
+static void Display_Event_Mask (long);
+static void Display_Events_Info (struct wininfo *);
+static void Display_Tree_Info (struct wininfo *, int);
+static void display_tree_info_1 (struct wininfo *, int, int);
+static void Display_Hints (xcb_size_hints_t *);
+static void Display_Size_Hints (struct wininfo *);
+static void Display_Window_Shape (xcb_window_t);
+static void Display_WM_Info (struct wininfo *);
+static void wininfo_wipe (struct wininfo *);
+
+static const char *window_id_format = "0x%lx";
+
+#ifdef HAVE_ICONV
+static iconv_t iconv_from_utf8;
+#endif
+static const char *user_encoding;
+static void print_utf8 (const char *, char *, size_t, const char *);
+static void print_friendly_name (const char *, const char *, const char *);
+
+static xcb_connection_t *dpy;
+static xcb_screen_t *screen;
+static xcb_generic_error_t *err;
+
+#ifndef HAVE_STRLCAT
+static size_t strlcat (char *dst, const char *src, size_t dstsize)
+{
+ size_t sd = strlen (dst);
+ size_t ss = strlen (src);
+ size_t s = sd + ss;
+
+ if (s < dstsize) {
+ strcpy (dst + sd, src);
+ } else {
+ strncpy (dst + sd, src, dstsize-sd-1);
+ dst[dstsize] = '\0';
+ }
+ return s;
+}
+#endif
+
+/*
+ * Report the syntax for calling xwininfo:
+ */
+static void
+usage (void)
+{
+ fprintf (stderr,
+ "usage: %s [-options ...]\n\n"
+ "where options include:\n"
+ " -help print this message\n"
+ " -display host:dpy X server to contact\n"
+ " -root use the root window\n"
+ " -id windowid use the window with the specified id\n"
+ " -name windowname use the window with the specified name\n"
+ " -int print window id in decimal\n"
+ " -children print parent and child identifiers\n"
+ " -tree print children identifiers recursively\n"
+ " -stats print window geometry [DEFAULT]\n"
+ " -bits print window pixel information\n"
+ " -events print events selected for on window\n"
+ " -size print size hints\n"
+ " -wm print window manager hints\n"
+ " -shape print shape extents\n"
+ " -frame don't ignore window manager frames\n"
+ " -english print sizes in english units\n"
+ " -metric print sizes in metric units\n"
+ " -all -tree, -stats, -bits, -events, -wm, -size, -shape\n"
+ "\n",
+ program_name);
+ exit (1);
+}
+
+/*
+ * pixel to inch, metric converter.
+ * Hacked in by Mark W. Eichin <eichin@athena> [eichin:19880619.1509EST]
+ *
+ * Simply put: replace the old numbers with string print calls.
+ * Returning a local string is ok, since we only ever get called to
+ * print one x and one y, so as long as they don't collide, they're
+ * fine. This is not meant to be a general purpose routine.
+ *
+ */
+
+static int xp = 0, xmm = 0;
+static int yp = 0, ymm = 0;
+static int bp = 0, bmm = 0;
+static int english = 0, metric = 0;
+
+static void
+scale_init (xcb_screen_t *screen)
+{
+ xp = screen->width_in_pixels;
+ yp = screen->height_in_pixels;
+ xmm = screen->width_in_millimeters;
+ ymm = screen->height_in_millimeters;
+ bp = xp + yp;
+ bmm = xmm + ymm;
+}
+
+#define MILE (5280*12)
+#define YARD (3*12)
+#define FOOT (12)
+
+static char *
+nscale (int n, int np, int nmm, char *nbuf, size_t nbufsize)
+{
+ int s;
+ snprintf (nbuf, nbufsize, "%d", n);
+
+ if (metric||english) {
+ s = strlcat (nbuf, " (", nbufsize);
+
+ if (metric) {
+ snprintf (nbuf+s, nbufsize-s, "%.2f mm%s",
+ ((double) n) * nmm/np , english ? "; " : "");
+ }
+ if (english) {
+ double inch_frac;
+ Bool printed_anything = False;
+ int mi, yar, ft, inr;
+
+ inch_frac = ((double) n)*(nmm/25.4)/np;
+ inr = (int)inch_frac;
+ inch_frac -= (double)inr;
+ if (inr >= MILE) {
+ mi = inr/MILE;
+ inr %= MILE;
+ s = strlen (nbuf);
+ snprintf (nbuf+s, nbufsize-s, "%d %s(?!?)",
+ mi, (mi == 1) ? "mile" : "miles");
+ printed_anything = True;
+ }
+ if (inr >= YARD) {
+ yar = inr/YARD;
+ inr %= YARD;
+ if (printed_anything)
+ strlcat (nbuf, ", ", nbufsize);
+ s = strlen (nbuf);
+ snprintf (nbuf+s, nbufsize-s, "%d %s",
+ yar, (yar==1) ? "yard" : "yards");
+ printed_anything = True;
+ }
+ if (inr >= FOOT) {
+ ft = inr/FOOT;
+ inr %= FOOT;
+ if (printed_anything)
+ strlcat (nbuf, ", ", nbufsize);
+ s = strlen (nbuf);
+ snprintf (nbuf+s, nbufsize-s, "%d %s",
+ ft, (ft==1) ? "foot" : "feet");
+ printed_anything = True;
+ }
+ if (!printed_anything || inch_frac != 0.0 || inr != 0) {
+ if (printed_anything)
+ strlcat (nbuf, ", ", nbufsize);
+ s = strlen (nbuf);
+ snprintf (nbuf+s, nbufsize-s, "%.2f inches", inr+inch_frac);
+ }
+ }
+ strlcat (nbuf, ")", nbufsize);
+ }
+ return (nbuf);
+}
+
+static char xbuf[BUFSIZ];
+static char *
+xscale (int x)
+{
+ return (nscale (x, xp, xmm, xbuf, sizeof(xbuf)));
+}
+
+static char ybuf[BUFSIZ];
+static char *
+yscale (int y)
+{
+ return (nscale (y, yp, ymm, ybuf, sizeof(ybuf)));
+}
+
+static char bbuf[BUFSIZ];
+static char *
+bscale (int b)
+{
+ return (nscale (b, bp, bmm, bbuf, sizeof(bbuf)));
+}
+
+/* end of pixel to inch, metric converter */
+
+int
+main (int argc, char **argv)
+{
+ register int i;
+ int tree = 0, stats = 0, bits = 0, events = 0, wm = 0, size = 0, shape = 0;
+ int frame = 0, children = 0;
+ int pauseatend = 0;
+ int use_root = 0;
+ xcb_window_t window = 0;
+ char *display_name = NULL;
+ const char *window_name = NULL;
+ struct wininfo wininfo;
+ struct wininfo *w = &wininfo;
+
+ program_name = argv[0];
+
+ if (!setlocale (LC_ALL, ""))
+ fprintf (stderr, "%s: can not set locale properly\n", program_name);
+#ifndef _MSC_VER
+ user_encoding = nl_langinfo (CODESET);
+#endif
+ if (user_encoding == NULL)
+ user_encoding = "unknown encoding";
+
+ memset (w, 0, sizeof(struct wininfo));
+
+ /* Handle our command line arguments */
+ for (i = 1; i < argc; i++) {
+ if (!strcmp (argv[i], "-help"))
+ usage ();
+ if (!strcmp (argv[i], "-display") || !strcmp (argv[i], "-d")) {
+ if (++i >= argc)
+ Fatal_Error("-display requires argument");
+ display_name = argv[i];
+ continue;
+ }
+ if (!strcmp (argv[i], "-root")) {
+ use_root = 1;
+ continue;
+ }
+ if (!strcmp (argv[i], "-id")) {
+ if (++i >= argc)
+ Fatal_Error("-id requires argument");
+ window = strtoul(argv[i], NULL, 0);
+ continue;
+ }
+ if (!strcmp (argv[i], "-name")) {
+ if (++i >= argc)
+ Fatal_Error("-name requires argument");
+ window_name = argv[i];
+ continue;
+ }
+ if (!strcmp (argv[i], "-int")) {
+ window_id_format = "%ld";
+ continue;
+ }
+ if (!strcmp (argv[i], "-children")) {
+ children = 1;
+ continue;
+ }
+ if (!strcmp (argv[i], "-tree")) {
+ tree = 1;
+ continue;
+ }
+ if (!strcmp (argv[i], "-stats")) {
+ stats = 1;
+ continue;
+ }
+ if (!strcmp (argv[i], "-bits")) {
+ bits = 1;
+ continue;
+ }
+ if (!strcmp (argv[i], "-events")) {
+ events = 1;
+ continue;
+ }
+ if (!strcmp (argv[i], "-wm")) {
+ wm = 1;
+ continue;
+ }
+ if (!strcmp (argv[i], "-frame")) {
+ frame = 1;
+ continue;
+ }
+ if (!strcmp (argv[i], "-size")) {
+ size = 1;
+ continue;
+ }
+ if (!strcmp (argv[i], "-shape")) {
+ shape = 1;
+ continue;
+ }
+ if (!strcmp (argv[i], "-english")) {
+ english = 1;
+ continue;
+ }
+ if (!strcmp (argv[i], "-metric")) {
+ metric = 1;
+ continue;
+ }
+ if (!strcmp (argv[i], "-all")) {
+ tree = stats = bits = events = wm = size = shape = 1;
+ continue;
+ }
+ if (!strcmp(argv[i], "-pause")) {
+ pauseatend = 1;
+ continue;
+ }
+ usage ();
+ }
+
+ Setup_Display_And_Screen (display_name, &dpy, &screen);
+
+ /* preload atoms we may need later */
+ Intern_Atom (dpy, "_NET_WM_NAME");
+ Intern_Atom (dpy, "UTF8_STRING");
+ if (wm) {
+ Intern_Atom (dpy, "_NET_WM_DESKTOP");
+ Intern_Atom (dpy, "_NET_WM_WINDOW_TYPE");
+ Intern_Atom (dpy, "_NET_WM_STATE");
+ Intern_Atom (dpy, "_NET_WM_PID");
+ Intern_Atom (dpy, "_NET_FRAME_EXTENTS");
+ }
+ /* initialize scaling data */
+ scale_init(screen);
+
+ if (use_root)
+ window = screen->root;
+ else if (window_name) {
+ window = Window_With_Name (dpy, screen->root, window_name);
+ if (!window)
+ Fatal_Error ("No window with name \"%s\" exists!", window_name);
+ }
+
+ /* If no window selected on command line, let user pick one the hard way */
+ if (!window) {
+ printf ("\n"
+ "xwininfo: Please select the window about which you\n"
+ " would like information by clicking the\n"
+ " mouse in that window.\n");
+ Intern_Atom (dpy, "_NET_VIRTUAL_ROOTS");
+ Intern_Atom (dpy, "WM_STATE");
+ window = Select_Window (dpy, screen, !frame);
+ }
+
+ /*
+ * Do the actual displaying as per parameters
+ */
+ if (!(children || tree || bits || events || wm || size))
+ stats = 1;
+
+ /*
+ * make sure that the window is valid
+ */
+ {
+ xcb_get_geometry_cookie_t gg_cookie =
+ xcb_get_geometry (dpy, window);
+
+ w->geometry = xcb_get_geometry_reply(dpy, gg_cookie, &err);
+
+ if (!w->geometry) {
+ char badid[20];
+
+ if (err)
+ Print_X_Error (dpy, err);
+
+ snprintf (badid, sizeof(badid), window_id_format, window);
+ Fatal_Error ("No such window with id %s.", badid);
+ }
+ }
+
+ /* Send requests to prefetch data we'll need */
+ w->window = window;
+ w->net_wm_name_cookie = get_net_wm_name (dpy, window);
+ w->wm_name_cookie = xcb_icccm_get_wm_name (dpy, window);
+ if (children || tree)
+ w->tree_cookie = xcb_query_tree (dpy, window);
+ if (stats) {
+ w->trans_coords_cookie =
+ xcb_translate_coordinates (dpy, window, w->geometry->root,
+ -(w->geometry->border_width),
+ -(w->geometry->border_width));
+ }
+ if (stats || bits || events)
+ w->attr_cookie = xcb_get_window_attributes (dpy, window);
+ if (stats || size)
+ w->normal_hints_cookie = xcb_icccm_get_wm_normal_hints (dpy, window);
+ if (wm) {
+ w->hints_cookie = xcb_icccm_get_wm_hints(dpy, window);
+
+ atom_net_wm_desktop = Get_Atom (dpy, "_NET_WM_DESKTOP");
+ if (atom_net_wm_desktop) {
+ w->wm_desktop_cookie = xcb_get_property
+ (dpy, False, window, atom_net_wm_desktop,
+ XCB_ATOM_CARDINAL, 0, 4);
+ }
+
+ atom_net_wm_window_type = Get_Atom (dpy, "_NET_WM_WINDOW_TYPE");
+ if (atom_net_wm_window_type) {
+ w->wm_window_type_cookie = xcb_get_property
+ (dpy, False, window, atom_net_wm_window_type,
+ XCB_ATOM_ATOM, 0, BUFSIZ);
+ }
+
+ atom_net_wm_state = Get_Atom (dpy, "_NET_WM_STATE");
+ if (atom_net_wm_state) {
+ w->wm_state_cookie = xcb_get_property
+ (dpy, False, window, atom_net_wm_state,
+ XCB_ATOM_ATOM, 0, BUFSIZ);
+ }
+
+ atom_net_wm_pid = Get_Atom (dpy, "_NET_WM_PID");
+ if (atom_net_wm_pid) {
+ w->wm_pid_cookie = xcb_get_property
+ (dpy, False, window, atom_net_wm_pid,
+ XCB_ATOM_CARDINAL, 0, BUFSIZ);
+ w->wm_client_machine_cookie = xcb_get_property
+ (dpy, False, window, XCB_ATOM_WM_CLIENT_MACHINE,
+ XCB_GET_PROPERTY_TYPE_ANY, 0, BUFSIZ);
+ }
+
+ atom_net_frame_extents = Get_Atom (dpy, "_NET_FRAME_EXTENTS");
+ if (atom_net_frame_extents) {
+ w->frame_extents_cookie = xcb_get_property
+ (dpy, False, window, atom_net_frame_extents,
+ XCB_ATOM_CARDINAL, 0, 4 * 4);
+ }
+ }
+ if (size)
+ w->zoom_cookie = xcb_icccm_get_wm_size_hints (dpy, window,
+ XCB_ATOM_WM_ZOOM_HINTS);
+ xcb_flush (dpy);
+
+ printf ("\nxwininfo: Window id: ");
+ Display_Window_Id (w, True);
+ if (children || tree)
+ Display_Tree_Info (w, tree);
+ if (stats)
+ Display_Stats_Info (w);
+ if (bits)
+ Display_Bits_Info (w);
+ if (events)
+ Display_Events_Info (w);
+ if (wm)
+ Display_WM_Info (w);
+ if (size)
+ Display_Size_Hints (w);
+ if (shape)
+ Display_Window_Shape (window);
+ printf ("\n");
+ if (pauseatend) getchar();
+
+ wininfo_wipe (w);
+ xcb_disconnect (dpy);
+#ifdef HAVE_ICONV
+ if (iconv_from_utf8 && (iconv_from_utf8 != (iconv_t) -1)) {
+ iconv_close (iconv_from_utf8);
+ }
+#endif
+ exit (0);
+}
+
+/* Ensure win_attributes field is filled in */
+static xcb_get_window_attributes_reply_t *
+fetch_win_attributes (struct wininfo *w)
+{
+ if (!w->win_attributes) {
+ w->win_attributes =
+ xcb_get_window_attributes_reply (dpy, w->attr_cookie, &err);
+
+ if (!w->win_attributes) {
+ Print_X_Error (dpy, err);
+ Fatal_Error ("Can't get window attributes.");
+ }
+ }
+ return w->win_attributes;
+}
+
+#ifndef USE_XCB_ICCCM
+static Bool
+wm_size_hints_reply (xcb_connection_t *dpy, xcb_get_property_cookie_t cookie,
+ wm_size_hints_t *hints_return, xcb_generic_error_t **err)
+{
+ xcb_get_property_reply_t *prop = xcb_get_property_reply (dpy, cookie, err);
+ int length;
+
+ if (!prop || (prop->type != XCB_ATOM_WM_SIZE_HINTS) ||
+ (prop->format != 32)) {
+ free (prop);
+ return False;
+ }
+
+ memset (hints_return, 0, sizeof(wm_size_hints_t));
+
+ length = xcb_get_property_value_length(prop);
+ if (length > sizeof(wm_size_hints_t))
+ length = sizeof(wm_size_hints_t);
+ memcpy (hints_return, xcb_get_property_value (prop), length);
+
+ free (prop);
+ return True;
+}
+
+#define xcb_icccm_get_wm_normal_hints_reply wm_size_hints_reply
+#define xcb_icccm_get_wm_size_hints_reply wm_size_hints_reply
+#endif
+
+
+
+/* Ensure normal_hints field is filled in */
+static xcb_size_hints_t *
+fetch_normal_hints (struct wininfo *w, xcb_size_hints_t *hints_return)
+{
+ xcb_size_hints_t hints;
+
+ if (!w->normal_hints) {
+ if (xcb_icccm_get_wm_normal_hints_reply (dpy, w->normal_hints_cookie,
+ &hints, NULL)) {
+ w->normal_hints = malloc (sizeof(xcb_size_hints_t));
+ if (w->normal_hints)
+ memcpy(w->normal_hints, &hints, sizeof(xcb_size_hints_t));
+ }
+ }
+ if (hints_return && w->normal_hints)
+ memcpy(hints_return, w->normal_hints, sizeof(xcb_size_hints_t));
+ return w->normal_hints;
+}
+
+
+/*
+ * Lookup: lookup a code in a table.
+ */
+static char _lookup_buffer[100];
+
+static const char *
+LookupL (long code, const binding *table)
+{
+ const char *name = NULL;
+
+ while (table->name) {
+ if (table->code == code) {
+ name = table->name;
+ break;
+ }
+ table++;
+ }
+
+ if (name == NULL) {
+ snprintf (_lookup_buffer, sizeof(_lookup_buffer),
+ "unknown (code = %ld. = 0x%lx)", code, code);
+ name = _lookup_buffer;
+ }
+
+ return (name);
+}
+
+static const char *
+Lookup (int code, const binding *table)
+{
+ return LookupL ((long)code, table);
+}
+
+/*
+ * Routine to display a window id in dec/hex with name if window has one
+ *
+ * Requires wininfo members initialized: window, wm_name_cookie
+ */
+
+static void
+Display_Window_Id (struct wininfo *w, Bool newline_wanted)
+{
+#ifdef USE_XCB_ICCCM
+ xcb_icccm_get_text_property_reply_t wmn_reply;
+ uint8_t got_reply = False;
+#endif
+ xcb_get_property_reply_t *prop;
+ const char *wm_name = NULL;
+ unsigned int wm_name_len = 0;
+ xcb_atom_t wm_name_encoding = XCB_NONE;
+
+ printf (window_id_format, w->window); /* print id # in hex/dec */
+
+ if (!w->window) {
+ printf (" (none)");
+ } else {
+ if (w->window == screen->root) {
+ printf (" (the root window)");
+ }
+ /* Get window name if any */
+ prop = xcb_get_property_reply (dpy, w->net_wm_name_cookie, NULL);
+ if (prop && (prop->type != XCB_NONE)) {
+ wm_name = xcb_get_property_value (prop);
+ wm_name_len = xcb_get_property_value_length (prop);
+ wm_name_encoding = prop->type;
+ } else { /* No _NET_WM_NAME, check WM_NAME */
+#ifdef USE_XCB_ICCCM
+ got_reply = xcb_icccm_get_wm_name_reply (dpy, w->wm_name_cookie,
+ &wmn_reply, NULL);
+ if (got_reply) {
+ wm_name = wmn_reply.name;
+ wm_name_len = wmn_reply.name_len;
+ wm_name_encoding = wmn_reply.encoding;
+ }
+#else
+ prop = xcb_get_property_reply (dpy, w->wm_name_cookie, NULL);
+ if (prop && (prop->type != XCB_NONE)) {
+ wm_name = xcb_get_property_value (prop);
+ wm_name_len = xcb_get_property_value_length (prop);
+ wm_name_encoding = prop->type;
+ }
+#endif
+ }
+ if (wm_name_len == 0) {
+ printf (" (has no name)");
+ } else {
+ if (wm_name_encoding == XCB_ATOM_STRING) {
+ printf (" \"%.*s\"", wm_name_len, wm_name);
+ } else if (wm_name_encoding == atom_utf8_string) {
+ print_utf8 (" \"", (char *) wm_name, wm_name_len, "\"");
+ } else {
+ /* Encodings we don't support, including COMPOUND_TEXT */
+ const char *enc_name = Get_Atom_Name (dpy, wm_name_encoding);
+ if (enc_name) {
+ printf (" (name in unsupported encoding %s)", enc_name);
+ } else {
+ printf (" (name in unsupported encoding ATOM 0x%x)",
+ wm_name_encoding);
+ }
+ }
+ }
+#ifdef USE_XCB_ICCCM
+ if (got_reply)
+ xcb_icccm_get_text_property_reply_wipe (&wmn_reply);
+#else
+ free (prop);
+#endif
+ }
+
+ if (newline_wanted)
+ printf ("\n");
+
+ return;
+}
+
+
+/*
+ * Display Stats on window
+ */
+static const binding _window_classes[] = {
+ { XCB_WINDOW_CLASS_INPUT_OUTPUT, "InputOutput" },
+ { XCB_WINDOW_CLASS_INPUT_ONLY, "InputOnly" },
+ { 0, NULL } };
+
+static const binding _map_states[] = {
+ { XCB_MAP_STATE_UNMAPPED, "IsUnMapped" },
+ { XCB_MAP_STATE_UNVIEWABLE, "IsUnviewable" },
+ { XCB_MAP_STATE_VIEWABLE, "IsViewable" },
+ { 0, NULL } };
+
+static const binding _backing_store_states[] = {
+ { XCB_BACKING_STORE_NOT_USEFUL, "NotUseful" },
+ { XCB_BACKING_STORE_WHEN_MAPPED,"WhenMapped" },
+ { XCB_BACKING_STORE_ALWAYS, "Always" },
+ { 0, NULL } };
+
+static const binding _bit_gravity_states[] = {
+ { XCB_GRAVITY_BIT_FORGET, "ForgetGravity" },
+ { XCB_GRAVITY_NORTH_WEST, "NorthWestGravity" },
+ { XCB_GRAVITY_NORTH, "NorthGravity" },
+ { XCB_GRAVITY_NORTH_EAST, "NorthEastGravity" },
+ { XCB_GRAVITY_WEST, "WestGravity" },
+ { XCB_GRAVITY_CENTER, "CenterGravity" },
+ { XCB_GRAVITY_EAST, "EastGravity" },
+ { XCB_GRAVITY_SOUTH_WEST, "SouthWestGravity" },
+ { XCB_GRAVITY_SOUTH, "SouthGravity" },
+ { XCB_GRAVITY_SOUTH_EAST, "SouthEastGravity" },
+ { XCB_GRAVITY_STATIC, "StaticGravity" },
+ { 0, NULL }};
+
+static const binding _window_gravity_states[] = {
+ { XCB_GRAVITY_WIN_UNMAP, "UnmapGravity" },
+ { XCB_GRAVITY_NORTH_WEST, "NorthWestGravity" },
+ { XCB_GRAVITY_NORTH, "NorthGravity" },
+ { XCB_GRAVITY_NORTH_EAST, "NorthEastGravity" },
+ { XCB_GRAVITY_WEST, "WestGravity" },
+ { XCB_GRAVITY_CENTER, "CenterGravity" },
+ { XCB_GRAVITY_EAST, "EastGravity" },
+ { XCB_GRAVITY_SOUTH_WEST, "SouthWestGravity" },
+ { XCB_GRAVITY_SOUTH, "SouthGravity" },
+ { XCB_GRAVITY_SOUTH_EAST, "SouthEastGravity" },
+ { XCB_GRAVITY_STATIC, "StaticGravity" },
+ { 0, NULL }};
+
+static const binding _visual_classes[] = {
+ { XCB_VISUAL_CLASS_STATIC_GRAY, "StaticGray" },
+ { XCB_VISUAL_CLASS_GRAY_SCALE, "GrayScale" },
+ { XCB_VISUAL_CLASS_STATIC_COLOR,"StaticColor" },
+ { XCB_VISUAL_CLASS_PSEUDO_COLOR,"PseudoColor" },
+ { XCB_VISUAL_CLASS_TRUE_COLOR, "TrueColor" },
+ { XCB_VISUAL_CLASS_DIRECT_COLOR,"DirectColor" },
+ { 0, NULL }};
+
+/*
+ * Requires wininfo members initialized:
+ * window, geometry, attr_cookie, trans_coords_cookie, normal_hints_cookie
+ */
+static void
+Display_Stats_Info (struct wininfo *w)
+{
+ xcb_translate_coordinates_reply_t *trans_coords;
+ xcb_get_window_attributes_reply_t *win_attributes;
+ xcb_size_hints_t hints;
+
+ int dw = screen->width_in_pixels, dh = screen->height_in_pixels;
+ int rx, ry, xright, ybelow;
+ int showright = 0, showbelow = 0;
+ xcb_window_t wmframe, parent;
+
+ trans_coords =
+ xcb_translate_coordinates_reply (dpy, w->trans_coords_cookie, NULL);
+ if (!trans_coords)
+ Fatal_Error ("Can't get translated coordinates.");
+
+ rx = (int16_t)trans_coords->dst_x;
+ ry = (int16_t)trans_coords->dst_y;
+ free (trans_coords);
+
+ xright = (dw - rx - w->geometry->border_width * 2 -
+ w->geometry->width);
+ ybelow = (dh - ry - w->geometry->border_width * 2 -
+ w->geometry->height);
+
+
+ printf ("\n");
+ printf (" Absolute upper-left X: %s\n", xscale (rx));
+ printf (" Absolute upper-left Y: %s\n", yscale (ry));
+ printf (" Relative upper-left X: %s\n", xscale (w->geometry->x));
+ printf (" Relative upper-left Y: %s\n", yscale (w->geometry->y));
+ printf (" Width: %s\n", xscale (w->geometry->width));
+ printf (" Height: %s\n", yscale (w->geometry->height));
+ printf (" Depth: %d\n", w->geometry->depth);
+
+ win_attributes = fetch_win_attributes (w);
+
+ printf (" Visual: 0x%lx\n", (unsigned long) win_attributes->visual);
+ if (screen)
+ {
+ xcb_depth_iterator_t depth_iter;
+ xcb_visualtype_t *visual_type = NULL;
+
+ depth_iter = xcb_screen_allowed_depths_iterator (screen);
+ for (; depth_iter.rem; xcb_depth_next (&depth_iter)) {
+ xcb_visualtype_iterator_t visual_iter;
+
+ visual_iter = xcb_depth_visuals_iterator (depth_iter.data);
+ for (; visual_iter.rem; xcb_visualtype_next (&visual_iter)) {
+ if (screen->root_visual == visual_iter.data->visual_id) {
+ visual_type = visual_iter.data;
+ break;
+ }
+ }
+ }
+ if (visual_type)
+ printf (" Visual Class: %s\n", Lookup (visual_type->_class,
+ _visual_classes));
+ }
+
+ printf (" Border width: %s\n", bscale (w->geometry->border_width));
+ printf (" Class: %s\n",
+ Lookup (win_attributes->_class, _window_classes));
+ printf (" Colormap: 0x%lx (%sinstalled)\n",
+ (unsigned long) win_attributes->colormap,
+ win_attributes->map_is_installed ? "" : "not ");
+ printf (" Bit Gravity State: %s\n",
+ Lookup (win_attributes->bit_gravity, _bit_gravity_states));
+ printf (" Window Gravity State: %s\n",
+ Lookup (win_attributes->win_gravity, _window_gravity_states));
+ printf (" Backing Store State: %s\n",
+ Lookup (win_attributes->backing_store, _backing_store_states));
+ printf (" Save Under State: %s\n",
+ win_attributes->save_under ? "yes" : "no");
+ printf (" Map State: %s\n",
+ Lookup (win_attributes->map_state, _map_states));
+ printf (" Override Redirect State: %s\n",
+ win_attributes->override_redirect ? "yes" : "no");
+ printf (" Corners: +%d+%d -%d+%d -%d-%d +%d-%d\n",
+ rx, ry, xright, ry, xright, ybelow, rx, ybelow);
+
+ /*
+ * compute geometry string that would recreate window
+ */
+ printf (" -geometry ");
+
+ /* compute size in appropriate units */
+ if (!fetch_normal_hints (w, &hints))
+ hints.flags = 0;
+
+ if ((hints.flags & XCB_ICCCM_SIZE_HINT_P_RESIZE_INC) &&
+ (hints.width_inc != 0) && (hints.height_inc != 0)) {
+ if (hints.flags &
+ (XCB_ICCCM_SIZE_HINT_BASE_SIZE|XCB_ICCCM_SIZE_HINT_P_MIN_SIZE)) {
+ if (hints.flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE) {
+ w->geometry->width -= hints.base_width;
+ w->geometry->height -= hints.base_height;
+ } else {
+ /* ICCCM says MinSize is default for BaseSize */
+ w->geometry->width -= hints.min_width;
+ w->geometry->height -= hints.min_height;
+ }
+ }
+ printf ("%dx%d", w->geometry->width/hints.width_inc,
+ w->geometry->height/hints.height_inc);
+ } else
+ printf ("%dx%d", w->geometry->width, w->geometry->height);
+
+ if (!(hints.flags & XCB_ICCCM_SIZE_HINT_P_WIN_GRAVITY))
+ hints.win_gravity = XCB_GRAVITY_NORTH_WEST; /* per ICCCM */
+ /* find our window manager frame, if any */
+ for (wmframe = parent = w->window; parent != 0 ; wmframe = parent) {
+ xcb_query_tree_cookie_t qt_cookie;
+ xcb_query_tree_reply_t *tree;
+
+ qt_cookie = xcb_query_tree (dpy, wmframe);
+ tree = xcb_query_tree_reply (dpy, qt_cookie, &err);
+ if (!tree) {
+ Print_X_Error (dpy, err);
+ Fatal_Error ("Can't query window tree.");
+ }
+ parent = tree->parent;
+ free (tree);
+ if (parent == w->geometry->root || !parent)
+ break;
+ }
+ if (wmframe != w->window) {
+ /* WM reparented, so find edges of the frame */
+ /* Only works for ICCCM-compliant WMs, and then only if the
+ window has corner gravity. We would need to know the original width
+ of the window to correctly handle the other gravities. */
+ xcb_get_geometry_cookie_t geom_cookie;
+ xcb_get_geometry_reply_t *frame_geometry;
+
+ geom_cookie = xcb_get_geometry (dpy, wmframe);
+ frame_geometry = xcb_get_geometry_reply (dpy, geom_cookie, &err);
+
+ if (!frame_geometry) {
+ Print_X_Error (dpy, err);
+ Fatal_Error ("Can't get frame geometry.");
+ }
+ switch (hints.win_gravity) {
+ case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST:
+ case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST:
+ case XCB_GRAVITY_WEST:
+ rx = frame_geometry->x;
+ }
+ switch (hints.win_gravity) {
+ case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST:
+ case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST:
+ case XCB_GRAVITY_EAST:
+ xright = dw - frame_geometry->x - frame_geometry->width -
+ (2 * frame_geometry->border_width);
+ }
+ switch (hints.win_gravity) {
+ case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST:
+ case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST:
+ case XCB_GRAVITY_NORTH:
+ ry = frame_geometry->y;
+ }
+ switch (hints.win_gravity) {
+ case XCB_GRAVITY_NORTH_WEST: case XCB_GRAVITY_SOUTH_WEST:
+ case XCB_GRAVITY_NORTH_EAST: case XCB_GRAVITY_SOUTH_EAST:
+ case XCB_GRAVITY_SOUTH:
+ ybelow = dh - frame_geometry->y - frame_geometry->height -
+ (2 * frame_geometry->border_width);
+ }
+ free (frame_geometry);
+ }
+ /* If edge gravity, offer a corner on that edge (because the application
+ programmer cares about that edge), otherwise offer upper left unless
+ some other corner is close to an edge of the screen.
+ (For corner gravity, assume gravity was set by XWMGeometry.
+ For CenterGravity, it doesn't matter.) */
+ if (hints.win_gravity == XCB_GRAVITY_EAST ||
+ (abs (xright) <= 100 && abs (xright) < abs (rx)
+ && hints.win_gravity != XCB_GRAVITY_WEST))
+ showright = 1;
+ if (hints.win_gravity == XCB_GRAVITY_SOUTH ||
+ (abs (ybelow) <= 100 && abs (ybelow) < abs (ry)
+ && hints.win_gravity != XCB_GRAVITY_NORTH))
+ showbelow = 1;
+
+ if (showright)
+ printf ("-%d", xright);
+ else
+ printf ("+%d", rx);
+ if (showbelow)
+ printf ("-%d", ybelow);
+ else
+ printf ("+%d", ry);
+ printf ("\n");
+}
+
+
+/*
+ * Display bits info:
+ */
+static const binding _gravities[] = {
+ /* WARNING: the first two of these have the same value - see code */
+ { XCB_GRAVITY_WIN_UNMAP, "UnMapGravity" },
+ { XCB_GRAVITY_BIT_FORGET, "ForgetGravity" },
+ { XCB_GRAVITY_NORTH_WEST, "NorthWestGravity" },
+ { XCB_GRAVITY_NORTH, "NorthGravity" },
+ { XCB_GRAVITY_NORTH_EAST, "NorthEastGravity" },
+ { XCB_GRAVITY_WEST, "WestGravity" },
+ { XCB_GRAVITY_CENTER, "CenterGravity" },
+ { XCB_GRAVITY_EAST, "EastGravity" },
+ { XCB_GRAVITY_SOUTH_WEST, "SouthWestGravity" },
+ { XCB_GRAVITY_SOUTH, "SouthGravity" },
+ { XCB_GRAVITY_SOUTH_EAST, "SouthEastGravity" },
+ { XCB_GRAVITY_STATIC, "StaticGravity" },
+ { 0, NULL } };
+
+static const binding _backing_store_hint[] = {
+ { XCB_BACKING_STORE_NOT_USEFUL, "NotUseful" },
+ { XCB_BACKING_STORE_WHEN_MAPPED,"WhenMapped" },
+ { XCB_BACKING_STORE_ALWAYS, "Always" },
+ { 0, NULL } };
+
+static const binding _bool[] = {
+ { 0, "No" },
+ { 1, "Yes" },
+ { 0, NULL } };
+
+/*
+ * Requires wininfo members initialized:
+ * window, attr_cookie (or win_attributes)
+ */
+static void
+Display_Bits_Info (struct wininfo * w)
+{
+ xcb_get_window_attributes_reply_t *win_attributes
+ = fetch_win_attributes (w);
+
+ printf ("\n");
+ printf (" Bit gravity: %s\n",
+ Lookup (win_attributes->bit_gravity, _gravities+1));
+ printf (" Window gravity: %s\n",
+ Lookup (win_attributes->win_gravity, _gravities));
+ printf (" Backing-store hint: %s\n",
+ Lookup (win_attributes->backing_store, _backing_store_hint));
+ printf (" Backing-planes to be preserved: 0x%lx\n",
+ (unsigned long) win_attributes->backing_planes);
+ printf (" Backing pixel: %ld\n",
+ (unsigned long) win_attributes->backing_pixel);
+ printf (" Save-unders: %s\n",
+ Lookup (win_attributes->save_under, _bool));
+}
+
+
+/*
+ * Routine to display all events in an event mask
+ */
+static const binding _event_mask_names[] = {
+ { XCB_EVENT_MASK_KEY_PRESS, "KeyPress" },
+ { XCB_EVENT_MASK_KEY_RELEASE, "KeyRelease" },
+ { XCB_EVENT_MASK_BUTTON_PRESS, "ButtonPress" },
+ { XCB_EVENT_MASK_BUTTON_RELEASE, "ButtonRelease" },
+ { XCB_EVENT_MASK_ENTER_WINDOW, "EnterWindow" },
+ { XCB_EVENT_MASK_LEAVE_WINDOW, "LeaveWindow" },
+ { XCB_EVENT_MASK_POINTER_MOTION, "PointerMotion" },
+ { XCB_EVENT_MASK_POINTER_MOTION_HINT, "PointerMotionHint" },
+ { XCB_EVENT_MASK_BUTTON_1_MOTION, "Button1Motion" },
+ { XCB_EVENT_MASK_BUTTON_2_MOTION, "Button2Motion" },
+ { XCB_EVENT_MASK_BUTTON_3_MOTION, "Button3Motion" },
+ { XCB_EVENT_MASK_BUTTON_4_MOTION, "Button4Motion" },
+ { XCB_EVENT_MASK_BUTTON_5_MOTION, "Button5Motion" },
+ { XCB_EVENT_MASK_BUTTON_MOTION, "ButtonMotion" },
+ { XCB_EVENT_MASK_KEYMAP_STATE, "KeymapState" },
+ { XCB_EVENT_MASK_EXPOSURE, "Exposure" },
+ { XCB_EVENT_MASK_VISIBILITY_CHANGE, "VisibilityChange" },
+ { XCB_EVENT_MASK_STRUCTURE_NOTIFY, "StructureNotify" },
+ { XCB_EVENT_MASK_RESIZE_REDIRECT, "ResizeRedirect" },
+ { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, "SubstructureNotify" },
+ { XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, "SubstructureRedirect" },
+ { XCB_EVENT_MASK_FOCUS_CHANGE, "FocusChange" },
+ { XCB_EVENT_MASK_PROPERTY_CHANGE, "PropertyChange" },
+ { XCB_EVENT_MASK_COLOR_MAP_CHANGE, "ColormapChange" },
+ { XCB_EVENT_MASK_OWNER_GRAB_BUTTON, "OwnerGrabButton" },
+ { 0, NULL } };
+
+static void
+Display_Event_Mask (long mask)
+{
+ long bit, bit_mask;
+
+ for (bit=0, bit_mask=1; bit < sizeof(long)*8; bit++, bit_mask <<= 1)
+ if (mask & bit_mask)
+ printf (" %s\n",
+ LookupL (bit_mask, _event_mask_names));
+}
+
+
+/*
+ * Display info on events
+ *
+ * Requires wininfo members initialized:
+ * window, attr_cookie (or win_attributes)
+ */
+static void
+Display_Events_Info (struct wininfo *w)
+{
+ xcb_get_window_attributes_reply_t *win_attributes
+ = fetch_win_attributes (w);
+
+ printf ("\n");
+ printf (" Someone wants these events:\n");
+ Display_Event_Mask (win_attributes->all_event_masks);
+
+ printf (" Do not propagate these events:\n");
+ Display_Event_Mask (win_attributes->do_not_propagate_mask);
+
+ printf (" Override redirection?: %s\n",
+ Lookup (win_attributes->override_redirect, _bool));
+}
+
+
+ /* left out visual stuff */
+ /* left out colormap */
+ /* left out map_installed */
+
+
+/*
+ * Display root, parent, and (recursively) children information
+ * recurse - true to show children information
+ *
+ * Requires wininfo members initialized: window, tree_cookie
+ */
+static void
+Display_Tree_Info (struct wininfo *w, int recurse)
+{
+ display_tree_info_1 (w, recurse, 0);
+}
+
+/*
+ * level - recursion level
+ */
+static void
+display_tree_info_1 (struct wininfo *w, int recurse, int level)
+{
+ int i, j;
+ unsigned int num_children;
+ xcb_query_tree_reply_t *tree;
+
+ tree = xcb_query_tree_reply (dpy, w->tree_cookie, &err);
+ if (!tree) {
+ Print_X_Error (dpy, err);
+ Fatal_Error ("Can't query window tree.");
+ }
+
+ if (level == 0) {
+ struct wininfo rw, pw;
+ rw.window = tree->root;
+ rw.net_wm_name_cookie = get_net_wm_name (dpy, rw.window);
+ rw.wm_name_cookie = xcb_icccm_get_wm_name (dpy, rw.window);
+ pw.window = tree->parent;
+ pw.net_wm_name_cookie = get_net_wm_name (dpy, pw.window);
+ pw.wm_name_cookie = xcb_icccm_get_wm_name (dpy, pw.window);
+ xcb_flush (dpy);
+
+ printf ("\n");
+ printf (" Root window id: ");
+ Display_Window_Id (&rw, True);
+ printf (" Parent window id: ");
+ Display_Window_Id (&pw, True);
+ }
+
+ num_children = xcb_query_tree_children_length (tree);
+
+ if (level == 0 || num_children > 0) {
+ printf (" ");
+ for (j = 0; j < level; j++) printf (" ");
+ printf ("%d child%s%s\n", num_children, num_children == 1 ? "" : "ren",
+ num_children ? ":" : ".");
+ }
+
+ if (num_children > 0) {
+ xcb_window_t *child_list = xcb_query_tree_children (tree);
+ struct wininfo *children
+ = calloc (num_children, sizeof(struct wininfo));
+
+ if (children == NULL)
+ Fatal_Error ("Failed to allocate memory in display_tree_info");
+
+ for (i = (int)num_children - 1; i >= 0; i--) {
+ struct wininfo *cw = &children[i];
+
+ cw->window = child_list[i];
+ cw->net_wm_name_cookie = get_net_wm_name (dpy, child_list[i]);
+ cw->wm_name_cookie = xcb_icccm_get_wm_name (dpy, child_list[i]);
+ cw->wm_class_cookie = xcb_icccm_get_wm_class (dpy, child_list[i]);
+ cw->geometry_cookie = xcb_get_geometry (dpy, child_list[i]);
+ cw->trans_coords_cookie = xcb_translate_coordinates
+ (dpy, child_list[i], tree->root, 0, 0);
+ if (recurse)
+ cw->tree_cookie = xcb_query_tree (dpy, child_list[i]);
+ }
+ xcb_flush (dpy);
+
+ for (i = (int)num_children - 1; i >= 0; i--) {
+ struct wininfo *cw = &children[i];
+ Bool got_wm_class = False;
+ char *instance_name = NULL, *class_name = NULL;
+ int instance_name_len, class_name_len;
+#ifdef USE_XCB_ICCCM
+ xcb_icccm_get_wm_class_reply_t classhint;
+#else
+ xcb_get_property_reply_t *classprop;
+#endif
+ xcb_get_geometry_reply_t *geometry;
+
+ printf (" ");
+ for (j = 0; j < level; j++) printf (" ");
+ Display_Window_Id (cw, False);
+ printf (": (");
+
+#ifdef USE_XCB_ICCCM
+ if (xcb_icccm_get_wm_class_reply (dpy, cw->wm_class_cookie,
+ &classhint, NULL)) {
+ got_wm_class = True;
+ instance_name = classhint.instance_name;
+ class_name = classhint.class_name;
+ instance_name_len = strlen(instance_name);
+ class_name_len = strlen(class_name);
+ }
+#else
+ classprop = xcb_get_property_reply
+ (dpy, cw->wm_class_cookie, NULL);
+ if (classprop) {
+ if (classprop->type == XCB_ATOM_STRING &&
+ classprop->format == 8) {
+ int proplen = xcb_get_property_value_length (classprop);
+
+ instance_name = xcb_get_property_value (classprop);
+ instance_name_len = strnlen (instance_name, proplen);
+ if (instance_name_len < proplen) {
+ class_name = instance_name + instance_name_len + 1;
+ class_name_len = strnlen
+ (class_name, proplen - (instance_name_len + 1));
+ } else
+ class_name_len = 0;
+ got_wm_class = True;
+ }
+ else
+ free (classprop);
+ }
+#endif
+
+ if (got_wm_class) {
+ if (instance_name)
+ printf ("\"%.*s\" ", instance_name_len, instance_name);
+ else
+ printf ("(none) ");
+
+ if (class_name)
+ printf ("\"%.*s\") ", class_name_len, class_name);
+ else
+ printf ("(none)) ");
+
+#ifdef USE_XCB_ICCCM
+ xcb_icccm_get_wm_class_reply_wipe (&classhint);
+#else
+ free (classprop);
+#endif
+ } else
+ printf (") ");
+
+ geometry = xcb_get_geometry_reply(dpy, cw->geometry_cookie, &err);
+ if (geometry) {
+ xcb_translate_coordinates_reply_t *trans_coords;
+
+ printf (" %ux%u+%d+%d", geometry->width, geometry->height,
+ geometry->x, geometry->y);
+
+ trans_coords = xcb_translate_coordinates_reply
+ (dpy, cw->trans_coords_cookie, &err);
+
+ if (trans_coords) {
+ int16_t abs_x = (int16_t) trans_coords->dst_x;
+ int16_t abs_y = (int16_t) trans_coords->dst_y;
+ int border = geometry->border_width;
+
+ printf (" +%d+%d", abs_x - border, abs_y - border);
+ free (trans_coords);
+ } else if (err) {
+ Print_X_Error (dpy, err);
+ }
+
+ free (geometry);
+ } else if (err) {
+ Print_X_Error (dpy, err);
+ }
+ printf ("\n");
+
+ if (recurse)
+ display_tree_info_1 (cw, 1, level+1);
+
+ wininfo_wipe (cw);
+ }
+ free (children);
+ }
+
+ free (tree); /* includes storage for child_list[] */
+}
+
+
+/*
+ * Display a set of size hints
+ */
+static void
+Display_Hints (xcb_size_hints_t *hints)
+{
+ long flags;
+
+ flags = hints->flags;
+
+ if (flags & XCB_ICCCM_SIZE_HINT_US_POSITION)
+ printf (" User supplied location: %s, %s\n",
+ xscale (hints->x), yscale (hints->y));
+
+ if (flags & XCB_ICCCM_SIZE_HINT_P_POSITION)
+ printf (" Program supplied location: %s, %s\n",
+ xscale (hints->x), yscale (hints->y));
+
+ if (flags & XCB_ICCCM_SIZE_HINT_US_SIZE) {
+ printf (" User supplied size: %s by %s\n",
+ xscale (hints->width), yscale (hints->height));
+ }
+
+ if (flags & XCB_ICCCM_SIZE_HINT_P_SIZE)
+ printf (" Program supplied size: %s by %s\n",
+ xscale (hints->width), yscale (hints->height));
+
+ if (flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE)
+ printf (" Program supplied minimum size: %s by %s\n",
+ xscale (hints->min_width), yscale (hints->min_height));
+
+ if (flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE)
+ printf (" Program supplied maximum size: %s by %s\n",
+ xscale (hints->max_width), yscale (hints->max_height));
+
+ if (flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE) {
+ printf (" Program supplied base size: %s by %s\n",
+ xscale (hints->base_width), yscale (hints->base_height));
+ }
+
+ if (flags & XCB_ICCCM_SIZE_HINT_P_RESIZE_INC) {
+ printf (" Program supplied x resize increment: %s\n",
+ xscale (hints->width_inc));
+ printf (" Program supplied y resize increment: %s\n",
+ yscale (hints->height_inc));
+ if (hints->width_inc != 0 && hints->height_inc != 0) {
+ if (flags & XCB_ICCCM_SIZE_HINT_US_SIZE)
+ printf (" User supplied size in resize increments: %s by %s\n",
+ (xscale (hints->width / hints->width_inc)),
+ (yscale (hints->height / hints->height_inc)));
+ if (flags & XCB_ICCCM_SIZE_HINT_P_SIZE)
+ printf (" Program supplied size in resize increments: %s by %s\n",
+ (xscale (hints->width / hints->width_inc)),
+ (yscale (hints->height / hints->height_inc)));
+ if (flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE)
+ printf (" Program supplied minimum size in resize increments: %s by %s\n",
+ xscale (hints->min_width / hints->width_inc), yscale (hints->min_height / hints->height_inc));
+ if (flags & XCB_ICCCM_SIZE_HINT_BASE_SIZE)
+ printf (" Program supplied base size in resize increments: %s by %s\n",
+ (xscale (hints->base_width / hints->width_inc)),
+ (yscale (hints->base_height / hints->height_inc)));
+ }
+ }
+
+ if (flags & XCB_ICCCM_SIZE_HINT_P_ASPECT) {
+ printf (" Program supplied min aspect ratio: %s/%s\n",
+ xscale (hints->min_aspect_num), yscale (hints->min_aspect_den));
+ printf (" Program supplied max aspect ratio: %s/%s\n",
+ xscale (hints->max_aspect_num), yscale (hints->max_aspect_den));
+ }
+
+ if (flags & XCB_ICCCM_SIZE_HINT_P_WIN_GRAVITY) {
+ printf (" Program supplied window gravity: %s\n",
+ Lookup (hints->win_gravity, _gravities));
+ }
+}
+
+
+/*
+ * Display Size Hints info
+ */
+static void
+Display_Size_Hints (struct wininfo *w)
+{
+ xcb_size_hints_t hints;
+
+ printf ("\n");
+ if (!fetch_normal_hints (w, &hints))
+ printf (" No normal window size hints defined\n");
+ else {
+ printf (" Normal window size hints:\n");
+ Display_Hints (&hints);
+ }
+
+ if (!xcb_icccm_get_wm_size_hints_reply (dpy, w->zoom_cookie, &hints, NULL))
+ printf (" No zoom window size hints defined\n");
+ else {
+ printf (" Zoom window size hints:\n");
+ Display_Hints (&hints);
+ }
+}
+
+
+static void
+Display_Window_Shape (xcb_window_t window)
+{
+ const xcb_query_extension_reply_t *shape_query;
+ xcb_shape_query_extents_cookie_t extents_cookie;
+ xcb_shape_query_extents_reply_t *extents;
+
+ shape_query = xcb_get_extension_data (dpy, &xcb_shape_id);
+ if (!shape_query->present)
+ return;
+
+ printf ("\n");
+
+ extents_cookie = xcb_shape_query_extents (dpy, window);
+ extents = xcb_shape_query_extents_reply (dpy, extents_cookie, &err);
+
+ if (!extents) {
+ if (err)
+ Print_X_Error (dpy, err);
+ else
+ {
+ printf (" No window shape defined\n");
+ printf (" No border shape defined\n");
+ }
+ return;
+ }
+
+ if (!extents->bounding_shaped)
+ printf (" No window shape defined\n");
+ else {
+ printf (" Window shape extents: %sx%s",
+ xscale (extents->bounding_shape_extents_width),
+ yscale (extents->bounding_shape_extents_height));
+ printf ("+%s+%s\n",
+ xscale (extents->bounding_shape_extents_x),
+ yscale (extents->bounding_shape_extents_y));
+ }
+ if (!extents->clip_shaped)
+ printf (" No border shape defined\n");
+ else {
+ printf (" Border shape extents: %sx%s",
+ xscale (extents->clip_shape_extents_width),
+ yscale (extents->clip_shape_extents_height));
+ printf ("+%s+%s\n",
+ xscale (extents->clip_shape_extents_x),
+ yscale (extents->clip_shape_extents_y));
+ }
+
+ free (extents);
+}
+
+/*
+ * Display Window Manager Info
+ *
+ * Requires wininfo members initialized:
+ * window, hints_cookie
+ */
+static const binding _state_hints[] = {
+ { XCB_ICCCM_WM_STATE_WITHDRAWN, "Withdrawn State" },
+ { XCB_ICCCM_WM_STATE_NORMAL, "Normal State" },
+ { XCB_ICCCM_WM_STATE_ICONIC, "Iconic State" },
+/* xwininfo previously also reported the ZoomState & InactiveState,
+ but ICCCM declared those obsolete long ago */
+ { 0, NULL } };
+
+#ifndef USE_XCB_ICCCM
+static Bool
+wm_hints_reply (xcb_connection_t *dpy, xcb_get_property_cookie_t cookie,
+ wm_hints_t *hints_return, xcb_generic_error_t **err)
+{
+ xcb_get_property_reply_t *prop = xcb_get_property_reply (dpy, cookie, err);
+ int length;
+
+ if (!prop || (prop->type != XCB_ATOM_WM_HINTS) || (prop->format != 32)) {
+ free (prop);
+ return False;
+ }
+
+ memset (hints_return, 0, sizeof(wm_hints_t));
+
+ length = xcb_get_property_value_length(prop);
+ if (length > sizeof(wm_hints_t))
+ length = sizeof(wm_hints_t);
+ memcpy (hints_return, xcb_get_property_value (prop), length);
+
+ free (prop);
+ return True;
+}
+
+#define xcb_icccm_get_wm_hints_reply wm_hints_reply
+#endif
+
+static void
+Display_WM_Info (struct wininfo *w)
+{
+ xcb_icccm_wm_hints_t wmhints;
+ long flags;
+ xcb_get_property_reply_t *prop;
+ int i;
+
+ printf ("\n");
+ if (!xcb_icccm_get_wm_hints_reply(dpy, w->hints_cookie, &wmhints, &err))
+ {
+ printf (" No window manager hints defined\n");
+ if (err)
+ Print_X_Error (dpy, err);
+ flags = 0;
+ } else
+ flags = wmhints.flags;
+
+ printf (" Window manager hints:\n");
+
+ if (flags & XCB_ICCCM_WM_HINT_INPUT)
+ printf (" Client accepts input or input focus: %s\n",
+ Lookup (wmhints.input, _bool));
+
+ if (flags & XCB_ICCCM_WM_HINT_ICON_WINDOW) {
+ struct wininfo iw;
+ iw.window = wmhints.icon_window;
+ iw.net_wm_name_cookie = get_net_wm_name (dpy, iw.window);
+ iw.wm_name_cookie = xcb_icccm_get_wm_name (dpy, iw.window);
+
+ printf (" Icon window id: ");
+ Display_Window_Id (&iw, True);
+ }
+
+ if (flags & XCB_ICCCM_WM_HINT_ICON_POSITION)
+ printf (" Initial icon position: %s, %s\n",
+ xscale (wmhints.icon_x), yscale (wmhints.icon_y));
+
+ if (flags & XCB_ICCCM_WM_HINT_STATE)
+ printf (" Initial state is %s\n",
+ Lookup (wmhints.initial_state, _state_hints));
+
+ if (atom_net_wm_desktop) {
+ prop = xcb_get_property_reply (dpy, w->wm_desktop_cookie, NULL);
+ if (prop && (prop->type != XCB_NONE)) {
+ uint32_t *desktop = xcb_get_property_value (prop);
+ if (*desktop == 0xFFFFFFFF) {
+ printf (" Displayed on all desktops\n");
+ } else {
+ printf (" Displayed on desktop %d\n", *desktop);
+ }
+ }
+ free (prop);
+ }
+
+ if (atom_net_wm_window_type) {
+ prop = xcb_get_property_reply (dpy, w->wm_window_type_cookie,
+ NULL);
+ if (prop && (prop->type != XCB_NONE) && (prop->value_len > 0)) {
+ xcb_atom_t *atoms = xcb_get_property_value (prop);
+ int atom_count = prop->value_len;
+
+ if (atom_count > 0) {
+ printf (" Window type:\n");
+ for (i = 0; i < atom_count; i++) {
+ const char *atom_name = Get_Atom_Name (dpy, atoms[i]);
+
+ if (atom_name) {
+ print_friendly_name (" %s\n", atom_name,
+ "_NET_WM_WINDOW_TYPE_");
+ } else {
+ printf (" (unresolvable ATOM 0x%x)\n",
+ atoms[i]);
+ }
+ }
+ }
+ }
+ free (prop);
+ }
+
+ if (atom_net_wm_state) {
+ prop = xcb_get_property_reply (dpy, w->wm_state_cookie, NULL);
+ if (prop && (prop->type != XCB_NONE) && (prop->value_len > 0)) {
+ xcb_atom_t *atoms = xcb_get_property_value (prop);
+ int atom_count = prop->value_len;
+
+ if (atom_count > 0) {
+ printf (" Window state:\n");
+ for (i = 0; i < atom_count; i++) {
+ const char *atom_name = Get_Atom_Name (dpy, atoms[i]);
+
+ if (atom_name) {
+ print_friendly_name (" %s\n", atom_name,
+ "_NET_WM_STATE_");
+ } else {
+ printf (" (unresolvable ATOM 0x%x)\n",
+ atoms[i]);
+ }
+ }
+ }
+ }
+ free (prop);
+ }
+
+ if (atom_net_wm_pid) {
+ printf (" Process id: ");
+ prop = xcb_get_property_reply (dpy, w->wm_pid_cookie, NULL);
+ if (prop && (prop->type == XCB_ATOM_CARDINAL)) {
+ uint32_t *pid = xcb_get_property_value (prop);
+ printf ("%d", *pid);
+ } else {
+ printf ("(unknown)");
+ }
+ free (prop);
+
+ prop = xcb_get_property_reply (dpy, w->wm_client_machine_cookie, NULL);
+ if (prop && (prop->type == XCB_ATOM_STRING)) {
+ const char *hostname = xcb_get_property_value (prop);
+ int hostname_len = xcb_get_property_value_length (prop);
+ printf (" on host %.*s", hostname_len, hostname);
+ }
+ printf ("\n");
+ free (prop);
+ }
+
+ if (atom_net_frame_extents) {
+ prop = xcb_get_property_reply (dpy, w->frame_extents_cookie, NULL);
+ if (prop && (prop->type == XCB_ATOM_CARDINAL)
+ && (prop->value_len == 4)) {
+ uint32_t *extents = xcb_get_property_value (prop);
+
+ printf (" Frame extents: %d, %d, %d, %d\n",
+ extents[0], extents[1], extents[2], extents[3]);
+ }
+ free (prop);
+ }
+}
+
+/* Frees all members of a wininfo struct, but not the struct itself */
+static void
+wininfo_wipe (struct wininfo *w)
+{
+ free (w->geometry);
+ free (w->win_attributes);
+ free (w->normal_hints);
+}
+
+/* Gets UTF-8 encoded EMWH property _NET_WM_NAME for a window */
+static xcb_get_property_cookie_t
+get_net_wm_name (xcb_connection_t *dpy, xcb_window_t win)
+{
+ if (!atom_net_wm_name)
+ atom_net_wm_name = Get_Atom (dpy, "_NET_WM_NAME");
+
+ if (!atom_utf8_string)
+ atom_utf8_string = Get_Atom (dpy, "UTF8_STRING");
+
+ if (atom_net_wm_name && atom_utf8_string)
+ return xcb_get_property (dpy, False, win, atom_net_wm_name,
+ atom_utf8_string, 0, BUFSIZ);
+ else {
+ xcb_get_property_cookie_t dummy = { 0 };
+ return dummy;
+ }
+}
+
+/* [Copied from code added by Yang Zhao to xprop/xprop.c]
+ *
+ * Validate a string as UTF-8 encoded according to RFC 3629
+ *
+ * Simply, a unicode code point (up to 21-bits long) is encoded as follows:
+ *
+ * Char. number range | UTF-8 octet sequence
+ * (hexadecimal) | (binary)
+ * --------------------+---------------------------------------------
+ * 0000 0000-0000 007F | 0xxxxxxx
+ * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
+ * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
+ * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ *
+ * Validation is done left-to-right, and an error condition, if any, refers to
+ * only the left-most problem in the string.
+ *
+ * Return values:
+ * UTF8_VALID: Valid UTF-8 encoded string
+ * UTF8_OVERLONG: Using more bytes than needed for a code point
+ * UTF8_SHORT_TAIL: Not enough bytes in a multi-byte sequence
+ * UTF8_LONG_TAIL: Too many bytes in a multi-byte sequence
+ * UTF8_FORBIDDEN_VALUE: Forbidden prefix or code point outside 0x10FFFF
+ */
+#define UTF8_VALID 0
+#define UTF8_FORBIDDEN_VALUE 1
+#define UTF8_OVERLONG 2
+#define UTF8_SHORT_TAIL 3
+#define UTF8_LONG_TAIL 4
+static int
+is_valid_utf8 (const char *string, int len)
+{
+ unsigned long codepoint;
+ int rem, i;
+ unsigned char c;
+
+ rem = 0;
+ for (i = 0; i < len; i++) {
+ c = (unsigned char) string[i];
+
+ /* Order of type check:
+ * - Single byte code point
+ * - Non-starting byte of multi-byte sequence
+ * - Start of 2-byte sequence
+ * - Start of 3-byte sequence
+ * - Start of 4-byte sequence
+ */
+ if (!(c & 0x80)) {
+ if (rem > 0) return UTF8_SHORT_TAIL;
+ rem = 0;
+ codepoint = c;
+ } else if ((c & 0xC0) == 0x80) {
+ if (rem == 0) return UTF8_LONG_TAIL;
+ rem--;
+ codepoint |= (c & 0x3F) << (rem * 6);
+ if (codepoint == 0) return UTF8_OVERLONG;
+ } else if ((c & 0xE0) == 0xC0) {
+ if (rem > 0) return UTF8_SHORT_TAIL;
+ rem = 1;
+ codepoint = (c & 0x1F) << 6;
+ if (codepoint == 0) return UTF8_OVERLONG;
+ } else if ((c & 0xF0) == 0xE0) {
+ if (rem > 0) return UTF8_SHORT_TAIL;
+ rem = 2;
+ codepoint = (c & 0x0F) << 12;
+ } else if ((c & 0xF8) == 0xF0) {
+ if (rem > 0) return UTF8_SHORT_TAIL;
+ rem = 3;
+ codepoint = (c & 0x07) << 18;
+ if (codepoint > 0x10FFFF) return UTF8_FORBIDDEN_VALUE;
+ } else
+ return UTF8_FORBIDDEN_VALUE;
+ }
+
+ return UTF8_VALID;
+}
+
+/*
+ * Converts a UTF-8 encoded string to the current locale encoding,
+ * if possible, and prints it, with prefix before and suffix after.
+ * Length of the string is specified in bytes, or -1 for going until '\0'
+ */
+static void
+print_utf8 (const char *prefix, char *u8str, size_t length, const char *suffix)
+{
+ size_t inlen = length;
+
+ if (inlen < 0) {
+ inlen = strlen (u8str);
+ }
+
+ if (is_valid_utf8 (u8str, inlen) != UTF8_VALID) {
+ printf (" (invalid UTF8_STRING)");
+ return;
+ }
+
+ if (strcmp (user_encoding, "UTF-8") == 0) {
+ /* Don't need to convert */
+ printf ("%s", prefix);
+ fwrite (u8str, 1, inlen, stdout);
+ printf ("%s", suffix);
+ return;
+ }
+
+#ifdef HAVE_ICONV
+ if (!iconv_from_utf8) {
+ iconv_from_utf8 = iconv_open (user_encoding, "UTF-8");
+ }
+
+ if (iconv_from_utf8 != (iconv_t) -1) {
+ Bool done = True;
+ char *inp = u8str;
+ char convbuf[BUFSIZ];
+ int convres;
+
+ printf ("%s", prefix);
+ do {
+ char *outp = convbuf;
+ size_t outlen = sizeof(convbuf);
+
+ convres = iconv (iconv_from_utf8, &inp, &inlen, &outp, &outlen);
+
+ if ((convres == -1) && (errno == E2BIG)) {
+ done = False;
+ convres = 0;
+ }
+
+ if (convres == 0) {
+ fwrite (convbuf, 1, sizeof(convbuf) - outlen, stdout);
+ } else {
+ printf (" (failure in conversion from UTF8_STRING to %s)",
+ user_encoding);
+ }
+ } while (!done);
+ printf ("%s", suffix);
+ } else {
+ printf (" (can't load iconv conversion for UTF8_STRING to %s)",
+ user_encoding);
+ }
+#else
+ printf (" (can't convert UTF8_STRING to %s)", user_encoding);
+#endif
+}
+
+/*
+ * Takes a string such as an atom name, strips the prefix, converts
+ * underscores to spaces, lowercases all but the first letter of each word,
+ * and prints it.
+ */
+static void
+print_friendly_name (const char *format, const char *string,
+ const char *prefix)
+{
+ const char *name_start = string;
+ char *lowered_name, *n;
+ int prefix_len = strlen (prefix);
+
+ if (strncmp (name_start, prefix, prefix_len) == 0) {
+ name_start += prefix_len;
+ }
+
+ lowered_name = strdup (name_start);
+ if (lowered_name) {
+ Bool first = True;
+
+ for (n = lowered_name ; *n != 0 ; n++) {
+ if (*n == '_') {
+ *n = ' ';
+ first = True;
+ } else if (first) {
+ first = False;
+ } else {
+ *n = tolower(*n);
+ }
+ }
+ name_start = lowered_name;
+ }
+
+ printf (format, name_start);
+ free (lowered_name);
+}
|