xprop.c revision 49bee38c
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 6949bee38cSmrgstatic unsigned 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; 14849bee38cSmrg int 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 (;;) { 15649bee38cSmrg int c; 15749bee38cSmrg 158fc89c0fbSmrg if (length < 0) 159fc89c0fbSmrg Fatal_Error("Bad format file format: dformat too long."); 160fc89c0fbSmrg c = Read_Char(stream); 161fc89c0fbSmrg if (c == (int) '\'') 162fc89c0fbSmrg break; 163fc89c0fbSmrg ptr++[0] = c; length--; 164fc89c0fbSmrg if (c == (int) '\\') { 165fc89c0fbSmrg c = Read_Char(stream); 166fc89c0fbSmrg if (c == '\n') { 167fc89c0fbSmrg ptr--; length++; 168b5cf802fSmrg } else { 169fc89c0fbSmrg ptr++[0] = c; length--; 170b5cf802fSmrg } 171fc89c0fbSmrg } 172fc89c0fbSmrg } 173fc89c0fbSmrg ptr++[0] = '\0'; 174fc89c0fbSmrg 175f4a95042Smrg ptr = strdup(_large_buffer); 176f4a95042Smrg if (!ptr) 177f4a95042Smrg Fatal_Error("Out of memory!"); 178f4a95042Smrg return ptr; 179fc89c0fbSmrg} 180fc89c0fbSmrg 181fc89c0fbSmrg/* 182fc89c0fbSmrg * 183fc89c0fbSmrg * Parsing Routines: a group of routines to parse strings into values 184fc89c0fbSmrg * 185fc89c0fbSmrg * Routines: Parse_Atom, Scan_Long, Skip_Past_Right_Paren, Scan_Octal 186fc89c0fbSmrg * 187fc89c0fbSmrg * Routines of the form Parse_XXX take a string which is parsed to a value. 188fc89c0fbSmrg * Routines of the form Scan_XXX take a string, parse the beginning to a value, 189fc89c0fbSmrg * and return the rest of the string. The value is returned via. the last 190fc89c0fbSmrg * parameter. All numeric values are longs! 191fc89c0fbSmrg * 192fc89c0fbSmrg */ 193fc89c0fbSmrg 194fc89c0fbSmrgstatic const char * 195fc89c0fbSmrgSkip_Digits (const char *string) 196fc89c0fbSmrg{ 197fc89c0fbSmrg while (isdigit((unsigned char) string[0])) string++; 198fc89c0fbSmrg return string; 199fc89c0fbSmrg} 200fc89c0fbSmrg 201fc89c0fbSmrgstatic const char * 202fc89c0fbSmrgScan_Long (const char *string, long *value) 203fc89c0fbSmrg{ 204fc89c0fbSmrg if (!isdigit((unsigned char) *string)) 205fc89c0fbSmrg Fatal_Error("Bad number: %s.", string); 206fc89c0fbSmrg 207fc89c0fbSmrg *value = atol(string); 208fc89c0fbSmrg return Skip_Digits(string); 209fc89c0fbSmrg} 210fc89c0fbSmrg 211fc89c0fbSmrgstatic const char * 212fc89c0fbSmrgScan_Octal (const char *string, unsigned long *value) 213fc89c0fbSmrg{ 214fc89c0fbSmrg if (sscanf(string, "%lo", value)!=1) 215fc89c0fbSmrg Fatal_Error("Bad octal number: %s.", string); 216fc89c0fbSmrg return Skip_Digits(string); 217fc89c0fbSmrg} 218fc89c0fbSmrg 219fc89c0fbSmrgstatic Atom 220fc89c0fbSmrgParse_Atom (const char *name, int only_if_exists) 221fc89c0fbSmrg{ 222fc89c0fbSmrg /* may return None = 0 */ 223fc89c0fbSmrg return XInternAtom(dpy, name, only_if_exists); 224fc89c0fbSmrg} 225fc89c0fbSmrg 226fc89c0fbSmrgstatic const char * 227fc89c0fbSmrgSkip_Past_Right_Paren (const char *string) 228fc89c0fbSmrg{ 229fc89c0fbSmrg char c; 230fc89c0fbSmrg int nesting = 0; 231fc89c0fbSmrg 232fc89c0fbSmrg while (c = string++[0], c != ')' || nesting) 233fc89c0fbSmrg switch (c) { 234fc89c0fbSmrg case '\0': 235fc89c0fbSmrg Fatal_Error("Missing ')'."); 236fc89c0fbSmrg case '(': 237fc89c0fbSmrg nesting++; 238fc89c0fbSmrg break; 239fc89c0fbSmrg case ')': 240fc89c0fbSmrg nesting--; 241fc89c0fbSmrg break; 242fc89c0fbSmrg case '\\': 243fc89c0fbSmrg string++; 244fc89c0fbSmrg break; 245fc89c0fbSmrg } 246fc89c0fbSmrg return string; 247fc89c0fbSmrg} 248fc89c0fbSmrg 249fc89c0fbSmrg/* 250fc89c0fbSmrg * 251fc89c0fbSmrg * Atom to format, dformat mapping Manager 252fc89c0fbSmrg * 253fc89c0fbSmrg */ 254fc89c0fbSmrg 255fc89c0fbSmrg#define D_FORMAT "0x" /* Default format for properties */ 256fc89c0fbSmrg#define D_DFORMAT " = $0+\n" /* Default display pattern for properties */ 257fc89c0fbSmrg 258fc89c0fbSmrgstatic thunk *_property_formats = NULL; /* Holds mapping */ 259fc89c0fbSmrg 260fc89c0fbSmrgstatic void 261fc89c0fbSmrgApply_Default_Formats (const char **format, const char **dformat) 262fc89c0fbSmrg{ 263fc89c0fbSmrg if (!*format) 264fc89c0fbSmrg *format = D_FORMAT; 265fc89c0fbSmrg if (!*dformat) 266fc89c0fbSmrg *dformat = D_DFORMAT; 267fc89c0fbSmrg} 268fc89c0fbSmrg 269fc89c0fbSmrgstatic void 270fc89c0fbSmrgLookup_Formats (Atom atom, const char **format, const char **dformat) 271fc89c0fbSmrg{ 272fc89c0fbSmrg if (_property_formats) 27349bee38cSmrg for (int i = _property_formats->thunk_count-1; i >= 0; i--) { 27449bee38cSmrg if (_property_formats[i].value == (long) atom) { 275fc89c0fbSmrg if (!*format) 276fc89c0fbSmrg *format = _property_formats[i].format; 277fc89c0fbSmrg if (!*dformat) 278fc89c0fbSmrg *dformat = _property_formats[i].dformat; 279fc89c0fbSmrg break; 280fc89c0fbSmrg } 28149bee38cSmrg } 282fc89c0fbSmrg} 283fc89c0fbSmrg 284fc89c0fbSmrgstatic void 285fc89c0fbSmrgAdd_Mapping (Atom atom, const char *format, const char *dformat) 286fc89c0fbSmrg{ 287f4a95042Smrg thunk t = {0}; 288fc89c0fbSmrg 289fc89c0fbSmrg if (!_property_formats) 290fc89c0fbSmrg _property_formats = Create_Thunk_List(); 291fc89c0fbSmrg 292fc89c0fbSmrg t.value = atom; 293fc89c0fbSmrg t.format = format; 294fc89c0fbSmrg t.dformat = dformat; 295fc89c0fbSmrg 296fc89c0fbSmrg _property_formats = Add_Thunk(_property_formats, t); 297fc89c0fbSmrg} 298fc89c0fbSmrg 299fc89c0fbSmrg/* 300fc89c0fbSmrg * 301fc89c0fbSmrg * Setup_Mapping: Routine to setup default atom to format, dformat mapping: 302fc89c0fbSmrg * 303fc89c0fbSmrg */ 304fc89c0fbSmrg 305fc89c0fbSmrgtypedef struct _propertyRec { 306fc89c0fbSmrg const char * name; 307fc89c0fbSmrg Atom atom; 308fc89c0fbSmrg const char * format; 309fc89c0fbSmrg const char * dformat; 310fc89c0fbSmrg} propertyRec; 311fc89c0fbSmrg 312fc89c0fbSmrg#define ARC_DFORMAT ":\n"\ 313fc89c0fbSmrg"\t\tarc at $0, $1\n"\ 314fc89c0fbSmrg"\t\tsize: $2 by $3\n"\ 315fc89c0fbSmrg"\t\tfrom angle $4 to angle $5\n" 316fc89c0fbSmrg 317fc89c0fbSmrg#define RECTANGLE_DFORMAT ":\n"\ 318fc89c0fbSmrg"\t\tupper left corner: $0, $1\n"\ 319fc89c0fbSmrg"\t\tsize: $2 by $3\n" 320fc89c0fbSmrg 321fc89c0fbSmrg#define RGB_COLOR_MAP_DFORMAT ":\n"\ 322fc89c0fbSmrg"\t\tcolormap id #: $0\n"\ 323fc89c0fbSmrg"\t\tred-max: $1\n"\ 324fc89c0fbSmrg"\t\tred-mult: $2\n"\ 325fc89c0fbSmrg"\t\tgreen-max: $3\n"\ 326fc89c0fbSmrg"\t\tgreen-mult: $4\n"\ 327fc89c0fbSmrg"\t\tblue-max: $5\n"\ 328fc89c0fbSmrg"\t\tblue-mult: $6\n"\ 329fc89c0fbSmrg"\t\tbase-pixel: $7\n"\ 330fc89c0fbSmrg"\t\tvisual id #: $8\n"\ 331fc89c0fbSmrg"\t\tkill id #: $9\n" 332fc89c0fbSmrg 333fc89c0fbSmrg#define WM_HINTS_DFORMAT ":\n"\ 334fc89c0fbSmrg"?m0(\t\tClient accepts input or input focus: $1\n)"\ 335fc89c0fbSmrg"?m1(\t\tInitial state is "\ 336fc89c0fbSmrg"?$2=0(Don't Care State)"\ 337fc89c0fbSmrg"?$2=1(Normal State)"\ 338fc89c0fbSmrg"?$2=2(Zoomed State)"\ 339fc89c0fbSmrg"?$2=3(Iconic State)"\ 340fc89c0fbSmrg"?$2=4(Inactive State)"\ 341fc89c0fbSmrg".\n)"\ 342fc89c0fbSmrg"?m2(\t\tbitmap id # to use for icon: $3\n)"\ 343fc89c0fbSmrg"?m5(\t\tbitmap id # of mask for icon: $7\n)"\ 344fc89c0fbSmrg"?m3(\t\twindow id # to use for icon: $4\n)"\ 345fc89c0fbSmrg"?m4(\t\tstarting position for icon: $5, $6\n)"\ 346fc89c0fbSmrg"?m6(\t\twindow id # of group leader: $8\n)"\ 34791ec45ceSmrg"?m8(\t\tThe urgency hint bit is set\n)" 348fc89c0fbSmrg 349fc89c0fbSmrg#define WM_ICON_SIZE_DFORMAT ":\n"\ 350fc89c0fbSmrg"\t\tminimum icon size: $0 by $1\n"\ 351fc89c0fbSmrg"\t\tmaximum icon size: $2 by $3\n"\ 352fc89c0fbSmrg"\t\tincremental size change: $4 by $5\n" 353fc89c0fbSmrg 354fc89c0fbSmrg#define WM_SIZE_HINTS_DFORMAT ":\n"\ 355fc89c0fbSmrg"?m0(\t\tuser specified location: $1, $2\n)"\ 356fc89c0fbSmrg"?m2(\t\tprogram specified location: $1, $2\n)"\ 357fc89c0fbSmrg"?m1(\t\tuser specified size: $3 by $4\n)"\ 358fc89c0fbSmrg"?m3(\t\tprogram specified size: $3 by $4\n)"\ 359fc89c0fbSmrg"?m4(\t\tprogram specified minimum size: $5 by $6\n)"\ 360fc89c0fbSmrg"?m5(\t\tprogram specified maximum size: $7 by $8\n)"\ 361fc89c0fbSmrg"?m6(\t\tprogram specified resize increment: $9 by $10\n)"\ 362fc89c0fbSmrg"?m7(\t\tprogram specified minimum aspect ratio: $11/$12\n"\ 363fc89c0fbSmrg"\t\tprogram specified maximum aspect ratio: $13/$14\n)"\ 364fc89c0fbSmrg"?m8(\t\tprogram specified base size: $15 by $16\n)"\ 365fc89c0fbSmrg"?m9(\t\twindow gravity: "\ 366fc89c0fbSmrg"?$17=0(Forget)"\ 367fc89c0fbSmrg"?$17=1(NorthWest)"\ 368fc89c0fbSmrg"?$17=2(North)"\ 369fc89c0fbSmrg"?$17=3(NorthEast)"\ 370fc89c0fbSmrg"?$17=4(West)"\ 371fc89c0fbSmrg"?$17=5(Center)"\ 372fc89c0fbSmrg"?$17=6(East)"\ 373fc89c0fbSmrg"?$17=7(SouthWest)"\ 374fc89c0fbSmrg"?$17=8(South)"\ 375fc89c0fbSmrg"?$17=9(SouthEast)"\ 376fc89c0fbSmrg"?$17=10(Static)"\ 377fc89c0fbSmrg"\n)" 378fc89c0fbSmrg 379fc89c0fbSmrg#define WM_STATE_DFORMAT ":\n"\ 380fc89c0fbSmrg"\t\twindow state: ?$0=0(Withdrawn)?$0=1(Normal)?$0=3(Iconic)\n"\ 381fc89c0fbSmrg"\t\ticon window: $1\n" 382fc89c0fbSmrg 383fc89c0fbSmrgstatic propertyRec windowPropTable[] = { 384fc89c0fbSmrg {"ARC", XA_ARC, "16iiccii", ARC_DFORMAT }, 385fc89c0fbSmrg {"ATOM", XA_ATOM, "32a", 0 }, 386fc89c0fbSmrg {"BITMAP", XA_BITMAP, "32x", ": bitmap id # $0\n" }, 387fc89c0fbSmrg {"CARDINAL", XA_CARDINAL, "0c", 0 }, 388fc89c0fbSmrg {"COLORMAP", XA_COLORMAP, "32x", ": colormap id # $0\n" }, 389fc89c0fbSmrg {"CURSOR", XA_CURSOR, "32x", ": cursor id # $0\n" }, 390fc89c0fbSmrg {"DRAWABLE", XA_DRAWABLE, "32x", ": drawable id # $0\n" }, 391fc89c0fbSmrg {"FONT", XA_FONT, "32x", ": font id # $0\n" }, 392fc89c0fbSmrg {"INTEGER", XA_INTEGER, "0i", 0 }, 393fc89c0fbSmrg {"PIXMAP", XA_PIXMAP, "32x", ": pixmap id # $0\n" }, 394fc89c0fbSmrg {"POINT", XA_POINT, "16ii", " = $0, $1\n" }, 395fc89c0fbSmrg {"RECTANGLE", XA_RECTANGLE, "16iicc", RECTANGLE_DFORMAT }, 396fc89c0fbSmrg {"RGB_COLOR_MAP", XA_RGB_COLOR_MAP,"32xcccccccxx",RGB_COLOR_MAP_DFORMAT}, 397fc89c0fbSmrg {"STRING", XA_STRING, "8s", 0 }, 398a0996ce0Smrg {"UTF8_STRING", 0, "8u", 0 }, 399fc89c0fbSmrg {"WINDOW", XA_WINDOW, "32x", ": window id # $0+\n" }, 400fc89c0fbSmrg {"VISUALID", XA_VISUALID, "32x", ": visual id # $0\n" }, 401fc89c0fbSmrg {"WM_COLORMAP_WINDOWS", 0, "32x", ": window id # $0+\n"}, 402fc89c0fbSmrg {"WM_COMMAND", XA_WM_COMMAND, "8s", " = { $0+ }\n" }, 403fc89c0fbSmrg {"WM_HINTS", XA_WM_HINTS, "32mbcxxiixx", WM_HINTS_DFORMAT }, 404fc89c0fbSmrg {"WM_ICON_NAME", XA_WM_ICON_NAME, "8t", 0 }, 405fc89c0fbSmrg {"WM_ICON_SIZE", XA_WM_ICON_SIZE, "32cccccc", WM_ICON_SIZE_DFORMAT}, 406fc89c0fbSmrg {"WM_NAME", XA_WM_NAME, "8t", 0 }, 407fc89c0fbSmrg {"WM_PROTOCOLS", 0, "32a", ": protocols $0+\n"}, 408fc89c0fbSmrg {"WM_SIZE_HINTS", XA_WM_SIZE_HINTS,"32mii", WM_SIZE_HINTS_DFORMAT }, 40991ec45ceSmrg {"_NET_WM_ICON", 0, "32o", 0 }, 410fc89c0fbSmrg {"WM_STATE", 0, "32cx", WM_STATE_DFORMAT} 411fc89c0fbSmrg}; 412fc89c0fbSmrg#undef ARC_DFORMAT 413fc89c0fbSmrg#undef RECTANGLE_DFORMAT 414fc89c0fbSmrg#undef RGB_COLOR_MAP_DFORMAT 415fc89c0fbSmrg#undef WM_ICON_SIZE_DFORMAT 416fc89c0fbSmrg#undef WM_HINTS_DFORMAT 417fc89c0fbSmrg#undef WM_SIZE_HINTS_DFORMAT 418fc89c0fbSmrg#undef WM_STATE_DFORMAT 419fc89c0fbSmrg 420fc89c0fbSmrg/* 421fc89c0fbSmrg * Font-specific mapping of property names to types: 422fc89c0fbSmrg */ 423fc89c0fbSmrgstatic propertyRec fontPropTable[] = { 424fc89c0fbSmrg 425fc89c0fbSmrg /* XLFD name properties */ 426fc89c0fbSmrg 427fc89c0fbSmrg { "FOUNDRY", 0, "32a", 0 }, 428fc89c0fbSmrg { "FAMILY_NAME", XA_FAMILY_NAME, "32a", 0 }, 429fc89c0fbSmrg { "WEIGHT_NAME", 0, "32a", 0 }, 430fc89c0fbSmrg { "SLANT", 0, "32a", 0 }, 431fc89c0fbSmrg { "SETWIDTH_NAME", 0, "32a", 0 }, 432fc89c0fbSmrg { "ADD_STYLE_NAME", 0, "32a", 0 }, 433fc89c0fbSmrg { "PIXEL_SIZE", 0, "32c", 0 }, 434fc89c0fbSmrg { "POINT_SIZE", XA_POINT_SIZE, "32c", 0 }, 435fc89c0fbSmrg { "RESOLUTION_X", 0, "32c", 0 }, 436fc89c0fbSmrg { "RESOLUTION_Y", 0, "32c", 0 }, 437fc89c0fbSmrg { "SPACING", 0, "32a", 0 }, 438fc89c0fbSmrg { "AVERAGE_WIDTH", 0, "32c", 0 }, 439fc89c0fbSmrg { "CHARSET_REGISTRY", 0, "32a", 0 }, 440fc89c0fbSmrg { "CHARSET_ENCODING", 0, "32a", 0 }, 441fc89c0fbSmrg 442fc89c0fbSmrg /* other font properties referenced in the XLFD */ 443fc89c0fbSmrg 444fc89c0fbSmrg { "QUAD_WIDTH", XA_QUAD_WIDTH, "32i", 0 }, 445fc89c0fbSmrg { "RESOLUTION", XA_RESOLUTION, "32c", 0 }, 446fc89c0fbSmrg { "MIN_SPACE", XA_MIN_SPACE, "32c", 0 }, 447fc89c0fbSmrg { "NORM_SPACE", XA_NORM_SPACE, "32c", 0 }, 448fc89c0fbSmrg { "MAX_SPACE", XA_MAX_SPACE, "32c", 0 }, 449fc89c0fbSmrg { "END_SPACE", XA_END_SPACE, "32c", 0 }, 450fc89c0fbSmrg { "SUPERSCRIPT_X", XA_SUPERSCRIPT_X, "32i", 0 }, 451fc89c0fbSmrg { "SUPERSCRIPT_Y", XA_SUPERSCRIPT_Y, "32i", 0 }, 452fc89c0fbSmrg { "SUBSCRIPT_X", XA_SUBSCRIPT_X, "32i", 0 }, 453fc89c0fbSmrg { "SUBSCRIPT_Y", XA_SUBSCRIPT_Y, "32i", 0 }, 454fc89c0fbSmrg { "UNDERLINE_POSITION", XA_UNDERLINE_POSITION, "32i", 0 }, 455fc89c0fbSmrg { "UNDERLINE_THICKNESS", XA_UNDERLINE_THICKNESS, "32i", 0 }, 456fc89c0fbSmrg { "STRIKEOUT_ASCENT", XA_STRIKEOUT_ASCENT, "32i", 0 }, 457fc89c0fbSmrg { "STRIKEOUT_DESCENT", XA_STRIKEOUT_DESCENT, "32i", 0 }, 458fc89c0fbSmrg { "ITALIC_ANGLE", XA_ITALIC_ANGLE, "32i", 0 }, 459fc89c0fbSmrg { "X_HEIGHT", XA_X_HEIGHT, "32i", 0 }, 460fc89c0fbSmrg { "WEIGHT", XA_WEIGHT, "32i", 0 }, 461fc89c0fbSmrg { "FACE_NAME", 0, "32a", 0 }, 462fc89c0fbSmrg { "COPYRIGHT", XA_COPYRIGHT, "32a", 0 }, 463fc89c0fbSmrg { "AVG_CAPITAL_WIDTH", 0, "32i", 0 }, 464fc89c0fbSmrg { "AVG_LOWERCASE_WIDTH", 0, "32i", 0 }, 465fc89c0fbSmrg { "RELATIVE_SETWIDTH", 0, "32c", 0 }, 466fc89c0fbSmrg { "RELATIVE_WEIGHT", 0, "32c", 0 }, 467fc89c0fbSmrg { "CAP_HEIGHT", XA_CAP_HEIGHT, "32c", 0 }, 468fc89c0fbSmrg { "SUPERSCRIPT_SIZE", 0, "32c", 0 }, 469fc89c0fbSmrg { "FIGURE_WIDTH", 0, "32i", 0 }, 470fc89c0fbSmrg { "SUBSCRIPT_SIZE", 0, "32c", 0 }, 471fc89c0fbSmrg { "SMALL_CAP_SIZE", 0, "32i", 0 }, 472fc89c0fbSmrg { "NOTICE", XA_NOTICE, "32a", 0 }, 473fc89c0fbSmrg { "DESTINATION", 0, "32c", 0 }, 474fc89c0fbSmrg 475fc89c0fbSmrg /* other font properties */ 476fc89c0fbSmrg 477fc89c0fbSmrg { "FONT", XA_FONT, "32a", 0 }, 478fc89c0fbSmrg { "FONT_NAME", XA_FONT_NAME, "32a", 0 }, 479fc89c0fbSmrg}; 480fc89c0fbSmrg 481fc89c0fbSmrgstatic int XpropMode; 482fc89c0fbSmrg#define XpropWindowProperties 0 483fc89c0fbSmrg#define XpropFontProperties 1 484fc89c0fbSmrg 485fc89c0fbSmrgstatic void 486fc89c0fbSmrgSetup_Mapping (void) 487fc89c0fbSmrg{ 488fc89c0fbSmrg int n; 489fc89c0fbSmrg propertyRec *p; 490fc89c0fbSmrg 491fc89c0fbSmrg if (XpropMode == XpropWindowProperties) { 492fc89c0fbSmrg n = sizeof(windowPropTable) / sizeof(propertyRec); 493fc89c0fbSmrg p = windowPropTable; 494fc89c0fbSmrg } else { 495fc89c0fbSmrg n = sizeof (fontPropTable) / sizeof (propertyRec); 496fc89c0fbSmrg p = fontPropTable; 497fc89c0fbSmrg } 498fc89c0fbSmrg for ( ; --n >= 0; p++) { 499fc89c0fbSmrg if (! p->atom) { 500fc89c0fbSmrg p->atom = XInternAtom(dpy, p->name, True); 501fc89c0fbSmrg if (p->atom == None) 502fc89c0fbSmrg continue; 503fc89c0fbSmrg } 504fc89c0fbSmrg Add_Mapping(p->atom, p->format, p->dformat); 505fc89c0fbSmrg } 506fc89c0fbSmrg} 507fc89c0fbSmrg 508fc89c0fbSmrgstatic const char * 509fc89c0fbSmrgGetAtomName (Atom atom) 510fc89c0fbSmrg{ 511fc89c0fbSmrg int n; 512fc89c0fbSmrg propertyRec *p; 513fc89c0fbSmrg 514fc89c0fbSmrg if (XpropMode == XpropWindowProperties) { 515fc89c0fbSmrg n = sizeof(windowPropTable) / sizeof(propertyRec); 516fc89c0fbSmrg p = windowPropTable; 517fc89c0fbSmrg } else { 518fc89c0fbSmrg n = sizeof (fontPropTable) / sizeof (propertyRec); 519fc89c0fbSmrg p = fontPropTable; 520fc89c0fbSmrg } 521fc89c0fbSmrg for ( ; --n >= 0; p++) 522fc89c0fbSmrg if (p->atom == atom) 523fc89c0fbSmrg return p->name; 524fc89c0fbSmrg 525fc89c0fbSmrg return NULL; 526fc89c0fbSmrg} 527fc89c0fbSmrg 528fc89c0fbSmrg/* 529fc89c0fbSmrg * Read_Mapping: routine to read in additional mappings from a stream 530fc89c0fbSmrg * already open for reading. 531fc89c0fbSmrg */ 532fc89c0fbSmrg 533fc89c0fbSmrgstatic void 534fc89c0fbSmrgRead_Mappings (FILE *stream) 535fc89c0fbSmrg{ 536fc89c0fbSmrg char format_buffer[100]; 537576bbdfcSmrg char name[1000]; 53849bee38cSmrg int count; 539fc89c0fbSmrg 540fc89c0fbSmrg while ((count = fscanf(stream," %990s %90s ",name,format_buffer)) != EOF) { 54149bee38cSmrg const char *dformat, *format; 54249bee38cSmrg int c; 54349bee38cSmrg Atom atom; 54449bee38cSmrg 545fc89c0fbSmrg if (count != 2) 546fc89c0fbSmrg Fatal_Error("Bad format file format."); 547fc89c0fbSmrg 548fc89c0fbSmrg atom = Parse_Atom(name, False); 549f4a95042Smrg format = strdup(format_buffer); 550f4a95042Smrg if (!format) 551f4a95042Smrg Fatal_Error("Out of memory!"); 552fc89c0fbSmrg 553fc89c0fbSmrg Read_White_Space(stream); 554fc89c0fbSmrg dformat = D_DFORMAT; 555fc89c0fbSmrg c = getc(stream); 556fc89c0fbSmrg ungetc(c, stream); 557fc89c0fbSmrg if (c == (int) '\'') 558fc89c0fbSmrg dformat = Read_Quoted(stream); 559fc89c0fbSmrg 560fc89c0fbSmrg Add_Mapping(atom, format, dformat); 561fc89c0fbSmrg } 562fc89c0fbSmrg} 563fc89c0fbSmrg 564fc89c0fbSmrg/* 565fc89c0fbSmrg * 566fc89c0fbSmrg * Formatting Routines: a group of routines to translate from various 567fc89c0fbSmrg * values to a static read-only string useful for output. 568fc89c0fbSmrg * 569fc89c0fbSmrg * Routines: Format_Hex, Format_Unsigned, Format_Signed, Format_Atom, 570fc89c0fbSmrg * Format_Mask_Word, Format_Bool, Format_String, Format_Len_String. 571fc89c0fbSmrg * 572fc89c0fbSmrg * All of the above routines take a long except for Format_String and 573fc89c0fbSmrg * Format_Len_String. 574fc89c0fbSmrg * 575fc89c0fbSmrg */ 576fc89c0fbSmrgstatic char _formatting_buffer[MAXSTR+100]; 577fc89c0fbSmrgstatic char _formatting_buffer2[21]; 578fc89c0fbSmrg 579fc89c0fbSmrgstatic const char * 580fc89c0fbSmrgFormat_Hex (long wrd) 581fc89c0fbSmrg{ 582fc89c0fbSmrg snprintf(_formatting_buffer2, sizeof(_formatting_buffer2), "0x%lx", wrd); 583fc89c0fbSmrg return _formatting_buffer2; 584fc89c0fbSmrg} 585fc89c0fbSmrg 586fc89c0fbSmrgstatic const char * 587fc89c0fbSmrgFormat_Unsigned (long wrd) 588fc89c0fbSmrg{ 589fc89c0fbSmrg snprintf(_formatting_buffer2, sizeof(_formatting_buffer2), "%lu", wrd); 590fc89c0fbSmrg return _formatting_buffer2; 591fc89c0fbSmrg} 592fc89c0fbSmrg 593fc89c0fbSmrgstatic const char * 594fc89c0fbSmrgFormat_Signed (long wrd) 595fc89c0fbSmrg{ 596fc89c0fbSmrg snprintf(_formatting_buffer2, sizeof(_formatting_buffer2), "%ld", wrd); 597fc89c0fbSmrg return _formatting_buffer2; 598fc89c0fbSmrg} 599fc89c0fbSmrg 600fc89c0fbSmrg/*ARGSUSED*/ 601fc89c0fbSmrgstatic int 60249bee38cSmrgignore_errors (Display *display, XErrorEvent *ev) 603fc89c0fbSmrg{ 604fc89c0fbSmrg return 0; 605fc89c0fbSmrg} 606fc89c0fbSmrg 607fc89c0fbSmrgstatic const char * 608fc89c0fbSmrgFormat_Atom (Atom atom) 609fc89c0fbSmrg{ 610fc89c0fbSmrg const char *found; 611fc89c0fbSmrg char *name; 612fc89c0fbSmrg XErrorHandler handler; 613fc89c0fbSmrg 614fc89c0fbSmrg if ((found = GetAtomName(atom)) != NULL) 615fc89c0fbSmrg return found; 616fc89c0fbSmrg 617fc89c0fbSmrg handler = XSetErrorHandler (ignore_errors); 618fc89c0fbSmrg name = XGetAtomName(dpy, atom); 619fc89c0fbSmrg XSetErrorHandler(handler); 620fc89c0fbSmrg if (! name) 621fc89c0fbSmrg snprintf(_formatting_buffer, sizeof(_formatting_buffer), 622fc89c0fbSmrg "undefined atom # 0x%lx", atom); 623fc89c0fbSmrg else { 62449bee38cSmrg size_t namelen = strlen(name); 625fc89c0fbSmrg if (namelen > MAXSTR) namelen = MAXSTR; 626fc89c0fbSmrg memcpy(_formatting_buffer, name, namelen); 627fc89c0fbSmrg _formatting_buffer[namelen] = '\0'; 628fc89c0fbSmrg XFree(name); 629fc89c0fbSmrg } 630fc89c0fbSmrg return _formatting_buffer; 631fc89c0fbSmrg} 632fc89c0fbSmrg 633fc89c0fbSmrgstatic const char * 634fc89c0fbSmrgFormat_Mask_Word (long wrd) 635fc89c0fbSmrg{ 63649bee38cSmrg unsigned long bit_mask, bit; 637fc89c0fbSmrg int seen = 0; 638fc89c0fbSmrg 639fc89c0fbSmrg strcpy(_formatting_buffer, "{MASK: "); 640fc89c0fbSmrg for (bit=0, bit_mask=1; bit <= sizeof(long)*8; bit++, bit_mask<<=1) { 641fc89c0fbSmrg if (bit_mask & wrd) { 642fc89c0fbSmrg if (seen) { 643fc89c0fbSmrg strcat(_formatting_buffer, ", "); 644fc89c0fbSmrg } 645fc89c0fbSmrg seen = 1; 646fc89c0fbSmrg strcat(_formatting_buffer, Format_Unsigned(bit)); 647fc89c0fbSmrg } 648fc89c0fbSmrg } 649fc89c0fbSmrg strcat(_formatting_buffer, "}"); 650fc89c0fbSmrg 651fc89c0fbSmrg return _formatting_buffer; 652fc89c0fbSmrg} 653fc89c0fbSmrg 654fc89c0fbSmrgstatic const char * 655fc89c0fbSmrgFormat_Bool (long value) 656fc89c0fbSmrg{ 657fc89c0fbSmrg if (!value) 658fc89c0fbSmrg return "False"; 659fc89c0fbSmrg 660fc89c0fbSmrg return "True"; 661fc89c0fbSmrg} 662fc89c0fbSmrg 663fc89c0fbSmrgstatic char *_buf_ptr; 664fc89c0fbSmrgstatic int _buf_len; 665fc89c0fbSmrg 666fc89c0fbSmrgstatic void 667fc89c0fbSmrg_put_char (char c) 668fc89c0fbSmrg{ 669fc89c0fbSmrg if (_buf_len <= 0) { 670fc89c0fbSmrg _buf_ptr[0] = '\0'; 671fc89c0fbSmrg return; 672fc89c0fbSmrg } 673fc89c0fbSmrg _buf_ptr++[0] = c; 674fc89c0fbSmrg _buf_len--; 675fc89c0fbSmrg} 676fc89c0fbSmrg 677fc89c0fbSmrgstatic void 678a0996ce0Smrg_format_char (char c, int unicode) 679fc89c0fbSmrg{ 680fc89c0fbSmrg switch (c) { 681fc89c0fbSmrg case '\\': 682fc89c0fbSmrg case '\"': 683fc89c0fbSmrg _put_char('\\'); 684fc89c0fbSmrg _put_char(c); 685fc89c0fbSmrg break; 686fc89c0fbSmrg case '\n': 687fc89c0fbSmrg _put_char('\\'); 688fc89c0fbSmrg _put_char('n'); 689fc89c0fbSmrg break; 690fc89c0fbSmrg case '\t': 691fc89c0fbSmrg _put_char('\\'); 692fc89c0fbSmrg _put_char('t'); 693fc89c0fbSmrg break; 694fc89c0fbSmrg default: 695fc89c0fbSmrg if (!c_isprint(c)) { 696a0996ce0Smrg if (unicode && (c & 0x80)) { 697a0996ce0Smrg _put_char(c); 698a0996ce0Smrg } else { 699a0996ce0Smrg _put_char('\\'); 700a0996ce0Smrg snprintf(_buf_ptr, _buf_len, "%03o", (unsigned char) c); 701a0996ce0Smrg _buf_ptr += 3; 702a0996ce0Smrg _buf_len -= 3; 703a0996ce0Smrg } 704fc89c0fbSmrg } else 705fc89c0fbSmrg _put_char(c); 706fc89c0fbSmrg } 707fc89c0fbSmrg} 708fc89c0fbSmrg 709fc89c0fbSmrgstatic const char * 710a0996ce0SmrgFormat_String (const char *string, int unicode) 711fc89c0fbSmrg{ 712fc89c0fbSmrg char c; 713fc89c0fbSmrg 714fc89c0fbSmrg _buf_ptr = _formatting_buffer; 715fc89c0fbSmrg _buf_len = MAXSTR; 716fc89c0fbSmrg _put_char('\"'); 717fc89c0fbSmrg 718fc89c0fbSmrg while ((c = string++[0])) 719a0996ce0Smrg _format_char(c, unicode); 720fc89c0fbSmrg 721fc89c0fbSmrg *_buf_ptr++ = '"'; 722fc89c0fbSmrg *_buf_ptr++ = '\0'; 723fc89c0fbSmrg return _formatting_buffer; 724fc89c0fbSmrg} 725fc89c0fbSmrg 726fc89c0fbSmrgstatic const char * 727576bbdfcSmrgFormat_Len_String (const char *string, int len, int unicode) 728fc89c0fbSmrg{ 729fc89c0fbSmrg char *data; 730fc89c0fbSmrg const char *result; 731fc89c0fbSmrg 732f4a95042Smrg data = malloc(len+1); 733f4a95042Smrg if (!data) 734f4a95042Smrg Fatal_Error("Out of memory!"); 735fc89c0fbSmrg 736fc89c0fbSmrg memcpy(data, string, len); 737fc89c0fbSmrg data[len] = '\0'; 738fc89c0fbSmrg 739576bbdfcSmrg result = Format_String(data, unicode); 740fc89c0fbSmrg free(data); 741fc89c0fbSmrg 742fc89c0fbSmrg return result; 743fc89c0fbSmrg} 744fc89c0fbSmrg 74591ec45ceSmrgstatic int 74691ec45ceSmrgis_utf8_locale (void) 74791ec45ceSmrg{ 74891ec45ceSmrg#ifdef HAVE_LANGINFO_H 74991ec45ceSmrg char *charmap = nl_langinfo (CODESET); 75091ec45ceSmrg 75191ec45ceSmrg return charmap && strcmp (charmap, "UTF-8") == 0; 75291ec45ceSmrg#else 75391ec45ceSmrg return 0; 75491ec45ceSmrg#endif 75591ec45ceSmrg} 75691ec45ceSmrg 757f9c28e31Smrgstatic int 758f9c28e31Smrgis_truecolor_term (void) 759f9c28e31Smrg{ 760f9c28e31Smrg char *colorterm = getenv( "COLORTERM" ); 761f9c28e31Smrg 762f9c28e31Smrg if (colorterm && !strcmp(colorterm,"truecolor")) 763f9c28e31Smrg return 1; 764f9c28e31Smrg 765f9c28e31Smrg return 0; 766f9c28e31Smrg} 767f9c28e31Smrg 76891ec45ceSmrgstatic const char * 76991ec45ceSmrgFormat_Icons (const unsigned long *icon, int len) 77091ec45ceSmrg{ 77181676fe2Smrg static char *result = NULL; 77281676fe2Smrg char *tail = NULL; 77391ec45ceSmrg int alloced; 77491ec45ceSmrg const unsigned long *end = icon + len / sizeof (unsigned long); 77591ec45ceSmrg 77681676fe2Smrg free(result); 77781676fe2Smrg result = NULL; 77881676fe2Smrg 77991ec45ceSmrg alloced = 0; 78091ec45ceSmrg 78191ec45ceSmrg while (icon < end) 78291ec45ceSmrg { 783f9c28e31Smrg unsigned long width, height, display_width; 784f9c28e31Smrg unsigned int icon_pixel_bytes; 785f9c28e31Smrg unsigned int icon_line_bytes; 78691ec45ceSmrg int offset; 78791ec45ceSmrg 78891ec45ceSmrg width = *icon++; 78991ec45ceSmrg height = *icon++; 790f9c28e31Smrg display_width = width * 2; /* Two characters per icon pixel. */ 791f9c28e31Smrg 792f9c28e31Smrg icon_pixel_bytes = 1; 793f9c28e31Smrg if (is_truecolor_term()) 794f9c28e31Smrg icon_pixel_bytes = 25; /* 16 control characters, and up to 9 chars of RGB. */ 795f9c28e31Smrg else if (is_utf8_locale()) 796f9c28e31Smrg icon_pixel_bytes = 3; /* Up to 3 bytes per character in that mode. */ 797f9c28e31Smrg 798f9c28e31Smrg /* Initial tab, pixels, and newline. */ 799f9c28e31Smrg icon_line_bytes = 8 + display_width * icon_pixel_bytes + 1; 80091ec45ceSmrg 80191ec45ceSmrg offset = (tail - result); 80291ec45ceSmrg 803f9c28e31Smrg alloced += 80; /* For the header, final newline, color reset */ 804f9c28e31Smrg alloced += icon_line_bytes * height; /* For the rows */ 80591ec45ceSmrg 806f4a95042Smrg result = realloc (result, alloced); 807f4a95042Smrg if (!result) 808f4a95042Smrg Fatal_Error("Out of memory!"); 80991ec45ceSmrg tail = &result[offset]; 81091ec45ceSmrg 81191ec45ceSmrg if (end - icon < width * height) 81291ec45ceSmrg break; 81391ec45ceSmrg 81491ec45ceSmrg tail += sprintf (tail, "\tIcon (%lu x %lu):\n", width, height); 81591ec45ceSmrg 816f9c28e31Smrg if ((display_width + 8) > term_width || height > 144) 81791ec45ceSmrg { 818f9c28e31Smrg tail += sprintf (tail, "\t(not shown)\n"); 81991ec45ceSmrg icon += width * height; 82091ec45ceSmrg continue; 82191ec45ceSmrg } 82291ec45ceSmrg 82349bee38cSmrg for (unsigned int h = 0; h < height; ++h) 82491ec45ceSmrg { 82591ec45ceSmrg tail += sprintf (tail, "\t"); 82691ec45ceSmrg 82749bee38cSmrg for (unsigned int w = 0; w < width; ++w) 82891ec45ceSmrg { 82991ec45ceSmrg unsigned char a, r, g, b; 83091ec45ceSmrg unsigned long pixel = *icon++; 83191ec45ceSmrg unsigned long brightness; 83291ec45ceSmrg 83391ec45ceSmrg a = (pixel & 0xff000000) >> 24; 83491ec45ceSmrg r = (pixel & 0x00ff0000) >> 16; 83591ec45ceSmrg g = (pixel & 0x0000ff00) >> 8; 83691ec45ceSmrg b = (pixel & 0x000000ff); 83791ec45ceSmrg 83891ec45ceSmrg brightness = 83991ec45ceSmrg (a / 255.0) * (1000 - ((299 * (r / 255.0)) + 84091ec45ceSmrg (587 * (g / 255.0)) + 84191ec45ceSmrg (114 * (b / 255.0)))); 84291ec45ceSmrg 843f9c28e31Smrg if (is_truecolor_term()) 844f9c28e31Smrg { 845f9c28e31Smrg float opacity = a / 255.0; 846f9c28e31Smrg 847f9c28e31Smrg r = r * opacity; 848f9c28e31Smrg g = g * opacity; 849f9c28e31Smrg b = b * opacity; 850f9c28e31Smrg 851f9c28e31Smrg tail += sprintf (tail, "\033[38;2;%d;%d;%dm\342\226\210\342\226\210", r, g, b ); 852f9c28e31Smrg } 853f9c28e31Smrg else if (is_utf8_locale()) 85491ec45ceSmrg { 85591ec45ceSmrg static const char palette[][4] = 85691ec45ceSmrg { 85791ec45ceSmrg " ", 85891ec45ceSmrg "\342\226\221", /* 25% */ 85991ec45ceSmrg "\342\226\222", /* 50% */ 86091ec45ceSmrg "\342\226\223", /* 75% */ 86191ec45ceSmrg "\342\226\210", /* 100% */ 86291ec45ceSmrg }; 86391ec45ceSmrg int idx; 86491ec45ceSmrg 86591ec45ceSmrg idx = (brightness * ((sizeof (palette)/sizeof(palette[0])) - 1)) / 1000; 86691ec45ceSmrg 867f9c28e31Smrg tail += sprintf (tail, "%s%s", palette[idx], palette[idx]); 86891ec45ceSmrg } 86991ec45ceSmrg else 87091ec45ceSmrg { 87191ec45ceSmrg static const char palette[] = 87291ec45ceSmrg " .'`,^:\";~-_+<>i!lI?/\\|()1{}[]rcvunxzjftLCJUYXZO0Qoahkbdpqwm*WMB8&%$#@"; 87391ec45ceSmrg int idx; 87491ec45ceSmrg 87591ec45ceSmrg idx = (brightness * (sizeof(palette) - 2)) / 1000; 87691ec45ceSmrg 87791ec45ceSmrg *tail++ = palette[idx]; 878f9c28e31Smrg *tail++ = palette[idx]; 87991ec45ceSmrg } 88091ec45ceSmrg } 88191ec45ceSmrg 88291ec45ceSmrg tail += sprintf (tail, "\n"); 88391ec45ceSmrg } 88491ec45ceSmrg 885f9c28e31Smrg /* Reset colors. */ 886f9c28e31Smrg if (is_truecolor_term()) 887f9c28e31Smrg tail += sprintf (tail, "\033[0m"); 888f9c28e31Smrg 88991ec45ceSmrg tail += sprintf (tail, "\n"); 89091ec45ceSmrg } 89191ec45ceSmrg 89291ec45ceSmrg return result; 89391ec45ceSmrg} 89491ec45ceSmrg 895fc89c0fbSmrgstatic const char * 896fc89c0fbSmrgFormat_Len_Text (const char *string, int len, Atom encoding) 897fc89c0fbSmrg{ 898fc89c0fbSmrg XTextProperty textprop; 89949bee38cSmrg char **start_list; 900fc89c0fbSmrg int count; 901fc89c0fbSmrg 902fc89c0fbSmrg /* Try to convert to local encoding. */ 903fc89c0fbSmrg textprop.encoding = encoding; 904fc89c0fbSmrg textprop.format = 8; 905fc89c0fbSmrg textprop.value = (unsigned char *) string; 906fc89c0fbSmrg textprop.nitems = len; 907f9c28e31Smrg if (XmbTextPropertyToTextList(dpy, &textprop, &start_list, &count) == Success) { 90849bee38cSmrg char **list = start_list; 909fc89c0fbSmrg _buf_ptr = _formatting_buffer; 910fc89c0fbSmrg _buf_len = MAXSTR; 911fc89c0fbSmrg *_buf_ptr++ = '"'; 912fc89c0fbSmrg while (count > 0) { 913fc89c0fbSmrg string = *list++; 914fc89c0fbSmrg len = strlen(string); 915fc89c0fbSmrg while (len > 0) { 916fc89c0fbSmrg wchar_t wc; 917fc89c0fbSmrg int n = mbtowc(&wc, string, len); 918fc89c0fbSmrg if (n > 0 && iswprint(wc)) { 919fc89c0fbSmrg if (_buf_len >= n) { 920fc89c0fbSmrg memcpy(_buf_ptr, string, n); 921fc89c0fbSmrg _buf_ptr += n; 922fc89c0fbSmrg _buf_len -= n; 923fc89c0fbSmrg } 924fc89c0fbSmrg string += n; 925fc89c0fbSmrg len -= n; 926fc89c0fbSmrg } else { 927fc89c0fbSmrg _put_char('\\'); 928fc89c0fbSmrg snprintf(_buf_ptr, _buf_len, "%03o", (unsigned char) *string); 929fc89c0fbSmrg _buf_ptr += 3; 930fc89c0fbSmrg _buf_len -= 3; 931fc89c0fbSmrg string++; 932fc89c0fbSmrg len--; 933fc89c0fbSmrg } 934fc89c0fbSmrg } 935fc89c0fbSmrg count--; 936fc89c0fbSmrg if (count > 0) { 937fc89c0fbSmrg snprintf(_buf_ptr, _buf_len, "\\000"); 938fc89c0fbSmrg _buf_ptr += 4; 939fc89c0fbSmrg _buf_len -= 4; 940fc89c0fbSmrg } 941fc89c0fbSmrg } 942f9c28e31Smrg XFreeStringList(start_list); 943fc89c0fbSmrg *_buf_ptr++ = '"'; 944fc89c0fbSmrg *_buf_ptr++ = '\0'; 945fc89c0fbSmrg return _formatting_buffer; 946fc89c0fbSmrg } else 947576bbdfcSmrg return Format_Len_String(string, len, 0); 948fc89c0fbSmrg} 949fc89c0fbSmrg 950a0996ce0Smrg/* 951a0996ce0Smrg * Validate a string as UTF-8 encoded according to RFC 3629 952a0996ce0Smrg * 953a0996ce0Smrg * Simply, a unicode code point (up to 21-bits long) is encoded as follows: 954a0996ce0Smrg * 955a0996ce0Smrg * Char. number range | UTF-8 octet sequence 956a0996ce0Smrg * (hexadecimal) | (binary) 957a0996ce0Smrg * --------------------+--------------------------------------------- 958a0996ce0Smrg * 0000 0000-0000 007F | 0xxxxxxx 959a0996ce0Smrg * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx 960a0996ce0Smrg * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx 961a0996ce0Smrg * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 962a0996ce0Smrg * 963a0996ce0Smrg * Validation is done left-to-right, and an error condition, if any, refers to 964a0996ce0Smrg * only the left-most problem in the string. 965a0996ce0Smrg * 966a0996ce0Smrg * Return values: 967a0996ce0Smrg * UTF8_VALID: Valid UTF-8 encoded string 968a0996ce0Smrg * UTF8_OVERLONG: Using more bytes than needed for a code point 969a0996ce0Smrg * UTF8_SHORT_TAIL: Not enough bytes in a multi-byte sequence 970a0996ce0Smrg * UTF8_LONG_TAIL: Too many bytes in a multi-byte sequence 971a0996ce0Smrg * UTF8_FORBIDDEN_VALUE: Forbidden prefix or code point outside 0x10FFFF 972a0996ce0Smrg */ 973a0996ce0Smrg#define UTF8_VALID 0 974a0996ce0Smrg#define UTF8_FORBIDDEN_VALUE 1 975a0996ce0Smrg#define UTF8_OVERLONG 2 976a0996ce0Smrg#define UTF8_SHORT_TAIL 3 977a0996ce0Smrg#define UTF8_LONG_TAIL 4 978a0996ce0Smrgstatic int 979a0996ce0Smrgis_valid_utf8 (const char *string, int len) 980a0996ce0Smrg{ 981f4a95042Smrg unsigned long codepoint = 0; 98249bee38cSmrg int rem = 0; 983a0996ce0Smrg 98449bee38cSmrg for (int i = 0; i < len; i++) { 98549bee38cSmrg unsigned char 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 int validity = is_valid_utf8(string, len); 1028a0996ce0Smrg 1029a0996ce0Smrg if (validity != UTF8_VALID) { 103049bee38cSmrg char *data; 103149bee38cSmrg const char *result, *error; 103249bee38cSmrg 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{ 115049bee38cSmrg for (int j = 0; j < (int)strlen(format); j++) 1151fc89c0fbSmrg if (Get_Format_Char(format, j) == 'm') 1152fc89c0fbSmrg return thunks[j].value; 1153fc89c0fbSmrg return 0; 1154fc89c0fbSmrg} 1155fc89c0fbSmrg 1156fc89c0fbSmrg/* 1157fc89c0fbSmrg * 1158fc89c0fbSmrg * The Display Format Manager: 1159fc89c0fbSmrg * 1160fc89c0fbSmrg */ 1161fc89c0fbSmrg 1162fc89c0fbSmrgstatic int 1163fc89c0fbSmrgIs_A_DFormat (const char *string) 1164fc89c0fbSmrg{ 1165fc89c0fbSmrg return string[0] && string[0] != '-' 1166fc89c0fbSmrg && !(isalpha((unsigned char) string[0]) || string[0] == '_'); 1167fc89c0fbSmrg} 1168fc89c0fbSmrg 1169fc89c0fbSmrgstatic const char * 1170fc89c0fbSmrgHandle_Backslash (const char *dformat) 1171fc89c0fbSmrg{ 1172fc89c0fbSmrg char c; 1173fc89c0fbSmrg unsigned long i; 1174fc89c0fbSmrg 1175fc89c0fbSmrg if (!(c = *(dformat++))) 1176fc89c0fbSmrg return dformat; 1177fc89c0fbSmrg 1178fc89c0fbSmrg switch (c) { 1179fc89c0fbSmrg case 'n': 1180fc89c0fbSmrg putchar('\n'); 1181fc89c0fbSmrg break; 1182fc89c0fbSmrg case 't': 1183fc89c0fbSmrg putchar('\t'); 1184fc89c0fbSmrg break; 1185fc89c0fbSmrg case '0': 1186fc89c0fbSmrg case '1': 1187fc89c0fbSmrg case '2': 1188fc89c0fbSmrg case '3': 1189fc89c0fbSmrg case '4': 1190fc89c0fbSmrg case '5': 1191fc89c0fbSmrg case '6': 1192fc89c0fbSmrg case '7': 1193fc89c0fbSmrg dformat = Scan_Octal(dformat, &i); 1194fc89c0fbSmrg putchar((int) i); 1195fc89c0fbSmrg break; 1196fc89c0fbSmrg default: 1197fc89c0fbSmrg putchar(c); 1198fc89c0fbSmrg break; 1199fc89c0fbSmrg } 1200fc89c0fbSmrg return dformat; 1201fc89c0fbSmrg} 1202fc89c0fbSmrg 1203fc89c0fbSmrgstatic const char * 1204fc89c0fbSmrgHandle_Dollar_sign (const char *dformat, thunk *thunks, const char *format) 1205fc89c0fbSmrg{ 1206fc89c0fbSmrg long i; 1207fc89c0fbSmrg 1208fc89c0fbSmrg dformat = Scan_Long(dformat, &i); 1209fc89c0fbSmrg 1210fc89c0fbSmrg if (dformat[0] == '+') { 1211fc89c0fbSmrg int seen = 0; 1212fc89c0fbSmrg dformat++; 1213fc89c0fbSmrg for (; i < thunks->thunk_count; i++) { 1214fc89c0fbSmrg if (seen) 1215fc89c0fbSmrg printf(", "); 1216fc89c0fbSmrg seen = 1; 1217fc89c0fbSmrg printf("%s", Format_Thunk_I(thunks, format, (int) i)); 1218fc89c0fbSmrg } 1219fc89c0fbSmrg } else 1220fc89c0fbSmrg printf("%s", Format_Thunk_I(thunks, format, (int) i)); 1221fc89c0fbSmrg 1222fc89c0fbSmrg return dformat; 1223fc89c0fbSmrg} 1224fc89c0fbSmrg 1225fc89c0fbSmrgstatic int 1226fc89c0fbSmrgMask_Bit_I (thunk *thunks, const char *format, int i) 1227fc89c0fbSmrg{ 1228fc89c0fbSmrg long value; 1229fc89c0fbSmrg 1230fc89c0fbSmrg value = Mask_Word(thunks, format); 1231fc89c0fbSmrg 1232fc89c0fbSmrg value = value & (1L<<i); 1233fc89c0fbSmrg if (value) 1234fc89c0fbSmrg value = 1; 1235fc89c0fbSmrg return value; 1236fc89c0fbSmrg} 1237fc89c0fbSmrg 1238fc89c0fbSmrgstatic const char * 1239fc89c0fbSmrgScan_Term (const char *string, thunk *thunks, const char *format, long *value) 1240fc89c0fbSmrg{ 1241fc89c0fbSmrg long i; 1242fc89c0fbSmrg 1243fc89c0fbSmrg *value = 0; 1244fc89c0fbSmrg 1245fc89c0fbSmrg if (isdigit((unsigned char) *string)) 1246fc89c0fbSmrg string = Scan_Long(string, value); 1247fc89c0fbSmrg else if (*string == '$') { 1248fc89c0fbSmrg string = Scan_Long(++string, &i); 1249fc89c0fbSmrg if (i >= thunks->thunk_count) 1250fc89c0fbSmrg i = thunks->thunk_count; 1251fc89c0fbSmrg *value = thunks[i].value; 1252fc89c0fbSmrg } else if (*string == 'm') { 1253fc89c0fbSmrg string = Scan_Long(++string, &i); 1254fc89c0fbSmrg *value = Mask_Bit_I(thunks, format, (int) i); 1255fc89c0fbSmrg } else 1256fc89c0fbSmrg Fatal_Error("Bad term: %s.", string); 1257fc89c0fbSmrg 1258fc89c0fbSmrg return string; 1259fc89c0fbSmrg} 1260fc89c0fbSmrg 1261fc89c0fbSmrgstatic const char * 1262fc89c0fbSmrgScan_Exp (const char *string, thunk *thunks, const char *format, long *value) 1263fc89c0fbSmrg{ 1264fc89c0fbSmrg long temp; 1265fc89c0fbSmrg 1266fc89c0fbSmrg if (string[0] == '(') { 1267fc89c0fbSmrg string = Scan_Exp(++string, thunks, format, value); 1268fc89c0fbSmrg if (string[0]!=')') 1269fc89c0fbSmrg Fatal_Error("Missing ')'"); 1270fc89c0fbSmrg return ++string; 1271fc89c0fbSmrg } 1272fc89c0fbSmrg if (string[0] == '!') { 1273fc89c0fbSmrg string = Scan_Exp(++string, thunks, format, value); 1274fc89c0fbSmrg *value = !*value; 1275fc89c0fbSmrg return string; 1276fc89c0fbSmrg } 1277fc89c0fbSmrg 1278fc89c0fbSmrg string = Scan_Term(string, thunks, format, value); 1279fc89c0fbSmrg 1280fc89c0fbSmrg if (string[0] == '=') { 1281fc89c0fbSmrg string = Scan_Exp(++string, thunks, format, &temp); 1282fc89c0fbSmrg *value = *value == temp; 1283fc89c0fbSmrg } 1284fc89c0fbSmrg 1285fc89c0fbSmrg return string; 1286fc89c0fbSmrg} 1287fc89c0fbSmrg 1288fc89c0fbSmrgstatic const char * 1289fc89c0fbSmrgHandle_Question_Mark (const char *dformat, thunk *thunks, const char *format) 1290fc89c0fbSmrg{ 1291fc89c0fbSmrg long true; 1292fc89c0fbSmrg 1293fc89c0fbSmrg dformat = Scan_Exp(dformat, thunks, format, &true); 1294fc89c0fbSmrg 1295fc89c0fbSmrg if (*dformat != '(') 1296fc89c0fbSmrg Fatal_Error("Bad conditional: '(' expected: %s.", dformat); 1297fc89c0fbSmrg ++dformat; 1298fc89c0fbSmrg 1299fc89c0fbSmrg if (!true) 1300fc89c0fbSmrg dformat = Skip_Past_Right_Paren(dformat); 1301fc89c0fbSmrg 1302fc89c0fbSmrg return dformat; 1303fc89c0fbSmrg} 1304fc89c0fbSmrg 1305fc89c0fbSmrgstatic void 1306fc89c0fbSmrgDisplay_Property (thunk *thunks, const char *dformat, const char *format) 1307fc89c0fbSmrg{ 1308fc89c0fbSmrg char c; 1309fc89c0fbSmrg 1310fc89c0fbSmrg while ((c = *(dformat++))) 1311fc89c0fbSmrg switch (c) { 1312fc89c0fbSmrg case ')': 1313fc89c0fbSmrg continue; 1314fc89c0fbSmrg case '\\': 1315fc89c0fbSmrg dformat = Handle_Backslash(dformat); 1316fc89c0fbSmrg continue; 1317fc89c0fbSmrg case '$': 1318fc89c0fbSmrg dformat = Handle_Dollar_sign(dformat, thunks, format); 1319fc89c0fbSmrg continue; 1320fc89c0fbSmrg case '?': 1321fc89c0fbSmrg dformat = Handle_Question_Mark(dformat, thunks, format); 1322fc89c0fbSmrg continue; 1323fc89c0fbSmrg default: 1324fc89c0fbSmrg putchar(c); 1325fc89c0fbSmrg continue; 1326fc89c0fbSmrg } 1327fc89c0fbSmrg} 1328fc89c0fbSmrg 1329fc89c0fbSmrg/* 1330fc89c0fbSmrg * 1331fc89c0fbSmrg * Routines to convert property data to thunks 1332fc89c0fbSmrg * 1333fc89c0fbSmrg */ 1334fc89c0fbSmrg 1335fc89c0fbSmrgstatic long 1336fc89c0fbSmrgExtract_Value (const char **pointer, int *length, int size, int signedp) 1337fc89c0fbSmrg{ 1338fc89c0fbSmrg long value; 1339fc89c0fbSmrg 1340fc89c0fbSmrg switch (size) { 1341fc89c0fbSmrg case 8: 1342fc89c0fbSmrg if (signedp) 1343fc89c0fbSmrg value = * (const signed char *) *pointer; 1344fc89c0fbSmrg else 1345fc89c0fbSmrg value = * (const unsigned char *) *pointer; 1346fc89c0fbSmrg *pointer += 1; 1347fc89c0fbSmrg *length -= 1; 1348fc89c0fbSmrg break; 1349fc89c0fbSmrg case 16: 1350fc89c0fbSmrg if (signedp) 1351fc89c0fbSmrg value = * (const short *) *pointer; 1352fc89c0fbSmrg else 1353fc89c0fbSmrg value = * (const unsigned short *) *pointer; 1354fc89c0fbSmrg *pointer += sizeof(short); 1355fc89c0fbSmrg *length -= sizeof(short); 1356fc89c0fbSmrg break; 1357fc89c0fbSmrg case 32: 1358fc89c0fbSmrg if (signedp) 1359fc89c0fbSmrg value = * (const long *) *pointer; 1360fc89c0fbSmrg else 1361fc89c0fbSmrg value = * (const unsigned long *) *pointer & 0xffffffff; 1362fc89c0fbSmrg *pointer += sizeof(long); 1363fc89c0fbSmrg *length -= sizeof(long); 1364fc89c0fbSmrg break; 1365fc89c0fbSmrg default: 1366fc89c0fbSmrg abort(); 1367fc89c0fbSmrg } 1368fc89c0fbSmrg return value; 1369fc89c0fbSmrg} 1370fc89c0fbSmrg 1371fc89c0fbSmrgstatic long 1372fc89c0fbSmrgExtract_Len_String (const char **pointer, int *length, int size, const char **string) 1373fc89c0fbSmrg{ 1374fc89c0fbSmrg int len; 1375fc89c0fbSmrg 1376fc89c0fbSmrg if (size != 8) 1377fc89c0fbSmrg Fatal_Error("can't use format character 's' with any size except 8."); 1378fc89c0fbSmrg len = 0; *string = *pointer; 1379fc89c0fbSmrg while ((len++, --*length, *((*pointer)++)) && *length>0); 1380fc89c0fbSmrg 1381fc89c0fbSmrg return len; 1382fc89c0fbSmrg} 1383fc89c0fbSmrg 138491ec45ceSmrgstatic long 138591ec45ceSmrgExtract_Icon (const char **pointer, int *length, int size, const char **icon) 138691ec45ceSmrg{ 138791ec45ceSmrg int len = 0; 138891ec45ceSmrg 138991ec45ceSmrg if (size != 32) 139091ec45ceSmrg Fatal_Error("can't use format character 'o' with any size except 32."); 139191ec45ceSmrg 139291ec45ceSmrg len = *length; 139391ec45ceSmrg *icon = *pointer; 139491ec45ceSmrg *length = 0; 139591ec45ceSmrg return len; 139691ec45ceSmrg} 139791ec45ceSmrg 1398fc89c0fbSmrgstatic thunk * 1399fc89c0fbSmrgBreak_Down_Property (const char *pointer, int length, Atom type, const char *format, int size) 1400fc89c0fbSmrg{ 1401fc89c0fbSmrg thunk *thunks; 1402f4a95042Smrg thunk t = {0}; 1403fc89c0fbSmrg int i; 1404fc89c0fbSmrg 1405fc89c0fbSmrg thunks = Create_Thunk_List(); 1406fc89c0fbSmrg i = 0; 1407fc89c0fbSmrg 1408fc89c0fbSmrg while (length >= size/8) { 140949bee38cSmrg char format_char = Get_Format_Char(format, i); 141049bee38cSmrg 1411a0996ce0Smrg if (format_char == 's' || format_char == 'u') 1412fc89c0fbSmrg t.value = Extract_Len_String(&pointer,&length,size,&t.extra_value); 1413fc89c0fbSmrg else if (format_char == 't') { 1414fc89c0fbSmrg t.extra_encoding = type; 1415fc89c0fbSmrg t.value = Extract_Len_String(&pointer,&length,size,&t.extra_value); 141691ec45ceSmrg } 141791ec45ceSmrg else if (format_char == 'o') 141891ec45ceSmrg t.value = Extract_Icon (&pointer,&length,size,&t.extra_value); 141991ec45ceSmrg else 1420fc89c0fbSmrg t.value = Extract_Value(&pointer,&length,size,format_char=='i'); 1421fc89c0fbSmrg thunks = Add_Thunk(thunks, t); 1422fc89c0fbSmrg i++; 1423fc89c0fbSmrg } 1424fc89c0fbSmrg 1425fc89c0fbSmrg return thunks; 1426fc89c0fbSmrg} 1427fc89c0fbSmrg 1428fc89c0fbSmrg/* 1429fc89c0fbSmrg * Variables set by main() 1430fc89c0fbSmrg */ 1431fc89c0fbSmrg 1432fc89c0fbSmrgstatic Window target_win = 0; 1433fc89c0fbSmrgstatic int notype = 0; 1434fc89c0fbSmrgstatic int max_len = MAXSTR; 1435fc89c0fbSmrgstatic XFontStruct *font; 1436fc89c0fbSmrgstatic unsigned long _font_prop; 1437fc89c0fbSmrg 1438fc89c0fbSmrg/* 1439fc89c0fbSmrg * 1440fc89c0fbSmrg * Other Stuff (temp.): 1441fc89c0fbSmrg * 1442fc89c0fbSmrg */ 1443fc89c0fbSmrg 1444fc89c0fbSmrgstatic const char * 1445fc89c0fbSmrgGet_Font_Property_Data_And_Type (Atom atom, 1446fc89c0fbSmrg long *length, Atom *type, int *size) 1447fc89c0fbSmrg{ 1448fc89c0fbSmrg *type = None; 1449fc89c0fbSmrg 145049bee38cSmrg for (int i = 0; i < font->n_properties; i++) 1451fc89c0fbSmrg if (atom == font->properties[i].name) { 1452fc89c0fbSmrg _font_prop = font->properties[i].card32; 1453fc89c0fbSmrg *length = sizeof(long); 1454fc89c0fbSmrg *size = 32; 1455fc89c0fbSmrg return (const char *) &_font_prop; 1456fc89c0fbSmrg } 1457fc89c0fbSmrg *size = 0; 1458fc89c0fbSmrg return NULL; 1459fc89c0fbSmrg} 1460fc89c0fbSmrg 1461fc89c0fbSmrgstatic const char * 1462fc89c0fbSmrgGet_Window_Property_Data_And_Type (Atom atom, 1463fc89c0fbSmrg long *length, Atom *type, int *size) 1464fc89c0fbSmrg{ 1465fc89c0fbSmrg Atom actual_type; 1466fc89c0fbSmrg int actual_format; 1467fc89c0fbSmrg unsigned long nitems; 1468fc89c0fbSmrg unsigned long nbytes; 1469fc89c0fbSmrg unsigned long bytes_after; 147081676fe2Smrg static unsigned char *prop = NULL; 1471fc89c0fbSmrg int status; 147281676fe2Smrg 147381676fe2Smrg if (prop) 147481676fe2Smrg { 147581676fe2Smrg XFree(prop); 147681676fe2Smrg prop = NULL; 147781676fe2Smrg } 147881676fe2Smrg 1479fc89c0fbSmrg status = XGetWindowProperty(dpy, target_win, atom, 0, (max_len+3)/4, 1480fc89c0fbSmrg False, AnyPropertyType, &actual_type, 1481fc89c0fbSmrg &actual_format, &nitems, &bytes_after, 1482fc89c0fbSmrg &prop); 1483fc89c0fbSmrg if (status == BadWindow) 1484fc89c0fbSmrg Fatal_Error("window id # 0x%lx does not exists!", target_win); 1485fc89c0fbSmrg if (status != Success) 1486fc89c0fbSmrg Fatal_Error("XGetWindowProperty failed!"); 1487fc89c0fbSmrg 1488fc89c0fbSmrg if (actual_format == 32) 1489fc89c0fbSmrg nbytes = sizeof(long); 1490fc89c0fbSmrg else if (actual_format == 16) 1491fc89c0fbSmrg nbytes = sizeof(short); 1492fc89c0fbSmrg else if (actual_format == 8) 1493fc89c0fbSmrg nbytes = 1; 1494fc89c0fbSmrg else if (actual_format == 0) 1495fc89c0fbSmrg nbytes = 0; 1496fc89c0fbSmrg else 1497fc89c0fbSmrg abort(); 1498fc89c0fbSmrg *length = min(nitems * nbytes, max_len); 1499fc89c0fbSmrg *type = actual_type; 1500fc89c0fbSmrg *size = actual_format; 1501fc89c0fbSmrg return (const char *)prop; 1502fc89c0fbSmrg} 1503fc89c0fbSmrg 1504fc89c0fbSmrgstatic const char * 1505fc89c0fbSmrgGet_Property_Data_And_Type (Atom atom, long *length, Atom *type, int *size) 1506fc89c0fbSmrg{ 150749bee38cSmrg if (target_win == (Window) -1) 1508fc89c0fbSmrg return Get_Font_Property_Data_And_Type(atom, length, type, size); 1509fc89c0fbSmrg else 1510fc89c0fbSmrg return Get_Window_Property_Data_And_Type(atom, length, type, size); 1511fc89c0fbSmrg} 1512fc89c0fbSmrg 1513fc89c0fbSmrgstatic void 1514fc89c0fbSmrgShow_Prop (const char *format, const char *dformat, const char *prop) 1515fc89c0fbSmrg{ 1516fc89c0fbSmrg const char *data; 1517fc89c0fbSmrg long length; 1518fc89c0fbSmrg Atom atom, type; 1519fc89c0fbSmrg thunk *thunks; 1520fc89c0fbSmrg int size, fsize; 1521fc89c0fbSmrg 1522fc89c0fbSmrg printf("%s", prop); 1523fc89c0fbSmrg atom = Parse_Atom(prop, True); 1524fc89c0fbSmrg if (atom == None) { 1525fc89c0fbSmrg printf(": no such atom on any window.\n"); 1526fc89c0fbSmrg return; 1527fc89c0fbSmrg } 1528fc89c0fbSmrg 1529fc89c0fbSmrg data = Get_Property_Data_And_Type(atom, &length, &type, &size); 1530fc89c0fbSmrg if (!size) { 1531fc89c0fbSmrg puts(": not found."); 1532fc89c0fbSmrg return; 1533fc89c0fbSmrg } 1534fc89c0fbSmrg 1535fc89c0fbSmrg if (!notype && type != None) 1536fc89c0fbSmrg printf("(%s)", Format_Atom(type)); 1537fc89c0fbSmrg 1538fc89c0fbSmrg Lookup_Formats(atom, &format, &dformat); 1539fc89c0fbSmrg if (type != None) 1540fc89c0fbSmrg Lookup_Formats(type, &format, &dformat); 1541fc89c0fbSmrg Apply_Default_Formats(&format, &dformat); 1542fc89c0fbSmrg 1543fc89c0fbSmrg fsize = Get_Format_Size(format); 1544fc89c0fbSmrg if (fsize != size && fsize != 0) { 1545fc89c0fbSmrg printf(": Type mismatch: assumed size %d bits, actual size %d bits.\n", 1546fc89c0fbSmrg fsize, size); 1547fc89c0fbSmrg return; 1548fc89c0fbSmrg } 1549fc89c0fbSmrg 1550fc89c0fbSmrg thunks = Break_Down_Property(data, (int)length, type, format, size); 1551fc89c0fbSmrg Display_Property(thunks, dformat, format); 155281676fe2Smrg free(thunks); 1553fc89c0fbSmrg} 1554fc89c0fbSmrg 1555fc89c0fbSmrgstatic void 1556fc89c0fbSmrgShow_All_Props (void) 1557fc89c0fbSmrg{ 155849bee38cSmrg if (target_win != (Window) -1) { 155949bee38cSmrg int count; 156049bee38cSmrg Atom *atoms = XListProperties(dpy, target_win, &count); 156149bee38cSmrg for (int i = 0; i < count; i++) { 156249bee38cSmrg const char *name = Format_Atom(atoms[i]); 1563fc89c0fbSmrg Show_Prop(NULL, NULL, name); 1564fc89c0fbSmrg } 156581676fe2Smrg XFree(atoms); 156649bee38cSmrg } else { 156749bee38cSmrg for (int i = 0; i < font->n_properties; i++) { 156849bee38cSmrg Atom atom = font->properties[i].name; 156949bee38cSmrg const char *name = Format_Atom(atom); 1570fc89c0fbSmrg Show_Prop(NULL, NULL, name); 1571fc89c0fbSmrg } 157249bee38cSmrg } 1573fc89c0fbSmrg} 1574fc89c0fbSmrg 1575fc89c0fbSmrgstatic thunk * 1576fc89c0fbSmrgHandle_Prop_Requests (int argc, char **argv) 1577fc89c0fbSmrg{ 1578fc89c0fbSmrg char *format, *dformat, *prop; 1579f4a95042Smrg thunk *thunks, t = {0}; 1580fc89c0fbSmrg 1581fc89c0fbSmrg /* if no prop referenced, by default list all properties for given window */ 1582fc89c0fbSmrg if (!argc) { 1583fc89c0fbSmrg Show_All_Props(); 1584fc89c0fbSmrg return NULL; 1585fc89c0fbSmrg } 1586fc89c0fbSmrg 1587fc89c0fbSmrg thunks = Create_Thunk_List(); 1588fc89c0fbSmrg 1589fc89c0fbSmrg while (argc > 0) { 1590fc89c0fbSmrg format = NULL; 1591fc89c0fbSmrg dformat = NULL; 1592fc89c0fbSmrg 1593fc89c0fbSmrg /* Get overriding formats, if any */ 1594fc89c0fbSmrg if (Is_A_Format(argv[0])) { 1595fc89c0fbSmrg format = argv++[0]; argc--; 159681676fe2Smrg if (!argc) usage("format specified without atom"); 1597fc89c0fbSmrg } 1598fc89c0fbSmrg if (Is_A_DFormat(argv[0])) { 1599fc89c0fbSmrg dformat = argv++[0]; argc--; 160081676fe2Smrg if (!argc) usage("dformat specified without atom"); 1601fc89c0fbSmrg } 1602fc89c0fbSmrg 1603fc89c0fbSmrg /* Get property name */ 1604fc89c0fbSmrg prop = argv++[0]; argc--; 1605fc89c0fbSmrg 1606fc89c0fbSmrg t.propname = prop; 1607fc89c0fbSmrg t.value = Parse_Atom(prop, True); 1608fc89c0fbSmrg t.format = format; 1609fc89c0fbSmrg t.dformat = dformat; 1610fc89c0fbSmrg if (t.value) 1611fc89c0fbSmrg thunks = Add_Thunk(thunks, t); 1612fc89c0fbSmrg Show_Prop(format, dformat, prop); 1613fc89c0fbSmrg } 1614fc89c0fbSmrg return thunks; 1615fc89c0fbSmrg} 1616fc89c0fbSmrg 1617fc89c0fbSmrgstatic void 161849bee38cSmrgRemove_Property (Display *display, Window w, const char *propname) 1619fc89c0fbSmrg{ 162049bee38cSmrg Atom id = XInternAtom (display, propname, True); 1621fc89c0fbSmrg 1622fc89c0fbSmrg if (id == None) { 1623fc89c0fbSmrg fprintf (stderr, "%s: no such property \"%s\"\n", 1624fc89c0fbSmrg program_name, propname); 1625fc89c0fbSmrg return; 1626fc89c0fbSmrg } 162749bee38cSmrg XDeleteProperty (display, w, id); 1628fc89c0fbSmrg} 1629fc89c0fbSmrg 1630fc89c0fbSmrgstatic void 163149bee38cSmrgSet_Property (Display *display, Window w, const char *propname, const char *value) 1632fc89c0fbSmrg{ 1633fc89c0fbSmrg Atom atom; 1634fc89c0fbSmrg const char *format; 1635fc89c0fbSmrg const char *dformat; 1636fc89c0fbSmrg int size; 1637fc89c0fbSmrg char format_char; 1638fc89c0fbSmrg Atom type = 0; 1639576bbdfcSmrg const unsigned char *data = NULL; 1640fc89c0fbSmrg int nelements = 0; 1641fc89c0fbSmrg 1642fc89c0fbSmrg atom = Parse_Atom(propname, False); 1643fc89c0fbSmrg 1644fc89c0fbSmrg format = dformat = NULL; 1645fc89c0fbSmrg Lookup_Formats(atom, &format, &dformat); 1646fc89c0fbSmrg if (format == NULL) 1647fc89c0fbSmrg Fatal_Error("unsupported conversion for %s", propname); 1648fc89c0fbSmrg 1649fc89c0fbSmrg size = Get_Format_Size(format); 1650fc89c0fbSmrg 1651fc89c0fbSmrg format_char = Get_Format_Char(format, 0); 1652fc89c0fbSmrg switch (format_char) { 1653fc89c0fbSmrg case 's': 1654fc89c0fbSmrg if (size != 8) 1655fc89c0fbSmrg Fatal_Error("can't use format character 's' with any size except 8."); 1656fc89c0fbSmrg type = XA_STRING; 1657576bbdfcSmrg data = (const unsigned char *) value; 1658576bbdfcSmrg nelements = strlen(value); 1659576bbdfcSmrg break; 1660576bbdfcSmrg case 'u': 1661576bbdfcSmrg if (size != 8) 1662576bbdfcSmrg Fatal_Error("can't use format character 'u' with any size except 8."); 166349bee38cSmrg type = XInternAtom(display, "UTF8_STRING", False); 1664576bbdfcSmrg data = (const unsigned char *) value; 1665fc89c0fbSmrg nelements = strlen(value); 1666fc89c0fbSmrg break; 1667fc89c0fbSmrg case 't': { 1668fc89c0fbSmrg XTextProperty textprop; 1669fc89c0fbSmrg if (size != 8) 1670fc89c0fbSmrg Fatal_Error("can't use format character 't' with any size except 8."); 167149bee38cSmrg if (XmbTextListToTextProperty(display, (char **) &value, 1, 1672fc89c0fbSmrg XStdICCTextStyle, &textprop) != Success) { 1673fc89c0fbSmrg fprintf(stderr, "cannot convert %s argument to STRING or COMPOUND_TEXT.\n", propname); 1674fc89c0fbSmrg return; 1675fc89c0fbSmrg } 1676fc89c0fbSmrg type = textprop.encoding; 1677fc89c0fbSmrg data = textprop.value; 1678fc89c0fbSmrg nelements = textprop.nitems; 1679fc89c0fbSmrg break; 1680fc89c0fbSmrg } 1681fc89c0fbSmrg case 'x': 1682fc89c0fbSmrg case 'c': { 1683fc89c0fbSmrg static unsigned char data8[MAXELEMENTS]; 1684fc89c0fbSmrg static unsigned short data16[MAXELEMENTS]; 1685fc89c0fbSmrg static unsigned long data32[MAXELEMENTS]; 1686fc89c0fbSmrg unsigned long intvalue; 1687fc89c0fbSmrg char * value2 = strdup(value); 1688fc89c0fbSmrg char * tmp = strtok(value2,","); 1689fc89c0fbSmrg nelements = 1; 1690fc89c0fbSmrg intvalue = strtoul(tmp, NULL, 0); 1691fc89c0fbSmrg switch(size) { 1692fc89c0fbSmrg case 8: 1693576bbdfcSmrg data8[0] = intvalue; data = (const unsigned char *) data8; break; 1694fc89c0fbSmrg case 16: 1695576bbdfcSmrg data16[0] = intvalue; data = (const unsigned char *) data16; break; 1696fc89c0fbSmrg case 32: 1697576bbdfcSmrg data32[0] = intvalue; data = (const unsigned char *) data32; break; 1698fc89c0fbSmrg } 1699fc89c0fbSmrg tmp = strtok(NULL,","); 1700fc89c0fbSmrg while(tmp != NULL){ 1701fc89c0fbSmrg intvalue = strtoul(tmp, NULL,0); 1702fc89c0fbSmrg switch(size) { 1703fc89c0fbSmrg case 8: 1704fc89c0fbSmrg data8[nelements] = intvalue; break; 1705fc89c0fbSmrg case 16: 1706fc89c0fbSmrg data16[nelements] = intvalue; break; 1707fc89c0fbSmrg case 32: 1708fc89c0fbSmrg data32[nelements] = intvalue; break; 1709fc89c0fbSmrg } 1710fc89c0fbSmrg nelements++; 1711fc89c0fbSmrg if(nelements == MAXELEMENTS){ 1712fc89c0fbSmrg fprintf(stderr, "Maximum number of elements reached (%d). List truncated.\n",MAXELEMENTS); 1713fc89c0fbSmrg break; 1714fc89c0fbSmrg } 1715fc89c0fbSmrg tmp = strtok(NULL,","); 1716fc89c0fbSmrg } 1717fc89c0fbSmrg 1718fc89c0fbSmrg type = XA_CARDINAL; 1719fc89c0fbSmrg free(value2); 1720fc89c0fbSmrg break; 1721fc89c0fbSmrg } 1722fc89c0fbSmrg case 'i': { 1723fc89c0fbSmrg static unsigned char data8[MAXELEMENTS]; 1724fc89c0fbSmrg static unsigned short data16[MAXELEMENTS]; 1725fc89c0fbSmrg static unsigned long data32[MAXELEMENTS]; 1726fc89c0fbSmrg unsigned long intvalue; 1727fc89c0fbSmrg char * value2 = strdup(value); 1728fc89c0fbSmrg char * tmp = strtok(value2,","); 1729fc89c0fbSmrg nelements = 1; 1730fc89c0fbSmrg intvalue = strtoul(tmp, NULL, 0); 1731fc89c0fbSmrg switch(size) { 1732fc89c0fbSmrg case 8: 1733576bbdfcSmrg data8[0] = intvalue; data = (const unsigned char *) data8; break; 1734fc89c0fbSmrg case 16: 1735576bbdfcSmrg data16[0] = intvalue; data = (const unsigned char *) data16; break; 1736fc89c0fbSmrg case 32: 1737576bbdfcSmrg data32[0] = intvalue; data = (const unsigned char *) data32; break; 1738fc89c0fbSmrg } 1739fc89c0fbSmrg tmp = strtok(NULL,","); 1740fc89c0fbSmrg while(tmp != NULL){ 1741fc89c0fbSmrg intvalue = strtoul(tmp, NULL,0); 1742fc89c0fbSmrg switch(size) { 1743fc89c0fbSmrg case 8: 1744fc89c0fbSmrg data8[nelements] = intvalue; break; 1745fc89c0fbSmrg case 16: 1746fc89c0fbSmrg data16[nelements] = intvalue; break; 1747fc89c0fbSmrg case 32: 1748fc89c0fbSmrg data32[nelements] = intvalue; break; 1749fc89c0fbSmrg } 1750fc89c0fbSmrg nelements++; 1751fc89c0fbSmrg if(nelements == MAXELEMENTS){ 1752fc89c0fbSmrg fprintf(stderr, "Maximum number of elements reached (%d). List truncated.\n",MAXELEMENTS); 1753fc89c0fbSmrg break; 1754fc89c0fbSmrg } 1755fc89c0fbSmrg tmp = strtok(NULL,","); 1756fc89c0fbSmrg } 1757fc89c0fbSmrg 1758fc89c0fbSmrg type = XA_INTEGER; 1759fc89c0fbSmrg free(value2); 1760fc89c0fbSmrg break; 1761fc89c0fbSmrg } 1762fc89c0fbSmrg case 'b': { 1763fc89c0fbSmrg unsigned long boolvalue; 1764fc89c0fbSmrg static unsigned char data8; 1765fc89c0fbSmrg static unsigned short data16; 1766fc89c0fbSmrg static unsigned long data32; 1767fc89c0fbSmrg if (!strcmp(value, "True")) 1768fc89c0fbSmrg boolvalue = 1; 1769fc89c0fbSmrg else if (!strcmp(value, "False")) 1770fc89c0fbSmrg boolvalue = 0; 1771fc89c0fbSmrg else { 1772fc89c0fbSmrg fprintf(stderr, "cannot convert %s argument to Bool\n", propname); 1773fc89c0fbSmrg return; 1774fc89c0fbSmrg } 1775fc89c0fbSmrg type = XA_INTEGER; 1776fc89c0fbSmrg switch (size) { 1777fc89c0fbSmrg case 8: 1778576bbdfcSmrg data8 = boolvalue; data = (const unsigned char *) &data8; break; 1779fc89c0fbSmrg case 16: 1780576bbdfcSmrg data16 = boolvalue; data = (const unsigned char *) &data16; break; 1781fc89c0fbSmrg case 32: default: 1782576bbdfcSmrg data32 = boolvalue; data = (const unsigned char *) &data32; break; 1783fc89c0fbSmrg } 1784fc89c0fbSmrg nelements = 1; 1785fc89c0fbSmrg break; 1786fc89c0fbSmrg } 1787fc89c0fbSmrg case 'a': { 1788fc89c0fbSmrg static Atom avalue; 1789fc89c0fbSmrg avalue = Parse_Atom(value, False); 1790fc89c0fbSmrg type = XA_ATOM; 1791576bbdfcSmrg data = (const unsigned char *) &avalue; 1792fc89c0fbSmrg nelements = 1; 1793fc89c0fbSmrg break; 1794fc89c0fbSmrg } 1795fc89c0fbSmrg case 'm': 1796fc89c0fbSmrg /* NYI */ 1797fc89c0fbSmrg default: 1798fc89c0fbSmrg Fatal_Error("bad format character: %c", format_char); 1799fc89c0fbSmrg } 1800fc89c0fbSmrg 180149bee38cSmrg XChangeProperty(display, target_win, atom, type, size, PropModeReplace, 1802fc89c0fbSmrg data, nelements); 1803fc89c0fbSmrg} 1804fc89c0fbSmrg 1805fc89c0fbSmrg/* 1806fc89c0fbSmrg * 1807fc89c0fbSmrg * Routines for parsing command line: 1808fc89c0fbSmrg * 1809fc89c0fbSmrg */ 1810fc89c0fbSmrg 181149bee38cSmrgstatic void 1812f9c28e31Smrgprint_help (void) 1813fc89c0fbSmrg{ 181481676fe2Smrg static const char *help_message = 1815fc89c0fbSmrg"where options include:\n" 1816f9c28e31Smrg" -help print out a summary of command line options\n" 1817fc89c0fbSmrg" -grammar print out full grammar for command line\n" 1818fc89c0fbSmrg" -display host:dpy the X server to contact\n" 1819fc89c0fbSmrg" -id id resource id of window to examine\n" 1820fc89c0fbSmrg" -name name name of window to examine\n" 1821fc89c0fbSmrg" -font name name of font to examine\n" 1822fc89c0fbSmrg" -remove propname remove a property\n" 1823fc89c0fbSmrg" -set propname value set a property to a given value\n" 1824fc89c0fbSmrg" -root examine the root window\n" 1825fc89c0fbSmrg" -len n display at most n bytes of any property\n" 1826fc89c0fbSmrg" -notype do not display the type field\n" 1827fc89c0fbSmrg" -fs filename where to look for formats for properties\n" 1828fc89c0fbSmrg" -frame don't ignore window manager frames\n" 1829fc89c0fbSmrg" -f propname format [dformat] formats to use for property of given name\n" 183081676fe2Smrg" -spy examine window properties forever\n" 183181676fe2Smrg" -version print program version\n"; 1832fc89c0fbSmrg 1833fc89c0fbSmrg 1834fc89c0fbSmrg fflush (stdout); 183581676fe2Smrg 1836fc89c0fbSmrg fprintf (stderr, 1837fc89c0fbSmrg "usage: %s [-options ...] [[format [dformat]] atom] ...\n\n", 1838fc89c0fbSmrg program_name); 1839fc89c0fbSmrg fprintf (stderr, "%s\n", help_message); 1840f9c28e31Smrg} 1841f9c28e31Smrg 184249bee38cSmrgstatic inline void _X_NORETURN _X_COLD 184349bee38cSmrghelp (void) 184449bee38cSmrg{ 1845f9c28e31Smrg print_help(); 1846f9c28e31Smrg exit(0); 1847f9c28e31Smrg} 1848f9c28e31Smrg 184949bee38cSmrgvoid _X_NORETURN _X_COLD 1850f9c28e31Smrgusage (const char *errmsg) 1851f9c28e31Smrg{ 1852f9c28e31Smrg if (errmsg != NULL) 1853f9c28e31Smrg fprintf (stderr, "%s: %s\n\n", program_name, errmsg); 1854f9c28e31Smrg 1855f9c28e31Smrg print_help(); 1856fc89c0fbSmrg exit (1); 1857fc89c0fbSmrg} 1858fc89c0fbSmrg 185949bee38cSmrgstatic void _X_NORETURN _X_COLD 1860fc89c0fbSmrggrammar (void) 1861fc89c0fbSmrg{ 1862fc89c0fbSmrg printf ("Grammar for xprop:\n\n"); 1863fc89c0fbSmrg printf("\t%s [<disp>] [<select option>] <option>* <mapping>* <spec>*", 1864fc89c0fbSmrg program_name); 1865fc89c0fbSmrg printf("\n\n\tdisp ::= -display host:dpy\ 1866fc89c0fbSmrg\n\tselect option ::= -root | -id <id> | -font <font> | -name <name>\ 1867fc89c0fbSmrg\n\toption ::= -len <n> | -notype | -spy | {-formats|-fs} <format file>\ 1868fc89c0fbSmrg\n\tmapping ::= {-f|-format} <atom> <format> [<dformat>]\ 1869fc89c0fbSmrg\n\t | -remove <propname>\ 1870fc89c0fbSmrg\n\t | -set <propname> <value>\ 1871fc89c0fbSmrg\n\tspec ::= [<format> [<dformat>]] <atom>\ 1872fc89c0fbSmrg\n\tformat ::= {0|8|16|32}{a|b|c|i|m|s|t|x}*\ 1873fc89c0fbSmrg\n\tdformat ::= <unit><unit>* (can't start with a letter or '-')\ 1874fc89c0fbSmrg\n\tunit ::= ?<exp>(<unit>*) | $<n> | <display char>\ 1875fc89c0fbSmrg\n\texp ::= <term> | <term>=<exp> | !<exp>\ 1876fc89c0fbSmrg\n\tterm ::= <n> | $<n> | m<n>\ 1877fc89c0fbSmrg\n\tdisplay char ::= <normal char> | \\<non digit char> | \\<octal number>\ 1878fc89c0fbSmrg\n\tnormal char ::= <any char except a digit, $, ?, \\, or )>\ 1879fc89c0fbSmrg\n\n"); 1880fc89c0fbSmrg exit(0); 1881fc89c0fbSmrg} 1882fc89c0fbSmrg 1883fc89c0fbSmrgstatic void 1884fc89c0fbSmrgParse_Format_Mapping (int *argc, char ***argv) 1885fc89c0fbSmrg{ 1886fc89c0fbSmrg#define ARGC (*argc) 1887fc89c0fbSmrg#define ARGV (*argv) 1888fc89c0fbSmrg#define OPTION ARGV[0] 188949bee38cSmrg#define NXTOPT if (++ARGV, --ARGC==0) usage("insufficient arguments for -format") 1890fc89c0fbSmrg char *type_name, *format, *dformat; 1891fc89c0fbSmrg 1892fc89c0fbSmrg NXTOPT; type_name = OPTION; 1893fc89c0fbSmrg 1894fc89c0fbSmrg NXTOPT; format = OPTION; 1895fc89c0fbSmrg if (!Is_A_Format(format)) 1896fc89c0fbSmrg Fatal_Error("Bad format: %s.", format); 1897fc89c0fbSmrg 1898fc89c0fbSmrg dformat = NULL; 1899fc89c0fbSmrg if (ARGC>1 && Is_A_DFormat(ARGV[1])) { 1900fc89c0fbSmrg ARGV++; ARGC--; dformat = OPTION; 1901fc89c0fbSmrg } 1902fc89c0fbSmrg 1903fc89c0fbSmrg Add_Mapping(Parse_Atom(type_name, False), format, dformat); 1904fc89c0fbSmrg} 1905fc89c0fbSmrg 1906fc89c0fbSmrg/* 1907fc89c0fbSmrg * 1908fc89c0fbSmrg * The Main Program: 1909fc89c0fbSmrg * 1910fc89c0fbSmrg */ 1911fc89c0fbSmrg 1912fc89c0fbSmrgstatic int spy = 0; 1913fc89c0fbSmrg 191449bee38cSmrgstatic int (*old_error_handler)(Display *display, XErrorEvent *ev); 191591ec45ceSmrg 191649bee38cSmrgstatic int spy_error_handler(Display *display, XErrorEvent *ev) 191791ec45ceSmrg{ 191891ec45ceSmrg if (ev->error_code == BadWindow || ev->error_code == BadMatch) { 191991ec45ceSmrg /* Window was destroyed */ 192091ec45ceSmrg puts(""); 192191ec45ceSmrg exit(0); 192291ec45ceSmrg } 192391ec45ceSmrg 192491ec45ceSmrg if (old_error_handler) 192549bee38cSmrg return old_error_handler(display, ev); 192691ec45ceSmrg 192791ec45ceSmrg return 0; 192891ec45ceSmrg} 192991ec45ceSmrg 1930fc89c0fbSmrgint 1931fc89c0fbSmrgmain (int argc, char **argv) 1932fc89c0fbSmrg{ 1933fc89c0fbSmrg FILE *stream; 1934fc89c0fbSmrg char *name; 1935fc89c0fbSmrg thunk *props; 1936fc89c0fbSmrg thunk *remove_props = NULL; 1937fc89c0fbSmrg thunk *set_props = NULL; 1938fc89c0fbSmrg Bool frame_only = False; 1939fc89c0fbSmrg int n; 1940fc89c0fbSmrg char **nargv; 1941fc89c0fbSmrg 1942f9c28e31Smrg#ifdef TIOCGWINSZ 1943f9c28e31Smrg struct winsize ws; 1944f9c28e31Smrg ws.ws_col = 0; 1945f9c28e31Smrg if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0) 1946f9c28e31Smrg term_width = ws.ws_col; 1947f9c28e31Smrg#endif 1948f9c28e31Smrg 1949fc89c0fbSmrg INIT_NAME; 1950fc89c0fbSmrg 1951fc89c0fbSmrg /* Set locale for XmbTextProptertyToTextList and iswprint(). */ 1952fc89c0fbSmrg setlocale(LC_CTYPE, ""); 1953fc89c0fbSmrg 1954fc89c0fbSmrg /* Handle display name, opening the display */ 1955fc89c0fbSmrg Setup_Display_And_Screen(&argc, argv); 1956fc89c0fbSmrg 1957fc89c0fbSmrg /* Handle selecting the window to display properties for */ 1958fc89c0fbSmrg target_win = Select_Window_Args(&argc, argv); 1959fc89c0fbSmrg 1960fc89c0fbSmrg /* Set up default atom to format, dformat mapping */ 1961fc89c0fbSmrg XpropMode = XpropWindowProperties; 1962fc89c0fbSmrg for (n = argc, nargv = argv; n; nargv++, n--) 1963fc89c0fbSmrg if (! strcmp(nargv[0], "-font")) { 1964fc89c0fbSmrg XpropMode = XpropFontProperties; 1965fc89c0fbSmrg break; 1966fc89c0fbSmrg } 1967fc89c0fbSmrg Setup_Mapping(); 1968fc89c0fbSmrg if ((name = getenv("XPROPFORMATS"))) { 1969fc89c0fbSmrg if (!(stream = fopen(name, "r"))) 1970fc89c0fbSmrg Fatal_Error("unable to open file %s for reading.", name); 1971fc89c0fbSmrg Read_Mappings(stream); 1972fc89c0fbSmrg fclose(stream); 1973fc89c0fbSmrg } 1974fc89c0fbSmrg 1975fc89c0fbSmrg /* Handle '-' options to setup xprop, select window to work on */ 1976fc89c0fbSmrg while (argv++, --argc>0 && **argv == '-') { 1977fc89c0fbSmrg if (!strcmp(argv[0], "-")) 1978fc89c0fbSmrg continue; 1979f9c28e31Smrg if (!strcmp(argv[0], "-help")) { 1980f9c28e31Smrg help (); 1981f9c28e31Smrg /* NOTREACHED */ 1982f9c28e31Smrg } 1983fc89c0fbSmrg if (!strcmp(argv[0], "-grammar")) { 1984fc89c0fbSmrg grammar (); 1985fc89c0fbSmrg /* NOTREACHED */ 1986fc89c0fbSmrg } 1987fc89c0fbSmrg if (!strcmp(argv[0], "-notype")) { 1988fc89c0fbSmrg notype = 1; 1989fc89c0fbSmrg continue; 1990fc89c0fbSmrg } 1991fc89c0fbSmrg if (!strcmp(argv[0], "-spy")) { 1992fc89c0fbSmrg spy = 1; 1993fc89c0fbSmrg continue; 1994fc89c0fbSmrg } 1995fc89c0fbSmrg if (!strcmp(argv[0], "-len")) { 199681676fe2Smrg if (++argv, --argc == 0) usage("-len requires an argument"); 1997fc89c0fbSmrg max_len = atoi(argv[0]); 1998fc89c0fbSmrg continue; 1999fc89c0fbSmrg } 2000fc89c0fbSmrg if (!strcmp(argv[0], "-formats") || !strcmp(argv[0], "-fs")) { 200181676fe2Smrg if (++argv, --argc == 0) usage("-fs requires an argument"); 2002fc89c0fbSmrg if (!(stream = fopen(argv[0], "r"))) 2003fc89c0fbSmrg Fatal_Error("unable to open file %s for reading.", argv[0]); 2004fc89c0fbSmrg Read_Mappings(stream); 2005fc89c0fbSmrg fclose(stream); 2006fc89c0fbSmrg continue; 2007fc89c0fbSmrg } 2008fc89c0fbSmrg if (!strcmp(argv[0], "-font")) { 200981676fe2Smrg if (++argv, --argc == 0) usage("-font requires an argument"); 2010fc89c0fbSmrg font = Open_Font(argv[0]); 201149bee38cSmrg target_win = (Window) -1; 2012fc89c0fbSmrg continue; 2013fc89c0fbSmrg } 2014fc89c0fbSmrg if (!strcmp(argv[0], "-remove")) { 2015f4a95042Smrg thunk t = {0}; 201681676fe2Smrg if (++argv, --argc == 0) usage("-remove requires an argument"); 2017fc89c0fbSmrg t.propname = argv[0]; 2018fc89c0fbSmrg if (remove_props == NULL) remove_props = Create_Thunk_List(); 2019fc89c0fbSmrg remove_props = Add_Thunk(remove_props, t); 2020fc89c0fbSmrg continue; 2021fc89c0fbSmrg } 2022fc89c0fbSmrg if (!strcmp(argv[0], "-set")) { 2023f4a95042Smrg thunk t = {0}; 202449bee38cSmrg if (argc < 3) usage("insufficient arguments for -set"); 2025fc89c0fbSmrg t.propname = argv[1]; 2026fc89c0fbSmrg t.extra_value = argv[2]; 2027fc89c0fbSmrg argv += 3; argc -= 3; 2028fc89c0fbSmrg if (set_props == NULL) set_props = Create_Thunk_List(); 2029fc89c0fbSmrg set_props = Add_Thunk(set_props, t); 2030fc89c0fbSmrg continue; 2031fc89c0fbSmrg } 2032fc89c0fbSmrg if (!strcmp(argv[0], "-frame")) { 2033fc89c0fbSmrg frame_only = True; 2034fc89c0fbSmrg continue; 2035fc89c0fbSmrg } 2036fc89c0fbSmrg if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "-format")) { 2037fc89c0fbSmrg Parse_Format_Mapping(&argc, &argv); 2038fc89c0fbSmrg continue; 2039fc89c0fbSmrg } 204081676fe2Smrg if (!strcmp(argv[0], "-version")) { 204181676fe2Smrg puts(PACKAGE_STRING); 204281676fe2Smrg exit(0); 204381676fe2Smrg } 204481676fe2Smrg fprintf (stderr, "%s: unrecognized argument %s\n\n", 204581676fe2Smrg program_name, argv[0]); 204681676fe2Smrg usage(NULL); 2047fc89c0fbSmrg } 2048fc89c0fbSmrg 204981676fe2Smrg if ((remove_props != NULL || set_props != NULL) && argc > 0) { 205081676fe2Smrg fprintf (stderr, "%s: unrecognized argument %s\n\n", 205181676fe2Smrg program_name, argv[0]); 205281676fe2Smrg usage(NULL); 205381676fe2Smrg } 2054fc89c0fbSmrg 205591ec45ceSmrg if (target_win == None) 205691ec45ceSmrg target_win = Select_Window(dpy, !frame_only); 2057fc89c0fbSmrg 2058fc89c0fbSmrg if (remove_props != NULL) { 2059fc89c0fbSmrg int count; 2060fc89c0fbSmrg 206149bee38cSmrg if (target_win == (Window) -1) 2062fc89c0fbSmrg Fatal_Error("-remove works only on windows, not fonts"); 2063fc89c0fbSmrg 2064fc89c0fbSmrg count = remove_props->thunk_count; 2065fc89c0fbSmrg for (; count > 0; remove_props++, count--) 2066fc89c0fbSmrg Remove_Property (dpy, target_win, remove_props->propname); 2067fc89c0fbSmrg } 2068fc89c0fbSmrg 2069fc89c0fbSmrg if (set_props != NULL) { 2070fc89c0fbSmrg int count; 2071fc89c0fbSmrg 207249bee38cSmrg if (target_win == (Window) -1) 2073fc89c0fbSmrg Fatal_Error("-set works only on windows, not fonts"); 2074fc89c0fbSmrg 2075fc89c0fbSmrg count = set_props->thunk_count; 2076fc89c0fbSmrg for (; count > 0; set_props++, count--) 2077fc89c0fbSmrg Set_Property (dpy, target_win, set_props->propname, 2078fc89c0fbSmrg set_props->extra_value); 2079fc89c0fbSmrg } 2080fc89c0fbSmrg 2081fc89c0fbSmrg if (remove_props != NULL || set_props != NULL) { 2082fc89c0fbSmrg XCloseDisplay (dpy); 2083fc89c0fbSmrg exit (0); 2084fc89c0fbSmrg } 2085fc89c0fbSmrg 2086fc89c0fbSmrg props = Handle_Prop_Requests(argc, argv); 2087fc89c0fbSmrg 208849bee38cSmrg if (spy && target_win != (Window) -1) { 2089fc89c0fbSmrg XEvent event; 2090fc89c0fbSmrg const char *format, *dformat; 2091fc89c0fbSmrg 209291ec45ceSmrg XSelectInput(dpy, target_win, PropertyChangeMask | StructureNotifyMask); 209391ec45ceSmrg old_error_handler = XSetErrorHandler(spy_error_handler); 2094fc89c0fbSmrg for (;;) { 209591ec45ceSmrg fflush(stdout); 2096fc89c0fbSmrg XNextEvent(dpy, &event); 209791ec45ceSmrg if (event.type == DestroyNotify) 209891ec45ceSmrg break; 209991ec45ceSmrg if (event.type != PropertyNotify) 210091ec45ceSmrg continue; 2101fc89c0fbSmrg format = dformat = NULL; 2102fc89c0fbSmrg if (props) { 2103fc89c0fbSmrg int i; 2104fc89c0fbSmrg for (i = 0; i < props->thunk_count; i++) 210549bee38cSmrg if (props[i].value == (long) event.xproperty.atom) 2106fc89c0fbSmrg break; 2107fc89c0fbSmrg if (i >= props->thunk_count) 2108fc89c0fbSmrg continue; 2109fc89c0fbSmrg format = props[i].format; 2110fc89c0fbSmrg dformat = props[i].dformat; 2111fc89c0fbSmrg } 2112fc89c0fbSmrg Show_Prop(format, dformat, Format_Atom(event.xproperty.atom)); 2113fc89c0fbSmrg } 2114fc89c0fbSmrg } 2115fc89c0fbSmrg exit (0); 2116fc89c0fbSmrg} 2117