xprop.c revision 91ec45ce
1fc89c0fbSmrg/* $Xorg: xprop.c,v 1.6 2001/02/09 02:05:56 xorgcvs Exp $ */
2fc89c0fbSmrg/*
3fc89c0fbSmrg
4fc89c0fbSmrgCopyright 1990, 1998  The Open Group
5fc89c0fbSmrgCopyright (c) 2000  The XFree86 Project, Inc.
6fc89c0fbSmrg
7fc89c0fbSmrgPermission to use, copy, modify, distribute, and sell this software and its
8fc89c0fbSmrgdocumentation for any purpose is hereby granted without fee, provided that
9fc89c0fbSmrgthe above copyright notice appear in all copies and that both that
10fc89c0fbSmrgcopyright notice and this permission notice appear in supporting
11fc89c0fbSmrgdocumentation.
12fc89c0fbSmrg
13fc89c0fbSmrgThe above copyright notice and this permission notice shall be included
14fc89c0fbSmrgin all copies or substantial portions of the Software.
15fc89c0fbSmrg
16fc89c0fbSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17fc89c0fbSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18fc89c0fbSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19fc89c0fbSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
20fc89c0fbSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21fc89c0fbSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22fc89c0fbSmrgOTHER DEALINGS IN THE SOFTWARE.
23fc89c0fbSmrg
24fc89c0fbSmrgExcept as contained in this notice, the name of The Open Group shall
25fc89c0fbSmrgnot be used in advertising or otherwise to promote the sale, use or
26fc89c0fbSmrgother dealings in this Software without prior written authorization
27fc89c0fbSmrgfrom The Open Group.
28fc89c0fbSmrg
29fc89c0fbSmrg*/
30fc89c0fbSmrg/* $XFree86: xc/programs/xprop/xprop.c,v 1.15 2003/09/24 02:43:38 dawes Exp $ */
31fc89c0fbSmrg
32fc89c0fbSmrg#include "config.h"
33fc89c0fbSmrg
34fc89c0fbSmrg#include <X11/Xlib.h>
35fc89c0fbSmrg#include <X11/Xos.h>
36fc89c0fbSmrg#include <X11/Xfuncs.h>
37fc89c0fbSmrg#include <X11/Xutil.h>
38fc89c0fbSmrg#include <stdlib.h>
39fc89c0fbSmrg#include <stdio.h>
40fc89c0fbSmrg#include <ctype.h>
41fc89c0fbSmrg#ifdef HAVE_WCHAR_H
42fc89c0fbSmrg#include <wchar.h>
43fc89c0fbSmrg#endif
44fc89c0fbSmrg#ifdef HAVE_WCTYPE_H
45fc89c0fbSmrg#include <wctype.h>
46fc89c0fbSmrg#endif
47fc89c0fbSmrg#include <locale.h>
4891ec45ceSmrg#ifdef HAVE_LANGINFO_H
4991ec45ceSmrg#include <langinfo.h>
5091ec45ceSmrg#endif
51fc89c0fbSmrg
52fc89c0fbSmrg#ifndef HAVE_WCTYPE_H
53fc89c0fbSmrg#define iswprint(x) isprint(x)
54fc89c0fbSmrg#endif
55fc89c0fbSmrg
56fc89c0fbSmrg#include <X11/Xatom.h>
57fc89c0fbSmrg
58fc89c0fbSmrg#include "dsimple.h"
59fc89c0fbSmrg
60fc89c0fbSmrg#define MAXSTR 500000
61fc89c0fbSmrg#define MAXELEMENTS 64
62fc89c0fbSmrg
63fc89c0fbSmrg#ifndef min
64fc89c0fbSmrg#define min(a,b)  ((a) < (b) ? (a) : (b))
65fc89c0fbSmrg#endif
66fc89c0fbSmrg
67fc89c0fbSmrg/* isprint() in "C" locale */
68fc89c0fbSmrg#define c_isprint(c) ((c) >= 0x20 && (c) < 0x7f)
69fc89c0fbSmrg
70fc89c0fbSmrg/*
71fc89c0fbSmrg *
72fc89c0fbSmrg * The Thunk Manager - routines to create, add to, and free thunk lists
73fc89c0fbSmrg *
74fc89c0fbSmrg */
75fc89c0fbSmrg
76fc89c0fbSmrgtypedef struct {
77fc89c0fbSmrg  int thunk_count;
78fc89c0fbSmrg  const char *propname;
79fc89c0fbSmrg  long value;
80fc89c0fbSmrg  Atom extra_encoding;
81fc89c0fbSmrg  const char *extra_value;
82fc89c0fbSmrg  const char *format;
83fc89c0fbSmrg  const char *dformat;
84fc89c0fbSmrg} thunk;
85fc89c0fbSmrg
86fc89c0fbSmrgstatic thunk *
87fc89c0fbSmrgCreate_Thunk_List (void)
88fc89c0fbSmrg{
89fc89c0fbSmrg    thunk *tptr;
90fc89c0fbSmrg
91fc89c0fbSmrg    tptr = (thunk *) Malloc(sizeof(thunk));
92fc89c0fbSmrg
93fc89c0fbSmrg    tptr->thunk_count = 0;
94fc89c0fbSmrg
95fc89c0fbSmrg    return tptr;
96fc89c0fbSmrg}
97fc89c0fbSmrg
98fc89c0fbSmrg#ifdef notused
99fc89c0fbSmrgstatic void
100fc89c0fbSmrgFree_Thunk_List (thunk *list)
101fc89c0fbSmrg{
102fc89c0fbSmrg    free(list);
103fc89c0fbSmrg}
104fc89c0fbSmrg#endif
105fc89c0fbSmrg
106fc89c0fbSmrgstatic thunk *
107fc89c0fbSmrgAdd_Thunk (thunk *list, thunk t)
108fc89c0fbSmrg{
109fc89c0fbSmrg    int i;
110fc89c0fbSmrg
111fc89c0fbSmrg    i = list->thunk_count;
112fc89c0fbSmrg
113fc89c0fbSmrg    list = (thunk *) realloc(list, (i+1)*sizeof(thunk));
114fc89c0fbSmrg    if (!list)
115fc89c0fbSmrg	Fatal_Error("Out of memory!");
116fc89c0fbSmrg
117fc89c0fbSmrg    list[i++] = t;
118fc89c0fbSmrg    list->thunk_count = i;
119fc89c0fbSmrg
120fc89c0fbSmrg    return list;
121fc89c0fbSmrg}
122fc89c0fbSmrg
123fc89c0fbSmrg/*
124fc89c0fbSmrg * Misc. routines
125fc89c0fbSmrg */
126fc89c0fbSmrg
127fc89c0fbSmrgstatic char *
128fc89c0fbSmrgCopy_String (const char *string)
129fc89c0fbSmrg{
130fc89c0fbSmrg    char *new;
131fc89c0fbSmrg    int length;
132fc89c0fbSmrg
133fc89c0fbSmrg    length = strlen(string) + 1;
134fc89c0fbSmrg
135fc89c0fbSmrg    new = (char *) Malloc(length);
136fc89c0fbSmrg    memcpy(new, string, length);
137fc89c0fbSmrg
138fc89c0fbSmrg    return new;
139fc89c0fbSmrg}
140fc89c0fbSmrg
141fc89c0fbSmrgstatic int
142fc89c0fbSmrgRead_Char (FILE *stream)
143fc89c0fbSmrg{
144fc89c0fbSmrg    int c;
145fc89c0fbSmrg
146fc89c0fbSmrg    c = getc(stream);
147fc89c0fbSmrg    if (c == EOF)
148fc89c0fbSmrg	Fatal_Error("Bad format file: Unexpected EOF.");
149fc89c0fbSmrg    return c;
150fc89c0fbSmrg}
151fc89c0fbSmrg
152fc89c0fbSmrgstatic void
153fc89c0fbSmrgRead_White_Space (FILE *stream)
154fc89c0fbSmrg{
155fc89c0fbSmrg    int c;
156fc89c0fbSmrg
157fc89c0fbSmrg    while ((c = getc(stream)) == ' ' || c == '\n' || c == '\t');
158fc89c0fbSmrg    ungetc(c, stream);
159fc89c0fbSmrg}
160fc89c0fbSmrg
161fc89c0fbSmrgstatic char _large_buffer[MAXSTR+10];
162fc89c0fbSmrg
163fc89c0fbSmrgstatic char *
164fc89c0fbSmrgRead_Quoted (FILE *stream)
165fc89c0fbSmrg{
166fc89c0fbSmrg    char *ptr;
167fc89c0fbSmrg    int c, length;
168fc89c0fbSmrg
169fc89c0fbSmrg    Read_White_Space(stream);
170fc89c0fbSmrg    if (Read_Char(stream)!='\'')
171fc89c0fbSmrg	Fatal_Error("Bad format file format: missing dformat.");
172fc89c0fbSmrg
173fc89c0fbSmrg    ptr = _large_buffer; length = MAXSTR;
174fc89c0fbSmrg    for (;;) {
175fc89c0fbSmrg	if (length < 0)
176fc89c0fbSmrg	    Fatal_Error("Bad format file format: dformat too long.");
177fc89c0fbSmrg	c = Read_Char(stream);
178fc89c0fbSmrg	if (c == (int) '\'')
179fc89c0fbSmrg	    break;
180fc89c0fbSmrg	ptr++[0] = c; length--;
181fc89c0fbSmrg	if (c == (int) '\\') {
182fc89c0fbSmrg	    c = Read_Char(stream);
183fc89c0fbSmrg	    if (c == '\n') {
184fc89c0fbSmrg		ptr--; length++;
185fc89c0fbSmrg	    } else
186fc89c0fbSmrg		ptr++[0] = c; length--;
187fc89c0fbSmrg	}
188fc89c0fbSmrg    }
189fc89c0fbSmrg    ptr++[0] = '\0';
190fc89c0fbSmrg
191fc89c0fbSmrg    return Copy_String(_large_buffer);
192fc89c0fbSmrg}
193fc89c0fbSmrg
194fc89c0fbSmrg/*
195fc89c0fbSmrg *
196fc89c0fbSmrg * Parsing Routines: a group of routines to parse strings into values
197fc89c0fbSmrg *
198fc89c0fbSmrg * Routines: Parse_Atom, Scan_Long, Skip_Past_Right_Paren, Scan_Octal
199fc89c0fbSmrg *
200fc89c0fbSmrg * Routines of the form Parse_XXX take a string which is parsed to a value.
201fc89c0fbSmrg * Routines of the form Scan_XXX take a string, parse the beginning to a value,
202fc89c0fbSmrg * and return the rest of the string.  The value is returned via. the last
203fc89c0fbSmrg * parameter.  All numeric values are longs!
204fc89c0fbSmrg *
205fc89c0fbSmrg */
206fc89c0fbSmrg
207fc89c0fbSmrgstatic const char *
208fc89c0fbSmrgSkip_Digits (const char *string)
209fc89c0fbSmrg{
210fc89c0fbSmrg    while (isdigit((unsigned char) string[0])) string++;
211fc89c0fbSmrg    return string;
212fc89c0fbSmrg}
213fc89c0fbSmrg
214fc89c0fbSmrgstatic const char *
215fc89c0fbSmrgScan_Long (const char *string, long *value)
216fc89c0fbSmrg{
217fc89c0fbSmrg    if (!isdigit((unsigned char) *string))
218fc89c0fbSmrg	Fatal_Error("Bad number: %s.", string);
219fc89c0fbSmrg
220fc89c0fbSmrg    *value = atol(string);
221fc89c0fbSmrg    return Skip_Digits(string);
222fc89c0fbSmrg}
223fc89c0fbSmrg
224fc89c0fbSmrgstatic const char *
225fc89c0fbSmrgScan_Octal (const char *string, unsigned long *value)
226fc89c0fbSmrg{
227fc89c0fbSmrg    if (sscanf(string, "%lo", value)!=1)
228fc89c0fbSmrg	Fatal_Error("Bad octal number: %s.", string);
229fc89c0fbSmrg    return Skip_Digits(string);
230fc89c0fbSmrg}
231fc89c0fbSmrg
232fc89c0fbSmrgstatic Atom
233fc89c0fbSmrgParse_Atom (const char *name, int only_if_exists)
234fc89c0fbSmrg{
235fc89c0fbSmrg    /* may return None = 0 */
236fc89c0fbSmrg    return XInternAtom(dpy, name, only_if_exists);
237fc89c0fbSmrg}
238fc89c0fbSmrg
239fc89c0fbSmrgstatic const char *
240fc89c0fbSmrgSkip_Past_Right_Paren (const char *string)
241fc89c0fbSmrg{
242fc89c0fbSmrg    char c;
243fc89c0fbSmrg    int nesting = 0;
244fc89c0fbSmrg
245fc89c0fbSmrg    while (c = string++[0], c != ')' || nesting)
246fc89c0fbSmrg	switch (c) {
247fc89c0fbSmrg	  case '\0':
248fc89c0fbSmrg	    Fatal_Error("Missing ')'.");
249fc89c0fbSmrg	  case '(':
250fc89c0fbSmrg	    nesting++;
251fc89c0fbSmrg	    break;
252fc89c0fbSmrg	  case ')':
253fc89c0fbSmrg	    nesting--;
254fc89c0fbSmrg	    break;
255fc89c0fbSmrg	  case '\\':
256fc89c0fbSmrg	    string++;
257fc89c0fbSmrg	    break;
258fc89c0fbSmrg	}
259fc89c0fbSmrg    return string;
260fc89c0fbSmrg}
261fc89c0fbSmrg
262fc89c0fbSmrg/*
263fc89c0fbSmrg *
264fc89c0fbSmrg * Atom to format, dformat mapping Manager
265fc89c0fbSmrg *
266fc89c0fbSmrg */
267fc89c0fbSmrg
268fc89c0fbSmrg#define D_FORMAT "0x"              /* Default format for properties */
269fc89c0fbSmrg#define D_DFORMAT " = $0+\n"       /* Default display pattern for properties */
270fc89c0fbSmrg
271fc89c0fbSmrgstatic thunk *_property_formats = NULL;   /* Holds mapping */
272fc89c0fbSmrg
273fc89c0fbSmrgstatic void
274fc89c0fbSmrgApply_Default_Formats (const char **format, const char **dformat)
275fc89c0fbSmrg{
276fc89c0fbSmrg    if (!*format)
277fc89c0fbSmrg	*format = D_FORMAT;
278fc89c0fbSmrg    if (!*dformat)
279fc89c0fbSmrg	*dformat = D_DFORMAT;
280fc89c0fbSmrg}
281fc89c0fbSmrg
282fc89c0fbSmrgstatic void
283fc89c0fbSmrgLookup_Formats (Atom atom, const char **format, const char **dformat)
284fc89c0fbSmrg{
285fc89c0fbSmrg    int i;
286fc89c0fbSmrg
287fc89c0fbSmrg    if (_property_formats)
288fc89c0fbSmrg	for (i = _property_formats->thunk_count-1; i >= 0; i--)
289fc89c0fbSmrg	    if (_property_formats[i].value == atom) {
290fc89c0fbSmrg		if (!*format)
291fc89c0fbSmrg		    *format = _property_formats[i].format;
292fc89c0fbSmrg		if (!*dformat)
293fc89c0fbSmrg		    *dformat = _property_formats[i].dformat;
294fc89c0fbSmrg		break;
295fc89c0fbSmrg	    }
296fc89c0fbSmrg}
297fc89c0fbSmrg
298fc89c0fbSmrgstatic void
299fc89c0fbSmrgAdd_Mapping (Atom atom, const char *format, const char *dformat)
300fc89c0fbSmrg{
301fc89c0fbSmrg    thunk t;
302fc89c0fbSmrg
303fc89c0fbSmrg    if (!_property_formats)
304fc89c0fbSmrg	_property_formats = Create_Thunk_List();
305fc89c0fbSmrg
306fc89c0fbSmrg    t.value = atom;
307fc89c0fbSmrg    t.format = format;
308fc89c0fbSmrg    t.dformat = dformat;
309fc89c0fbSmrg
310fc89c0fbSmrg    _property_formats = Add_Thunk(_property_formats, t);
311fc89c0fbSmrg}
312fc89c0fbSmrg
313fc89c0fbSmrg/*
314fc89c0fbSmrg *
315fc89c0fbSmrg * Setup_Mapping: Routine to setup default atom to format, dformat mapping:
316fc89c0fbSmrg *
317fc89c0fbSmrg */
318fc89c0fbSmrg
319fc89c0fbSmrgtypedef struct _propertyRec {
320fc89c0fbSmrg    const char *	name;
321fc89c0fbSmrg    Atom		atom;
322fc89c0fbSmrg    const char *	format;
323fc89c0fbSmrg    const char *	dformat;
324fc89c0fbSmrg} propertyRec;
325fc89c0fbSmrg
326fc89c0fbSmrg#define ARC_DFORMAT	":\n"\
327fc89c0fbSmrg"\t\tarc at $0, $1\n"\
328fc89c0fbSmrg"\t\tsize: $2 by $3\n"\
329fc89c0fbSmrg"\t\tfrom angle $4 to angle $5\n"
330fc89c0fbSmrg
331fc89c0fbSmrg#define RECTANGLE_DFORMAT	":\n"\
332fc89c0fbSmrg"\t\tupper left corner: $0, $1\n"\
333fc89c0fbSmrg"\t\tsize: $2 by $3\n"
334fc89c0fbSmrg
335fc89c0fbSmrg#define RGB_COLOR_MAP_DFORMAT	":\n"\
336fc89c0fbSmrg"\t\tcolormap id #: $0\n"\
337fc89c0fbSmrg"\t\tred-max: $1\n"\
338fc89c0fbSmrg"\t\tred-mult: $2\n"\
339fc89c0fbSmrg"\t\tgreen-max: $3\n"\
340fc89c0fbSmrg"\t\tgreen-mult: $4\n"\
341fc89c0fbSmrg"\t\tblue-max: $5\n"\
342fc89c0fbSmrg"\t\tblue-mult: $6\n"\
343fc89c0fbSmrg"\t\tbase-pixel: $7\n"\
344fc89c0fbSmrg"\t\tvisual id #: $8\n"\
345fc89c0fbSmrg"\t\tkill id #: $9\n"
346fc89c0fbSmrg
347fc89c0fbSmrg#define WM_HINTS_DFORMAT	":\n"\
348fc89c0fbSmrg"?m0(\t\tClient accepts input or input focus: $1\n)"\
349fc89c0fbSmrg"?m1(\t\tInitial state is "\
350fc89c0fbSmrg"?$2=0(Don't Care State)"\
351fc89c0fbSmrg"?$2=1(Normal State)"\
352fc89c0fbSmrg"?$2=2(Zoomed State)"\
353fc89c0fbSmrg"?$2=3(Iconic State)"\
354fc89c0fbSmrg"?$2=4(Inactive State)"\
355fc89c0fbSmrg".\n)"\
356fc89c0fbSmrg"?m2(\t\tbitmap id # to use for icon: $3\n)"\
357fc89c0fbSmrg"?m5(\t\tbitmap id # of mask for icon: $7\n)"\
358fc89c0fbSmrg"?m3(\t\twindow id # to use for icon: $4\n)"\
359fc89c0fbSmrg"?m4(\t\tstarting position for icon: $5, $6\n)"\
360fc89c0fbSmrg"?m6(\t\twindow id # of group leader: $8\n)"\
36191ec45ceSmrg"?m8(\t\tThe urgency hint bit is set\n)"
362fc89c0fbSmrg
363fc89c0fbSmrg#define WM_ICON_SIZE_DFORMAT	":\n"\
364fc89c0fbSmrg"\t\tminimum icon size: $0 by $1\n"\
365fc89c0fbSmrg"\t\tmaximum icon size: $2 by $3\n"\
366fc89c0fbSmrg"\t\tincremental size change: $4 by $5\n"
367fc89c0fbSmrg
368fc89c0fbSmrg#define WM_SIZE_HINTS_DFORMAT ":\n"\
369fc89c0fbSmrg"?m0(\t\tuser specified location: $1, $2\n)"\
370fc89c0fbSmrg"?m2(\t\tprogram specified location: $1, $2\n)"\
371fc89c0fbSmrg"?m1(\t\tuser specified size: $3 by $4\n)"\
372fc89c0fbSmrg"?m3(\t\tprogram specified size: $3 by $4\n)"\
373fc89c0fbSmrg"?m4(\t\tprogram specified minimum size: $5 by $6\n)"\
374fc89c0fbSmrg"?m5(\t\tprogram specified maximum size: $7 by $8\n)"\
375fc89c0fbSmrg"?m6(\t\tprogram specified resize increment: $9 by $10\n)"\
376fc89c0fbSmrg"?m7(\t\tprogram specified minimum aspect ratio: $11/$12\n"\
377fc89c0fbSmrg"\t\tprogram specified maximum aspect ratio: $13/$14\n)"\
378fc89c0fbSmrg"?m8(\t\tprogram specified base size: $15 by $16\n)"\
379fc89c0fbSmrg"?m9(\t\twindow gravity: "\
380fc89c0fbSmrg"?$17=0(Forget)"\
381fc89c0fbSmrg"?$17=1(NorthWest)"\
382fc89c0fbSmrg"?$17=2(North)"\
383fc89c0fbSmrg"?$17=3(NorthEast)"\
384fc89c0fbSmrg"?$17=4(West)"\
385fc89c0fbSmrg"?$17=5(Center)"\
386fc89c0fbSmrg"?$17=6(East)"\
387fc89c0fbSmrg"?$17=7(SouthWest)"\
388fc89c0fbSmrg"?$17=8(South)"\
389fc89c0fbSmrg"?$17=9(SouthEast)"\
390fc89c0fbSmrg"?$17=10(Static)"\
391fc89c0fbSmrg"\n)"
392fc89c0fbSmrg
393fc89c0fbSmrg#define WM_STATE_DFORMAT	 ":\n"\
394fc89c0fbSmrg"\t\twindow state: ?$0=0(Withdrawn)?$0=1(Normal)?$0=3(Iconic)\n"\
395fc89c0fbSmrg"\t\ticon window: $1\n"
396fc89c0fbSmrg
397fc89c0fbSmrgstatic propertyRec windowPropTable[] = {
398fc89c0fbSmrg    {"ARC",		XA_ARC,		"16iiccii",   ARC_DFORMAT },
399fc89c0fbSmrg    {"ATOM",		XA_ATOM,	 "32a",	      0 },
400fc89c0fbSmrg    {"BITMAP",		XA_BITMAP,	 "32x",	      ": bitmap id # $0\n" },
401fc89c0fbSmrg    {"CARDINAL",	XA_CARDINAL,	 "0c",	      0 },
402fc89c0fbSmrg    {"COLORMAP",	XA_COLORMAP,	 "32x",	      ": colormap id # $0\n" },
403fc89c0fbSmrg    {"CURSOR",		XA_CURSOR,	 "32x",	      ": cursor id # $0\n" },
404fc89c0fbSmrg    {"DRAWABLE",	XA_DRAWABLE,	 "32x",	      ": drawable id # $0\n" },
405fc89c0fbSmrg    {"FONT",		XA_FONT,	 "32x",	      ": font id # $0\n" },
406fc89c0fbSmrg    {"INTEGER",		XA_INTEGER,	 "0i",	      0 },
407fc89c0fbSmrg    {"PIXMAP",		XA_PIXMAP,	 "32x",	      ": pixmap id # $0\n" },
408fc89c0fbSmrg    {"POINT",		XA_POINT,	 "16ii",      " = $0, $1\n" },
409fc89c0fbSmrg    {"RECTANGLE",	XA_RECTANGLE,	 "16iicc",    RECTANGLE_DFORMAT },
410fc89c0fbSmrg    {"RGB_COLOR_MAP",	XA_RGB_COLOR_MAP,"32xcccccccxx",RGB_COLOR_MAP_DFORMAT},
411fc89c0fbSmrg    {"STRING",		XA_STRING,	 "8s",	      0 },
412fc89c0fbSmrg    {"WINDOW",		XA_WINDOW,	 "32x",	      ": window id # $0+\n" },
413fc89c0fbSmrg    {"VISUALID",	XA_VISUALID,	 "32x",	      ": visual id # $0\n" },
414fc89c0fbSmrg    {"WM_COLORMAP_WINDOWS",	0,	 "32x",       ": window id # $0+\n"},
415fc89c0fbSmrg    {"WM_COMMAND",	XA_WM_COMMAND,	 "8s",	      " = { $0+ }\n" },
416fc89c0fbSmrg    {"WM_HINTS",	XA_WM_HINTS,	 "32mbcxxiixx",	WM_HINTS_DFORMAT },
417fc89c0fbSmrg    {"WM_ICON_NAME",	XA_WM_ICON_NAME, "8t",	      0 },
418fc89c0fbSmrg    {"WM_ICON_SIZE",	XA_WM_ICON_SIZE, "32cccccc",  WM_ICON_SIZE_DFORMAT},
419fc89c0fbSmrg    {"WM_NAME",		XA_WM_NAME,	 "8t",	      0 },
420fc89c0fbSmrg    {"WM_PROTOCOLS",		0,	 "32a",	      ": protocols  $0+\n"},
421fc89c0fbSmrg    {"WM_SIZE_HINTS",	XA_WM_SIZE_HINTS,"32mii",     WM_SIZE_HINTS_DFORMAT },
42291ec45ceSmrg    {"_NET_WM_ICON",            0,       "32o",        0 },
423fc89c0fbSmrg    {"WM_STATE",		0,	 "32cx",      WM_STATE_DFORMAT}
424fc89c0fbSmrg};
425fc89c0fbSmrg#undef ARC_DFORMAT
426fc89c0fbSmrg#undef RECTANGLE_DFORMAT
427fc89c0fbSmrg#undef RGB_COLOR_MAP_DFORMAT
428fc89c0fbSmrg#undef WM_ICON_SIZE_DFORMAT
429fc89c0fbSmrg#undef WM_HINTS_DFORMAT
430fc89c0fbSmrg#undef WM_SIZE_HINTS_DFORMAT
431fc89c0fbSmrg#undef WM_STATE_DFORMAT
432fc89c0fbSmrg
433fc89c0fbSmrg/*
434fc89c0fbSmrg * Font-specific mapping of property names to types:
435fc89c0fbSmrg */
436fc89c0fbSmrgstatic propertyRec fontPropTable[] = {
437fc89c0fbSmrg
438fc89c0fbSmrg    /* XLFD name properties */
439fc89c0fbSmrg
440fc89c0fbSmrg    { "FOUNDRY",		0, 	 		"32a",	0 },
441fc89c0fbSmrg    { "FAMILY_NAME",		XA_FAMILY_NAME,		"32a",	0 },
442fc89c0fbSmrg    { "WEIGHT_NAME",		0,			"32a",	0 },
443fc89c0fbSmrg    { "SLANT",			0,			"32a",	0 },
444fc89c0fbSmrg    { "SETWIDTH_NAME",		0,			"32a",	0 },
445fc89c0fbSmrg    { "ADD_STYLE_NAME",		0,			"32a",	0 },
446fc89c0fbSmrg    { "PIXEL_SIZE",		0,			"32c",	0 },
447fc89c0fbSmrg    { "POINT_SIZE",		XA_POINT_SIZE,		"32c",	0 },
448fc89c0fbSmrg    { "RESOLUTION_X",		0,			"32c",	0 },
449fc89c0fbSmrg    { "RESOLUTION_Y",		0,			"32c",	0 },
450fc89c0fbSmrg    { "SPACING",		0,			"32a",	0 },
451fc89c0fbSmrg    { "AVERAGE_WIDTH",		0,			"32c",	0 },
452fc89c0fbSmrg    { "CHARSET_REGISTRY",	0,			"32a",	0 },
453fc89c0fbSmrg    { "CHARSET_ENCODING",	0,			"32a",	0 },
454fc89c0fbSmrg
455fc89c0fbSmrg    /* other font properties referenced in the XLFD */
456fc89c0fbSmrg
457fc89c0fbSmrg    { "QUAD_WIDTH",		XA_QUAD_WIDTH,		"32i",	0 },
458fc89c0fbSmrg    { "RESOLUTION",		XA_RESOLUTION,		"32c",	0 },
459fc89c0fbSmrg    { "MIN_SPACE",		XA_MIN_SPACE,		"32c",	0 },
460fc89c0fbSmrg    { "NORM_SPACE",		XA_NORM_SPACE,		"32c",	0 },
461fc89c0fbSmrg    { "MAX_SPACE",		XA_MAX_SPACE,		"32c",	0 },
462fc89c0fbSmrg    { "END_SPACE",		XA_END_SPACE,		"32c",	0 },
463fc89c0fbSmrg    { "SUPERSCRIPT_X",		XA_SUPERSCRIPT_X,	"32i",	0 },
464fc89c0fbSmrg    { "SUPERSCRIPT_Y",		XA_SUPERSCRIPT_Y,	"32i",	0 },
465fc89c0fbSmrg    { "SUBSCRIPT_X",		XA_SUBSCRIPT_X,		"32i",	0 },
466fc89c0fbSmrg    { "SUBSCRIPT_Y",		XA_SUBSCRIPT_Y,		"32i",	0 },
467fc89c0fbSmrg    { "UNDERLINE_POSITION",	XA_UNDERLINE_POSITION,	"32i",	0 },
468fc89c0fbSmrg    { "UNDERLINE_THICKNESS",	XA_UNDERLINE_THICKNESS,	"32i",	0 },
469fc89c0fbSmrg    { "STRIKEOUT_ASCENT",	XA_STRIKEOUT_ASCENT,	"32i",	0 },
470fc89c0fbSmrg    { "STRIKEOUT_DESCENT",	XA_STRIKEOUT_DESCENT,	"32i",	0 },
471fc89c0fbSmrg    { "ITALIC_ANGLE",		XA_ITALIC_ANGLE,	"32i",	0 },
472fc89c0fbSmrg    { "X_HEIGHT",		XA_X_HEIGHT,		"32i",	0 },
473fc89c0fbSmrg    { "WEIGHT",			XA_WEIGHT,		"32i",	0 },
474fc89c0fbSmrg    { "FACE_NAME",		0,			"32a",	0 },
475fc89c0fbSmrg    { "COPYRIGHT",		XA_COPYRIGHT,		"32a",	0 },
476fc89c0fbSmrg    { "AVG_CAPITAL_WIDTH",	0,			"32i",	0 },
477fc89c0fbSmrg    { "AVG_LOWERCASE_WIDTH",	0,			"32i",	0 },
478fc89c0fbSmrg    { "RELATIVE_SETWIDTH",	0,			"32c",	0 },
479fc89c0fbSmrg    { "RELATIVE_WEIGHT",	0,			"32c",	0 },
480fc89c0fbSmrg    { "CAP_HEIGHT",		XA_CAP_HEIGHT,		"32c",	0 },
481fc89c0fbSmrg    { "SUPERSCRIPT_SIZE",	0,			"32c",	0 },
482fc89c0fbSmrg    { "FIGURE_WIDTH",		0,			"32i",	0 },
483fc89c0fbSmrg    { "SUBSCRIPT_SIZE",		0,			"32c",	0 },
484fc89c0fbSmrg    { "SMALL_CAP_SIZE",		0,			"32i",	0 },
485fc89c0fbSmrg    { "NOTICE",			XA_NOTICE,		"32a",	0 },
486fc89c0fbSmrg    { "DESTINATION",		0,			"32c",	0 },
487fc89c0fbSmrg
488fc89c0fbSmrg    /* other font properties */
489fc89c0fbSmrg
490fc89c0fbSmrg    { "FONT",			XA_FONT,		"32a",	0 },
491fc89c0fbSmrg    { "FONT_NAME",		XA_FONT_NAME,		"32a",	0 },
492fc89c0fbSmrg};
493fc89c0fbSmrg
494fc89c0fbSmrgstatic int XpropMode;
495fc89c0fbSmrg#define XpropWindowProperties 0
496fc89c0fbSmrg#define XpropFontProperties   1
497fc89c0fbSmrg
498fc89c0fbSmrgstatic void
499fc89c0fbSmrgSetup_Mapping (void)
500fc89c0fbSmrg{
501fc89c0fbSmrg    int n;
502fc89c0fbSmrg    propertyRec *p;
503fc89c0fbSmrg
504fc89c0fbSmrg    if (XpropMode == XpropWindowProperties) {
505fc89c0fbSmrg	n = sizeof(windowPropTable) / sizeof(propertyRec);
506fc89c0fbSmrg	p = windowPropTable;
507fc89c0fbSmrg    } else {
508fc89c0fbSmrg	n = sizeof (fontPropTable) / sizeof (propertyRec);
509fc89c0fbSmrg	p = fontPropTable;
510fc89c0fbSmrg    }
511fc89c0fbSmrg    for ( ; --n >= 0; p++) {
512fc89c0fbSmrg	if (! p->atom) {
513fc89c0fbSmrg	    p->atom = XInternAtom(dpy, p->name, True);
514fc89c0fbSmrg	    if (p->atom == None)
515fc89c0fbSmrg		continue;
516fc89c0fbSmrg	}
517fc89c0fbSmrg	Add_Mapping(p->atom, p->format, p->dformat);
518fc89c0fbSmrg    }
519fc89c0fbSmrg}
520fc89c0fbSmrg
521fc89c0fbSmrgstatic const char *
522fc89c0fbSmrgGetAtomName (Atom atom)
523fc89c0fbSmrg{
524fc89c0fbSmrg    int n;
525fc89c0fbSmrg    propertyRec *p;
526fc89c0fbSmrg
527fc89c0fbSmrg    if (XpropMode == XpropWindowProperties) {
528fc89c0fbSmrg	n = sizeof(windowPropTable) / sizeof(propertyRec);
529fc89c0fbSmrg	p = windowPropTable;
530fc89c0fbSmrg    } else {
531fc89c0fbSmrg	n = sizeof (fontPropTable) / sizeof (propertyRec);
532fc89c0fbSmrg	p = fontPropTable;
533fc89c0fbSmrg    }
534fc89c0fbSmrg    for ( ; --n >= 0; p++)
535fc89c0fbSmrg	if (p->atom == atom)
536fc89c0fbSmrg	    return p->name;
537fc89c0fbSmrg
538fc89c0fbSmrg    return NULL;
539fc89c0fbSmrg}
540fc89c0fbSmrg
541fc89c0fbSmrg/*
542fc89c0fbSmrg * Read_Mapping: routine to read in additional mappings from a stream
543fc89c0fbSmrg *               already open for reading.
544fc89c0fbSmrg */
545fc89c0fbSmrg
546fc89c0fbSmrgstatic void
547fc89c0fbSmrgRead_Mappings (FILE *stream)
548fc89c0fbSmrg{
549fc89c0fbSmrg    char format_buffer[100];
550fc89c0fbSmrg    char name[1000], *dformat, *format;
551fc89c0fbSmrg    int count, c;
552fc89c0fbSmrg    Atom atom;
553fc89c0fbSmrg
554fc89c0fbSmrg    while ((count = fscanf(stream," %990s %90s ",name,format_buffer)) != EOF) {
555fc89c0fbSmrg	if (count != 2)
556fc89c0fbSmrg	    Fatal_Error("Bad format file format.");
557fc89c0fbSmrg
558fc89c0fbSmrg	atom = Parse_Atom(name, False);
559fc89c0fbSmrg	format = Copy_String(format_buffer);
560fc89c0fbSmrg
561fc89c0fbSmrg	Read_White_Space(stream);
562fc89c0fbSmrg	dformat = D_DFORMAT;
563fc89c0fbSmrg	c = getc(stream);
564fc89c0fbSmrg	ungetc(c, stream);
565fc89c0fbSmrg	if (c == (int) '\'')
566fc89c0fbSmrg	    dformat = Read_Quoted(stream);
567fc89c0fbSmrg
568fc89c0fbSmrg	Add_Mapping(atom, format, dformat);
569fc89c0fbSmrg    }
570fc89c0fbSmrg}
571fc89c0fbSmrg
572fc89c0fbSmrg/*
573fc89c0fbSmrg *
574fc89c0fbSmrg * Formatting Routines: a group of routines to translate from various
575fc89c0fbSmrg *                      values to a static read-only string useful for output.
576fc89c0fbSmrg *
577fc89c0fbSmrg * Routines: Format_Hex, Format_Unsigned, Format_Signed, Format_Atom,
578fc89c0fbSmrg *           Format_Mask_Word, Format_Bool, Format_String, Format_Len_String.
579fc89c0fbSmrg *
580fc89c0fbSmrg * All of the above routines take a long except for Format_String and
581fc89c0fbSmrg * Format_Len_String.
582fc89c0fbSmrg *
583fc89c0fbSmrg */
584fc89c0fbSmrgstatic char _formatting_buffer[MAXSTR+100];
585fc89c0fbSmrgstatic char _formatting_buffer2[21];
586fc89c0fbSmrg
587fc89c0fbSmrgstatic const char *
588fc89c0fbSmrgFormat_Hex (long wrd)
589fc89c0fbSmrg{
590fc89c0fbSmrg    snprintf(_formatting_buffer2, sizeof(_formatting_buffer2), "0x%lx", wrd);
591fc89c0fbSmrg    return _formatting_buffer2;
592fc89c0fbSmrg}
593fc89c0fbSmrg
594fc89c0fbSmrgstatic const char *
595fc89c0fbSmrgFormat_Unsigned (long wrd)
596fc89c0fbSmrg{
597fc89c0fbSmrg    snprintf(_formatting_buffer2, sizeof(_formatting_buffer2), "%lu", wrd);
598fc89c0fbSmrg    return _formatting_buffer2;
599fc89c0fbSmrg}
600fc89c0fbSmrg
601fc89c0fbSmrgstatic const char *
602fc89c0fbSmrgFormat_Signed (long wrd)
603fc89c0fbSmrg{
604fc89c0fbSmrg    snprintf(_formatting_buffer2, sizeof(_formatting_buffer2), "%ld", wrd);
605fc89c0fbSmrg    return _formatting_buffer2;
606fc89c0fbSmrg}
607fc89c0fbSmrg
608fc89c0fbSmrg/*ARGSUSED*/
609fc89c0fbSmrgstatic int
610fc89c0fbSmrgignore_errors (Display *dpy, XErrorEvent *ev)
611fc89c0fbSmrg{
612fc89c0fbSmrg    return 0;
613fc89c0fbSmrg}
614fc89c0fbSmrg
615fc89c0fbSmrgstatic const char *
616fc89c0fbSmrgFormat_Atom (Atom atom)
617fc89c0fbSmrg{
618fc89c0fbSmrg    const char *found;
619fc89c0fbSmrg    char *name;
620fc89c0fbSmrg    XErrorHandler handler;
621fc89c0fbSmrg
622fc89c0fbSmrg    if ((found = GetAtomName(atom)) != NULL)
623fc89c0fbSmrg	return found;
624fc89c0fbSmrg
625fc89c0fbSmrg    handler = XSetErrorHandler (ignore_errors);
626fc89c0fbSmrg    name = XGetAtomName(dpy, atom);
627fc89c0fbSmrg    XSetErrorHandler(handler);
628fc89c0fbSmrg    if (! name)
629fc89c0fbSmrg	snprintf(_formatting_buffer, sizeof(_formatting_buffer),
630fc89c0fbSmrg		 "undefined atom # 0x%lx", atom);
631fc89c0fbSmrg    else {
632fc89c0fbSmrg	int namelen = strlen(name);
633fc89c0fbSmrg	if (namelen > MAXSTR) namelen = MAXSTR;
634fc89c0fbSmrg	memcpy(_formatting_buffer, name, namelen);
635fc89c0fbSmrg	_formatting_buffer[namelen] = '\0';
636fc89c0fbSmrg	XFree(name);
637fc89c0fbSmrg    }
638fc89c0fbSmrg    return _formatting_buffer;
639fc89c0fbSmrg}
640fc89c0fbSmrg
641fc89c0fbSmrgstatic const char *
642fc89c0fbSmrgFormat_Mask_Word (long wrd)
643fc89c0fbSmrg{
644fc89c0fbSmrg    long bit_mask, bit;
645fc89c0fbSmrg    int seen = 0;
646fc89c0fbSmrg
647fc89c0fbSmrg    strcpy(_formatting_buffer, "{MASK: ");
648fc89c0fbSmrg    for (bit=0, bit_mask=1; bit <= sizeof(long)*8; bit++, bit_mask<<=1) {
649fc89c0fbSmrg	if (bit_mask & wrd) {
650fc89c0fbSmrg	    if (seen) {
651fc89c0fbSmrg		strcat(_formatting_buffer, ", ");
652fc89c0fbSmrg	    }
653fc89c0fbSmrg	    seen = 1;
654fc89c0fbSmrg	    strcat(_formatting_buffer, Format_Unsigned(bit));
655fc89c0fbSmrg	}
656fc89c0fbSmrg    }
657fc89c0fbSmrg    strcat(_formatting_buffer, "}");
658fc89c0fbSmrg
659fc89c0fbSmrg    return _formatting_buffer;
660fc89c0fbSmrg}
661fc89c0fbSmrg
662fc89c0fbSmrgstatic const char *
663fc89c0fbSmrgFormat_Bool (long value)
664fc89c0fbSmrg{
665fc89c0fbSmrg    if (!value)
666fc89c0fbSmrg	return "False";
667fc89c0fbSmrg
668fc89c0fbSmrg    return "True";
669fc89c0fbSmrg}
670fc89c0fbSmrg
671fc89c0fbSmrgstatic char *_buf_ptr;
672fc89c0fbSmrgstatic int _buf_len;
673fc89c0fbSmrg
674fc89c0fbSmrgstatic void
675fc89c0fbSmrg_put_char (char c)
676fc89c0fbSmrg{
677fc89c0fbSmrg    if (_buf_len <= 0) {
678fc89c0fbSmrg	_buf_ptr[0] = '\0';
679fc89c0fbSmrg	return;
680fc89c0fbSmrg    }
681fc89c0fbSmrg    _buf_ptr++[0] = c;
682fc89c0fbSmrg    _buf_len--;
683fc89c0fbSmrg}
684fc89c0fbSmrg
685fc89c0fbSmrgstatic void
686fc89c0fbSmrg_format_char (char c)
687fc89c0fbSmrg{
688fc89c0fbSmrg    switch (c) {
689fc89c0fbSmrg      case '\\':
690fc89c0fbSmrg      case '\"':
691fc89c0fbSmrg	_put_char('\\');
692fc89c0fbSmrg	_put_char(c);
693fc89c0fbSmrg	break;
694fc89c0fbSmrg      case '\n':
695fc89c0fbSmrg	_put_char('\\');
696fc89c0fbSmrg	_put_char('n');
697fc89c0fbSmrg	break;
698fc89c0fbSmrg      case '\t':
699fc89c0fbSmrg	_put_char('\\');
700fc89c0fbSmrg	_put_char('t');
701fc89c0fbSmrg	break;
702fc89c0fbSmrg      default:
703fc89c0fbSmrg	if (!c_isprint(c)) {
704fc89c0fbSmrg	    _put_char('\\');
705fc89c0fbSmrg	    snprintf(_buf_ptr, _buf_len, "%03o", (unsigned char) c);
706fc89c0fbSmrg	    _buf_ptr += 3;
707fc89c0fbSmrg	    _buf_len -= 3;
708fc89c0fbSmrg	} else
709fc89c0fbSmrg	  _put_char(c);
710fc89c0fbSmrg    }
711fc89c0fbSmrg}
712fc89c0fbSmrg
713fc89c0fbSmrgstatic const char *
714fc89c0fbSmrgFormat_String (const char *string)
715fc89c0fbSmrg{
716fc89c0fbSmrg    char c;
717fc89c0fbSmrg
718fc89c0fbSmrg    _buf_ptr = _formatting_buffer;
719fc89c0fbSmrg    _buf_len = MAXSTR;
720fc89c0fbSmrg    _put_char('\"');
721fc89c0fbSmrg
722fc89c0fbSmrg    while ((c = string++[0]))
723fc89c0fbSmrg	_format_char(c);
724fc89c0fbSmrg
725fc89c0fbSmrg    *_buf_ptr++ = '"';
726fc89c0fbSmrg    *_buf_ptr++ = '\0';
727fc89c0fbSmrg    return _formatting_buffer;
728fc89c0fbSmrg}
729fc89c0fbSmrg
730fc89c0fbSmrgstatic const char *
731fc89c0fbSmrgFormat_Len_String (const char *string, int len)
732fc89c0fbSmrg{
733fc89c0fbSmrg    char *data;
734fc89c0fbSmrg    const char *result;
735fc89c0fbSmrg
736fc89c0fbSmrg    data = (char *) Malloc(len+1);
737fc89c0fbSmrg
738fc89c0fbSmrg    memcpy(data, string, len);
739fc89c0fbSmrg    data[len] = '\0';
740fc89c0fbSmrg
741fc89c0fbSmrg    result = Format_String(data);
742fc89c0fbSmrg    free(data);
743fc89c0fbSmrg
744fc89c0fbSmrg    return result;
745fc89c0fbSmrg}
746fc89c0fbSmrg
74791ec45ceSmrgstatic int
74891ec45ceSmrgis_utf8_locale (void)
74991ec45ceSmrg{
75091ec45ceSmrg#ifdef HAVE_LANGINFO_H
75191ec45ceSmrg    char *charmap = nl_langinfo (CODESET);
75291ec45ceSmrg
75391ec45ceSmrg    return charmap && strcmp (charmap, "UTF-8") == 0;
75491ec45ceSmrg#else
75591ec45ceSmrg    return 0;
75691ec45ceSmrg#endif
75791ec45ceSmrg}
75891ec45ceSmrg
75991ec45ceSmrgstatic const char *
76091ec45ceSmrgFormat_Icons (const unsigned long *icon, int len)
76191ec45ceSmrg{
76291ec45ceSmrg    char *result = NULL, *tail = NULL;
76391ec45ceSmrg    int alloced;
76491ec45ceSmrg    const unsigned long *end = icon + len / sizeof (unsigned long);
76591ec45ceSmrg
76691ec45ceSmrg    alloced = 0;
76791ec45ceSmrg
76891ec45ceSmrg    while (icon < end)
76991ec45ceSmrg    {
77091ec45ceSmrg	unsigned long width, height;
77191ec45ceSmrg	int w, h;
77291ec45ceSmrg	int offset;
77391ec45ceSmrg
77491ec45ceSmrg	width = *icon++;
77591ec45ceSmrg	height = *icon++;
77691ec45ceSmrg
77791ec45ceSmrg	offset = (tail - result);
77891ec45ceSmrg
77991ec45ceSmrg	alloced += 80;				/* For the header */
78091ec45ceSmrg	alloced += (width*4 + 8) * height;	/* For the rows (plus padding) */
78191ec45ceSmrg
78291ec45ceSmrg	result = Realloc (result, alloced);
78391ec45ceSmrg	tail = &result[offset];
78491ec45ceSmrg
78591ec45ceSmrg	if (end - icon < width * height)
78691ec45ceSmrg	    break;
78791ec45ceSmrg
78891ec45ceSmrg	tail += sprintf (tail, "\tIcon (%lu x %lu):\n", width, height);
78991ec45ceSmrg
79091ec45ceSmrg	if (width > 144 || height > 144)
79191ec45ceSmrg	{
79291ec45ceSmrg	    tail += sprintf (tail, "\t(not shown)");
79391ec45ceSmrg	    icon += width * height;
79491ec45ceSmrg	    continue;
79591ec45ceSmrg	}
79691ec45ceSmrg
79791ec45ceSmrg	for (h = 0; h < height; ++h)
79891ec45ceSmrg	{
79991ec45ceSmrg	    tail += sprintf (tail, "\t");
80091ec45ceSmrg
80191ec45ceSmrg	    for (w = 0; w < width; ++w)
80291ec45ceSmrg	    {
80391ec45ceSmrg		unsigned char a, r, g, b;
80491ec45ceSmrg		unsigned long pixel = *icon++;
80591ec45ceSmrg		unsigned long brightness;
80691ec45ceSmrg
80791ec45ceSmrg		a = (pixel & 0xff000000) >> 24;
80891ec45ceSmrg		r = (pixel & 0x00ff0000) >> 16;
80991ec45ceSmrg		g = (pixel & 0x0000ff00) >> 8;
81091ec45ceSmrg		b = (pixel & 0x000000ff);
81191ec45ceSmrg
81291ec45ceSmrg		brightness =
81391ec45ceSmrg		    (a / 255.0) * (1000 - ((299 * (r / 255.0)) +
81491ec45ceSmrg					   (587 * (g / 255.0)) +
81591ec45ceSmrg					   (114 * (b / 255.0))));
81691ec45ceSmrg
81791ec45ceSmrg		if (is_utf8_locale())
81891ec45ceSmrg		{
81991ec45ceSmrg		    static const char palette[][4] =
82091ec45ceSmrg		    {
82191ec45ceSmrg			" ",
82291ec45ceSmrg			"\342\226\221",		/* 25% */
82391ec45ceSmrg			"\342\226\222",		/* 50% */
82491ec45ceSmrg			"\342\226\223",		/* 75% */
82591ec45ceSmrg			"\342\226\210",		/* 100% */
82691ec45ceSmrg		    };
82791ec45ceSmrg		    int idx;
82891ec45ceSmrg
82991ec45ceSmrg		    idx = (brightness * ((sizeof (palette)/sizeof(palette[0])) - 1)) / 1000;
83091ec45ceSmrg
83191ec45ceSmrg		    tail += sprintf (tail, "%s", palette[idx]);
83291ec45ceSmrg		}
83391ec45ceSmrg		else
83491ec45ceSmrg		{
83591ec45ceSmrg		    static const char palette[] =
83691ec45ceSmrg			" .'`,^:\";~-_+<>i!lI?/\\|()1{}[]rcvunxzjftLCJUYXZO0Qoahkbdpqwm*WMB8&%$#@";
83791ec45ceSmrg		    int idx;
83891ec45ceSmrg
83991ec45ceSmrg		    idx = (brightness * (sizeof(palette) - 2)) / 1000;
84091ec45ceSmrg
84191ec45ceSmrg		    *tail++ = palette[idx];
84291ec45ceSmrg		}
84391ec45ceSmrg	    }
84491ec45ceSmrg
84591ec45ceSmrg	    tail += sprintf (tail, "\n");
84691ec45ceSmrg	}
84791ec45ceSmrg
84891ec45ceSmrg	tail += sprintf (tail, "\n");
84991ec45ceSmrg    }
85091ec45ceSmrg
85191ec45ceSmrg    return result;
85291ec45ceSmrg}
85391ec45ceSmrg
854fc89c0fbSmrgstatic const char *
855fc89c0fbSmrgFormat_Len_Text (const char *string, int len, Atom encoding)
856fc89c0fbSmrg{
857fc89c0fbSmrg    XTextProperty textprop;
858fc89c0fbSmrg    char **list;
859fc89c0fbSmrg    int count;
860fc89c0fbSmrg
861fc89c0fbSmrg    /* Try to convert to local encoding. */
862fc89c0fbSmrg    textprop.encoding = encoding;
863fc89c0fbSmrg    textprop.format = 8;
864fc89c0fbSmrg    textprop.value = (unsigned char *) string;
865fc89c0fbSmrg    textprop.nitems = len;
866fc89c0fbSmrg    if (XmbTextPropertyToTextList(dpy, &textprop, &list, &count) == Success) {
867fc89c0fbSmrg	_buf_ptr = _formatting_buffer;
868fc89c0fbSmrg	_buf_len = MAXSTR;
869fc89c0fbSmrg	*_buf_ptr++ = '"';
870fc89c0fbSmrg	while (count > 0) {
871fc89c0fbSmrg	    string = *list++;
872fc89c0fbSmrg	    len = strlen(string);
873fc89c0fbSmrg	    while (len > 0) {
874fc89c0fbSmrg		wchar_t wc;
875fc89c0fbSmrg		int n = mbtowc(&wc, string, len);
876fc89c0fbSmrg		if (n > 0 && iswprint(wc)) {
877fc89c0fbSmrg		    if (_buf_len >= n) {
878fc89c0fbSmrg			memcpy(_buf_ptr, string, n);
879fc89c0fbSmrg			_buf_ptr += n;
880fc89c0fbSmrg			_buf_len -= n;
881fc89c0fbSmrg		    }
882fc89c0fbSmrg		    string += n;
883fc89c0fbSmrg		    len -= n;
884fc89c0fbSmrg		} else {
885fc89c0fbSmrg		    _put_char('\\');
886fc89c0fbSmrg		    snprintf(_buf_ptr, _buf_len, "%03o", (unsigned char) *string);
887fc89c0fbSmrg		    _buf_ptr += 3;
888fc89c0fbSmrg		    _buf_len -= 3;
889fc89c0fbSmrg		    string++;
890fc89c0fbSmrg		    len--;
891fc89c0fbSmrg		}
892fc89c0fbSmrg	    }
893fc89c0fbSmrg	    count--;
894fc89c0fbSmrg	    if (count > 0) {
895fc89c0fbSmrg		snprintf(_buf_ptr, _buf_len, "\\000");
896fc89c0fbSmrg	        _buf_ptr += 4;
897fc89c0fbSmrg		_buf_len -= 4;
898fc89c0fbSmrg	    }
899fc89c0fbSmrg	}
900fc89c0fbSmrg	*_buf_ptr++ = '"';
901fc89c0fbSmrg	*_buf_ptr++ = '\0';
902fc89c0fbSmrg	return _formatting_buffer;
903fc89c0fbSmrg    } else
904fc89c0fbSmrg	return Format_Len_String(string, len);
905fc89c0fbSmrg}
906fc89c0fbSmrg
907fc89c0fbSmrg/*
908fc89c0fbSmrg *
909fc89c0fbSmrg * The Format Manager: a group of routines to manage "formats"
910fc89c0fbSmrg *
911fc89c0fbSmrg */
912fc89c0fbSmrg
913fc89c0fbSmrgstatic int
914fc89c0fbSmrgIs_A_Format (const char *string)
915fc89c0fbSmrg{
916fc89c0fbSmrg    return isdigit((unsigned char) string[0]);
917fc89c0fbSmrg}
918fc89c0fbSmrg
919fc89c0fbSmrgstatic int
920fc89c0fbSmrgGet_Format_Size (const char *format)
921fc89c0fbSmrg{
922fc89c0fbSmrg    long size;
923fc89c0fbSmrg
924fc89c0fbSmrg    Scan_Long(format, &size);
925fc89c0fbSmrg
926fc89c0fbSmrg    /* Check for legal sizes */
927fc89c0fbSmrg    if (size != 0 && size != 8 && size != 16 && size != 32)
928fc89c0fbSmrg	Fatal_Error("bad format: %s", format);
929fc89c0fbSmrg
930fc89c0fbSmrg    return (int) size;
931fc89c0fbSmrg}
932fc89c0fbSmrg
933fc89c0fbSmrgstatic char
934fc89c0fbSmrgGet_Format_Char (const char *format, int i)
935fc89c0fbSmrg{
936fc89c0fbSmrg    long size;
937fc89c0fbSmrg
938fc89c0fbSmrg    /* Remove # at front of format */
939fc89c0fbSmrg    format = Scan_Long(format, &size);
940fc89c0fbSmrg    if (!*format)
941fc89c0fbSmrg	Fatal_Error("bad format: %s", format);
942fc89c0fbSmrg
943fc89c0fbSmrg    /* Last character repeats forever... */
944fc89c0fbSmrg    if (i >= (int)strlen(format))
945fc89c0fbSmrg	i = strlen(format)-1;
946fc89c0fbSmrg
947fc89c0fbSmrg    return format[i];
948fc89c0fbSmrg}
949fc89c0fbSmrg
950fc89c0fbSmrgstatic const char *
951fc89c0fbSmrgFormat_Thunk (thunk t, char format_char)
952fc89c0fbSmrg{
953fc89c0fbSmrg    long value;
954fc89c0fbSmrg    value = t.value;
955fc89c0fbSmrg
956fc89c0fbSmrg    switch (format_char) {
957fc89c0fbSmrg      case 's':
958fc89c0fbSmrg	return Format_Len_String(t.extra_value, (int)t.value);
959fc89c0fbSmrg      case 't':
960fc89c0fbSmrg	return Format_Len_Text(t.extra_value, (int)t.value, t.extra_encoding);
961fc89c0fbSmrg      case 'x':
962fc89c0fbSmrg	return Format_Hex(value);
963fc89c0fbSmrg      case 'c':
964fc89c0fbSmrg	return Format_Unsigned(value);
965fc89c0fbSmrg      case 'i':
966fc89c0fbSmrg	return Format_Signed(value);
967fc89c0fbSmrg      case 'b':
968fc89c0fbSmrg	return Format_Bool(value);
969fc89c0fbSmrg      case 'm':
970fc89c0fbSmrg	return Format_Mask_Word(value);
971fc89c0fbSmrg      case 'a':
972fc89c0fbSmrg	return Format_Atom(value);
97391ec45ceSmrg      case 'o':
97491ec45ceSmrg	  return Format_Icons((const unsigned long *)t.extra_value, (int)t.value);
975fc89c0fbSmrg      default:
976fc89c0fbSmrg	Fatal_Error("bad format character: %c", format_char);
977fc89c0fbSmrg    }
978fc89c0fbSmrg}
979fc89c0fbSmrg
980fc89c0fbSmrgstatic const char *
981fc89c0fbSmrgFormat_Thunk_I (thunk *thunks, const char *format, int i)
982fc89c0fbSmrg{
983fc89c0fbSmrg    if (i >= thunks->thunk_count)
984fc89c0fbSmrg	return "<field not available>";
985fc89c0fbSmrg
986fc89c0fbSmrg    return Format_Thunk(thunks[i], Get_Format_Char(format, i));
987fc89c0fbSmrg}
988fc89c0fbSmrg
989fc89c0fbSmrgstatic long
990fc89c0fbSmrgMask_Word (thunk *thunks, const char *format)
991fc89c0fbSmrg{
992fc89c0fbSmrg    int j;
993fc89c0fbSmrg
994fc89c0fbSmrg    for (j = 0; j  < (int)strlen(format); j++)
995fc89c0fbSmrg	if (Get_Format_Char(format, j) == 'm')
996fc89c0fbSmrg	    return thunks[j].value;
997fc89c0fbSmrg    return 0;
998fc89c0fbSmrg}
999fc89c0fbSmrg
1000fc89c0fbSmrg/*
1001fc89c0fbSmrg *
1002fc89c0fbSmrg * The Display Format Manager:
1003fc89c0fbSmrg *
1004fc89c0fbSmrg */
1005fc89c0fbSmrg
1006fc89c0fbSmrgstatic int
1007fc89c0fbSmrgIs_A_DFormat (const char *string)
1008fc89c0fbSmrg{
1009fc89c0fbSmrg    return string[0] && string[0] != '-'
1010fc89c0fbSmrg	   && !(isalpha((unsigned char) string[0]) || string[0] == '_');
1011fc89c0fbSmrg}
1012fc89c0fbSmrg
1013fc89c0fbSmrgstatic const char *
1014fc89c0fbSmrgHandle_Backslash (const char *dformat)
1015fc89c0fbSmrg{
1016fc89c0fbSmrg    char c;
1017fc89c0fbSmrg    unsigned long i;
1018fc89c0fbSmrg
1019fc89c0fbSmrg    if (!(c = *(dformat++)))
1020fc89c0fbSmrg	return dformat;
1021fc89c0fbSmrg
1022fc89c0fbSmrg    switch (c) {
1023fc89c0fbSmrg      case 'n':
1024fc89c0fbSmrg	putchar('\n');
1025fc89c0fbSmrg	break;
1026fc89c0fbSmrg      case 't':
1027fc89c0fbSmrg	putchar('\t');
1028fc89c0fbSmrg	break;
1029fc89c0fbSmrg      case '0':
1030fc89c0fbSmrg      case '1':
1031fc89c0fbSmrg      case '2':
1032fc89c0fbSmrg      case '3':
1033fc89c0fbSmrg      case '4':
1034fc89c0fbSmrg      case '5':
1035fc89c0fbSmrg      case '6':
1036fc89c0fbSmrg      case '7':
1037fc89c0fbSmrg	dformat = Scan_Octal(dformat, &i);
1038fc89c0fbSmrg	putchar((int) i);
1039fc89c0fbSmrg	break;
1040fc89c0fbSmrg      default:
1041fc89c0fbSmrg	putchar(c);
1042fc89c0fbSmrg	break;
1043fc89c0fbSmrg    }
1044fc89c0fbSmrg    return dformat;
1045fc89c0fbSmrg}
1046fc89c0fbSmrg
1047fc89c0fbSmrgstatic const char *
1048fc89c0fbSmrgHandle_Dollar_sign (const char *dformat, thunk *thunks, const char *format)
1049fc89c0fbSmrg{
1050fc89c0fbSmrg    long i;
1051fc89c0fbSmrg
1052fc89c0fbSmrg    dformat = Scan_Long(dformat, &i);
1053fc89c0fbSmrg
1054fc89c0fbSmrg    if (dformat[0] == '+') {
1055fc89c0fbSmrg	int seen = 0;
1056fc89c0fbSmrg	dformat++;
1057fc89c0fbSmrg	for (; i < thunks->thunk_count; i++) {
1058fc89c0fbSmrg	    if (seen)
1059fc89c0fbSmrg		printf(", ");
1060fc89c0fbSmrg	    seen = 1;
1061fc89c0fbSmrg	    printf("%s", Format_Thunk_I(thunks, format, (int) i));
1062fc89c0fbSmrg	}
1063fc89c0fbSmrg    } else
1064fc89c0fbSmrg	printf("%s", Format_Thunk_I(thunks, format, (int) i));
1065fc89c0fbSmrg
1066fc89c0fbSmrg    return dformat;
1067fc89c0fbSmrg}
1068fc89c0fbSmrg
1069fc89c0fbSmrgstatic int
1070fc89c0fbSmrgMask_Bit_I (thunk *thunks, const char *format, int i)
1071fc89c0fbSmrg{
1072fc89c0fbSmrg    long value;
1073fc89c0fbSmrg
1074fc89c0fbSmrg    value = Mask_Word(thunks, format);
1075fc89c0fbSmrg
1076fc89c0fbSmrg    value = value & (1L<<i);
1077fc89c0fbSmrg    if (value)
1078fc89c0fbSmrg	value = 1;
1079fc89c0fbSmrg    return value;
1080fc89c0fbSmrg}
1081fc89c0fbSmrg
1082fc89c0fbSmrgstatic const char *
1083fc89c0fbSmrgScan_Term (const char *string, thunk *thunks, const char *format, long *value)
1084fc89c0fbSmrg{
1085fc89c0fbSmrg    long i;
1086fc89c0fbSmrg
1087fc89c0fbSmrg    *value = 0;
1088fc89c0fbSmrg
1089fc89c0fbSmrg    if (isdigit((unsigned char) *string))
1090fc89c0fbSmrg	string = Scan_Long(string, value);
1091fc89c0fbSmrg    else if (*string == '$') {
1092fc89c0fbSmrg	string = Scan_Long(++string, &i);
1093fc89c0fbSmrg	if (i >= thunks->thunk_count)
1094fc89c0fbSmrg	    i = thunks->thunk_count;
1095fc89c0fbSmrg	*value = thunks[i].value;
1096fc89c0fbSmrg    } else if (*string == 'm') {
1097fc89c0fbSmrg	string = Scan_Long(++string, &i);
1098fc89c0fbSmrg	*value = Mask_Bit_I(thunks, format, (int) i);
1099fc89c0fbSmrg    } else
1100fc89c0fbSmrg	Fatal_Error("Bad term: %s.", string);
1101fc89c0fbSmrg
1102fc89c0fbSmrg    return string;
1103fc89c0fbSmrg}
1104fc89c0fbSmrg
1105fc89c0fbSmrgstatic const char *
1106fc89c0fbSmrgScan_Exp (const char *string, thunk *thunks, const char *format, long *value)
1107fc89c0fbSmrg{
1108fc89c0fbSmrg    long temp;
1109fc89c0fbSmrg
1110fc89c0fbSmrg    if (string[0] == '(') {
1111fc89c0fbSmrg	string = Scan_Exp(++string, thunks, format, value);
1112fc89c0fbSmrg	if (string[0]!=')')
1113fc89c0fbSmrg	    Fatal_Error("Missing ')'");
1114fc89c0fbSmrg	return ++string;
1115fc89c0fbSmrg    }
1116fc89c0fbSmrg    if (string[0] == '!') {
1117fc89c0fbSmrg	string = Scan_Exp(++string, thunks, format, value);
1118fc89c0fbSmrg	*value = !*value;
1119fc89c0fbSmrg	return string;
1120fc89c0fbSmrg    }
1121fc89c0fbSmrg
1122fc89c0fbSmrg    string = Scan_Term(string, thunks, format, value);
1123fc89c0fbSmrg
1124fc89c0fbSmrg    if (string[0] == '=') {
1125fc89c0fbSmrg	string = Scan_Exp(++string, thunks, format, &temp);
1126fc89c0fbSmrg	*value = *value == temp;
1127fc89c0fbSmrg    }
1128fc89c0fbSmrg
1129fc89c0fbSmrg    return string;
1130fc89c0fbSmrg}
1131fc89c0fbSmrg
1132fc89c0fbSmrgstatic const char *
1133fc89c0fbSmrgHandle_Question_Mark (const char *dformat, thunk *thunks, const char *format)
1134fc89c0fbSmrg{
1135fc89c0fbSmrg    long true;
1136fc89c0fbSmrg
1137fc89c0fbSmrg    dformat = Scan_Exp(dformat, thunks, format, &true);
1138fc89c0fbSmrg
1139fc89c0fbSmrg    if (*dformat != '(')
1140fc89c0fbSmrg	Fatal_Error("Bad conditional: '(' expected: %s.", dformat);
1141fc89c0fbSmrg    ++dformat;
1142fc89c0fbSmrg
1143fc89c0fbSmrg    if (!true)
1144fc89c0fbSmrg	dformat = Skip_Past_Right_Paren(dformat);
1145fc89c0fbSmrg
1146fc89c0fbSmrg    return dformat;
1147fc89c0fbSmrg}
1148fc89c0fbSmrg
1149fc89c0fbSmrgstatic void
1150fc89c0fbSmrgDisplay_Property (thunk *thunks, const char *dformat, const char *format)
1151fc89c0fbSmrg{
1152fc89c0fbSmrg    char c;
1153fc89c0fbSmrg
1154fc89c0fbSmrg    while ((c = *(dformat++)))
1155fc89c0fbSmrg	switch (c) {
1156fc89c0fbSmrg	  case ')':
1157fc89c0fbSmrg	    continue;
1158fc89c0fbSmrg	  case '\\':
1159fc89c0fbSmrg	    dformat = Handle_Backslash(dformat);
1160fc89c0fbSmrg	    continue;
1161fc89c0fbSmrg	  case '$':
1162fc89c0fbSmrg	    dformat = Handle_Dollar_sign(dformat, thunks, format);
1163fc89c0fbSmrg	    continue;
1164fc89c0fbSmrg	  case '?':
1165fc89c0fbSmrg	    dformat = Handle_Question_Mark(dformat, thunks, format);
1166fc89c0fbSmrg	    continue;
1167fc89c0fbSmrg	  default:
1168fc89c0fbSmrg	    putchar(c);
1169fc89c0fbSmrg	    continue;
1170fc89c0fbSmrg	}
1171fc89c0fbSmrg}
1172fc89c0fbSmrg
1173fc89c0fbSmrg/*
1174fc89c0fbSmrg *
1175fc89c0fbSmrg * Routines to convert property data to thunks
1176fc89c0fbSmrg *
1177fc89c0fbSmrg */
1178fc89c0fbSmrg
1179fc89c0fbSmrgstatic long
1180fc89c0fbSmrgExtract_Value (const char **pointer, int *length, int size, int signedp)
1181fc89c0fbSmrg{
1182fc89c0fbSmrg    long value;
1183fc89c0fbSmrg
1184fc89c0fbSmrg    switch (size) {
1185fc89c0fbSmrg      case 8:
1186fc89c0fbSmrg	if (signedp)
1187fc89c0fbSmrg	    value = * (const signed char *) *pointer;
1188fc89c0fbSmrg	else
1189fc89c0fbSmrg	    value = * (const unsigned char *) *pointer;
1190fc89c0fbSmrg	*pointer += 1;
1191fc89c0fbSmrg	*length -= 1;
1192fc89c0fbSmrg	break;
1193fc89c0fbSmrg      case 16:
1194fc89c0fbSmrg	if (signedp)
1195fc89c0fbSmrg	    value = * (const short *) *pointer;
1196fc89c0fbSmrg	else
1197fc89c0fbSmrg	    value = * (const unsigned short *) *pointer;
1198fc89c0fbSmrg	*pointer += sizeof(short);
1199fc89c0fbSmrg	*length -= sizeof(short);
1200fc89c0fbSmrg	break;
1201fc89c0fbSmrg      case 32:
1202fc89c0fbSmrg	if (signedp)
1203fc89c0fbSmrg	    value = * (const long *) *pointer;
1204fc89c0fbSmrg	else
1205fc89c0fbSmrg	    value = * (const unsigned long *) *pointer & 0xffffffff;
1206fc89c0fbSmrg	*pointer += sizeof(long);
1207fc89c0fbSmrg	*length -= sizeof(long);
1208fc89c0fbSmrg	break;
1209fc89c0fbSmrg      default:
1210fc89c0fbSmrg	abort();
1211fc89c0fbSmrg    }
1212fc89c0fbSmrg    return value;
1213fc89c0fbSmrg}
1214fc89c0fbSmrg
1215fc89c0fbSmrgstatic long
1216fc89c0fbSmrgExtract_Len_String (const char **pointer, int *length, int size, const char **string)
1217fc89c0fbSmrg{
1218fc89c0fbSmrg    int len;
1219fc89c0fbSmrg
1220fc89c0fbSmrg    if (size != 8)
1221fc89c0fbSmrg	Fatal_Error("can't use format character 's' with any size except 8.");
1222fc89c0fbSmrg    len = 0; *string = *pointer;
1223fc89c0fbSmrg    while ((len++, --*length, *((*pointer)++)) && *length>0);
1224fc89c0fbSmrg
1225fc89c0fbSmrg    return len;
1226fc89c0fbSmrg}
1227fc89c0fbSmrg
122891ec45ceSmrgstatic long
122991ec45ceSmrgExtract_Icon (const char **pointer, int *length, int size, const char **icon)
123091ec45ceSmrg{
123191ec45ceSmrg    int len = 0;
123291ec45ceSmrg
123391ec45ceSmrg    if (size != 32)
123491ec45ceSmrg	Fatal_Error("can't use format character 'o' with any size except 32.");
123591ec45ceSmrg
123691ec45ceSmrg    len = *length;
123791ec45ceSmrg    *icon = *pointer;
123891ec45ceSmrg    *length = 0;
123991ec45ceSmrg    return len;
124091ec45ceSmrg}
124191ec45ceSmrg
1242fc89c0fbSmrgstatic thunk *
1243fc89c0fbSmrgBreak_Down_Property (const char *pointer, int length, Atom type, const char *format, int size)
1244fc89c0fbSmrg{
1245fc89c0fbSmrg    thunk *thunks;
1246fc89c0fbSmrg    thunk t;
1247fc89c0fbSmrg    int i;
1248fc89c0fbSmrg    char format_char;
1249fc89c0fbSmrg
1250fc89c0fbSmrg    thunks = Create_Thunk_List();
1251fc89c0fbSmrg    i = 0;
1252fc89c0fbSmrg
1253fc89c0fbSmrg    while (length >= size/8) {
1254fc89c0fbSmrg	format_char = Get_Format_Char(format, i);
1255fc89c0fbSmrg	if (format_char == 's')
1256fc89c0fbSmrg	    t.value = Extract_Len_String(&pointer,&length,size,&t.extra_value);
1257fc89c0fbSmrg	else if (format_char == 't') {
1258fc89c0fbSmrg	    t.extra_encoding = type;
1259fc89c0fbSmrg	    t.value = Extract_Len_String(&pointer,&length,size,&t.extra_value);
126091ec45ceSmrg	}
126191ec45ceSmrg	else if (format_char == 'o')
126291ec45ceSmrg	    t.value = Extract_Icon (&pointer,&length,size,&t.extra_value);
126391ec45ceSmrg	else
1264fc89c0fbSmrg	    t.value = Extract_Value(&pointer,&length,size,format_char=='i');
1265fc89c0fbSmrg	thunks = Add_Thunk(thunks, t);
1266fc89c0fbSmrg	i++;
1267fc89c0fbSmrg    }
1268fc89c0fbSmrg
1269fc89c0fbSmrg    return thunks;
1270fc89c0fbSmrg}
1271fc89c0fbSmrg
1272fc89c0fbSmrg/*
1273fc89c0fbSmrg * Variables set by main()
1274fc89c0fbSmrg */
1275fc89c0fbSmrg
1276fc89c0fbSmrgstatic Window target_win = 0;
1277fc89c0fbSmrgstatic int notype = 0;
1278fc89c0fbSmrgstatic int max_len = MAXSTR;
1279fc89c0fbSmrgstatic XFontStruct *font;
1280fc89c0fbSmrgstatic unsigned long _font_prop;
1281fc89c0fbSmrg
1282fc89c0fbSmrg/*
1283fc89c0fbSmrg *
1284fc89c0fbSmrg * Other Stuff (temp.):
1285fc89c0fbSmrg *
1286fc89c0fbSmrg */
1287fc89c0fbSmrg
1288fc89c0fbSmrgstatic const char *
1289fc89c0fbSmrgGet_Font_Property_Data_And_Type (Atom atom,
1290fc89c0fbSmrg                                 long *length, Atom *type, int *size)
1291fc89c0fbSmrg{
1292fc89c0fbSmrg    int i;
1293fc89c0fbSmrg
1294fc89c0fbSmrg    *type = None;
1295fc89c0fbSmrg
1296fc89c0fbSmrg    for (i = 0; i < font->n_properties; i++)
1297fc89c0fbSmrg	if (atom == font->properties[i].name) {
1298fc89c0fbSmrg	    _font_prop = font->properties[i].card32;
1299fc89c0fbSmrg	    *length = sizeof(long);
1300fc89c0fbSmrg	    *size = 32;
1301fc89c0fbSmrg	    return (const char *) &_font_prop;
1302fc89c0fbSmrg	}
1303fc89c0fbSmrg    *size = 0;
1304fc89c0fbSmrg    return NULL;
1305fc89c0fbSmrg}
1306fc89c0fbSmrg
1307fc89c0fbSmrgstatic const char *
1308fc89c0fbSmrgGet_Window_Property_Data_And_Type (Atom atom,
1309fc89c0fbSmrg                                   long *length, Atom *type, int *size)
1310fc89c0fbSmrg{
1311fc89c0fbSmrg    Atom actual_type;
1312fc89c0fbSmrg    int actual_format;
1313fc89c0fbSmrg    unsigned long nitems;
1314fc89c0fbSmrg    unsigned long nbytes;
1315fc89c0fbSmrg    unsigned long bytes_after;
1316fc89c0fbSmrg    unsigned char *prop;
1317fc89c0fbSmrg    int status;
1318fc89c0fbSmrg
1319fc89c0fbSmrg    status = XGetWindowProperty(dpy, target_win, atom, 0, (max_len+3)/4,
1320fc89c0fbSmrg				False, AnyPropertyType, &actual_type,
1321fc89c0fbSmrg				&actual_format, &nitems, &bytes_after,
1322fc89c0fbSmrg				&prop);
1323fc89c0fbSmrg    if (status == BadWindow)
1324fc89c0fbSmrg	Fatal_Error("window id # 0x%lx does not exists!", target_win);
1325fc89c0fbSmrg    if (status != Success)
1326fc89c0fbSmrg	Fatal_Error("XGetWindowProperty failed!");
1327fc89c0fbSmrg
1328fc89c0fbSmrg    if (actual_format == 32)
1329fc89c0fbSmrg	nbytes = sizeof(long);
1330fc89c0fbSmrg    else if (actual_format == 16)
1331fc89c0fbSmrg	nbytes = sizeof(short);
1332fc89c0fbSmrg    else if (actual_format == 8)
1333fc89c0fbSmrg	nbytes = 1;
1334fc89c0fbSmrg    else if (actual_format == 0)
1335fc89c0fbSmrg        nbytes = 0;
1336fc89c0fbSmrg    else
1337fc89c0fbSmrg	abort();
1338fc89c0fbSmrg    *length = min(nitems * nbytes, max_len);
1339fc89c0fbSmrg    *type = actual_type;
1340fc89c0fbSmrg    *size = actual_format;
1341fc89c0fbSmrg    return (const char *)prop;
1342fc89c0fbSmrg}
1343fc89c0fbSmrg
1344fc89c0fbSmrgstatic const char *
1345fc89c0fbSmrgGet_Property_Data_And_Type (Atom atom, long *length, Atom *type, int *size)
1346fc89c0fbSmrg{
1347fc89c0fbSmrg    if (target_win == -1)
1348fc89c0fbSmrg	return Get_Font_Property_Data_And_Type(atom, length, type, size);
1349fc89c0fbSmrg    else
1350fc89c0fbSmrg	return Get_Window_Property_Data_And_Type(atom, length, type, size);
1351fc89c0fbSmrg}
1352fc89c0fbSmrg
1353fc89c0fbSmrgstatic void
1354fc89c0fbSmrgShow_Prop (const char *format, const char *dformat, const char *prop)
1355fc89c0fbSmrg{
1356fc89c0fbSmrg    const char *data;
1357fc89c0fbSmrg    long length;
1358fc89c0fbSmrg    Atom atom, type;
1359fc89c0fbSmrg    thunk *thunks;
1360fc89c0fbSmrg    int size, fsize;
1361fc89c0fbSmrg
1362fc89c0fbSmrg    printf("%s", prop);
1363fc89c0fbSmrg    atom = Parse_Atom(prop, True);
1364fc89c0fbSmrg    if (atom == None) {
1365fc89c0fbSmrg	printf(":  no such atom on any window.\n");
1366fc89c0fbSmrg	return;
1367fc89c0fbSmrg    }
1368fc89c0fbSmrg
1369fc89c0fbSmrg    data = Get_Property_Data_And_Type(atom, &length, &type, &size);
1370fc89c0fbSmrg    if (!size) {
1371fc89c0fbSmrg	puts(":  not found.");
1372fc89c0fbSmrg	return;
1373fc89c0fbSmrg    }
1374fc89c0fbSmrg
1375fc89c0fbSmrg    if (!notype && type != None)
1376fc89c0fbSmrg	printf("(%s)", Format_Atom(type));
1377fc89c0fbSmrg
1378fc89c0fbSmrg    Lookup_Formats(atom, &format, &dformat);
1379fc89c0fbSmrg    if (type != None)
1380fc89c0fbSmrg	Lookup_Formats(type, &format, &dformat);
1381fc89c0fbSmrg    Apply_Default_Formats(&format, &dformat);
1382fc89c0fbSmrg
1383fc89c0fbSmrg    fsize = Get_Format_Size(format);
1384fc89c0fbSmrg    if (fsize != size && fsize != 0) {
1385fc89c0fbSmrg	printf(": Type mismatch: assumed size %d bits, actual size %d bits.\n",
1386fc89c0fbSmrg	       fsize, size);
1387fc89c0fbSmrg	return;
1388fc89c0fbSmrg    }
1389fc89c0fbSmrg
1390fc89c0fbSmrg    thunks = Break_Down_Property(data, (int)length, type, format, size);
1391fc89c0fbSmrg
1392fc89c0fbSmrg    Display_Property(thunks, dformat, format);
1393fc89c0fbSmrg}
1394fc89c0fbSmrg
1395fc89c0fbSmrgstatic void
1396fc89c0fbSmrgShow_All_Props (void)
1397fc89c0fbSmrg{
1398fc89c0fbSmrg    Atom *atoms, atom;
1399fc89c0fbSmrg    const char *name;
1400fc89c0fbSmrg    int count, i;
1401fc89c0fbSmrg
1402fc89c0fbSmrg    if (target_win != -1) {
1403fc89c0fbSmrg	atoms = XListProperties(dpy, target_win, &count);
1404fc89c0fbSmrg	for (i = 0; i < count; i++) {
1405fc89c0fbSmrg	    name = Format_Atom(atoms[i]);
1406fc89c0fbSmrg	    Show_Prop(NULL, NULL, name);
1407fc89c0fbSmrg	}
1408fc89c0fbSmrg    } else
1409fc89c0fbSmrg	for (i = 0; i < font->n_properties; i++) {
1410fc89c0fbSmrg	    atom = font->properties[i].name;
1411fc89c0fbSmrg	    name = Format_Atom(atom);
1412fc89c0fbSmrg	    Show_Prop(NULL, NULL, name);
1413fc89c0fbSmrg	}
1414fc89c0fbSmrg}
1415fc89c0fbSmrg
1416fc89c0fbSmrgstatic thunk *
1417fc89c0fbSmrgHandle_Prop_Requests (int argc, char **argv)
1418fc89c0fbSmrg{
1419fc89c0fbSmrg    char *format, *dformat, *prop;
1420fc89c0fbSmrg    thunk *thunks, t;
1421fc89c0fbSmrg
1422fc89c0fbSmrg    /* if no prop referenced, by default list all properties for given window */
1423fc89c0fbSmrg    if (!argc) {
1424fc89c0fbSmrg	Show_All_Props();
1425fc89c0fbSmrg	return NULL;
1426fc89c0fbSmrg    }
1427fc89c0fbSmrg
1428fc89c0fbSmrg    thunks = Create_Thunk_List();
1429fc89c0fbSmrg
1430fc89c0fbSmrg    while (argc > 0) {
1431fc89c0fbSmrg	format = NULL;
1432fc89c0fbSmrg	dformat = NULL;
1433fc89c0fbSmrg
1434fc89c0fbSmrg	/* Get overriding formats, if any */
1435fc89c0fbSmrg	if (Is_A_Format(argv[0])) {
1436fc89c0fbSmrg	    format = argv++[0]; argc--;
1437fc89c0fbSmrg	    if (!argc) usage();
1438fc89c0fbSmrg	}
1439fc89c0fbSmrg	if (Is_A_DFormat(argv[0])) {
1440fc89c0fbSmrg	    dformat = argv++[0]; argc--;
1441fc89c0fbSmrg	    if (!argc) usage();
1442fc89c0fbSmrg	}
1443fc89c0fbSmrg
1444fc89c0fbSmrg	/* Get property name */
1445fc89c0fbSmrg	prop = argv++[0]; argc--;
1446fc89c0fbSmrg
1447fc89c0fbSmrg	t.propname = prop;
1448fc89c0fbSmrg	t.value = Parse_Atom(prop, True);
1449fc89c0fbSmrg	t.format = format;
1450fc89c0fbSmrg	t.dformat = dformat;
1451fc89c0fbSmrg	if (t.value)
1452fc89c0fbSmrg	    thunks = Add_Thunk(thunks, t);
1453fc89c0fbSmrg	Show_Prop(format, dformat, prop);
1454fc89c0fbSmrg    }
1455fc89c0fbSmrg    return thunks;
1456fc89c0fbSmrg}
1457fc89c0fbSmrg
1458fc89c0fbSmrgstatic void
1459fc89c0fbSmrgRemove_Property (Display *dpy, Window w, const char *propname)
1460fc89c0fbSmrg{
1461fc89c0fbSmrg    Atom id = XInternAtom (dpy, propname, True);
1462fc89c0fbSmrg
1463fc89c0fbSmrg    if (id == None) {
1464fc89c0fbSmrg	fprintf (stderr, "%s:  no such property \"%s\"\n",
1465fc89c0fbSmrg		 program_name, propname);
1466fc89c0fbSmrg	return;
1467fc89c0fbSmrg    }
1468fc89c0fbSmrg    XDeleteProperty (dpy, w, id);
1469fc89c0fbSmrg}
1470fc89c0fbSmrg
1471fc89c0fbSmrgstatic void
1472fc89c0fbSmrgSet_Property (Display *dpy, Window w, const char *propname, const char *value)
1473fc89c0fbSmrg{
1474fc89c0fbSmrg    Atom atom;
1475fc89c0fbSmrg    const char *format;
1476fc89c0fbSmrg    const char *dformat;
1477fc89c0fbSmrg    int size;
1478fc89c0fbSmrg    char format_char;
1479fc89c0fbSmrg    Atom type = 0;
1480fc89c0fbSmrg    unsigned char *data = NULL;
1481fc89c0fbSmrg    int nelements = 0;
1482fc89c0fbSmrg
1483fc89c0fbSmrg    atom = Parse_Atom(propname, False);
1484fc89c0fbSmrg
1485fc89c0fbSmrg    format = dformat = NULL;
1486fc89c0fbSmrg    Lookup_Formats(atom, &format, &dformat);
1487fc89c0fbSmrg    if (format == NULL)
1488fc89c0fbSmrg	Fatal_Error("unsupported conversion for %s", propname);
1489fc89c0fbSmrg
1490fc89c0fbSmrg    size = Get_Format_Size(format);
1491fc89c0fbSmrg
1492fc89c0fbSmrg    format_char = Get_Format_Char(format, 0);
1493fc89c0fbSmrg    switch (format_char) {
1494fc89c0fbSmrg      case 's':
1495fc89c0fbSmrg	if (size != 8)
1496fc89c0fbSmrg	    Fatal_Error("can't use format character 's' with any size except 8.");
1497fc89c0fbSmrg	type = XA_STRING;
1498fc89c0fbSmrg	data = (unsigned char *) value;
1499fc89c0fbSmrg	nelements = strlen(value);
1500fc89c0fbSmrg	break;
1501fc89c0fbSmrg      case 't': {
1502fc89c0fbSmrg	XTextProperty textprop;
1503fc89c0fbSmrg	if (size != 8)
1504fc89c0fbSmrg	    Fatal_Error("can't use format character 't' with any size except 8.");
1505fc89c0fbSmrg	if (XmbTextListToTextProperty(dpy, (char **) &value, 1,
1506fc89c0fbSmrg				      XStdICCTextStyle, &textprop) != Success) {
1507fc89c0fbSmrg	    fprintf(stderr, "cannot convert %s argument to STRING or COMPOUND_TEXT.\n", propname);
1508fc89c0fbSmrg	    return;
1509fc89c0fbSmrg	}
1510fc89c0fbSmrg	type = textprop.encoding;
1511fc89c0fbSmrg	data = textprop.value;
1512fc89c0fbSmrg	nelements = textprop.nitems;
1513fc89c0fbSmrg	break;
1514fc89c0fbSmrg      }
1515fc89c0fbSmrg      case 'x':
1516fc89c0fbSmrg      case 'c': {
1517fc89c0fbSmrg	static unsigned char data8[MAXELEMENTS];
1518fc89c0fbSmrg	static unsigned short data16[MAXELEMENTS];
1519fc89c0fbSmrg	static unsigned long data32[MAXELEMENTS];
1520fc89c0fbSmrg	unsigned long intvalue;
1521fc89c0fbSmrg	char * value2 = strdup(value);
1522fc89c0fbSmrg	char * tmp = strtok(value2,",");
1523fc89c0fbSmrg	nelements = 1;
1524fc89c0fbSmrg	intvalue = strtoul(tmp, NULL, 0);
1525fc89c0fbSmrg	switch(size) {
1526fc89c0fbSmrg	    case 8:
1527fc89c0fbSmrg	        data8[0] = intvalue; data = (unsigned char *) data8; break;
1528fc89c0fbSmrg	    case 16:
1529fc89c0fbSmrg	        data16[0] = intvalue; data = (unsigned char *) data16; break;
1530fc89c0fbSmrg	    case 32:
1531fc89c0fbSmrg	        data32[0] = intvalue; data = (unsigned char *) data32; break;
1532fc89c0fbSmrg	}
1533fc89c0fbSmrg	tmp = strtok(NULL,",");
1534fc89c0fbSmrg	while(tmp != NULL){
1535fc89c0fbSmrg	    intvalue = strtoul(tmp, NULL,0);
1536fc89c0fbSmrg	    switch(size) {
1537fc89c0fbSmrg		case 8:
1538fc89c0fbSmrg	    	    data8[nelements] = intvalue; break;
1539fc89c0fbSmrg		case 16:
1540fc89c0fbSmrg	    	    data16[nelements] = intvalue; break;
1541fc89c0fbSmrg		case 32:
1542fc89c0fbSmrg	    	    data32[nelements] = intvalue; break;
1543fc89c0fbSmrg	    }
1544fc89c0fbSmrg	    nelements++;
1545fc89c0fbSmrg	    if(nelements == MAXELEMENTS){
1546fc89c0fbSmrg		fprintf(stderr, "Maximum number of elements reached (%d). List truncated.\n",MAXELEMENTS);
1547fc89c0fbSmrg		break;
1548fc89c0fbSmrg	    }
1549fc89c0fbSmrg	    tmp = strtok(NULL,",");
1550fc89c0fbSmrg	}
1551fc89c0fbSmrg
1552fc89c0fbSmrg	type = XA_CARDINAL;
1553fc89c0fbSmrg	free(value2);
1554fc89c0fbSmrg	break;
1555fc89c0fbSmrg      }
1556fc89c0fbSmrg      case 'i': {
1557fc89c0fbSmrg	static unsigned char data8[MAXELEMENTS];
1558fc89c0fbSmrg	static unsigned short data16[MAXELEMENTS];
1559fc89c0fbSmrg	static unsigned long data32[MAXELEMENTS];
1560fc89c0fbSmrg	unsigned long intvalue;
1561fc89c0fbSmrg	char * value2 = strdup(value);
1562fc89c0fbSmrg	char * tmp = strtok(value2,",");
1563fc89c0fbSmrg	nelements = 1;
1564fc89c0fbSmrg	intvalue = strtoul(tmp, NULL, 0);
1565fc89c0fbSmrg	switch(size) {
1566fc89c0fbSmrg	    case 8:
1567fc89c0fbSmrg	        data8[0] = intvalue; data = (unsigned char *) data8; break;
1568fc89c0fbSmrg	    case 16:
1569fc89c0fbSmrg	        data16[0] = intvalue; data = (unsigned char *) data16; break;
1570fc89c0fbSmrg	    case 32:
1571fc89c0fbSmrg	        data32[0] = intvalue; data = (unsigned char *) data32; break;
1572fc89c0fbSmrg	}
1573fc89c0fbSmrg	tmp = strtok(NULL,",");
1574fc89c0fbSmrg	while(tmp != NULL){
1575fc89c0fbSmrg	    intvalue = strtoul(tmp, NULL,0);
1576fc89c0fbSmrg	    switch(size) {
1577fc89c0fbSmrg		case 8:
1578fc89c0fbSmrg	    	    data8[nelements] = intvalue; break;
1579fc89c0fbSmrg		case 16:
1580fc89c0fbSmrg	    	    data16[nelements] = intvalue; break;
1581fc89c0fbSmrg		case 32:
1582fc89c0fbSmrg	    	    data32[nelements] = intvalue; break;
1583fc89c0fbSmrg	    }
1584fc89c0fbSmrg	    nelements++;
1585fc89c0fbSmrg	    if(nelements == MAXELEMENTS){
1586fc89c0fbSmrg		fprintf(stderr, "Maximum number of elements reached (%d). List truncated.\n",MAXELEMENTS);
1587fc89c0fbSmrg		break;
1588fc89c0fbSmrg	    }
1589fc89c0fbSmrg	    tmp = strtok(NULL,",");
1590fc89c0fbSmrg	}
1591fc89c0fbSmrg
1592fc89c0fbSmrg	type = XA_INTEGER;
1593fc89c0fbSmrg	free(value2);
1594fc89c0fbSmrg	break;
1595fc89c0fbSmrg      }
1596fc89c0fbSmrg      case 'b': {
1597fc89c0fbSmrg	unsigned long boolvalue;
1598fc89c0fbSmrg	static unsigned char data8;
1599fc89c0fbSmrg	static unsigned short data16;
1600fc89c0fbSmrg	static unsigned long data32;
1601fc89c0fbSmrg	if (!strcmp(value, "True"))
1602fc89c0fbSmrg	    boolvalue = 1;
1603fc89c0fbSmrg	else if (!strcmp(value, "False"))
1604fc89c0fbSmrg	    boolvalue = 0;
1605fc89c0fbSmrg	else {
1606fc89c0fbSmrg	    fprintf(stderr, "cannot convert %s argument to Bool\n", propname);
1607fc89c0fbSmrg	    return;
1608fc89c0fbSmrg	}
1609fc89c0fbSmrg	type = XA_INTEGER;
1610fc89c0fbSmrg	switch (size) {
1611fc89c0fbSmrg	  case 8:
1612fc89c0fbSmrg	    data8 = boolvalue; data = (unsigned char *) &data8; break;
1613fc89c0fbSmrg	  case 16:
1614fc89c0fbSmrg	    data16 = boolvalue; data = (unsigned char *) &data16; break;
1615fc89c0fbSmrg	  case 32: default:
1616fc89c0fbSmrg	    data32 = boolvalue; data = (unsigned char *) &data32; break;
1617fc89c0fbSmrg	}
1618fc89c0fbSmrg	nelements = 1;
1619fc89c0fbSmrg	break;
1620fc89c0fbSmrg      }
1621fc89c0fbSmrg      case 'a': {
1622fc89c0fbSmrg	static Atom avalue;
1623fc89c0fbSmrg	avalue = Parse_Atom(value, False);
1624fc89c0fbSmrg	type = XA_ATOM;
1625fc89c0fbSmrg	data = (unsigned char *) &avalue;
1626fc89c0fbSmrg	nelements = 1;
1627fc89c0fbSmrg	break;
1628fc89c0fbSmrg      }
1629fc89c0fbSmrg      case 'm':
1630fc89c0fbSmrg	/* NYI */
1631fc89c0fbSmrg      default:
1632fc89c0fbSmrg	Fatal_Error("bad format character: %c", format_char);
1633fc89c0fbSmrg    }
1634fc89c0fbSmrg
1635fc89c0fbSmrg    XChangeProperty(dpy, target_win, atom, type, size, PropModeReplace,
1636fc89c0fbSmrg		    data, nelements);
1637fc89c0fbSmrg}
1638fc89c0fbSmrg
1639fc89c0fbSmrg/*
1640fc89c0fbSmrg *
1641fc89c0fbSmrg * Routines for parsing command line:
1642fc89c0fbSmrg *
1643fc89c0fbSmrg */
1644fc89c0fbSmrg
1645fc89c0fbSmrgvoid
1646fc89c0fbSmrgusage (void)
1647fc89c0fbSmrg{
1648fc89c0fbSmrg    static const char help_message[] =
1649fc89c0fbSmrg"where options include:\n"
1650fc89c0fbSmrg"    -grammar                       print out full grammar for command line\n"
1651fc89c0fbSmrg"    -display host:dpy              the X server to contact\n"
1652fc89c0fbSmrg"    -id id                         resource id of window to examine\n"
1653fc89c0fbSmrg"    -name name                     name of window to examine\n"
1654fc89c0fbSmrg"    -font name                     name of font to examine\n"
1655fc89c0fbSmrg"    -remove propname               remove a property\n"
1656fc89c0fbSmrg"    -set propname value            set a property to a given value\n"
1657fc89c0fbSmrg"    -root                          examine the root window\n"
1658fc89c0fbSmrg"    -len n                         display at most n bytes of any property\n"
1659fc89c0fbSmrg"    -notype                        do not display the type field\n"
1660fc89c0fbSmrg"    -fs filename                   where to look for formats for properties\n"
1661fc89c0fbSmrg"    -frame                         don't ignore window manager frames\n"
1662fc89c0fbSmrg"    -f propname format [dformat]   formats to use for property of given name\n"
1663fc89c0fbSmrg"    -spy                           examine window properties forever\n";
1664fc89c0fbSmrg
1665fc89c0fbSmrg
1666fc89c0fbSmrg    fflush (stdout);
1667fc89c0fbSmrg    fprintf (stderr,
1668fc89c0fbSmrg	     "usage:  %s [-options ...] [[format [dformat]] atom] ...\n\n",
1669fc89c0fbSmrg	     program_name);
1670fc89c0fbSmrg    fprintf (stderr, "%s\n", help_message);
1671fc89c0fbSmrg    exit (1);
1672fc89c0fbSmrg}
1673fc89c0fbSmrg
1674fc89c0fbSmrgstatic void
1675fc89c0fbSmrggrammar (void)
1676fc89c0fbSmrg{
1677fc89c0fbSmrg    printf ("Grammar for xprop:\n\n");
1678fc89c0fbSmrg    printf("\t%s [<disp>] [<select option>] <option>* <mapping>* <spec>*",
1679fc89c0fbSmrg	   program_name);
1680fc89c0fbSmrg    printf("\n\n\tdisp ::= -display host:dpy\
1681fc89c0fbSmrg\n\tselect option ::= -root | -id <id> | -font <font> | -name <name>\
1682fc89c0fbSmrg\n\toption ::= -len <n> | -notype | -spy | {-formats|-fs} <format file>\
1683fc89c0fbSmrg\n\tmapping ::= {-f|-format} <atom> <format> [<dformat>]\
1684fc89c0fbSmrg\n\t            | -remove <propname>\
1685fc89c0fbSmrg\n\t            | -set <propname> <value>\
1686fc89c0fbSmrg\n\tspec ::= [<format> [<dformat>]] <atom>\
1687fc89c0fbSmrg\n\tformat ::= {0|8|16|32}{a|b|c|i|m|s|t|x}*\
1688fc89c0fbSmrg\n\tdformat ::= <unit><unit>*             (can't start with a letter or '-')\
1689fc89c0fbSmrg\n\tunit ::= ?<exp>(<unit>*) | $<n> | <display char>\
1690fc89c0fbSmrg\n\texp ::= <term> | <term>=<exp> | !<exp>\
1691fc89c0fbSmrg\n\tterm ::= <n> | $<n> | m<n>\
1692fc89c0fbSmrg\n\tdisplay char ::= <normal char> | \\<non digit char> | \\<octal number>\
1693fc89c0fbSmrg\n\tnormal char ::= <any char except a digit, $, ?, \\, or )>\
1694fc89c0fbSmrg\n\n");
1695fc89c0fbSmrg    exit(0);
1696fc89c0fbSmrg}
1697fc89c0fbSmrg
1698fc89c0fbSmrgstatic void
1699fc89c0fbSmrgParse_Format_Mapping (int *argc, char ***argv)
1700fc89c0fbSmrg{
1701fc89c0fbSmrg#define ARGC (*argc)
1702fc89c0fbSmrg#define ARGV (*argv)
1703fc89c0fbSmrg#define OPTION ARGV[0]
1704fc89c0fbSmrg#define NXTOPT if (++ARGV, --ARGC==0) usage()
1705fc89c0fbSmrg    char *type_name, *format, *dformat;
1706fc89c0fbSmrg
1707fc89c0fbSmrg    NXTOPT; type_name = OPTION;
1708fc89c0fbSmrg
1709fc89c0fbSmrg    NXTOPT; format = OPTION;
1710fc89c0fbSmrg    if (!Is_A_Format(format))
1711fc89c0fbSmrg	Fatal_Error("Bad format: %s.", format);
1712fc89c0fbSmrg
1713fc89c0fbSmrg    dformat = NULL;
1714fc89c0fbSmrg    if (ARGC>1 && Is_A_DFormat(ARGV[1])) {
1715fc89c0fbSmrg	ARGV++; ARGC--; dformat = OPTION;
1716fc89c0fbSmrg    }
1717fc89c0fbSmrg
1718fc89c0fbSmrg    Add_Mapping(Parse_Atom(type_name, False), format, dformat);
1719fc89c0fbSmrg}
1720fc89c0fbSmrg
1721fc89c0fbSmrg/*
1722fc89c0fbSmrg *
1723fc89c0fbSmrg * The Main Program:
1724fc89c0fbSmrg *
1725fc89c0fbSmrg */
1726fc89c0fbSmrg
1727fc89c0fbSmrgstatic int spy = 0;
1728fc89c0fbSmrg
172991ec45ceSmrgstatic int (*old_error_handler)(Display *dpy, XErrorEvent *ev);
173091ec45ceSmrg
173191ec45ceSmrgstatic int spy_error_handler(Display *dpy, XErrorEvent *ev)
173291ec45ceSmrg{
173391ec45ceSmrg    if (ev->error_code == BadWindow || ev->error_code == BadMatch) {
173491ec45ceSmrg	/* Window was destroyed */
173591ec45ceSmrg	puts("");
173691ec45ceSmrg	exit(0);
173791ec45ceSmrg    }
173891ec45ceSmrg
173991ec45ceSmrg    if (old_error_handler)
174091ec45ceSmrg	return old_error_handler(dpy, ev);
174191ec45ceSmrg
174291ec45ceSmrg    return 0;
174391ec45ceSmrg}
174491ec45ceSmrg
1745fc89c0fbSmrgint
1746fc89c0fbSmrgmain (int argc, char **argv)
1747fc89c0fbSmrg{
1748fc89c0fbSmrg    FILE *stream;
1749fc89c0fbSmrg    char *name;
1750fc89c0fbSmrg    thunk *props;
1751fc89c0fbSmrg    thunk *remove_props = NULL;
1752fc89c0fbSmrg    thunk *set_props = NULL;
1753fc89c0fbSmrg    Bool frame_only = False;
1754fc89c0fbSmrg    int n;
1755fc89c0fbSmrg    char **nargv;
1756fc89c0fbSmrg
1757fc89c0fbSmrg    INIT_NAME;
1758fc89c0fbSmrg
1759fc89c0fbSmrg    /* Set locale for XmbTextProptertyToTextList and iswprint(). */
1760fc89c0fbSmrg    setlocale(LC_CTYPE, "");
1761fc89c0fbSmrg
1762fc89c0fbSmrg    /* Handle display name, opening the display */
1763fc89c0fbSmrg    Setup_Display_And_Screen(&argc, argv);
1764fc89c0fbSmrg
1765fc89c0fbSmrg    /* Handle selecting the window to display properties for */
1766fc89c0fbSmrg    target_win = Select_Window_Args(&argc, argv);
1767fc89c0fbSmrg
1768fc89c0fbSmrg    /* Set up default atom to format, dformat mapping */
1769fc89c0fbSmrg    XpropMode = XpropWindowProperties;
1770fc89c0fbSmrg    for (n = argc, nargv = argv; n; nargv++, n--)
1771fc89c0fbSmrg	if (! strcmp(nargv[0], "-font")) {
1772fc89c0fbSmrg	    XpropMode = XpropFontProperties;
1773fc89c0fbSmrg	    break;
1774fc89c0fbSmrg	}
1775fc89c0fbSmrg    Setup_Mapping();
1776fc89c0fbSmrg    if ((name = getenv("XPROPFORMATS"))) {
1777fc89c0fbSmrg	if (!(stream = fopen(name, "r")))
1778fc89c0fbSmrg	    Fatal_Error("unable to open file %s for reading.", name);
1779fc89c0fbSmrg	Read_Mappings(stream);
1780fc89c0fbSmrg	fclose(stream);
1781fc89c0fbSmrg    }
1782fc89c0fbSmrg
1783fc89c0fbSmrg    /* Handle '-' options to setup xprop, select window to work on */
1784fc89c0fbSmrg    while (argv++, --argc>0 && **argv == '-') {
1785fc89c0fbSmrg	if (!strcmp(argv[0], "-"))
1786fc89c0fbSmrg	    continue;
1787fc89c0fbSmrg	if (!strcmp(argv[0], "-grammar")) {
1788fc89c0fbSmrg	    grammar ();
1789fc89c0fbSmrg	    /* NOTREACHED */
1790fc89c0fbSmrg	}
1791fc89c0fbSmrg	if (!strcmp(argv[0], "-notype")) {
1792fc89c0fbSmrg	    notype = 1;
1793fc89c0fbSmrg	    continue;
1794fc89c0fbSmrg	}
1795fc89c0fbSmrg	if (!strcmp(argv[0], "-spy")) {
1796fc89c0fbSmrg	    spy = 1;
1797fc89c0fbSmrg	    continue;
1798fc89c0fbSmrg	}
1799fc89c0fbSmrg	if (!strcmp(argv[0], "-len")) {
1800fc89c0fbSmrg	    if (++argv, --argc == 0) usage();
1801fc89c0fbSmrg	    max_len = atoi(argv[0]);
1802fc89c0fbSmrg	    continue;
1803fc89c0fbSmrg	}
1804fc89c0fbSmrg	if (!strcmp(argv[0], "-formats") || !strcmp(argv[0], "-fs")) {
1805fc89c0fbSmrg	    if (++argv, --argc == 0) usage();
1806fc89c0fbSmrg	    if (!(stream = fopen(argv[0], "r")))
1807fc89c0fbSmrg		Fatal_Error("unable to open file %s for reading.", argv[0]);
1808fc89c0fbSmrg	    Read_Mappings(stream);
1809fc89c0fbSmrg	    fclose(stream);
1810fc89c0fbSmrg	    continue;
1811fc89c0fbSmrg	}
1812fc89c0fbSmrg	if (!strcmp(argv[0], "-font")) {
1813fc89c0fbSmrg	    if (++argv, --argc == 0) usage();
1814fc89c0fbSmrg	    font = Open_Font(argv[0]);
1815fc89c0fbSmrg	    target_win = -1;
1816fc89c0fbSmrg	    continue;
1817fc89c0fbSmrg	}
1818fc89c0fbSmrg	if (!strcmp(argv[0], "-remove")) {
1819fc89c0fbSmrg	    thunk t;
1820fc89c0fbSmrg	    if (++argv, --argc == 0) usage();
1821fc89c0fbSmrg	    t.propname = argv[0];
1822fc89c0fbSmrg	    if (remove_props == NULL) remove_props = Create_Thunk_List();
1823fc89c0fbSmrg	    remove_props = Add_Thunk(remove_props, t);
1824fc89c0fbSmrg	    continue;
1825fc89c0fbSmrg	}
1826fc89c0fbSmrg	if (!strcmp(argv[0], "-set")) {
1827fc89c0fbSmrg	    thunk t;
1828fc89c0fbSmrg	    if (argc < 3) usage();
1829fc89c0fbSmrg	    t.propname = argv[1];
1830fc89c0fbSmrg	    t.extra_value = argv[2];
1831fc89c0fbSmrg	    argv += 3; argc -= 3;
1832fc89c0fbSmrg	    if (set_props == NULL) set_props = Create_Thunk_List();
1833fc89c0fbSmrg	    set_props = Add_Thunk(set_props, t);
1834fc89c0fbSmrg	    continue;
1835fc89c0fbSmrg	}
1836fc89c0fbSmrg	if (!strcmp(argv[0], "-frame")) {
1837fc89c0fbSmrg	    frame_only = True;
1838fc89c0fbSmrg	    continue;
1839fc89c0fbSmrg	}
1840fc89c0fbSmrg	if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "-format")) {
1841fc89c0fbSmrg	    Parse_Format_Mapping(&argc, &argv);
1842fc89c0fbSmrg	    continue;
1843fc89c0fbSmrg	}
1844fc89c0fbSmrg	usage();
1845fc89c0fbSmrg    }
1846fc89c0fbSmrg
1847fc89c0fbSmrg    if ((remove_props != NULL || set_props != NULL) && argc > 0)
1848fc89c0fbSmrg	usage();
1849fc89c0fbSmrg
185091ec45ceSmrg    if (target_win == None)
185191ec45ceSmrg	target_win = Select_Window(dpy, !frame_only);
1852fc89c0fbSmrg
1853fc89c0fbSmrg    if (remove_props != NULL) {
1854fc89c0fbSmrg	int count;
1855fc89c0fbSmrg
1856fc89c0fbSmrg	if (target_win == -1)
1857fc89c0fbSmrg	    Fatal_Error("-remove works only on windows, not fonts");
1858fc89c0fbSmrg
1859fc89c0fbSmrg	count = remove_props->thunk_count;
1860fc89c0fbSmrg	for (; count > 0; remove_props++, count--)
1861fc89c0fbSmrg	    Remove_Property (dpy, target_win, remove_props->propname);
1862fc89c0fbSmrg    }
1863fc89c0fbSmrg
1864fc89c0fbSmrg    if (set_props != NULL) {
1865fc89c0fbSmrg	int count;
1866fc89c0fbSmrg
1867fc89c0fbSmrg	if (target_win == -1)
1868fc89c0fbSmrg	    Fatal_Error("-set works only on windows, not fonts");
1869fc89c0fbSmrg
1870fc89c0fbSmrg	count = set_props->thunk_count;
1871fc89c0fbSmrg	for (; count > 0; set_props++, count--)
1872fc89c0fbSmrg	    Set_Property (dpy, target_win, set_props->propname,
1873fc89c0fbSmrg			  set_props->extra_value);
1874fc89c0fbSmrg    }
1875fc89c0fbSmrg
1876fc89c0fbSmrg    if (remove_props != NULL || set_props != NULL) {
1877fc89c0fbSmrg	XCloseDisplay (dpy);
1878fc89c0fbSmrg	exit (0);
1879fc89c0fbSmrg    }
1880fc89c0fbSmrg
1881fc89c0fbSmrg    props = Handle_Prop_Requests(argc, argv);
1882fc89c0fbSmrg
1883fc89c0fbSmrg    if (spy && target_win != -1) {
1884fc89c0fbSmrg	XEvent event;
1885fc89c0fbSmrg	const char *format, *dformat;
1886fc89c0fbSmrg
188791ec45ceSmrg	XSelectInput(dpy, target_win, PropertyChangeMask | StructureNotifyMask);
188891ec45ceSmrg 	old_error_handler = XSetErrorHandler(spy_error_handler);
1889fc89c0fbSmrg	for (;;) {
189091ec45ceSmrg	    fflush(stdout);
1891fc89c0fbSmrg	    XNextEvent(dpy, &event);
189291ec45ceSmrg 	    if (event.type == DestroyNotify)
189391ec45ceSmrg 		break;
189491ec45ceSmrg 	    if (event.type != PropertyNotify)
189591ec45ceSmrg 		continue;
1896fc89c0fbSmrg	    format = dformat = NULL;
1897fc89c0fbSmrg	    if (props) {
1898fc89c0fbSmrg		int i;
1899fc89c0fbSmrg		for (i = 0; i < props->thunk_count; i++)
1900fc89c0fbSmrg		    if (props[i].value == event.xproperty.atom)
1901fc89c0fbSmrg			break;
1902fc89c0fbSmrg		if (i >= props->thunk_count)
1903fc89c0fbSmrg		    continue;
1904fc89c0fbSmrg		format = props[i].format;
1905fc89c0fbSmrg		dformat = props[i].dformat;
1906fc89c0fbSmrg	    }
1907fc89c0fbSmrg	    Show_Prop(format, dformat, Format_Atom(event.xproperty.atom));
1908fc89c0fbSmrg	}
1909fc89c0fbSmrg    }
1910fc89c0fbSmrg    exit (0);
1911fc89c0fbSmrg}
1912