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