xlsfonts.c revision 6a45684f
1e6232409Smrg/*
26a45684fSmrg
3e6232409SmrgCopyright 1989, 1998  The Open Group
4e6232409Smrg
5e6232409SmrgPermission to use, copy, modify, distribute, and sell this software and its
6e6232409Smrgdocumentation for any purpose is hereby granted without fee, provided that
7e6232409Smrgthe above copyright notice appear in all copies and that both that
8e6232409Smrgcopyright notice and this permission notice appear in supporting
9e6232409Smrgdocumentation.
10e6232409Smrg
11e6232409SmrgThe above copyright notice and this permission notice shall be included in
12e6232409Smrgall copies or substantial portions of the Software.
13e6232409Smrg
14e6232409SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15e6232409SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16e6232409SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17e6232409SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18e6232409SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19e6232409SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20e6232409Smrg
21e6232409SmrgExcept as contained in this notice, the name of The Open Group shall not be
22e6232409Smrgused in advertising or otherwise to promote the sale, use or other dealings
23e6232409Smrgin this Software without prior written authorization from The Open Group.
246a45684fSmrg
256a45684fSmrg */
266a45684fSmrg
276a45684fSmrg#ifdef HAVE_CONFIG_H
286a45684fSmrg# include "config.h"
296a45684fSmrg#endif
30e6232409Smrg
31e6232409Smrg#include <X11/Xlib.h>
32e6232409Smrg#include <X11/Xutil.h>
33e6232409Smrg#include <X11/Xos.h>
34e6232409Smrg#include <stdio.h>
35e6232409Smrg#include <stdlib.h>
36e6232409Smrg#include <limits.h>
37e6232409Smrg#include "dsimple.h"
38e6232409Smrg
39e6232409Smrg#define N_START INT_MAX  /* Maximum # of fonts to start with (should
40e6232409Smrg                          * always be be > 10000 as modern OSes like
41e6232409Smrg                          * Solaris 8 already have more than 9000 XLFD
42e6232409Smrg                          * fonts available) */
43e6232409Smrg
44e6232409Smrg#define L_SHORT    0
45e6232409Smrg#define L_MEDIUM   1
46e6232409Smrg#define L_LONG     2
47e6232409Smrg#define L_VERYLONG 3
48e6232409Smrg
49e6232409Smrgstatic int  max_output_line_width     = 79;
50e6232409Smrgstatic int  output_line_padding       = 3;
51e6232409Smrgstatic int  columns                   = 0;
52e6232409Smrg
53e6232409Smrgstatic Bool sort_output               = True;
54e6232409Smrgstatic Bool open_instead_of_list      = False;
55e6232409Smrgstatic int  long_list                 = L_SHORT;
56e6232409Smrgstatic int  nnames                    = N_START;
57e6232409Smrgstatic int  font_cnt                  = 0;
58e6232409Smrgstatic int  min_max;
59e6232409Smrg
60e6232409Smrgtypedef struct {
61e6232409Smrg  char           *name;
62e6232409Smrg  XFontStruct    *info;
63e6232409Smrg} FontList;
64e6232409Smrg
65e6232409Smrgstatic FontList *font_list = NULL;
66e6232409Smrg
67e6232409Smrg/* Local prototypes */
6894a251fdSmrgstatic void get_list(const char *pattern);
69e6232409Smrgstatic int  compare(const void *arg1, const void *arg2);
70e6232409Smrgstatic void show_fonts(void);
71e6232409Smrgstatic void copy_number(char **pp1, char**pp2, int n1, int n2);
72e6232409Smrgstatic int  IgnoreError(Display *disp, XErrorEvent *event);
73e6232409Smrgstatic void PrintProperty(XFontProp *prop);
74e6232409Smrgstatic void ComputeFontType(XFontStruct *fs);
75e6232409Smrgstatic void print_character_metrics(register XFontStruct *info);
76e6232409Smrgstatic void do_query_font (Display *dpy, char *name);
77e6232409Smrg
786a45684fSmrgvoid usage(const char *errmsg)
79e6232409Smrg{
806a45684fSmrg    if (errmsg != NULL)
816a45684fSmrg        fprintf (stderr, "%s: %s\n\n", program_name, errmsg);
826a45684fSmrg
8394a251fdSmrg    fprintf (stderr, "usage:  %s [-options] [-fn pattern]\n%s", program_name,
8494a251fdSmrg    "where options include:\n"
8594a251fdSmrg    "    -l[l[l]]                 give long info about each font\n"
8694a251fdSmrg    "    -m                       give character min and max bounds\n"
8794a251fdSmrg    "    -C                       force columns\n"
8894a251fdSmrg    "    -1                       force single column\n"
8994a251fdSmrg    "    -u                       keep output unsorted\n"
9094a251fdSmrg    "    -o                       use OpenFont/QueryFont instead of ListFonts\n"
9194a251fdSmrg    "    -w width                 maximum width for multiple columns\n"
9294a251fdSmrg    "    -n columns               number of columns if multi column\n"
9394a251fdSmrg    "    -display displayname     X server to contact\n"
9494a251fdSmrg    "    -d displayname           (alias for -display displayname)\n"
956a45684fSmrg    "    -v                       print program version\n"
9694a251fdSmrg    "\n");
97e6232409Smrg    Close_Display();
98e6232409Smrg    exit(EXIT_FAILURE);
99e6232409Smrg}
100e6232409Smrg
101e6232409Smrgint main(int argc, char **argv)
102e6232409Smrg{
103e6232409Smrg    int argcnt = 0, i;
104e6232409Smrg
105e6232409Smrg    INIT_NAME;
106e6232409Smrg
107e6232409Smrg    /* Handle command line arguments, open display */
108e6232409Smrg    Setup_Display_And_Screen(&argc, argv);
109e6232409Smrg
110e6232409Smrg    for (argv++, argc--; argc; argv++, argc--) {
111e6232409Smrg        if (argv[0][0] == '-') {
1126a45684fSmrg            if (argcnt > 0)
1136a45684fSmrg                usage ("options may not be specified after font names");
114e6232409Smrg            for (i=1; argv[0][i]; i++)
115e6232409Smrg                switch(argv[0][i]) {
116e6232409Smrg                case 'l':
117e6232409Smrg                    long_list++;
118e6232409Smrg                    break;
119e6232409Smrg                case 'm':
120e6232409Smrg                    min_max++;
121e6232409Smrg                    break;
122e6232409Smrg                case 'C':
123e6232409Smrg                    columns = 0;
124e6232409Smrg                    break;
125e6232409Smrg                case '1':
126e6232409Smrg                    columns = 1;
127e6232409Smrg                    break;
128e6232409Smrg                case 'f': /* "-fn" */
1296a45684fSmrg                    if (argv[0][i+1] != 'n') {
1306a45684fSmrg                        fprintf (stderr, "%s: unrecognized argument %s\n\n",
1316a45684fSmrg                                 program_name, argv[0]);
1326a45684fSmrg                        usage(NULL);
1336a45684fSmrg                    }
1346a45684fSmrg                    if (--argc <= 0) usage ("-fn requires an argument");
135e6232409Smrg                    argcnt++;
136e6232409Smrg                    argv++;
137e6232409Smrg                    get_list(argv[0]);
138e6232409Smrg                    goto next;
139e6232409Smrg                case 'w':
1406a45684fSmrg                    if (--argc <= 0) usage ("-w requires an argument");
141e6232409Smrg                    argv++;
142e6232409Smrg                    max_output_line_width = atoi(argv[0]);
143e6232409Smrg                    goto next;
144e6232409Smrg                case 'n':
1456a45684fSmrg                    if (--argc <= 0) usage ("-n requires an argument");
146e6232409Smrg                    argv++;
147e6232409Smrg                    columns = atoi(argv[0]);
148e6232409Smrg                    goto next;
149e6232409Smrg                case 'o':
150e6232409Smrg                    open_instead_of_list = True;
151e6232409Smrg                    break;
152e6232409Smrg                case 'u':
153e6232409Smrg                    sort_output = False;
154e6232409Smrg                    break;
1556a45684fSmrg                case 'v':
1566a45684fSmrg                    puts(PACKAGE_STRING);
1576a45684fSmrg                    exit(0);
158e6232409Smrg                default:
1596a45684fSmrg                    fprintf (stderr, "%s: unrecognized argument -%c\n\n",
1606a45684fSmrg                             program_name, argv[0][i]);
1616a45684fSmrg                    usage(NULL);
162e6232409Smrg                    break;
163e6232409Smrg                }
1646a45684fSmrg            if (i == 1) {
1656a45684fSmrg                fprintf (stderr, "%s: unrecognized argument %s\n\n",
1666a45684fSmrg                         program_name, argv[0]);
1676a45684fSmrg                usage(NULL);
1686a45684fSmrg            }
169e6232409Smrg        } else {
170e6232409Smrg            argcnt++;
171e6232409Smrg            get_list(argv[0]);
172e6232409Smrg        }
173e6232409Smrg      next: ;
174e6232409Smrg    }
175e6232409Smrg
176e6232409Smrg    if (argcnt == 0)
177e6232409Smrg        get_list("*");
178e6232409Smrg
179e6232409Smrg    show_fonts();
180e6232409Smrg
181e6232409Smrg    Close_Display();
182e6232409Smrg    return EXIT_SUCCESS;
183e6232409Smrg}
184e6232409Smrg
185e6232409Smrg
186e6232409Smrgstatic
18794a251fdSmrgvoid get_list(const char *pattern)
188e6232409Smrg{
189e6232409Smrg    int           available = nnames+1,
190e6232409Smrg                  i;
191e6232409Smrg    char        **fonts;
192e6232409Smrg    XFontStruct  *info;
193e6232409Smrg
194e6232409Smrg    /* Get list of fonts matching pattern */
195e6232409Smrg    for (;;) {
196e6232409Smrg        if (open_instead_of_list) {
197e6232409Smrg            info = XLoadQueryFont (dpy, pattern);
198e6232409Smrg
199e6232409Smrg            if (info) {
200e6232409Smrg                fonts = &pattern;
201e6232409Smrg                available = 1;
202e6232409Smrg                XUnloadFont (dpy, info->fid);
203e6232409Smrg            } else {
204e6232409Smrg                fonts = NULL;
205e6232409Smrg            }
206e6232409Smrg            break;
207e6232409Smrg        }
208e6232409Smrg
209e6232409Smrg        if (long_list == L_MEDIUM)
210e6232409Smrg            fonts = XListFontsWithInfo(dpy, pattern, nnames, &available, &info);
211e6232409Smrg        else
212e6232409Smrg            fonts = XListFonts(dpy, pattern, nnames, &available);
213e6232409Smrg        if (fonts == NULL || available < nnames)
214e6232409Smrg            break;
215e6232409Smrg        if (long_list == L_MEDIUM)
216e6232409Smrg            XFreeFontInfo(fonts, info, available);
217e6232409Smrg        else
218e6232409Smrg            XFreeFontNames(fonts);
219e6232409Smrg        nnames = available * 2;
220e6232409Smrg    }
221e6232409Smrg
222e6232409Smrg    if (fonts == NULL) {
223e6232409Smrg        fprintf(stderr, "%s: pattern \"%s\" unmatched\n",
224e6232409Smrg                program_name, pattern);
225e6232409Smrg        return;
226e6232409Smrg    }
227e6232409Smrg
22894a251fdSmrg    font_list = realloc(font_list, (font_cnt + available) * sizeof(FontList));
22994a251fdSmrg    if (font_list == NULL)
23094a251fdSmrg        Fatal_Error("Out of memory!");
231e6232409Smrg    for (i=0; i<available; i++) {
232e6232409Smrg        font_list[font_cnt].name = fonts[i];
233e6232409Smrg        if (long_list == L_MEDIUM)
234e6232409Smrg            font_list[font_cnt].info = info + i;
235e6232409Smrg        else
236e6232409Smrg            font_list[font_cnt].info = NULL;
237e6232409Smrg
238e6232409Smrg        font_cnt++;
239e6232409Smrg    }
240e6232409Smrg}
241e6232409Smrg
242e6232409Smrgstatic
243e6232409Smrgint compare(const void *arg1, const void *arg2)
244e6232409Smrg{
245e6232409Smrg    const FontList *f1 = arg1;
246e6232409Smrg    const FontList *f2 = arg2;
247e6232409Smrg    const char *p1 = f1->name;
248e6232409Smrg    const char *p2 = f2->name;
249e6232409Smrg
250e6232409Smrg    while (*p1 && *p2 && *p1 == *p2)
251e6232409Smrg            p1++, p2++;
252e6232409Smrg    return(*p1 - *p2);
253e6232409Smrg}
254e6232409Smrg
255e6232409Smrgstatic
256e6232409Smrgvoid show_fonts(void)
257e6232409Smrg{
258e6232409Smrg    int i;
259e6232409Smrg
260e6232409Smrg    if (font_cnt == 0)
261e6232409Smrg        return;
262e6232409Smrg
263e6232409Smrg    /* first sort the output */
264e6232409Smrg    if (sort_output) qsort(font_list, font_cnt, sizeof(FontList), compare);
265e6232409Smrg
266e6232409Smrg    if (long_list > L_MEDIUM) {
267e6232409Smrg        for (i = 0; i < font_cnt; i++) {
268e6232409Smrg            do_query_font (dpy, font_list[i].name);
269e6232409Smrg        }
270e6232409Smrg        return;
271e6232409Smrg    }
272e6232409Smrg
273e6232409Smrg    if (long_list == L_MEDIUM) {
274e6232409Smrg        XFontStruct *pfi;
27594a251fdSmrg        const char  *string;
276e6232409Smrg
277e6232409Smrg        printf("DIR  ");
278e6232409Smrg        printf("MIN  ");
279e6232409Smrg        printf("MAX ");
280e6232409Smrg        printf("EXIST ");
281e6232409Smrg        printf("DFLT ");
282e6232409Smrg        printf("PROP ");
283e6232409Smrg        printf("ASC ");
284e6232409Smrg        printf("DESC ");
285e6232409Smrg        printf("NAME");
286e6232409Smrg        printf("\n");
287e6232409Smrg        for (i=0; i<font_cnt; i++) {
288e6232409Smrg            pfi = font_list[i].info;
289e6232409Smrg            if (!pfi) {
290e6232409Smrg                fprintf(stderr, "%s:  no font information for font \"%s\".\n",
291e6232409Smrg                        program_name,
292e6232409Smrg                        font_list[i].name ?
293e6232409Smrg                        font_list[i].name : "");
294e6232409Smrg                continue;
295e6232409Smrg            }
296e6232409Smrg            switch(pfi->direction) {
297e6232409Smrg                case FontLeftToRight: string = "-->"; break;
298e6232409Smrg                case FontRightToLeft: string = "<--"; break;
299e6232409Smrg                default:              string = "???"; break;
300e6232409Smrg            }
301e6232409Smrg            printf("%-4s", string);
302e6232409Smrg            if (pfi->min_byte1 == 0 &&
303e6232409Smrg                pfi->max_byte1 == 0) {
304e6232409Smrg                printf(" %3d ", pfi->min_char_or_byte2);
305e6232409Smrg                printf(" %3d ", pfi->max_char_or_byte2);
306e6232409Smrg            } else {
307e6232409Smrg                printf("*%3d ", pfi->min_byte1);
308e6232409Smrg                printf("*%3d ", pfi->max_byte1);
309e6232409Smrg            }
310e6232409Smrg            printf("%5s ", pfi->all_chars_exist ? "all" : "some");
311e6232409Smrg            printf("%4d ", pfi->default_char);
312e6232409Smrg            printf("%4d ", pfi->n_properties);
313e6232409Smrg            printf("%3d ", pfi->ascent);
314e6232409Smrg            printf("%4d ", pfi->descent);
315e6232409Smrg            printf("%s\n", font_list[i].name);
316e6232409Smrg            if (min_max) {
317e6232409Smrg                char  min[ BUFSIZ ],
318e6232409Smrg                      max[ BUFSIZ ];
319e6232409Smrg                char *pmax = max,
320e6232409Smrg                     *pmin = min;
321e6232409Smrg
322e6232409Smrg                strcpy(pmin, "     min(l,r,w,a,d) = (");
323e6232409Smrg                strcpy(pmax, "     max(l,r,w,a,d) = (");
324e6232409Smrg                pmin += strlen(pmin);
325e6232409Smrg                pmax += strlen(pmax);
326e6232409Smrg
327e6232409Smrg                copy_number(&pmin, &pmax,
328e6232409Smrg                            pfi->min_bounds.lbearing,
329e6232409Smrg                            pfi->max_bounds.lbearing);
330e6232409Smrg                *pmin++ = *pmax++ = ',';
331e6232409Smrg                copy_number(&pmin, &pmax,
332e6232409Smrg                            pfi->min_bounds.rbearing,
333e6232409Smrg                            pfi->max_bounds.rbearing);
334e6232409Smrg                *pmin++ = *pmax++ = ',';
335e6232409Smrg                copy_number(&pmin, &pmax,
336e6232409Smrg                            pfi->min_bounds.width,
337e6232409Smrg                            pfi->max_bounds.width);
338e6232409Smrg                *pmin++ = *pmax++ = ',';
339e6232409Smrg                copy_number(&pmin, &pmax,
340e6232409Smrg                            pfi->min_bounds.ascent,
341e6232409Smrg                            pfi->max_bounds.ascent);
342e6232409Smrg                *pmin++ = *pmax++ = ',';
343e6232409Smrg                copy_number(&pmin, &pmax,
344e6232409Smrg                            pfi->min_bounds.descent,
345e6232409Smrg                            pfi->max_bounds.descent);
346e6232409Smrg                *pmin++ = *pmax++ = ')';
347e6232409Smrg                *pmin = *pmax = '\0';
348e6232409Smrg                printf("%s\n", min);
349e6232409Smrg                printf("%s\n", max);
350e6232409Smrg            }
351e6232409Smrg        }
352e6232409Smrg        return;
353e6232409Smrg    }
354e6232409Smrg
355e6232409Smrg    if ((columns == 0 && isatty(1)) || columns > 1) {
356e6232409Smrg        int width,
357e6232409Smrg            max_width = 0,
358e6232409Smrg            lines_per_column,
359e6232409Smrg            j,
360e6232409Smrg            index;
361e6232409Smrg
362e6232409Smrg        for (i=0; i<font_cnt; i++) {
363e6232409Smrg            width = strlen(font_list[i].name);
364e6232409Smrg            if (width > max_width)
365e6232409Smrg                max_width = width;
366e6232409Smrg        }
367e6232409Smrg        if (max_width == 0)
368e6232409Smrg            Fatal_Error("all %d fontnames listed are zero length", font_cnt);
369e6232409Smrg
370e6232409Smrg        if (columns == 0) {
371e6232409Smrg            if ((max_width * 2) + output_line_padding >
372e6232409Smrg                max_output_line_width) {
373e6232409Smrg                columns = 1;
374e6232409Smrg            } else {
375e6232409Smrg                max_width += output_line_padding;
376e6232409Smrg                columns = ((max_output_line_width +
377e6232409Smrg                            output_line_padding) / max_width);
378e6232409Smrg            }
379e6232409Smrg        } else {
380e6232409Smrg            max_width += output_line_padding;
381e6232409Smrg        }
382e6232409Smrg        if (columns <= 1) goto single_column;
383e6232409Smrg
384e6232409Smrg        if (font_cnt < columns)
385e6232409Smrg            columns = font_cnt;
386e6232409Smrg        lines_per_column = (font_cnt + columns - 1) / columns;
387e6232409Smrg
388e6232409Smrg        for (i=0; i<lines_per_column; i++) {
389e6232409Smrg            for (j=0; j<columns; j++) {
390e6232409Smrg                index = j * lines_per_column + i;
391e6232409Smrg                if (index >= font_cnt)
392e6232409Smrg                    break;
393e6232409Smrg                if (j+1 == columns)
394e6232409Smrg                    printf("%s", font_list[ index ].name);
395e6232409Smrg                else
396e6232409Smrg                    printf("%-*s",
397e6232409Smrg                           max_width,
398e6232409Smrg                           font_list[ index ].name);
399e6232409Smrg            }
400e6232409Smrg            printf("\n");
401e6232409Smrg        }
402e6232409Smrg        return;
403e6232409Smrg    }
404e6232409Smrg
405e6232409Smrg  single_column:
406e6232409Smrg    for (i=0; i<font_cnt; i++)
407e6232409Smrg        printf("%s\n", font_list[i].name);
408e6232409Smrg}
409e6232409Smrg
410e6232409Smrgstatic
411e6232409Smrgvoid copy_number(char **pp1, char**pp2, int n1, int n2)
412e6232409Smrg{
413e6232409Smrg    char *p1 = *pp1;
414e6232409Smrg    char *p2 = *pp2;
415e6232409Smrg    int   w;
416e6232409Smrg
417e6232409Smrg    sprintf(p1, "%d", n1);
418e6232409Smrg    sprintf(p2, "%d", n2);
419e6232409Smrg    w = MAX(strlen(p1), strlen(p2));
420e6232409Smrg    sprintf(p1, "%*d", w, n1);
421e6232409Smrg    sprintf(p2, "%*d", w, n2);
422e6232409Smrg    p1 += strlen(p1);
423e6232409Smrg    p2 += strlen(p2);
424e6232409Smrg    *pp1 = p1;
425e6232409Smrg    *pp2 = p2;
426e6232409Smrg}
427e6232409Smrg
428e6232409Smrg
429e6232409Smrg
430e6232409Smrg/* ARGSUSED */
431e6232409Smrgstatic
432e6232409Smrgint IgnoreError(Display *disp, XErrorEvent *event)
433e6232409Smrg{
434e6232409Smrg    return 0;
435e6232409Smrg}
436e6232409Smrg
43794a251fdSmrgstatic const char *bounds_metrics_title =
438e6232409Smrg                      "width left  right  asc  desc   attr   keysym\n";
439e6232409Smrg
440e6232409Smrg#define PrintBounds(_what,_ptr) \
441e6232409Smrg{   register XCharStruct *p = (_ptr); \
4428fff3f40Smrg    printf ("\t%3s\t\t%4d  %4d  %4d  %4d  %4d  0x%04x\n", \
4438fff3f40Smrg          (_what), p->width, p->lbearing, \
444e6232409Smrg          p->rbearing, p->ascent, p->descent, p->attributes); }
445e6232409Smrg
446e6232409Smrg
44794a251fdSmrgstatic const char* stringValued [] = { /* values are atoms */
448e6232409Smrg    /* font name components (see section 3.2 of the XLFD) */
449e6232409Smrg    "FOUNDRY",
450e6232409Smrg    "FAMILY_NAME",
451e6232409Smrg    "WEIGHT_NAME",
452e6232409Smrg    "SLANT",
453e6232409Smrg    "SETWIDTH_NAME",
454e6232409Smrg    "ADD_STYLE_NAME",
455e6232409Smrg    "SPACING",
456e6232409Smrg    "CHARSET_REGISTRY",
457e6232409Smrg    "CHARSET_ENCODING",
458e6232409Smrg
459e6232409Smrg    /* other standard X font properties (see section 3.2 of the XLFD) */
460e6232409Smrg    "FONT",
461e6232409Smrg    "FACE_NAME",
462e6232409Smrg    "FULL_NAME",              /* deprecated */
463e6232409Smrg    "COPYRIGHT",
464e6232409Smrg    "NOTICE",
465e6232409Smrg    "FONT_TYPE",
466e6232409Smrg    "FONT_VERSION",
467e6232409Smrg    "RASTERIZER_NAME",
468e6232409Smrg    "RASTERIZER_VERSION",
469e6232409Smrg
470e6232409Smrg    /* other registered font properties (see the X.org Registry, sec. 15) */
471e6232409Smrg    "_ADOBE_POSTSCRIPT_FONTNAME",
472e6232409Smrg
473e6232409Smrg    /* unregistered font properties */
474e6232409Smrg    "CHARSET_COLLECTIONS",
475e6232409Smrg    "CLASSIFICATION",
476e6232409Smrg    "DEVICE_FONT_NAME",
477e6232409Smrg    "FONTNAME_REGISTRY",
478e6232409Smrg    "MONOSPACED",
479e6232409Smrg    "QUALITY",
480e6232409Smrg    "RELATIVE_SET",
481e6232409Smrg    "STYLE",
482e6232409Smrg     NULL
483e6232409Smrg    };
484e6232409Smrg
485e6232409Smrgstatic
486e6232409Smrgvoid PrintProperty(XFontProp *prop)
487e6232409Smrg{
488e6232409Smrg    char *atom, *value;
489e6232409Smrg    char nosuch[40];
490e6232409Smrg    int i;
491e6232409Smrg    XErrorHandler oldhandler = XSetErrorHandler(IgnoreError);
492e6232409Smrg
493e6232409Smrg    atom = XGetAtomName(dpy, prop->name);
494e6232409Smrg    if (!atom) {
495e6232409Smrg        atom = nosuch;
496e6232409Smrg        nosuch[0] = '\0';
497e6232409Smrg        (void)sprintf (atom, "No such atom = %ld", prop->name);
498e6232409Smrg    }
499e6232409Smrg    printf ("      %s", atom);
500e6232409Smrg
501e6232409Smrg    /* Pad out to a column width of 22, but ensure there is always at
502e6232409Smrg       least one space between property name & value. */
503e6232409Smrg    for (i = strlen(atom); i < 21; i++) putchar (' ');
504e6232409Smrg    putchar(' ');
505e6232409Smrg
506e6232409Smrg    for (i = 0; ; i++) {
507e6232409Smrg        if (stringValued[i] == NULL) {
508e6232409Smrg            printf ("%ld\n", prop->card32);
509e6232409Smrg            break;
510e6232409Smrg        }
511e6232409Smrg        if (strcmp(stringValued[i], atom) == 0) {
512e6232409Smrg            value = XGetAtomName(dpy, prop->card32);
513e6232409Smrg            if (value == NULL)
514e6232409Smrg                printf ("%ld (expected string value)\n", prop->card32);
515e6232409Smrg            else {
516e6232409Smrg                printf ("%s\n", value);
517e6232409Smrg                XFree (value);
518e6232409Smrg            }
519e6232409Smrg            break;
520e6232409Smrg        }
521e6232409Smrg    }
522e6232409Smrg    if (atom != nosuch) XFree (atom);
523e6232409Smrg    XSetErrorHandler (oldhandler);
524e6232409Smrg}
525e6232409Smrg
526e6232409Smrg
527e6232409Smrgstatic void
528e6232409SmrgComputeFontType(XFontStruct *fs)
529e6232409Smrg{
530e6232409Smrg    int i;
531e6232409Smrg    Bool char_cell = True;
53294a251fdSmrg    const char *reason = NULL;
533e6232409Smrg    XCharStruct *cs;
534e6232409Smrg    Atom awatom = XInternAtom (dpy, "AVERAGE_WIDTH", False);
535e6232409Smrg
536e6232409Smrg    printf ("  font type:\t\t");
537e6232409Smrg    if (fs->min_bounds.width != fs->max_bounds.width) {
538e6232409Smrg        printf ("Proportional (min and max widths not equal)\n");
539e6232409Smrg        return;
540e6232409Smrg    }
541e6232409Smrg
542e6232409Smrg    if (awatom) {
543e6232409Smrg        for (i = 0; i < fs->n_properties; i++) {
544e6232409Smrg            if (fs->properties[i].name == awatom &&
545e6232409Smrg                (fs->max_bounds.width * 10) != fs->properties[i].card32) {
546e6232409Smrg                char_cell = False;
547e6232409Smrg                reason = "font width not equal to AVERAGE_WIDTH";
548e6232409Smrg                break;
549e6232409Smrg            }
550e6232409Smrg        }
551e6232409Smrg    }
552e6232409Smrg
553e6232409Smrg    if (fs->per_char) {
554e6232409Smrg        for (i = fs->min_char_or_byte2, cs = fs->per_char;
555e6232409Smrg             i <= fs->max_char_or_byte2; i++, cs++) {
556e6232409Smrg            if (cs->width == 0) continue;
557e6232409Smrg            if (cs->width != fs->max_bounds.width) {
558e6232409Smrg                /* this shouldn't happen since we checked above */
559e6232409Smrg                printf ("Proportional (characters not all the same width)\n");
560e6232409Smrg                return;
561e6232409Smrg            }
562e6232409Smrg            if (char_cell) {
563e6232409Smrg                if (cs->width < 0) {
564e6232409Smrg                    if (!(cs->width <= cs->lbearing &&
565e6232409Smrg                          cs->lbearing <= cs->rbearing &&
566e6232409Smrg                          cs->rbearing <= 0)) {
567e6232409Smrg                        char_cell = False;
568e6232409Smrg                        reason = "ink outside bounding box";
569e6232409Smrg                    }
570e6232409Smrg                } else {
571e6232409Smrg                    if (!(0 <= cs->lbearing &&
572e6232409Smrg                          cs->lbearing <= cs->rbearing &&
573e6232409Smrg                          cs->rbearing <= cs->width)) {
574e6232409Smrg                        char_cell = False;
575e6232409Smrg                        reason = "ink outside bounding box";
576e6232409Smrg                    }
577e6232409Smrg                }
578e6232409Smrg                if (!(cs->ascent <= fs->ascent &&
579e6232409Smrg                      cs->descent <= fs->descent)) {
580e6232409Smrg                    char_cell  = False;
581e6232409Smrg                    reason = "characters not all same ascent or descent";
582e6232409Smrg                }
583e6232409Smrg            }
584e6232409Smrg        }
585e6232409Smrg    }
586e6232409Smrg
587e6232409Smrg    printf ("%s", char_cell ? "Character Cell" : "Monospaced");
588e6232409Smrg    if (reason) printf (" (%s)", reason);
589e6232409Smrg    printf ("\n");
590e6232409Smrg
591e6232409Smrg    return;
592e6232409Smrg}
593e6232409Smrg
594e6232409Smrg
595e6232409Smrgstatic void
596e6232409Smrgprint_character_metrics(register XFontStruct *info)
597e6232409Smrg{
598e6232409Smrg    register XCharStruct *pc = info->per_char;
599e6232409Smrg    register int i, j;
600e6232409Smrg    unsigned n, saven;
601e6232409Smrg
602e6232409Smrg    printf ("  character metrics:\n");
603e6232409Smrg    saven = ((info->min_byte1 << 8) | info->min_char_or_byte2);
604e6232409Smrg    for (j = info->min_byte1; j <= info->max_byte1; j++) {
605e6232409Smrg        n = saven;
606e6232409Smrg        for (i = info->min_char_or_byte2; i <= info->max_char_or_byte2; i++) {
607e6232409Smrg            char *s = XKeysymToString ((KeySym) n);
6088fff3f40Smrg            printf ("\t0x%02x%02x (%u)\t%4d  %4d  %4d  %4d  %4d  0x%04x  %s\n",
6098fff3f40Smrg                    j, i, n, pc->width, pc->lbearing,
610e6232409Smrg                    pc->rbearing, pc->ascent, pc->descent, pc->attributes,
611e6232409Smrg                    s ? s : ".");
612e6232409Smrg            pc++;
613e6232409Smrg            n++;
614e6232409Smrg        }
615e6232409Smrg        saven += 256;
616e6232409Smrg    }
617e6232409Smrg}
618e6232409Smrg
619e6232409Smrgstatic
620e6232409Smrgvoid do_query_font (Display *dpy, char *name)
621e6232409Smrg{
622e6232409Smrg    register int i;
623e6232409Smrg    register XFontStruct *info = XLoadQueryFont (dpy, name);
624e6232409Smrg
625e6232409Smrg    if (!info) {
626e6232409Smrg        fprintf (stderr, "%s:  unable to get info about font \"%s\"\n",
627e6232409Smrg                 program_name, name);
628e6232409Smrg        return;
629e6232409Smrg    }
630e6232409Smrg    printf ("name:  %s\n", name ? name : "(nil)");
631e6232409Smrg    printf ("  direction:\t\t%s\n", ((info->direction == FontLeftToRight)
632e6232409Smrg                                     ? "left to right" : "right to left"));
633e6232409Smrg    printf ("  indexing:\t\t%s\n",
634e6232409Smrg            ((info->min_byte1 == 0 && info->max_byte1 == 0) ? "linear" :
635e6232409Smrg             "matrix"));
636e6232409Smrg    printf ("  rows:\t\t\t0x%02x thru 0x%02x (%d thru %d)\n",
637e6232409Smrg            info->min_byte1, info->max_byte1,
638e6232409Smrg            info->min_byte1, info->max_byte1);
639e6232409Smrg    printf ("  columns:\t\t0x%02x thru 0x%02x (%d thru %d)\n",
640e6232409Smrg            info->min_char_or_byte2, info->max_char_or_byte2,
641e6232409Smrg            info->min_char_or_byte2, info->max_char_or_byte2);
642e6232409Smrg    printf ("  all chars exist:\t%s\n",
643e6232409Smrg        (info->all_chars_exist) ? "yes" : "no");
644e6232409Smrg    printf ("  default char:\t\t0x%04x (%d)\n",
645e6232409Smrg            info->default_char, info->default_char);
646e6232409Smrg    printf ("  ascent:\t\t%d\n", info->ascent);
647e6232409Smrg    printf ("  descent:\t\t%d\n", info->descent);
648e6232409Smrg    ComputeFontType (info);
649e6232409Smrg    printf ("  bounds:\t\t%s", bounds_metrics_title);
650e6232409Smrg    PrintBounds ("min", &info->min_bounds);
651e6232409Smrg    PrintBounds ("max", &info->max_bounds);
652e6232409Smrg    if (info->per_char && long_list >= L_VERYLONG)
653e6232409Smrg        print_character_metrics (info);
654e6232409Smrg    printf ("  properties:\t\t%d\n", info->n_properties);
655e6232409Smrg    for (i = 0; i < info->n_properties; i++)
656e6232409Smrg        PrintProperty (&info->properties[i]);
657e6232409Smrg    printf ("\n");
658e6232409Smrg
659e6232409Smrg    XFreeFontInfo (NULL, info, 1);
660e6232409Smrg}
661e6232409Smrg
662e6232409Smrg
663