xfd.c revision 31e5d586
1/* 2 * 3 * 4Copyright 1989, 1998 The Open Group 5 6Permission to use, copy, modify, distribute, and sell this software and its 7documentation for any purpose is hereby granted without fee, provided that 8the above copyright notice appear in all copies and that both that 9copyright notice and this permission notice appear in supporting 10documentation. 11 12The above copyright notice and this permission notice shall be included in 13all copies or substantial portions of the Software. 14 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall not be 23used in advertising or otherwise to promote the sale, use or other dealings 24in this Software without prior written authorization from The Open Group. 25 * * 26 * Author: Jim Fulton, MIT X Consortium 27 */ 28 29#ifdef HAVE_CONFIG_H 30# include "config.h" 31#endif 32 33#include <X11/Xfuncproto.h> 34#include <X11/Intrinsic.h> 35#include <X11/StringDefs.h> 36#include <X11/Xos.h> 37#include <X11/Xatom.h> 38#include <X11/Shell.h> 39#include <X11/Xaw/Cardinals.h> 40#include <X11/Xaw/Paned.h> 41#include <X11/Xaw/Box.h> 42#include <X11/Xaw/Form.h> 43#include <X11/Xaw/Command.h> 44#include <stdio.h> 45#include <stdlib.h> 46#ifdef USE_GETTEXT 47# include <X11/Xlocale.h> 48# include <libintl.h> 49#else 50# define gettext(a) (a) 51#endif 52#include "grid.h" 53#ifdef XRENDER 54#include <X11/Xft/Xft.h> 55#include <X11/extensions/Xrender.h> 56#endif 57 58static char *ProgramName; 59 60static XrmOptionDescRec xfd_options[] = { 61{"-fn", "*grid.font", XrmoptionSepArg, (caddr_t) NULL }, 62#ifdef XRENDER 63{"-fa", "*grid.face", XrmoptionSepArg, (caddr_t) NULL }, 64#endif 65{"-start", "*startChar", XrmoptionSepArg, (caddr_t) NULL }, 66{"-box", "*grid.boxChars", XrmoptionNoArg, (caddr_t) "on" }, 67{"-bc", "*grid.boxColor", XrmoptionSepArg, (caddr_t) NULL }, 68{"-center", "*grid.centerChars", XrmoptionNoArg, (caddr_t) "on" }, 69{"-rows", "*grid.cellRows", XrmoptionSepArg, (caddr_t) NULL }, 70{"-columns", "*grid.cellColumns", XrmoptionSepArg, (caddr_t) NULL }, 71}; 72 73static void usage(void) _X_NORETURN _X_COLD; 74static void SelectChar(Widget w, XtPointer closure, XtPointer data); 75static void do_quit(Widget w, XEvent *event, String *params, 76 Cardinal *num_params) _X_NORETURN; 77static void change_page(int page); 78static void set_button_state(void); 79static void do_prev(Widget w, XEvent *event, String *params, 80 Cardinal *num_params); 81static void do_next(Widget w, XEvent *event, String *params, 82 Cardinal *num_params); 83static void do_prev16(Widget w, XEvent *event, String *params, 84 Cardinal *num_params); 85static void do_next16(Widget w, XEvent *event, String *params, 86 Cardinal *num_params); 87static char *get_font_name(Display *dpy, XFontStruct *fs); 88static void CatchFontConversionWarning(String name, String type, String class, 89 String defaultp, String *params, 90 Cardinal *np); 91 92static XtActionsRec xfd_actions[] = { 93 { "Quit", do_quit }, 94 { "Prev16", do_prev16 }, 95 { "Prev", do_prev }, 96 { "Next", do_next }, 97 { "Next16", do_next16 }, 98}; 99 100static Atom wm_delete_window; 101 102static Widget quitButton, prev16Button, prevButton, nextButton, next16Button; 103 104 105#define DEF_SELECT_FORMAT "character 0x%04x%02x (%u,%u) (%#o,%#o)" 106#define DEF_METRICS_FORMAT "width %d; left %d, right %d; ascent %d, descent %d (font %d, %d)" 107#define DEF_RANGE_FORMAT "range: 0x%04x%02x (%u,%u) thru 0x%04x%02x (%u,%u)" 108#define DEF_START_FORMAT "upper left: 0x%06x (%d,%d)" 109#define DEF_NOCHAR_FORMAT "no such character 0x%04x%02x (%u,%u) (%#o,%#o)" 110 111static struct _xfd_resources { 112 char *select_format; 113 char *metrics_format; 114 char *range_format; 115 char *start_format; 116 char *nochar_format; 117} xfd_resources; 118 119#define Offset(field) XtOffsetOf(struct _xfd_resources, field) 120 121static XtResource Resources[] = { 122 { "selectFormat", "SelectFormat", XtRString, sizeof(char *), 123 Offset(select_format), XtRString, DEF_SELECT_FORMAT }, 124 { "metricsFormat", "MetricsFormat", XtRString, sizeof(char *), 125 Offset(metrics_format), XtRString, DEF_METRICS_FORMAT }, 126 { "rangeFormat", "RangeFormat", XtRString, sizeof(char *), 127 Offset(range_format), XtRString, DEF_RANGE_FORMAT }, 128 { "startFormat", "StartFormat", XtRString, sizeof(char *), 129 Offset(start_format), XtRString, DEF_START_FORMAT }, 130 { "nocharFormat", "NocharFormat", XtRString, sizeof(char *), 131 Offset(nochar_format), XtRString, DEF_NOCHAR_FORMAT }, 132}; 133 134#undef Offset 135 136static void 137usage(void) 138{ 139 fprintf (stderr, gettext("usage: %s [-options ...] "), ProgramName); 140 fprintf (stderr, "-fn "); 141 fprintf (stderr, gettext("font\n\n")); 142#ifdef XRENDER 143 fprintf (stderr, gettext(" %s [-options ...] "), ProgramName); 144 fprintf (stderr, "-fa "); 145 fprintf (stderr, gettext("font\n\n")); 146#endif 147 fprintf (stderr, gettext("where options include:\n")); 148 fprintf (stderr, " -display "); 149 fprintf (stderr, gettext("display X server to contact\n")); 150 fprintf (stderr, " -geometry "); 151 fprintf (stderr, gettext("geometry size and location of window\n")); 152 fprintf (stderr, " -bc "); 153 fprintf (stderr, gettext("color color for ImageText boxes\n")); 154 fprintf (stderr, " -start "); 155 fprintf (stderr, gettext("number first character to show\n")); 156 fprintf (stderr, " -box "); 157 fprintf (stderr, gettext("show a box around each character\n")); 158 fprintf (stderr, " -center "); 159 fprintf (stderr, gettext("center each character inside its grid\n")); 160 fprintf (stderr, " -rows "); 161 fprintf (stderr, gettext("number number of rows in grid\n")); 162 fprintf (stderr, " -columns "); 163 fprintf (stderr, gettext("number number of columns in grid\n")); 164 exit (1); 165} 166 167 168static Widget selectLabel, metricsLabel, rangeLabel, startLabel, fontGrid; 169 170static Boolean fontConversionFailed = False; 171static XtErrorMsgHandler oldWarningHandler; 172 173int 174main(int argc, char *argv[]) 175{ 176 XtAppContext xtcontext; 177 Widget toplevel, pane, toplabel, box, form; 178 char buf[256]; 179 Arg av[10]; 180 Cardinal i; 181 static XtCallbackRec cb[2] = { { SelectChar, NULL }, { NULL, NULL } }; 182 XFontStruct *fs; 183#ifdef XRENDER 184 XftFont *xft; 185#endif 186 char *fontname; 187 long minn, maxn; 188 189 XtSetLanguageProc(NULL, NULL, NULL); 190 191 ProgramName = argv[0]; 192 193 toplevel = XtAppInitialize (&xtcontext, "Xfd", 194 xfd_options, XtNumber(xfd_options), 195 &argc, argv, NULL, NULL, 0); 196 197#ifdef USE_GETTEXT 198 { 199 const char *domaindir; 200 201 textdomain("xfd"); 202 203 /* mainly for debugging */ 204 if ((domaindir = getenv ("TEXTDOMAINDIR")) == NULL) { 205 domaindir = LOCALEDIR; 206 } 207 bindtextdomain ("xfd", domaindir); 208 } 209#endif 210 211 Resources[0].default_addr = gettext(DEF_SELECT_FORMAT); 212 Resources[1].default_addr = gettext(DEF_METRICS_FORMAT); 213 Resources[2].default_addr = gettext(DEF_RANGE_FORMAT); 214 Resources[3].default_addr = gettext(DEF_START_FORMAT); 215 Resources[4].default_addr = gettext(DEF_NOCHAR_FORMAT); 216 217 if (argc != 1) usage (); 218 XtAppAddActions (xtcontext, xfd_actions, XtNumber (xfd_actions)); 219 XtOverrideTranslations 220 (toplevel, XtParseTranslationTable ("<Message>WM_PROTOCOLS: Quit()")); 221 222 XtGetApplicationResources (toplevel, (XtPointer) &xfd_resources, Resources, 223 XtNumber (Resources), NULL, ZERO); 224 225 226 /* pane wrapping everything */ 227 pane = XtCreateManagedWidget ("pane", panedWidgetClass, toplevel, 228 NULL, ZERO); 229 230 /* font name */ 231 toplabel = XtCreateManagedWidget ("fontname", labelWidgetClass, pane, 232 NULL, ZERO); 233 234 /* button box */ 235 box = XtCreateManagedWidget ("box", boxWidgetClass, pane, NULL, ZERO); 236 quitButton = XtCreateManagedWidget ("quit", commandWidgetClass, box, 237 NULL, ZERO); 238 prev16Button = XtCreateManagedWidget ("prev16", commandWidgetClass, box, 239 NULL, ZERO); 240 prevButton = XtCreateManagedWidget ("prev", commandWidgetClass, box, 241 NULL, ZERO); 242 nextButton = XtCreateManagedWidget ("next", commandWidgetClass, box, 243 NULL, ZERO); 244 next16Button = XtCreateManagedWidget ("next16", commandWidgetClass, box, 245 NULL, ZERO); 246 247 248 /* and labels in which to put information */ 249 selectLabel = XtCreateManagedWidget ("select", labelWidgetClass, 250 pane, NULL, ZERO); 251 252 metricsLabel = XtCreateManagedWidget ("metrics", labelWidgetClass, 253 pane, NULL, ZERO); 254 255 rangeLabel = XtCreateManagedWidget ("range", labelWidgetClass, pane, 256 NULL, ZERO); 257 258 startLabel = XtCreateManagedWidget ("start", labelWidgetClass, pane, 259 NULL, ZERO); 260 261 /* form in which to draw */ 262 form = XtCreateManagedWidget ("form", formWidgetClass, pane, NULL, ZERO); 263 264 i = 0; 265 XtSetArg (av[i], XtNtop, XtChainTop); i++; 266 XtSetArg (av[i], XtNbottom, XtChainBottom); i++; 267 XtSetArg (av[i], XtNleft, XtChainLeft); i++; 268 XtSetArg (av[i], XtNright, XtChainRight); i++; 269 XtSetArg (av[i], XtNcallback, cb); i++; 270 271 oldWarningHandler = XtAppSetWarningMsgHandler(xtcontext, 272 CatchFontConversionWarning); 273 274 fontGrid = XtCreateManagedWidget ("grid", fontgridWidgetClass, form, 275 av, i); 276 277 XtAppSetWarningMsgHandler(xtcontext, oldWarningHandler); 278 279 /* set the label at the top to tell us which font this is */ 280#ifdef XRENDER 281 i = 0; 282 XtSetArg (av[i], XtNface, &xft); i++; 283 XtGetValues (fontGrid, av, i); 284 if (xft) 285 { 286 FcChar8 *family; 287 FcChar8 *style; 288 FcPattern *p; 289 double size; 290 family = (FcChar8 *) ""; 291 FcPatternGetString (xft->pattern, FC_FAMILY, 0, &family); 292 style = (FcChar8 *) ""; 293 FcPatternGetString (xft->pattern, FC_STYLE, 0, &style); 294 size = 0; 295 FcPatternGetDouble (xft->pattern, FC_SIZE, 0, &size); 296 p = FcPatternBuild (NULL, 297 FC_FAMILY, FcTypeString, family, 298 FC_STYLE, FcTypeString, style, 299 FC_SIZE, FcTypeDouble, size, 300 NULL); 301 fontname = (char *) FcNameUnparse (p); 302 FcPatternDestroy (p); 303 } 304 else 305#endif 306 { 307 i = 0; 308 XtSetArg (av[i], XtNfont, &fs); i++; 309 XtGetValues (fontGrid, av, i); 310 if (!fs || fontConversionFailed) { 311 fprintf (stderr, gettext("%s: no font to display\n"), ProgramName); 312 exit (1); 313 } 314 fontname = get_font_name (XtDisplay(toplevel), fs); 315 if (!fontname) fontname = gettext("unknown font!"); 316 } 317 i = 0; 318 XtSetArg (av[i], XtNlabel, fontname); i++; 319 XtSetValues (toplabel, av, i); 320 321 minn = GridFirstChar (fontGrid); 322 maxn = GridLastChar (fontGrid); 323 snprintf (buf, sizeof(buf), xfd_resources.range_format, 324 minn >> 8, minn & 0xff, 325 minn >> 8, minn & 0xff, 326 maxn >> 8, maxn & 0xff, 327 maxn >> 8, maxn & 0xff); 328 329 i = 0; 330 XtSetArg (av[i], XtNlabel, buf); i++; 331 XtSetValues (rangeLabel, av, i); 332 333 XtRealizeWidget (toplevel); 334 335 wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW", 336 False); 337 (void) XSetWMProtocols (XtDisplay(toplevel), XtWindow(toplevel), 338 &wm_delete_window, 1); 339 340 change_page (0); 341 XtAppMainLoop (xtcontext); 342 exit(0); 343} 344 345/*ARGSUSED*/ 346static void 347SelectChar(Widget w, XtPointer closure _X_UNUSED, XtPointer data) 348{ 349 FontGridCharRec *p = (FontGridCharRec *) data; 350 XFontStruct *fs = p->thefont; 351 long n = p->thechar; 352 int direction, fontascent, fontdescent; 353 XCharStruct metrics; 354 char buf[256]; 355 Arg arg; 356 Boolean has_char = 1; 357 358 XtSetArg (arg, XtNlabel, buf); 359 360 buf[0] = '\0'; 361#ifdef XRENDER 362 if (p->theface) 363 { 364 XftFont *xft = p->theface; 365 FcChar32 c = (FcChar32) n; 366 has_char = (Boolean) FcCharSetHasChar (xft->charset, n); 367 if (has_char) 368 { 369 XGlyphInfo extents; 370 XftTextExtents32 (XtDisplay (w), xft, &c, 1, &extents); 371 snprintf (buf, sizeof(buf), xfd_resources.metrics_format, 372 extents.xOff, - extents.x, 373 extents.xOff - extents.width + extents.x, 374 extents.y, extents.height - extents.y, 375 xft->ascent, xft->descent); 376 } 377 } 378 else 379#endif 380 { 381 if ((!fs->min_byte1 && !fs->max_byte1) ? 382 (n < fs->min_char_or_byte2 || n > fs->max_char_or_byte2) : 383 (n >> 8 < fs->min_byte1 || n >> 8 > fs->max_byte1 || 384 (n & 0xff) < fs->min_char_or_byte2 || 385 (n & 0xff) > fs->max_char_or_byte2)) 386 { 387 has_char = 0; 388 } 389 else 390 { 391 XChar2b char2b; 392 char2b.byte1 = p->thechar >> 8; 393 char2b.byte2 = p->thechar & 0xff; 394 XTextExtents16 (fs, &char2b, 1, &direction, &fontascent, &fontdescent, 395 &metrics); 396 snprintf (buf, sizeof(buf), xfd_resources.metrics_format, 397 metrics.width, metrics.lbearing, metrics.rbearing, 398 metrics.ascent, metrics.descent, fontascent, fontdescent); 399 } 400 } 401 XtSetValues (metricsLabel, &arg, ONE); 402 403 if (has_char) 404 { 405 snprintf (buf, sizeof(buf), xfd_resources.select_format, 406 n >> 8, n & 0xff, 407 n >> 8, n & 0xff, 408 n >> 8, n & 0xff); 409 } 410 else 411 { 412 snprintf (buf, sizeof(buf), xfd_resources.nochar_format, 413 n >> 8, n & 0xff, 414 n >> 8, n & 0xff, 415 n >> 8, n & 0xff); 416 } 417 XtSetValues (selectLabel, &arg, ONE); 418 419 return; 420} 421 422 423/*ARGSUSED*/ 424static void 425do_quit (Widget w _X_UNUSED, XEvent *event _X_UNUSED, 426 String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 427{ 428 exit (0); 429} 430 431static void 432change_page(int page) 433{ 434 long oldstart, newstart; 435 int ncols, nrows; 436 Arg arg; 437 438 arg.name = XtNstartChar; 439 GetFontGridCellDimensions (fontGrid, &oldstart, &ncols, &nrows); 440 441 if (page) { 442 long start = (oldstart + 443 ((long) ncols) * ((long) nrows) * ((long) page)); 444 445 arg.value = (XtArgVal) start; 446 XtSetValues (fontGrid, &arg, ONE); 447 } 448 449 /* find out what it got set to */ 450 arg.value = (XtArgVal) &newstart; 451 XtGetValues (fontGrid, &arg, ONE); 452 453 /* if not paging, then initialize it, else only do it actually changed */ 454 if (!page || newstart != oldstart) { 455 unsigned int row = (unsigned int) ((newstart >> 8)); 456 unsigned int col = (unsigned int) (newstart & 0xff); 457 char buf[256]; 458 459 XtSetArg (arg, XtNlabel, buf); 460 snprintf (buf, sizeof(buf), xfd_resources.start_format, 461 newstart, row, col); 462 XtSetValues (startLabel, &arg, ONE); 463 } 464 465 set_button_state (); 466 467 return; 468} 469 470 471static void 472set_button_state(void) 473{ 474 Bool prevvalid, nextvalid, prev16valid, next16valid; 475 Arg arg; 476 477 GetPrevNextStates (fontGrid, &prevvalid, &nextvalid, &prev16valid, &next16valid); 478 arg.name = XtNsensitive; 479 arg.value = (XtArgVal) (prevvalid ? TRUE : FALSE); 480 XtSetValues (prevButton, &arg, ONE); 481 arg.value = (XtArgVal) (nextvalid ? TRUE : FALSE); 482 XtSetValues (nextButton, &arg, ONE); 483 arg.name = XtNsensitive; 484 arg.value = (XtArgVal) (prev16valid ? TRUE : FALSE); 485 XtSetValues (prev16Button, &arg, ONE); 486 arg.value = (XtArgVal) (next16valid ? TRUE : FALSE); 487 XtSetValues (next16Button, &arg, ONE); 488} 489 490 491/* ARGSUSED */ 492static void 493do_prev16(Widget w _X_UNUSED, XEvent *event _X_UNUSED, 494 String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 495{ 496 change_page (-16); 497} 498 499 500static void 501do_prev(Widget w _X_UNUSED, XEvent *event _X_UNUSED, 502 String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 503{ 504 change_page (-1); 505} 506 507 508/* ARGSUSED */ 509static void 510do_next(Widget w _X_UNUSED, XEvent *event _X_UNUSED, 511 String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 512{ 513 change_page (1); 514} 515 516/* ARGSUSED */ 517static void 518do_next16(Widget w _X_UNUSED, XEvent *event _X_UNUSED, 519 String *params _X_UNUSED, Cardinal *num_params _X_UNUSED) 520{ 521 change_page (16); 522} 523 524 525static char * 526get_font_name(Display *dpy, XFontStruct *fs) 527{ 528 register XFontProp *fp; 529 register int i; 530 Atom fontatom = XInternAtom (dpy, "FONT", False); 531 532 for (i = 0, fp = fs->properties; i < fs->n_properties; i++, fp++) { 533 if (fp->name == fontatom) { 534 return (XGetAtomName (dpy, fp->card32)); 535 } 536 } 537 return NULL; 538} 539 540 541static void 542CatchFontConversionWarning(String name, String type, String class, 543 String defaultp, String *params, Cardinal *np) 544{ 545 if (np && *np > 1 && 546 strcmp(name, "conversionError") == 0 && 547 strcmp(type, "string") == 0 && 548 strcmp(class, "XtToolkitError") == 0 && 549 strcmp(params[1], "FontStruct") == 0) fontConversionFailed = True; 550 551 (*oldWarningHandler)(name, type, class, defaultp, params, np); 552} 553