summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dsimple.c523
-rw-r--r--dsimple.h81
-rw-r--r--xprop.c1516
-rw-r--r--xprop.man327
4 files changed, 2447 insertions, 0 deletions
diff --git a/dsimple.c b/dsimple.c
new file mode 100644
index 0000000..210d121
--- /dev/null
+++ b/dsimple.c
@@ -0,0 +1,523 @@
+/* $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.
+
+*/
+
+#include <X11/Xos.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/cursorfont.h>
+#include <stdio.h>
+/*
+ * Other_stuff.h: Definitions of routines in other_stuff.
+ *
+ * Written by Mark Lillibridge. Last updated 7/1/87
+ */
+
+unsigned long Resolve_Color();
+Pixmap Bitmap_To_Pixmap();
+Window Select_Window();
+void out();
+void blip();
+Window Window_With_Name();
+void Fatal_Error();
+
+/*
+ * Just_display: A group of routines designed to make the writting 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 */
+extern char *program_name;
+extern Display *dpy;
+extern int screen;
+
+
+/*
+ * Malloc: like malloc but handles out of memory using Fatal_Error.
+ */
+char *Malloc(size)
+ unsigned size;
+{
+ char *data, *malloc();
+
+ if (!(data = malloc(size)))
+ Fatal_Error("Out of memory!");
+
+ return(data);
+}
+
+
+/*
+ * Realloc: like Malloc except for realloc, handles NULL using Malloc.
+ */
+char *Realloc(ptr, size)
+ char *ptr;
+ int size;
+{
+ char *new_ptr, *realloc();
+
+ if (!ptr)
+ return(Malloc(size));
+
+ if (!(new_ptr = realloc(ptr, size)))
+ Fatal_Error("Out of memory!");
+
+ return(new_ptr);
+}
+
+
+/*
+ * 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(pargc, argv)
+ 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(display_name)
+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(argc, argv)
+int *argc; /* MODIFIED */
+char **argv; /* MODIFIED */
+{
+ dpy = Open_Display (Get_Display_Name(argc, argv));
+ screen = DefaultScreen(dpy);
+}
+
+
+/*
+ * Open_Font: This routine opens a font with error handling.
+ */
+XFontStruct *Open_Font(name)
+char *name;
+{
+ XFontStruct *font;
+
+ if (!(font=XLoadQueryFont(dpy, name)))
+ Fatal_Error("Unable to open font %s!", name);
+
+ return(font);
+}
+
+
+/*
+ * Beep: Routine to beep the display.
+ */
+void Beep()
+{
+ XBell(dpy, 50);
+}
+
+
+/*
+ * ReadBitmapFile: same as XReadBitmapFile except it returns the bitmap
+ * directly and handles errors using Fatal_Error.
+ */
+static void _bitmap_error(status, filename)
+ int status;
+ char *filename;
+{
+ if (status == BitmapOpenFailed)
+ Fatal_Error("Can't open file %s!", filename);
+ else if (status == BitmapFileInvalid)
+ Fatal_Error("file %s: Bad bitmap format.", filename);
+ else
+ Fatal_Error("Out of memory!");
+}
+
+Pixmap ReadBitmapFile(d, filename, width, height, x_hot, y_hot)
+ Drawable d;
+ char *filename;
+ int *width, *height, *x_hot, *y_hot;
+{
+ Pixmap bitmap;
+ int status;
+
+ status = XReadBitmapFile(dpy, RootWindow(dpy, screen), filename,
+ (unsigned int *)width, (unsigned int *)height,
+ &bitmap, x_hot, y_hot);
+ if (status != BitmapSuccess)
+ _bitmap_error(status, filename);
+
+ return(bitmap);
+}
+
+
+/*
+ * WriteBitmapFile: same as XWriteBitmapFile except it handles errors
+ * using Fatal_Error.
+ */
+void WriteBitmapFile(filename, bitmap, width, height, x_hot, y_hot)
+ char *filename;
+ Pixmap bitmap;
+ int width, height, x_hot, y_hot;
+{
+ int status;
+
+ status= XWriteBitmapFile(dpy, filename, bitmap, width, height, x_hot,
+ y_hot);
+ if (status != BitmapSuccess)
+ _bitmap_error(status, filename);
+}
+
+
+/*
+ * 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(rargc, argv)
+ 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, "%ld", &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
+ */
+
+extern Display *dpy;
+extern int screen;
+
+/*
+ * Resolve_Color: This routine takes a color name and returns the pixel #
+ * that when used in the window w will be of color name.
+ * (WARNING: The colormap of w MAY be modified! )
+ * If colors are run out of, only the first n colors will be
+ * as correct as the hardware can make them where n depends
+ * on the display. This routine does not require wind to
+ * be defined.
+ */
+unsigned long Resolve_Color(w, name)
+ Window w;
+ char *name;
+{
+ XColor c;
+ Colormap colormap;
+ XWindowAttributes wind_info;
+
+ /*
+ * The following is a hack to insure machines without a rgb table
+ * handle at least white & black right.
+ */
+ if (!strcmp(name, "white"))
+ name="#ffffffffffff";
+ if (!strcmp(name, "black"))
+ name="#000000000000";
+
+ XGetWindowAttributes(dpy, w, &wind_info);
+ colormap = wind_info.colormap;
+
+ if (!XParseColor(dpy, colormap, name, &c))
+ Fatal_Error("Bad color format '%s'.", name);
+
+ if (!XAllocColor(dpy, colormap, &c))
+ Fatal_Error("XAllocColor failed!");
+
+ return(c.pixel);
+}
+
+
+/*
+ * Bitmap_To_Pixmap: Convert a bitmap to a 2 colored pixmap. The colors come
+ * from the foreground and background colors of the gc.
+ * Width and height are required solely for efficiency.
+ * If needed, they can be obtained via. XGetGeometry.
+ */
+Pixmap Bitmap_To_Pixmap(dpy, d, gc, bitmap, width, height)
+ Display *dpy;
+ Drawable d;
+ GC gc;
+ Pixmap bitmap;
+ int width, height;
+{
+ Pixmap pix;
+ int x;
+ unsigned int i, depth;
+ Drawable root;
+
+ if (!XGetGeometry(dpy, d, &root, &x, &x, &i, &i, &i, &depth))
+ return(0);
+
+ pix = XCreatePixmap(dpy, d, width, height, (int)depth);
+
+ XCopyPlane(dpy, bitmap, pix, gc, 0, 0, width, height, 0, 0, 1);
+
+ return(pix);
+}
+
+
+/*
+ * blip: a debugging routine. Prints Blip! on stderr with flushing.
+ */
+void blip()
+{
+ outl("blip!");
+}
+
+
+/*
+ * Routine to let user select a window using the mouse
+ */
+
+Window Select_Window(dpy)
+ Display *dpy;
+{
+ 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 */
+
+ 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(dpy, top, 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);
+}
+
+/*
+ * outl: a debugging routine. Flushes stdout then prints a message on stderr
+ * and flushes stderr. Used to print messages when past certain points
+ * in code so we can tell where we are. Outl may be invoked like
+ * printf with up to 7 arguments.
+ */
+/* VARARGS1 */
+outl(msg, arg0,arg1,arg2,arg3,arg4,arg5,arg6)
+ char *msg;
+ char *arg0, *arg1, *arg2, *arg3, *arg4, *arg5, *arg6;
+{
+ fflush(stdout);
+ fprintf(stderr, msg, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+}
+
+
+/*
+ * Standard fatal error routine - call like printf but maximum of 7 arguments.
+ * Does not require dpy or screen defined.
+ */
+/* VARARGS1 */
+void Fatal_Error(msg, arg0,arg1,arg2,arg3,arg4,arg5,arg6)
+char *msg;
+char *arg0, *arg1, *arg2, *arg3, *arg4, *arg5, *arg6;
+{
+ fflush(stdout);
+ fflush(stderr);
+ fprintf(stderr, "%s: error: ", program_name);
+ fprintf(stderr, msg, arg0, arg1, arg2, arg3, arg4, arg5, arg6);
+ fprintf(stderr, "\n");
+ exit(1);
+}
diff --git a/dsimple.h b/dsimple.h
new file mode 100644
index 0000000..a634848
--- /dev/null
+++ b/dsimple.h
@@ -0,0 +1,81 @@
+/* $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.
+
+*/
+
+/*
+ * 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@athena.mit.edu.
+ */
+
+ /* Global variables used by routines in just_display.c */
+
+char *program_name = "unknown_program"; /* Name of this program */
+Display *dpy; /* The current display */
+int screen; /* The current screen */
+
+#define INIT_NAME program_name=argv[0] /* use this in main to setup
+ program_name */
+
+ /* Declaritions for functions in just_display.c */
+
+void Fatal_Error();
+char *Malloc();
+char *Realloc();
+char *Get_Display_Name();
+Display *Open_Display();
+void Setup_Display_And_Screen();
+XFontStruct *Open_Font();
+void Beep();
+Pixmap ReadBitmapFile();
+void WriteBitmapFile();
+Window Select_Window_Args();
+
+#define X_USAGE "[host:display]" /* X arguments handled by
+ Get_Display_Name */
+#define SELECT_USAGE "[{-root|-id <id>|-font <font>|-name <name>}]"
+
+/*
+ * Other_stuff.h: Definitions of routines in other_stuff.
+ *
+ * Written by Mark Lillibridge. Last updated 7/1/87
+ *
+ * Send bugs, etc. to chariot@athena.mit.edu.
+ */
+
+unsigned long Resolve_Color();
+Pixmap Bitmap_To_Pixmap();
+Window Select_Window();
+void out();
+void blip();
+Window Window_With_Name();
diff --git a/xprop.c b/xprop.c
new file mode 100644
index 0000000..0d8f32d
--- /dev/null
+++ b/xprop.c
@@ -0,0 +1,1516 @@
+/* $Xorg: xprop.c,v 1.6 2001/02/09 02:05:56 xorgcvs Exp $ */
+/*
+
+Copyright 1990, 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.
+
+*/
+
+
+#include <X11/Xlib.h>
+#include <X11/Xos.h>
+#include <X11/Xfuncs.h>
+#include <X11/Xutil.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include <X11/Xatom.h>
+#include <X11/Xmu/WinUtil.h>
+
+#include "dsimple.h"
+
+#ifndef X_NOT_STDC_ENV
+#include <stdlib.h>
+#else
+char *getenv();
+#endif
+
+#define MAXSTR 10000
+
+#define min(a,b) ((a) < (b) ? (a) : (b))
+
+/*
+ *
+ * The Thunk Manager - routines to create, add to, and free thunk lists
+ *
+ */
+
+typedef struct {
+ int thunk_count;
+ long value;
+ char *extra_value;
+ char *format;
+ char *dformat;
+} thunk;
+
+thunk *Create_Thunk_List()
+{
+ thunk *tptr;
+
+ tptr = (thunk *) Malloc( sizeof(thunk) );
+
+ tptr->thunk_count = 0;
+
+ return(tptr);
+}
+
+Free_Thunk_List(list)
+thunk *list;
+{
+ free(list);
+}
+
+thunk *Add_Thunk(list, t)
+thunk *list;
+thunk t;
+{
+ int i;
+
+ i = list->thunk_count;
+
+ list = (thunk *) realloc(list, (i+1)*sizeof(thunk) );
+ if (!list)
+ Fatal_Error("Out of memory!");
+
+ list[i++] = t;
+ list->thunk_count = i;
+
+ return(list);
+}
+
+/*
+ * Misc. routines
+ */
+
+char *Copy_String(string)
+ char *string;
+{
+ char *new;
+ int length;
+
+ length = strlen(string) + 1;
+
+ new = (char *) Malloc(length);
+ memmove( new, string, length);
+
+ return(new);
+}
+
+int Read_Char(stream)
+ FILE *stream;
+{
+ int c;
+
+ c = getc(stream);
+ if (c==EOF)
+ Fatal_Error("Bad format file: Unexpected EOF.");
+ return(c);
+}
+
+Read_White_Space(stream)
+ FILE *stream;
+{
+ int c;
+
+ while ((c=getc(stream))==' ' || c=='\n' || c=='\t');
+ ungetc(c, stream);
+}
+
+static char _large_buffer[MAXSTR+10];
+
+char *Read_Quoted(stream)
+ FILE *stream;
+{
+ char *ptr;
+ int c, length;
+
+ Read_White_Space(stream);
+ if (Read_Char(stream)!='\'')
+ Fatal_Error("Bad format file format: missing dformat.");
+
+ ptr = _large_buffer; length=MAXSTR;
+ for (;;) {
+ if (length<0)
+ Fatal_Error("Bad format file format: dformat too long.");
+ c = Read_Char(stream);
+ if (c==(int) '\'')
+ break;
+ ptr++[0]=c; length--;
+ if (c== (int) '\\') {
+ c=Read_Char(stream);
+ if (c=='\n') {
+ ptr--; length++;
+ } else
+ ptr++[0]=c; length--;
+ }
+ }
+ ptr++[0]='\0';
+
+ return(Copy_String(_large_buffer));
+}
+
+/*
+ *
+ * Atom to format, dformat mapping Manager
+ *
+ */
+
+#define D_FORMAT "0x" /* Default format for properties */
+#define D_DFORMAT " = $0+\n" /* Default display pattern for properties */
+
+static thunk *_property_formats = 0; /* Holds mapping */
+
+Apply_Default_Formats(format, dformat)
+ char **format;
+ char **dformat;
+{
+ if (!*format)
+ *format = D_FORMAT;
+ if (!*dformat)
+ *dformat = D_DFORMAT;
+}
+
+Lookup_Formats(atom, format, dformat)
+ Atom atom;
+ char **format;
+ char **dformat;
+{
+ int i;
+
+ if (_property_formats)
+ for (i=_property_formats->thunk_count-1; i>=0; i--)
+ if (_property_formats[i].value==atom) {
+ if (!*format)
+ *format = _property_formats[i].format;
+ if (!*dformat)
+ *dformat = _property_formats[i].dformat;
+ break;
+ }
+}
+
+Add_Mapping(atom, format, dformat)
+ Atom atom;
+ char *format;
+ char *dformat;
+{
+ thunk t;
+
+ if (!_property_formats)
+ _property_formats = Create_Thunk_List();
+
+ t.value=atom;
+ t.format=format;
+ t.dformat=dformat;
+
+ _property_formats = Add_Thunk(_property_formats, t);
+}
+
+/*
+ *
+ * Setup_Mapping: Routine to setup default atom to format, dformat mapping:
+ *
+ */
+
+typedef struct _propertyRec {
+ char * name;
+ Atom atom;
+ char * format;
+ char * dformat;
+} propertyRec;
+
+#define ARC_DFORMAT ":\n\
+\t\tarc at $0, $1\n\
+\t\tsize: $2 by $3\n\
+\t\tfrom angle $4 to angle $5\n"
+
+#define RECTANGLE_DFORMAT ":\n\
+\t\tupper left corner: $0, $1\n\
+\t\tsize: $2 by $3\n"
+
+#define RGB_COLOR_MAP_DFORMAT ":\n\
+\t\tcolormap id #: $0\n\
+\t\tred-max: $1\n\
+\t\tred-mult: $2\n\
+\t\tgreen-max: $3\n\
+\t\tgreen-mult: $4\n\
+\t\tblue-max: $5\n\
+\t\tblue-mult: $6\n\
+\t\tbase-pixel: $7\n\
+\t\tvisual id #: $8\n\
+\t\tkill id #: $9\n"
+
+#define WM_HINTS_DFORMAT ":\n\
+?m0(\t\tClient accepts input or input focus: $1\n)\
+?m1(\t\tInitial state is \
+?$2=0(Don't Care State)\
+?$2=1(Normal State)\
+?$2=2(Zoomed State)\
+?$2=3(Iconic State)\
+?$2=4(Inactive State)\
+.\n)\
+?m2(\t\tbitmap id # to use for icon: $3\n)\
+?m5(\t\tbitmap id # of mask for icon: $7\n)\
+?m3(\t\twindow id # to use for icon: $4\n)\
+?m4(\t\tstarting position for icon: $5, $6\n)\
+?m6(\t\twindow id # of group leader: $8\n)\
+?m8(\t\tThe visible hint bit is set\n)"
+
+#define WM_ICON_SIZE_DFORMAT ":\n\
+\t\tminimum icon size: $0 by $1\n\
+\t\tmaximum icon size: $2 by $3\n\
+\t\tincremental size change: $4 by $5\n"
+
+#define WM_SIZE_HINTS_DFORMAT ":\n\
+?m0(\t\tuser specified location: $1, $2\n)\
+?m2(\t\tprogram specified location: $1, $2\n)\
+?m1(\t\tuser specified size: $3 by $4\n)\
+?m3(\t\tprogram specified size: $3 by $4\n)\
+?m4(\t\tprogram specified minimum size: $5 by $6\n)\
+?m5(\t\tprogram specified maximum size: $7 by $8\n)\
+?m6(\t\tprogram specified resize increment: $9 by $10\n)\
+?m7(\t\tprogram specified minimum aspect ratio: $11/$12\n\
+\t\tprogram specified maximum aspect ratio: $13/$14\n)\
+?m8(\t\tprogram specified base size: $15 by $16\n)\
+?m9(\t\twindow gravity: \
+?$17=0(Forget)\
+?$17=1(NorthWest)\
+?$17=2(North)\
+?$17=3(NorthEast)\
+?$17=4(West)\
+?$17=5(Center)\
+?$17=6(East)\
+?$17=7(SouthWest)\
+?$17=8(South)\
+?$17=9(SouthEast)\
+?$17=10(Static)\
+\n)"
+
+#define WM_STATE_DFORMAT ":\n\
+\t\twindow state: ?$0=0(Withdrawn)?$0=1(Normal)?$0=3(Iconic)\n\
+\t\ticon window: $1\n"
+
+propertyRec windowPropTable[] = {
+ {"ARC", XA_ARC, "16iiccii", ARC_DFORMAT },
+ {"ATOM", XA_ATOM, "32a", 0 },
+ {"BITMAP", XA_BITMAP, "32x", ": bitmap id # $0\n" },
+ {"CARDINAL", XA_CARDINAL, "0c", 0 },
+ {"COLORMAP", XA_COLORMAP, "32x", ": colormap id # $0\n" },
+ {"CURSOR", XA_CURSOR, "32x", ": cursor id # $0\n" },
+ {"DRAWABLE", XA_DRAWABLE, "32x", ": drawable id # $0\n" },
+ {"FONT", XA_FONT, "32x", ": font id # $0\n" },
+ {"INTEGER", XA_INTEGER, "0i", 0 },
+ {"PIXMAP", XA_PIXMAP, "32x", ": pixmap id # $0\n" },
+ {"POINT", XA_POINT, "16ii", " = $0, $1\n" },
+ {"RECTANGLE", XA_RECTANGLE, "16iicc", RECTANGLE_DFORMAT },
+ {"RGB_COLOR_MAP", XA_RGB_COLOR_MAP,"32xcccccccxx",RGB_COLOR_MAP_DFORMAT},
+ {"STRING", XA_STRING, "8s", 0 },
+ {"WINDOW", XA_WINDOW, "32x", ": window id # $0\n" },
+ {"VISUALID", XA_VISUALID, "32x", ": visual id # $0\n" },
+ {"WM_COLORMAP_WINDOWS", 0, "32x", ": window id # $0+\n"},
+ {"WM_COMMAND", XA_WM_COMMAND, "8s", " = { $0+ }\n" },
+ {"WM_HINTS", XA_WM_HINTS, "32mbcxxiixx", WM_HINTS_DFORMAT },
+ {"WM_ICON_SIZE", XA_WM_ICON_SIZE, "32cccccc", WM_ICON_SIZE_DFORMAT},
+ {"WM_PROTOCOLS", 0, "32a", ": protocols $0+\n"},
+ {"WM_SIZE_HINTS", XA_WM_SIZE_HINTS,"32mii", WM_SIZE_HINTS_DFORMAT },
+ {"WM_STATE", 0, "32cx", WM_STATE_DFORMAT}
+};
+#undef ARC_DFORMAT
+#undef RECTANGLE_DFORMAT
+#undef RGB_COLOR_MAP_DFORMAT
+#undef WM_ICON_SIZE_DFORMAT
+#undef WM_HINTS_DFORMAT
+#undef WM_SIZE_HINTS_DFORMAT
+#undef WM_STATE_DFORMAT
+
+/*
+ * Font-specific mapping of property names to types:
+ */
+propertyRec fontPropTable[] = {
+
+ /* XLFD name properties */
+
+ "FOUNDRY", 0, "32a", 0,
+ "FAMILY_NAME", XA_FAMILY_NAME, "32a", 0,
+ "WEIGHT_NAME", 0, "32a", 0,
+ "SLANT", 0, "32a", 0,
+ "SETWIDTH_NAME", 0, "32a", 0,
+ "ADD_STYLE_NAME", 0, "32a", 0,
+ "PIXEL_SIZE", 0, "32c", 0,
+ "POINT_SIZE", XA_POINT_SIZE, "32c", 0,
+ "RESOLUTION_X", 0, "32c", 0,
+ "RESOLUTION_Y", 0, "32c", 0,
+ "SPACING", 0, "32a", 0,
+ "AVERAGE_WIDTH", 0, "32c", 0,
+ "CHARSET_REGISTRY", 0, "32a", 0,
+ "CHARSET_ENCODING", 0, "32a", 0,
+
+ /* other font properties referenced in the XLFD */
+
+ "QUAD_WIDTH", XA_QUAD_WIDTH, "32i", 0,
+ "RESOLUTION", XA_RESOLUTION, "32c", 0,
+ "MIN_SPACE", XA_MIN_SPACE, "32c", 0,
+ "NORM_SPACE", XA_NORM_SPACE, "32c", 0,
+ "MAX_SPACE", XA_MAX_SPACE, "32c", 0,
+ "END_SPACE", XA_END_SPACE, "32c", 0,
+ "SUPERSCRIPT_X", XA_SUPERSCRIPT_X, "32i", 0,
+ "SUPERSCRIPT_Y", XA_SUPERSCRIPT_Y, "32i", 0,
+ "SUBSCRIPT_X", XA_SUBSCRIPT_X, "32i", 0,
+ "SUBSCRIPT_Y", XA_SUBSCRIPT_Y, "32i", 0,
+ "UNDERLINE_POSITION", XA_UNDERLINE_POSITION, "32i", 0,
+ "UNDERLINE_THICKNESS", XA_UNDERLINE_THICKNESS, "32i", 0,
+ "STRIKEOUT_ASCENT", XA_STRIKEOUT_ASCENT, "32i", 0,
+ "STRIKEOUT_DESCENT", XA_STRIKEOUT_DESCENT, "32i", 0,
+ "ITALIC_ANGLE", XA_ITALIC_ANGLE, "32i", 0,
+ "X_HEIGHT", XA_X_HEIGHT, "32i", 0,
+ "WEIGHT", XA_WEIGHT, "32i", 0,
+ "FACE_NAME", 0, "32a", 0,
+ "COPYRIGHT", XA_COPYRIGHT, "32a", 0,
+ "AVG_CAPITAL_WIDTH", 0, "32i", 0,
+ "AVG_LOWERCASE_WIDTH", 0, "32i", 0,
+ "RELATIVE_SETWIDTH", 0, "32c", 0,
+ "RELATIVE_WEIGHT", 0, "32c", 0,
+ "CAP_HEIGHT", XA_CAP_HEIGHT, "32c", 0,
+ "SUPERSCRIPT_SIZE", 0, "32c", 0,
+ "FIGURE_WIDTH", 0, "32i", 0,
+ "SUBSCRIPT_SIZE", 0, "32c", 0,
+ "SMALL_CAP_SIZE", 0, "32i", 0,
+ "NOTICE", XA_NOTICE, "32a", 0,
+ "DESTINATION", 0, "32c", 0,
+
+ /* other font properties */
+
+ "FONT", XA_FONT, "32a", 0,
+ "FONT_NAME", XA_FONT_NAME, "32a", 0,
+};
+
+static int XpropMode;
+#define XpropWindowProperties 0
+#define XpropFontProperties 1
+
+Setup_Mapping()
+{
+ int n;
+ propertyRec *p;
+
+ if (XpropMode == XpropWindowProperties) {
+ n = sizeof(windowPropTable) / sizeof(propertyRec);
+ p = windowPropTable;
+ } else {
+ n = sizeof (fontPropTable) / sizeof (propertyRec);
+ p = fontPropTable;
+ }
+ for ( ; --n >= 0; p++) {
+ if (! p->atom) {
+ p->atom = XInternAtom(dpy, p->name, True);
+ if (p->atom == None)
+ continue;
+ }
+ Add_Mapping(p->atom, p->format, p->dformat);
+ }
+}
+
+char *GetAtomName(atom)
+ Atom atom;
+{
+ int n;
+ propertyRec *p;
+
+ if (XpropMode == XpropWindowProperties) {
+ n = sizeof(windowPropTable) / sizeof(propertyRec);
+ p = windowPropTable;
+ } else {
+ n = sizeof (fontPropTable) / sizeof (propertyRec);
+ p = fontPropTable;
+ }
+ for ( ; --n >= 0; p++)
+ if (p->atom == atom)
+ return p->name;
+
+ return (char *) NULL;
+}
+
+/*
+ * Read_Mapping: routine to read in additional mappings from a stream
+ * already open for reading.
+ */
+
+Read_Mappings(stream)
+ FILE *stream;
+{
+ char format_buffer[100];
+ char name[1000], *dformat, *format;
+ int count, c;
+ Atom atom, Parse_Atom();
+
+ while ((count=fscanf(stream," %990s %90s ",name,format_buffer))!=EOF) {
+ if (count != 2)
+ Fatal_Error("Bad format file format.");
+
+ atom = Parse_Atom(name, False);
+ format = Copy_String(format_buffer);
+
+ Read_White_Space(stream);
+ dformat = D_DFORMAT;
+ c = getc(stream);
+ ungetc(c, stream);
+ if (c==(int)'\'')
+ dformat = Read_Quoted(stream);
+
+ Add_Mapping(atom, format, dformat);
+ }
+}
+
+/*
+ *
+ * Formatting Routines: a group of routines to translate from various
+ * values to a static read-only string useful for output.
+ *
+ * Routines: Format_Hex, Format_Unsigned, Format_Signed, Format_Atom,
+ * Format_Mask_Word, Format_Bool, Format_String, Format_Len_String.
+ *
+ * All of the above routines take a long except for Format_String and
+ * Format_Len_String.
+ *
+ */
+static char _formatting_buffer[MAXSTR+100];
+static char _formatting_buffer2[10];
+
+char *Format_Hex(wrd)
+ long wrd;
+{
+ sprintf(_formatting_buffer2, "0x%lx", wrd);
+ return(_formatting_buffer2);
+}
+
+char *Format_Unsigned(wrd)
+ long wrd;
+{
+ sprintf(_formatting_buffer2, "%lu", wrd);
+ return(_formatting_buffer2);
+}
+
+char *Format_Signed(wrd)
+ long wrd;
+{
+ sprintf(_formatting_buffer2, "%ld", wrd);
+ return(_formatting_buffer2);
+}
+
+/*ARGSUSED*/
+int ignore_errors (dpy, ev)
+ Display *dpy;
+ XErrorEvent *ev;
+{
+ return 0;
+}
+
+char *Format_Atom(atom)
+ Atom atom;
+{
+ char *name;
+ int (*handler)();
+
+ if ((name = GetAtomName(atom))) {
+ strncpy(_formatting_buffer, name, MAXSTR);
+ return(_formatting_buffer);
+ }
+
+ handler = XSetErrorHandler (ignore_errors);
+ name=XGetAtomName(dpy, atom);
+ XSetErrorHandler(handler);
+ if (! name)
+ sprintf(_formatting_buffer, "undefined atom # 0x%lx", atom);
+ else {
+ strncpy(_formatting_buffer, name, MAXSTR);
+ XFree(name);
+ }
+ return(_formatting_buffer);
+}
+
+char *Format_Mask_Word(wrd)
+ long wrd;
+{
+ long bit_mask, bit;
+ int seen = 0;
+
+ strcpy(_formatting_buffer, "{MASK: ");
+ for (bit=0, bit_mask=1; bit<=sizeof(long)*8; bit++, bit_mask<<=1) {
+ if (bit_mask & wrd) {
+ if (seen) {
+ strcat(_formatting_buffer, ", ");
+ }
+ seen=1;
+ strcat(_formatting_buffer, Format_Unsigned(bit));
+ }
+ }
+ strcat(_formatting_buffer, "}");
+
+ return(_formatting_buffer);
+}
+
+char *Format_Bool(value)
+ long value;
+{
+ if (!value)
+ return("False");
+
+ return("True");
+}
+
+static char *_buf_ptr;
+static int _buf_len;
+
+_put_char(c)
+ char c;
+{
+ if (--_buf_len<0) {
+ _buf_ptr[0]='\0';
+ return;
+ }
+ _buf_ptr++[0] = c;
+}
+
+_format_char(c)
+ char c;
+{
+ switch (c) {
+ case '\\':
+ case '\"':
+ _put_char('\\');
+ _put_char(c);
+ break;
+ case '\n':
+ _put_char('\\');
+ _put_char('n');
+ break;
+ case '\t':
+ _put_char('\\');
+ _put_char('t');
+ break;
+ default:
+ if (!isprint (c)) {
+ _put_char('\\');
+ sprintf(_buf_ptr, "%o", (int) c);
+ _buf_ptr += strlen(_buf_ptr);
+ _buf_len -= strlen(_buf_ptr);
+ } else
+ _put_char(c);
+ }
+}
+
+char *Format_String(string)
+ char *string;
+{
+ char c;
+
+ _buf_ptr = _formatting_buffer;
+ _buf_len = MAXSTR;
+ _put_char('\"');
+
+ while ((c = string++[0]))
+ _format_char(c);
+
+ _buf_len += 3;
+ _put_char('\"');
+ _put_char('\0');
+ return(_formatting_buffer);
+}
+
+char *Format_Len_String(string, len)
+ char *string;
+ int len;
+{
+ char *data, *result;
+
+ data = (char *) Malloc(len+1);
+
+ memmove( data, string, len);
+ data[len]='\0';
+
+ result = Format_String(data);
+ free(data);
+
+ return(result);
+}
+
+/*
+ *
+ * Parsing Routines: a group of routines to parse strings into values
+ *
+ * Routines: Parse_Atom, Scan_Long, Skip_Past_Right_Paran, Scan_Octal
+ *
+ * Routines of the form Parse_XXX take a string which is parsed to a value.
+ * Routines of the form Scan_XXX take a string, parse the beginning to a value,
+ * and return the rest of the string. The value is returned via. the last
+ * parameter. All numeric values are longs!
+ *
+ */
+
+char *Skip_Digits(string)
+ char *string;
+{
+ while (isdigit(string[0])) string++;
+ return(string);
+}
+
+char *Scan_Long(string, value)
+ char *string;
+ long *value;
+{
+ if (!isdigit(*string))
+ Fatal_Error("Bad number: %s.", string);
+
+ *value = atol(string);
+ return(Skip_Digits(string));
+}
+
+char *Scan_Octal(string, value)
+ char *string;
+ long *value;
+{
+ if (sscanf(string, "%lo", value)!=1)
+ Fatal_Error("Bad octal number: %s.", string);
+ return(Skip_Digits(string));
+}
+
+Atom Parse_Atom(name, only_if_exists)
+ char *name;
+ int only_if_exists;
+{
+ Atom atom;
+
+ if ((atom = XInternAtom(dpy, name, only_if_exists))==None)
+ return(0);
+
+ return(atom);
+}
+
+char *Skip_Past_Right_Paran(string)
+ char *string;
+{
+ char c;
+ int nesting=0;
+
+ while (c=string++[0], c!=')' || nesting)
+ switch (c) {
+ case '\0':
+ Fatal_Error("Missing ')'.");
+ case '(':
+ nesting++;
+ break;
+ case ')':
+ nesting--;
+ break;
+ case '\\':
+ string++;
+ break;
+ }
+ return(string);
+}
+
+/*
+ *
+ * The Format Manager: a group of routines to manage "formats"
+ *
+ */
+
+int Is_A_Format(string)
+char *string;
+{
+ return(isdigit(string[0]));
+}
+
+int Get_Format_Size(format)
+ char *format;
+{
+ long size;
+
+ Scan_Long(format, &size);
+
+ /* Check for legal sizes */
+ if (size != 0 && size != 8 && size != 16 && size != 32)
+ Fatal_Error("bad format: %s", format);
+
+ return((int) size);
+}
+
+char Get_Format_Char(format, i)
+ char *format;
+ int i;
+{
+ long size;
+
+ /* Remove # at front of format */
+ format = Scan_Long(format, &size);
+ if (!*format)
+ Fatal_Error("bad format: %s", format);
+
+ /* Last character repeats forever... */
+ if (i >= (int)strlen(format))
+ i=strlen(format)-1;
+
+ return(format[i]);
+}
+
+char *Format_Thunk(t, format_char)
+ thunk t;
+ char format_char;
+{
+ long value;
+ value = t.value;
+
+ switch (format_char) {
+ case 's':
+ return(Format_Len_String(t.extra_value, (int)t.value));
+ case 'x':
+ return(Format_Hex(value));
+ case 'c':
+ return(Format_Unsigned(value));
+ case 'i':
+ return(Format_Signed(value));
+ case 'b':
+ return(Format_Bool(value));
+ case 'm':
+ return(Format_Mask_Word(value));
+ case 'a':
+ return(Format_Atom(value));
+ default:
+ Fatal_Error("bad format character: %c", format_char);
+ }
+}
+
+char *Format_Thunk_I(thunks, format, i)
+ thunk *thunks;
+ char *format;
+ int i;
+{
+ if (i >= thunks->thunk_count)
+ return("<field not available>");
+
+ return(Format_Thunk(thunks[i], Get_Format_Char(format, i)));
+}
+
+long Mask_Word(thunks, format)
+ thunk *thunks;
+ char *format;
+{
+ int j;
+
+ for (j=0; j<(int)strlen(format); j++)
+ if (Get_Format_Char(format, j) == 'm')
+ return(thunks[j].value);
+ return(0L);
+}
+
+/*
+ *
+ * The Display Format Manager:
+ *
+ */
+
+int Is_A_DFormat(string)
+ char *string;
+{
+ return( string[0] && string[0] != '-' &&
+ !(isalpha(string[0]) || string[0] == '_') );
+}
+
+char *Handle_Backslash(dformat)
+ char *dformat;
+{
+ char c;
+ long i;
+
+ if (!(c = *(dformat++)))
+ return(dformat);
+
+ switch (c) {
+ case 'n':
+ putchar('\n');
+ break;
+ case 't':
+ putchar('\t');
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ dformat = Scan_Octal(dformat, &i);
+ putchar((int) i);
+ break;
+ default:
+ putchar(c);
+ break;
+ }
+ return(dformat);
+}
+
+char *Handle_Dollar_sign(dformat, thunks, format)
+ char *dformat;
+ thunk *thunks;
+ char *format;
+{
+ long i;
+
+ dformat = Scan_Long(dformat, &i);
+
+ if (dformat[0]=='+') {
+ int seen=0;
+ dformat++;
+ for (; i<thunks->thunk_count; i++) {
+ if (seen)
+ printf(", ");
+ seen = 1;
+ printf("%s", Format_Thunk_I(thunks, format, (int) i));
+ }
+ } else
+ printf("%s", Format_Thunk_I(thunks, format, (int) i));
+
+ return(dformat);
+}
+
+int Mask_Bit_I(thunks, format, i)
+ thunk *thunks;
+ char *format;
+ int i;
+{
+ long value;
+
+ value = Mask_Word(thunks, format);
+
+ value = value & (1L<<i);
+ if (value)
+ value=1;
+ return(value);
+}
+
+char *Scan_Term(string, thunks, format, value)
+ thunk *thunks;
+ char *string, *format;
+ long *value;
+{
+ long i;
+
+ *value=0;
+
+ if (isdigit(*string))
+ string = Scan_Long(string, value);
+ else if (*string=='$') {
+ string = Scan_Long(++string, &i);
+ if (i>=thunks->thunk_count)
+ i=thunks->thunk_count;
+ *value = thunks[i].value;
+ } else if (*string=='m') {
+ string = Scan_Long(++string, &i);
+ *value = Mask_Bit_I(thunks, format, (int) i);
+ } else
+ Fatal_Error("Bad term: %s.", string);
+
+ return(string);
+}
+
+char *Scan_Exp(string, thunks, format, value)
+ thunk *thunks;
+ char *string, *format;
+ long *value;
+{
+ long temp;
+
+ if (string[0]=='(') {
+ string = Scan_Exp(++string, thunks, format, value);
+ if (string[0]!=')')
+ Fatal_Error("Missing ')'");
+ return(++string);
+ }
+ if (string[0]=='!') {
+ string = Scan_Exp(++string, thunks, format, value);
+ *value = !*value;
+ return(string);
+ }
+
+ string = Scan_Term(string, thunks, format, value);
+
+ if (string[0]=='=') {
+ string = Scan_Exp(++string, thunks, format, &temp);
+ *value = *value == temp;
+ }
+
+ return(string);
+}
+
+char *Handle_Question_Mark(dformat, thunks, format)
+ thunk *thunks;
+ char *dformat, *format;
+{
+ long true;
+
+ dformat = Scan_Exp(dformat, thunks, format, &true);
+
+ if (*dformat!='(')
+ Fatal_Error("Bad conditional: '(' expected: %s.", dformat);
+ ++dformat;
+
+ if (!true)
+ dformat = Skip_Past_Right_Paran(dformat);
+
+ return(dformat);
+}
+
+Display_Property(thunks, dformat, format)
+ thunk *thunks;
+ char *dformat, *format;
+{
+ char c;
+
+ while ((c = *(dformat++)))
+ switch (c) {
+ case ')':
+ continue;
+ case '\\':
+ dformat = Handle_Backslash(dformat);
+ continue;
+ case '$':
+ dformat = Handle_Dollar_sign(dformat, thunks, format);
+ continue;
+ case '?':
+ dformat = Handle_Question_Mark(dformat, thunks, format);
+ continue;
+ default:
+ putchar(c);
+ continue;
+ }
+}
+
+/*
+ *
+ * Routines to convert property data to and from thunks
+ *
+ */
+
+long Extract_Value(pointer, length, size, signedp)
+ char **pointer;
+ int *length;
+ int size;
+{
+ long value, mask;
+
+ switch (size) {
+ case 8:
+ value = (long) * (char *) *pointer;
+ *pointer += 1;
+ *length -= 1;
+ mask = 0xff;
+ break;
+ case 16:
+ value = (long) * (short *) *pointer;
+ *pointer += sizeof(short);
+ *length -= sizeof(short);
+ mask = 0xffff;
+ break;
+ default:
+ /* Error */
+ case 32:
+ value = (long) * (long *) *pointer;
+ *pointer += sizeof(long);
+ *length -= sizeof(long);
+ mask = 0xffffffff;
+ break;
+ }
+ if (!signedp)
+ value &= mask;
+ return(value);
+}
+
+long Extract_Len_String(pointer, length, size, string)
+ char **pointer;
+ int *length;
+ int size;
+ char **string;
+{
+ int len;
+
+ if (size!=8)
+ Fatal_Error("can't use format character 's' with any size except 8.");
+ len=0; *string = *pointer;
+ while ((len++, --*length, *((*pointer)++)) && *length>0);
+
+ return(len);
+}
+
+thunk *Break_Down_Property(pointer, length, format, size)
+ char *pointer, *format;
+ int length, size;
+{
+ thunk *thunks;
+ thunk t;
+ int i;
+ char format_char;
+
+ thunks = Create_Thunk_List();
+ i=0;
+
+ while (length>=(size/8)) {
+ format_char = Get_Format_Char(format, i);
+ if (format_char=='s')
+ t.value=Extract_Len_String(&pointer,&length,size,&t.extra_value);
+ else
+ t.value=Extract_Value(&pointer,&length,size,format_char=='i');
+ thunks = Add_Thunk(thunks, t);
+ i++;
+ }
+
+ return(thunks);
+}
+
+/*
+ *
+ * Routines for parsing command line:
+ *
+ */
+
+usage()
+{
+ char **cpp;
+ static char *help_message[] = {
+"where options include:",
+" -grammar print out full grammar for command line",
+" -display host:dpy the X server to contact",
+" -id id resource id of window to examine",
+" -name name name of window to examine",
+" -font name name of font to examine",
+" -remove propname name of property to remove",
+" -root examine the root window",
+" -len n display at most n bytes of any property",
+" -notype do not display the type field",
+" -fs filename where to look for formats for properties",
+" -frame don't ignore window manager frames",
+" -f propname format [dformat] formats to use for property of given name",
+" -spy examine window properties forever",
+NULL};
+
+ fflush (stdout);
+ fprintf (stderr, "usage: %s [-options ...] [[format [dformat]] atom]\n\n",
+ program_name);
+ for (cpp = help_message; *cpp; cpp++) {
+ fprintf (stderr, "%s\n", *cpp);
+ }
+ fprintf (stderr, "\n");
+ exit (1);
+}
+
+grammar ()
+{
+ printf ("Grammar for xprop:\n\n");
+ printf("\t%s [<disp>] [<select option>] <option>* <mapping>* <spec>*",
+ program_name);
+ printf("\n\n\tdisp ::= -display host:dpy\
+\n\tselect option ::= -root | -id <id> | -font <font> | -name <name>\
+\n\toption ::= -len <n> | -notype | -spy | {-formats|-fs} <format file>\
+\n\tmapping ::= {-f|-format} <atom> <format> [<dformat>] | -remove <propname>\
+\n\tspec ::= [<format> [<dformat>]] <atom>\
+\n\tformat ::= {0|8|16|32}{a|b|c|i|m|s|x}*\
+\n\tdformat ::= <unit><unit>* (can't start with a letter or '-')\
+\n\tunit ::= ?<exp>(<unit>*) | $<n> | <display char>\
+\n\texp ::= <term> | <term>=<exp> | !<exp>\
+\n\tterm ::= <n> | $<n> | m<n>\
+\n\tdisplay char ::= <normal char> | \\<non digit char> | \\<octal number>\
+\n\tnormal char ::= <any char except a digit, $, ?, \\, or )>\
+\n\n");
+ exit(0);
+}
+
+Parse_Format_Mapping(argc, argv)
+ int *argc;
+ char ***argv;
+#define ARGC (*argc)
+#define ARGV (*argv)
+#define OPTION ARGV[0]
+#define NXTOPT if (++ARGV, --ARGC==0) usage()
+{
+ char *type_name, *format, *dformat;
+
+ NXTOPT; type_name = OPTION;
+
+ NXTOPT; format = OPTION;
+ if (!Is_A_Format(format))
+ Fatal_Error("Bad format: %s.", format);
+
+ dformat=0;
+ if (ARGC>0 && Is_A_DFormat(ARGV[1])) {
+ ARGV++; ARGC--; dformat=OPTION;
+ }
+
+ Add_Mapping( Parse_Atom(type_name, False), format, dformat);
+}
+
+/*
+ *
+ * The Main Program:
+ *
+ */
+
+Window target_win=0;
+int notype=0;
+int spy=0;
+int max_len=MAXSTR;
+XFontStruct *font;
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+ FILE *stream;
+ char *name;
+ thunk *props, *Handle_Prop_Requests();
+ char *remove_propname = NULL;
+ Bool frame_only = False;
+ int n;
+ char **nargv;
+
+ INIT_NAME;
+
+ /* Handle display name, opening the display */
+ Setup_Display_And_Screen(&argc, argv);
+
+ /* Handle selecting the window to display properties for */
+ target_win = Select_Window_Args(&argc, argv);
+
+ /* Set up default atom to format, dformat mapping */
+ XpropMode = XpropWindowProperties;
+ for (n=argc, nargv=argv; n; nargv++, n--)
+ if (! strcmp(nargv[0], "-font")) {
+ XpropMode = XpropFontProperties;
+ break;
+ }
+ Setup_Mapping();
+ if ((name = getenv("XPROPFORMATS"))) {
+ if (!(stream=fopen(name, "r")))
+ Fatal_Error("unable to open file %s for reading.", name);
+ Read_Mappings(stream);
+ fclose(stream);
+ }
+
+ /* Handle '-' options to setup xprop, select window to work on */
+ while (argv++, --argc>0 && **argv=='-') {
+ if (!strcmp(argv[0], "-"))
+ continue;
+ if (!strcmp(argv[0], "-grammar")) {
+ grammar ();
+ /* NOTREACHED */
+ }
+ if (!strcmp(argv[0], "-notype")) {
+ notype=1;
+ continue;
+ }
+ if (!strcmp(argv[0], "-spy")) {
+ spy=1;
+ continue;
+ }
+ if (!strcmp(argv[0], "-len")) {
+ if (++argv, --argc==0) usage();
+ max_len = atoi(argv[0]);
+ continue;
+ }
+ if (!strcmp(argv[0], "-formats") || !strcmp(argv[0], "-fs")) {
+ if (++argv, --argc==0) usage();
+ if (!(stream=fopen(argv[0], "r")))
+ Fatal_Error("unable to open file %s for reading.", argv[0]);
+ Read_Mappings(stream);
+ fclose(stream);
+ continue;
+ }
+ if (!strcmp(argv[0], "-font")) {
+ if (++argv, --argc==0) usage();
+ font = Open_Font(argv[0]);
+ target_win = -1;
+ continue;
+ }
+ if (!strcmp(argv[0], "-remove")) {
+ if (++argv, --argc==0) usage();
+ remove_propname = argv[0];
+ continue;
+ }
+ if (!strcmp(argv[0], "-frame")) {
+ frame_only = True;
+ continue;
+ }
+ if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "-format")) {
+ Parse_Format_Mapping(&argc, &argv);
+ continue;
+ }
+ usage();
+ }
+
+ if (target_win == None) {
+ target_win = Select_Window(dpy);
+ if (target_win != None && !frame_only) {
+ Window root;
+ int dummyi;
+ unsigned int dummy;
+
+ if (XGetGeometry (dpy, target_win, &root, &dummyi, &dummyi,
+ &dummy, &dummy, &dummy, &dummy) &&
+ target_win != root)
+ target_win = XmuClientWindow (dpy, target_win);
+ }
+ }
+
+ if (remove_propname) {
+ remove_property (dpy, target_win, remove_propname);
+ XCloseDisplay (dpy);
+ exit (0);
+ }
+
+ props=Handle_Prop_Requests(argc, argv);
+
+ if (spy && target_win != -1) {
+ XEvent event;
+ char *format, *dformat;
+
+ XSelectInput(dpy, target_win, PropertyChangeMask);
+ for (;;) {
+ XNextEvent(dpy, &event);
+ format = dformat = NULL;
+ if (props) {
+ int i;
+ for (i=0; i<props->thunk_count; i++)
+ if (props[i].value == event.xproperty.atom)
+ break;
+ if (i>=props->thunk_count)
+ continue;
+ format = props[i].format;
+ dformat = props[i].dformat;
+ }
+ Show_Prop(format, dformat, Format_Atom(event.xproperty.atom));
+ }
+ }
+ exit (0);
+}
+
+/*
+ *
+ * Other Stuff (temp.):
+ *
+ */
+
+remove_property (dpy, w, propname)
+ Display *dpy;
+ Window w;
+ char *propname;
+{
+ Atom id = XInternAtom (dpy, propname, True);
+
+ if (id == None) {
+ fprintf (stderr, "%s: no such property \"%s\"\n",
+ program_name, propname);
+ return;
+ }
+ XDeleteProperty (dpy, w, id);
+ return;
+}
+
+thunk *Handle_Prop_Requests(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *format, *dformat, *prop;
+ thunk *thunks, t;
+
+ thunks = Create_Thunk_List();
+
+ /* if no prop referenced, by default list all properties for given window */
+ if (!argc) {
+ Show_All_Props();
+ return(NULL);
+ }
+
+ while (argc>0) {
+ format = 0;
+ dformat = 0;
+
+ /* Get overriding formats, if any */
+ if (Is_A_Format(argv[0])) {
+ format = argv++[0]; argc--;
+ if (!argc) usage();
+ }
+ if (Is_A_DFormat(argv[0])) {
+ dformat = argv++[0]; argc--;
+ if (!argc) usage();
+ }
+
+ /* Get property name */
+ prop = argv++[0]; argc--;
+
+ t.value = Parse_Atom(prop, True);
+ t.format = format;
+ t.dformat = dformat;
+ if (t.value)
+ thunks = Add_Thunk(thunks, t);
+ Show_Prop(format, dformat, prop);
+ }
+ return(thunks);
+}
+
+Show_All_Props()
+{
+ Atom *atoms, atom;
+ char *name;
+ int count, i;
+
+ if (target_win!=-1) {
+ atoms = XListProperties(dpy, target_win, &count);
+ for (i=0; i<count; i++) {
+ name = Format_Atom(atoms[i]);
+ Show_Prop(0, 0, name);
+ }
+ } else
+ for (i=0; i<font->n_properties; i++) {
+ atom = font->properties[i].name;
+ name = Format_Atom(atom);
+ Show_Prop(0, 0, name);
+ }
+}
+
+Set_Prop(format, dformat, prop, mode, value)
+ char *format, *dformat, *prop, *value;
+ char mode;
+{
+ outl("Seting prop %s(%s) using %s mode %c to %s",
+ prop, format, dformat, mode, value);
+}
+
+static unsigned long _font_prop;
+
+char *Get_Font_Property_Data_And_Type(atom, length, type, size)
+ Atom atom;
+ long *length;
+ Atom *type;
+ int *size;
+{
+ int i;
+
+ *type = 0;
+
+ for (i=0; i<font->n_properties; i++)
+ if (atom==font->properties[i].name) {
+ _font_prop=font->properties[i].card32;
+ *length=sizeof(long);
+ *size=32;
+ return((char *) &_font_prop);
+ }
+ return(0);
+}
+
+char *Get_Window_Property_Data_And_Type(atom, length, type, size)
+ Atom atom;
+ long *length;
+ Atom *type;
+ int *size;
+{
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems;
+ unsigned long nbytes;
+ unsigned long bytes_after;
+ unsigned char *prop;
+ int status;
+
+ status = XGetWindowProperty(dpy, target_win, atom, 0, (max_len+3)/4,
+ False, AnyPropertyType, &actual_type,
+ &actual_format, &nitems, &bytes_after,
+ &prop);
+ if (status==BadWindow)
+ Fatal_Error("window id # 0x%lx does not exists!", target_win);
+ if (status!=Success)
+ Fatal_Error("XGetWindowProperty failed!");
+
+ if (actual_format == 32)
+ nbytes = sizeof(long);
+ else if (actual_format == 16)
+ nbytes = sizeof(short);
+ else
+ nbytes = 1;
+ *length = min(nitems * nbytes, max_len);
+ *type = actual_type;
+ *size = actual_format;
+ return((char *)prop);
+}
+
+char *Get_Property_Data_And_Type(atom, length, type, size)
+ Atom atom;
+ long *length;
+ Atom *type;
+ int *size;
+{
+ if (target_win == -1)
+ return(Get_Font_Property_Data_And_Type(atom, length, type, size));
+ else
+ return(Get_Window_Property_Data_And_Type(atom, length, type, size));
+}
+
+Show_Prop(format, dformat, prop)
+ char *format, *dformat, *prop;
+{
+ char *data;
+ long length;
+ Atom atom, type;
+ thunk *thunks;
+ int size, fsize;
+
+ printf("%s", prop);
+ if (!(atom = Parse_Atom(prop, True))) {
+ printf(": no such atom on any window.\n");
+ return;
+ }
+
+ data = Get_Property_Data_And_Type(atom, &length, &type, &size);
+ if (!size) {
+ puts(": not found.");
+ return;
+ }
+
+ if (!notype && type)
+ printf("(%s)", Format_Atom(type));
+
+ Lookup_Formats(atom, &format, &dformat);
+ if (type)
+ Lookup_Formats(type, &format, &dformat);
+ Apply_Default_Formats(&format, &dformat);
+
+ fsize=Get_Format_Size(format);
+ if (fsize!=size && fsize!=0) {
+ printf(": Type mismatch: assumed size %d bits, actual size %d bits.\n",
+ fsize, size);
+ return;
+ }
+
+ thunks = Break_Down_Property(data, (int)length, format, size);
+
+ Display_Property(thunks, dformat, format);
+}
diff --git a/xprop.man b/xprop.man
new file mode 100644
index 0000000..0de6e25
--- /dev/null
+++ b/xprop.man
@@ -0,0 +1,327 @@
+.\" $Xorg: xprop.man,v 1.4 2001/02/09 02:05:56 xorgcvs Exp $
+.\" Copyright 1988, 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.
+.TH XPROP 1 "Release 6.4" "X Version 11"
+.SH NAME
+xprop - property displayer for X
+.SH SYNOPSIS
+.B "xprop"
+[-help] [-grammar] [-id \fIid\fP] [-root] [-name \fIname\fP]
+[-frame]
+[-font \fIfont\fP]
+[-display \fIdisplay\fP]
+[-len \fIn\fP] [-notype] [-fs \fIfile\fP]
+[-remove \fIproperty-name\fP]
+[-spy]
+[-f \fIatom\fP \fIformat\fP [\fIdformat\fP]]*
+[\fIformat\fP [\fIdformat\fP] \fIatom\fP]*
+.SH SUMMARY
+.PP
+The
+.I xprop
+utility is for displaying window and font properties in an X server.
+One window or font is selected using the command
+line arguments or possibly in the case of a window, by clicking on the desired
+window. A list of properties is then given, possibly with formatting
+information.
+.SH OPTIONS
+.PP
+.TP 8
+.B "-help"
+Print out a summary of command line options.
+.PP
+.TP 8
+.B "-grammar"
+Print out a detailed grammar for all command line options.
+.PP
+.TP 8
+.B "-id \fIid\fP"
+This argument allows the user to select window \fIid\fP on the
+command line rather than using the pointer to select the target window.
+This is very useful in debugging X applications where the target
+window is not mapped to the screen or where the use of the pointer might
+be impossible or interfere with the application.
+.PP
+.TP 8
+.B "-name \fIname\fP"
+This argument allows the user to specify that the window named \fIname\fP
+is the target window on the command line rather than using the pointer to
+select the target window.
+.PP
+.TP 8
+.B "-font \fIfont\fP"
+This argument allows the user to specify that the properties of font
+\fIfont\fP should be displayed.
+.PP
+.TP 8
+.B "-root"
+This argument specifies that X's root window is the target window.
+This is useful in situations where the root window is completely
+obscured.
+.PP
+.TP 8
+.B "-display \fIdisplay\fP"
+This argument allows you to specify the server to connect to;
+see \fIX(1)\fP.
+.PP
+.TP 8
+.B "-len \fIn\fP"
+Specifies that at most \fIn\fP bytes of any property should be read or
+displayed.
+.PP
+.TP 8
+.B "-notype"
+Specifies that the type of each property should not be displayed.
+.PP
+.TP 8
+.B "-fs \fIfile\fP"
+Specifies that file \fIfile\fP should be used as a source of more formats
+for properties.
+.PP
+.TP 8
+.B "-frame"
+Specifies that when selecting a window by hand (i.e. if none of \fB-name\fP,
+\fB-root\fP, or \fB-id\fP are given), look at the window manager frame (if
+any) instead of looking for the client window.
+.PP
+.TP 8
+.B "-remove \fIproperty-name\fP"
+Specifies the name of a property to be removed from the indicated window.
+.PP
+.TP 8
+.B "-spy"
+Examine window properties forever, looking for property change events.
+.PP
+.TP 8
+.B "-f \fIname\fP \fIformat\fP [\fIdformat\fP]"
+Specifies that the \fIformat\fP for \fIname\fP should be \fIformat\fP and that
+the \fIdformat\fP for \fIname\fP should be \fIdformat\fP. If \fIdformat\fP
+is missing, " = $0+\\n" is assumed.
+.SH DESCRIPTION
+.PP
+For each of these properties, its value on the selected window
+or font is printed using the supplied formatting information if any. If no
+formatting information is supplied, internal defaults are used. If a property
+is not defined on the selected window or font, "not defined" is printed as the
+value for that property. If no property list is given, all the properties
+possessed by the selected window or font are printed.
+.PP
+A window may be selected in one of four ways. First, if the desired window
+is the root window, the -root argument may be used.
+If the desired window is not the root window, it may be selected
+in two ways on the command line, either by id number such as might be obtained
+from \fIxwininfo\fP, or by name if the window possesses a name. The -id
+argument selects a window by id number in either decimal or hex (must start
+with 0x) while the -name argument selects a window by name.
+.PP
+The last way to select a window does not involve the command line at all.
+If none of -font, -id, -name, and -root are specified, a crosshairs cursor
+is displayed and the user is allowed to choose any visible window by pressing
+any pointer button in the desired window. If it is desired to display properties
+of a font as opposed to a window, the -font argument must be used.
+.PP
+Other than the above four arguments and the -help argument for obtaining help,
+and the -grammar argument for listing the full grammar for the command line,
+all the other command line arguments are used in specifying both the format
+of the properties to be displayed and how to display them. The -len \fIn\fP
+argument specifies that at most \fIn\fP bytes of any given property will be
+read and displayed. This is useful for example when displaying the cut buffer
+on the root window which could run to several pages if displayed in full.
+.PP
+Normally each property name is displayed by printing first the property
+name then its type (if it has one) in parentheses followed by its value.
+The -notype argument specifies that property types should not be
+displayed. The -fs argument is used to specify a file containing a list of
+formats for properties while the -f argument is used to specify the format
+for one property.
+.PP
+The formatting information for a property actually consists of two parts,
+a \fIformat\fP and a \fIdformat\fP. The \fIformat\fP specifies the actual
+formatting of the property (i.e., is it made up of words, bytes, or longs?,
+etc.) while the \fIdformat\fP specifies how the property should be displayed.
+.PP
+The following paragraphs describe how to construct \fIformat\fPs and
+\fIdformat\fPs. However, for the vast majority of users and uses, this should
+not be necessary as the built in defaults contain the \fIformat\fPs and
+\fIdformat\fPs necessary to display all the standard properties. It should
+only be necessary to specify \fIformat\fPs and \fIdformat\fPs
+if a new property is being dealt with or the user dislikes the standard display
+format. New users especially are encouraged to skip this part.
+.PP
+A \fIformat\fP consists of one of 0, 8, 16, or 32 followed by a sequence of one
+or more format characters. The 0, 8, 16, or 32 specifies how many bits per
+field there are in the property. Zero is a special case meaning use the
+field size information associated with the property itself. (This is only
+needed for special cases like type INTEGER which is actually three different
+types depending on the size of the fields of the property)
+.PP
+A value of 8 means
+that the property is a sequence of bytes while a value of 16 would mean that
+the property is a sequence of words. The difference between these two lies in
+the fact that the sequence of words will be byte swapped while the sequence of
+bytes will not be when read by a machine of the opposite byte order of the
+machine that originally wrote the property. For more information on how
+properties are formatted and stored, consult the Xlib manual.
+.PP
+Once the size of the fields has been specified, it is necessary to specify
+the type of each field (i.e., is it an integer, a string, an atom, or what?)
+This is done using one format character per field. If there are more fields
+in the property than format characters supplied, the last character will be
+repeated as many times as necessary for the extra fields. The format
+characters and their meaning are as follows:
+.TP
+a
+The field holds an atom number. A field of this type should be of size 32.
+.TP
+b
+The field is an boolean. A 0 means false while anything else means true.
+.TP
+c
+The field is an unsigned number, a cardinal.
+.TP
+i
+The field is a signed integer.
+.TP
+m
+The field is a set of bit flags, 1 meaning on.
+.TP
+s
+This field and the next ones until either a 0 or the end of the property
+represent a sequence of bytes. This format character is only usable with
+a field size of 8 and is most often used to represent a string.
+.TP
+x
+The field is a hex number (like 'c' but displayed in hex - most useful
+for displaying window ids and the like)
+.PP
+An example \fIformat\fP is 32ica which is the format for a property of three
+fields of 32 bits each, the first holding a signed integer, the second an
+unsigned integer, and the third an atom.
+.PP
+The format of a \fIdformat\fP unlike that of a \fIformat\fP is not so rigid.
+The only limitations on a \fIdformat\fP is that one may not start with a letter
+or a dash. This is so that it can be distinguished from a property name or
+an argument. A \fIdformat\fP is a text string containing special characters
+instructing that various fields be printed at various points in a manner similar
+to the formatting string used by printf. For example, the \fIdformat\fP
+" is ( $0, $1 \\)\\n" would render the POINT 3, -4 which has a \fIformat\fP of
+32ii as " is ( 3, -4 )\\n".
+.PP
+Any character other than a $, ?, \\, or a ( in a \fIdformat\fP prints as
+itself. To print out one of $, ?, \\, or ( precede it by a \\. For example,
+to print out a $, use \\$. Several special backslash sequences are provided
+as shortcuts. \\n will cause a newline to be displayed while \\t will
+cause a tab to be displayed. \\\fIo\fP where \fIo\fP is an octal number
+will display character number \fIo\fP.
+.PP
+A $ followed by a number \fIn\fP causes field number \fIn\fP to be
+displayed. The format of the displayed field depends on the formatting
+character used to describe it in the corresponding \fIformat\fP. I.e., if
+a cardinal is described by 'c' it will print in decimal while if it is
+described by a 'x' it is displayed in hex.
+.PP
+If the field is not present in
+the property (this is possible with some properties), <field not available>
+is displayed instead. $\fIn\fP+ will display field number \fIn\fP then a
+comma then field number \fIn\fP+1 then another comma then ... until the last
+field defined. If field \fIn\fP is not defined, nothing is displayed.
+This is useful for a property that is a list of values.
+.PP
+A ? is used to start a conditional expression, a kind of if-then statement.
+?\fIexp\fP(\fItext\fP) will display \fItext\fP if and only if \fIexp\fP evaluates to
+non-zero. This is useful for two things. First, it allows fields to be
+displayed if and only if a flag is set.
+And second, it allows a value such as a state
+number to be displayed as a name rather than as just a number. The syntax of
+\fIexp\fP is as follows:
+.TP
+\fIexp\fP
+::= \fIterm\fP | \fIterm\fP=\fIexp\fP | !\fIexp\fP
+.TP
+\fIterm\fP
+::= \fIn\fP | $\fIn\fP | m\fIn\fP
+.PP
+The ! operator is a logical ``not'', changing 0 to 1 and any non-zero value to 0.
+= is an equality operator. Note that internally all expressions are evaluated
+as 32 bit numbers so -1 is not equal to 65535. = returns 1 if the two values
+are equal and 0 if not.
+\fIn\fP represents the constant value \fIn\fP while $\fIn\fP represents the
+value of field number \fIn\fP.
+m\fIn\fP is 1 if flag number \fIn\fP in the first field having format
+character 'm' in the corresponding \fIformat\fP is 1, 0 otherwise.
+.PP
+Examples: ?m3(count: $3\\n) displays field 3 with a label of count if and only if flag
+number 3 (count starts at 0!) is on. ?$2=0(True)?!$2=0(False) displays the
+inverted value of field 2 as a boolean.
+.PP
+In order to display a property, \fIxprop\fP needs both a \fIformat\fP and a
+\fIdformat\fP. Before \fIxprop\fP uses its default values of a \fIformat\fP
+of 32x and a \fIdformat\fP of " = { $0+ }\\n", it searches several places
+in an attempt to find more specific formats.
+First, a search is made using the name of the property. If this
+fails, a search is made using the type of the property. This allows type
+STRING to be defined with one set of formats while allowing property WM_NAME
+which is of type STRING to be defined with a different format. In this way,
+the display formats for a given type can be overridden for specific properties.
+.PP
+The locations searched are in order: the format if any specified with the
+property name (as in 8x WM_NAME), the formats defined by -f options in last to
+first order, the contents of the file specified by the -fs option if any,
+the contents of the file specified by the environmental variable XPROPFORMATS
+if any, and finally \fIxprop\fP's built in file of formats.
+.PP
+The format of the files referred to by the -fs argument and the XPROPFORMATS
+variable is one or more lines of the following form:
+.PP
+\fIname\fP \fIformat\fP [\fIdformat\fP]
+.PP
+Where \fIname\fP is either the name of a property or the name of a type,
+\fIformat\fP is the \fIformat\fP to be used with \fIname\fP and \fIdformat\fP
+is the \fIdformat\fP to be used with \fIname\fP. If \fIdformat\fP is not
+present, " = $0+\\n" is assumed.
+.SH EXAMPLES
+.PP
+To display the name of the root window: \fIxprop\fP -root WM_NAME
+.PP
+To display the window manager hints for the clock: \fIxprop\fP -name xclock
+WM_HINTS
+.PP
+To display the start of the cut buffer: \fIxprop\fP -root -len 100 CUT_BUFFER0
+.PP
+To display the point size of the fixed font: \fIxprop\fP -font fixed POINT_SIZE
+.PP
+To display all the properties of window # 0x200007: \fIxprop\fP -id 0x200007
+.SH ENVIRONMENT
+.PP
+.TP 8
+.B DISPLAY
+To get default display.
+.TP 8
+.B XPROPFORMATS
+Specifies the name of a file from which additional formats are to be obtained.
+.PP
+.SH SEE ALSO
+X(1), xwininfo(1)
+.SH AUTHOR
+Mark Lillibridge, MIT Project Athena