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