diff options
-rw-r--r-- | dsimple.c | 523 | ||||
-rw-r--r-- | dsimple.h | 81 | ||||
-rw-r--r-- | xprop.c | 1516 | ||||
-rw-r--r-- | xprop.man | 327 |
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(); @@ -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 |