diff options
Diffstat (limited to 'apps/xwininfo/xwininfo.c')
-rw-r--r-- | apps/xwininfo/xwininfo.c | 2398 |
1 files changed, 1619 insertions, 779 deletions
diff --git a/apps/xwininfo/xwininfo.c b/apps/xwininfo/xwininfo.c index 838408ab3..265f6c611 100644 --- a/apps/xwininfo/xwininfo.c +++ b/apps/xwininfo/xwininfo.c @@ -1,9 +1,28 @@ -/* $XdotOrg: $ */ -/* $Xorg: xwininfo.c,v 1.4 2001/02/09 02:06:04 xorgcvs Exp $ */ +/* + * 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 -Copyright 1999 Sun Microsystems, Inc. Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that @@ -30,7 +49,6 @@ or other dealings in this Software without prior written authorization of the copyright holder. */ -/* $XFree86: xc/programs/xwininfo/xwininfo.c,v 1.9 2003/09/09 22:08:25 herrb Exp $ */ /* @@ -46,59 +64,210 @@ of the copyright holder. */ #include "config.h" -#include <X11/Xlib.h> -#include <X11/Xutil.h> -#include <X11/Xatom.h> -#include <X11/Xos.h> -#include <X11/extensions/shape.h> -#ifndef NO_I18N -#include <X11/Xlocale.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; + long code; + const char *name; } binding; -static void scale_init(void); -static char *nscale(int, int, int, char *, size_t); -static char *xscale(int); -static char *yscale(int); -static char *bscale(int); -static int bad_window_handler(Display *, XErrorEvent *); -int main(int, char **); -static const char *LookupL(long, const binding *); -static const char *Lookup(int, const binding *); -static void Display_Window_Id(Window, int); -static void Display_Stats_Info(Window); -static void Display_Bits_Info(Window); -static void Display_Event_Mask(long); -static void Display_Events_Info(Window); -static void Display_Tree_Info(Window, int); -static void display_tree_info_1(Window, int, int); -static void Display_Hints(XSizeHints *); -static void Display_Size_Hints(Window); -static void Display_Window_Shape(Window); -static void Display_WM_Info(Window); - -static char *window_id_format = "0x%lx"; +#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_wm_hints_t wm_hints_t + +enum { + /* xcb_size_hints_flags_t */ + XCB_SIZE_HINT_US_POSITION = 1 << 0, + XCB_SIZE_HINT_US_SIZE = 1 << 1, + XCB_SIZE_HINT_P_POSITION = 1 << 2, + XCB_SIZE_HINT_P_SIZE = 1 << 3, + XCB_SIZE_HINT_P_MIN_SIZE = 1 << 4, + XCB_SIZE_HINT_P_MAX_SIZE = 1 << 5, + XCB_SIZE_HINT_P_RESIZE_INC = 1 << 6, + XCB_SIZE_HINT_P_ASPECT = 1 << 7, + XCB_SIZE_HINT_BASE_SIZE = 1 << 8, + XCB_SIZE_HINT_P_WIN_GRAVITY = 1 << 9, + /* xcb_wm_state_t */ + XCB_WM_STATE_WITHDRAWN = 0, + XCB_WM_STATE_NORMAL = 1, + XCB_WM_STATE_ICONIC = 3, + /* xcb_wm_t */ + XCB_WM_HINT_INPUT = (1L << 0), + XCB_WM_HINT_STATE = (1L << 1), + XCB_WM_HINT_ICON_PIXMAP = (1L << 2), + XCB_WM_HINT_ICON_WINDOW = (1L << 3), + XCB_WM_HINT_ICON_POSITION = (1L << 4), + XCB_WM_HINT_ICON_MASK = (1L << 5), + XCB_WM_HINT_WINDOW_GROUP = (1L << 6), + XCB_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_get_wm_name(Dpy, Win) GET_TEXT_PROPERTY(Dpy, Win, XCB_ATOM_WM_NAME) + +# define xcb_get_wm_class(Dpy, Win) \ + xcb_get_property (Dpy, False, Win, XCB_ATOM_WM_CLASS, XCB_ATOM_STRING, 0, BUFSIZ) +# define xcb_get_wm_hints(Dpy, Win) \ + xcb_get_property(Dpy, False, Win, XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 0, 9) + +# define xcb_get_wm_size_hints(Dpy, Win, Atom) \ + xcb_get_property (Dpy, False, Win, Atom, XCB_ATOM_WM_SIZE_HINTS, 0, 18) +# define xcb_get_wm_normal_hints(Dpy, Win) \ + xcb_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) +static size_t strlcat (char *dst, const char *src, size_t dstsize) { - size_t sd = strlen(dst); - size_t ss = strlen(src); + size_t sd = strlen (dst); + size_t ss = strlen (src); size_t s = sd + ss; - + if (s < dstsize) { - strcpy(dst + sd, src); + strcpy (dst + sd, src); } else { - strncpy(dst + sd, src, dstsize-sd-1); + strncpy (dst + sd, src, dstsize-sd-1); dst[dstsize] = '\0'; } return s; @@ -109,50 +278,31 @@ static size_t strlcat(char *dst, const char *src, size_t dstsize) * Report the syntax for calling xwininfo: */ void -usage(void) +usage (void) { fprintf (stderr, - "usage: %s [-options ...]\n\n", program_name); - fprintf (stderr, - "where options include:\n"); - fprintf (stderr, - " -help print this message\n"); - fprintf (stderr, - " -display host:dpy X server to contact\n"); - fprintf (stderr, - " -root use the root window\n"); - fprintf (stderr, - " -id windowid use the window with the specified id\n"); - fprintf (stderr, - " -name windowname use the window with the specified name\n"); - fprintf (stderr, - " -int print window id in decimal\n"); - fprintf (stderr, - " -children print parent and child identifiers\n"); - fprintf (stderr, - " -tree print children identifiers recursively\n"); - fprintf (stderr, - " -stats print window geometry [DEFAULT]\n"); - fprintf (stderr, - " -bits print window pixel information\n"); - fprintf (stderr, - " -events print events selected for on window\n"); - fprintf (stderr, - " -size print size hints\n"); - fprintf (stderr, - " -wm print window manager hints\n"); - fprintf (stderr, - " -shape print shape extents\n"); - fprintf (stderr, - " -frame don't ignore window manager frames\n"); - fprintf (stderr, - " -english print sizes in english units\n"); - fprintf (stderr, - " -metric print sizes in metric units\n"); - fprintf (stderr, - " -all -tree, -stats, -bits, -events, -wm, -size, -shape\n"); - fprintf (stderr, - "\n"); + "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); } @@ -167,21 +317,20 @@ usage(void) * */ -#define getdsp(var,fn) var = fn(dpy, DefaultScreen(dpy)) -static int xp=0, xmm=0; -static int yp=0, ymm=0; -static int bp=0, bmm=0; +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(void) +scale_init (xcb_screen_t *screen) { - getdsp(yp, DisplayHeight); - getdsp(ymm, DisplayHeightMM); - getdsp(xp, DisplayWidth); - getdsp(xmm, DisplayWidthMM); - bp = xp + yp; - bmm = xmm + ymm; + 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) @@ -189,17 +338,17 @@ scale_init(void) #define FOOT (12) static char * -nscale(int n, int np, int nmm, char *nbuf, size_t nbufsize) +nscale (int n, int np, int nmm, char *nbuf, size_t nbufsize) { int s; - snprintf(nbuf, nbufsize, "%d", n); - + snprintf (nbuf, nbufsize, "%d", n); + if (metric||english) { - s = strlcat(nbuf, " (", nbufsize); + s = strlcat (nbuf, " (", nbufsize); if (metric) { - snprintf(nbuf+s, nbufsize-s, "%.2f mm%s", - ((double) n)*nmm/np, english ? "; " : ""); + snprintf (nbuf+s, nbufsize-s, "%.2f mm%s", + ((double) n) * nmm/np , english ? "; " : ""); } if (english) { double inch_frac; @@ -212,223 +361,383 @@ nscale(int n, int np, int nmm, char *nbuf, size_t nbufsize) if (inr >= MILE) { mi = inr/MILE; inr %= MILE; - s = strlen(nbuf); - snprintf(nbuf+s, nbufsize-s, "%d %s(?!?)", - mi, (mi==1) ? "mile" : "miles"); + 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"); + 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"); + 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); + s = strlen (nbuf); + snprintf (nbuf+s, nbufsize-s, "%.2f inches", inr+inch_frac); } } strlcat (nbuf, ")", nbufsize); } - return(nbuf); -} - + return (nbuf); +} + static char xbuf[BUFSIZ]; static char * -xscale(int x) +xscale (int x) { - if(!xp) { - scale_init(); - } - return(nscale(x, xp, xmm, xbuf, sizeof(xbuf))); + return (nscale (x, xp, xmm, xbuf, sizeof(xbuf))); } static char ybuf[BUFSIZ]; static char * -yscale(int y) +yscale (int y) { - if(!yp) { - scale_init(); - } - return(nscale(y, yp, ymm, ybuf, sizeof(ybuf))); + return (nscale (y, yp, ymm, ybuf, sizeof(ybuf))); } static char bbuf[BUFSIZ]; static char * -bscale(int b) +bscale (int b) { - if(!bp) { - scale_init(); - } - return(nscale(b, bp, bmm, bbuf, sizeof(bbuf))); + return (nscale (b, bp, bmm, bbuf, sizeof(bbuf))); } /* end of pixel to inch, metric converter */ -/* This handler is enabled when we are checking - to see if the -id the user specified is valid. */ - -/* ARGSUSED */ -static int -bad_window_handler(Display *disp, XErrorEvent *err) +int +main (int argc, char **argv) { - char badid[20]; + 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 (); + } - snprintf(badid, sizeof(badid), window_id_format, err->resourceid); - Fatal_Error("No such window with id %s.", badid); - exit (1); - return 0; -} + 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); + } -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; - Window window; - - INIT_NAME; - -#ifndef NO_I18N - { - char *lc; - lc = setlocale(LC_ALL, ""); - if(!lc) - fprintf(stderr, "can not set locale properly\n"); - } -#endif + /* + * Do the actual displaying as per parameters + */ + if (!(children || tree || bits || events || wm || size)) + stats = 1; - /* Open display, handle command line arguments */ - Setup_Display_And_Screen(&argc, argv); + /* + * make sure that the window is valid + */ + { + xcb_get_geometry_cookie_t gg_cookie = + xcb_get_geometry (dpy, window); - /* Get window selected on command line, if any */ - window = Select_Window_Args(&argc, argv); + w->geometry = xcb_get_geometry_reply(dpy, gg_cookie, &err); - /* Handle our command line arguments */ - for (i = 1; i < argc; i++) { - if (!strcmp(argv[i], "-help")) - usage(); - 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 (!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); + } } - if (!strcmp(argv[i], "-frame")) { - frame = 1; - continue; + + /* 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_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 (!strcmp(argv[i], "-size")) { - size = 1; - continue; + if (stats || bits || events) + w->attr_cookie = xcb_get_window_attributes (dpy, window); + if (stats || size) + w->normal_hints_cookie = xcb_get_wm_normal_hints (dpy, window); + if (wm) { + w->hints_cookie = xcb_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 = + GET_TEXT_PROPERTY(dpy, window, XCB_ATOM_WM_CLIENT_MACHINE); + } + + 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 (!strcmp(argv[i], "-shape")) { - shape = 1; - continue; + if (size) + w->zoom_cookie = xcb_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); } - if (!strcmp(argv[i], "-english")) { - english = 1; - continue; +#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."); + } } - if (!strcmp(argv[i], "-metric")) { - metric = 1; - continue; + 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; } - if (!strcmp(argv[i], "-all")) { - tree = stats = bits = events = wm = size = shape = 1; - continue; + + 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_get_wm_normal_hints_reply wm_size_hints_reply +#define xcb_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_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)); + } } - usage(); - } - - /* If no window selected on command line, let user pick one the hard way */ - if (!window) { - printf("\n"); - printf("xwininfo: Please select the window about which you\n"); - printf(" would like information by clicking the\n"); - printf(" mouse in that window.\n"); - window = Select_Window(dpy, !frame); - } - - /* - * Do the actual displaying as per parameters - */ - if (!(children || tree || bits || events || wm || size)) - stats = 1; - - /* - * make sure that the window is valid - */ - { - Window root; - int x, y; - unsigned width, height, bw, depth; - XErrorHandler old_handler; - - old_handler = XSetErrorHandler(bad_window_handler); - XGetGeometry (dpy, window, &root, &x, &y, &width, &height, &bw, &depth); - XSync (dpy, False); - (void) XSetErrorHandler(old_handler); - } - - printf("\nxwininfo: Window id: "); - Display_Window_Id(window, True); - if (children || tree) - Display_Tree_Info(window, tree); - if (stats) - Display_Stats_Info(window); - if (bits) - Display_Bits_Info(window); - if (events) - Display_Events_Info(window); - if (wm) - Display_WM_Info(window); - if (size) - Display_Size_Hints(window); - if (shape) - Display_Window_Shape(window); - printf("\n"); - exit(0); + if (hints_return && w->normal_hints) + memcpy(hints_return, w->normal_hints, sizeof(xcb_size_hints_t)); + return w->normal_hints; } @@ -438,85 +747,115 @@ main(int argc, char **argv) static char _lookup_buffer[100]; static const char * -LookupL(long code, const binding *table) +LookupL (long code, const binding *table) { - const char *name; + const char *name = NULL; - snprintf(_lookup_buffer, sizeof(_lookup_buffer), - "unknown (code = %ld. = 0x%lx)", code, code); - name = _lookup_buffer; - - while (table->name) { - if (table->code == code) { - name = table->name; - break; - } - table++; + while (table->name) { + if (table->code == code) { + name = table->name; + break; } + table++; + } - return(name); + 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) +Lookup (int code, const binding *table) { - return LookupL((long)code, 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(Window window, Bool newline_wanted) +Display_Window_Id (struct wininfo *w, Bool newline_wanted) { -#ifdef NO_I18N - char *win_name; -#else - XTextProperty tp; +#ifdef USE_XCB_ICCCM + xcb_get_text_property_reply_t wmn_reply; #endif - - printf(window_id_format, window); /* print id # in hex/dec */ + xcb_get_property_reply_t *prop; + uint8_t got_reply = False; + const char *wm_name = NULL; + unsigned int wm_name_len = 0; + xcb_atom_t wm_name_encoding = XCB_NONE; - if (!window) { - printf(" (none)"); + printf (window_id_format, w->window); /* print id # in hex/dec */ + + if (!w->window) { + printf (" (none)"); } else { - if (window == RootWindow(dpy, screen)) { - printf(" (the root window)"); + if (w->window == screen->root) { + printf (" (the root window)"); } -#ifdef NO_I18N - if (!XFetchName(dpy, window, &win_name)) { /* Get window name if any */ - printf(" (has no name)"); - } else if (win_name) { - printf(" \"%s\"", win_name); - XFree(win_name); + /* 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; + got_reply = True; } + + if (!got_reply) { /* No _NET_WM_NAME, check WM_NAME */ +#ifdef USE_XCB_ICCCM + got_reply = xcb_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 - if (!XGetWMName(dpy, window, &tp)) { /* Get window name if any */ - printf(" (has no name)"); - } else if (tp.nitems > 0) { - printf(" \""); - { - int count = 0, i, ret; - char **list = NULL; - ret = XmbTextPropertyToTextList(dpy, &tp, &list, &count); - if((ret == Success || ret > 0) && list != NULL){ - for(i=0; i<count; i++) - printf("%s", list[i]); - XFreeStringList(list); - } else { - printf("%s", tp.value); - } - } - printf("\""); + 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; + got_reply = True; + } +#endif } + if (!got_reply || 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_get_text_property_reply_wipe (&wmn_reply); +#else + free (prop); #endif - else - printf(" (has no name)"); } if (newline_wanted) - printf("\n"); + printf ("\n"); return; } @@ -526,221 +865,255 @@ Display_Window_Id(Window window, Bool newline_wanted) * Display Stats on window */ static const binding _window_classes[] = { - { InputOutput, "InputOutput" }, - { InputOnly, "InputOnly" }, + { XCB_WINDOW_CLASS_INPUT_OUTPUT, "InputOutput" }, + { XCB_WINDOW_CLASS_INPUT_ONLY, "InputOnly" }, { 0, NULL } }; static const binding _map_states[] = { - { IsUnmapped, "IsUnMapped" }, - { IsUnviewable, "IsUnviewable" }, - { IsViewable, "IsViewable" }, + { XCB_MAP_STATE_UNMAPPED, "IsUnMapped" }, + { XCB_MAP_STATE_UNVIEWABLE, "IsUnviewable" }, + { XCB_MAP_STATE_VIEWABLE, "IsViewable" }, { 0, NULL } }; static const binding _backing_store_states[] = { - { NotUseful, "NotUseful" }, - { WhenMapped, "WhenMapped" }, - { Always, "Always" }, + { 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[] = { - { ForgetGravity, "ForgetGravity" }, - { NorthWestGravity, "NorthWestGravity" }, - { NorthGravity, "NorthGravity" }, - { NorthEastGravity, "NorthEastGravity" }, - { WestGravity, "WestGravity" }, - { CenterGravity, "CenterGravity" }, - { EastGravity, "EastGravity" }, - { SouthWestGravity, "SouthWestGravity" }, - { SouthGravity, "SouthGravity" }, - { SouthEastGravity, "SouthEastGravity" }, - { StaticGravity, "StaticGravity" }, + { 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[] = { - { UnmapGravity, "UnmapGravity" }, - { NorthWestGravity, "NorthWestGravity" }, - { NorthGravity, "NorthGravity" }, - { NorthEastGravity, "NorthEastGravity" }, - { WestGravity, "WestGravity" }, - { CenterGravity, "CenterGravity" }, - { EastGravity, "EastGravity" }, - { SouthWestGravity, "SouthWestGravity" }, - { SouthGravity, "SouthGravity" }, - { SouthEastGravity, "SouthEastGravity" }, - { StaticGravity, "StaticGravity" }, + { 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[] = { - { StaticGray, "StaticGray" }, - { GrayScale, "GrayScale" }, - { StaticColor, "StaticColor" }, - { PseudoColor, "PseudoColor" }, - { TrueColor, "TrueColor" }, - { DirectColor, "DirectColor" }, + { 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(Window window) +Display_Stats_Info (struct wininfo *w) { - XWindowAttributes win_attributes; - XVisualInfo vistemplate, *vinfo; - XSizeHints hints; - int dw = DisplayWidth (dpy, screen), dh = DisplayHeight (dpy, screen); - int rx, ry, xright, ybelow; - int showright = 0, showbelow = 0; - Status status; - Window wmframe; - int junk; - long longjunk; - Window junkwin; - - if (!XGetWindowAttributes(dpy, window, &win_attributes)) - Fatal_Error("Can't get window attributes."); - vistemplate.visualid = XVisualIDFromVisual(win_attributes.visual); - vinfo = XGetVisualInfo(dpy, VisualIDMask, &vistemplate, &junk); - - (void) XTranslateCoordinates (dpy, window, win_attributes.root, - -win_attributes.border_width, - -win_attributes.border_width, - &rx, &ry, &junkwin); - - xright = (dw - rx - win_attributes.border_width * 2 - - win_attributes.width); - ybelow = (dh - ry - win_attributes.border_width * 2 - - win_attributes.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(win_attributes.x)); - printf(" Relative upper-left Y: %s\n", yscale(win_attributes.y)); - printf(" Width: %s\n", xscale(win_attributes.width)); - printf(" Height: %s\n", yscale(win_attributes.height)); - printf(" Depth: %d\n", win_attributes.depth); - printf(" Visual: 0x%lx\n", vinfo->visualid); - printf(" Visual Class: %s\n", Lookup(vinfo->class, _visual_classes)); - printf(" Border width: %s\n", bscale(win_attributes.border_width)); - printf(" Class: %s\n", - Lookup(win_attributes.class, _window_classes)); - printf(" Colormap: 0x%lx (%sinstalled)\n", - win_attributes.colormap, win_attributes.map_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); - - XFree(vinfo); - - /* - * compute geometry string that would recreate window - */ - printf(" -geometry "); - - /* compute size in appropriate units */ - status = XGetWMNormalHints(dpy, window, &hints, &longjunk); - if (status && hints.flags & PResizeInc && - hints.width_inc != 0 && hints.height_inc != 0) { - if (hints.flags & (PBaseSize|PMinSize)) { - if (hints.flags & PBaseSize) { - win_attributes.width -= hints.base_width; - win_attributes.height -= hints.base_height; - } else { - /* ICCCM says MinSize is default for BaseSize */ - win_attributes.width -= hints.min_width; - win_attributes.height -= hints.min_height; - } - } - printf("%dx%d", win_attributes.width/hints.width_inc, - win_attributes.height/hints.height_inc); - } else - printf("%dx%d", win_attributes.width, win_attributes.height); - - if (!(hints.flags&PWinGravity)) - hints.win_gravity = NorthWestGravity; /* per ICCCM */ - /* find our window manager frame, if any */ - wmframe = window; - while (True) { - Window root, parent; - Window *childlist; - unsigned int ujunk; - - status = XQueryTree(dpy, wmframe, &root, &parent, &childlist, &ujunk); - if (parent == root || !parent || !status) - break; - wmframe = parent; - if (status && childlist) - XFree((char *)childlist); - } - if (wmframe != 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. */ - - XWindowAttributes frame_attr; - - if (!XGetWindowAttributes(dpy, wmframe, &frame_attr)) - Fatal_Error("Can't get frame attributes."); - switch (hints.win_gravity) { - case NorthWestGravity: case SouthWestGravity: - case NorthEastGravity: case SouthEastGravity: - case WestGravity: - rx = frame_attr.x; - } - switch (hints.win_gravity) { - case NorthWestGravity: case SouthWestGravity: - case NorthEastGravity: case SouthEastGravity: - case EastGravity: - xright = dw - frame_attr.x - frame_attr.width - - 2*frame_attr.border_width; - } - switch (hints.win_gravity) { - case NorthWestGravity: case SouthWestGravity: - case NorthEastGravity: case SouthEastGravity: - case NorthGravity: - ry = frame_attr.y; - } - switch (hints.win_gravity) { - case NorthWestGravity: case SouthWestGravity: - case NorthEastGravity: case SouthEastGravity: - case SouthGravity: - ybelow = dh - frame_attr.y - frame_attr.height - - 2*frame_attr.border_width; - } - } - /* 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 == EastGravity || - (abs(xright) <= 100 && abs(xright) < abs(rx) - && hints.win_gravity != WestGravity)) - showright = 1; - if (hints.win_gravity == SouthGravity || - (abs(ybelow) <= 100 && abs(ybelow) < abs(ry) - && hints.win_gravity != NorthGravity)) - showbelow = 1; - - if (showright) - printf("-%d", xright); - else - printf("+%d", rx); - if (showbelow) - printf("-%d", ybelow); - else - printf("+%d", ry); - printf("\n"); + 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 = trans_coords->dst_x; + ry = 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_SIZE_HINT_P_RESIZE_INC) && + (hints.width_inc != 0) && (hints.height_inc != 0)) { + if (hints.flags & (XCB_SIZE_HINT_BASE_SIZE|XCB_SIZE_HINT_P_MIN_SIZE)) { + if (hints.flags & XCB_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_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"); } @@ -748,24 +1121,25 @@ Display_Stats_Info(Window window) * Display bits info: */ static const binding _gravities[] = { - { UnmapGravity, "UnMapGravity" }, /* WARNING: both of these have*/ - { ForgetGravity, "ForgetGravity" }, /* the same value - see code */ - { NorthWestGravity, "NorthWestGravity" }, - { NorthGravity, "NorthGravity" }, - { NorthEastGravity, "NorthEastGravity" }, - { WestGravity, "WestGravity" }, - { CenterGravity, "CenterGravity" }, - { EastGravity, "EastGravity" }, - { SouthWestGravity, "SouthWestGravity" }, - { SouthGravity, "SouthGravity" }, - { SouthEastGravity, "SouthEastGravity" }, - { StaticGravity, "StaticGravity" }, + /* 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[] = { - { NotUseful, "NotUseful" }, - { WhenMapped, "WhenMapped" }, - { Always, "Always" }, + { XCB_BACKING_STORE_NOT_USEFUL, "NotUseful" }, + { XCB_BACKING_STORE_WHEN_MAPPED,"WhenMapped" }, + { XCB_BACKING_STORE_ALWAYS, "Always" }, { 0, NULL } }; static const binding _bool[] = { @@ -773,26 +1147,29 @@ static const binding _bool[] = { { 1, "Yes" }, { 0, NULL } }; +/* + * Requires wininfo members initialized: + * window, attr_cookie (or win_attributes) + */ static void -Display_Bits_Info(Window window) +Display_Bits_Info (struct wininfo * w) { - XWindowAttributes win_attributes; - - if (!XGetWindowAttributes(dpy, window, &win_attributes)) - Fatal_Error("Can't get window attributes."); - - 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", - win_attributes.backing_planes); - printf(" Backing pixel: %ld\n", win_attributes.backing_pixel); - printf(" Save-unders: %s\n", - Lookup(win_attributes.save_under, _bool)); + 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)); } @@ -800,65 +1177,66 @@ Display_Bits_Info(Window window) * Routine to display all events in an event mask */ static const binding _event_mask_names[] = { - { KeyPressMask, "KeyPress" }, - { KeyReleaseMask, "KeyRelease" }, - { ButtonPressMask, "ButtonPress" }, - { ButtonReleaseMask, "ButtonRelease" }, - { EnterWindowMask, "EnterWindow" }, - { LeaveWindowMask, "LeaveWindow" }, - { PointerMotionMask, "PointerMotion" }, - { PointerMotionHintMask, "PointerMotionHint" }, - { Button1MotionMask, "Button1Motion" }, - { Button2MotionMask, "Button2Motion" }, - { Button3MotionMask, "Button3Motion" }, - { Button4MotionMask, "Button4Motion" }, - { Button5MotionMask, "Button5Motion" }, - { ButtonMotionMask, "ButtonMotion" }, - { KeymapStateMask, "KeymapState" }, - { ExposureMask, "Exposure" }, - { VisibilityChangeMask, "VisibilityChange" }, - { StructureNotifyMask, "StructureNotify" }, - { ResizeRedirectMask, "ResizeRedirect" }, - { SubstructureNotifyMask, "SubstructureNotify" }, - { SubstructureRedirectMask, "SubstructureRedirect" }, - { FocusChangeMask, "FocusChange" }, - { PropertyChangeMask, "PropertyChange" }, - { ColormapChangeMask, "ColormapChange" }, - { OwnerGrabButtonMask, "OwnerGrabButton" }, + { 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) +Display_Event_Mask (long mask) { - long bit, bit_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)); + 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(Window window) +Display_Events_Info (struct wininfo *w) { - XWindowAttributes win_attributes; - - if (!XGetWindowAttributes(dpy, window, &win_attributes)) - Fatal_Error("Can't get window attributes."); + 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 ("\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 (" 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)); + printf (" Override redirection?: %s\n", + Lookup (win_attributes->override_redirect, _bool)); } @@ -870,82 +1248,184 @@ Display_Events_Info(Window window) /* * 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(Window window, int recurse) +Display_Tree_Info (struct wininfo *w, int recurse) { - display_tree_info_1(window, recurse, 0); + display_tree_info_1 (w, recurse, 0); } /* * level - recursion level */ static void -display_tree_info_1(Window window, int recurse, int level) +display_tree_info_1 (struct wininfo *w, int recurse, int level) { - int i, j; - int rel_x, rel_y, abs_x, abs_y; - unsigned int width, height, border, depth; - Window root_win, parent_win; - unsigned int num_children; - Window *child_list; - XClassHint classhint; - - if (!XQueryTree(dpy, window, &root_win, &parent_win, &child_list, - &num_children)) - Fatal_Error("Can't query window tree."); - - if (level == 0) { - printf("\n"); - printf(" Root window id: "); - Display_Window_Id(root_win, True); - printf(" Parent window id: "); - Display_Window_Id(parent_win, True); - } - - 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 ? ":" : "."); - } - - for (i = (int)num_children - 1; i >= 0; i--) { - printf(" "); - for (j=0; j<level; j++) printf(" "); - Display_Window_Id(child_list[i], False); - printf(": ("); - if(XGetClassHint(dpy, child_list[i], &classhint)) { - if(classhint.res_name) { - printf("\"%s\" ", classhint.res_name); - XFree(classhint.res_name); - } else - printf("(none) "); - if(classhint.res_class) { - printf("\"%s\") ", classhint.res_class); - XFree(classhint.res_class); - } else - printf("(none)) "); - } else - printf(") "); + 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 (XGetGeometry(dpy, child_list[i], &root_win, - &rel_x, &rel_y, &width, &height, &border, &depth)) { - Window child; + 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_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_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); - printf (" %ux%u+%d+%d", width, height, rel_x, rel_y); - if (XTranslateCoordinates (dpy, child_list[i], root_win, - 0 ,0, &abs_x, &abs_y, &child)) { - printf (" +%d+%d", abs_x - border, abs_y - border); + 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_get_wm_name (dpy, child_list[i]); + cw->wm_class_cookie = xcb_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_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_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_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); } - printf("\n"); - - if (recurse) - display_tree_info_1(child_list[i], 1, level+1); - } - if (child_list) XFree((char *)child_list); + free (tree); /* includes storage for child_list[] */ } @@ -953,77 +1433,77 @@ display_tree_info_1(Window window, int recurse, int level) * Display a set of size hints */ static void -Display_Hints(XSizeHints *hints) +Display_Hints (xcb_size_hints_t *hints) { - long flags; + long flags; - flags = hints->flags; - - if (flags & USPosition) - printf(" User supplied location: %s, %s\n", - xscale(hints->x), yscale(hints->y)); + flags = hints->flags; - if (flags & PPosition) - printf(" Program supplied location: %s, %s\n", - xscale(hints->x), yscale(hints->y)); + if (flags & XCB_SIZE_HINT_US_POSITION) + printf (" User supplied location: %s, %s\n", + xscale (hints->x), yscale (hints->y)); - if (flags & USSize) { - printf(" User supplied size: %s by %s\n", - xscale(hints->width), yscale(hints->height)); - } + if (flags & XCB_SIZE_HINT_P_POSITION) + printf (" Program supplied location: %s, %s\n", + xscale (hints->x), yscale (hints->y)); - if (flags & PSize) - printf(" Program supplied size: %s by %s\n", - xscale(hints->width), yscale(hints->height)); + if (flags & XCB_SIZE_HINT_US_SIZE) { + printf (" User supplied size: %s by %s\n", + xscale (hints->width), yscale (hints->height)); + } - if (flags & PMinSize) - printf(" Program supplied minimum size: %s by %s\n", - xscale(hints->min_width), yscale(hints->min_height)); + if (flags & XCB_SIZE_HINT_P_SIZE) + printf (" Program supplied size: %s by %s\n", + xscale (hints->width), yscale (hints->height)); - if (flags & PMaxSize) - printf(" Program supplied maximum size: %s by %s\n", - xscale(hints->max_width), yscale(hints->max_height)); + if (flags & XCB_SIZE_HINT_P_MIN_SIZE) + printf (" Program supplied minimum size: %s by %s\n", + xscale (hints->min_width), yscale (hints->min_height)); - if (flags & PBaseSize) { - printf(" Program supplied base size: %s by %s\n", - xscale(hints->base_width), yscale(hints->base_height)); - } + if (flags & XCB_SIZE_HINT_P_MAX_SIZE) + printf (" Program supplied maximum size: %s by %s\n", + xscale (hints->max_width), yscale (hints->max_height)); - if (flags & PResizeInc) { - 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 & USSize) - 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 & PSize) - 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 & PMinSize) - 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 & PBaseSize) - 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 & PAspect) { - printf(" Program supplied min aspect ratio: %s/%s\n", - xscale(hints->min_aspect.x), yscale(hints->min_aspect.y)); - printf(" Program supplied max aspect ratio: %s/%s\n", - xscale(hints->max_aspect.x), yscale(hints->max_aspect.y)); - } - - if (flags & PWinGravity) { - printf(" Program supplied window gravity: %s\n", - Lookup(hints->win_gravity, _gravities)); + if (flags & XCB_SIZE_HINT_BASE_SIZE) { + printf (" Program supplied base size: %s by %s\n", + xscale (hints->base_width), yscale (hints->base_height)); + } + + if (flags & XCB_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_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_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_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_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_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_SIZE_HINT_P_WIN_GRAVITY) { + printf (" Program supplied window gravity: %s\n", + Lookup (hints->win_gravity, _gravities)); + } } @@ -1031,103 +1511,463 @@ Display_Hints(XSizeHints *hints) * Display Size Hints info */ static void -Display_Size_Hints(Window window) +Display_Size_Hints (struct wininfo *w) { - XSizeHints *hints = XAllocSizeHints(); - long supplied; - - printf("\n"); - if (!XGetWMNormalHints(dpy, window, hints, &supplied)) - printf(" No normal window size hints defined\n"); - else { - printf(" Normal window size hints:\n"); - hints->flags &= supplied; - Display_Hints(hints); - } + xcb_size_hints_t hints; - if (!XGetWMSizeHints(dpy, window, hints, &supplied, XA_WM_ZOOM_HINTS)) - printf(" No zoom window size hints defined\n"); - else { - printf(" Zoom window size hints:\n"); - hints->flags &= supplied; - Display_Hints(hints); - } - XFree((char *)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_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 (Window window) +Display_Window_Shape (xcb_window_t window) { - Bool ws, bs; - int xws, yws, xbs, ybs; - unsigned int wws, hws, wbs, hbs; + const xcb_query_extension_reply_t *shape_query; + xcb_shape_query_extents_cookie_t extents_cookie; + xcb_shape_query_extents_reply_t *extents; - if (!XShapeQueryExtension (dpy, &bs, &ws)) + shape_query = xcb_get_extension_data (dpy, &xcb_shape_id); + if (!shape_query->present) return; - printf("\n"); - XShapeQueryExtents (dpy, window, &ws, &xws, &yws, &wws, &hws, - &bs, &xbs, &ybs, &wbs, &hbs); - if (!ws) - printf(" No window shape defined\n"); + 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(wws), yscale(hws)); - printf("+%s+%s\n", xscale(xws), yscale(yws)); + 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 (!bs) - printf(" No border shape defined\n"); + if (!extents->clip_shaped) + printf (" No border shape defined\n"); else { - printf(" Border shape extents: %sx%s", - xscale(wbs), yscale(hbs)); - printf("+%s+%s\n", xscale(xbs), yscale(ybs)); + 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[] = { - { DontCareState, "Don't Care State" }, - { NormalState, "Normal State" }, - { ZoomState, "Zoomed State" }, - { IconicState, "Iconic State" }, - { InactiveState, "Inactive State" }, + { XCB_WM_STATE_WITHDRAWN, "Withdrawn State" }, + { XCB_WM_STATE_NORMAL, "Normal State" }, + { XCB_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_get_wm_hints_reply wm_hints_reply +#endif + static void -Display_WM_Info(Window window) +Display_WM_Info (struct wininfo *w) { - XWMHints *wmhints; - long flags; - - wmhints = XGetWMHints(dpy, window); - printf("\n"); - if (!wmhints) { - printf(" No window manager hints defined\n"); - return; + xcb_wm_hints_t wmhints; + long flags; + xcb_get_property_reply_t *prop; + int i; + + printf ("\n"); + if (!xcb_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_WM_HINT_INPUT) + printf (" Client accepts input or input focus: %s\n", + Lookup (wmhints.input, _bool)); + + if (flags & XCB_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_get_wm_name (dpy, iw.window); + + printf (" Icon window id: "); + Display_Window_Id (&iw, True); + } + + if (flags & XCB_WM_HINT_ICON_POSITION) + printf (" Initial icon position: %s, %s\n", + xscale (wmhints.icon_x), yscale (wmhints.icon_y)); + + if (flags & XCB_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); + } } - flags = wmhints->flags; + free (prop); + } - printf(" Window manager hints:\n"); + 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 (flags & InputHint) - printf(" Client accepts input or input focus: %s\n", - Lookup(wmhints->input, _bool)); + 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); - if (flags & IconWindowHint) { - printf(" Icon window id: "); - Display_Window_Id(wmhints->icon_window, True); + 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; + } - if (flags & IconPositionHint) - printf(" Initial icon position: %s, %s\n", - xscale(wmhints->icon_x), yscale(wmhints->icon_y)); + 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 (flags & StateHint) - printf(" Initial state is %s\n", - Lookup(wmhints->initial_state, _state_hints)); + 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; + } - XFree(wmhints); + printf (format, name_start); + free (lowered_name); } |