lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Tue, 31 Aug 2010 22:58:17 -0400
From:	Mathieu Desnoyers <mathieu.desnoyers@...icios.com>
To:	Pauli Nieminen <ext-pauli.nieminen@...ia.com>
Cc:	Peter Zijlstra <peterz@...radead.org>,
	Tony Lindgren <tony@...mide.com>,
	Jarkko Nikula <jhnikula@...il.com>,
	linux-kernel@...r.kernel.org, Pauli <suokkos@...il.com>
Subject: Re: IPC between application and xserver is causing extra context
	switches

* Pauli Nieminen (ext-pauli.nieminen@...ia.com) wrote:
> Hi,
> 
> While running rendering benchmark we noticed huge context switch numbers that
> were a lot larger than excepted. Numbers were showing 20-30 context switches
> per frame. Theoretical minimum context switches is less than 10.
> 
> Problem was traced using FineToothComp (FTC) [1]. Tracing down to per
> instruction view what happens in system.
> 
> Conext switches are relatively easy to track down from the trace
> visualization so it was easy to find out what was causing the extra context
> switches.
> 
>  * What application is doing when calling xserver?
> 
> Application opens unix socket connection to xserver. Communication is based
> on simple message protocol. Application does following call sequence when
> communicating to xserver.
> 
> writev(...) // Send message(s) to xserver
> 
> poll(...) // wait for response(s) from xserver
> 
> read(...) // read the response(s)
> 
>  * Where does extra context switches happen?
> 
> Application developer would except that only poll call would trigger context
> switch. But in worst case every system call is triggering context switch.
> 
> - writev()
> 
> writev does implicit context switch in kernel after writing to socket. This
> isn't perfect behavior for asynchronous IPC because application might want to
> queue up more messages before context switch.
> 
> This doesn't affect X communication because there is buffering implementation
> in xcb for asynchronous operations. But it might be good to fix for some
> other implementations that don't have buffering.
> 
> - poll()
> 
> But scheduling in writev backfires when poll is called. There is some X calls
> (DRI2GetBuffers etc) that takes very long to handle. While xserver is handlnig
> the request kernel decides to schedule client before there is response.
> 
> Now client executes very few instructions before hitting the poll. Now poll
> blocks because there is no response from xserver.

Well, actually, I just traced it with LTTng, and the situation is a little
weird. Xorg does a read() system call on the unix socket, which triggers a
wakeup that targets xwininfo which is waiting on a poll(). The poll wakes up for
a very short amount of time, returns back to the kernel, and schedules xorg
again to complete the read() (it actually returns 8 bytes, even weirder). Then
later xwininfo will be woken up by the writev system call (which is a little
more expected).

I'm attaching a snapshot showing the event list pinpointing the exact execution
sequence. Any thoughts ?

> 
> - read()
> 
> Application hits read soon after returning from poll. xserver has gone to
> sleep in select call waiting for multiple file descriptor.
> 
> When read call is returning from kernel unlocking the socket triggers xserver
> scheduling. This schedulnig never returns from kernel space but it iterates
> over all file descriptors that xserver is waiting for.
> 
>  * Test case
> 
> There is relatively simple test case attached that can check if kernel is
> scheduling too many times. Test case is xwininfo tool modified not to output
> anything. Running it with -root and -tree parameters is generating lots of
> request for xserver.
> 
> Compilation instructions are in  xwininfo.c. 
> 
> test.sh can be used to automatically test if there was too many extra
> scheduling. In perfect case scheduling should be only twice the number of
> request.
> 
>  * Where the bug has been seen?
> 
> I first saw this while doing development on arm. I have also tested a few x86
> kernels to see if problem can be reproduced there too. Problem was
> reproducing in most of configurations that I tested.
> 
> broken:
> 2.6.32 (ARM)
> 2.6.28 (x86 Debian Lenny)
> 2.6.35-rc4 (x86 vanila, Ubuntu Karmic user space)
> 
> But for my surprise I could find single working configuration that was my
> work desktop using Ubuntu kernel.
> 
> correctly working:
> 2.6.31 (x86 Ubuntu Karmic)

I'd be careful about bissection between a Ubuntu kernel and mainline. Ubuntu can
add many tweaks to their kernels. An example of a tweak that makes the test
"pass" is:

echo NO_WAKEUP_PREEMPT > /debugfs/sched_features
(with CONFIG_DEBUG_SCHED=y)

Thanks,

Mathieu

> 
>  * Bisecting failed
> 
> I tried to bisect if I could find the kernel commit that has fixed the
> problem for Ubuntu karmic but I hit problem that my self compiled kernels
> didn't boot. I don't have enough time now to try to do the bisecting.
> 
> If bisecting would help I can try to find some time.
> 
> 
> There is still open question if the bug is caused by userspace doing stupid
> stuff with unix socket or actual kernel problem. But my debugging is pointing
> to kernel problem because same userspace hits the bug with different kernel.
> 
> Pauli
> 
> [1] QT blog post explaining what can be done with FTC
> http://labs.trolltech.com/blogs/2009/09/29/exploring-qt-performance-on-arm-using-finetoothcomb/

> /**
>  * Compile: gcc -DHAVE_CONFIG_H -I. -g -O2 -o xwininfo xwininfo.c -lXext -lX11
>  * test case:
>  * 1. Count number of writes to xserver.
>  *  strace ./xwininfo -root -tree 2>&1 | grep writev | wc
>  * 2. Compare that value to number of context switches happening while running
>  *    xwininfo.
>  *  vmstat -n 1 & sleep 3; ./xwininfo -root -tree; sleep 3; killall vmstat
>  * 3. Compare how context switch numbers increase with number of runs
>  *  vmstat -n 1 & sleep 3; echo START; for i in 1 2; do ./xwininfo -root -tree; done; echo END; sleep 3; killall vmstat
>  *  vmstat -n 1 & sleep 3; echo START; for i in 1 2 3; do ./xwininfo -root -tree; done; echo END; sleep 3; killall vmstat
>  *  vmstat -n 1 & sleep 3; echo START; for i in 1 2 3 4 5; do ./xwininfo -root -tree; done; echo END; sleep 3; killall vmstat
>  **/
> 
> /* config.h.  Generated from config.h.in by configure.  */
> /* config.h.in.  Generated from configure.ac by autoheader.  */
> 
> /* Define to 1 if you have the `strlcat' function. */
> /* #undef HAVE_STRLCAT */
> 
> /* Name of package */
> #define PACKAGE "xwininfo"
> 
> /* Define to the address where bug reports for this package should be sent. */
> #define PACKAGE_BUGREPORT "https://bugs.freedesktop.org/enter_bug.cgi?product=xorg"
> 
> /* Define to the full name of this package. */
> #define PACKAGE_NAME "xwininfo"
> 
> /* Define to the full name and version of this package. */
> #define PACKAGE_STRING "xwininfo 1.0.4"
> 
> /* Define to the one symbol short name of this package. */
> #define PACKAGE_TARNAME "xwininfo"
> 
> /* Define to the version of this package. */
> #define PACKAGE_VERSION "1.0.4"
> 
> /* Major version of this package */
> #define PACKAGE_VERSION_MAJOR 1
> 
> /* Minor version of this package */
> #define PACKAGE_VERSION_MINOR 0
> 
> /* Patch version of this package */
> #define PACKAGE_VERSION_PATCHLEVEL 4
> 
> /* Version number of package */
> #define VERSION "1.0.4"
> 
> 
> /*
>  * Copyright 2007 Kim woelders
>  *
>  * 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, and
>  * that the name of the copyright holders not be used in advertising or
>  * publicity pertaining to distribution of the software without specific,
>  * written prior permission.  The copyright holders make no representations
>  * about the suitability of this software for any purpose.  It is provided "as
>  * is" without express or implied warranty.
>  *
>  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
>  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
>  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR 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.
>  */
> #ifndef _CLIENTWIN_H_
> #define _CLIENTWIN_H_
> 
> #include <X11/Xlib.h>
> 
> extern Window Find_Client(Display * dpy, Window root, Window target_win);
> 
> #endif
> 
> 
> /* $Xorg: dsimple.h,v 1.4 2001/02/09 02:05:54 xorgcvs Exp $ */
> /*
> 
> Copyright 1993, 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.
> IN NO EVENT SHALL THE OPEN GROUP 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.
> 
> Except as contained in this notice, the name of The Open Group shall
> not be used in advertising or otherwise to promote the sale, use or
> other dealings in this Software without prior written authorization
> from The Open Group.
> 
> */
> /* $XFree86: xc/programs/xlsfonts/dsimple.h,v 1.8 2002/12/24 17:43:01 tsi Exp $ */
> 
> /*
>  * Just_display.h: This file contains the definitions needed to use the
>  *                 functions in just_display.c.  It also declares the global
>  *                 variables dpy, screen, and program_name which are needed to
>  *                 use just_display.c.
>  *
>  * Written by Mark Lillibridge.   Last updated 7/1/87
>  *
>  * Send bugs, etc. to chariot@...ena.mit.edu.
>  */
> 
>     /* Simple helper macros */
> #ifndef MAX
> #define MAX(a,b) (((a)>(b))?(a):(b))
> #endif /* MAX */
> #ifndef MIN
> #define MIN(a,b) (((a)<(b))?(a):(b))
> #endif /* MIN */
> 
>     /* Global variables used by routines in dsimple.c */
> 
> extern char *program_name;                   /* Name of this program */
> extern Display *dpy;                         /* The current display */
> extern int screen;                           /* The current screen */
> 
> #define INIT_NAME program_name=argv[0]        /* use this in main to setup
>                                                  program_name */
> 
>     /* Declaritions for functions in dsimple.c */
> 
> char *Get_Display_Name(int *, char **);
> Display *Open_Display(char *);
> void Setup_Display_And_Screen(int *, char **);
> void Close_Display(void);
> Window Select_Window_Args(int *, char **);
> void usage(void);
> 
> #define X_USAGE "[host:display]"              /* X arguments handled by
> 						 Get_Display_Name */
> 
> /*
>  * Other_stuff.h: Definitions of routines in other_stuff.
>  *
>  * Written by Mark Lillibridge.   Last updated 7/1/87
>  *
>  * Send bugs, etc. to chariot@...ena.mit.edu.
>  */
> 
> Window Select_Window(Display *, int);
> Window Window_With_Name(Display *, Window, char *);
> #ifdef __GNUC__
> void Fatal_Error(char *, ...) __attribute__((__noreturn__));
> #else
> void Fatal_Error(char *, ...);
> #endif
> 
> /*
>  * Copyright 2007 Kim woelders
>  *
>  * 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, and
>  * that the name of the copyright holders not be used in advertising or
>  * publicity pertaining to distribution of the software without specific,
>  * written prior permission.  The copyright holders make no representations
>  * about the suitability of this software for any purpose.  It is provided "as
>  * is" without express or implied warranty.
>  *
>  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
>  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
>  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR 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.
>  */
> #include <X11/Xatom.h>
> #include <X11/Xlib.h>
> 
> static Atom atom_wm_state = None;
> 
> /*
>  * Check if window has given property
>  */
> static Bool
> Window_Has_Property(Display * dpy, Window win, Atom atom)
> {
>     Atom type_ret;
>     int format_ret;
>     unsigned char *prop_ret;
>     unsigned long bytes_after, num_ret;
> 
>     type_ret = None;
>     prop_ret = NULL;
>     XGetWindowProperty(dpy, win, atom, 0, 0, False, AnyPropertyType,
>                        &type_ret, &format_ret, &num_ret,
>                        &bytes_after, &prop_ret);
>     if (prop_ret)
>         XFree(prop_ret);
> 
>     return (type_ret != None) ? True : False;
> }
> 
> /*
>  * Check if window is viewable
>  */
> static Bool
> Window_Is_Viewable(Display * dpy, Window win)
> {
>     Bool ok;
>     XWindowAttributes xwa;
> 
>     XGetWindowAttributes(dpy, win, &xwa);
> 
>     ok = (xwa.class == InputOutput) && (xwa.map_state == IsViewable);
> 
>     return ok;
> }
> 
> /*
>  * Find a window that has WM_STATE set in the window tree below win.
>  * Unmapped/unviewable windows are not considered valid matches.
>  * Children are searched in top-down stacking order.
>  * The first matching window is returned, None if no match is found.
>  */
> Window
> Find_Client_In_Children(Display * dpy, Window win)
> {
>     Window root, parent;
>     Window *children;
>     unsigned int n_children;
>     int i;
> 
>     if (!XQueryTree(dpy, win, &root, &parent, &children, &n_children))
>         return None;
>     if (!children)
>         return None;
> 
>     /* Check each child for WM_STATE and other validity */
>     win = None;
>     for (i = (int) n_children - 1; i >= 0; i--) {
>         if (!Window_Is_Viewable(dpy, children[i])) {
>             children[i] = None; /* Don't bother descending into this one */
>             continue;
>         }
>         if (!Window_Has_Property(dpy, children[i], atom_wm_state))
>             continue;
> 
>         /* Got one */
>         win = children[i];
>         goto done;
>     }
> 
>     /* No children matched, now descend into each child */
>     for (i = (int) n_children - 1; i >= 0; i--) {
>         if (children[i] == None)
>             continue;
>         win = Find_Client_In_Children(dpy, children[i]);
>         if (win != None)
>             break;
>     }
> 
>   done:
>     XFree(children);
> 
>     return win;
> }
> 
> /*
>  * Find virtual roots (_NET_VIRTUAL_ROOTS)
>  */
> unsigned long *
> Find_Roots(Display * dpy, Window root, unsigned int *num)
> {
>     Atom type_ret;
>     int format_ret;
>     unsigned char *prop_ret;
>     unsigned long bytes_after, num_ret;
>     Atom atom;
> 
>     *num = 0;
>     atom = XInternAtom(dpy, "_NET_VIRTUAL_ROOTS", False);
>     if (!atom)
>         return NULL;
> 
>     type_ret = None;
>     prop_ret = NULL;
>     if (XGetWindowProperty(dpy, root, atom, 0, 0x7fffffff, False,
>                            XA_WINDOW, &type_ret, &format_ret, &num_ret,
>                            &bytes_after, &prop_ret) != Success)
>         return NULL;
> 
>     if (prop_ret && type_ret == XA_WINDOW && format_ret == 32) {
>         *num = num_ret;
>         return ((unsigned long *) prop_ret);
>     }
>     if (prop_ret)
>         XFree(prop_ret);
> 
>     return NULL;
> }
> 
> /*
>  * Find child window at pointer location
>  */
> static Window
> Find_Child_At_Pointer(Display * dpy, Window win)
> {
>     Window root_return, child_return;
>     int dummyi;
>     unsigned int dummyu;
> 
>     XQueryPointer(dpy, win, &root_return, &child_return,
>                   &dummyi, &dummyi, &dummyi, &dummyi, &dummyu);
> 
>     return child_return;
> }
> 
> /*
>  * Find client window at pointer location
>  *
>  * root   is the root window.
>  * subwin is the subwindow reported by a ButtonPress event on root.
>  *
>  * If the WM uses virtual roots subwin may be a virtual root.
>  * If so, we descend the window stack at the pointer location and assume the
>  * child is the client or one of its WM frame windows.
>  * This will of course work only if the virtual roots are children of the real
>  * root.
>  */
> Window
> Find_Client(Display * dpy, Window root, Window subwin)
> {
>     unsigned long *roots;
>     unsigned int i, n_roots;
>     Window win;
> 
>     /* Check if subwin is a virtual root */
>     roots = Find_Roots(dpy, root, &n_roots);
>     for (i = 0; i < n_roots; i++) {
>         if (subwin != roots[i])
>             continue;
>         win = Find_Child_At_Pointer(dpy, subwin);
>         if (win == None)
>             return subwin;      /* No child - Return virtual root. */
>         subwin = win;
>         break;
>     }
>     if (roots)
>         XFree(roots);
> 
>     if (atom_wm_state == None) {
>         atom_wm_state = XInternAtom(dpy, "WM_STATE", False);
>         if (!atom_wm_state)
>             return subwin;
>     }
> 
>     /* Check if subwin has WM_STATE */
>     if (Window_Has_Property(dpy, subwin, atom_wm_state))
>         return subwin;
> 
>     /* Attempt to find a client window in subwin's children */
>     win = Find_Client_In_Children(dpy, subwin);
>     if (win != None)
>         return win;             /* Found a client */
> 
>     /* Did not find a client */
>     return subwin;
> }
> /* $Xorg: dsimple.c,v 1.4 2001/02/09 02:05:54 xorgcvs Exp $ */
> /*
> 
> Copyright 1993, 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.
> IN NO EVENT SHALL THE OPEN GROUP 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.
> 
> Except as contained in this notice, the name of The Open Group shall
> not be used in advertising or otherwise to promote the sale, use or
> other dealings in this Software without prior written authorization
> from The Open Group.
> 
> */
> /* $XFree86: xc/programs/xlsfonts/dsimple.c,v 3.6 2001/12/14 20:02:09 dawes Exp $ */
> 
> #include <X11/Xos.h>
> #include <X11/Xlib.h>
> #include <X11/Xutil.h>
> #include <X11/cursorfont.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <stdarg.h>
> /*
>  * Other_stuff.h: Definitions of routines in other_stuff.
>  *
>  * Written by Mark Lillibridge.   Last updated 7/1/87
>  */
> 
> 
> /*
>  * Just_display: A group of routines designed to make the writing of simple
>  *               X11 applications which open a display but do not open
>  *               any windows much faster and easier.  Unless a routine says
>  *               otherwise, it may be assumed to require program_name, dpy,
>  *               and screen already defined on entry.
>  *
>  * Written by Mark Lillibridge.   Last updated 7/1/87
>  */
> 
> 
> /* This stuff is defined in the calling program by just_display.h */
> char    *program_name = "unknown_program";
> Display *dpy = NULL;
> int      screen = 0;
> 
> 
> /*
>  * Get_Display_Name (argc, argv) Look for -display, -d, or host:dpy (obselete)
>  * If found, remove it from command line.  Don't go past a lone -.
>  */
> char *Get_Display_Name(
>     int *pargc,  /* MODIFIED */
>     char **argv) /* MODIFIED */
> {
>     int argc = *pargc;
>     char **pargv = argv+1;
>     char *displayname = NULL;
>     int i;
> 
>     for (i = 1; i < argc; i++) {
> 	char *arg = argv[i];
> 
> 	if (!strcmp (arg, "-display") || !strcmp (arg, "-d")) {
> 	    if (++i >= argc) usage ();
> 
> 	    displayname = argv[i];
> 	    *pargc -= 2;
> 	    continue;
> 	}
> 	if (!strcmp(arg,"-")) {
> 		while (i<argc)
> 			*pargv++ = argv[i++];
> 		break;
> 	}
> 	*pargv++ = arg;
>     }
> 
>     *pargv = NULL;
>     return (displayname);
> }
> 
> 
> 
> /*
>  * Open_Display: Routine to open a display with correct error handling.
>  *               Does not require dpy or screen defined on entry.
>  */
> Display *Open_Display(char *display_name)
> {
> 	Display *d;
> 
> 	d = XOpenDisplay(display_name);
> 	if (d == NULL) {
> 	    fprintf (stderr, "%s:  unable to open display '%s'\n",
> 		     program_name, XDisplayName (display_name));
> 	    usage ();
> 	    /* doesn't return */
> 	}
> 
> 	return(d);
> }
> 
> 
> /*
>  * Setup_Display_And_Screen: This routine opens up the correct display (i.e.,
>  *                           it calls Get_Display_Name) and then stores a
>  *                           pointer to it in dpy.  The default screen
>  *                           for this display is then stored in screen.
>  *                           Does not require dpy or screen defined.
>  */
> void Setup_Display_And_Screen(
>     int *argc,      /* MODIFIED */
>     char **argv)    /* MODIFIED */
> {
> 	char *displayname = NULL;
>         
>         displayname = Get_Display_Name(argc, argv);
> 	dpy = Open_Display (displayname);
> 	screen = XDefaultScreen(dpy);
> }
> 
> /*
>  * Close_Display: Close display
>  */
> void Close_Display(void)
> {
>     if (dpy == NULL)
>       return;
>       
>     XCloseDisplay(dpy);
>     dpy = NULL;
> }
> 
> 
> /*
>  * Select_Window_Args: a rountine to provide a common interface for
>  *                     applications that need to allow the user to select one
>  *                     window on the screen for special consideration.
>  *                     This routine implements the following command line
>  *                     arguments:
>  *
>  *                       -root            Selects the root window.
>  *                       -id <id>         Selects window with id <id>. <id> may
>  *                                        be either in decimal or hex.
>  *                       -name <name>     Selects the window with name <name>.
>  *
>  *                     Call as Select_Window_Args(&argc, argv) in main before
>  *                     parsing any of your program's command line arguments.
>  *                     Select_Window_Args will remove its arguments so that
>  *                     your program does not have to worry about them.
>  *                     The window returned is the window selected or 0 if
>  *                     none of the above arguments was present.  If 0 is
>  *                     returned, Select_Window should probably be called after
>  *                     all command line arguments, and other setup is done.
>  *                     For examples of usage, see xwininfo, xwd, or xprop.
>  */
> Window Select_Window_Args(
>     int *rargc,
>     char **argv)
> #define ARGC (*rargc)
> {
> 	int nargc=1;
> 	int argc;
> 	char **nargv;
> 	Window w=0;
> 
> 	nargv = argv+1; argc = ARGC;
> #define OPTION argv[0]
> #define NXTOPTP ++argv, --argc>0
> #define NXTOPT if (++argv, --argc==0) usage()
> #define COPYOPT nargv++[0]=OPTION, nargc++
> 
> 	while (NXTOPTP) {
> 		if (!strcmp(OPTION, "-")) {
> 			COPYOPT;
> 			while (NXTOPTP)
> 			  COPYOPT;
> 			break;
> 		}
> 		if (!strcmp(OPTION, "-root")) {
> 			w=RootWindow(dpy, screen);
> 			continue;
> 		}
> 		if (!strcmp(OPTION, "-name")) {
> 			NXTOPT;
> 			w = Window_With_Name(dpy, RootWindow(dpy, screen),
> 					     OPTION);
> 			if (!w)
> 			  Fatal_Error("No window with name %s exists!",OPTION);
> 			continue;
> 		}
> 		if (!strcmp(OPTION, "-id")) {
> 			NXTOPT;
> 			w=0;
> 			sscanf(OPTION, "0x%lx", &w);
> 			if (!w)
> 			  sscanf(OPTION, "%lu", &w);
> 			if (!w)
> 			  Fatal_Error("Invalid window id format: %s.", OPTION);
> 			continue;
> 		}
> 		COPYOPT;
> 	}
> 	ARGC = nargc;
> 	
> 	return(w);
> }
> 
> /*
>  * Other_stuff: A group of routines which do common X11 tasks.
>  *
>  * Written by Mark Lillibridge.   Last updated 7/1/87
>  */
> 
> 
> /*
>  * Routine to let user select a window using the mouse
>  */
> 
> Window Select_Window(Display *dpy, int descend)
> {
>   int status;
>   Cursor cursor;
>   XEvent event;
>   Window target_win = None, root = RootWindow(dpy,screen);
>   int buttons = 0;
> 
>   /* Make the target cursor */
>   cursor = XCreateFontCursor(dpy, XC_crosshair);
> 
>   /* Grab the pointer using target cursor, letting it room all over */
>   status = XGrabPointer(dpy, root, False,
> 			ButtonPressMask|ButtonReleaseMask, GrabModeSync,
> 			GrabModeAsync, root, cursor, CurrentTime);
>   if (status != GrabSuccess) Fatal_Error("Can't grab the mouse.");
> 
>   /* Let the user select a window... */
>   while ((target_win == None) || (buttons != 0)) {
>     /* allow one more event */
>     XAllowEvents(dpy, SyncPointer, CurrentTime);
>     XWindowEvent(dpy, root, ButtonPressMask|ButtonReleaseMask, &event);
>     switch (event.type) {
>     case ButtonPress:
>       if (target_win == None) {
> 	target_win = event.xbutton.subwindow; /* window selected */
> 	if (target_win == None) target_win = root;
>       }
>       buttons++;
>       break;
>     case ButtonRelease:
>       if (buttons > 0) /* there may have been some down before we started */
> 	buttons--;
>        break;
>     }
>   } 
> 
>   XUngrabPointer(dpy, CurrentTime);      /* Done with pointer */
> 
>   if (!descend || (target_win == root))
>     return(target_win);
> 
>   target_win = Find_Client(dpy, root, target_win);
> 
>   return(target_win);
> }
> 
> 
> /*
>  * Window_With_Name: routine to locate a window with a given name on a display.
>  *                   If no window with the given name is found, 0 is returned.
>  *                   If more than one window has the given name, the first
>  *                   one found will be returned.  Only top and its subwindows
>  *                   are looked at.  Normally, top should be the RootWindow.
>  */
> Window Window_With_Name(
>     Display *dpy,
>     Window top,
>     char *name)
> {
> 	Window *children, dummy;
> 	unsigned int nchildren;
> 	int i;
> 	Window w=0;
> 	char *window_name;
> 
> 	if (XFetchName(dpy, top, &window_name) && !strcmp(window_name, name))
> 	  return(top);
> 
> 	if (!XQueryTree(dpy, top, &dummy, &dummy, &children, &nchildren))
> 	  return(0);
> 
> 	for (i=0; i<nchildren; i++) {
> 		w = Window_With_Name(dpy, children[i], name);
> 		if (w)
> 		  break;
> 	}
> 	if (children) XFree ((char *)children);
> 	return(w);
> }
> 
> 
> /*
>  * Standard fatal error routine - call like printf
>  * Does not require dpy or screen defined.
>  */
> void Fatal_Error(char *msg, ...)
> {
> 	va_list args;
> 	fflush(stdout);
> 	fflush(stderr);
> 	fprintf(stderr, "%s: error: ", program_name);
> 	va_start(args, msg);
> 	vfprintf(stderr, msg, args);
> 	va_end(args);
> 	fprintf(stderr, "\n");
>         Close_Display();
> 	exit(EXIT_FAILURE);
> }
> /* $XdotOrg: $ */
> /* $Xorg: xwininfo.c,v 1.4 2001/02/09 02:06:04 xorgcvs Exp $ */
> /*
> 
> 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
> 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.
> 
> */
> /* $XFree86: xc/programs/xwininfo/xwininfo.c,v 1.9 2003/09/09 22:08:25 herrb Exp $ */
> 
> 
> /*
>  * 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 <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>
> #endif
> #include <stdio.h>
> #include <stdlib.h>
> 
> /* Include routines to handle parsing defaults */
> 
> #define printf /* */
> 
> typedef struct {
> 	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 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:
>  */
> 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");
>     exit (1);
> }
> 
> /*
>  * pixel to inch, metric converter.
>  * Hacked in by Mark W. Eichin <eichin@...ena> [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.
>  *
>  */
> 
> #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 english = 0, metric = 0;
> 
> static void
> scale_init(void)
> {
>   getdsp(yp,  DisplayHeight);
>   getdsp(ymm, DisplayHeightMM);
>   getdsp(xp,  DisplayWidth);
>   getdsp(xmm, DisplayWidthMM);
>   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)
> {
>   if(!xp) {
>     scale_init();
>   }
>   return(nscale(x, xp, xmm, xbuf, sizeof(xbuf)));
> }
> 
> static char ybuf[BUFSIZ];
> static char *
> yscale(int y)
> {
>   if(!yp) {
>     scale_init();
>   }
>   return(nscale(y, yp, ymm, ybuf, sizeof(ybuf)));
> }
> 
> static char bbuf[BUFSIZ];
> static char *
> bscale(int b)
> {
>   if(!bp) {
>     scale_init();
>   }
>   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)
> {
>     char badid[20];
> 
>     snprintf(badid, sizeof(badid), window_id_format, err->resourceid);
>     Fatal_Error("No such window with id %s.", badid);
>     exit (1);
>     return 0;
> }
> 
> 
> 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
> 
>   /* Open display, handle command line arguments */
>   Setup_Display_And_Screen(&argc, argv);
> 
>   /* Get window selected on command line, if any */
>   window = Select_Window_Args(&argc, argv);
> 
>   /* 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 (!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();
>   }
> 
>   /* 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);
> }
> 
> 
> /*
>  * Lookup: lookup a code in a table.
>  */
> static char _lookup_buffer[100];
> 
> static const char *
> LookupL(long code, const binding *table)
> {
> 	const char *name;
> 
> 	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++;
> 	}
> 
> 	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
>  */
> 
> static void
> Display_Window_Id(Window window, Bool newline_wanted)
> {
> #ifdef NO_I18N
>     char *win_name;
> #else
>     XTextProperty tp;
> #endif
>     
>     printf(window_id_format, window);         /* print id # in hex/dec */
> 
>     if (!window) {
> 	printf(" (none)");
>     } else {
> 	if (window == RootWindow(dpy, screen)) {
> 	    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);
> 	}
> #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("\"");
> 	}
> #endif
> 	else
> 	    printf(" (has no name)");
>     }
> 
>     if (newline_wanted)
> 	printf("\n");
> 
>     return;
> }
> 
> 
> /*
>  * Display Stats on window
>  */
> static const binding _window_classes[] = {
> 	{ InputOutput, "InputOutput" },
> 	{ InputOnly, "InputOnly" },
>         { 0, 0 } };
> 
> static const binding _map_states[] = {
> 	{ IsUnmapped, "IsUnMapped" },
> 	{ IsUnviewable, "IsUnviewable" },
> 	{ IsViewable, "IsViewable" },
> 	{ 0, 0 } };
> 
> static const binding _backing_store_states[] = {
> 	{ NotUseful, "NotUseful" },
> 	{ WhenMapped, "WhenMapped" },
> 	{ Always, "Always" },
> 	{ 0, 0 } };
> 
> 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" },
> 	{ 0, 0 }};
> 
> 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" },
> 	{ 0, 0 }};
> 
> static const binding _visual_classes[] = {
> 	{ StaticGray, "StaticGray" },
> 	{ GrayScale, "GrayScale" },
> 	{ StaticColor, "StaticColor" },
> 	{ PseudoColor, "PseudoColor" },
> 	{ TrueColor, "TrueColor" },
> 	{ DirectColor, "DirectColor" },
> 	{ 0, 0 }};
> 
> static void
> Display_Stats_Info(Window window)
> {
>   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 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");
> }
> 
> 
> /*
>  * 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" },
> 	{ 0, 0 } };
> 
> static const binding _backing_store_hint[] = {
> 	{ NotUseful, "NotUseful" },
> 	{ WhenMapped, "WhenMapped" },
> 	{ Always, "Always" },
> 	{ 0, 0 } };
> 
> static const binding _bool[] = {
> 	{ 0, "No" },
> 	{ 1, "Yes" },
> 	{ 0, 0 } };
> 
> static void
> Display_Bits_Info(Window window)
> {
>   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));
> }
> 
> 
> /*
>  * 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" },
> 	{ 0, 0 } };
> 
> 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
>  */
> static void
> Display_Events_Info(Window window)
> {
>   XWindowAttributes win_attributes;
> 
>   if (!XGetWindowAttributes(dpy, window, &win_attributes))
>     Fatal_Error("Can't get window attributes.");
> 
>   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
>  */
> static void
> Display_Tree_Info(Window window, int recurse)
> {
>     display_tree_info_1(window, recurse, 0);
> }
> 
> /*
>  * level - recursion level
>  */
> static void
> display_tree_info_1(Window window, 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(") ");
> 
>     if (XGetGeometry(dpy, child_list[i], &root_win,
> 		     &rel_x, &rel_y, &width, &height, &border, &depth)) {
> 	Window child;
> 
> 	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);
> 	}
>     }
>     printf("\n");
>     
>     if (recurse)
> 	display_tree_info_1(child_list[i], 1, level+1);
>   }
> 
>   if (child_list) XFree((char *)child_list);
> }
> 
> 
> /*
>  * Display a set of size hints
>  */
> static void
> Display_Hints(XSizeHints *hints)
> {
> 	long flags;
> 
> 	flags = hints->flags;
> 	
> 	if (flags & USPosition)
> 	  printf("      User supplied location: %s, %s\n",
> 		 xscale(hints->x), yscale(hints->y));
> 
> 	if (flags & PPosition)
> 	  printf("      Program 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 & PSize)
> 	  printf("      Program 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 & PMaxSize)
> 	  printf("      Program supplied maximum size: %s by %s\n",
> 		 xscale(hints->max_width), yscale(hints->max_height));
> 
> 	if (flags & PBaseSize) {
> 	  printf("      Program supplied base size: %s by %s\n",
> 		 xscale(hints->base_width), yscale(hints->base_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));
> 	}
> }
> 
> 
> /*
>  * Display Size Hints info
>  */
> static void
> Display_Size_Hints(Window window)
> {
> 	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);
> 	}
> 
> 	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);
> }
> 
> 
> static void
> Display_Window_Shape (Window window)
> {
>     Bool    ws, bs;
>     int	    xws, yws, xbs, ybs;
>     unsigned int wws, hws, wbs, hbs;
> 
>     if (!XShapeQueryExtension (dpy, &bs, &ws))
> 	return;
> 
>     printf("\n");
>     XShapeQueryExtents (dpy, window, &ws, &xws, &yws, &wws, &hws,
> 				     &bs, &xbs, &ybs, &wbs, &hbs);
>     if (!ws)
> 	  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));
>     }
>     if (!bs)
> 	  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));
>     }
> }
> 
> /*
>  * Display Window Manager Info
>  */
> static const binding _state_hints[] = {
> 	{ DontCareState, "Don't Care State" },
> 	{ NormalState, "Normal State" },
> 	{ ZoomState, "Zoomed State" },
> 	{ IconicState, "Iconic State" },
> 	{ InactiveState, "Inactive State" },
> 	{ 0, 0 } };
> 
> static void
> Display_WM_Info(Window window)
> {
>         XWMHints *wmhints;
> 	long flags;
> 
> 	wmhints = XGetWMHints(dpy, window);
> 	printf("\n");
> 	if (!wmhints) {
> 		printf("  No window manager hints defined\n");
> 		return;
> 	}
> 	flags = wmhints->flags;
> 
> 	printf("  Window manager hints:\n");
> 
> 	if (flags & InputHint)
> 	  printf("      Client accepts input or input focus: %s\n",
> 		 Lookup(wmhints->input, _bool));
> 
> 	if (flags & IconWindowHint) {
> 		printf("      Icon window id: ");
> 		Display_Window_Id(wmhints->icon_window, True);
> 	}
> 
> 	if (flags & IconPositionHint)
> 	  printf("      Initial icon position: %s, %s\n",
> 		 xscale(wmhints->icon_x), yscale(wmhints->icon_y));
> 
> 	if (flags & StateHint)
> 	  printf("      Initial state is %s\n",
> 		 Lookup(wmhints->initial_state, _state_hints));
> 
> 	XFree(wmhints);
> }



-- 
Mathieu Desnoyers
Operating System Efficiency R&D Consultant
EfficiOS Inc.
http://www.efficios.com

Download attachment "capture-xwinsched.png" of type "image/png" (126377 bytes)

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ