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