xprop.c revision f9c28e31
1fc89c0fbSmrg/*
2fc89c0fbSmrg
3fc89c0fbSmrgCopyright 1990, 1998  The Open Group
4fc89c0fbSmrgCopyright (c) 2000  The XFree86 Project, Inc.
5fc89c0fbSmrg
6fc89c0fbSmrgPermission to use, copy, modify, distribute, and sell this software and its
7fc89c0fbSmrgdocumentation for any purpose is hereby granted without fee, provided that
8fc89c0fbSmrgthe above copyright notice appear in all copies and that both that
9fc89c0fbSmrgcopyright notice and this permission notice appear in supporting
10fc89c0fbSmrgdocumentation.
11fc89c0fbSmrg
12fc89c0fbSmrgThe above copyright notice and this permission notice shall be included
13fc89c0fbSmrgin all copies or substantial portions of the Software.
14fc89c0fbSmrg
15fc89c0fbSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16fc89c0fbSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17fc89c0fbSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18fc89c0fbSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
19fc89c0fbSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20fc89c0fbSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21fc89c0fbSmrgOTHER DEALINGS IN THE SOFTWARE.
22fc89c0fbSmrg
23fc89c0fbSmrgExcept as contained in this notice, the name of The Open Group shall
24fc89c0fbSmrgnot be used in advertising or otherwise to promote the sale, use or
25fc89c0fbSmrgother dealings in this Software without prior written authorization
26fc89c0fbSmrgfrom The Open Group.
27fc89c0fbSmrg
28fc89c0fbSmrg*/
29fc89c0fbSmrg
30fc89c0fbSmrg#include "config.h"
31fc89c0fbSmrg
32fc89c0fbSmrg#include <X11/Xlib.h>
33fc89c0fbSmrg#include <X11/Xos.h>
34fc89c0fbSmrg#include <X11/Xfuncs.h>
35fc89c0fbSmrg#include <X11/Xutil.h>
36f9c28e31Smrg#include <sys/ioctl.h>
37fc89c0fbSmrg#include <stdlib.h>
38fc89c0fbSmrg#include <stdio.h>
39fc89c0fbSmrg#include <ctype.h>
40fc89c0fbSmrg#ifdef HAVE_WCHAR_H
41fc89c0fbSmrg#include <wchar.h>
42fc89c0fbSmrg#endif
43fc89c0fbSmrg#ifdef HAVE_WCTYPE_H
44fc89c0fbSmrg#include <wctype.h>
45fc89c0fbSmrg#endif
46fc89c0fbSmrg#include <locale.h>
4791ec45ceSmrg#ifdef HAVE_LANGINFO_H
4891ec45ceSmrg#include <langinfo.h>
4991ec45ceSmrg#endif
50fc89c0fbSmrg
51fc89c0fbSmrg#ifndef HAVE_WCTYPE_H
52fc89c0fbSmrg#define iswprint(x) isprint(x)
53fc89c0fbSmrg#endif
54fc89c0fbSmrg
55fc89c0fbSmrg#include <X11/Xatom.h>
56fc89c0fbSmrg
57fc89c0fbSmrg#include "dsimple.h"
58fc89c0fbSmrg
59fc89c0fbSmrg#define MAXSTR 500000
60fc89c0fbSmrg#define MAXELEMENTS 64
61fc89c0fbSmrg
62fc89c0fbSmrg#ifndef min
63fc89c0fbSmrg#define min(a,b)  ((a) < (b) ? (a) : (b))
64fc89c0fbSmrg#endif
65fc89c0fbSmrg
66fc89c0fbSmrg/* isprint() in "C" locale */
67fc89c0fbSmrg#define c_isprint(c) ((c) >= 0x20 && (c) < 0x7f)
68fc89c0fbSmrg
69f9c28e31Smrgstatic int term_width = 144 + 8;
70f9c28e31Smrg
71fc89c0fbSmrg/*
72fc89c0fbSmrg *
73fc89c0fbSmrg * The Thunk Manager - routines to create, add to, and free thunk lists
74fc89c0fbSmrg *
75fc89c0fbSmrg */
76fc89c0fbSmrg
77fc89c0fbSmrgtypedef struct {
78fc89c0fbSmrg  int thunk_count;
79fc89c0fbSmrg  const char *propname;
80fc89c0fbSmrg  long value;
81fc89c0fbSmrg  Atom extra_encoding;
82fc89c0fbSmrg  const char *extra_value;
83fc89c0fbSmrg  const char *format;
84fc89c0fbSmrg  const char *dformat;
85fc89c0fbSmrg} thunk;
86fc89c0fbSmrg
87fc89c0fbSmrgstatic thunk *
88fc89c0fbSmrgCreate_Thunk_List (void)
89fc89c0fbSmrg{
90fc89c0fbSmrg    thunk *tptr;
91fc89c0fbSmrg
92f4a95042Smrg    tptr = malloc(sizeof(thunk));
93f4a95042Smrg    if (!tptr)
94f4a95042Smrg	Fatal_Error("Out of memory!");
95fc89c0fbSmrg
96fc89c0fbSmrg    tptr->thunk_count = 0;
97fc89c0fbSmrg
98fc89c0fbSmrg    return tptr;
99fc89c0fbSmrg}
100fc89c0fbSmrg
101fc89c0fbSmrgstatic thunk *
102fc89c0fbSmrgAdd_Thunk (thunk *list, thunk t)
103fc89c0fbSmrg{
104fc89c0fbSmrg    int i;
105fc89c0fbSmrg
106fc89c0fbSmrg    i = list->thunk_count;
107fc89c0fbSmrg
108f4a95042Smrg    list = realloc(list, (i+1)*sizeof(thunk));
109fc89c0fbSmrg    if (!list)
110fc89c0fbSmrg	Fatal_Error("Out of memory!");
111fc89c0fbSmrg
112fc89c0fbSmrg    list[i++] = t;
113fc89c0fbSmrg    list->thunk_count = i;
114fc89c0fbSmrg
115fc89c0fbSmrg    return list;
116fc89c0fbSmrg}
117fc89c0fbSmrg
118fc89c0fbSmrg/*
119fc89c0fbSmrg * Misc. routines
120fc89c0fbSmrg */
121fc89c0fbSmrg
122fc89c0fbSmrgstatic int
123fc89c0fbSmrgRead_Char (FILE *stream)
124fc89c0fbSmrg{
125fc89c0fbSmrg    int c;
126fc89c0fbSmrg
127fc89c0fbSmrg    c = getc(stream);
128fc89c0fbSmrg    if (c == EOF)
129fc89c0fbSmrg	Fatal_Error("Bad format file: Unexpected EOF.");
130fc89c0fbSmrg    return c;
131fc89c0fbSmrg}
132fc89c0fbSmrg
133fc89c0fbSmrgstatic void
134fc89c0fbSmrgRead_White_Space (FILE *stream)
135fc89c0fbSmrg{
136fc89c0fbSmrg    int c;
137fc89c0fbSmrg
138fc89c0fbSmrg    while ((c = getc(stream)) == ' ' || c == '\n' || c == '\t');
139fc89c0fbSmrg    ungetc(c, stream);
140fc89c0fbSmrg}
141fc89c0fbSmrg
142fc89c0fbSmrgstatic char _large_buffer[MAXSTR+10];
143fc89c0fbSmrg
144fc89c0fbSmrgstatic char *
145fc89c0fbSmrgRead_Quoted (FILE *stream)
146fc89c0fbSmrg{
147fc89c0fbSmrg    char *ptr;
148fc89c0fbSmrg    int c, length;
149fc89c0fbSmrg
150fc89c0fbSmrg    Read_White_Space(stream);
151fc89c0fbSmrg    if (Read_Char(stream)!='\'')
152fc89c0fbSmrg	Fatal_Error("Bad format file format: missing dformat.");
153fc89c0fbSmrg
154fc89c0fbSmrg    ptr = _large_buffer; length = MAXSTR;
155fc89c0fbSmrg    for (;;) {
156fc89c0fbSmrg	if (length < 0)
157fc89c0fbSmrg	    Fatal_Error("Bad format file format: dformat too long.");
158fc89c0fbSmrg	c = Read_Char(stream);
159fc89c0fbSmrg	if (c == (int) '\'')
160fc89c0fbSmrg	    break;
161fc89c0fbSmrg	ptr++[0] = c; length--;
162fc89c0fbSmrg	if (c == (int) '\\') {
163fc89c0fbSmrg	    c = Read_Char(stream);
164fc89c0fbSmrg	    if (c == '\n') {
165fc89c0fbSmrg		ptr--; length++;
166b5cf802fSmrg	    } else {
167fc89c0fbSmrg		ptr++[0] = c; length--;
168b5cf802fSmrg	    }
169fc89c0fbSmrg	}
170fc89c0fbSmrg    }
171fc89c0fbSmrg    ptr++[0] = '\0';
172fc89c0fbSmrg
173f4a95042Smrg    ptr = strdup(_large_buffer);
174f4a95042Smrg    if (!ptr)
175f4a95042Smrg	Fatal_Error("Out of memory!");
176f4a95042Smrg    return ptr;
177fc89c0fbSmrg}
178fc89c0fbSmrg
179fc89c0fbSmrg/*
180fc89c0fbSmrg *
181fc89c0fbSmrg * Parsing Routines: a group of routines to parse strings into values
182fc89c0fbSmrg *
183fc89c0fbSmrg * Routines: Parse_Atom, Scan_Long, Skip_Past_Right_Paren, Scan_Octal
184fc89c0fbSmrg *
185fc89c0fbSmrg * Routines of the form Parse_XXX take a string which is parsed to a value.
186fc89c0fbSmrg * Routines of the form Scan_XXX take a string, parse the beginning to a value,
187fc89c0fbSmrg * and return the rest of the string.  The value is returned via. the last
188fc89c0fbSmrg * parameter.  All numeric values are longs!
189fc89c0fbSmrg *
190fc89c0fbSmrg */
191fc89c0fbSmrg
192fc89c0fbSmrgstatic const char *
193fc89c0fbSmrgSkip_Digits (const char *string)
194fc89c0fbSmrg{
195fc89c0fbSmrg    while (isdigit((unsigned char) string[0])) string++;
196fc89c0fbSmrg    return string;
197fc89c0fbSmrg}
198fc89c0fbSmrg
199fc89c0fbSmrgstatic const char *
200fc89c0fbSmrgScan_Long (const char *string, long *value)
201fc89c0fbSmrg{
202fc89c0fbSmrg    if (!isdigit((unsigned char) *string))
203fc89c0fbSmrg	Fatal_Error("Bad number: %s.", string);
204fc89c0fbSmrg
205fc89c0fbSmrg    *value = atol(string);
206fc89c0fbSmrg    return Skip_Digits(string);
207fc89c0fbSmrg}
208fc89c0fbSmrg
209fc89c0fbSmrgstatic const char *
210fc89c0fbSmrgScan_Octal (const char *string, unsigned long *value)
211fc89c0fbSmrg{
212fc89c0fbSmrg    if (sscanf(string, "%lo", value)!=1)
213fc89c0fbSmrg	Fatal_Error("Bad octal number: %s.", string);
214fc89c0fbSmrg    return Skip_Digits(string);
215fc89c0fbSmrg}
216fc89c0fbSmrg
217fc89c0fbSmrgstatic Atom
218fc89c0fbSmrgParse_Atom (const char *name, int only_if_exists)
219fc89c0fbSmrg{
220fc89c0fbSmrg    /* may return None = 0 */
221fc89c0fbSmrg    return XInternAtom(dpy, name, only_if_exists);
222fc89c0fbSmrg}
223fc89c0fbSmrg
224fc89c0fbSmrgstatic const char *
225fc89c0fbSmrgSkip_Past_Right_Paren (const char *string)
226fc89c0fbSmrg{
227fc89c0fbSmrg    char c;
228fc89c0fbSmrg    int nesting = 0;
229fc89c0fbSmrg
230fc89c0fbSmrg    while (c = string++[0], c != ')' || nesting)
231fc89c0fbSmrg	switch (c) {
232fc89c0fbSmrg	  case '\0':
233fc89c0fbSmrg	    Fatal_Error("Missing ')'.");
234fc89c0fbSmrg	  case '(':
235fc89c0fbSmrg	    nesting++;
236fc89c0fbSmrg	    break;
237fc89c0fbSmrg	  case ')':
238fc89c0fbSmrg	    nesting--;
239fc89c0fbSmrg	    break;
240fc89c0fbSmrg	  case '\\':
241fc89c0fbSmrg	    string++;
242fc89c0fbSmrg	    break;
243fc89c0fbSmrg	}
244fc89c0fbSmrg    return string;
245fc89c0fbSmrg}
246fc89c0fbSmrg
247fc89c0fbSmrg/*
248fc89c0fbSmrg *
249fc89c0fbSmrg * Atom to format, dformat mapping Manager
250fc89c0fbSmrg *
251fc89c0fbSmrg */
252fc89c0fbSmrg
253fc89c0fbSmrg#define D_FORMAT "0x"              /* Default format for properties */
254fc89c0fbSmrg#define D_DFORMAT " = $0+\n"       /* Default display pattern for properties */
255fc89c0fbSmrg
256fc89c0fbSmrgstatic thunk *_property_formats = NULL;   /* Holds mapping */
257fc89c0fbSmrg
258fc89c0fbSmrgstatic void
259fc89c0fbSmrgApply_Default_Formats (const char **format, const char **dformat)
260fc89c0fbSmrg{
261fc89c0fbSmrg    if (!*format)
262fc89c0fbSmrg	*format = D_FORMAT;
263fc89c0fbSmrg    if (!*dformat)
264fc89c0fbSmrg	*dformat = D_DFORMAT;
265fc89c0fbSmrg}
266fc89c0fbSmrg
267fc89c0fbSmrgstatic void
268fc89c0fbSmrgLookup_Formats (Atom atom, const char **format, const char **dformat)
269fc89c0fbSmrg{
270fc89c0fbSmrg    int i;
271fc89c0fbSmrg
272fc89c0fbSmrg    if (_property_formats)
273fc89c0fbSmrg	for (i = _property_formats->thunk_count-1; i >= 0; i--)
274fc89c0fbSmrg	    if (_property_formats[i].value == atom) {
275fc89c0fbSmrg		if (!*format)
276fc89c0fbSmrg		    *format = _property_formats[i].format;
277fc89c0fbSmrg		if (!*dformat)
278fc89c0fbSmrg		    *dformat = _property_formats[i].dformat;
279fc89c0fbSmrg		break;
280fc89c0fbSmrg	    }
281fc89c0fbSmrg}
282fc89c0fbSmrg
283fc89c0fbSmrgstatic void
284fc89c0fbSmrgAdd_Mapping (Atom atom, const char *format, const char *dformat)
285fc89c0fbSmrg{
286f4a95042Smrg    thunk t = {0};
287fc89c0fbSmrg
288fc89c0fbSmrg    if (!_property_formats)
289fc89c0fbSmrg	_property_formats = Create_Thunk_List();
290fc89c0fbSmrg
291fc89c0fbSmrg    t.value = atom;
292fc89c0fbSmrg    t.format = format;
293fc89c0fbSmrg    t.dformat = dformat;
294fc89c0fbSmrg
295fc89c0fbSmrg    _property_formats = Add_Thunk(_property_formats, t);
296fc89c0fbSmrg}
297fc89c0fbSmrg
298fc89c0fbSmrg/*
299fc89c0fbSmrg *
300fc89c0fbSmrg * Setup_Mapping: Routine to setup default atom to format, dformat mapping:
301fc89c0fbSmrg *
302fc89c0fbSmrg */
303fc89c0fbSmrg
304fc89c0fbSmrgtypedef struct _propertyRec {
305fc89c0fbSmrg    const char *	name;
306fc89c0fbSmrg    Atom		atom;
307fc89c0fbSmrg    const char *	format;
308fc89c0fbSmrg    const char *	dformat;
309fc89c0fbSmrg} propertyRec;
310fc89c0fbSmrg
311fc89c0fbSmrg#define ARC_DFORMAT	":\n"\
312fc89c0fbSmrg"\t\tarc at $0, $1\n"\
313fc89c0fbSmrg"\t\tsize: $2 by $3\n"\
314fc89c0fbSmrg"\t\tfrom angle $4 to angle $5\n"
315fc89c0fbSmrg
316fc89c0fbSmrg#define RECTANGLE_DFORMAT	":\n"\
317fc89c0fbSmrg"\t\tupper left corner: $0, $1\n"\
318fc89c0fbSmrg"\t\tsize: $2 by $3\n"
319fc89c0fbSmrg
320fc89c0fbSmrg#define RGB_COLOR_MAP_DFORMAT	":\n"\
321fc89c0fbSmrg"\t\tcolormap id #: $0\n"\
322fc89c0fbSmrg"\t\tred-max: $1\n"\
323fc89c0fbSmrg"\t\tred-mult: $2\n"\
324fc89c0fbSmrg"\t\tgreen-max: $3\n"\
325fc89c0fbSmrg"\t\tgreen-mult: $4\n"\
326fc89c0fbSmrg"\t\tblue-max: $5\n"\
327fc89c0fbSmrg"\t\tblue-mult: $6\n"\
328fc89c0fbSmrg"\t\tbase-pixel: $7\n"\
329fc89c0fbSmrg"\t\tvisual id #: $8\n"\
330fc89c0fbSmrg"\t\tkill id #: $9\n"
331fc89c0fbSmrg
332fc89c0fbSmrg#define WM_HINTS_DFORMAT	":\n"\
333fc89c0fbSmrg"?m0(\t\tClient accepts input or input focus: $1\n)"\
334fc89c0fbSmrg"?m1(\t\tInitial state is "\
335fc89c0fbSmrg"?$2=0(Don't Care State)"\
336fc89c0fbSmrg"?$2=1(Normal State)"\
337fc89c0fbSmrg"?$2=2(Zoomed State)"\
338fc89c0fbSmrg"?$2=3(Iconic State)"\
339fc89c0fbSmrg"?$2=4(Inactive State)"\
340fc89c0fbSmrg".\n)"\
341fc89c0fbSmrg"?m2(\t\tbitmap id # to use for icon: $3\n)"\
342fc89c0fbSmrg"?m5(\t\tbitmap id # of mask for icon: $7\n)"\
343fc89c0fbSmrg"?m3(\t\twindow id # to use for icon: $4\n)"\
344fc89c0fbSmrg"?m4(\t\tstarting position for icon: $5, $6\n)"\
345fc89c0fbSmrg"?m6(\t\twindow id # of group leader: $8\n)"\
34691ec45ceSmrg"?m8(\t\tThe urgency hint bit is set\n)"
347fc89c0fbSmrg
348fc89c0fbSmrg#define WM_ICON_SIZE_DFORMAT	":\n"\
349fc89c0fbSmrg"\t\tminimum icon size: $0 by $1\n"\
350fc89c0fbSmrg"\t\tmaximum icon size: $2 by $3\n"\
351fc89c0fbSmrg"\t\tincremental size change: $4 by $5\n"
352fc89c0fbSmrg
353fc89c0fbSmrg#define WM_SIZE_HINTS_DFORMAT ":\n"\
354fc89c0fbSmrg"?m0(\t\tuser specified location: $1, $2\n)"\
355fc89c0fbSmrg"?m2(\t\tprogram specified location: $1, $2\n)"\
356fc89c0fbSmrg"?m1(\t\tuser specified size: $3 by $4\n)"\
357fc89c0fbSmrg"?m3(\t\tprogram specified size: $3 by $4\n)"\
358fc89c0fbSmrg"?m4(\t\tprogram specified minimum size: $5 by $6\n)"\
359fc89c0fbSmrg"?m5(\t\tprogram specified maximum size: $7 by $8\n)"\
360fc89c0fbSmrg"?m6(\t\tprogram specified resize increment: $9 by $10\n)"\
361fc89c0fbSmrg"?m7(\t\tprogram specified minimum aspect ratio: $11/$12\n"\
362fc89c0fbSmrg"\t\tprogram specified maximum aspect ratio: $13/$14\n)"\
363fc89c0fbSmrg"?m8(\t\tprogram specified base size: $15 by $16\n)"\
364fc89c0fbSmrg"?m9(\t\twindow gravity: "\
365fc89c0fbSmrg"?$17=0(Forget)"\
366fc89c0fbSmrg"?$17=1(NorthWest)"\
367fc89c0fbSmrg"?$17=2(North)"\
368fc89c0fbSmrg"?$17=3(NorthEast)"\
369fc89c0fbSmrg"?$17=4(West)"\
370fc89c0fbSmrg"?$17=5(Center)"\
371fc89c0fbSmrg"?$17=6(East)"\
372fc89c0fbSmrg"?$17=7(SouthWest)"\
373fc89c0fbSmrg"?$17=8(South)"\
374fc89c0fbSmrg"?$17=9(SouthEast)"\
375fc89c0fbSmrg"?$17=10(Static)"\
376fc89c0fbSmrg"\n)"
377fc89c0fbSmrg
378fc89c0fbSmrg#define WM_STATE_DFORMAT	 ":\n"\
379fc89c0fbSmrg"\t\twindow state: ?$0=0(Withdrawn)?$0=1(Normal)?$0=3(Iconic)\n"\
380fc89c0fbSmrg"\t\ticon window: $1\n"
381fc89c0fbSmrg
382fc89c0fbSmrgstatic propertyRec windowPropTable[] = {
383fc89c0fbSmrg    {"ARC",		XA_ARC,		"16iiccii",   ARC_DFORMAT },
384fc89c0fbSmrg    {"ATOM",		XA_ATOM,	 "32a",	      0 },
385fc89c0fbSmrg    {"BITMAP",		XA_BITMAP,	 "32x",	      ": bitmap id # $0\n" },
386fc89c0fbSmrg    {"CARDINAL",	XA_CARDINAL,	 "0c",	      0 },
387fc89c0fbSmrg    {"COLORMAP",	XA_COLORMAP,	 "32x",	      ": colormap id # $0\n" },
388fc89c0fbSmrg    {"CURSOR",		XA_CURSOR,	 "32x",	      ": cursor id # $0\n" },
389fc89c0fbSmrg    {"DRAWABLE",	XA_DRAWABLE,	 "32x",	      ": drawable id # $0\n" },
390fc89c0fbSmrg    {"FONT",		XA_FONT,	 "32x",	      ": font id # $0\n" },
391fc89c0fbSmrg    {"INTEGER",		XA_INTEGER,	 "0i",	      0 },
392fc89c0fbSmrg    {"PIXMAP",		XA_PIXMAP,	 "32x",	      ": pixmap id # $0\n" },
393fc89c0fbSmrg    {"POINT",		XA_POINT,	 "16ii",      " = $0, $1\n" },
394fc89c0fbSmrg    {"RECTANGLE",	XA_RECTANGLE,	 "16iicc",    RECTANGLE_DFORMAT },
395fc89c0fbSmrg    {"RGB_COLOR_MAP",	XA_RGB_COLOR_MAP,"32xcccccccxx",RGB_COLOR_MAP_DFORMAT},
396fc89c0fbSmrg    {"STRING",		XA_STRING,	 "8s",	      0 },
397a0996ce0Smrg    {"UTF8_STRING",		0,	 "8u",	      0 },
398fc89c0fbSmrg    {"WINDOW",		XA_WINDOW,	 "32x",	      ": window id # $0+\n" },
399fc89c0fbSmrg    {"VISUALID",	XA_VISUALID,	 "32x",	      ": visual id # $0\n" },
400fc89c0fbSmrg    {"WM_COLORMAP_WINDOWS",	0,	 "32x",       ": window id # $0+\n"},
401fc89c0fbSmrg    {"WM_COMMAND",	XA_WM_COMMAND,	 "8s",	      " = { $0+ }\n" },
402fc89c0fbSmrg    {"WM_HINTS",	XA_WM_HINTS,	 "32mbcxxiixx",	WM_HINTS_DFORMAT },
403fc89c0fbSmrg    {"WM_ICON_NAME",	XA_WM_ICON_NAME, "8t",	      0 },
404fc89c0fbSmrg    {"WM_ICON_SIZE",	XA_WM_ICON_SIZE, "32cccccc",  WM_ICON_SIZE_DFORMAT},
405fc89c0fbSmrg    {"WM_NAME",		XA_WM_NAME,	 "8t",	      0 },
406fc89c0fbSmrg    {"WM_PROTOCOLS",		0,	 "32a",	      ": protocols  $0+\n"},
407fc89c0fbSmrg    {"WM_SIZE_HINTS",	XA_WM_SIZE_HINTS,"32mii",     WM_SIZE_HINTS_DFORMAT },
40891ec45ceSmrg    {"_NET_WM_ICON",            0,       "32o",        0 },
409fc89c0fbSmrg    {"WM_STATE",		0,	 "32cx",      WM_STATE_DFORMAT}
410fc89c0fbSmrg};
411fc89c0fbSmrg#undef ARC_DFORMAT
412fc89c0fbSmrg#undef RECTANGLE_DFORMAT
413fc89c0fbSmrg#undef RGB_COLOR_MAP_DFORMAT
414fc89c0fbSmrg#undef WM_ICON_SIZE_DFORMAT
415fc89c0fbSmrg#undef WM_HINTS_DFORMAT
416fc89c0fbSmrg#undef WM_SIZE_HINTS_DFORMAT
417fc89c0fbSmrg#undef WM_STATE_DFORMAT
418fc89c0fbSmrg
419fc89c0fbSmrg/*
420fc89c0fbSmrg * Font-specific mapping of property names to types:
421fc89c0fbSmrg */
422fc89c0fbSmrgstatic propertyRec fontPropTable[] = {
423fc89c0fbSmrg
424fc89c0fbSmrg    /* XLFD name properties */
425fc89c0fbSmrg
426fc89c0fbSmrg    { "FOUNDRY",		0, 	 		"32a",	0 },
427fc89c0fbSmrg    { "FAMILY_NAME",		XA_FAMILY_NAME,		"32a",	0 },
428fc89c0fbSmrg    { "WEIGHT_NAME",		0,			"32a",	0 },
429fc89c0fbSmrg    { "SLANT",			0,			"32a",	0 },
430fc89c0fbSmrg    { "SETWIDTH_NAME",		0,			"32a",	0 },
431fc89c0fbSmrg    { "ADD_STYLE_NAME",		0,			"32a",	0 },
432fc89c0fbSmrg    { "PIXEL_SIZE",		0,			"32c",	0 },
433fc89c0fbSmrg    { "POINT_SIZE",		XA_POINT_SIZE,		"32c",	0 },
434fc89c0fbSmrg    { "RESOLUTION_X",		0,			"32c",	0 },
435fc89c0fbSmrg    { "RESOLUTION_Y",		0,			"32c",	0 },
436fc89c0fbSmrg    { "SPACING",		0,			"32a",	0 },
437fc89c0fbSmrg    { "AVERAGE_WIDTH",		0,			"32c",	0 },
438fc89c0fbSmrg    { "CHARSET_REGISTRY",	0,			"32a",	0 },
439fc89c0fbSmrg    { "CHARSET_ENCODING",	0,			"32a",	0 },
440fc89c0fbSmrg
441fc89c0fbSmrg    /* other font properties referenced in the XLFD */
442fc89c0fbSmrg
443fc89c0fbSmrg    { "QUAD_WIDTH",		XA_QUAD_WIDTH,		"32i",	0 },
444fc89c0fbSmrg    { "RESOLUTION",		XA_RESOLUTION,		"32c",	0 },
445fc89c0fbSmrg    { "MIN_SPACE",		XA_MIN_SPACE,		"32c",	0 },
446fc89c0fbSmrg    { "NORM_SPACE",		XA_NORM_SPACE,		"32c",	0 },
447fc89c0fbSmrg    { "MAX_SPACE",		XA_MAX_SPACE,		"32c",	0 },
448fc89c0fbSmrg    { "END_SPACE",		XA_END_SPACE,		"32c",	0 },
449fc89c0fbSmrg    { "SUPERSCRIPT_X",		XA_SUPERSCRIPT_X,	"32i",	0 },
450fc89c0fbSmrg    { "SUPERSCRIPT_Y",		XA_SUPERSCRIPT_Y,	"32i",	0 },
451fc89c0fbSmrg    { "SUBSCRIPT_X",		XA_SUBSCRIPT_X,		"32i",	0 },
452fc89c0fbSmrg    { "SUBSCRIPT_Y",		XA_SUBSCRIPT_Y,		"32i",	0 },
453fc89c0fbSmrg    { "UNDERLINE_POSITION",	XA_UNDERLINE_POSITION,	"32i",	0 },
454fc89c0fbSmrg    { "UNDERLINE_THICKNESS",	XA_UNDERLINE_THICKNESS,	"32i",	0 },
455fc89c0fbSmrg    { "STRIKEOUT_ASCENT",	XA_STRIKEOUT_ASCENT,	"32i",	0 },
456fc89c0fbSmrg    { "STRIKEOUT_DESCENT",	XA_STRIKEOUT_DESCENT,	"32i",	0 },
457fc89c0fbSmrg    { "ITALIC_ANGLE",		XA_ITALIC_ANGLE,	"32i",	0 },
458fc89c0fbSmrg    { "X_HEIGHT",		XA_X_HEIGHT,		"32i",	0 },
459fc89c0fbSmrg    { "WEIGHT",			XA_WEIGHT,		"32i",	0 },
460fc89c0fbSmrg    { "FACE_NAME",		0,			"32a",	0 },
461fc89c0fbSmrg    { "COPYRIGHT",		XA_COPYRIGHT,		"32a",	0 },
462fc89c0fbSmrg    { "AVG_CAPITAL_WIDTH",	0,			"32i",	0 },
463fc89c0fbSmrg    { "AVG_LOWERCASE_WIDTH",	0,			"32i",	0 },
464fc89c0fbSmrg    { "RELATIVE_SETWIDTH",	0,			"32c",	0 },
465fc89c0fbSmrg    { "RELATIVE_WEIGHT",	0,			"32c",	0 },
466fc89c0fbSmrg    { "CAP_HEIGHT",		XA_CAP_HEIGHT,		"32c",	0 },
467fc89c0fbSmrg    { "SUPERSCRIPT_SIZE",	0,			"32c",	0 },
468fc89c0fbSmrg    { "FIGURE_WIDTH",		0,			"32i",	0 },
469fc89c0fbSmrg    { "SUBSCRIPT_SIZE",		0,			"32c",	0 },
470fc89c0fbSmrg    { "SMALL_CAP_SIZE",		0,			"32i",	0 },
471fc89c0fbSmrg    { "NOTICE",			XA_NOTICE,		"32a",	0 },
472fc89c0fbSmrg    { "DESTINATION",		0,			"32c",	0 },
473fc89c0fbSmrg
474fc89c0fbSmrg    /* other font properties */
475fc89c0fbSmrg
476fc89c0fbSmrg    { "FONT",			XA_FONT,		"32a",	0 },
477fc89c0fbSmrg    { "FONT_NAME",		XA_FONT_NAME,		"32a",	0 },
478fc89c0fbSmrg};
479fc89c0fbSmrg
480fc89c0fbSmrgstatic int XpropMode;
481fc89c0fbSmrg#define XpropWindowProperties 0
482fc89c0fbSmrg#define XpropFontProperties   1
483fc89c0fbSmrg
484fc89c0fbSmrgstatic void
485fc89c0fbSmrgSetup_Mapping (void)
486fc89c0fbSmrg{
487fc89c0fbSmrg    int n;
488fc89c0fbSmrg    propertyRec *p;
489fc89c0fbSmrg
490fc89c0fbSmrg    if (XpropMode == XpropWindowProperties) {
491fc89c0fbSmrg	n = sizeof(windowPropTable) / sizeof(propertyRec);
492fc89c0fbSmrg	p = windowPropTable;
493fc89c0fbSmrg    } else {
494fc89c0fbSmrg	n = sizeof (fontPropTable) / sizeof (propertyRec);
495fc89c0fbSmrg	p = fontPropTable;
496fc89c0fbSmrg    }
497fc89c0fbSmrg    for ( ; --n >= 0; p++) {
498fc89c0fbSmrg	if (! p->atom) {
499fc89c0fbSmrg	    p->atom = XInternAtom(dpy, p->name, True);
500fc89c0fbSmrg	    if (p->atom == None)
501fc89c0fbSmrg		continue;
502fc89c0fbSmrg	}
503fc89c0fbSmrg	Add_Mapping(p->atom, p->format, p->dformat);
504fc89c0fbSmrg    }
505fc89c0fbSmrg}
506fc89c0fbSmrg
507fc89c0fbSmrgstatic const char *
508fc89c0fbSmrgGetAtomName (Atom atom)
509fc89c0fbSmrg{
510fc89c0fbSmrg    int n;
511fc89c0fbSmrg    propertyRec *p;
512fc89c0fbSmrg
513fc89c0fbSmrg    if (XpropMode == XpropWindowProperties) {
514fc89c0fbSmrg	n = sizeof(windowPropTable) / sizeof(propertyRec);
515fc89c0fbSmrg	p = windowPropTable;
516fc89c0fbSmrg    } else {
517fc89c0fbSmrg	n = sizeof (fontPropTable) / sizeof (propertyRec);
518fc89c0fbSmrg	p = fontPropTable;
519fc89c0fbSmrg    }
520fc89c0fbSmrg    for ( ; --n >= 0; p++)
521fc89c0fbSmrg	if (p->atom == atom)
522fc89c0fbSmrg	    return p->name;
523fc89c0fbSmrg
524fc89c0fbSmrg    return NULL;
525fc89c0fbSmrg}
526fc89c0fbSmrg
527fc89c0fbSmrg/*
528fc89c0fbSmrg * Read_Mapping: routine to read in additional mappings from a stream
529fc89c0fbSmrg *               already open for reading.
530fc89c0fbSmrg */
531fc89c0fbSmrg
532fc89c0fbSmrgstatic void
533fc89c0fbSmrgRead_Mappings (FILE *stream)
534fc89c0fbSmrg{
535fc89c0fbSmrg    char format_buffer[100];
536576bbdfcSmrg    char name[1000];
537576bbdfcSmrg    const char *dformat, *format;
538fc89c0fbSmrg    int count, c;
539fc89c0fbSmrg    Atom atom;
540fc89c0fbSmrg
541fc89c0fbSmrg    while ((count = fscanf(stream," %990s %90s ",name,format_buffer)) != EOF) {
542fc89c0fbSmrg	if (count != 2)
543fc89c0fbSmrg	    Fatal_Error("Bad format file format.");
544fc89c0fbSmrg
545fc89c0fbSmrg	atom = Parse_Atom(name, False);
546f4a95042Smrg	format = strdup(format_buffer);
547f4a95042Smrg	if (!format)
548f4a95042Smrg	    Fatal_Error("Out of memory!");
549fc89c0fbSmrg
550fc89c0fbSmrg	Read_White_Space(stream);
551fc89c0fbSmrg	dformat = D_DFORMAT;
552fc89c0fbSmrg	c = getc(stream);
553fc89c0fbSmrg	ungetc(c, stream);
554fc89c0fbSmrg	if (c == (int) '\'')
555fc89c0fbSmrg	    dformat = Read_Quoted(stream);
556fc89c0fbSmrg
557fc89c0fbSmrg	Add_Mapping(atom, format, dformat);
558fc89c0fbSmrg    }
559fc89c0fbSmrg}
560fc89c0fbSmrg
561fc89c0fbSmrg/*
562fc89c0fbSmrg *
563fc89c0fbSmrg * Formatting Routines: a group of routines to translate from various
564fc89c0fbSmrg *                      values to a static read-only string useful for output.
565fc89c0fbSmrg *
566fc89c0fbSmrg * Routines: Format_Hex, Format_Unsigned, Format_Signed, Format_Atom,
567fc89c0fbSmrg *           Format_Mask_Word, Format_Bool, Format_String, Format_Len_String.
568fc89c0fbSmrg *
569fc89c0fbSmrg * All of the above routines take a long except for Format_String and
570fc89c0fbSmrg * Format_Len_String.
571fc89c0fbSmrg *
572fc89c0fbSmrg */
573fc89c0fbSmrgstatic char _formatting_buffer[MAXSTR+100];
574fc89c0fbSmrgstatic char _formatting_buffer2[21];
575fc89c0fbSmrg
576fc89c0fbSmrgstatic const char *
577fc89c0fbSmrgFormat_Hex (long wrd)
578fc89c0fbSmrg{
579fc89c0fbSmrg    snprintf(_formatting_buffer2, sizeof(_formatting_buffer2), "0x%lx", wrd);
580fc89c0fbSmrg    return _formatting_buffer2;
581fc89c0fbSmrg}
582fc89c0fbSmrg
583fc89c0fbSmrgstatic const char *
584fc89c0fbSmrgFormat_Unsigned (long wrd)
585fc89c0fbSmrg{
586fc89c0fbSmrg    snprintf(_formatting_buffer2, sizeof(_formatting_buffer2), "%lu", wrd);
587fc89c0fbSmrg    return _formatting_buffer2;
588fc89c0fbSmrg}
589fc89c0fbSmrg
590fc89c0fbSmrgstatic const char *
591fc89c0fbSmrgFormat_Signed (long wrd)
592fc89c0fbSmrg{
593fc89c0fbSmrg    snprintf(_formatting_buffer2, sizeof(_formatting_buffer2), "%ld", wrd);
594fc89c0fbSmrg    return _formatting_buffer2;
595fc89c0fbSmrg}
596fc89c0fbSmrg
597fc89c0fbSmrg/*ARGSUSED*/
598fc89c0fbSmrgstatic int
599fc89c0fbSmrgignore_errors (Display *dpy, XErrorEvent *ev)
600fc89c0fbSmrg{
601fc89c0fbSmrg    return 0;
602fc89c0fbSmrg}
603fc89c0fbSmrg
604fc89c0fbSmrgstatic const char *
605fc89c0fbSmrgFormat_Atom (Atom atom)
606fc89c0fbSmrg{
607fc89c0fbSmrg    const char *found;
608fc89c0fbSmrg    char *name;
609fc89c0fbSmrg    XErrorHandler handler;
610fc89c0fbSmrg
611fc89c0fbSmrg    if ((found = GetAtomName(atom)) != NULL)
612fc89c0fbSmrg	return found;
613fc89c0fbSmrg
614fc89c0fbSmrg    handler = XSetErrorHandler (ignore_errors);
615fc89c0fbSmrg    name = XGetAtomName(dpy, atom);
616fc89c0fbSmrg    XSetErrorHandler(handler);
617fc89c0fbSmrg    if (! name)
618fc89c0fbSmrg	snprintf(_formatting_buffer, sizeof(_formatting_buffer),
619fc89c0fbSmrg		 "undefined atom # 0x%lx", atom);
620fc89c0fbSmrg    else {
621fc89c0fbSmrg	int namelen = strlen(name);
622fc89c0fbSmrg	if (namelen > MAXSTR) namelen = MAXSTR;
623fc89c0fbSmrg	memcpy(_formatting_buffer, name, namelen);
624fc89c0fbSmrg	_formatting_buffer[namelen] = '\0';
625fc89c0fbSmrg	XFree(name);
626fc89c0fbSmrg    }
627fc89c0fbSmrg    return _formatting_buffer;
628fc89c0fbSmrg}
629fc89c0fbSmrg
630fc89c0fbSmrgstatic const char *
631fc89c0fbSmrgFormat_Mask_Word (long wrd)
632fc89c0fbSmrg{
633fc89c0fbSmrg    long bit_mask, bit;
634fc89c0fbSmrg    int seen = 0;
635fc89c0fbSmrg
636fc89c0fbSmrg    strcpy(_formatting_buffer, "{MASK: ");
637fc89c0fbSmrg    for (bit=0, bit_mask=1; bit <= sizeof(long)*8; bit++, bit_mask<<=1) {
638fc89c0fbSmrg	if (bit_mask & wrd) {
639fc89c0fbSmrg	    if (seen) {
640fc89c0fbSmrg		strcat(_formatting_buffer, ", ");
641fc89c0fbSmrg	    }
642fc89c0fbSmrg	    seen = 1;
643fc89c0fbSmrg	    strcat(_formatting_buffer, Format_Unsigned(bit));
644fc89c0fbSmrg	}
645fc89c0fbSmrg    }
646fc89c0fbSmrg    strcat(_formatting_buffer, "}");
647fc89c0fbSmrg
648fc89c0fbSmrg    return _formatting_buffer;
649fc89c0fbSmrg}
650fc89c0fbSmrg
651fc89c0fbSmrgstatic const char *
652fc89c0fbSmrgFormat_Bool (long value)
653fc89c0fbSmrg{
654fc89c0fbSmrg    if (!value)
655fc89c0fbSmrg	return "False";
656fc89c0fbSmrg
657fc89c0fbSmrg    return "True";
658fc89c0fbSmrg}
659fc89c0fbSmrg
660fc89c0fbSmrgstatic char *_buf_ptr;
661fc89c0fbSmrgstatic int _buf_len;
662fc89c0fbSmrg
663fc89c0fbSmrgstatic void
664fc89c0fbSmrg_put_char (char c)
665fc89c0fbSmrg{
666fc89c0fbSmrg    if (_buf_len <= 0) {
667fc89c0fbSmrg	_buf_ptr[0] = '\0';
668fc89c0fbSmrg	return;
669fc89c0fbSmrg    }
670fc89c0fbSmrg    _buf_ptr++[0] = c;
671fc89c0fbSmrg    _buf_len--;
672fc89c0fbSmrg}
673fc89c0fbSmrg
674fc89c0fbSmrgstatic void
675a0996ce0Smrg_format_char (char c, int unicode)
676fc89c0fbSmrg{
677fc89c0fbSmrg    switch (c) {
678fc89c0fbSmrg      case '\\':
679fc89c0fbSmrg      case '\"':
680fc89c0fbSmrg	_put_char('\\');
681fc89c0fbSmrg	_put_char(c);
682fc89c0fbSmrg	break;
683fc89c0fbSmrg      case '\n':
684fc89c0fbSmrg	_put_char('\\');
685fc89c0fbSmrg	_put_char('n');
686fc89c0fbSmrg	break;
687fc89c0fbSmrg      case '\t':
688fc89c0fbSmrg	_put_char('\\');
689fc89c0fbSmrg	_put_char('t');
690fc89c0fbSmrg	break;
691fc89c0fbSmrg      default:
692fc89c0fbSmrg	if (!c_isprint(c)) {
693a0996ce0Smrg	    if (unicode && (c & 0x80)) {
694a0996ce0Smrg		_put_char(c);
695a0996ce0Smrg	    } else {
696a0996ce0Smrg		_put_char('\\');
697a0996ce0Smrg		snprintf(_buf_ptr, _buf_len, "%03o", (unsigned char) c);
698a0996ce0Smrg		_buf_ptr += 3;
699a0996ce0Smrg		_buf_len -= 3;
700a0996ce0Smrg	    }
701fc89c0fbSmrg	} else
702fc89c0fbSmrg	  _put_char(c);
703fc89c0fbSmrg    }
704fc89c0fbSmrg}
705fc89c0fbSmrg
706fc89c0fbSmrgstatic const char *
707a0996ce0SmrgFormat_String (const char *string, int unicode)
708fc89c0fbSmrg{
709fc89c0fbSmrg    char c;
710fc89c0fbSmrg
711fc89c0fbSmrg    _buf_ptr = _formatting_buffer;
712fc89c0fbSmrg    _buf_len = MAXSTR;
713fc89c0fbSmrg    _put_char('\"');
714fc89c0fbSmrg
715fc89c0fbSmrg    while ((c = string++[0]))
716a0996ce0Smrg	_format_char(c, unicode);
717fc89c0fbSmrg
718fc89c0fbSmrg    *_buf_ptr++ = '"';
719fc89c0fbSmrg    *_buf_ptr++ = '\0';
720fc89c0fbSmrg    return _formatting_buffer;
721fc89c0fbSmrg}
722fc89c0fbSmrg
723fc89c0fbSmrgstatic const char *
724576bbdfcSmrgFormat_Len_String (const char *string, int len, int unicode)
725fc89c0fbSmrg{
726fc89c0fbSmrg    char *data;
727fc89c0fbSmrg    const char *result;
728fc89c0fbSmrg
729f4a95042Smrg    data = malloc(len+1);
730f4a95042Smrg    if (!data)
731f4a95042Smrg	Fatal_Error("Out of memory!");
732fc89c0fbSmrg
733fc89c0fbSmrg    memcpy(data, string, len);
734fc89c0fbSmrg    data[len] = '\0';
735fc89c0fbSmrg
736576bbdfcSmrg    result = Format_String(data, unicode);
737fc89c0fbSmrg    free(data);
738fc89c0fbSmrg
739fc89c0fbSmrg    return result;
740fc89c0fbSmrg}
741fc89c0fbSmrg
74291ec45ceSmrgstatic int
74391ec45ceSmrgis_utf8_locale (void)
74491ec45ceSmrg{
74591ec45ceSmrg#ifdef HAVE_LANGINFO_H
74691ec45ceSmrg    char *charmap = nl_langinfo (CODESET);
74791ec45ceSmrg
74891ec45ceSmrg    return charmap && strcmp (charmap, "UTF-8") == 0;
74991ec45ceSmrg#else
75091ec45ceSmrg    return 0;
75191ec45ceSmrg#endif
75291ec45ceSmrg}
75391ec45ceSmrg
754f9c28e31Smrgstatic int
755f9c28e31Smrgis_truecolor_term (void)
756f9c28e31Smrg{
757f9c28e31Smrg    char *colorterm = getenv( "COLORTERM" );
758f9c28e31Smrg
759f9c28e31Smrg    if (colorterm && !strcmp(colorterm,"truecolor"))
760f9c28e31Smrg	return 1;
761f9c28e31Smrg
762f9c28e31Smrg    return 0;
763f9c28e31Smrg}
764f9c28e31Smrg
76591ec45ceSmrgstatic const char *
76691ec45ceSmrgFormat_Icons (const unsigned long *icon, int len)
76791ec45ceSmrg{
76881676fe2Smrg    static char *result = NULL;
76981676fe2Smrg    char *tail = NULL;
77091ec45ceSmrg    int alloced;
77191ec45ceSmrg    const unsigned long *end = icon + len / sizeof (unsigned long);
77291ec45ceSmrg
77381676fe2Smrg    free(result);
77481676fe2Smrg    result = NULL;
77581676fe2Smrg
77691ec45ceSmrg    alloced = 0;
77791ec45ceSmrg
77891ec45ceSmrg    while (icon < end)
77991ec45ceSmrg    {
780f9c28e31Smrg	unsigned long width, height, display_width;
781f9c28e31Smrg	unsigned int icon_pixel_bytes;
782f9c28e31Smrg	unsigned int icon_line_bytes;
78391ec45ceSmrg	int w, h;
78491ec45ceSmrg	int offset;
78591ec45ceSmrg
78691ec45ceSmrg	width = *icon++;
78791ec45ceSmrg	height = *icon++;
788f9c28e31Smrg	display_width = width * 2; /* Two characters per icon pixel. */
789f9c28e31Smrg
790f9c28e31Smrg	icon_pixel_bytes = 1;
791f9c28e31Smrg	if (is_truecolor_term())
792f9c28e31Smrg	    icon_pixel_bytes = 25; /* 16 control characters, and up to 9 chars of RGB. */
793f9c28e31Smrg	else if (is_utf8_locale())
794f9c28e31Smrg	    icon_pixel_bytes = 3; /* Up to 3 bytes per character in that mode. */
795f9c28e31Smrg
796f9c28e31Smrg	/* Initial tab, pixels, and newline. */
797f9c28e31Smrg	icon_line_bytes = 8 + display_width * icon_pixel_bytes + 1;
79891ec45ceSmrg
79991ec45ceSmrg	offset = (tail - result);
80091ec45ceSmrg
801f9c28e31Smrg	alloced += 80;				/* For the header, final newline, color reset */
802f9c28e31Smrg	alloced += icon_line_bytes * height;	/* For the rows */
80391ec45ceSmrg
804f4a95042Smrg	result = realloc (result, alloced);
805f4a95042Smrg	if (!result)
806f4a95042Smrg	    Fatal_Error("Out of memory!");
80791ec45ceSmrg	tail = &result[offset];
80891ec45ceSmrg
80991ec45ceSmrg	if (end - icon < width * height)
81091ec45ceSmrg	    break;
81191ec45ceSmrg
81291ec45ceSmrg	tail += sprintf (tail, "\tIcon (%lu x %lu):\n", width, height);
81391ec45ceSmrg
814f9c28e31Smrg	if ((display_width + 8) > term_width || height > 144)
81591ec45ceSmrg	{
816f9c28e31Smrg	    tail += sprintf (tail, "\t(not shown)\n");
81791ec45ceSmrg	    icon += width * height;
81891ec45ceSmrg	    continue;
81991ec45ceSmrg	}
82091ec45ceSmrg
82191ec45ceSmrg	for (h = 0; h < height; ++h)
82291ec45ceSmrg	{
82391ec45ceSmrg	    tail += sprintf (tail, "\t");
82491ec45ceSmrg
82591ec45ceSmrg	    for (w = 0; w < width; ++w)
82691ec45ceSmrg	    {
82791ec45ceSmrg		unsigned char a, r, g, b;
82891ec45ceSmrg		unsigned long pixel = *icon++;
82991ec45ceSmrg		unsigned long brightness;
83091ec45ceSmrg
83191ec45ceSmrg		a = (pixel & 0xff000000) >> 24;
83291ec45ceSmrg		r = (pixel & 0x00ff0000) >> 16;
83391ec45ceSmrg		g = (pixel & 0x0000ff00) >> 8;
83491ec45ceSmrg		b = (pixel & 0x000000ff);
83591ec45ceSmrg
83691ec45ceSmrg		brightness =
83791ec45ceSmrg		    (a / 255.0) * (1000 - ((299 * (r / 255.0)) +
83891ec45ceSmrg					   (587 * (g / 255.0)) +
83991ec45ceSmrg					   (114 * (b / 255.0))));
84091ec45ceSmrg
841f9c28e31Smrg		if (is_truecolor_term())
842f9c28e31Smrg		{
843f9c28e31Smrg		    float opacity = a / 255.0;
844f9c28e31Smrg
845f9c28e31Smrg		    r = r * opacity;
846f9c28e31Smrg		    g = g * opacity;
847f9c28e31Smrg		    b = b * opacity;
848f9c28e31Smrg
849f9c28e31Smrg		    tail += sprintf (tail, "\033[38;2;%d;%d;%dm\342\226\210\342\226\210", r, g, b );
850f9c28e31Smrg		}
851f9c28e31Smrg		else if (is_utf8_locale())
85291ec45ceSmrg		{
85391ec45ceSmrg		    static const char palette[][4] =
85491ec45ceSmrg		    {
85591ec45ceSmrg			" ",
85691ec45ceSmrg			"\342\226\221",		/* 25% */
85791ec45ceSmrg			"\342\226\222",		/* 50% */
85891ec45ceSmrg			"\342\226\223",		/* 75% */
85991ec45ceSmrg			"\342\226\210",		/* 100% */
86091ec45ceSmrg		    };
86191ec45ceSmrg		    int idx;
86291ec45ceSmrg
86391ec45ceSmrg		    idx = (brightness * ((sizeof (palette)/sizeof(palette[0])) - 1)) / 1000;
86491ec45ceSmrg
865f9c28e31Smrg		    tail += sprintf (tail, "%s%s", palette[idx], palette[idx]);
86691ec45ceSmrg		}
86791ec45ceSmrg		else
86891ec45ceSmrg		{
86991ec45ceSmrg		    static const char palette[] =
87091ec45ceSmrg			" .'`,^:\";~-_+<>i!lI?/\\|()1{}[]rcvunxzjftLCJUYXZO0Qoahkbdpqwm*WMB8&%$#@";
87191ec45ceSmrg		    int idx;
87291ec45ceSmrg
87391ec45ceSmrg		    idx = (brightness * (sizeof(palette) - 2)) / 1000;
87491ec45ceSmrg
87591ec45ceSmrg		    *tail++ = palette[idx];
876f9c28e31Smrg		    *tail++ = palette[idx];
87791ec45ceSmrg		}
87891ec45ceSmrg	    }
87991ec45ceSmrg
88091ec45ceSmrg	    tail += sprintf (tail, "\n");
88191ec45ceSmrg	}
88291ec45ceSmrg
883f9c28e31Smrg	/* Reset colors. */
884f9c28e31Smrg	if (is_truecolor_term())
885f9c28e31Smrg	    tail += sprintf (tail, "\033[0m");
886f9c28e31Smrg
88791ec45ceSmrg	tail += sprintf (tail, "\n");
88891ec45ceSmrg    }
88991ec45ceSmrg
89091ec45ceSmrg    return result;
89191ec45ceSmrg}
89291ec45ceSmrg
893fc89c0fbSmrgstatic const char *
894fc89c0fbSmrgFormat_Len_Text (const char *string, int len, Atom encoding)
895fc89c0fbSmrg{
896fc89c0fbSmrg    XTextProperty textprop;
897f9c28e31Smrg    char **list, **start_list;
898fc89c0fbSmrg    int count;
899fc89c0fbSmrg
900fc89c0fbSmrg    /* Try to convert to local encoding. */
901fc89c0fbSmrg    textprop.encoding = encoding;
902fc89c0fbSmrg    textprop.format = 8;
903fc89c0fbSmrg    textprop.value = (unsigned char *) string;
904fc89c0fbSmrg    textprop.nitems = len;
905f9c28e31Smrg    if (XmbTextPropertyToTextList(dpy, &textprop, &start_list, &count) == Success) {
906f9c28e31Smrg	list = start_list;
907fc89c0fbSmrg	_buf_ptr = _formatting_buffer;
908fc89c0fbSmrg	_buf_len = MAXSTR;
909fc89c0fbSmrg	*_buf_ptr++ = '"';
910fc89c0fbSmrg	while (count > 0) {
911fc89c0fbSmrg	    string = *list++;
912fc89c0fbSmrg	    len = strlen(string);
913fc89c0fbSmrg	    while (len > 0) {
914fc89c0fbSmrg		wchar_t wc;
915fc89c0fbSmrg		int n = mbtowc(&wc, string, len);
916fc89c0fbSmrg		if (n > 0 && iswprint(wc)) {
917fc89c0fbSmrg		    if (_buf_len >= n) {
918fc89c0fbSmrg			memcpy(_buf_ptr, string, n);
919fc89c0fbSmrg			_buf_ptr += n;
920fc89c0fbSmrg			_buf_len -= n;
921fc89c0fbSmrg		    }
922fc89c0fbSmrg		    string += n;
923fc89c0fbSmrg		    len -= n;
924fc89c0fbSmrg		} else {
925fc89c0fbSmrg		    _put_char('\\');
926fc89c0fbSmrg		    snprintf(_buf_ptr, _buf_len, "%03o", (unsigned char) *string);
927fc89c0fbSmrg		    _buf_ptr += 3;
928fc89c0fbSmrg		    _buf_len -= 3;
929fc89c0fbSmrg		    string++;
930fc89c0fbSmrg		    len--;
931fc89c0fbSmrg		}
932fc89c0fbSmrg	    }
933fc89c0fbSmrg	    count--;
934fc89c0fbSmrg	    if (count > 0) {
935fc89c0fbSmrg		snprintf(_buf_ptr, _buf_len, "\\000");
936fc89c0fbSmrg	        _buf_ptr += 4;
937fc89c0fbSmrg		_buf_len -= 4;
938fc89c0fbSmrg	    }
939fc89c0fbSmrg	}
940f9c28e31Smrg	XFreeStringList(start_list);
941fc89c0fbSmrg	*_buf_ptr++ = '"';
942fc89c0fbSmrg	*_buf_ptr++ = '\0';
943fc89c0fbSmrg	return _formatting_buffer;
944fc89c0fbSmrg    } else
945576bbdfcSmrg	return Format_Len_String(string, len, 0);
946fc89c0fbSmrg}
947fc89c0fbSmrg
948a0996ce0Smrg/*
949a0996ce0Smrg * Validate a string as UTF-8 encoded according to RFC 3629
950a0996ce0Smrg *
951a0996ce0Smrg * Simply, a unicode code point (up to 21-bits long) is encoded as follows:
952a0996ce0Smrg *
953a0996ce0Smrg *    Char. number range  |        UTF-8 octet sequence
954a0996ce0Smrg *       (hexadecimal)    |              (binary)
955a0996ce0Smrg *    --------------------+---------------------------------------------
956a0996ce0Smrg *    0000 0000-0000 007F | 0xxxxxxx
957a0996ce0Smrg *    0000 0080-0000 07FF | 110xxxxx 10xxxxxx
958a0996ce0Smrg *    0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
959a0996ce0Smrg *    0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
960a0996ce0Smrg *
961a0996ce0Smrg * Validation is done left-to-right, and an error condition, if any, refers to
962a0996ce0Smrg * only the left-most problem in the string.
963a0996ce0Smrg *
964a0996ce0Smrg * Return values:
965a0996ce0Smrg *   UTF8_VALID: Valid UTF-8 encoded string
966a0996ce0Smrg *   UTF8_OVERLONG: Using more bytes than needed for a code point
967a0996ce0Smrg *   UTF8_SHORT_TAIL: Not enough bytes in a multi-byte sequence
968a0996ce0Smrg *   UTF8_LONG_TAIL: Too many bytes in a multi-byte sequence
969a0996ce0Smrg *   UTF8_FORBIDDEN_VALUE: Forbidden prefix or code point outside 0x10FFFF
970a0996ce0Smrg */
971a0996ce0Smrg#define UTF8_VALID 0
972a0996ce0Smrg#define UTF8_FORBIDDEN_VALUE 1
973a0996ce0Smrg#define UTF8_OVERLONG 2
974a0996ce0Smrg#define UTF8_SHORT_TAIL 3
975a0996ce0Smrg#define UTF8_LONG_TAIL 4
976a0996ce0Smrgstatic int
977a0996ce0Smrgis_valid_utf8 (const char *string, int len)
978a0996ce0Smrg{
979f4a95042Smrg    unsigned long codepoint = 0;
980a0996ce0Smrg    int rem, i;
981a0996ce0Smrg    unsigned char c;
982a0996ce0Smrg
983a0996ce0Smrg    rem = 0;
984a0996ce0Smrg    for (i = 0; i < len; i++) {
985a0996ce0Smrg	c = (unsigned char) string[i];
986a0996ce0Smrg
987a0996ce0Smrg	/* Order of type check:
988a0996ce0Smrg	 *   - Single byte code point
989a0996ce0Smrg	 *   - Non-starting byte of multi-byte sequence
990a0996ce0Smrg	 *   - Start of 2-byte sequence
991a0996ce0Smrg	 *   - Start of 3-byte sequence
992a0996ce0Smrg	 *   - Start of 4-byte sequence
993a0996ce0Smrg	 */
994a0996ce0Smrg	if (!(c & 0x80)) {
995a0996ce0Smrg	    if (rem > 0) return UTF8_SHORT_TAIL;
996a0996ce0Smrg	    rem = 0;
997a0996ce0Smrg	    codepoint = c;
998a0996ce0Smrg	} else if ((c & 0xC0) == 0x80) {
999a0996ce0Smrg	    if (rem == 0) return UTF8_LONG_TAIL;
1000a0996ce0Smrg	    rem--;
1001a0996ce0Smrg	    codepoint |= (c & 0x3F) << (rem * 6);
1002a0996ce0Smrg	    if (codepoint == 0) return UTF8_OVERLONG;
1003a0996ce0Smrg	} else if ((c & 0xE0) == 0xC0) {
1004a0996ce0Smrg	    if (rem > 0) return UTF8_SHORT_TAIL;
1005a0996ce0Smrg	    rem = 1;
1006a0996ce0Smrg	    codepoint = (c & 0x1F) << 6;
1007a0996ce0Smrg	    if (codepoint == 0) return UTF8_OVERLONG;
1008a0996ce0Smrg	} else if ((c & 0xF0) == 0xE0) {
1009a0996ce0Smrg	    if (rem > 0) return UTF8_SHORT_TAIL;
1010a0996ce0Smrg	    rem = 2;
1011a0996ce0Smrg	    codepoint = (c & 0x0F) << 12;
1012a0996ce0Smrg	} else if ((c & 0xF8) == 0xF0) {
1013a0996ce0Smrg	    if (rem > 0) return UTF8_SHORT_TAIL;
1014a0996ce0Smrg	    rem = 3;
1015a0996ce0Smrg	    codepoint = (c & 0x07) << 18;
1016a0996ce0Smrg	    if (codepoint > 0x10FFFF) return UTF8_FORBIDDEN_VALUE;
1017a0996ce0Smrg	} else
1018a0996ce0Smrg	    return UTF8_FORBIDDEN_VALUE;
1019a0996ce0Smrg    }
1020a0996ce0Smrg
1021a0996ce0Smrg    return UTF8_VALID;
1022a0996ce0Smrg}
1023a0996ce0Smrg
1024a0996ce0Smrgstatic const char *
1025a0996ce0SmrgFormat_Len_Unicode (const char *string, int len)
1026a0996ce0Smrg{
1027a0996ce0Smrg    char *data;
1028a0996ce0Smrg    const char *result, *error;
1029a0996ce0Smrg
1030a0996ce0Smrg    int validity = is_valid_utf8(string, len);
1031a0996ce0Smrg
1032a0996ce0Smrg    if (validity != UTF8_VALID) {
1033a0996ce0Smrg	switch (validity) {
1034a0996ce0Smrg	  case UTF8_FORBIDDEN_VALUE:
1035a0996ce0Smrg	    error = "<Invalid UTF-8 string: Forbidden value> "; break;
1036a0996ce0Smrg	  case UTF8_OVERLONG:
1037a0996ce0Smrg	    error = "<Invalid UTF-8 string: Overlong encoding> "; break;
1038a0996ce0Smrg	  case UTF8_SHORT_TAIL:
1039a0996ce0Smrg	    error = "<Invalid UTF-8 string: Tail too short> "; break;
1040a0996ce0Smrg	  case UTF8_LONG_TAIL:
1041a0996ce0Smrg	    error = "<Invalid UTF-8 string: Tail too long> "; break;
1042f4a95042Smrg	  default:
1043f4a95042Smrg	    error = "<Invalid UTF-8 string: Unknown error>"; break;
1044a0996ce0Smrg	}
1045a0996ce0Smrg
1046576bbdfcSmrg	result = Format_Len_String(string, len, 0);
1047576bbdfcSmrg	/* result is stored in _formatting_buffer, so make a temporary
1048576bbdfcSmrg	   copy before we overwrite _formatting_buffer with error */
1049576bbdfcSmrg	data = strdup(result);
1050f4a95042Smrg	if (!data)
1051f4a95042Smrg	    Fatal_Error("Out of memory!");
1052a0996ce0Smrg
1053a0996ce0Smrg	memcpy(_formatting_buffer, error, strlen(error)+1);
1054a0996ce0Smrg	strcat(_formatting_buffer, data);
1055a0996ce0Smrg	free(data);
1056a0996ce0Smrg
1057a0996ce0Smrg	return _formatting_buffer;
1058a0996ce0Smrg    }
1059a0996ce0Smrg
1060576bbdfcSmrg    return Format_Len_String(string, len, is_utf8_locale());
1061a0996ce0Smrg}
1062a0996ce0Smrg
1063fc89c0fbSmrg/*
1064fc89c0fbSmrg *
1065fc89c0fbSmrg * The Format Manager: a group of routines to manage "formats"
1066fc89c0fbSmrg *
1067fc89c0fbSmrg */
1068fc89c0fbSmrg
1069fc89c0fbSmrgstatic int
1070fc89c0fbSmrgIs_A_Format (const char *string)
1071fc89c0fbSmrg{
1072fc89c0fbSmrg    return isdigit((unsigned char) string[0]);
1073fc89c0fbSmrg}
1074fc89c0fbSmrg
1075fc89c0fbSmrgstatic int
1076fc89c0fbSmrgGet_Format_Size (const char *format)
1077fc89c0fbSmrg{
1078fc89c0fbSmrg    long size;
1079fc89c0fbSmrg
1080fc89c0fbSmrg    Scan_Long(format, &size);
1081fc89c0fbSmrg
1082fc89c0fbSmrg    /* Check for legal sizes */
1083fc89c0fbSmrg    if (size != 0 && size != 8 && size != 16 && size != 32)
1084fc89c0fbSmrg	Fatal_Error("bad format: %s", format);
1085fc89c0fbSmrg
1086fc89c0fbSmrg    return (int) size;
1087fc89c0fbSmrg}
1088fc89c0fbSmrg
1089fc89c0fbSmrgstatic char
1090fc89c0fbSmrgGet_Format_Char (const char *format, int i)
1091fc89c0fbSmrg{
1092fc89c0fbSmrg    long size;
1093fc89c0fbSmrg
1094fc89c0fbSmrg    /* Remove # at front of format */
1095fc89c0fbSmrg    format = Scan_Long(format, &size);
1096fc89c0fbSmrg    if (!*format)
1097fc89c0fbSmrg	Fatal_Error("bad format: %s", format);
1098fc89c0fbSmrg
1099fc89c0fbSmrg    /* Last character repeats forever... */
1100fc89c0fbSmrg    if (i >= (int)strlen(format))
1101fc89c0fbSmrg	i = strlen(format)-1;
1102fc89c0fbSmrg
1103fc89c0fbSmrg    return format[i];
1104fc89c0fbSmrg}
1105fc89c0fbSmrg
1106fc89c0fbSmrgstatic const char *
1107fc89c0fbSmrgFormat_Thunk (thunk t, char format_char)
1108fc89c0fbSmrg{
1109fc89c0fbSmrg    long value;
1110fc89c0fbSmrg    value = t.value;
1111fc89c0fbSmrg
1112fc89c0fbSmrg    switch (format_char) {
1113fc89c0fbSmrg      case 's':
1114576bbdfcSmrg	return Format_Len_String(t.extra_value, (int)t.value, 0);
1115a0996ce0Smrg      case 'u':
1116a0996ce0Smrg	return Format_Len_Unicode(t.extra_value, (int)t.value);
1117fc89c0fbSmrg      case 't':
1118fc89c0fbSmrg	return Format_Len_Text(t.extra_value, (int)t.value, t.extra_encoding);
1119fc89c0fbSmrg      case 'x':
1120fc89c0fbSmrg	return Format_Hex(value);
1121fc89c0fbSmrg      case 'c':
1122fc89c0fbSmrg	return Format_Unsigned(value);
1123fc89c0fbSmrg      case 'i':
1124fc89c0fbSmrg	return Format_Signed(value);
1125fc89c0fbSmrg      case 'b':
1126fc89c0fbSmrg	return Format_Bool(value);
1127fc89c0fbSmrg      case 'm':
1128fc89c0fbSmrg	return Format_Mask_Word(value);
1129fc89c0fbSmrg      case 'a':
1130fc89c0fbSmrg	return Format_Atom(value);
113191ec45ceSmrg      case 'o':
113291ec45ceSmrg	  return Format_Icons((const unsigned long *)t.extra_value, (int)t.value);
1133fc89c0fbSmrg      default:
1134fc89c0fbSmrg	Fatal_Error("bad format character: %c", format_char);
1135fc89c0fbSmrg    }
1136fc89c0fbSmrg}
1137fc89c0fbSmrg
1138fc89c0fbSmrgstatic const char *
1139fc89c0fbSmrgFormat_Thunk_I (thunk *thunks, const char *format, int i)
1140fc89c0fbSmrg{
1141fc89c0fbSmrg    if (i >= thunks->thunk_count)
1142fc89c0fbSmrg	return "<field not available>";
1143fc89c0fbSmrg
1144fc89c0fbSmrg    return Format_Thunk(thunks[i], Get_Format_Char(format, i));
1145fc89c0fbSmrg}
1146fc89c0fbSmrg
1147fc89c0fbSmrgstatic long
1148fc89c0fbSmrgMask_Word (thunk *thunks, const char *format)
1149fc89c0fbSmrg{
1150fc89c0fbSmrg    int j;
1151fc89c0fbSmrg
1152fc89c0fbSmrg    for (j = 0; j  < (int)strlen(format); j++)
1153fc89c0fbSmrg	if (Get_Format_Char(format, j) == 'm')
1154fc89c0fbSmrg	    return thunks[j].value;
1155fc89c0fbSmrg    return 0;
1156fc89c0fbSmrg}
1157fc89c0fbSmrg
1158fc89c0fbSmrg/*
1159fc89c0fbSmrg *
1160fc89c0fbSmrg * The Display Format Manager:
1161fc89c0fbSmrg *
1162fc89c0fbSmrg */
1163fc89c0fbSmrg
1164fc89c0fbSmrgstatic int
1165fc89c0fbSmrgIs_A_DFormat (const char *string)
1166fc89c0fbSmrg{
1167fc89c0fbSmrg    return string[0] && string[0] != '-'
1168fc89c0fbSmrg	   && !(isalpha((unsigned char) string[0]) || string[0] == '_');
1169fc89c0fbSmrg}
1170fc89c0fbSmrg
1171fc89c0fbSmrgstatic const char *
1172fc89c0fbSmrgHandle_Backslash (const char *dformat)
1173fc89c0fbSmrg{
1174fc89c0fbSmrg    char c;
1175fc89c0fbSmrg    unsigned long i;
1176fc89c0fbSmrg
1177fc89c0fbSmrg    if (!(c = *(dformat++)))
1178fc89c0fbSmrg	return dformat;
1179fc89c0fbSmrg
1180fc89c0fbSmrg    switch (c) {
1181fc89c0fbSmrg      case 'n':
1182fc89c0fbSmrg	putchar('\n');
1183fc89c0fbSmrg	break;
1184fc89c0fbSmrg      case 't':
1185fc89c0fbSmrg	putchar('\t');
1186fc89c0fbSmrg	break;
1187fc89c0fbSmrg      case '0':
1188fc89c0fbSmrg      case '1':
1189fc89c0fbSmrg      case '2':
1190fc89c0fbSmrg      case '3':
1191fc89c0fbSmrg      case '4':
1192fc89c0fbSmrg      case '5':
1193fc89c0fbSmrg      case '6':
1194fc89c0fbSmrg      case '7':
1195fc89c0fbSmrg	dformat = Scan_Octal(dformat, &i);
1196fc89c0fbSmrg	putchar((int) i);
1197fc89c0fbSmrg	break;
1198fc89c0fbSmrg      default:
1199fc89c0fbSmrg	putchar(c);
1200fc89c0fbSmrg	break;
1201fc89c0fbSmrg    }
1202fc89c0fbSmrg    return dformat;
1203fc89c0fbSmrg}
1204fc89c0fbSmrg
1205fc89c0fbSmrgstatic const char *
1206fc89c0fbSmrgHandle_Dollar_sign (const char *dformat, thunk *thunks, const char *format)
1207fc89c0fbSmrg{
1208fc89c0fbSmrg    long i;
1209fc89c0fbSmrg
1210fc89c0fbSmrg    dformat = Scan_Long(dformat, &i);
1211fc89c0fbSmrg
1212fc89c0fbSmrg    if (dformat[0] == '+') {
1213fc89c0fbSmrg	int seen = 0;
1214fc89c0fbSmrg	dformat++;
1215fc89c0fbSmrg	for (; i < thunks->thunk_count; i++) {
1216fc89c0fbSmrg	    if (seen)
1217fc89c0fbSmrg		printf(", ");
1218fc89c0fbSmrg	    seen = 1;
1219fc89c0fbSmrg	    printf("%s", Format_Thunk_I(thunks, format, (int) i));
1220fc89c0fbSmrg	}
1221fc89c0fbSmrg    } else
1222fc89c0fbSmrg	printf("%s", Format_Thunk_I(thunks, format, (int) i));
1223fc89c0fbSmrg
1224fc89c0fbSmrg    return dformat;
1225fc89c0fbSmrg}
1226fc89c0fbSmrg
1227fc89c0fbSmrgstatic int
1228fc89c0fbSmrgMask_Bit_I (thunk *thunks, const char *format, int i)
1229fc89c0fbSmrg{
1230fc89c0fbSmrg    long value;
1231fc89c0fbSmrg
1232fc89c0fbSmrg    value = Mask_Word(thunks, format);
1233fc89c0fbSmrg
1234fc89c0fbSmrg    value = value & (1L<<i);
1235fc89c0fbSmrg    if (value)
1236fc89c0fbSmrg	value = 1;
1237fc89c0fbSmrg    return value;
1238fc89c0fbSmrg}
1239fc89c0fbSmrg
1240fc89c0fbSmrgstatic const char *
1241fc89c0fbSmrgScan_Term (const char *string, thunk *thunks, const char *format, long *value)
1242fc89c0fbSmrg{
1243fc89c0fbSmrg    long i;
1244fc89c0fbSmrg
1245fc89c0fbSmrg    *value = 0;
1246fc89c0fbSmrg
1247fc89c0fbSmrg    if (isdigit((unsigned char) *string))
1248fc89c0fbSmrg	string = Scan_Long(string, value);
1249fc89c0fbSmrg    else if (*string == '$') {
1250fc89c0fbSmrg	string = Scan_Long(++string, &i);
1251fc89c0fbSmrg	if (i >= thunks->thunk_count)
1252fc89c0fbSmrg	    i = thunks->thunk_count;
1253fc89c0fbSmrg	*value = thunks[i].value;
1254fc89c0fbSmrg    } else if (*string == 'm') {
1255fc89c0fbSmrg	string = Scan_Long(++string, &i);
1256fc89c0fbSmrg	*value = Mask_Bit_I(thunks, format, (int) i);
1257fc89c0fbSmrg    } else
1258fc89c0fbSmrg	Fatal_Error("Bad term: %s.", string);
1259fc89c0fbSmrg
1260fc89c0fbSmrg    return string;
1261fc89c0fbSmrg}
1262fc89c0fbSmrg
1263fc89c0fbSmrgstatic const char *
1264fc89c0fbSmrgScan_Exp (const char *string, thunk *thunks, const char *format, long *value)
1265fc89c0fbSmrg{
1266fc89c0fbSmrg    long temp;
1267fc89c0fbSmrg
1268fc89c0fbSmrg    if (string[0] == '(') {
1269fc89c0fbSmrg	string = Scan_Exp(++string, thunks, format, value);
1270fc89c0fbSmrg	if (string[0]!=')')
1271fc89c0fbSmrg	    Fatal_Error("Missing ')'");
1272fc89c0fbSmrg	return ++string;
1273fc89c0fbSmrg    }
1274fc89c0fbSmrg    if (string[0] == '!') {
1275fc89c0fbSmrg	string = Scan_Exp(++string, thunks, format, value);
1276fc89c0fbSmrg	*value = !*value;
1277fc89c0fbSmrg	return string;
1278fc89c0fbSmrg    }
1279fc89c0fbSmrg
1280fc89c0fbSmrg    string = Scan_Term(string, thunks, format, value);
1281fc89c0fbSmrg
1282fc89c0fbSmrg    if (string[0] == '=') {
1283fc89c0fbSmrg	string = Scan_Exp(++string, thunks, format, &temp);
1284fc89c0fbSmrg	*value = *value == temp;
1285fc89c0fbSmrg    }
1286fc89c0fbSmrg
1287fc89c0fbSmrg    return string;
1288fc89c0fbSmrg}
1289fc89c0fbSmrg
1290fc89c0fbSmrgstatic const char *
1291fc89c0fbSmrgHandle_Question_Mark (const char *dformat, thunk *thunks, const char *format)
1292fc89c0fbSmrg{
1293fc89c0fbSmrg    long true;
1294fc89c0fbSmrg
1295fc89c0fbSmrg    dformat = Scan_Exp(dformat, thunks, format, &true);
1296fc89c0fbSmrg
1297fc89c0fbSmrg    if (*dformat != '(')
1298fc89c0fbSmrg	Fatal_Error("Bad conditional: '(' expected: %s.", dformat);
1299fc89c0fbSmrg    ++dformat;
1300fc89c0fbSmrg
1301fc89c0fbSmrg    if (!true)
1302fc89c0fbSmrg	dformat = Skip_Past_Right_Paren(dformat);
1303fc89c0fbSmrg
1304fc89c0fbSmrg    return dformat;
1305fc89c0fbSmrg}
1306fc89c0fbSmrg
1307fc89c0fbSmrgstatic void
1308fc89c0fbSmrgDisplay_Property (thunk *thunks, const char *dformat, const char *format)
1309fc89c0fbSmrg{
1310fc89c0fbSmrg    char c;
1311fc89c0fbSmrg
1312fc89c0fbSmrg    while ((c = *(dformat++)))
1313fc89c0fbSmrg	switch (c) {
1314fc89c0fbSmrg	  case ')':
1315fc89c0fbSmrg	    continue;
1316fc89c0fbSmrg	  case '\\':
1317fc89c0fbSmrg	    dformat = Handle_Backslash(dformat);
1318fc89c0fbSmrg	    continue;
1319fc89c0fbSmrg	  case '$':
1320fc89c0fbSmrg	    dformat = Handle_Dollar_sign(dformat, thunks, format);
1321fc89c0fbSmrg	    continue;
1322fc89c0fbSmrg	  case '?':
1323fc89c0fbSmrg	    dformat = Handle_Question_Mark(dformat, thunks, format);
1324fc89c0fbSmrg	    continue;
1325fc89c0fbSmrg	  default:
1326fc89c0fbSmrg	    putchar(c);
1327fc89c0fbSmrg	    continue;
1328fc89c0fbSmrg	}
1329fc89c0fbSmrg}
1330fc89c0fbSmrg
1331fc89c0fbSmrg/*
1332fc89c0fbSmrg *
1333fc89c0fbSmrg * Routines to convert property data to thunks
1334fc89c0fbSmrg *
1335fc89c0fbSmrg */
1336fc89c0fbSmrg
1337fc89c0fbSmrgstatic long
1338fc89c0fbSmrgExtract_Value (const char **pointer, int *length, int size, int signedp)
1339fc89c0fbSmrg{
1340fc89c0fbSmrg    long value;
1341fc89c0fbSmrg
1342fc89c0fbSmrg    switch (size) {
1343fc89c0fbSmrg      case 8:
1344fc89c0fbSmrg	if (signedp)
1345fc89c0fbSmrg	    value = * (const signed char *) *pointer;
1346fc89c0fbSmrg	else
1347fc89c0fbSmrg	    value = * (const unsigned char *) *pointer;
1348fc89c0fbSmrg	*pointer += 1;
1349fc89c0fbSmrg	*length -= 1;
1350fc89c0fbSmrg	break;
1351fc89c0fbSmrg      case 16:
1352fc89c0fbSmrg	if (signedp)
1353fc89c0fbSmrg	    value = * (const short *) *pointer;
1354fc89c0fbSmrg	else
1355fc89c0fbSmrg	    value = * (const unsigned short *) *pointer;
1356fc89c0fbSmrg	*pointer += sizeof(short);
1357fc89c0fbSmrg	*length -= sizeof(short);
1358fc89c0fbSmrg	break;
1359fc89c0fbSmrg      case 32:
1360fc89c0fbSmrg	if (signedp)
1361fc89c0fbSmrg	    value = * (const long *) *pointer;
1362fc89c0fbSmrg	else
1363fc89c0fbSmrg	    value = * (const unsigned long *) *pointer & 0xffffffff;
1364fc89c0fbSmrg	*pointer += sizeof(long);
1365fc89c0fbSmrg	*length -= sizeof(long);
1366fc89c0fbSmrg	break;
1367fc89c0fbSmrg      default:
1368fc89c0fbSmrg	abort();
1369fc89c0fbSmrg    }
1370fc89c0fbSmrg    return value;
1371fc89c0fbSmrg}
1372fc89c0fbSmrg
1373fc89c0fbSmrgstatic long
1374fc89c0fbSmrgExtract_Len_String (const char **pointer, int *length, int size, const char **string)
1375fc89c0fbSmrg{
1376fc89c0fbSmrg    int len;
1377fc89c0fbSmrg
1378fc89c0fbSmrg    if (size != 8)
1379fc89c0fbSmrg	Fatal_Error("can't use format character 's' with any size except 8.");
1380fc89c0fbSmrg    len = 0; *string = *pointer;
1381fc89c0fbSmrg    while ((len++, --*length, *((*pointer)++)) && *length>0);
1382fc89c0fbSmrg
1383fc89c0fbSmrg    return len;
1384fc89c0fbSmrg}
1385fc89c0fbSmrg
138691ec45ceSmrgstatic long
138791ec45ceSmrgExtract_Icon (const char **pointer, int *length, int size, const char **icon)
138891ec45ceSmrg{
138991ec45ceSmrg    int len = 0;
139091ec45ceSmrg
139191ec45ceSmrg    if (size != 32)
139291ec45ceSmrg	Fatal_Error("can't use format character 'o' with any size except 32.");
139391ec45ceSmrg
139491ec45ceSmrg    len = *length;
139591ec45ceSmrg    *icon = *pointer;
139691ec45ceSmrg    *length = 0;
139791ec45ceSmrg    return len;
139891ec45ceSmrg}
139991ec45ceSmrg
1400fc89c0fbSmrgstatic thunk *
1401fc89c0fbSmrgBreak_Down_Property (const char *pointer, int length, Atom type, const char *format, int size)
1402fc89c0fbSmrg{
1403fc89c0fbSmrg    thunk *thunks;
1404f4a95042Smrg    thunk t = {0};
1405fc89c0fbSmrg    int i;
1406fc89c0fbSmrg    char format_char;
1407fc89c0fbSmrg
1408fc89c0fbSmrg    thunks = Create_Thunk_List();
1409fc89c0fbSmrg    i = 0;
1410fc89c0fbSmrg
1411fc89c0fbSmrg    while (length >= size/8) {
1412fc89c0fbSmrg	format_char = Get_Format_Char(format, i);
1413a0996ce0Smrg	if (format_char == 's' || format_char == 'u')
1414fc89c0fbSmrg	    t.value = Extract_Len_String(&pointer,&length,size,&t.extra_value);
1415fc89c0fbSmrg	else if (format_char == 't') {
1416fc89c0fbSmrg	    t.extra_encoding = type;
1417fc89c0fbSmrg	    t.value = Extract_Len_String(&pointer,&length,size,&t.extra_value);
141891ec45ceSmrg	}
141991ec45ceSmrg	else if (format_char == 'o')
142091ec45ceSmrg	    t.value = Extract_Icon (&pointer,&length,size,&t.extra_value);
142191ec45ceSmrg	else
1422fc89c0fbSmrg	    t.value = Extract_Value(&pointer,&length,size,format_char=='i');
1423fc89c0fbSmrg	thunks = Add_Thunk(thunks, t);
1424fc89c0fbSmrg	i++;
1425fc89c0fbSmrg    }
1426fc89c0fbSmrg
1427fc89c0fbSmrg    return thunks;
1428fc89c0fbSmrg}
1429fc89c0fbSmrg
1430fc89c0fbSmrg/*
1431fc89c0fbSmrg * Variables set by main()
1432fc89c0fbSmrg */
1433fc89c0fbSmrg
1434fc89c0fbSmrgstatic Window target_win = 0;
1435fc89c0fbSmrgstatic int notype = 0;
1436fc89c0fbSmrgstatic int max_len = MAXSTR;
1437fc89c0fbSmrgstatic XFontStruct *font;
1438fc89c0fbSmrgstatic unsigned long _font_prop;
1439fc89c0fbSmrg
1440fc89c0fbSmrg/*
1441fc89c0fbSmrg *
1442fc89c0fbSmrg * Other Stuff (temp.):
1443fc89c0fbSmrg *
1444fc89c0fbSmrg */
1445fc89c0fbSmrg
1446fc89c0fbSmrgstatic const char *
1447fc89c0fbSmrgGet_Font_Property_Data_And_Type (Atom atom,
1448fc89c0fbSmrg                                 long *length, Atom *type, int *size)
1449fc89c0fbSmrg{
1450fc89c0fbSmrg    int i;
1451fc89c0fbSmrg
1452fc89c0fbSmrg    *type = None;
1453fc89c0fbSmrg
1454fc89c0fbSmrg    for (i = 0; i < font->n_properties; i++)
1455fc89c0fbSmrg	if (atom == font->properties[i].name) {
1456fc89c0fbSmrg	    _font_prop = font->properties[i].card32;
1457fc89c0fbSmrg	    *length = sizeof(long);
1458fc89c0fbSmrg	    *size = 32;
1459fc89c0fbSmrg	    return (const char *) &_font_prop;
1460fc89c0fbSmrg	}
1461fc89c0fbSmrg    *size = 0;
1462fc89c0fbSmrg    return NULL;
1463fc89c0fbSmrg}
1464fc89c0fbSmrg
1465fc89c0fbSmrgstatic const char *
1466fc89c0fbSmrgGet_Window_Property_Data_And_Type (Atom atom,
1467fc89c0fbSmrg                                   long *length, Atom *type, int *size)
1468fc89c0fbSmrg{
1469fc89c0fbSmrg    Atom actual_type;
1470fc89c0fbSmrg    int actual_format;
1471fc89c0fbSmrg    unsigned long nitems;
1472fc89c0fbSmrg    unsigned long nbytes;
1473fc89c0fbSmrg    unsigned long bytes_after;
147481676fe2Smrg    static unsigned char *prop = NULL;
1475fc89c0fbSmrg    int status;
147681676fe2Smrg
147781676fe2Smrg    if (prop)
147881676fe2Smrg    {
147981676fe2Smrg	XFree(prop);
148081676fe2Smrg	prop = NULL;
148181676fe2Smrg    }
148281676fe2Smrg
1483fc89c0fbSmrg    status = XGetWindowProperty(dpy, target_win, atom, 0, (max_len+3)/4,
1484fc89c0fbSmrg				False, AnyPropertyType, &actual_type,
1485fc89c0fbSmrg				&actual_format, &nitems, &bytes_after,
1486fc89c0fbSmrg				&prop);
1487fc89c0fbSmrg    if (status == BadWindow)
1488fc89c0fbSmrg	Fatal_Error("window id # 0x%lx does not exists!", target_win);
1489fc89c0fbSmrg    if (status != Success)
1490fc89c0fbSmrg	Fatal_Error("XGetWindowProperty failed!");
1491fc89c0fbSmrg
1492fc89c0fbSmrg    if (actual_format == 32)
1493fc89c0fbSmrg	nbytes = sizeof(long);
1494fc89c0fbSmrg    else if (actual_format == 16)
1495fc89c0fbSmrg	nbytes = sizeof(short);
1496fc89c0fbSmrg    else if (actual_format == 8)
1497fc89c0fbSmrg	nbytes = 1;
1498fc89c0fbSmrg    else if (actual_format == 0)
1499fc89c0fbSmrg        nbytes = 0;
1500fc89c0fbSmrg    else
1501fc89c0fbSmrg	abort();
1502fc89c0fbSmrg    *length = min(nitems * nbytes, max_len);
1503fc89c0fbSmrg    *type = actual_type;
1504fc89c0fbSmrg    *size = actual_format;
1505fc89c0fbSmrg    return (const char *)prop;
1506fc89c0fbSmrg}
1507fc89c0fbSmrg
1508fc89c0fbSmrgstatic const char *
1509fc89c0fbSmrgGet_Property_Data_And_Type (Atom atom, long *length, Atom *type, int *size)
1510fc89c0fbSmrg{
1511fc89c0fbSmrg    if (target_win == -1)
1512fc89c0fbSmrg	return Get_Font_Property_Data_And_Type(atom, length, type, size);
1513fc89c0fbSmrg    else
1514fc89c0fbSmrg	return Get_Window_Property_Data_And_Type(atom, length, type, size);
1515fc89c0fbSmrg}
1516fc89c0fbSmrg
1517fc89c0fbSmrgstatic void
1518fc89c0fbSmrgShow_Prop (const char *format, const char *dformat, const char *prop)
1519fc89c0fbSmrg{
1520fc89c0fbSmrg    const char *data;
1521fc89c0fbSmrg    long length;
1522fc89c0fbSmrg    Atom atom, type;
1523fc89c0fbSmrg    thunk *thunks;
1524fc89c0fbSmrg    int size, fsize;
1525fc89c0fbSmrg
1526fc89c0fbSmrg    printf("%s", prop);
1527fc89c0fbSmrg    atom = Parse_Atom(prop, True);
1528fc89c0fbSmrg    if (atom == None) {
1529fc89c0fbSmrg	printf(":  no such atom on any window.\n");
1530fc89c0fbSmrg	return;
1531fc89c0fbSmrg    }
1532fc89c0fbSmrg
1533fc89c0fbSmrg    data = Get_Property_Data_And_Type(atom, &length, &type, &size);
1534fc89c0fbSmrg    if (!size) {
1535fc89c0fbSmrg	puts(":  not found.");
1536fc89c0fbSmrg	return;
1537fc89c0fbSmrg    }
1538fc89c0fbSmrg
1539fc89c0fbSmrg    if (!notype && type != None)
1540fc89c0fbSmrg	printf("(%s)", Format_Atom(type));
1541fc89c0fbSmrg
1542fc89c0fbSmrg    Lookup_Formats(atom, &format, &dformat);
1543fc89c0fbSmrg    if (type != None)
1544fc89c0fbSmrg	Lookup_Formats(type, &format, &dformat);
1545fc89c0fbSmrg    Apply_Default_Formats(&format, &dformat);
1546fc89c0fbSmrg
1547fc89c0fbSmrg    fsize = Get_Format_Size(format);
1548fc89c0fbSmrg    if (fsize != size && fsize != 0) {
1549fc89c0fbSmrg	printf(": Type mismatch: assumed size %d bits, actual size %d bits.\n",
1550fc89c0fbSmrg	       fsize, size);
1551fc89c0fbSmrg	return;
1552fc89c0fbSmrg    }
1553fc89c0fbSmrg
1554fc89c0fbSmrg    thunks = Break_Down_Property(data, (int)length, type, format, size);
1555fc89c0fbSmrg    Display_Property(thunks, dformat, format);
155681676fe2Smrg    free(thunks);
1557fc89c0fbSmrg}
1558fc89c0fbSmrg
1559fc89c0fbSmrgstatic void
1560fc89c0fbSmrgShow_All_Props (void)
1561fc89c0fbSmrg{
1562fc89c0fbSmrg    Atom *atoms, atom;
1563fc89c0fbSmrg    const char *name;
1564fc89c0fbSmrg    int count, i;
1565fc89c0fbSmrg
1566fc89c0fbSmrg    if (target_win != -1) {
1567fc89c0fbSmrg	atoms = XListProperties(dpy, target_win, &count);
1568fc89c0fbSmrg	for (i = 0; i < count; i++) {
1569fc89c0fbSmrg	    name = Format_Atom(atoms[i]);
1570fc89c0fbSmrg	    Show_Prop(NULL, NULL, name);
1571fc89c0fbSmrg	}
157281676fe2Smrg	XFree(atoms);
1573fc89c0fbSmrg    } else
1574fc89c0fbSmrg	for (i = 0; i < font->n_properties; i++) {
1575fc89c0fbSmrg	    atom = font->properties[i].name;
1576fc89c0fbSmrg	    name = Format_Atom(atom);
1577fc89c0fbSmrg	    Show_Prop(NULL, NULL, name);
1578fc89c0fbSmrg	}
1579fc89c0fbSmrg}
1580fc89c0fbSmrg
1581fc89c0fbSmrgstatic thunk *
1582fc89c0fbSmrgHandle_Prop_Requests (int argc, char **argv)
1583fc89c0fbSmrg{
1584fc89c0fbSmrg    char *format, *dformat, *prop;
1585f4a95042Smrg    thunk *thunks, t = {0};
1586fc89c0fbSmrg
1587fc89c0fbSmrg    /* if no prop referenced, by default list all properties for given window */
1588fc89c0fbSmrg    if (!argc) {
1589fc89c0fbSmrg	Show_All_Props();
1590fc89c0fbSmrg	return NULL;
1591fc89c0fbSmrg    }
1592fc89c0fbSmrg
1593fc89c0fbSmrg    thunks = Create_Thunk_List();
1594fc89c0fbSmrg
1595fc89c0fbSmrg    while (argc > 0) {
1596fc89c0fbSmrg	format = NULL;
1597fc89c0fbSmrg	dformat = NULL;
1598fc89c0fbSmrg
1599fc89c0fbSmrg	/* Get overriding formats, if any */
1600fc89c0fbSmrg	if (Is_A_Format(argv[0])) {
1601fc89c0fbSmrg	    format = argv++[0]; argc--;
160281676fe2Smrg	    if (!argc) usage("format specified without atom");
1603fc89c0fbSmrg	}
1604fc89c0fbSmrg	if (Is_A_DFormat(argv[0])) {
1605fc89c0fbSmrg	    dformat = argv++[0]; argc--;
160681676fe2Smrg	    if (!argc) usage("dformat specified without atom");
1607fc89c0fbSmrg	}
1608fc89c0fbSmrg
1609fc89c0fbSmrg	/* Get property name */
1610fc89c0fbSmrg	prop = argv++[0]; argc--;
1611fc89c0fbSmrg
1612fc89c0fbSmrg	t.propname = prop;
1613fc89c0fbSmrg	t.value = Parse_Atom(prop, True);
1614fc89c0fbSmrg	t.format = format;
1615fc89c0fbSmrg	t.dformat = dformat;
1616fc89c0fbSmrg	if (t.value)
1617fc89c0fbSmrg	    thunks = Add_Thunk(thunks, t);
1618fc89c0fbSmrg	Show_Prop(format, dformat, prop);
1619fc89c0fbSmrg    }
1620fc89c0fbSmrg    return thunks;
1621fc89c0fbSmrg}
1622fc89c0fbSmrg
1623fc89c0fbSmrgstatic void
1624fc89c0fbSmrgRemove_Property (Display *dpy, Window w, const char *propname)
1625fc89c0fbSmrg{
1626fc89c0fbSmrg    Atom id = XInternAtom (dpy, propname, True);
1627fc89c0fbSmrg
1628fc89c0fbSmrg    if (id == None) {
1629fc89c0fbSmrg	fprintf (stderr, "%s:  no such property \"%s\"\n",
1630fc89c0fbSmrg		 program_name, propname);
1631fc89c0fbSmrg	return;
1632fc89c0fbSmrg    }
1633fc89c0fbSmrg    XDeleteProperty (dpy, w, id);
1634fc89c0fbSmrg}
1635fc89c0fbSmrg
1636fc89c0fbSmrgstatic void
1637fc89c0fbSmrgSet_Property (Display *dpy, Window w, const char *propname, const char *value)
1638fc89c0fbSmrg{
1639fc89c0fbSmrg    Atom atom;
1640fc89c0fbSmrg    const char *format;
1641fc89c0fbSmrg    const char *dformat;
1642fc89c0fbSmrg    int size;
1643fc89c0fbSmrg    char format_char;
1644fc89c0fbSmrg    Atom type = 0;
1645576bbdfcSmrg    const unsigned char *data = NULL;
1646fc89c0fbSmrg    int nelements = 0;
1647fc89c0fbSmrg
1648fc89c0fbSmrg    atom = Parse_Atom(propname, False);
1649fc89c0fbSmrg
1650fc89c0fbSmrg    format = dformat = NULL;
1651fc89c0fbSmrg    Lookup_Formats(atom, &format, &dformat);
1652fc89c0fbSmrg    if (format == NULL)
1653fc89c0fbSmrg	Fatal_Error("unsupported conversion for %s", propname);
1654fc89c0fbSmrg
1655fc89c0fbSmrg    size = Get_Format_Size(format);
1656fc89c0fbSmrg
1657fc89c0fbSmrg    format_char = Get_Format_Char(format, 0);
1658fc89c0fbSmrg    switch (format_char) {
1659fc89c0fbSmrg      case 's':
1660fc89c0fbSmrg	if (size != 8)
1661fc89c0fbSmrg	    Fatal_Error("can't use format character 's' with any size except 8.");
1662fc89c0fbSmrg	type = XA_STRING;
1663576bbdfcSmrg	data = (const unsigned char *) value;
1664576bbdfcSmrg	nelements = strlen(value);
1665576bbdfcSmrg	break;
1666576bbdfcSmrg      case 'u':
1667576bbdfcSmrg	if (size != 8)
1668576bbdfcSmrg	    Fatal_Error("can't use format character 'u' with any size except 8.");
1669576bbdfcSmrg	type = XInternAtom(dpy, "UTF8_STRING", False);
1670576bbdfcSmrg	data = (const unsigned char *) value;
1671fc89c0fbSmrg	nelements = strlen(value);
1672fc89c0fbSmrg	break;
1673fc89c0fbSmrg      case 't': {
1674fc89c0fbSmrg	XTextProperty textprop;
1675fc89c0fbSmrg	if (size != 8)
1676fc89c0fbSmrg	    Fatal_Error("can't use format character 't' with any size except 8.");
1677fc89c0fbSmrg	if (XmbTextListToTextProperty(dpy, (char **) &value, 1,
1678fc89c0fbSmrg				      XStdICCTextStyle, &textprop) != Success) {
1679fc89c0fbSmrg	    fprintf(stderr, "cannot convert %s argument to STRING or COMPOUND_TEXT.\n", propname);
1680fc89c0fbSmrg	    return;
1681fc89c0fbSmrg	}
1682fc89c0fbSmrg	type = textprop.encoding;
1683fc89c0fbSmrg	data = textprop.value;
1684fc89c0fbSmrg	nelements = textprop.nitems;
1685fc89c0fbSmrg	break;
1686fc89c0fbSmrg      }
1687fc89c0fbSmrg      case 'x':
1688fc89c0fbSmrg      case 'c': {
1689fc89c0fbSmrg	static unsigned char data8[MAXELEMENTS];
1690fc89c0fbSmrg	static unsigned short data16[MAXELEMENTS];
1691fc89c0fbSmrg	static unsigned long data32[MAXELEMENTS];
1692fc89c0fbSmrg	unsigned long intvalue;
1693fc89c0fbSmrg	char * value2 = strdup(value);
1694fc89c0fbSmrg	char * tmp = strtok(value2,",");
1695fc89c0fbSmrg	nelements = 1;
1696fc89c0fbSmrg	intvalue = strtoul(tmp, NULL, 0);
1697fc89c0fbSmrg	switch(size) {
1698fc89c0fbSmrg	    case 8:
1699576bbdfcSmrg	        data8[0] = intvalue; data = (const unsigned char *) data8; break;
1700fc89c0fbSmrg	    case 16:
1701576bbdfcSmrg	        data16[0] = intvalue; data = (const unsigned char *) data16; break;
1702fc89c0fbSmrg	    case 32:
1703576bbdfcSmrg	        data32[0] = intvalue; data = (const unsigned char *) data32; break;
1704fc89c0fbSmrg	}
1705fc89c0fbSmrg	tmp = strtok(NULL,",");
1706fc89c0fbSmrg	while(tmp != NULL){
1707fc89c0fbSmrg	    intvalue = strtoul(tmp, NULL,0);
1708fc89c0fbSmrg	    switch(size) {
1709fc89c0fbSmrg		case 8:
1710fc89c0fbSmrg	    	    data8[nelements] = intvalue; break;
1711fc89c0fbSmrg		case 16:
1712fc89c0fbSmrg	    	    data16[nelements] = intvalue; break;
1713fc89c0fbSmrg		case 32:
1714fc89c0fbSmrg	    	    data32[nelements] = intvalue; break;
1715fc89c0fbSmrg	    }
1716fc89c0fbSmrg	    nelements++;
1717fc89c0fbSmrg	    if(nelements == MAXELEMENTS){
1718fc89c0fbSmrg		fprintf(stderr, "Maximum number of elements reached (%d). List truncated.\n",MAXELEMENTS);
1719fc89c0fbSmrg		break;
1720fc89c0fbSmrg	    }
1721fc89c0fbSmrg	    tmp = strtok(NULL,",");
1722fc89c0fbSmrg	}
1723fc89c0fbSmrg
1724fc89c0fbSmrg	type = XA_CARDINAL;
1725fc89c0fbSmrg	free(value2);
1726fc89c0fbSmrg	break;
1727fc89c0fbSmrg      }
1728fc89c0fbSmrg      case 'i': {
1729fc89c0fbSmrg	static unsigned char data8[MAXELEMENTS];
1730fc89c0fbSmrg	static unsigned short data16[MAXELEMENTS];
1731fc89c0fbSmrg	static unsigned long data32[MAXELEMENTS];
1732fc89c0fbSmrg	unsigned long intvalue;
1733fc89c0fbSmrg	char * value2 = strdup(value);
1734fc89c0fbSmrg	char * tmp = strtok(value2,",");
1735fc89c0fbSmrg	nelements = 1;
1736fc89c0fbSmrg	intvalue = strtoul(tmp, NULL, 0);
1737fc89c0fbSmrg	switch(size) {
1738fc89c0fbSmrg	    case 8:
1739576bbdfcSmrg	        data8[0] = intvalue; data = (const unsigned char *) data8; break;
1740fc89c0fbSmrg	    case 16:
1741576bbdfcSmrg	        data16[0] = intvalue; data = (const unsigned char *) data16; break;
1742fc89c0fbSmrg	    case 32:
1743576bbdfcSmrg	        data32[0] = intvalue; data = (const unsigned char *) data32; break;
1744fc89c0fbSmrg	}
1745fc89c0fbSmrg	tmp = strtok(NULL,",");
1746fc89c0fbSmrg	while(tmp != NULL){
1747fc89c0fbSmrg	    intvalue = strtoul(tmp, NULL,0);
1748fc89c0fbSmrg	    switch(size) {
1749fc89c0fbSmrg		case 8:
1750fc89c0fbSmrg	    	    data8[nelements] = intvalue; break;
1751fc89c0fbSmrg		case 16:
1752fc89c0fbSmrg	    	    data16[nelements] = intvalue; break;
1753fc89c0fbSmrg		case 32:
1754fc89c0fbSmrg	    	    data32[nelements] = intvalue; break;
1755fc89c0fbSmrg	    }
1756fc89c0fbSmrg	    nelements++;
1757fc89c0fbSmrg	    if(nelements == MAXELEMENTS){
1758fc89c0fbSmrg		fprintf(stderr, "Maximum number of elements reached (%d). List truncated.\n",MAXELEMENTS);
1759fc89c0fbSmrg		break;
1760fc89c0fbSmrg	    }
1761fc89c0fbSmrg	    tmp = strtok(NULL,",");
1762fc89c0fbSmrg	}
1763fc89c0fbSmrg
1764fc89c0fbSmrg	type = XA_INTEGER;
1765fc89c0fbSmrg	free(value2);
1766fc89c0fbSmrg	break;
1767fc89c0fbSmrg      }
1768fc89c0fbSmrg      case 'b': {
1769fc89c0fbSmrg	unsigned long boolvalue;
1770fc89c0fbSmrg	static unsigned char data8;
1771fc89c0fbSmrg	static unsigned short data16;
1772fc89c0fbSmrg	static unsigned long data32;
1773fc89c0fbSmrg	if (!strcmp(value, "True"))
1774fc89c0fbSmrg	    boolvalue = 1;
1775fc89c0fbSmrg	else if (!strcmp(value, "False"))
1776fc89c0fbSmrg	    boolvalue = 0;
1777fc89c0fbSmrg	else {
1778fc89c0fbSmrg	    fprintf(stderr, "cannot convert %s argument to Bool\n", propname);
1779fc89c0fbSmrg	    return;
1780fc89c0fbSmrg	}
1781fc89c0fbSmrg	type = XA_INTEGER;
1782fc89c0fbSmrg	switch (size) {
1783fc89c0fbSmrg	  case 8:
1784576bbdfcSmrg	    data8 = boolvalue; data = (const unsigned char *) &data8; break;
1785fc89c0fbSmrg	  case 16:
1786576bbdfcSmrg	    data16 = boolvalue; data = (const unsigned char *) &data16; break;
1787fc89c0fbSmrg	  case 32: default:
1788576bbdfcSmrg	    data32 = boolvalue; data = (const unsigned char *) &data32; break;
1789fc89c0fbSmrg	}
1790fc89c0fbSmrg	nelements = 1;
1791fc89c0fbSmrg	break;
1792fc89c0fbSmrg      }
1793fc89c0fbSmrg      case 'a': {
1794fc89c0fbSmrg	static Atom avalue;
1795fc89c0fbSmrg	avalue = Parse_Atom(value, False);
1796fc89c0fbSmrg	type = XA_ATOM;
1797576bbdfcSmrg	data = (const unsigned char *) &avalue;
1798fc89c0fbSmrg	nelements = 1;
1799fc89c0fbSmrg	break;
1800fc89c0fbSmrg      }
1801fc89c0fbSmrg      case 'm':
1802fc89c0fbSmrg	/* NYI */
1803fc89c0fbSmrg      default:
1804fc89c0fbSmrg	Fatal_Error("bad format character: %c", format_char);
1805fc89c0fbSmrg    }
1806fc89c0fbSmrg
1807fc89c0fbSmrg    XChangeProperty(dpy, target_win, atom, type, size, PropModeReplace,
1808fc89c0fbSmrg		    data, nelements);
1809fc89c0fbSmrg}
1810fc89c0fbSmrg
1811fc89c0fbSmrg/*
1812fc89c0fbSmrg *
1813fc89c0fbSmrg * Routines for parsing command line:
1814fc89c0fbSmrg *
1815fc89c0fbSmrg */
1816fc89c0fbSmrg
1817fc89c0fbSmrgvoid
1818f9c28e31Smrgprint_help (void)
1819fc89c0fbSmrg{
182081676fe2Smrg    static const char *help_message =
1821fc89c0fbSmrg"where options include:\n"
1822f9c28e31Smrg"    -help                          print out a summary of command line options\n"
1823fc89c0fbSmrg"    -grammar                       print out full grammar for command line\n"
1824fc89c0fbSmrg"    -display host:dpy              the X server to contact\n"
1825fc89c0fbSmrg"    -id id                         resource id of window to examine\n"
1826fc89c0fbSmrg"    -name name                     name of window to examine\n"
1827fc89c0fbSmrg"    -font name                     name of font to examine\n"
1828fc89c0fbSmrg"    -remove propname               remove a property\n"
1829fc89c0fbSmrg"    -set propname value            set a property to a given value\n"
1830fc89c0fbSmrg"    -root                          examine the root window\n"
1831fc89c0fbSmrg"    -len n                         display at most n bytes of any property\n"
1832fc89c0fbSmrg"    -notype                        do not display the type field\n"
1833fc89c0fbSmrg"    -fs filename                   where to look for formats for properties\n"
1834fc89c0fbSmrg"    -frame                         don't ignore window manager frames\n"
1835fc89c0fbSmrg"    -f propname format [dformat]   formats to use for property of given name\n"
183681676fe2Smrg"    -spy                           examine window properties forever\n"
183781676fe2Smrg"    -version                       print program version\n";
1838fc89c0fbSmrg
1839fc89c0fbSmrg
1840fc89c0fbSmrg    fflush (stdout);
184181676fe2Smrg
1842fc89c0fbSmrg    fprintf (stderr,
1843fc89c0fbSmrg	     "usage:  %s [-options ...] [[format [dformat]] atom] ...\n\n",
1844fc89c0fbSmrg	     program_name);
1845fc89c0fbSmrg    fprintf (stderr, "%s\n", help_message);
1846f9c28e31Smrg}
1847f9c28e31Smrg
1848f9c28e31Smrgvoid help (void) {
1849f9c28e31Smrg	print_help();
1850f9c28e31Smrg	exit(0);
1851f9c28e31Smrg}
1852f9c28e31Smrg
1853f9c28e31Smrgvoid
1854f9c28e31Smrgusage (const char *errmsg)
1855f9c28e31Smrg{
1856f9c28e31Smrg    if (errmsg != NULL)
1857f9c28e31Smrg	fprintf (stderr, "%s: %s\n\n", program_name, errmsg);
1858f9c28e31Smrg
1859f9c28e31Smrg    print_help();
1860fc89c0fbSmrg    exit (1);
1861fc89c0fbSmrg}
1862fc89c0fbSmrg
1863fc89c0fbSmrgstatic void
1864fc89c0fbSmrggrammar (void)
1865fc89c0fbSmrg{
1866fc89c0fbSmrg    printf ("Grammar for xprop:\n\n");
1867fc89c0fbSmrg    printf("\t%s [<disp>] [<select option>] <option>* <mapping>* <spec>*",
1868fc89c0fbSmrg	   program_name);
1869fc89c0fbSmrg    printf("\n\n\tdisp ::= -display host:dpy\
1870fc89c0fbSmrg\n\tselect option ::= -root | -id <id> | -font <font> | -name <name>\
1871fc89c0fbSmrg\n\toption ::= -len <n> | -notype | -spy | {-formats|-fs} <format file>\
1872fc89c0fbSmrg\n\tmapping ::= {-f|-format} <atom> <format> [<dformat>]\
1873fc89c0fbSmrg\n\t            | -remove <propname>\
1874fc89c0fbSmrg\n\t            | -set <propname> <value>\
1875fc89c0fbSmrg\n\tspec ::= [<format> [<dformat>]] <atom>\
1876fc89c0fbSmrg\n\tformat ::= {0|8|16|32}{a|b|c|i|m|s|t|x}*\
1877fc89c0fbSmrg\n\tdformat ::= <unit><unit>*             (can't start with a letter or '-')\
1878fc89c0fbSmrg\n\tunit ::= ?<exp>(<unit>*) | $<n> | <display char>\
1879fc89c0fbSmrg\n\texp ::= <term> | <term>=<exp> | !<exp>\
1880fc89c0fbSmrg\n\tterm ::= <n> | $<n> | m<n>\
1881fc89c0fbSmrg\n\tdisplay char ::= <normal char> | \\<non digit char> | \\<octal number>\
1882fc89c0fbSmrg\n\tnormal char ::= <any char except a digit, $, ?, \\, or )>\
1883fc89c0fbSmrg\n\n");
1884fc89c0fbSmrg    exit(0);
1885fc89c0fbSmrg}
1886fc89c0fbSmrg
1887fc89c0fbSmrgstatic void
1888fc89c0fbSmrgParse_Format_Mapping (int *argc, char ***argv)
1889fc89c0fbSmrg{
1890fc89c0fbSmrg#define ARGC (*argc)
1891fc89c0fbSmrg#define ARGV (*argv)
1892fc89c0fbSmrg#define OPTION ARGV[0]
189381676fe2Smrg#define NXTOPT if (++ARGV, --ARGC==0) usage("insufficent arguments for -format")
1894fc89c0fbSmrg    char *type_name, *format, *dformat;
1895fc89c0fbSmrg
1896fc89c0fbSmrg    NXTOPT; type_name = OPTION;
1897fc89c0fbSmrg
1898fc89c0fbSmrg    NXTOPT; format = OPTION;
1899fc89c0fbSmrg    if (!Is_A_Format(format))
1900fc89c0fbSmrg	Fatal_Error("Bad format: %s.", format);
1901fc89c0fbSmrg
1902fc89c0fbSmrg    dformat = NULL;
1903fc89c0fbSmrg    if (ARGC>1 && Is_A_DFormat(ARGV[1])) {
1904fc89c0fbSmrg	ARGV++; ARGC--; dformat = OPTION;
1905fc89c0fbSmrg    }
1906fc89c0fbSmrg
1907fc89c0fbSmrg    Add_Mapping(Parse_Atom(type_name, False), format, dformat);
1908fc89c0fbSmrg}
1909fc89c0fbSmrg
1910fc89c0fbSmrg/*
1911fc89c0fbSmrg *
1912fc89c0fbSmrg * The Main Program:
1913fc89c0fbSmrg *
1914fc89c0fbSmrg */
1915fc89c0fbSmrg
1916fc89c0fbSmrgstatic int spy = 0;
1917fc89c0fbSmrg
191891ec45ceSmrgstatic int (*old_error_handler)(Display *dpy, XErrorEvent *ev);
191991ec45ceSmrg
192091ec45ceSmrgstatic int spy_error_handler(Display *dpy, XErrorEvent *ev)
192191ec45ceSmrg{
192291ec45ceSmrg    if (ev->error_code == BadWindow || ev->error_code == BadMatch) {
192391ec45ceSmrg	/* Window was destroyed */
192491ec45ceSmrg	puts("");
192591ec45ceSmrg	exit(0);
192691ec45ceSmrg    }
192791ec45ceSmrg
192891ec45ceSmrg    if (old_error_handler)
192991ec45ceSmrg	return old_error_handler(dpy, ev);
193091ec45ceSmrg
193191ec45ceSmrg    return 0;
193291ec45ceSmrg}
193391ec45ceSmrg
1934fc89c0fbSmrgint
1935fc89c0fbSmrgmain (int argc, char **argv)
1936fc89c0fbSmrg{
1937fc89c0fbSmrg    FILE *stream;
1938fc89c0fbSmrg    char *name;
1939fc89c0fbSmrg    thunk *props;
1940fc89c0fbSmrg    thunk *remove_props = NULL;
1941fc89c0fbSmrg    thunk *set_props = NULL;
1942fc89c0fbSmrg    Bool frame_only = False;
1943fc89c0fbSmrg    int n;
1944fc89c0fbSmrg    char **nargv;
1945fc89c0fbSmrg
1946f9c28e31Smrg#ifdef TIOCGWINSZ
1947f9c28e31Smrg    struct winsize ws;
1948f9c28e31Smrg    ws.ws_col = 0;
1949f9c28e31Smrg    if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0)
1950f9c28e31Smrg	term_width = ws.ws_col;
1951f9c28e31Smrg#endif
1952f9c28e31Smrg
1953fc89c0fbSmrg    INIT_NAME;
1954fc89c0fbSmrg
1955fc89c0fbSmrg    /* Set locale for XmbTextProptertyToTextList and iswprint(). */
1956fc89c0fbSmrg    setlocale(LC_CTYPE, "");
1957fc89c0fbSmrg
1958fc89c0fbSmrg    /* Handle display name, opening the display */
1959fc89c0fbSmrg    Setup_Display_And_Screen(&argc, argv);
1960fc89c0fbSmrg
1961fc89c0fbSmrg    /* Handle selecting the window to display properties for */
1962fc89c0fbSmrg    target_win = Select_Window_Args(&argc, argv);
1963fc89c0fbSmrg
1964fc89c0fbSmrg    /* Set up default atom to format, dformat mapping */
1965fc89c0fbSmrg    XpropMode = XpropWindowProperties;
1966fc89c0fbSmrg    for (n = argc, nargv = argv; n; nargv++, n--)
1967fc89c0fbSmrg	if (! strcmp(nargv[0], "-font")) {
1968fc89c0fbSmrg	    XpropMode = XpropFontProperties;
1969fc89c0fbSmrg	    break;
1970fc89c0fbSmrg	}
1971fc89c0fbSmrg    Setup_Mapping();
1972fc89c0fbSmrg    if ((name = getenv("XPROPFORMATS"))) {
1973fc89c0fbSmrg	if (!(stream = fopen(name, "r")))
1974fc89c0fbSmrg	    Fatal_Error("unable to open file %s for reading.", name);
1975fc89c0fbSmrg	Read_Mappings(stream);
1976fc89c0fbSmrg	fclose(stream);
1977fc89c0fbSmrg    }
1978fc89c0fbSmrg
1979fc89c0fbSmrg    /* Handle '-' options to setup xprop, select window to work on */
1980fc89c0fbSmrg    while (argv++, --argc>0 && **argv == '-') {
1981fc89c0fbSmrg	if (!strcmp(argv[0], "-"))
1982fc89c0fbSmrg	    continue;
1983f9c28e31Smrg	if (!strcmp(argv[0], "-help")) {
1984f9c28e31Smrg	    help ();
1985f9c28e31Smrg	    /* NOTREACHED */
1986f9c28e31Smrg	}
1987fc89c0fbSmrg	if (!strcmp(argv[0], "-grammar")) {
1988fc89c0fbSmrg	    grammar ();
1989fc89c0fbSmrg	    /* NOTREACHED */
1990fc89c0fbSmrg	}
1991fc89c0fbSmrg	if (!strcmp(argv[0], "-notype")) {
1992fc89c0fbSmrg	    notype = 1;
1993fc89c0fbSmrg	    continue;
1994fc89c0fbSmrg	}
1995fc89c0fbSmrg	if (!strcmp(argv[0], "-spy")) {
1996fc89c0fbSmrg	    spy = 1;
1997fc89c0fbSmrg	    continue;
1998fc89c0fbSmrg	}
1999fc89c0fbSmrg	if (!strcmp(argv[0], "-len")) {
200081676fe2Smrg	    if (++argv, --argc == 0) usage("-len requires an argument");
2001fc89c0fbSmrg	    max_len = atoi(argv[0]);
2002fc89c0fbSmrg	    continue;
2003fc89c0fbSmrg	}
2004fc89c0fbSmrg	if (!strcmp(argv[0], "-formats") || !strcmp(argv[0], "-fs")) {
200581676fe2Smrg	    if (++argv, --argc == 0) usage("-fs requires an argument");
2006fc89c0fbSmrg	    if (!(stream = fopen(argv[0], "r")))
2007fc89c0fbSmrg		Fatal_Error("unable to open file %s for reading.", argv[0]);
2008fc89c0fbSmrg	    Read_Mappings(stream);
2009fc89c0fbSmrg	    fclose(stream);
2010fc89c0fbSmrg	    continue;
2011fc89c0fbSmrg	}
2012fc89c0fbSmrg	if (!strcmp(argv[0], "-font")) {
201381676fe2Smrg	    if (++argv, --argc == 0) usage("-font requires an argument");
2014fc89c0fbSmrg	    font = Open_Font(argv[0]);
2015fc89c0fbSmrg	    target_win = -1;
2016fc89c0fbSmrg	    continue;
2017fc89c0fbSmrg	}
2018fc89c0fbSmrg	if (!strcmp(argv[0], "-remove")) {
2019f4a95042Smrg	    thunk t = {0};
202081676fe2Smrg	    if (++argv, --argc == 0) usage("-remove requires an argument");
2021fc89c0fbSmrg	    t.propname = argv[0];
2022fc89c0fbSmrg	    if (remove_props == NULL) remove_props = Create_Thunk_List();
2023fc89c0fbSmrg	    remove_props = Add_Thunk(remove_props, t);
2024fc89c0fbSmrg	    continue;
2025fc89c0fbSmrg	}
2026fc89c0fbSmrg	if (!strcmp(argv[0], "-set")) {
2027f4a95042Smrg	    thunk t = {0};
202881676fe2Smrg	    if (argc < 3) usage("insufficent arguments for -set");
2029fc89c0fbSmrg	    t.propname = argv[1];
2030fc89c0fbSmrg	    t.extra_value = argv[2];
2031fc89c0fbSmrg	    argv += 3; argc -= 3;
2032fc89c0fbSmrg	    if (set_props == NULL) set_props = Create_Thunk_List();
2033fc89c0fbSmrg	    set_props = Add_Thunk(set_props, t);
2034fc89c0fbSmrg	    continue;
2035fc89c0fbSmrg	}
2036fc89c0fbSmrg	if (!strcmp(argv[0], "-frame")) {
2037fc89c0fbSmrg	    frame_only = True;
2038fc89c0fbSmrg	    continue;
2039fc89c0fbSmrg	}
2040fc89c0fbSmrg	if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "-format")) {
2041fc89c0fbSmrg	    Parse_Format_Mapping(&argc, &argv);
2042fc89c0fbSmrg	    continue;
2043fc89c0fbSmrg	}
204481676fe2Smrg	if (!strcmp(argv[0], "-version")) {
204581676fe2Smrg	    puts(PACKAGE_STRING);
204681676fe2Smrg	    exit(0);
204781676fe2Smrg	}
204881676fe2Smrg	fprintf (stderr, "%s: unrecognized argument %s\n\n",
204981676fe2Smrg		 program_name, argv[0]);
205081676fe2Smrg	usage(NULL);
2051fc89c0fbSmrg    }
2052fc89c0fbSmrg
205381676fe2Smrg    if ((remove_props != NULL || set_props != NULL) && argc > 0) {
205481676fe2Smrg	fprintf (stderr, "%s: unrecognized argument %s\n\n",
205581676fe2Smrg		 program_name, argv[0]);
205681676fe2Smrg	usage(NULL);
205781676fe2Smrg    }
2058fc89c0fbSmrg
205991ec45ceSmrg    if (target_win == None)
206091ec45ceSmrg	target_win = Select_Window(dpy, !frame_only);
2061fc89c0fbSmrg
2062fc89c0fbSmrg    if (remove_props != NULL) {
2063fc89c0fbSmrg	int count;
2064fc89c0fbSmrg
2065fc89c0fbSmrg	if (target_win == -1)
2066fc89c0fbSmrg	    Fatal_Error("-remove works only on windows, not fonts");
2067fc89c0fbSmrg
2068fc89c0fbSmrg	count = remove_props->thunk_count;
2069fc89c0fbSmrg	for (; count > 0; remove_props++, count--)
2070fc89c0fbSmrg	    Remove_Property (dpy, target_win, remove_props->propname);
2071fc89c0fbSmrg    }
2072fc89c0fbSmrg
2073fc89c0fbSmrg    if (set_props != NULL) {
2074fc89c0fbSmrg	int count;
2075fc89c0fbSmrg
2076fc89c0fbSmrg	if (target_win == -1)
2077fc89c0fbSmrg	    Fatal_Error("-set works only on windows, not fonts");
2078fc89c0fbSmrg
2079fc89c0fbSmrg	count = set_props->thunk_count;
2080fc89c0fbSmrg	for (; count > 0; set_props++, count--)
2081fc89c0fbSmrg	    Set_Property (dpy, target_win, set_props->propname,
2082fc89c0fbSmrg			  set_props->extra_value);
2083fc89c0fbSmrg    }
2084fc89c0fbSmrg
2085fc89c0fbSmrg    if (remove_props != NULL || set_props != NULL) {
2086fc89c0fbSmrg	XCloseDisplay (dpy);
2087fc89c0fbSmrg	exit (0);
2088fc89c0fbSmrg    }
2089fc89c0fbSmrg
2090fc89c0fbSmrg    props = Handle_Prop_Requests(argc, argv);
2091fc89c0fbSmrg
2092fc89c0fbSmrg    if (spy && target_win != -1) {
2093fc89c0fbSmrg	XEvent event;
2094fc89c0fbSmrg	const char *format, *dformat;
2095fc89c0fbSmrg
209691ec45ceSmrg	XSelectInput(dpy, target_win, PropertyChangeMask | StructureNotifyMask);
209791ec45ceSmrg 	old_error_handler = XSetErrorHandler(spy_error_handler);
2098fc89c0fbSmrg	for (;;) {
209991ec45ceSmrg	    fflush(stdout);
2100fc89c0fbSmrg	    XNextEvent(dpy, &event);
210191ec45ceSmrg 	    if (event.type == DestroyNotify)
210291ec45ceSmrg 		break;
210391ec45ceSmrg 	    if (event.type != PropertyNotify)
210491ec45ceSmrg 		continue;
2105fc89c0fbSmrg	    format = dformat = NULL;
2106fc89c0fbSmrg	    if (props) {
2107fc89c0fbSmrg		int i;
2108fc89c0fbSmrg		for (i = 0; i < props->thunk_count; i++)
2109fc89c0fbSmrg		    if (props[i].value == event.xproperty.atom)
2110fc89c0fbSmrg			break;
2111fc89c0fbSmrg		if (i >= props->thunk_count)
2112fc89c0fbSmrg		    continue;
2113fc89c0fbSmrg		format = props[i].format;
2114fc89c0fbSmrg		dformat = props[i].dformat;
2115fc89c0fbSmrg	    }
2116fc89c0fbSmrg	    Show_Prop(format, dformat, Format_Atom(event.xproperty.atom));
2117fc89c0fbSmrg	}
2118fc89c0fbSmrg    }
2119fc89c0fbSmrg    exit (0);
2120fc89c0fbSmrg}
2121