xfd.c revision 1afad795
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 const char *domaindir; 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 textdomain("xfd"); 199 200 /* mainly for debugging */ 201 if ((domaindir = getenv ("TEXTDOMAINDIR")) == NULL) { 202 domaindir = LOCALEDIR; 203 } 204 bindtextdomain ("xfd", domaindir); 205#endif 206 207 Resources[0].default_addr = gettext(DEF_SELECT_FORMAT); 208 Resources[1].default_addr = gettext(DEF_METRICS_FORMAT); 209 Resources[2].default_addr = gettext(DEF_RANGE_FORMAT); 210 Resources[3].default_addr = gettext(DEF_START_FORMAT); 211 Resources[4].default_addr = gettext(DEF_NOCHAR_FORMAT); 212 213 if (argc != 1) usage (); 214 XtAppAddActions (xtcontext, xfd_actions, XtNumber (xfd_actions)); 215 XtOverrideTranslations 216 (toplevel, XtParseTranslationTable ("<Message>WM_PROTOCOLS: Quit()")); 217 218 XtGetApplicationResources (toplevel, (XtPointer) &xfd_resources, Resources, 219 XtNumber (Resources), NULL, ZERO); 220 221 222 /* pane wrapping everything */ 223 pane = XtCreateManagedWidget ("pane", panedWidgetClass, toplevel, 224 NULL, ZERO); 225 226 /* font name */ 227 toplabel = XtCreateManagedWidget ("fontname", labelWidgetClass, pane, 228 NULL, ZERO); 229 230 /* button box */ 231 box = XtCreateManagedWidget ("box", boxWidgetClass, pane, NULL, ZERO); 232 quitButton = XtCreateManagedWidget ("quit", commandWidgetClass, box, 233 NULL, ZERO); 234 prev16Button = XtCreateManagedWidget ("prev16", commandWidgetClass, box, 235 NULL, ZERO); 236 prevButton = XtCreateManagedWidget ("prev", commandWidgetClass, box, 237 NULL, ZERO); 238 nextButton = XtCreateManagedWidget ("next", commandWidgetClass, box, 239 NULL, ZERO); 240 next16Button = XtCreateManagedWidget ("next16", commandWidgetClass, box, 241 NULL, ZERO); 242 243 244 /* and labels in which to put information */ 245 selectLabel = XtCreateManagedWidget ("select", labelWidgetClass, 246 pane, NULL, ZERO); 247 248 metricsLabel = XtCreateManagedWidget ("metrics", labelWidgetClass, 249 pane, NULL, ZERO); 250 251 rangeLabel = XtCreateManagedWidget ("range", labelWidgetClass, pane, 252 NULL, ZERO); 253 254 startLabel = XtCreateManagedWidget ("start", labelWidgetClass, pane, 255 NULL, ZERO); 256 257 /* form in which to draw */ 258 form = XtCreateManagedWidget ("form", formWidgetClass, pane, NULL, ZERO); 259 260 i = 0; 261 XtSetArg (av[i], XtNtop, XtChainTop); i++; 262 XtSetArg (av[i], XtNbottom, XtChainBottom); i++; 263 XtSetArg (av[i], XtNleft, XtChainLeft); i++; 264 XtSetArg (av[i], XtNright, XtChainRight); i++; 265 XtSetArg (av[i], XtNcallback, cb); i++; 266 267 oldWarningHandler = XtAppSetWarningMsgHandler(xtcontext, 268 CatchFontConversionWarning); 269 270 fontGrid = XtCreateManagedWidget ("grid", fontgridWidgetClass, form, 271 av, i); 272 273 XtAppSetWarningMsgHandler(xtcontext, oldWarningHandler); 274 275 /* set the label at the top to tell us which font this is */ 276#ifdef XRENDER 277 i = 0; 278 XtSetArg (av[i], XtNface, &xft); i++; 279 XtGetValues (fontGrid, av, i); 280 if (xft) 281 { 282 FcChar8 *family; 283 FcChar8 *style; 284 FcPattern *p; 285 double size; 286 family = (FcChar8 *) ""; 287 FcPatternGetString (xft->pattern, FC_FAMILY, 0, &family); 288 style = (FcChar8 *) ""; 289 FcPatternGetString (xft->pattern, FC_STYLE, 0, &style); 290 size = 0; 291 FcPatternGetDouble (xft->pattern, FC_SIZE, 0, &size); 292 p = FcPatternBuild (NULL, 293 FC_FAMILY, FcTypeString, family, 294 FC_STYLE, FcTypeString, style, 295 FC_SIZE, FcTypeDouble, size, 296 NULL); 297 fontname = (char *) FcNameUnparse (p); 298 FcPatternDestroy (p); 299 } 300 else 301#endif 302 { 303 i = 0; 304 XtSetArg (av[i], XtNfont, &fs); i++; 305 XtGetValues (fontGrid, av, i); 306 if (!fs || fontConversionFailed) { 307 fprintf (stderr, gettext("%s: no font to display\n"), ProgramName); 308 exit (1); 309 } 310 fontname = get_font_name (XtDisplay(toplevel), fs); 311 if (!fontname) fontname = gettext("unknown font!"); 312 } 313 i = 0; 314 XtSetArg (av[i], XtNlabel, fontname); i++; 315 XtSetValues (toplabel, av, i); 316 317 minn = GridFirstChar (fontGrid); 318 maxn = GridLastChar (fontGrid); 319 snprintf (buf, sizeof(buf), xfd_resources.range_format, 320 minn >> 8, minn & 0xff, 321 minn >> 8, minn & 0xff, 322 maxn >> 8, maxn & 0xff, 323 maxn >> 8, maxn & 0xff); 324 325 i = 0; 326 XtSetArg (av[i], XtNlabel, buf); i++; 327 XtSetValues (rangeLabel, av, i); 328 329 XtRealizeWidget (toplevel); 330 331 wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW", 332 False); 333 (void) XSetWMProtocols (XtDisplay(toplevel), XtWindow(toplevel), 334 &wm_delete_window, 1); 335 336 change_page (0); 337 XtAppMainLoop (xtcontext); 338 exit(0); 339} 340 341/*ARGSUSED*/ 342static void 343SelectChar(Widget w, XtPointer closure, XtPointer data) 344{ 345 FontGridCharRec *p = (FontGridCharRec *) data; 346 XFontStruct *fs = p->thefont; 347 long n = p->thechar; 348 int direction, fontascent, fontdescent; 349 XCharStruct metrics; 350 char buf[256]; 351 Arg arg; 352 Boolean has_char = 1; 353 354 XtSetArg (arg, XtNlabel, buf); 355 356 buf[0] = '\0'; 357#ifdef XRENDER 358 if (p->theface) 359 { 360 XftFont *xft = p->theface; 361 FcChar32 c = (FcChar32) n; 362 has_char = (Boolean) FcCharSetHasChar (xft->charset, n); 363 if (has_char) 364 { 365 XGlyphInfo extents; 366 XftTextExtents32 (XtDisplay (w), xft, &c, 1, &extents); 367 snprintf (buf, sizeof(buf), xfd_resources.metrics_format, 368 extents.xOff, - extents.x, 369 extents.xOff - extents.width + extents.x, 370 extents.y, extents.height - extents.y, 371 xft->ascent, xft->descent); 372 } 373 } 374 else 375#endif 376 { 377 if ((!fs->min_byte1 && !fs->max_byte1) ? 378 (n < fs->min_char_or_byte2 || n > fs->max_char_or_byte2) : 379 (n >> 8 < fs->min_byte1 || n >> 8 > fs->max_byte1 || 380 (n & 0xff) < fs->min_char_or_byte2 || 381 (n & 0xff) > fs->max_char_or_byte2)) 382 { 383 has_char = 0; 384 } 385 else 386 { 387 XChar2b char2b; 388 char2b.byte1 = p->thechar >> 8; 389 char2b.byte2 = p->thechar & 0xff; 390 XTextExtents16 (fs, &char2b, 1, &direction, &fontascent, &fontdescent, 391 &metrics); 392 snprintf (buf, sizeof(buf), xfd_resources.metrics_format, 393 metrics.width, metrics.lbearing, metrics.rbearing, 394 metrics.ascent, metrics.descent, fontascent, fontdescent); 395 } 396 } 397 XtSetValues (metricsLabel, &arg, ONE); 398 399 if (has_char) 400 { 401 snprintf (buf, sizeof(buf), xfd_resources.select_format, 402 n >> 8, n & 0xff, 403 n >> 8, n & 0xff, 404 n >> 8, n & 0xff); 405 } 406 else 407 { 408 snprintf (buf, sizeof(buf), xfd_resources.nochar_format, 409 n >> 8, n & 0xff, 410 n >> 8, n & 0xff, 411 n >> 8, n & 0xff); 412 } 413 XtSetValues (selectLabel, &arg, ONE); 414 415 return; 416} 417 418 419/*ARGSUSED*/ 420static void 421do_quit (Widget w, XEvent *event, String *params, Cardinal *num_params) 422{ 423 exit (0); 424} 425 426static void 427change_page(int page) 428{ 429 long oldstart, newstart; 430 int ncols, nrows; 431 char buf[256]; 432 Arg arg; 433 434 arg.name = XtNstartChar; 435 GetFontGridCellDimensions (fontGrid, &oldstart, &ncols, &nrows); 436 437 if (page) { 438 long start = (oldstart + 439 ((long) ncols) * ((long) nrows) * ((long) page)); 440 441 arg.value = (XtArgVal) start; 442 XtSetValues (fontGrid, &arg, ONE); 443 } 444 445 /* find out what it got set to */ 446 arg.value = (XtArgVal) &newstart; 447 XtGetValues (fontGrid, &arg, ONE); 448 449 /* if not paging, then initialize it, else only do it actually changed */ 450 if (!page || newstart != oldstart) { 451 unsigned int row = (unsigned int) ((newstart >> 8)); 452 unsigned int col = (unsigned int) (newstart & 0xff); 453 454 XtSetArg (arg, XtNlabel, buf); 455 snprintf (buf, sizeof(buf), xfd_resources.start_format, 456 newstart, row, col); 457 XtSetValues (startLabel, &arg, ONE); 458 } 459 460 set_button_state (); 461 462 return; 463} 464 465 466static void 467set_button_state(void) 468{ 469 Bool prevvalid, nextvalid, prev16valid, next16valid; 470 Arg arg; 471 472 GetPrevNextStates (fontGrid, &prevvalid, &nextvalid, &prev16valid, &next16valid); 473 arg.name = XtNsensitive; 474 arg.value = (XtArgVal) (prevvalid ? TRUE : FALSE); 475 XtSetValues (prevButton, &arg, ONE); 476 arg.value = (XtArgVal) (nextvalid ? TRUE : FALSE); 477 XtSetValues (nextButton, &arg, ONE); 478 arg.name = XtNsensitive; 479 arg.value = (XtArgVal) (prev16valid ? TRUE : FALSE); 480 XtSetValues (prev16Button, &arg, ONE); 481 arg.value = (XtArgVal) (next16valid ? TRUE : FALSE); 482 XtSetValues (next16Button, &arg, ONE); 483} 484 485 486/* ARGSUSED */ 487static void 488do_prev16(Widget w, XEvent *event, String *params, Cardinal *num_params) 489{ 490 change_page (-16); 491} 492 493 494static void 495do_prev(Widget w, XEvent *event, String *params, Cardinal *num_params) 496{ 497 change_page (-1); 498} 499 500 501/* ARGSUSED */ 502static void 503do_next(Widget w, XEvent *event, String *params, Cardinal *num_params) 504{ 505 change_page (1); 506} 507 508/* ARGSUSED */ 509static void 510do_next16(Widget w, XEvent *event, String *params, Cardinal *num_params) 511{ 512 change_page (16); 513} 514 515 516static char * 517get_font_name(Display *dpy, XFontStruct *fs) 518{ 519 register XFontProp *fp; 520 register int i; 521 Atom fontatom = XInternAtom (dpy, "FONT", False); 522 523 for (i = 0, fp = fs->properties; i < fs->n_properties; i++, fp++) { 524 if (fp->name == fontatom) { 525 return (XGetAtomName (dpy, fp->card32)); 526 } 527 } 528 return NULL; 529} 530 531 532static void 533CatchFontConversionWarning(String name, String type, String class, 534 String defaultp, String *params, Cardinal *np) 535{ 536 if (np && *np > 1 && 537 strcmp(name, "conversionError") == 0 && 538 strcmp(type, "string") == 0 && 539 strcmp(class, "XtToolkitError") == 0 && 540 strcmp(params[1], "FontStruct") == 0) fontConversionFailed = True; 541 542 (*oldWarningHandler)(name, type, class, defaultp, params, np); 543} 544