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