diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 0000000000..616f98f3f7 --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,9 @@ +noinst_PROGRAMS = test_gravity + +INCLUDES = $(all_includes) + +test_gravity_SOURCES = test_gravity.cpp +test_gravity_LDFLAGS = $(all_libraries) $(KDE_RPATH) +test_gravity_LDADD = $(LIB_X11) + +METASOURCES = AUTO diff --git a/tools/test_gravity.cpp b/tools/test_gravity.cpp new file mode 100644 index 0000000000..573721f1d4 --- /dev/null +++ b/tools/test_gravity.cpp @@ -0,0 +1,85 @@ +// tests for window gravity + +#define INITIAL_POSITION_TEST + +#include +#include +#include +#include + +using namespace std; + +const int gravities[ 10 ] = + { + NorthWestGravity, + NorthGravity, + NorthEastGravity, + WestGravity, + CenterGravity, + EastGravity, + SouthWestGravity, + SouthGravity, + SouthEastGravity, + StaticGravity + }; + +const char* const gravity_names[ 10 ] = + { + "NW", "N", "NE", "W", "C", "E", "SW", "S", "SE", "ST" + }; + +Display* dpy = NULL; + +int get_gravity( const char* name ) + { + for( int i = 0; + i < 10; + ++i ) + if( strcmp( name, gravity_names[ i ] ) == 0 ) + return gravities[ i ]; + cerr << "Wrong gravity name" << endl; + exit( 1 ); + } + +void initial_position_test( const char* gravity ) + { + XSetWindowAttributes attrs; + XSizeHints hints; + hints.flags = USPosition | PWinGravity; + hints.win_gravity = get_gravity( gravity ); + Window w = XCreateWindow( dpy, DefaultRootWindow( dpy ), 100, 100, 200, 100, 0, CopyFromParent, CopyFromParent, + CopyFromParent, 0, &attrs ); + XSetWMNormalHints( dpy, w, &hints ); + XSelectInput( dpy, w, StructureNotifyMask ); + XMapWindow( dpy, w ); + for(;;) + { + XEvent ev; + XNextEvent( dpy, &ev ); + if( ev.type == ConfigureNotify ) + { + cout << "CONFIGURENOTIFY:" << ev.xany.send_event << ":" << ev.xconfigure.x << ":" << ev.xconfigure.y + << ":" << ev.xconfigure.width << ":" << ev.xconfigure.height << endl; + Window root, child; + int x, x_local, y, y_local; + unsigned int width, height, border, depth; + XGetGeometry( dpy, w, &root, &x_local, &y_local, &width, &height, &border, &depth ); + XTranslateCoordinates( dpy, w, root, 0, 0, &x, &y, &child ); + cout << "GEOMETRY:" << x << ":" << y << ":" << width << ":" << height << ":(" << x_local << ":" << y_local << ")" << endl; + } + } + } + +int main( int argc, char* argv[] ) + { + dpy = XOpenDisplay( NULL ); +#ifdef INITIAL_POSITION_TEST + if( argc != 2 ) + { + cerr << "specify gravity" << endl; + exit( 1 ); + } + initial_position_test( argv[ 1 ] ); +#endif + XCloseDisplay( dpy ); + } diff --git a/tools/xprop/Makefile b/tools/xprop/Makefile new file mode 100644 index 0000000000..08210dfe8f --- /dev/null +++ b/tools/xprop/Makefile @@ -0,0 +1,2 @@ +all: + gcc dsimple.c xprop.c -o xprop -lXmu -lX11 -L/usr/X11R6/lib diff --git a/tools/xprop/README b/tools/xprop/README new file mode 100644 index 0000000000..ad77bd9064 --- /dev/null +++ b/tools/xprop/README @@ -0,0 +1 @@ +patched xprop that shows all WINDOW elements in properties, not just the first one diff --git a/tools/xprop/dsimple.c b/tools/xprop/dsimple.c new file mode 100644 index 0000000000..bbdbd932e3 --- /dev/null +++ b/tools/xprop/dsimple.c @@ -0,0 +1,521 @@ +/* $Xorg: dsimple.c,v 1.4 2001/02/09 02:05:54 xorgcvs Exp $ */ +/* + +Copyright 1993, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +*/ +/* $XFree86: xc/programs/xlsfonts/dsimple.c,v 3.6 2001/12/14 20:02:09 dawes Exp $ */ + +#include +#include +#include +#include +#include +#include +#include +/* + * Other_stuff.h: Definitions of routines in other_stuff. + * + * Written by Mark Lillibridge. Last updated 7/1/87 + */ + +#include "dsimple.h" + +/* + * 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 */ +char *program_name = "unknown_program"; +Display *dpy; +int screen; + +static void _bitmap_error(int, char *); + +/* + * Malloc: like malloc but handles out of memory using Fatal_Error. + */ +char *Malloc(size) + unsigned size; +{ + char *data; + + 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; + + 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 Selects window with id . may + * be either in decimal or hex. + * -name Selects the window with 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 + */ + +/* + * 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() +{ + fflush(stdout); + fprintf(stderr, "blip!\n"); + fflush(stderr); +} + + +/* + * 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 +#include +#include +#include +#include +#include +#include +#ifdef HAS_WCHAR_H +#include +#endif +#ifdef HAS_WCTYPE_H +#include +#endif +#include + +#ifndef HAS_WCTYPE_H +#define iswprint(x) isprint(x) +#endif + +#include +#include + +#include "dsimple.h" + +#define MAXSTR 10000 + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* isprint() in "C" locale */ +#define c_isprint(c) ((c) >= 0x20 && (c) < 0x7f) + +/* + * + * The Thunk Manager - routines to create, add to, and free thunk lists + * + */ + +typedef struct { + int thunk_count; + const char *propname; + long value; + Atom extra_encoding; + const char *extra_value; + const char *format; + const char *dformat; +} thunk; + +static thunk * +Create_Thunk_List (void) +{ + thunk *tptr; + + tptr = (thunk *) Malloc(sizeof(thunk)); + + tptr->thunk_count = 0; + + return tptr; +} + +#ifdef notused +static void +Free_Thunk_List (thunk *list) +{ + free(list); +} +#endif + +static thunk * +Add_Thunk (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 + */ + +static char * +Copy_String (const char *string) +{ + char *new; + int length; + + length = strlen(string) + 1; + + new = (char *) Malloc(length); + memcpy(new, string, length); + + return new; +} + +static int +Read_Char (FILE *stream) +{ + int c; + + c = getc(stream); + if (c == EOF) + Fatal_Error("Bad format file: Unexpected EOF."); + return c; +} + +static void +Read_White_Space (FILE *stream) +{ + int c; + + while ((c = getc(stream)) == ' ' || c == '\n' || c == '\t'); + ungetc(c, stream); +} + +static char _large_buffer[MAXSTR+10]; + +static char * +Read_Quoted (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); +} + +/* + * + * Parsing Routines: a group of routines to parse strings into values + * + * Routines: Parse_Atom, Scan_Long, Skip_Past_Right_Paren, 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! + * + */ + +static const char * +Skip_Digits (const char *string) +{ + while (isdigit((unsigned char) string[0])) string++; + return string; +} + +static const char * +Scan_Long (const char *string, long *value) +{ + if (!isdigit((unsigned char) *string)) + Fatal_Error("Bad number: %s.", string); + + *value = atol(string); + return Skip_Digits(string); +} + +static const char * +Scan_Octal (const char *string, long *value) +{ + if (sscanf(string, "%lo", value)!=1) + Fatal_Error("Bad octal number: %s.", string); + return Skip_Digits(string); +} + +static Atom +Parse_Atom (const char *name, int only_if_exists) +{ + /* may return None = 0 */ + return XInternAtom(dpy, name, only_if_exists); +} + +static const char * +Skip_Past_Right_Paren (const 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; +} + +/* + * + * 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 = NULL; /* Holds mapping */ + +static void +Apply_Default_Formats (const char **format, const char **dformat) +{ + if (!*format) + *format = D_FORMAT; + if (!*dformat) + *dformat = D_DFORMAT; +} + +static void +Lookup_Formats (Atom atom, const char **format, const 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; + } +} + +static void +Add_Mapping (Atom atom, const char *format, const 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 { + const char * name; + Atom atom; + const char * format; + const 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" + +static 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_NAME", XA_WM_ICON_NAME, "8t", 0 }, + {"WM_ICON_SIZE", XA_WM_ICON_SIZE, "32cccccc", WM_ICON_SIZE_DFORMAT}, + {"WM_NAME", XA_WM_NAME, "8t", 0 }, + {"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: + */ +static 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 + +static void +Setup_Mapping (void) +{ + 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); + } +} + +static const char * +GetAtomName (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 NULL; +} + +/* + * Read_Mapping: routine to read in additional mappings from a stream + * already open for reading. + */ + +static void +Read_Mappings (FILE *stream) +{ + char format_buffer[100]; + char name[1000], *dformat, *format; + int count, c; + Atom 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[21]; + +static const char * +Format_Hex (long wrd) +{ + sprintf(_formatting_buffer2, "0x%lx", wrd); + return _formatting_buffer2; +} + +static const char * +Format_Unsigned (long wrd) +{ + sprintf(_formatting_buffer2, "%lu", wrd); + return _formatting_buffer2; +} + +static const char * +Format_Signed (long wrd) +{ + sprintf(_formatting_buffer2, "%ld", wrd); + return _formatting_buffer2; +} + +/*ARGSUSED*/ +static int +ignore_errors (Display *dpy, XErrorEvent *ev) +{ + return 0; +} + +static const char * +Format_Atom (Atom atom) +{ + const char *found; + char *name; + XErrorHandler handler; + + if ((found = GetAtomName(atom)) != NULL) + return found; + + handler = XSetErrorHandler (ignore_errors); + name = XGetAtomName(dpy, atom); + XSetErrorHandler(handler); + if (! name) + sprintf(_formatting_buffer, "undefined atom # 0x%lx", atom); + else { + int namelen = strlen(name); + if (namelen > MAXSTR) namelen = MAXSTR; + memcpy(_formatting_buffer, name, namelen); + _formatting_buffer[namelen] = '\0'; + XFree(name); + } + return _formatting_buffer; +} + +static const char * +Format_Mask_Word (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; +} + +static const char * +Format_Bool (long value) +{ + if (!value) + return "False"; + + return "True"; +} + +static char *_buf_ptr; +static int _buf_len; + +static void +_put_char (char c) +{ + if (--_buf_len < 0) { + _buf_ptr[0] = '\0'; + return; + } + _buf_ptr++[0] = c; +} + +static void +_format_char (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 (!c_isprint(c)) { + _put_char('\\'); + sprintf(_buf_ptr, "%03o", (unsigned char) c); + _buf_ptr += 3; + _buf_len -= 3; + } else + _put_char(c); + } +} + +static const char * +Format_String (const char *string) +{ + char c; + + _buf_ptr = _formatting_buffer; + _buf_len = MAXSTR; + _put_char('\"'); + + while ((c = string++[0])) + _format_char(c); + + *_buf_ptr++ = '"'; + *_buf_ptr++ = '\0'; + return _formatting_buffer; +} + +static const char * +Format_Len_String (const char *string, int len) +{ + char *data; + const char *result; + + data = (char *) Malloc(len+1); + + memcpy(data, string, len); + data[len] = '\0'; + + result = Format_String(data); + free(data); + + return result; +} + +static const char * +Format_Len_Text (const char *string, int len, Atom encoding) +{ + XTextProperty textprop; + char **list; + int count; + + /* Try to convert to local encoding. */ + textprop.encoding = encoding; + textprop.format = 8; + textprop.value = (unsigned char *) string; + textprop.nitems = len; + if (XmbTextPropertyToTextList(dpy, &textprop, &list, &count) == Success) { + _buf_ptr = _formatting_buffer; + _buf_len = MAXSTR; + *_buf_ptr++ = '"'; + while (count > 0) { + string = *list++; + len = strlen(string); + while (len > 0) { + wchar_t wc; + int n = mbtowc(&wc, string, len); + if (n > 0 && iswprint(wc)) { + if (_buf_len >= n) { + memcpy(_buf_ptr, string, n); + _buf_ptr += n; + _buf_len -= n; + } + string += n; + len -= n; + } else { + _put_char('\\'); + sprintf(_buf_ptr, "%03o", (unsigned char) *string); + _buf_ptr += 3; + _buf_len -= 3; + string++; + len--; + } + } + count--; + if (count > 0) { + sprintf(_buf_ptr, "\\000"); + _buf_ptr += 4; + _buf_len -= 4; + } + } + *_buf_ptr++ = '"'; + *_buf_ptr++ = '\0'; + return _formatting_buffer; + } else + return Format_Len_String(string, len); +} + +/* + * + * The Format Manager: a group of routines to manage "formats" + * + */ + +static int +Is_A_Format (const char *string) +{ + return isdigit((unsigned char) string[0]); +} + +static int +Get_Format_Size (const 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; +} + +static char +Get_Format_Char (const 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]; +} + +static const char * +Format_Thunk (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 't': + return Format_Len_Text(t.extra_value, (int)t.value, t.extra_encoding); + 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); + } +} + +static const char * +Format_Thunk_I (thunk *thunks, const char *format, int i) +{ + if (i >= thunks->thunk_count) + return ""; + + return Format_Thunk(thunks[i], Get_Format_Char(format, i)); +} + +static long +Mask_Word (thunk *thunks, const char *format) +{ + int j; + + for (j = 0; j < (int)strlen(format); j++) + if (Get_Format_Char(format, j) == 'm') + return thunks[j].value; + return 0; +} + +/* + * + * The Display Format Manager: + * + */ + +static int +Is_A_DFormat (const char *string) +{ + return string[0] && string[0] != '-' + && !(isalpha((unsigned char) string[0]) || string[0] == '_'); +} + +static const char * +Handle_Backslash (const 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; +} + +static const char * +Handle_Dollar_sign (const char *dformat, thunk *thunks, const 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; +} + +static int +Mask_Bit_I (thunk *thunks, const char *format, int i) +{ + long value; + + value = Mask_Word(thunks, format); + + value = value & (1L<= 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; +} + +static const char * +Scan_Exp (const char *string, thunk *thunks, const char *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; +} + +static const char * +Handle_Question_Mark (const char *dformat, thunk *thunks, const char *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_Paren(dformat); + + return dformat; +} + +static void +Display_Property (thunk *thunks, const char *dformat, const char *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 thunks + * + */ + +static long +Extract_Value (const char **pointer, int *length, int size, int signedp) +{ + long value; + + switch (size) { + case 8: + if (signedp) + value = * (const signed char *) *pointer; + else + value = * (const unsigned char *) *pointer; + *pointer += 1; + *length -= 1; + break; + case 16: + if (signedp) + value = * (const short *) *pointer; + else + value = * (const unsigned short *) *pointer; + *pointer += sizeof(short); + *length -= sizeof(short); + break; + case 32: + if (signedp) + value = * (const long *) *pointer; + else + value = * (const unsigned long *) *pointer & 0xffffffff; + *pointer += sizeof(long); + *length -= sizeof(long); + break; + default: + abort(); + } + return value; +} + +static long +Extract_Len_String (const char **pointer, int *length, int size, const 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; +} + +static thunk * +Break_Down_Property (const char *pointer, int length, Atom type, const char *format, int 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 if (format_char == 't') { + t.extra_encoding = type; + 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; +} + +/* + * Variables set by main() + */ + +static Window target_win = 0; +static int notype = 0; +static int max_len = MAXSTR; +static XFontStruct *font; +static unsigned long _font_prop; + +/* + * + * Other Stuff (temp.): + * + */ + +static const char * +Get_Font_Property_Data_And_Type (Atom atom, + long *length, Atom *type, int *size) +{ + int i; + + *type = None; + + 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 (const char *) &_font_prop; + } + *size = 0; + return NULL; +} + +static const char * +Get_Window_Property_Data_And_Type (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 if (actual_format == 8) + nbytes = 1; + else + abort(); + *length = min(nitems * nbytes, max_len); + *type = actual_type; + *size = actual_format; + return (const char *)prop; +} + +static const char * +Get_Property_Data_And_Type (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); +} + +static void +Show_Prop (const char *format, const char *dformat, const char *prop) +{ + const char *data; + long length; + Atom atom, type; + thunk *thunks; + int size, fsize; + + printf("%s", prop); + atom = Parse_Atom(prop, True); + if (atom == None) { + 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 != None) + printf("(%s)", Format_Atom(type)); + + Lookup_Formats(atom, &format, &dformat); + if (type != None) + 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, type, format, size); + + Display_Property(thunks, dformat, format); +} + +static void +Show_All_Props (void) +{ + Atom *atoms, atom; + const 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(NULL, NULL, name); + } + } else + for (i = 0; i < font->n_properties; i++) { + atom = font->properties[i].name; + name = Format_Atom(atom); + Show_Prop(NULL, NULL, name); + } +} + +static thunk * +Handle_Prop_Requests (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 = NULL; + dformat = NULL; + + /* 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.propname = prop; + 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; +} + +static void +Remove_Property (Display *dpy, Window w, const 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); +} + +static void +Set_Property (Display *dpy, Window w, const char *propname, const char *value) +{ + Atom atom; + const char *format; + const char *dformat; + int size; + char format_char; + Atom type; + unsigned char *data; + int nelements; + + atom = Parse_Atom(propname, False); + + format = dformat = NULL; + Lookup_Formats(atom, &format, &dformat); + if (format == NULL) + Fatal_Error("unsupported conversion for %s", propname); + + size = Get_Format_Size(format); + + format_char = Get_Format_Char(format, 0); + switch (format_char) { + case 's': + if (size != 8) + Fatal_Error("can't use format character 's' with any size except 8."); + type = XA_STRING; + data = (unsigned char *) value; + nelements = strlen(value); + break; + case 't': { + XTextProperty textprop; + if (size != 8) + Fatal_Error("can't use format character 't' with any size except 8."); + if (XmbTextListToTextProperty(dpy, (char **) &value, 1, + XStdICCTextStyle, &textprop) != Success) { + fprintf(stderr, "cannot convert %s argument to STRING or COMPOUND_TEXT.\n", propname); + return; + } + type = textprop.encoding; + data = textprop.value; + nelements = textprop.nitems; + break; + } + case 'x': + case 'c': { + unsigned long intvalue = strtoul(value, NULL, 0); + static unsigned char data8; + static unsigned short data16; + static unsigned long data32; + type = XA_INTEGER; + switch (size) { + case 8: + data8 = intvalue; data = (unsigned char *) &data8; break; + case 16: + data16 = intvalue; data = (unsigned char *) &data16; break; + case 32: default: + data32 = intvalue; data = (unsigned char *) &data32; break; + } + nelements = 1; + break; + } + case 'i': { + long intvalue = strtol(value, NULL, 0); + static signed char data8; + static short data16; + static long data32; + type = XA_INTEGER; + switch (size) { + case 8: + data8 = intvalue; data = (unsigned char *) &data8; break; + case 16: + data16 = intvalue; data = (unsigned char *) &data16; break; + case 32: default: + data32 = intvalue; data = (unsigned char *) &data32; break; + } + nelements = 1; + break; + } + case 'b': { + unsigned long boolvalue; + static unsigned char data8; + static unsigned short data16; + static unsigned long data32; + if (!strcmp(value, "True")) + boolvalue = 1; + else if (!strcmp(value, "False")) + boolvalue = 0; + else { + fprintf(stderr, "cannot convert %s argument to Bool\n", propname); + return; + } + type = XA_INTEGER; + switch (size) { + case 8: + data8 = boolvalue; data = (unsigned char *) &data8; break; + case 16: + data16 = boolvalue; data = (unsigned char *) &data16; break; + case 32: default: + data32 = boolvalue; data = (unsigned char *) &data32; break; + } + nelements = 1; + break; + } + case 'a': { + static Atom avalue; + avalue = Parse_Atom(value, False); + type = XA_ATOM; + data = (unsigned char *) &avalue; + nelements = 1; + break; + } + case 'm': + /* NYI */ + default: + Fatal_Error("bad format character: %c", format_char); + } + + XChangeProperty(dpy, target_win, atom, type, size, PropModeReplace, + data, nelements); +} + +/* + * + * Routines for parsing command line: + * + */ + +void +usage (void) +{ + 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 remove a property", +" -set propname value set a property to a given value", +" -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); +} + +static void +grammar (void) +{ + printf ("Grammar for xprop:\n\n"); + printf("\t%s [] [