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