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