fontutils.c revision 9a64e1c5
19a64e1c5Smrg/* $XTermId: fontutils.c,v 1.439 2014/06/17 20:38:27 tom Exp $ */
2d522f475Smrg
30bd37d32Smrg/*
49a64e1c5Smrg * Copyright 1998-2013,2014 by Thomas E. Dickey
50bd37d32Smrg *
60bd37d32Smrg *                         All Rights Reserved
70bd37d32Smrg *
80bd37d32Smrg * Permission is hereby granted, free of charge, to any person obtaining a
90bd37d32Smrg * copy of this software and associated documentation files (the
100bd37d32Smrg * "Software"), to deal in the Software without restriction, including
110bd37d32Smrg * without limitation the rights to use, copy, modify, merge, publish,
120bd37d32Smrg * distribute, sublicense, and/or sell copies of the Software, and to
130bd37d32Smrg * permit persons to whom the Software is furnished to do so, subject to
140bd37d32Smrg * the following conditions:
150bd37d32Smrg *
160bd37d32Smrg * The above copyright notice and this permission notice shall be included
170bd37d32Smrg * in all copies or substantial portions of the Software.
180bd37d32Smrg *
190bd37d32Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
200bd37d32Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
210bd37d32Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
220bd37d32Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
230bd37d32Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
240bd37d32Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
250bd37d32Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
260bd37d32Smrg *
270bd37d32Smrg * Except as contained in this notice, the name(s) of the above copyright
280bd37d32Smrg * holders shall not be used in advertising or otherwise to promote the
290bd37d32Smrg * sale, use or other dealings in this Software without prior written
300bd37d32Smrg * authorization.
310bd37d32Smrg */
32d522f475Smrg
33d522f475Smrg/*
34d522f475Smrg * A portion of this module (for FontNameProperties) was adapted from EMU 1.3;
35d522f475Smrg * it constructs font names with specific properties changed, e.g., for bold
36d522f475Smrg * and double-size characters.
37d522f475Smrg */
38d522f475Smrg
39d522f475Smrg#define RES_OFFSET(field)	XtOffsetOf(SubResourceRec, field)
40d522f475Smrg
41d522f475Smrg#include <fontutils.h>
42d522f475Smrg#include <X11/Xmu/Drawing.h>
4320d2c4d2Smrg#include <X11/Xmu/CharSet.h>
44d522f475Smrg
45d522f475Smrg#include <main.h>
46d522f475Smrg#include <data.h>
47d522f475Smrg#include <menu.h>
48d522f475Smrg#include <xstrings.h>
49d522f475Smrg#include <xterm.h>
50d522f475Smrg
51d522f475Smrg#include <stdio.h>
52d522f475Smrg#include <ctype.h>
53d522f475Smrg
549a64e1c5Smrg#define ALLOC_STRING(name) \
559a64e1c5Smrg	if (name != 0) \
569a64e1c5Smrg	    name = x_strdup(name)
579a64e1c5Smrg#define FREE_STRING(name) \
589a64e1c5Smrg	    free_string(name)
599a64e1c5Smrg
600bd37d32Smrg#define SetFontWidth(screen,dst,src)  (dst)->f_width = (src)
610bd37d32Smrg#define SetFontHeight(screen,dst,src) (dst)->f_height = dimRound((screen)->scale_height * (float) (src))
620bd37d32Smrg
63d522f475Smrg/* from X11/Xlibint.h - not all vendors install this file */
64d522f475Smrg#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
65d522f475Smrg			     (((cs)->rbearing|(cs)->lbearing| \
66d522f475Smrg			       (cs)->ascent|(cs)->descent) == 0))
67d522f475Smrg
68fa3f02f3Smrg#define CI_GET_CHAR_INFO_1D(fs,col,cs) \
69d522f475Smrg{ \
70fa3f02f3Smrg    cs = 0; \
71d522f475Smrg    if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
72d522f475Smrg	if (fs->per_char == NULL) { \
73d522f475Smrg	    cs = &fs->min_bounds; \
74d522f475Smrg	} else { \
75d522f475Smrg	    cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
76d522f475Smrg	} \
77fa3f02f3Smrg	if (CI_NONEXISTCHAR(cs)) cs = 0; \
78d522f475Smrg    } \
79d522f475Smrg}
80d522f475Smrg
81fa3f02f3Smrg#define CI_GET_CHAR_INFO_2D(fs,row,col,cs) \
82d522f475Smrg{ \
83fa3f02f3Smrg    cs = 0; \
84d522f475Smrg    if (row >= fs->min_byte1 && row <= fs->max_byte1 && \
85d522f475Smrg	col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
86d522f475Smrg	if (fs->per_char == NULL) { \
87d522f475Smrg	    cs = &fs->min_bounds; \
88d522f475Smrg	} else { \
89d522f475Smrg	    cs = &fs->per_char[((row - fs->min_byte1) * \
90d522f475Smrg				(fs->max_char_or_byte2 - \
91d522f475Smrg				 fs->min_char_or_byte2 + 1)) + \
92d522f475Smrg			       (col - fs->min_char_or_byte2)]; \
93d522f475Smrg	} \
94fa3f02f3Smrg	if (CI_NONEXISTCHAR(cs)) cs = 0; \
95d522f475Smrg    } \
96d522f475Smrg}
97d522f475Smrg
989a64e1c5Smrg#define FREE_FNAME(field) \
999a64e1c5Smrg	    if (fonts == 0 || myfonts.field != fonts->field) { \
1009a64e1c5Smrg		FREE_STRING(myfonts.field); \
1019a64e1c5Smrg		myfonts.field = 0; \
1029a64e1c5Smrg	    }
1039a64e1c5Smrg
104d522f475Smrg/*
105d522f475Smrg * A structure to hold the relevant properties from a font
106d522f475Smrg * we need to make a well formed font name for it.
107d522f475Smrg */
108d522f475Smrgtypedef struct {
109d522f475Smrg    /* registry, foundry, family */
1109a64e1c5Smrg    const char *beginning;
111d522f475Smrg    /* weight */
1129a64e1c5Smrg    const char *weight;
113d522f475Smrg    /* slant */
1149a64e1c5Smrg    const char *slant;
115d522f475Smrg    /* wideness */
1169a64e1c5Smrg    const char *wideness;
117d522f475Smrg    /* add style */
1189a64e1c5Smrg    const char *add_style;
119d522f475Smrg    int pixel_size;
1209a64e1c5Smrg    const char *point_size;
121d522f475Smrg    int res_x;
122d522f475Smrg    int res_y;
1239a64e1c5Smrg    const char *spacing;
124d522f475Smrg    int average_width;
125d522f475Smrg    /* charset registry, charset encoding */
126d522f475Smrg    char *end;
127d522f475Smrg} FontNameProperties;
128d522f475Smrg
1299a64e1c5Smrgstatic void
1309a64e1c5Smrgfree_string(String value)
1319a64e1c5Smrg{
1329a64e1c5Smrg    free((void *) value);
1339a64e1c5Smrg}
1349a64e1c5Smrg
1350bd37d32Smrg#if OPT_RENDERFONT
1360bd37d32Smrgstatic void fillInFaceSize(XtermWidget, int);
1370bd37d32Smrg#endif
1380bd37d32Smrg
139d522f475Smrg#if OPT_SHIFT_FONTS
1400bd37d32Smrgstatic int lookupOneFontSize(XtermWidget, int);
141d522f475Smrg#endif
142d522f475Smrg
143fa3f02f3Smrg#if OPT_REPORT_FONTS || OPT_WIDE_CHARS
1442eaa94a1Schristosstatic unsigned
1459a64e1c5SmrgcountGlyphs(XFontStruct *fp)
146d522f475Smrg{
147d522f475Smrg    unsigned count = 0;
148d522f475Smrg
149d522f475Smrg    if (fp != 0) {
150d522f475Smrg	if (fp->min_byte1 == 0 && fp->max_byte1 == 0) {
151fa3f02f3Smrg	    count = fp->max_char_or_byte2 - fp->min_char_or_byte2 + 1;
152d522f475Smrg	} else if (fp->min_char_or_byte2 < 256
153d522f475Smrg		   && fp->max_char_or_byte2 < 256) {
154d522f475Smrg	    unsigned first = (fp->min_byte1 << 8) + fp->min_char_or_byte2;
155d522f475Smrg	    unsigned last = (fp->max_byte1 << 8) + fp->max_char_or_byte2;
156d522f475Smrg	    count = last + 1 - first;
157d522f475Smrg	}
158d522f475Smrg    }
159d522f475Smrg    return count;
160d522f475Smrg}
161fa3f02f3Smrg#endif
162d522f475Smrg
163fa3f02f3Smrg#if OPT_WIDE_CHARS
164d522f475Smrg/*
165d522f475Smrg * Verify that the wide-bold font is at least a bold font with roughly as many
166d522f475Smrg * glyphs as the wide font.  The counts should be the same, but settle for
167d522f475Smrg * filtering out the worst of the font mismatches.
168d522f475Smrg */
169d522f475Smrgstatic Bool
1709a64e1c5SmrgcompatibleWideCounts(XFontStruct *wfs, XFontStruct *wbfs)
171d522f475Smrg{
172d522f475Smrg    unsigned count_w = countGlyphs(wfs);
173d522f475Smrg    unsigned count_wb = countGlyphs(wbfs);
174d522f475Smrg    if (count_w <= 256 ||
175d522f475Smrg	count_wb <= 256 ||
176d522f475Smrg	((count_w / 4) * 3) > count_wb) {
177d522f475Smrg	TRACE(("...font server lied (count wide %u vs wide-bold %u)\n",
178d522f475Smrg	       count_w, count_wb));
179d522f475Smrg	return False;
180d522f475Smrg    }
181d522f475Smrg    return True;
182d522f475Smrg}
183d522f475Smrg#endif /* OPT_WIDE_CHARS */
184d522f475Smrg
18520d2c4d2Smrg#if OPT_BOX_CHARS
18620d2c4d2Smrgstatic void
18720d2c4d2SmrgsetupPackedFonts(XtermWidget xw)
18820d2c4d2Smrg{
18920d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
19020d2c4d2Smrg    Bool value = False;
19120d2c4d2Smrg
19220d2c4d2Smrg#if OPT_RENDERFONT
19320d2c4d2Smrg#define MIXED(name) screen->name[fontnum].map.mixed
1940bd37d32Smrg    if (xw->work.render_font == True) {
19520d2c4d2Smrg	int fontnum = screen->menu_font_number;
19620d2c4d2Smrg
19720d2c4d2Smrg	screen->allow_packing = (Boolean) (MIXED(renderFontNorm)
19820d2c4d2Smrg					   || MIXED(renderFontBold)
19920d2c4d2Smrg					   || MIXED(renderFontItal)
20020d2c4d2Smrg#if OPT_RENDERWIDE
20120d2c4d2Smrg					   || MIXED(renderWideNorm)
20220d2c4d2Smrg					   || MIXED(renderWideBold)
20320d2c4d2Smrg					   || MIXED(renderWideItal)
20420d2c4d2Smrg#endif
20520d2c4d2Smrg	    );
20620d2c4d2Smrg#undef MIXED
20720d2c4d2Smrg    }
20820d2c4d2Smrg#endif /* OPT_RENDERFONT */
20920d2c4d2Smrg
21020d2c4d2Smrg    value = screen->allow_packing;
21120d2c4d2Smrg
21220d2c4d2Smrg    SetItemSensitivity(fontMenuEntries[fontMenu_font_packedfont].widget, value);
21320d2c4d2Smrg}
21420d2c4d2Smrg#endif
21520d2c4d2Smrg
216d522f475Smrg/*
217d522f475Smrg * Returns the fields from start to stop in a dash- separated string.  This
2189a64e1c5Smrg * function will modify the source, putting '\0's in the appropriate place and
219d522f475Smrg * moving the beginning forward to after the '\0'
220d522f475Smrg *
221d522f475Smrg * This will NOT work for the last field (but we won't need it).
222d522f475Smrg */
223d522f475Smrgstatic char *
224d522f475Smrgn_fields(char **source, int start, int stop)
225d522f475Smrg{
226d522f475Smrg    int i;
227d522f475Smrg    char *str, *str1;
228d522f475Smrg
229d522f475Smrg    /*
230d522f475Smrg     * find the start-1th dash
231d522f475Smrg     */
2329a64e1c5Smrg    for (i = start - 1, str = *source; i; i--, str++) {
233d522f475Smrg	if ((str = strchr(str, '-')) == 0)
234d522f475Smrg	    return 0;
2359a64e1c5Smrg    }
236d522f475Smrg
237d522f475Smrg    /*
238d522f475Smrg     * find the stopth dash
239d522f475Smrg     */
2409a64e1c5Smrg    for (i = stop - start + 1, str1 = str; i; i--, str1++) {
241d522f475Smrg	if ((str1 = strchr(str1, '-')) == 0)
242d522f475Smrg	    return 0;
2439a64e1c5Smrg    }
244d522f475Smrg
245d522f475Smrg    /*
246d522f475Smrg     * put a \0 at the end of the fields
247d522f475Smrg     */
248d522f475Smrg    *(str1 - 1) = '\0';
249d522f475Smrg
250d522f475Smrg    /*
251d522f475Smrg     * move source forward
252d522f475Smrg     */
253d522f475Smrg    *source = str1;
254d522f475Smrg
255d522f475Smrg    return str;
256d522f475Smrg}
257d522f475Smrg
258956cc18dSsnjstatic Boolean
259956cc18dSsnjcheck_fontname(const char *name)
260956cc18dSsnj{
261956cc18dSsnj    Boolean result = True;
262956cc18dSsnj
263492d43a5Smrg    if (IsEmpty(name)) {
264956cc18dSsnj	TRACE(("fontname missing\n"));
265956cc18dSsnj	result = False;
266956cc18dSsnj    }
267956cc18dSsnj    return result;
268956cc18dSsnj}
269956cc18dSsnj
270d522f475Smrg/*
271d522f475Smrg * Gets the font properties from a given font structure.  We use the FONT name
272d522f475Smrg * to find them out, since that seems easier.
273d522f475Smrg *
274d522f475Smrg * Returns a pointer to a static FontNameProperties structure
275d522f475Smrg * or NULL on error.
276d522f475Smrg */
277d522f475Smrgstatic FontNameProperties *
2789a64e1c5Smrgget_font_name_props(Display *dpy, XFontStruct *fs, char **result)
279d522f475Smrg{
280d522f475Smrg    static FontNameProperties props;
281d522f475Smrg    static char *last_name;
282d522f475Smrg
283d522f475Smrg    XFontProp *fp;
284d522f475Smrg    int i;
285d522f475Smrg    Atom fontatom = XInternAtom(dpy, "FONT", False);
28620d2c4d2Smrg    char *name = 0;
287d522f475Smrg    char *str;
288d522f475Smrg
289d522f475Smrg    /*
290d522f475Smrg     * first get the full font name
291d522f475Smrg     */
29220d2c4d2Smrg    if (fontatom != 0) {
29320d2c4d2Smrg	for (i = 0, fp = fs->properties; i < fs->n_properties; i++, fp++) {
29420d2c4d2Smrg	    if (fp->name == fontatom) {
29520d2c4d2Smrg		name = XGetAtomName(dpy, fp->card32);
29620d2c4d2Smrg		break;
29720d2c4d2Smrg	    }
29820d2c4d2Smrg	}
29920d2c4d2Smrg    }
300d522f475Smrg
301d522f475Smrg    if (name == 0)
302d522f475Smrg	return 0;
303d522f475Smrg
304d522f475Smrg    /*
305d522f475Smrg     * XGetAtomName allocates memory - don't leak
306d522f475Smrg     */
307d522f475Smrg    if (last_name != 0)
308d522f475Smrg	XFree(last_name);
309d522f475Smrg    last_name = name;
310d522f475Smrg
311d522f475Smrg    if (result != 0) {
312956cc18dSsnj	if (!check_fontname(name))
313d522f475Smrg	    return 0;
3140bd37d32Smrg	if (*result != 0)
3150bd37d32Smrg	    free(*result);
3160bd37d32Smrg	*result = x_strdup(name);
317d522f475Smrg    }
318d522f475Smrg
319d522f475Smrg    /*
320d522f475Smrg     * Now split it up into parts and put them in
321d522f475Smrg     * their places. Since we are using parts of
322d522f475Smrg     * the original string, we must not free the Atom Name
323d522f475Smrg     */
324d522f475Smrg
325d522f475Smrg    /* registry, foundry, family */
326d522f475Smrg    if ((props.beginning = n_fields(&name, 1, 3)) == 0)
327d522f475Smrg	return 0;
328d522f475Smrg
329d522f475Smrg    /* weight is the next */
330d522f475Smrg    if ((props.weight = n_fields(&name, 1, 1)) == 0)
331d522f475Smrg	return 0;
332d522f475Smrg
333d522f475Smrg    /* slant */
334d522f475Smrg    if ((props.slant = n_fields(&name, 1, 1)) == 0)
335d522f475Smrg	return 0;
336d522f475Smrg
337d522f475Smrg    /* width */
338d522f475Smrg    if ((props.wideness = n_fields(&name, 1, 1)) == 0)
339d522f475Smrg	return 0;
340d522f475Smrg
341d522f475Smrg    /* add style */
342d522f475Smrg    if ((props.add_style = n_fields(&name, 1, 1)) == 0)
343d522f475Smrg	return 0;
344d522f475Smrg
345d522f475Smrg    /* pixel size */
346d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
347d522f475Smrg	return 0;
348d522f475Smrg    if ((props.pixel_size = atoi(str)) == 0)
349d522f475Smrg	return 0;
350d522f475Smrg
351d522f475Smrg    /* point size */
352d522f475Smrg    if ((props.point_size = n_fields(&name, 1, 1)) == 0)
353d522f475Smrg	return 0;
354d522f475Smrg
355d522f475Smrg    /* res_x */
356d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
357d522f475Smrg	return 0;
358d522f475Smrg    if ((props.res_x = atoi(str)) == 0)
359d522f475Smrg	return 0;
360d522f475Smrg
361d522f475Smrg    /* res_y */
362d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
363d522f475Smrg	return 0;
364d522f475Smrg    if ((props.res_y = atoi(str)) == 0)
365d522f475Smrg	return 0;
366d522f475Smrg
367d522f475Smrg    /* spacing */
368d522f475Smrg    if ((props.spacing = n_fields(&name, 1, 1)) == 0)
369d522f475Smrg	return 0;
370d522f475Smrg
371d522f475Smrg    /* average width */
372d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
373d522f475Smrg	return 0;
374d522f475Smrg    if ((props.average_width = atoi(str)) == 0)
375d522f475Smrg	return 0;
376d522f475Smrg
377d522f475Smrg    /* the rest: charset registry and charset encoding */
378d522f475Smrg    props.end = name;
379d522f475Smrg
380d522f475Smrg    return &props;
381d522f475Smrg}
382d522f475Smrg
383d522f475Smrg#define ALLOCHUNK(n) ((n | 127) + 1)
384d522f475Smrg
385d522f475Smrgstatic void
386956cc18dSsnjalloca_fontname(char **result, size_t next)
387d522f475Smrg{
388956cc18dSsnj    size_t last = (*result != 0) ? strlen(*result) : 0;
389956cc18dSsnj    size_t have = (*result != 0) ? ALLOCHUNK(last) : 0;
390956cc18dSsnj    size_t want = last + next + 2;
391d522f475Smrg
392d522f475Smrg    if (want >= have) {
393d522f475Smrg	want = ALLOCHUNK(want);
394d522f475Smrg	if (last != 0) {
3959a64e1c5Smrg	    char *save = *result;
396d522f475Smrg	    *result = TypeRealloc(char, want, *result);
3979a64e1c5Smrg	    if (*result == 0)
3989a64e1c5Smrg		free(save);
399d522f475Smrg	} else {
400d522f475Smrg	    if ((*result = TypeMallocN(char, want)) != 0)
401d522f475Smrg		**result = '\0';
402d522f475Smrg	}
403d522f475Smrg    }
404d522f475Smrg}
405d522f475Smrg
406d522f475Smrgstatic void
40720d2c4d2Smrgappend_fontname_str(char **result, const char *value)
408d522f475Smrg{
409d522f475Smrg    if (value == 0)
410d522f475Smrg	value = "*";
411d522f475Smrg    alloca_fontname(result, strlen(value));
412d522f475Smrg    if (*result != 0) {
413d522f475Smrg	if (**result != '\0')
414d522f475Smrg	    strcat(*result, "-");
415d522f475Smrg	strcat(*result, value);
416d522f475Smrg    }
417d522f475Smrg}
418d522f475Smrg
419d522f475Smrgstatic void
420d522f475Smrgappend_fontname_num(char **result, int value)
421d522f475Smrg{
422d522f475Smrg    if (value < 0) {
423d522f475Smrg	append_fontname_str(result, "*");
424d522f475Smrg    } else {
425d522f475Smrg	char temp[100];
426d522f475Smrg	sprintf(temp, "%d", value);
427d522f475Smrg	append_fontname_str(result, temp);
428d522f475Smrg    }
429d522f475Smrg}
430d522f475Smrg
431d522f475Smrg/*
432d522f475Smrg * Take the given font props and try to make a well formed font name specifying
433d522f475Smrg * the same base font and size and everything, but with different weight/width
434d522f475Smrg * according to the parameters.  The return value is allocated, should be freed
435d522f475Smrg * by the caller.
436d522f475Smrg */
437d522f475Smrgstatic char *
4389a64e1c5Smrgderive_font_name(FontNameProperties *props,
43920d2c4d2Smrg		 const char *use_weight,
440d522f475Smrg		 int use_average_width,
44120d2c4d2Smrg		 const char *use_encoding)
442d522f475Smrg{
443d522f475Smrg    char *result = 0;
444d522f475Smrg
445d522f475Smrg    append_fontname_str(&result, props->beginning);
446d522f475Smrg    append_fontname_str(&result, use_weight);
447d522f475Smrg    append_fontname_str(&result, props->slant);
448d522f475Smrg    append_fontname_str(&result, 0);
449d522f475Smrg    append_fontname_str(&result, 0);
450d522f475Smrg    append_fontname_num(&result, props->pixel_size);
451d522f475Smrg    append_fontname_str(&result, props->point_size);
452d522f475Smrg    append_fontname_num(&result, props->res_x);
453d522f475Smrg    append_fontname_num(&result, props->res_y);
454d522f475Smrg    append_fontname_str(&result, props->spacing);
455d522f475Smrg    append_fontname_num(&result, use_average_width);
456d522f475Smrg    append_fontname_str(&result, use_encoding);
457d522f475Smrg
458d522f475Smrg    return result;
459d522f475Smrg}
460d522f475Smrg
461d522f475Smrgstatic char *
4629a64e1c5Smrgbold_font_name(FontNameProperties *props, int use_average_width)
463d522f475Smrg{
464d522f475Smrg    return derive_font_name(props, "bold", use_average_width, props->end);
465d522f475Smrg}
466d522f475Smrg
4679a64e1c5Smrg#if OPT_WIDE_ATTRS
4689a64e1c5Smrgstatic char *
4699a64e1c5Smrgitalic_font_name(FontNameProperties *props, int use_average_width)
4709a64e1c5Smrg{
4719a64e1c5Smrg    FontNameProperties myprops = *props;
4729a64e1c5Smrg    myprops.slant = "o";
4739a64e1c5Smrg    return derive_font_name(&myprops, props->weight, use_average_width, props->end);
4749a64e1c5Smrg}
4759a64e1c5Smrg#endif
4769a64e1c5Smrg
477d522f475Smrg#if OPT_WIDE_CHARS
478d522f475Smrg#define derive_wide_font(props, weight) \
479d522f475Smrg	derive_font_name(props, weight, props->average_width * 2, "ISO10646-1")
480d522f475Smrg
481d522f475Smrgstatic char *
4829a64e1c5Smrgwide_font_name(FontNameProperties *props)
483d522f475Smrg{
484d522f475Smrg    return derive_wide_font(props, "medium");
485d522f475Smrg}
486d522f475Smrg
487d522f475Smrgstatic char *
4889a64e1c5Smrgwidebold_font_name(FontNameProperties *props)
489d522f475Smrg{
490d522f475Smrg    return derive_wide_font(props, "bold");
491d522f475Smrg}
492d522f475Smrg#endif /* OPT_WIDE_CHARS */
493d522f475Smrg
494d522f475Smrg#if OPT_DEC_CHRSET
495d522f475Smrg/*
496d522f475Smrg * Take the given font props and try to make a well formed font name specifying
497d522f475Smrg * the same base font but changed depending on the given attributes and chrset.
498d522f475Smrg *
499d522f475Smrg * For double width fonts, we just double the X-resolution, for double height
500d522f475Smrg * fonts we double the pixel-size and Y-resolution
501d522f475Smrg */
502d522f475Smrgchar *
5039a64e1c5SmrgxtermSpecialFont(TScreen *screen, unsigned attr_flags, unsigned draw_flags, unsigned chrset)
504d522f475Smrg{
505d522f475Smrg#if OPT_TRACE
506d522f475Smrg    static char old_spacing[80];
507d522f475Smrg    static FontNameProperties old_props;
508d522f475Smrg#endif
509d522f475Smrg    FontNameProperties *props;
510d522f475Smrg    char *result = 0;
51120d2c4d2Smrg    const char *weight;
512d522f475Smrg    int pixel_size;
513d522f475Smrg    int res_x;
514d522f475Smrg    int res_y;
515d522f475Smrg
516d522f475Smrg    props = get_font_name_props(screen->display, screen->fnts[fNorm].fs, 0);
517d522f475Smrg    if (props == 0)
518d522f475Smrg	return result;
519d522f475Smrg
520d522f475Smrg    pixel_size = props->pixel_size;
521d522f475Smrg    res_x = props->res_x;
522d522f475Smrg    res_y = props->res_y;
5239a64e1c5Smrg    if (attr_flags & BOLD)
524d522f475Smrg	weight = "bold";
525d522f475Smrg    else
526d522f475Smrg	weight = props->weight;
527d522f475Smrg
528d522f475Smrg    if (CSET_DOUBLE(chrset))
529d522f475Smrg	res_x *= 2;
530d522f475Smrg
531d522f475Smrg    if (chrset == CSET_DHL_TOP
532d522f475Smrg	|| chrset == CSET_DHL_BOT) {
533d522f475Smrg	res_y *= 2;
534d522f475Smrg	pixel_size *= 2;
535d522f475Smrg    }
536d522f475Smrg#if OPT_TRACE
537d522f475Smrg    if (old_props.res_x != res_x
538d522f475Smrg	|| old_props.res_x != res_y
539d522f475Smrg	|| old_props.pixel_size != pixel_size
540d522f475Smrg	|| strcmp(old_props.spacing, props->spacing)) {
5419a64e1c5Smrg	TRACE(("xtermSpecialFont(atts = %#x, draw = %#x, chrset = %#x)\n",
5429a64e1c5Smrg	       attr_flags, draw_flags, chrset));
543d522f475Smrg	TRACE(("res_x      = %d\n", res_x));
544d522f475Smrg	TRACE(("res_y      = %d\n", res_y));
545d522f475Smrg	TRACE(("point_size = %s\n", props->point_size));
546d522f475Smrg	TRACE(("pixel_size = %d\n", pixel_size));
547d522f475Smrg	TRACE(("spacing    = %s\n", props->spacing));
548d522f475Smrg	old_props.res_x = res_x;
549d522f475Smrg	old_props.res_x = res_y;
550d522f475Smrg	old_props.pixel_size = pixel_size;
5510bd37d32Smrg	old_props.spacing = old_spacing;
5520bd37d32Smrg	sprintf(old_spacing, "%.*s", (int) sizeof(old_spacing) - 2, props->spacing);
553d522f475Smrg    }
554d522f475Smrg#endif
555d522f475Smrg
556d522f475Smrg    append_fontname_str(&result, props->beginning);
557d522f475Smrg    append_fontname_str(&result, weight);
558d522f475Smrg    append_fontname_str(&result, props->slant);
559d522f475Smrg    append_fontname_str(&result, props->wideness);
560d522f475Smrg    append_fontname_str(&result, props->add_style);
561d522f475Smrg    append_fontname_num(&result, pixel_size);
562d522f475Smrg    append_fontname_str(&result, props->point_size);
5639a64e1c5Smrg    append_fontname_num(&result, (draw_flags & NORESOLUTION) ? -1 : res_x);
5649a64e1c5Smrg    append_fontname_num(&result, (draw_flags & NORESOLUTION) ? -1 : res_y);
565d522f475Smrg    append_fontname_str(&result, props->spacing);
566d522f475Smrg    append_fontname_str(&result, 0);
567d522f475Smrg    append_fontname_str(&result, props->end);
568d522f475Smrg
569d522f475Smrg    return result;
570d522f475Smrg}
571d522f475Smrg#endif /* OPT_DEC_CHRSET */
572d522f475Smrg
573d522f475Smrg/*
574d522f475Smrg * Case-independent comparison for font-names, including wildcards.
575d522f475Smrg * XLFD allows '?' as a wildcard, but we do not handle that (no one seems
576d522f475Smrg * to use it).
577d522f475Smrg */
578d522f475Smrgstatic Bool
579492d43a5Smrgsame_font_name(const char *pattern, const char *match)
580d522f475Smrg{
581956cc18dSsnj    Bool result = False;
582956cc18dSsnj
583956cc18dSsnj    if (pattern && match) {
584956cc18dSsnj	while (*pattern && *match) {
585956cc18dSsnj	    if (*pattern == *match) {
586956cc18dSsnj		pattern++;
587956cc18dSsnj		match++;
588956cc18dSsnj	    } else if (*pattern == '*' || *match == '*') {
589956cc18dSsnj		if (same_font_name(pattern + 1, match)) {
590956cc18dSsnj		    return True;
591956cc18dSsnj		} else if (same_font_name(pattern, match + 1)) {
592956cc18dSsnj		    return True;
593956cc18dSsnj		} else {
594956cc18dSsnj		    return False;
595956cc18dSsnj		}
596d522f475Smrg	    } else {
597956cc18dSsnj		int p = x_toupper(*pattern++);
598956cc18dSsnj		int m = x_toupper(*match++);
599956cc18dSsnj		if (p != m)
600956cc18dSsnj		    return False;
601d522f475Smrg	    }
602d522f475Smrg	}
603956cc18dSsnj	result = (*pattern == *match);	/* both should be NUL */
604d522f475Smrg    }
605956cc18dSsnj    return result;
606d522f475Smrg}
607d522f475Smrg
608d522f475Smrg/*
609d522f475Smrg * Double-check the fontname that we asked for versus what the font server
610d522f475Smrg * actually gave us.  The larger fixed fonts do not always have a matching bold
611d522f475Smrg * font, and the font server may try to scale another font or otherwise
612d522f475Smrg * substitute a mismatched font.
613d522f475Smrg *
614d522f475Smrg * If we cannot get what we requested, we will fallback to the original
615d522f475Smrg * behavior, which simulates bold by overstriking each character at one pixel
616d522f475Smrg * offset.
617d522f475Smrg */
618d522f475Smrgstatic int
6199a64e1c5Smrggot_bold_font(Display *dpy, XFontStruct *fs, String requested)
620d522f475Smrg{
6210bd37d32Smrg    char *actual = 0;
622d522f475Smrg    int got;
623d522f475Smrg
6240bd37d32Smrg    if (get_font_name_props(dpy, fs, &actual) == 0)
625d522f475Smrg	got = 0;
626d522f475Smrg    else
627d522f475Smrg	got = same_font_name(requested, actual);
6280bd37d32Smrg    free(actual);
629d522f475Smrg    return got;
630d522f475Smrg}
631d522f475Smrg
6329a64e1c5Smrg/*
6339a64e1c5Smrg * Check normal/bold (or wide/wide-bold) font pairs to see if we will be able
6349a64e1c5Smrg * to check for missing glyphs in a comparable manner.
6359a64e1c5Smrg */
6369a64e1c5Smrgstatic int
6379a64e1c5Smrgcomparable_metrics(XFontStruct *normal, XFontStruct *bold)
6389a64e1c5Smrg{
6399a64e1c5Smrg#define DATA "comparable_metrics: "
6409a64e1c5Smrg    int result = 0;
6419a64e1c5Smrg
6429a64e1c5Smrg    if (normal->all_chars_exist) {
6439a64e1c5Smrg	if (bold->all_chars_exist) {
6449a64e1c5Smrg	    result = 1;
6459a64e1c5Smrg	} else {
6469a64e1c5Smrg	    TRACE((DATA "all chars exist in normal font, but not in bold\n"));
6479a64e1c5Smrg	}
6489a64e1c5Smrg    } else if (normal->per_char != 0) {
6499a64e1c5Smrg	if (bold->per_char != 0) {
6509a64e1c5Smrg	    result = 1;
6519a64e1c5Smrg	} else {
6529a64e1c5Smrg	    TRACE((DATA "normal font has per-char metrics, but not bold\n"));
6539a64e1c5Smrg	}
6549a64e1c5Smrg    } else {
6559a64e1c5Smrg	TRACE((DATA "normal font is not very good!\n"));
6569a64e1c5Smrg	result = 1;		/* give in (we're not going in reverse) */
6579a64e1c5Smrg    }
6589a64e1c5Smrg    return result;
6599a64e1c5Smrg#undef DATA
6609a64e1c5Smrg}
6619a64e1c5Smrg
662d522f475Smrg/*
663d522f475Smrg * If the font server tries to adjust another font, it may not adjust it
664d522f475Smrg * properly.  Check that the bounding boxes are compatible.  Otherwise we'll
665d522f475Smrg * leave trash on the display when we mix normal and bold fonts.
666d522f475Smrg */
667d522f475Smrgstatic int
6689a64e1c5Smrgsame_font_size(XtermWidget xw, XFontStruct *nfs, XFontStruct *bfs)
669d522f475Smrg{
670956cc18dSsnj    TScreen *screen = TScreenOf(xw);
671d522f475Smrg    TRACE(("same_font_size height %d/%d, min %d/%d max %d/%d\n",
672d522f475Smrg	   nfs->ascent + nfs->descent,
673d522f475Smrg	   bfs->ascent + bfs->descent,
674d522f475Smrg	   nfs->min_bounds.width, bfs->min_bounds.width,
675d522f475Smrg	   nfs->max_bounds.width, bfs->max_bounds.width));
676956cc18dSsnj    return screen->free_bold_box
677d522f475Smrg	|| ((nfs->ascent + nfs->descent) == (bfs->ascent + bfs->descent)
678d522f475Smrg	    && (nfs->min_bounds.width == bfs->min_bounds.width
679d522f475Smrg		|| nfs->min_bounds.width == bfs->min_bounds.width + 1)
680d522f475Smrg	    && (nfs->max_bounds.width == bfs->max_bounds.width
681d522f475Smrg		|| nfs->max_bounds.width == bfs->max_bounds.width + 1));
682d522f475Smrg}
683d522f475Smrg
684d522f475Smrg/*
685d522f475Smrg * Check if the font looks like it has fixed width
686d522f475Smrg */
687d522f475Smrgstatic int
6889a64e1c5Smrgis_fixed_font(XFontStruct *fs)
689d522f475Smrg{
690d522f475Smrg    if (fs)
691d522f475Smrg	return (fs->min_bounds.width == fs->max_bounds.width);
692d522f475Smrg    return 1;
693d522f475Smrg}
694d522f475Smrg
695d522f475Smrg/*
696d522f475Smrg * Check if the font looks like a double width font (i.e. contains
697d522f475Smrg * characters of width X and 2X
698d522f475Smrg */
699d522f475Smrg#if OPT_WIDE_CHARS
700d522f475Smrgstatic int
7019a64e1c5Smrgis_double_width_font(XFontStruct *fs)
702d522f475Smrg{
703d522f475Smrg    return ((2 * fs->min_bounds.width) == fs->max_bounds.width);
704d522f475Smrg}
705d522f475Smrg#else
706d522f475Smrg#define is_double_width_font(fs) 0
707d522f475Smrg#endif
708d522f475Smrg
709d522f475Smrg#if OPT_WIDE_CHARS && OPT_RENDERFONT && defined(HAVE_TYPE_FCCHAR32)
710d522f475Smrg#define HALF_WIDTH_TEST_STRING "1234567890"
711d522f475Smrg
712d522f475Smrg/* '1234567890' in Chinese characters in UTF-8 */
713d522f475Smrg#define FULL_WIDTH_TEST_STRING "\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89" \
714d522f475Smrg                               "\xe5\x9b\x9b\xe4\xba\x94" \
715d522f475Smrg			       "\xef\xa7\x91\xe4\xb8\x83\xe5\x85\xab" \
716d522f475Smrg			       "\xe4\xb9\x9d\xef\xa6\xb2"
717d522f475Smrg
718d522f475Smrg/* '1234567890' in Korean script in UTF-8 */
719d522f475Smrg#define FULL_WIDTH_TEST_STRING2 "\xec\x9d\xbc\xec\x9d\xb4\xec\x82\xbc" \
720d522f475Smrg                                "\xec\x82\xac\xec\x98\xa4" \
721d522f475Smrg			        "\xec\x9c\xa1\xec\xb9\xa0\xed\x8c\x94" \
722d522f475Smrg			        "\xea\xb5\xac\xec\x98\x81"
723d522f475Smrg
724d522f475Smrg#define HALF_WIDTH_CHAR1  0x0031	/* '1' */
725d522f475Smrg#define HALF_WIDTH_CHAR2  0x0057	/* 'W' */
726d522f475Smrg#define FULL_WIDTH_CHAR1  0x4E00	/* CJK Ideograph 'number one' */
727d522f475Smrg#define FULL_WIDTH_CHAR2  0xAC00	/* Korean script syllable 'Ka' */
728d522f475Smrg
729d522f475Smrgstatic Bool
7309a64e1c5Smrgis_double_width_font_xft(Display *dpy, XftFont *font)
731d522f475Smrg{
732d522f475Smrg    XGlyphInfo gi1, gi2;
733d522f475Smrg    FcChar32 c1 = HALF_WIDTH_CHAR1, c2 = HALF_WIDTH_CHAR2;
7340bd37d32Smrg    String fwstr = FULL_WIDTH_TEST_STRING;
7350bd37d32Smrg    String hwstr = HALF_WIDTH_TEST_STRING;
736d522f475Smrg
737d522f475Smrg    /* Some Korean fonts don't have Chinese characters at all. */
738d522f475Smrg    if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR1)) {
739d522f475Smrg	if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR2))
740d522f475Smrg	    return False;	/* Not a CJK font */
741d522f475Smrg	else			/* a Korean font without CJK Ideographs */
742d522f475Smrg	    fwstr = FULL_WIDTH_TEST_STRING2;
743d522f475Smrg    }
744d522f475Smrg
745d522f475Smrg    XftTextExtents32(dpy, font, &c1, 1, &gi1);
746d522f475Smrg    XftTextExtents32(dpy, font, &c2, 1, &gi2);
747d522f475Smrg    if (gi1.xOff != gi2.xOff)	/* Not a fixed-width font */
748d522f475Smrg	return False;
749d522f475Smrg
7500bd37d32Smrg    XftTextExtentsUtf8(dpy,
7510bd37d32Smrg		       font,
7520bd37d32Smrg		       (_Xconst FcChar8 *) hwstr,
7530bd37d32Smrg		       (int) strlen(hwstr),
7540bd37d32Smrg		       &gi1);
7550bd37d32Smrg    XftTextExtentsUtf8(dpy,
7560bd37d32Smrg		       font,
7570bd37d32Smrg		       (_Xconst FcChar8 *) fwstr,
7580bd37d32Smrg		       (int) strlen(fwstr),
7590bd37d32Smrg		       &gi2);
760d522f475Smrg
761d522f475Smrg    /*
762d522f475Smrg     * fontconfig and Xft prior to 2.2(?) set the width of half-width
763d522f475Smrg     * characters identical to that of full-width character in CJK double-width
764d522f475Smrg     * (bi-width / monospace) font even though the former is half as wide as
765d522f475Smrg     * the latter.  This was fixed sometime before the release of fontconfig
766d522f475Smrg     * 2.2 in early 2003.  See
767d522f475Smrg     *  http://bugzilla.mozilla.org/show_bug.cgi?id=196312
768d522f475Smrg     * In the meantime, we have to check both possibilities.
769d522f475Smrg     */
770d522f475Smrg    return ((2 * gi1.xOff == gi2.xOff) || (gi1.xOff == gi2.xOff));
771d522f475Smrg}
772d522f475Smrg#else
773d522f475Smrg#define is_double_width_font_xft(dpy, xftfont) 0
774d522f475Smrg#endif
775d522f475Smrg
776d522f475Smrg#define EmptyFont(fs) (fs != 0 \
777d522f475Smrg		   && ((fs)->ascent + (fs)->descent == 0 \
778d522f475Smrg		    || (fs)->max_bounds.width == 0))
779d522f475Smrg
780d522f475Smrg#define FontSize(fs) (((fs)->ascent + (fs)->descent) \
781d522f475Smrg		    *  (fs)->max_bounds.width)
782d522f475Smrg
783d522f475Smrgconst VTFontNames *
78420d2c4d2SmrgxtermFontName(const char *normal)
785d522f475Smrg{
786d522f475Smrg    static VTFontNames data;
7879a64e1c5Smrg    FREE_STRING(data.f_n);
788d522f475Smrg    memset(&data, 0, sizeof(data));
78920d2c4d2Smrg    data.f_n = x_strdup(normal);
790d522f475Smrg    return &data;
791d522f475Smrg}
792d522f475Smrg
793d522f475Smrgstatic void
794fa3f02f3Smrgcache_menu_font_name(TScreen *screen, int fontnum, int which, const char *name)
795d522f475Smrg{
796d522f475Smrg    if (name != 0) {
7979a64e1c5Smrg	String last = screen->menu_font_names[fontnum][which];
798d522f475Smrg	if (last != 0) {
799d522f475Smrg	    if (strcmp(last, name)) {
8009a64e1c5Smrg		FREE_STRING(last);
801d522f475Smrg		TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name));
802d522f475Smrg		screen->menu_font_names[fontnum][which] = x_strdup(name);
803d522f475Smrg	    }
804d522f475Smrg	} else {
805d522f475Smrg	    TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name));
806d522f475Smrg	    screen->menu_font_names[fontnum][which] = x_strdup(name);
807d522f475Smrg	}
808d522f475Smrg    }
809d522f475Smrg}
810d522f475Smrg
811d522f475Smrg/*
812d522f475Smrg * Open the given font and verify that it is non-empty.  Return a null on
813d522f475Smrg * failure.
814d522f475Smrg */
815d522f475SmrgBool
816956cc18dSsnjxtermOpenFont(XtermWidget xw,
817956cc18dSsnj	      const char *name,
818956cc18dSsnj	      XTermFonts * result,
819956cc18dSsnj	      fontWarningTypes warn,
820956cc18dSsnj	      Bool force)
821d522f475Smrg{
822d522f475Smrg    Bool code = False;
823d522f475Smrg    TScreen *screen = TScreenOf(xw);
824d522f475Smrg
825492d43a5Smrg    if (!IsEmpty(name)) {
826956cc18dSsnj	if ((result->fs = XLoadQueryFont(screen->display, name)) != 0) {
827956cc18dSsnj	    code = True;
828956cc18dSsnj	    if (EmptyFont(result->fs)) {
82920d2c4d2Smrg		(void) xtermCloseFont(xw, result);
830956cc18dSsnj		code = False;
831956cc18dSsnj	    } else {
832956cc18dSsnj		result->fn = x_strdup(name);
833956cc18dSsnj	    }
83420d2c4d2Smrg	} else if (XmuCompareISOLatin1(name, DEFFONT) != 0) {
835956cc18dSsnj	    if (warn <= xw->misc.fontWarnings
836956cc18dSsnj#if OPT_RENDERFONT
837956cc18dSsnj		&& !UsingRenderFont(xw)
838956cc18dSsnj#endif
839956cc18dSsnj		) {
840956cc18dSsnj		TRACE(("OOPS: cannot load font %s\n", name));
8410bd37d32Smrg		xtermWarning("cannot load font '%s'\n", name);
84220d2c4d2Smrg#if OPT_RENDERFONT
84320d2c4d2Smrg		/*
84420d2c4d2Smrg		 * Do a sanity check in case someone's mixed up xterm with
84520d2c4d2Smrg		 * one of those programs that read their resource data from
84620d2c4d2Smrg		 * xterm's namespace.
84720d2c4d2Smrg		 */
84820d2c4d2Smrg		if (strchr(name, ':') != 0 || strchr(name, '=') != 0) {
8490bd37d32Smrg		    xtermWarning("Use the \"-fa\" option for the Xft fonts\n");
85020d2c4d2Smrg		}
85120d2c4d2Smrg#endif
852956cc18dSsnj	    } else {
853492d43a5Smrg		TRACE(("xtermOpenFont: cannot load font '%s'\n", name));
854956cc18dSsnj	    }
855956cc18dSsnj	    if (force) {
856956cc18dSsnj		code = xtermOpenFont(xw, DEFFONT, result, fwAlways, True);
857956cc18dSsnj	    }
858d522f475Smrg	}
859d522f475Smrg    }
860d522f475Smrg    return code;
861d522f475Smrg}
862d522f475Smrg
863d522f475Smrg/*
864956cc18dSsnj * Close the font and free the font info.
865d522f475Smrg */
866d522f475SmrgXTermFonts *
867d522f475SmrgxtermCloseFont(XtermWidget xw, XTermFonts * fnt)
868d522f475Smrg{
869d522f475Smrg    if (fnt != 0 && fnt->fs != 0) {
870d522f475Smrg	TScreen *screen = TScreenOf(xw);
871d522f475Smrg
872d522f475Smrg	clrCgsFonts(xw, WhichVWin(screen), fnt);
873d522f475Smrg	XFreeFont(screen->display, fnt->fs);
874d522f475Smrg	xtermFreeFontInfo(fnt);
875d522f475Smrg    }
876d522f475Smrg    return 0;
877d522f475Smrg}
878d522f475Smrg
879d522f475Smrg/*
880d522f475Smrg * Close the listed fonts, noting that some may use copies of the pointer.
881d522f475Smrg */
882d522f475Smrgvoid
883d522f475SmrgxtermCloseFonts(XtermWidget xw, XTermFonts * fnts)
884d522f475Smrg{
885d522f475Smrg    int j, k;
886d522f475Smrg
887d522f475Smrg    for (j = 0; j < fMAX; ++j) {
888d522f475Smrg	/*
889d522f475Smrg	 * Need to save the pointer since xtermCloseFont zeroes it
890d522f475Smrg	 */
891d522f475Smrg	XFontStruct *thisFont = fnts[j].fs;
892d522f475Smrg	if (thisFont != 0) {
893d522f475Smrg	    xtermCloseFont(xw, &fnts[j]);
894d522f475Smrg	    for (k = j + 1; k < fMAX; ++k) {
895d522f475Smrg		if (thisFont == fnts[k].fs)
896d522f475Smrg		    xtermFreeFontInfo(&fnts[k]);
897d522f475Smrg	    }
898d522f475Smrg	}
899d522f475Smrg    }
900d522f475Smrg}
901d522f475Smrg
902d522f475Smrg/*
903d522f475Smrg * Make a copy of the source, assuming the XFontStruct's to be unique, but
904d522f475Smrg * ensuring that the names are reallocated to simplify freeing.
905d522f475Smrg */
906d522f475Smrgvoid
907d522f475SmrgxtermCopyFontInfo(XTermFonts * target, XTermFonts * source)
908d522f475Smrg{
909d522f475Smrg    xtermFreeFontInfo(target);
910d522f475Smrg    target->chrset = source->chrset;
911d522f475Smrg    target->flags = source->flags;
912d522f475Smrg    target->fn = x_strdup(source->fn);
913d522f475Smrg    target->fs = source->fs;
914d522f475Smrg}
915d522f475Smrg
916d522f475Smrgvoid
917d522f475SmrgxtermFreeFontInfo(XTermFonts * target)
918d522f475Smrg{
919d522f475Smrg    target->chrset = 0;
920d522f475Smrg    target->flags = 0;
921d522f475Smrg    if (target->fn != 0) {
922d522f475Smrg	free(target->fn);
923d522f475Smrg	target->fn = 0;
924d522f475Smrg    }
925d522f475Smrg    target->fs = 0;
926d522f475Smrg}
927d522f475Smrg
928fa3f02f3Smrg#if OPT_REPORT_FONTS
929fa3f02f3Smrgstatic void
930fa3f02f3SmrgreportXCharStruct(const char *tag, XCharStruct * cs)
931fa3f02f3Smrg{
932fa3f02f3Smrg    printf("\t\t%s:\n", tag);
933fa3f02f3Smrg    printf("\t\t\tlbearing: %d\n", cs->lbearing);
934fa3f02f3Smrg    printf("\t\t\trbearing: %d\n", cs->rbearing);
935fa3f02f3Smrg    printf("\t\t\twidth:    %d\n", cs->width);
936fa3f02f3Smrg    printf("\t\t\tascent:   %d\n", cs->ascent);
937fa3f02f3Smrg    printf("\t\t\tdescent:  %d\n", cs->descent);
938fa3f02f3Smrg}
939fa3f02f3Smrg
940fa3f02f3Smrgstatic void
941fa3f02f3SmrgreportOneVTFont(const char *tag,
942fa3f02f3Smrg		XTermFonts * fnt)
943fa3f02f3Smrg{
944fa3f02f3Smrg    if (!IsEmpty(fnt->fn)) {
945fa3f02f3Smrg	XFontStruct *fs = fnt->fs;
946fa3f02f3Smrg	unsigned first_char = 0;
947fa3f02f3Smrg	unsigned last_char = 0;
948fa3f02f3Smrg	unsigned ch;
949fa3f02f3Smrg
950fa3f02f3Smrg	if (fs->max_byte1 == 0) {
951fa3f02f3Smrg	    first_char = fs->min_char_or_byte2;
952fa3f02f3Smrg	    last_char = fs->max_char_or_byte2;
953fa3f02f3Smrg	} else {
954fa3f02f3Smrg	    first_char = (fs->min_byte1 * 256) + fs->min_char_or_byte2;
955fa3f02f3Smrg	    last_char = (fs->max_byte1 * 256) + fs->max_char_or_byte2;
956fa3f02f3Smrg	}
957fa3f02f3Smrg
958fa3f02f3Smrg	printf("\t%s: %s\n", tag, NonNull(fnt->fn));
959fa3f02f3Smrg	printf("\t\tall chars:     %s\n", fs->all_chars_exist ? "yes" : "no");
960fa3f02f3Smrg	printf("\t\tdefault char:  %d\n", fs->default_char);
961fa3f02f3Smrg	printf("\t\tdirection:     %d\n", fs->direction);
962fa3f02f3Smrg	printf("\t\tascent:        %d\n", fs->ascent);
963fa3f02f3Smrg	printf("\t\tdescent:       %d\n", fs->descent);
964fa3f02f3Smrg	printf("\t\tfirst char:    %u\n", first_char);
965fa3f02f3Smrg	printf("\t\tlast char:     %u\n", last_char);
966fa3f02f3Smrg	printf("\t\tmaximum-chars: %u\n", countGlyphs(fs));
9679a64e1c5Smrg	if (FontLacksMetrics(fnt)) {
9689a64e1c5Smrg	    printf("\t\tmissing-chars: ?\n");
9699a64e1c5Smrg	    printf("\t\tpresent-chars: ?\n");
9709a64e1c5Smrg	} else {
9719a64e1c5Smrg	    unsigned missing = 0;
9729a64e1c5Smrg	    for (ch = first_char; ch <= last_char; ++ch) {
9739a64e1c5Smrg		if (xtermMissingChar(ch, fnt)) {
9749a64e1c5Smrg		    ++missing;
9759a64e1c5Smrg		}
9769a64e1c5Smrg	    }
9779a64e1c5Smrg	    printf("\t\tmissing-chars: %u\n", missing);
9789a64e1c5Smrg	    printf("\t\tpresent-chars: %u\n", countGlyphs(fs) - missing);
9799a64e1c5Smrg	}
980fa3f02f3Smrg	printf("\t\tmin_byte1:     %d\n", fs->min_byte1);
981fa3f02f3Smrg	printf("\t\tmax_byte1:     %d\n", fs->max_byte1);
982fa3f02f3Smrg	printf("\t\tproperties:    %d\n", fs->n_properties);
983fa3f02f3Smrg	reportXCharStruct("min_bounds", &(fs->min_bounds));
984fa3f02f3Smrg	reportXCharStruct("max_bounds", &(fs->max_bounds));
985fa3f02f3Smrg	/* TODO: report fs->properties and fs->per_char */
986fa3f02f3Smrg    }
987fa3f02f3Smrg}
988fa3f02f3Smrg
989fa3f02f3Smrgstatic void
990fa3f02f3SmrgreportVTFontInfo(XtermWidget xw, int fontnum)
991fa3f02f3Smrg{
992fa3f02f3Smrg    if (resource.reportFonts) {
993fa3f02f3Smrg	TScreen *screen = TScreenOf(xw);
994fa3f02f3Smrg
995fa3f02f3Smrg	if (fontnum) {
996fa3f02f3Smrg	    printf("Loaded VTFonts(font%d)\n", fontnum);
997fa3f02f3Smrg	} else {
998fa3f02f3Smrg	    printf("Loaded VTFonts(default)\n");
999fa3f02f3Smrg	}
1000fa3f02f3Smrg	reportOneVTFont("fNorm", &screen->fnts[fNorm]);
1001fa3f02f3Smrg	reportOneVTFont("fBold", &screen->fnts[fBold]);
1002fa3f02f3Smrg#if OPT_WIDE_CHARS
1003fa3f02f3Smrg	reportOneVTFont("fWide", &screen->fnts[fWide]);
1004fa3f02f3Smrg	reportOneVTFont("fWBold", &screen->fnts[fWBold]);
1005fa3f02f3Smrg#endif
1006fa3f02f3Smrg    }
1007fa3f02f3Smrg}
1008fa3f02f3Smrg#endif
1009fa3f02f3Smrg
10109a64e1c5Smrgvoid
10119a64e1c5SmrgxtermUpdateFontGCs(XtermWidget xw, XTermFonts * fnts)
10129a64e1c5Smrg{
10139a64e1c5Smrg    TScreen *screen = TScreenOf(xw);
10149a64e1c5Smrg    VTwin *win = WhichVWin(screen);
10159a64e1c5Smrg    Pixel new_normal = getXtermForeground(xw, xw->flags, xw->cur_foreground);
10169a64e1c5Smrg    Pixel new_revers = getXtermBackground(xw, xw->flags, xw->cur_background);
10179a64e1c5Smrg
10189a64e1c5Smrg    setCgsFore(xw, win, gcNorm, new_normal);
10199a64e1c5Smrg    setCgsBack(xw, win, gcNorm, new_revers);
10209a64e1c5Smrg    setCgsFont(xw, win, gcNorm, &(fnts[fNorm]));
10219a64e1c5Smrg
10229a64e1c5Smrg    copyCgs(xw, win, gcBold, gcNorm);
10239a64e1c5Smrg    setCgsFont(xw, win, gcBold, &(fnts[fBold]));
10249a64e1c5Smrg
10259a64e1c5Smrg    setCgsFore(xw, win, gcNormReverse, new_revers);
10269a64e1c5Smrg    setCgsBack(xw, win, gcNormReverse, new_normal);
10279a64e1c5Smrg    setCgsFont(xw, win, gcNormReverse, &(fnts[fNorm]));
10289a64e1c5Smrg
10299a64e1c5Smrg    copyCgs(xw, win, gcBoldReverse, gcNormReverse);
10309a64e1c5Smrg    setCgsFont(xw, win, gcBoldReverse, &(fnts[fBold]));
10319a64e1c5Smrg
10329a64e1c5Smrg    if_OPT_WIDE_CHARS(screen, {
10339a64e1c5Smrg	if (fnts[fWide].fs != 0
10349a64e1c5Smrg	    && fnts[fWBold].fs != 0) {
10359a64e1c5Smrg	    setCgsFore(xw, win, gcWide, new_normal);
10369a64e1c5Smrg	    setCgsBack(xw, win, gcWide, new_revers);
10379a64e1c5Smrg	    setCgsFont(xw, win, gcWide, &(fnts[fWide]));
10389a64e1c5Smrg
10399a64e1c5Smrg	    copyCgs(xw, win, gcWBold, gcWide);
10409a64e1c5Smrg	    setCgsFont(xw, win, gcWBold, &(fnts[fWBold]));
10419a64e1c5Smrg
10429a64e1c5Smrg	    setCgsFore(xw, win, gcWideReverse, new_revers);
10439a64e1c5Smrg	    setCgsBack(xw, win, gcWideReverse, new_normal);
10449a64e1c5Smrg	    setCgsFont(xw, win, gcWideReverse, &(fnts[fWide]));
10459a64e1c5Smrg
10469a64e1c5Smrg	    copyCgs(xw, win, gcWBoldReverse, gcWideReverse);
10479a64e1c5Smrg	    setCgsFont(xw, win, gcWBoldReverse, &(fnts[fWBold]));
10489a64e1c5Smrg	}
10499a64e1c5Smrg    });
10509a64e1c5Smrg}
10519a64e1c5Smrg
10529a64e1c5Smrg#if OPT_TRACE
10539a64e1c5Smrgstatic void
10549a64e1c5Smrgshow_font_misses(const char *name, XTermFonts * fp)
10559a64e1c5Smrg{
10569a64e1c5Smrg    if (fp->fs != 0) {
10579a64e1c5Smrg	if (FontLacksMetrics(fp)) {
10589a64e1c5Smrg	    TRACE(("%s font lacks metrics\n", name));
10599a64e1c5Smrg	} else if (FontIsIncomplete(fp)) {
10609a64e1c5Smrg	    TRACE(("%s font is incomplete\n", name));
10619a64e1c5Smrg	} else {
10629a64e1c5Smrg	    TRACE(("%s font is complete\n", name));
10639a64e1c5Smrg	}
10649a64e1c5Smrg    } else {
10659a64e1c5Smrg	TRACE(("%s font is missing\n", name));
10669a64e1c5Smrg    }
10679a64e1c5Smrg}
10689a64e1c5Smrg#endif
10699a64e1c5Smrg
1070d522f475Smrgint
1071d522f475SmrgxtermLoadFont(XtermWidget xw,
1072d522f475Smrg	      const VTFontNames * fonts,
1073d522f475Smrg	      Bool doresize,
1074d522f475Smrg	      int fontnum)
1075d522f475Smrg{
1076956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1077d522f475Smrg    VTwin *win = WhichVWin(screen);
1078d522f475Smrg
1079d522f475Smrg    VTFontNames myfonts;
1080d522f475Smrg    FontNameProperties *fp;
1081d522f475Smrg    XTermFonts fnts[fMAX];
1082d522f475Smrg    char *tmpname = NULL;
10830bd37d32Smrg    char *normal = NULL;
1084956cc18dSsnj    Boolean proportional = False;
1085956cc18dSsnj    fontWarningTypes warn[fMAX];
1086956cc18dSsnj    int j;
1087d522f475Smrg
1088d522f475Smrg    memset(&myfonts, 0, sizeof(myfonts));
1089d522f475Smrg    memset(fnts, 0, sizeof(fnts));
1090d522f475Smrg
1091d522f475Smrg    if (fonts != 0)
1092d522f475Smrg	myfonts = *fonts;
1093956cc18dSsnj    if (!check_fontname(myfonts.f_n))
1094d522f475Smrg	return 0;
1095d522f475Smrg
1096956cc18dSsnj    /*
1097956cc18dSsnj     * Check the font names against the resource values, to see which were
1098956cc18dSsnj     * derived in a previous call.  If so, we'll only warn about those if
1099956cc18dSsnj     * the warning level is set to "always".
1100956cc18dSsnj     */
1101956cc18dSsnj    for (j = 0; j < fMAX; ++j) {
1102956cc18dSsnj	warn[j] = fwAlways;
1103956cc18dSsnj    }
1104956cc18dSsnj#define CmpResource(field, index) \
1105956cc18dSsnj    if (same_font_name(screen->menu_font_names[fontnum][index], myfonts.field)) \
1106956cc18dSsnj	warn[index] = fwResource
1107956cc18dSsnj
1108956cc18dSsnj    CmpResource(f_n, fNorm);
1109956cc18dSsnj    if (fontnum == fontMenu_default) {
1110956cc18dSsnj	CmpResource(f_b, fBold);
1111956cc18dSsnj#if OPT_WIDE_CHARS
1112956cc18dSsnj	CmpResource(f_b, fWide);
1113956cc18dSsnj	CmpResource(f_b, fWBold);
1114956cc18dSsnj#endif
1115956cc18dSsnj    }
1116956cc18dSsnj
1117d522f475Smrg    if (fontnum == fontMenu_fontescape
1118d522f475Smrg	&& myfonts.f_n != screen->MenuFontName(fontnum)) {
1119d522f475Smrg	if ((tmpname = x_strdup(myfonts.f_n)) == 0)
1120d522f475Smrg	    return 0;
1121d522f475Smrg    }
1122d522f475Smrg
1123d522f475Smrg    TRACE(("Begin Cgs - xtermLoadFont(%s)\n", myfonts.f_n));
1124d522f475Smrg    releaseWindowGCs(xw, win);
1125d522f475Smrg
1126956cc18dSsnj#define DbgResource(name, field, index) \
1127956cc18dSsnj    TRACE(("xtermLoadFont #%d "name" %s%s\n", \
1128956cc18dSsnj    	   fontnum, \
1129956cc18dSsnj	   (warn[index] == fwResource) ? "*" : " ", \
1130492d43a5Smrg	   NonNull(myfonts.field)))
1131956cc18dSsnj    DbgResource("normal", f_n, fNorm);
1132956cc18dSsnj    DbgResource("bold  ", f_b, fBold);
1133d522f475Smrg#if OPT_WIDE_CHARS
1134956cc18dSsnj    DbgResource("wide  ", f_w, fWide);
1135956cc18dSsnj    DbgResource("w/bold", f_wb, fWBold);
1136d522f475Smrg#endif
1137d522f475Smrg
1138e39b573cSmrg    /*
1139e39b573cSmrg     * If we are opening the default font, and it happens to be missing, force
1140e39b573cSmrg     * that to the compiled-in default font, e.g., "fixed".  If we cannot open
1141e39b573cSmrg     * the font, disable it from the menu.
1142e39b573cSmrg     */
1143e39b573cSmrg    if (!xtermOpenFont(xw,
1144e39b573cSmrg		       myfonts.f_n,
1145e39b573cSmrg		       &fnts[fNorm],
1146e39b573cSmrg		       warn[fNorm],
1147e39b573cSmrg		       (fontnum == fontMenu_default))) {
1148e39b573cSmrg	SetItemSensitivity(fontMenuEntries[fontnum].widget, False);
1149d522f475Smrg	goto bad;
1150e39b573cSmrg    }
1151d522f475Smrg
11520bd37d32Smrg    normal = x_strdup(myfonts.f_n);
1153956cc18dSsnj    if (!check_fontname(myfonts.f_b)) {
1154956cc18dSsnj	warn[fBold] = fwAlways;
11550bd37d32Smrg	fp = get_font_name_props(screen->display, fnts[fNorm].fs, &normal);
1156d522f475Smrg	if (fp != 0) {
11579a64e1c5Smrg	    FREE_FNAME(f_b);
1158d522f475Smrg	    myfonts.f_b = bold_font_name(fp, fp->average_width);
1159956cc18dSsnj	    if (!xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], fwAlways, False)) {
11609a64e1c5Smrg		FREE_FNAME(f_b);
1161d522f475Smrg		myfonts.f_b = bold_font_name(fp, -1);
1162956cc18dSsnj		xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], fwAlways, False);
1163d522f475Smrg	    }
1164492d43a5Smrg	    TRACE(("...derived bold '%s'\n", NonNull(myfonts.f_b)));
1165d522f475Smrg	}
1166d522f475Smrg	if (fp == 0 || fnts[fBold].fs == 0) {
1167d522f475Smrg	    xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]);
1168d522f475Smrg	    TRACE(("...cannot load a matching bold font\n"));
11699a64e1c5Smrg	} else if (comparable_metrics(fnts[fNorm].fs, fnts[fBold].fs)
11709a64e1c5Smrg		   && same_font_size(xw, fnts[fNorm].fs, fnts[fBold].fs)
1171d522f475Smrg		   && got_bold_font(screen->display, fnts[fBold].fs, myfonts.f_b)) {
1172d522f475Smrg	    TRACE(("...got a matching bold font\n"));
1173d522f475Smrg	    cache_menu_font_name(screen, fontnum, fBold, myfonts.f_b);
1174d522f475Smrg	} else {
1175d522f475Smrg	    xtermCloseFont(xw, &fnts[fBold]);
1176d522f475Smrg	    fnts[fBold] = fnts[fNorm];
1177d522f475Smrg	    TRACE(("...did not get a matching bold font\n"));
1178d522f475Smrg	}
1179956cc18dSsnj    } else if (!xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], warn[fBold], False)) {
1180d522f475Smrg	xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]);
1181956cc18dSsnj	warn[fBold] = fwAlways;
1182492d43a5Smrg	TRACE(("...cannot load bold font '%s'\n", NonNull(myfonts.f_b)));
1183d522f475Smrg    } else {
1184d522f475Smrg	cache_menu_font_name(screen, fontnum, fBold, myfonts.f_b);
1185d522f475Smrg    }
1186d522f475Smrg
1187d522f475Smrg    /*
1188d522f475Smrg     * If there is no widefont specified, fake it by doubling AVERAGE_WIDTH
1189d522f475Smrg     * of normal fonts XLFD, and asking for it.  This plucks out 18x18ja
1190d522f475Smrg     * and 12x13ja as the corresponding fonts for 9x18 and 6x13.
1191d522f475Smrg     */
1192d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
11930bd37d32Smrg	Boolean derived;
11940bd37d32Smrg	char *bold = NULL;
1195d522f475Smrg
1196956cc18dSsnj	if (check_fontname(myfonts.f_w)) {
1197d522f475Smrg	    cache_menu_font_name(screen, fontnum, fWide, myfonts.f_w);
1198e39b573cSmrg	} else if (screen->utf8_fonts && !is_double_width_font(fnts[fNorm].fs)) {
11999a64e1c5Smrg	    FREE_FNAME(f_w);
12000bd37d32Smrg	    fp = get_font_name_props(screen->display, fnts[fNorm].fs, &normal);
1201d522f475Smrg	    if (fp != 0) {
1202d522f475Smrg		myfonts.f_w = wide_font_name(fp);
1203956cc18dSsnj		warn[fWide] = fwAlways;
1204d522f475Smrg		TRACE(("...derived wide %s\n", NonNull(myfonts.f_w)));
1205d522f475Smrg		cache_menu_font_name(screen, fontnum, fWide, myfonts.f_w);
1206d522f475Smrg	    }
1207d522f475Smrg	}
1208d522f475Smrg
1209956cc18dSsnj	if (check_fontname(myfonts.f_w)) {
1210956cc18dSsnj	    (void) xtermOpenFont(xw, myfonts.f_w, &fnts[fWide], warn[fWide], False);
1211d522f475Smrg	} else {
1212d522f475Smrg	    xtermCopyFontInfo(&fnts[fWide], &fnts[fNorm]);
1213956cc18dSsnj	    warn[fWide] = fwAlways;
1214d522f475Smrg	}
1215d522f475Smrg
1216d522f475Smrg	derived = False;
1217956cc18dSsnj	if (!check_fontname(myfonts.f_wb)) {
12180bd37d32Smrg	    fp = get_font_name_props(screen->display, fnts[fBold].fs, &bold);
1219d522f475Smrg	    if (fp != 0) {
1220d522f475Smrg		myfonts.f_wb = widebold_font_name(fp);
1221956cc18dSsnj		warn[fWBold] = fwAlways;
1222d522f475Smrg		derived = True;
1223d522f475Smrg	    }
1224d522f475Smrg	}
1225d522f475Smrg
1226956cc18dSsnj	if (check_fontname(myfonts.f_wb)) {
1227d522f475Smrg
1228e39b573cSmrg	    xtermOpenFont(xw,
1229e39b573cSmrg			  myfonts.f_wb,
1230e39b573cSmrg			  &fnts[fWBold],
1231e39b573cSmrg			  (screen->utf8_fonts
1232e39b573cSmrg			   ? warn[fWBold]
12330bd37d32Smrg			   : (fontWarningTypes) (xw->misc.fontWarnings + 1)),
1234e39b573cSmrg			  False);
1235d522f475Smrg
1236d522f475Smrg	    if (derived
1237d522f475Smrg		&& !compatibleWideCounts(fnts[fWide].fs, fnts[fWBold].fs)) {
1238d522f475Smrg		xtermCloseFont(xw, &fnts[fWBold]);
1239d522f475Smrg	    }
1240d522f475Smrg	    if (fnts[fWBold].fs == 0) {
12419a64e1c5Smrg		FREE_FNAME(f_wb);
1242e39b573cSmrg		if (IsEmpty(myfonts.f_w)) {
12439a64e1c5Smrg		    myfonts.f_wb = x_strdup(myfonts.f_b);
1244e39b573cSmrg		    warn[fWBold] = fwAlways;
1245e39b573cSmrg		    xtermCopyFontInfo(&fnts[fWBold], &fnts[fBold]);
1246e39b573cSmrg		    TRACE(("...cannot load wide-bold, use bold %s\n",
1247e39b573cSmrg			   NonNull(myfonts.f_b)));
1248e39b573cSmrg		} else {
12499a64e1c5Smrg		    myfonts.f_wb = x_strdup(myfonts.f_w);
1250e39b573cSmrg		    warn[fWBold] = fwAlways;
1251e39b573cSmrg		    xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
1252e39b573cSmrg		    TRACE(("...cannot load wide-bold, use wide %s\n",
1253e39b573cSmrg			   NonNull(myfonts.f_w)));
1254e39b573cSmrg		}
1255d522f475Smrg	    } else {
1256d522f475Smrg		TRACE(("...%s wide/bold %s\n",
1257d522f475Smrg		       derived ? "derived" : "given",
1258d522f475Smrg		       NonNull(myfonts.f_wb)));
1259d522f475Smrg		cache_menu_font_name(screen, fontnum, fWBold, myfonts.f_wb);
1260d522f475Smrg	    }
1261d522f475Smrg	} else if (is_double_width_font(fnts[fBold].fs)) {
1262d522f475Smrg	    xtermCopyFontInfo(&fnts[fWBold], &fnts[fBold]);
1263956cc18dSsnj	    warn[fWBold] = fwAlways;
1264d522f475Smrg	    TRACE(("...bold font is double-width, use it %s\n", NonNull(myfonts.f_b)));
1265d522f475Smrg	} else {
1266d522f475Smrg	    xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
1267956cc18dSsnj	    warn[fWBold] = fwAlways;
1268d522f475Smrg	    TRACE(("...cannot load wide bold font, use wide %s\n", NonNull(myfonts.f_w)));
1269d522f475Smrg	}
1270d522f475Smrg
12710bd37d32Smrg	free(bold);
12720bd37d32Smrg
1273d522f475Smrg	if (EmptyFont(fnts[fWBold].fs))
1274d522f475Smrg	    goto bad;		/* can't use a 0-sized font */
1275d522f475Smrg    });
1276d522f475Smrg
1277d522f475Smrg    /*
1278d522f475Smrg     * Most of the time this call to load the font will succeed, even if
1279d522f475Smrg     * there is no wide font :  the X server doubles the width of the
1280d522f475Smrg     * normal font, or similar.
1281d522f475Smrg     *
1282d522f475Smrg     * But if it did fail for some reason, then nevermind.
1283d522f475Smrg     */
1284d522f475Smrg    if (EmptyFont(fnts[fBold].fs))
1285d522f475Smrg	goto bad;		/* can't use a 0-sized font */
1286d522f475Smrg
1287d522f475Smrg    if (!same_font_size(xw, fnts[fNorm].fs, fnts[fBold].fs)
1288d522f475Smrg	&& (is_fixed_font(fnts[fNorm].fs) && is_fixed_font(fnts[fBold].fs))) {
1289d522f475Smrg	TRACE(("...ignoring mismatched normal/bold fonts\n"));
1290d522f475Smrg	xtermCloseFont(xw, &fnts[fBold]);
1291d522f475Smrg	xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]);
1292d522f475Smrg    }
1293d522f475Smrg
1294d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
1295d522f475Smrg	if (fnts[fWide].fs != 0
1296d522f475Smrg	    && fnts[fWBold].fs != 0
12979a64e1c5Smrg	    && (!comparable_metrics(fnts[fWide].fs, fnts[fWBold].fs)
12989a64e1c5Smrg		|| (!same_font_size(xw, fnts[fWide].fs, fnts[fWBold].fs)
12999a64e1c5Smrg		    && is_fixed_font(fnts[fWide].fs)
13009a64e1c5Smrg		    && is_fixed_font(fnts[fWBold].fs)))) {
1301d522f475Smrg	    TRACE(("...ignoring mismatched normal/bold wide fonts\n"));
1302d522f475Smrg	    xtermCloseFont(xw, &fnts[fWBold]);
1303d522f475Smrg	    xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
1304d522f475Smrg	}
1305d522f475Smrg    });
1306d522f475Smrg
1307d522f475Smrg    /*
1308d522f475Smrg     * Normal/bold fonts should be the same width.  Also, the min/max
1309d522f475Smrg     * values should be the same.
1310d522f475Smrg     */
1311d522f475Smrg    if (!is_fixed_font(fnts[fNorm].fs)
1312d522f475Smrg	|| !is_fixed_font(fnts[fBold].fs)
1313d522f475Smrg	|| fnts[fNorm].fs->max_bounds.width != fnts[fBold].fs->max_bounds.width) {
1314d522f475Smrg	TRACE(("Proportional font! normal %d/%d, bold %d/%d\n",
1315d522f475Smrg	       fnts[fNorm].fs->min_bounds.width,
1316d522f475Smrg	       fnts[fNorm].fs->max_bounds.width,
1317d522f475Smrg	       fnts[fBold].fs->min_bounds.width,
1318d522f475Smrg	       fnts[fBold].fs->max_bounds.width));
1319d522f475Smrg	proportional = True;
1320d522f475Smrg    }
1321d522f475Smrg
1322d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
1323d522f475Smrg	if (fnts[fWide].fs != 0
1324d522f475Smrg	    && fnts[fWBold].fs != 0
1325d522f475Smrg	    && (!is_fixed_font(fnts[fWide].fs)
1326d522f475Smrg		|| !is_fixed_font(fnts[fWBold].fs)
1327d522f475Smrg		|| fnts[fWide].fs->max_bounds.width != fnts[fWBold].fs->max_bounds.width)) {
1328d522f475Smrg	    TRACE(("Proportional font! wide %d/%d, wide bold %d/%d\n",
1329d522f475Smrg		   fnts[fWide].fs->min_bounds.width,
1330d522f475Smrg		   fnts[fWide].fs->max_bounds.width,
1331d522f475Smrg		   fnts[fWBold].fs->min_bounds.width,
1332d522f475Smrg		   fnts[fWBold].fs->max_bounds.width));
1333d522f475Smrg	    proportional = True;
1334d522f475Smrg	}
1335d522f475Smrg    });
1336d522f475Smrg
1337d522f475Smrg    /* TODO : enforce that the width of the wide font is 2* the width
1338d522f475Smrg       of the narrow font */
1339d522f475Smrg
1340d522f475Smrg    /*
1341d522f475Smrg     * If we're switching fonts, free the old ones.  Otherwise we'll leak
1342d522f475Smrg     * the memory that is associated with the old fonts.  The
1343d522f475Smrg     * XLoadQueryFont call allocates a new XFontStruct.
1344d522f475Smrg     */
1345d522f475Smrg    xtermCloseFonts(xw, screen->fnts);
13469a64e1c5Smrg#if OPT_WIDE_ATTRS
13479a64e1c5Smrg    xtermCloseFonts(xw, screen->ifnts);
13489a64e1c5Smrg    screen->ifnts_ok = False;
13499a64e1c5Smrg#endif
1350d522f475Smrg
1351d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fNorm]), &fnts[fNorm]);
1352d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fBold]), &fnts[fBold]);
1353d522f475Smrg#if OPT_WIDE_CHARS
1354d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fWide]), &fnts[fWide]);
1355d522f475Smrg    if (fnts[fWBold].fs == NULL)
1356d522f475Smrg	xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
1357d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fWBold]), &fnts[fWBold]);
1358d522f475Smrg#endif
1359d522f475Smrg
13609a64e1c5Smrg    xtermUpdateFontGCs(xw, screen->fnts);
1361d522f475Smrg
136220d2c4d2Smrg#if OPT_BOX_CHARS
136320d2c4d2Smrg    screen->allow_packing = proportional;
136420d2c4d2Smrg    setupPackedFonts(xw);
136520d2c4d2Smrg#endif
136620d2c4d2Smrg    screen->fnt_prop = (Boolean) (proportional && !(screen->force_packed));
1367d522f475Smrg    screen->fnt_boxes = True;
1368d522f475Smrg
1369d522f475Smrg#if OPT_BOX_CHARS
1370d522f475Smrg    /*
13719a64e1c5Smrg     * xterm uses character positions 1-31 of a font for the line-drawing
1372d522f475Smrg     * characters.  Check that they are all present.  The null character
1373d522f475Smrg     * (0) is special, and is not used.
1374d522f475Smrg     */
1375d522f475Smrg#if OPT_RENDERFONT
1376d522f475Smrg    if (UsingRenderFont(xw)) {
1377d522f475Smrg	/*
1378d522f475Smrg	 * FIXME: we shouldn't even be here if we're using Xft.
1379d522f475Smrg	 */
1380d522f475Smrg	screen->fnt_boxes = False;
1381d522f475Smrg	TRACE(("assume Xft missing line-drawing chars\n"));
1382d522f475Smrg    } else
1383d522f475Smrg#endif
1384d522f475Smrg    {
1385d522f475Smrg	unsigned ch;
1386d522f475Smrg
13879a64e1c5Smrg#if OPT_TRACE
13889a64e1c5Smrg#define TRACE_MISS(index) show_font_misses(#index, &fnts[index])
13899a64e1c5Smrg	TRACE_MISS(fNorm);
13909a64e1c5Smrg	TRACE_MISS(fBold);
13919a64e1c5Smrg#if OPT_WIDE_CHARS
13929a64e1c5Smrg	TRACE_MISS(fWide);
13939a64e1c5Smrg	TRACE_MISS(fWBold);
13949a64e1c5Smrg#endif
13959a64e1c5Smrg#endif
1396fa3f02f3Smrg
1397d522f475Smrg	for (ch = 1; ch < 32; ch++) {
1398d522f475Smrg	    unsigned n = ch;
1399d522f475Smrg#if OPT_WIDE_CHARS
1400d522f475Smrg	    if (screen->utf8_mode || screen->unicode_font) {
1401d522f475Smrg		n = dec2ucs(ch);
1402d522f475Smrg		if (n == UCS_REPL)
1403d522f475Smrg		    continue;
1404d522f475Smrg	    }
1405d522f475Smrg#endif
1406956cc18dSsnj	    if (IsXtermMissingChar(screen, n, &fnts[fNorm])) {
1407d522f475Smrg		TRACE(("missing normal char #%d\n", n));
1408d522f475Smrg		screen->fnt_boxes = False;
1409d522f475Smrg		break;
1410d522f475Smrg	    }
1411956cc18dSsnj	    if (IsXtermMissingChar(screen, n, &fnts[fBold])) {
1412d522f475Smrg		TRACE(("missing bold char #%d\n", n));
1413d522f475Smrg		screen->fnt_boxes = False;
1414d522f475Smrg		break;
1415d522f475Smrg	    }
1416d522f475Smrg	}
1417d522f475Smrg    }
1418d522f475Smrg    TRACE(("Will %suse internal line-drawing characters\n",
1419d522f475Smrg	   screen->fnt_boxes ? "not " : ""));
1420d522f475Smrg#endif
1421d522f475Smrg
1422d522f475Smrg    if (screen->always_bold_mode) {
1423d522f475Smrg	screen->enbolden = screen->bold_mode;
1424d522f475Smrg    } else {
1425d522f475Smrg	screen->enbolden = screen->bold_mode
1426d522f475Smrg	    && ((fnts[fNorm].fs == fnts[fBold].fs)
1427d522f475Smrg		|| same_font_name(normal, myfonts.f_b));
1428d522f475Smrg    }
1429d522f475Smrg    TRACE(("Will %suse 1-pixel offset/overstrike to simulate bold\n",
1430d522f475Smrg	   screen->enbolden ? "" : "not "));
1431d522f475Smrg
1432d522f475Smrg    set_menu_font(False);
1433d522f475Smrg    screen->menu_font_number = fontnum;
1434d522f475Smrg    set_menu_font(True);
1435d522f475Smrg    if (tmpname) {		/* if setting escape or sel */
1436d522f475Smrg	if (screen->MenuFontName(fontnum))
14379a64e1c5Smrg	    FREE_STRING(screen->MenuFontName(fontnum));
1438d522f475Smrg	screen->MenuFontName(fontnum) = tmpname;
1439d522f475Smrg	if (fontnum == fontMenu_fontescape) {
1440d522f475Smrg	    SetItemSensitivity(fontMenuEntries[fontMenu_fontescape].widget,
1441d522f475Smrg			       True);
1442d522f475Smrg	}
1443d522f475Smrg#if OPT_SHIFT_FONTS
1444d522f475Smrg	screen->menu_font_sizes[fontnum] = FontSize(fnts[fNorm].fs);
1445d522f475Smrg#endif
1446d522f475Smrg    }
14470bd37d32Smrg    if (normal)
14480bd37d32Smrg	free(normal);
1449d522f475Smrg    set_cursor_gcs(xw);
1450d522f475Smrg    xtermUpdateFontInfo(xw, doresize);
1451d522f475Smrg    TRACE(("Success Cgs - xtermLoadFont\n"));
1452fa3f02f3Smrg#if OPT_REPORT_FONTS
1453fa3f02f3Smrg    reportVTFontInfo(xw, fontnum);
14549a64e1c5Smrg#endif
14559a64e1c5Smrg    FREE_FNAME(f_n);
14569a64e1c5Smrg    FREE_FNAME(f_b);
14579a64e1c5Smrg#if OPT_WIDE_CHARS
14589a64e1c5Smrg    FREE_FNAME(f_w);
14599a64e1c5Smrg    FREE_FNAME(f_wb);
14609a64e1c5Smrg#endif
14619a64e1c5Smrg    if (fnts[fNorm].fn == fnts[fBold].fn) {
14629a64e1c5Smrg	free(fnts[fNorm].fn);
14639a64e1c5Smrg    } else {
14649a64e1c5Smrg	free(fnts[fNorm].fn);
14659a64e1c5Smrg	free(fnts[fBold].fn);
14669a64e1c5Smrg    }
14679a64e1c5Smrg#if OPT_WIDE_CHARS
14689a64e1c5Smrg    free(fnts[fWide].fn);
14699a64e1c5Smrg    free(fnts[fWBold].fn);
1470fa3f02f3Smrg#endif
1471d522f475Smrg    return 1;
1472d522f475Smrg
1473d522f475Smrg  bad:
14740bd37d32Smrg    if (normal)
14750bd37d32Smrg	free(normal);
1476d522f475Smrg    if (tmpname)
1477d522f475Smrg	free(tmpname);
14780bd37d32Smrg
14790bd37d32Smrg#if OPT_RENDERFONT
14809a64e1c5Smrg    if (fontnum == fontMenu_fontsel) {
14819a64e1c5Smrg	int old_fontnum = screen->menu_font_number;
14829a64e1c5Smrg#if OPT_TOOLBAR
14839a64e1c5Smrg	SetItemSensitivity(fontMenuEntries[fontnum].widget, True);
14849a64e1c5Smrg#endif
14859a64e1c5Smrg	Bell(xw, XkbBI_MinorError, 0);
14869a64e1c5Smrg	myfonts.f_n = screen->MenuFontName(old_fontnum);
14879a64e1c5Smrg	return xtermLoadFont(xw, &myfonts, doresize, old_fontnum);
14889a64e1c5Smrg    } else if (x_strcasecmp(myfonts.f_n, DEFFONT)) {
14890bd37d32Smrg	int code;
14900bd37d32Smrg
14910bd37d32Smrg	myfonts.f_n = DEFFONT;
14920bd37d32Smrg	TRACE(("...recovering for TrueType fonts\n"));
14930bd37d32Smrg	code = xtermLoadFont(xw, &myfonts, doresize, fontnum);
14940bd37d32Smrg	if (code) {
14950bd37d32Smrg	    SetItemSensitivity(fontMenuEntries[fontnum].widget,
14960bd37d32Smrg			       UsingRenderFont(xw));
14970bd37d32Smrg	    TRACE(("...recovered size %dx%d\n",
14980bd37d32Smrg		   FontHeight(screen),
14990bd37d32Smrg		   FontWidth(screen)));
15000bd37d32Smrg	}
15010bd37d32Smrg	return code;
15020bd37d32Smrg    }
15030bd37d32Smrg#endif
15040bd37d32Smrg
1505d522f475Smrg    releaseWindowGCs(xw, win);
1506d522f475Smrg
1507d522f475Smrg    xtermCloseFonts(xw, fnts);
1508d522f475Smrg    TRACE(("Fail Cgs - xtermLoadFont\n"));
1509d522f475Smrg    return 0;
1510d522f475Smrg}
1511d522f475Smrg
15129a64e1c5Smrg#if OPT_WIDE_ATTRS
15139a64e1c5Smrg/*
15149a64e1c5Smrg * (Attempt to) load matching italics for the current normal/bold/etc fonts.
15159a64e1c5Smrg * If the attempt fails for a given style, use the non-italic font.
15169a64e1c5Smrg */
15179a64e1c5Smrgvoid
15189a64e1c5SmrgxtermLoadItalics(XtermWidget xw)
15199a64e1c5Smrg{
15209a64e1c5Smrg    TScreen *screen = TScreenOf(xw);
15219a64e1c5Smrg    FontNameProperties *fp;
15229a64e1c5Smrg    char *name;
15239a64e1c5Smrg    int n;
15249a64e1c5Smrg
15259a64e1c5Smrg    if (!screen->ifnts_ok) {
15269a64e1c5Smrg	screen->ifnts_ok = True;
15279a64e1c5Smrg	for (n = 0; n < fMAX; ++n) {
15289a64e1c5Smrg	    /*
15299a64e1c5Smrg	     * FIXME - need to handle font-leaks
15309a64e1c5Smrg	     */
15319a64e1c5Smrg	    screen->ifnts[n].fs = 0;
15329a64e1c5Smrg	    if (screen->fnts[n].fs != 0 &&
15339a64e1c5Smrg		(fp = get_font_name_props(screen->display,
15349a64e1c5Smrg					  screen->fnts[n].fs,
15359a64e1c5Smrg					  0)) != 0) {
15369a64e1c5Smrg		if ((name = italic_font_name(fp, fp->average_width)) != 0) {
15379a64e1c5Smrg		    TRACE(("xtermLoadItalics #%d %s\n", n, name));
15389a64e1c5Smrg		    (void) xtermOpenFont(xw,
15399a64e1c5Smrg					 name,
15409a64e1c5Smrg					 &(screen->ifnts[n]),
15419a64e1c5Smrg					 fwResource,
15429a64e1c5Smrg					 False);
15439a64e1c5Smrg#if OPT_TRACE
15449a64e1c5Smrg		    {
15459a64e1c5Smrg			XFontStruct *fs =
15469a64e1c5Smrg			screen->ifnts[n].fs;
15479a64e1c5Smrg			if (fs != 0) {
15489a64e1c5Smrg			    TRACE(("...actual size %dx%d (ascent %d, descent %d)\n",
15499a64e1c5Smrg				   fs->ascent +
15509a64e1c5Smrg				   fs->descent,
15519a64e1c5Smrg				   fs->max_bounds.width,
15529a64e1c5Smrg				   fs->ascent,
15539a64e1c5Smrg				   fs->descent));
15549a64e1c5Smrg			}
15559a64e1c5Smrg		    }
15569a64e1c5Smrg#endif
15579a64e1c5Smrg		    free(name);
15589a64e1c5Smrg		}
15599a64e1c5Smrg	    }
15609a64e1c5Smrg	}
15619a64e1c5Smrg    }
15629a64e1c5Smrg}
15639a64e1c5Smrg#endif
15649a64e1c5Smrg
1565d522f475Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
1566d522f475Smrg/*
1567d522f475Smrg * Collect font-names that we can modify with the load-vt-fonts() action.
1568d522f475Smrg */
1569d522f475Smrg#define MERGE_SUBFONT(src,dst,name) \
1570492d43a5Smrg	if (IsEmpty(dst.name)) { \
1571d522f475Smrg	    TRACE(("MERGE_SUBFONT " #dst "." #name " merge %s\n", NonNull(src.name))); \
15729a64e1c5Smrg	    dst.name = x_strdup(src.name); \
1573d522f475Smrg	} else { \
1574d522f475Smrg	    TRACE(("MERGE_SUBFONT " #dst "." #name " found %s\n", NonNull(dst.name))); \
1575d522f475Smrg	}
1576d522f475Smrg
1577e39b573cSmrg#define INFER_SUBFONT(src,dst,name) \
1578e39b573cSmrg	if (IsEmpty(dst.name)) { \
1579e39b573cSmrg	    TRACE(("INFER_SUBFONT " #dst "." #name " will infer\n")); \
1580e39b573cSmrg	    dst.name = x_strdup(""); \
1581e39b573cSmrg	} else { \
1582e39b573cSmrg	    TRACE(("INFER_SUBFONT " #dst "." #name " found %s\n", NonNull(dst.name))); \
1583e39b573cSmrg	}
1584e39b573cSmrg
15859a64e1c5Smrg#define FREE_MENU_FONTS(dst) \
15869a64e1c5Smrg	TRACE(("FREE_MENU_FONTS " #dst "\n")); \
15879a64e1c5Smrg	for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \
15889a64e1c5Smrg	    for (m = 0; m < fMAX; ++m) { \
15899a64e1c5Smrg		FREE_STRING(dst.menu_font_names[n][m]); \
15909a64e1c5Smrg		dst.menu_font_names[n][m] = 0; \
15919a64e1c5Smrg	    } \
15929a64e1c5Smrg	}
15939a64e1c5Smrg
1594d522f475Smrg#define COPY_MENU_FONTS(src,dst) \
1595d522f475Smrg	TRACE(("COPY_MENU_FONTS " #src " to " #dst "\n")); \
1596d522f475Smrg	for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \
1597d522f475Smrg	    for (m = 0; m < fMAX; ++m) { \
15989a64e1c5Smrg		FREE_STRING(dst.menu_font_names[n][m]); \
1599492d43a5Smrg		dst.menu_font_names[n][m] = x_strdup(src.menu_font_names[n][m]); \
1600d522f475Smrg	    } \
1601e39b573cSmrg	    TRACE((".. " #dst ".menu_fonts_names[%d] = %s\n", n, dst.menu_font_names[n][fNorm])); \
1602e39b573cSmrg	}
1603e39b573cSmrg
16049a64e1c5Smrg#define COPY_DEFAULT_FONTS(target, source) \
16059a64e1c5Smrg	xtermCopyVTFontNames(&target.default_font, &source.default_font)
16069a64e1c5Smrg
16079a64e1c5Smrgstatic void
16089a64e1c5SmrgxtermCopyVTFontNames(VTFontNames * target, VTFontNames * source)
16099a64e1c5Smrg{
16109a64e1c5Smrg    target->f_n = x_strdup(source->f_n);
16119a64e1c5Smrg    target->f_b = x_strdup(source->f_b);
16129a64e1c5Smrg#if OPT_WIDE_CHARS
16139a64e1c5Smrg    target->f_w = x_strdup(source->f_w);
16149a64e1c5Smrg    target->f_wb = x_strdup(source->f_wb);
16159a64e1c5Smrg#endif
16169a64e1c5Smrg}
16179a64e1c5Smrg
1618e39b573cSmrgvoid
1619e39b573cSmrgxtermSaveVTFonts(XtermWidget xw)
1620e39b573cSmrg{
1621e39b573cSmrg    TScreen *screen = TScreenOf(xw);
1622e39b573cSmrg    Cardinal n, m;
1623e39b573cSmrg
1624e39b573cSmrg    if (!screen->savedVTFonts) {
1625e39b573cSmrg
1626e39b573cSmrg	screen->savedVTFonts = True;
1627e39b573cSmrg	TRACE(("xtermSaveVTFonts saving original\n"));
16289a64e1c5Smrg	COPY_DEFAULT_FONTS(screen->cacheVTFonts, xw->misc);
1629e39b573cSmrg	COPY_MENU_FONTS(xw->screen, screen->cacheVTFonts);
1630e39b573cSmrg    }
1631e39b573cSmrg}
1632e39b573cSmrg
1633e39b573cSmrg#define SAME_STRING(x,y) ((x) == (y) || ((x) && (y) && !strcmp(x, y)))
1634e39b573cSmrg#define SAME_MEMBER(n)   SAME_STRING(a->n, b->n)
1635e39b573cSmrg
1636e39b573cSmrgstatic Boolean
1637e39b573cSmrgsameSubResources(SubResourceRec * a, SubResourceRec * b)
1638e39b573cSmrg{
1639e39b573cSmrg    Boolean result = True;
1640e39b573cSmrg    int n;
1641e39b573cSmrg
1642e39b573cSmrg    if (!SAME_MEMBER(default_font.f_n)
1643e39b573cSmrg	|| !SAME_MEMBER(default_font.f_b)
16440bd37d32Smrg#if OPT_WIDE_CHARS
1645e39b573cSmrg	|| !SAME_MEMBER(default_font.f_w)
16460bd37d32Smrg	|| !SAME_MEMBER(default_font.f_wb)
16470bd37d32Smrg#endif
16480bd37d32Smrg	) {
1649e39b573cSmrg	TRACE(("sameSubResources: default_font differs\n"));
1650e39b573cSmrg	result = False;
1651e39b573cSmrg    } else {
1652e39b573cSmrg	for (n = 0; n < NMENUFONTS; ++n) {
1653e39b573cSmrg	    if (!SAME_MEMBER(menu_font_names[n][fNorm])) {
1654e39b573cSmrg		TRACE(("sameSubResources: menu_font_names[%d] differs\n", n));
1655e39b573cSmrg		result = False;
1656e39b573cSmrg		break;
1657e39b573cSmrg	    }
1658d522f475Smrg	}
1659e39b573cSmrg    }
1660e39b573cSmrg
1661e39b573cSmrg    return result;
1662e39b573cSmrg}
1663d522f475Smrg
1664d522f475Smrg/*
1665d522f475Smrg * Load the "VT" font names from the given subresource name/class.  These
1666d522f475Smrg * correspond to the VT100 resources.
1667d522f475Smrg */
1668d522f475Smrgstatic Bool
166920d2c4d2SmrgxtermLoadVTFonts(XtermWidget xw, String myName, String myClass)
1670d522f475Smrg{
1671e39b573cSmrg    SubResourceRec subresourceRec;
1672e39b573cSmrg    SubResourceRec referenceRec;
1673d522f475Smrg
1674d522f475Smrg    /*
1675d522f475Smrg     * These are duplicates of the VT100 font resources, but with a special
1676d522f475Smrg     * application/classname passed in to distinguish them.
1677d522f475Smrg     */
1678d522f475Smrg    static XtResource font_resources[] =
1679d522f475Smrg    {
1680d522f475Smrg	Sres(XtNfont, XtCFont, default_font.f_n, DEFFONT),
1681d522f475Smrg	Sres(XtNboldFont, XtCBoldFont, default_font.f_b, DEFBOLDFONT),
1682d522f475Smrg#if OPT_WIDE_CHARS
1683d522f475Smrg	Sres(XtNwideFont, XtCWideFont, default_font.f_w, DEFWIDEFONT),
1684d522f475Smrg	Sres(XtNwideBoldFont, XtCWideBoldFont, default_font.f_wb, DEFWIDEBOLDFONT),
1685d522f475Smrg#endif
1686d522f475Smrg	Sres(XtNfont1, XtCFont1, MenuFontName(fontMenu_font1), NULL),
1687d522f475Smrg	Sres(XtNfont2, XtCFont2, MenuFontName(fontMenu_font2), NULL),
1688d522f475Smrg	Sres(XtNfont3, XtCFont3, MenuFontName(fontMenu_font3), NULL),
1689d522f475Smrg	Sres(XtNfont4, XtCFont4, MenuFontName(fontMenu_font4), NULL),
1690d522f475Smrg	Sres(XtNfont5, XtCFont5, MenuFontName(fontMenu_font5), NULL),
1691d522f475Smrg	Sres(XtNfont6, XtCFont6, MenuFontName(fontMenu_font6), NULL),
1692d522f475Smrg    };
1693d522f475Smrg    Cardinal n, m;
1694d522f475Smrg    Bool status = True;
1695956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1696d522f475Smrg
1697e39b573cSmrg    TRACE(("called xtermLoadVTFonts(name=%s, class=%s)\n",
1698e39b573cSmrg	   NonNull(myName), NonNull(myClass)));
1699d522f475Smrg
1700e39b573cSmrg    xtermSaveVTFonts(xw);
1701d522f475Smrg
1702492d43a5Smrg    if (IsEmpty(myName)) {
1703d522f475Smrg	TRACE(("xtermLoadVTFonts restoring original\n"));
17049a64e1c5Smrg	COPY_DEFAULT_FONTS(xw->misc, screen->cacheVTFonts);
17059a64e1c5Smrg	FREE_MENU_FONTS(xw->screen);
1706e39b573cSmrg	COPY_MENU_FONTS(screen->cacheVTFonts, xw->screen);
1707d522f475Smrg    } else {
1708d522f475Smrg	TRACE(("xtermLoadVTFonts(%s, %s)\n", myName, myClass));
1709d522f475Smrg
1710e39b573cSmrg	memset(&referenceRec, 0, sizeof(referenceRec));
1711d522f475Smrg	memset(&subresourceRec, 0, sizeof(subresourceRec));
1712956cc18dSsnj	XtGetSubresources((Widget) xw, (XtPointer) &subresourceRec,
1713d522f475Smrg			  myName, myClass,
1714d522f475Smrg			  font_resources,
1715d522f475Smrg			  (Cardinal) XtNumber(font_resources),
1716d522f475Smrg			  NULL, (Cardinal) 0);
1717d522f475Smrg
1718e39b573cSmrg	/*
1719e39b573cSmrg	 * XtGetSubresources returns no status, so we compare the returned
1720e39b573cSmrg	 * data against a zero'd struct to see if any data is returned.
1721e39b573cSmrg	 */
1722e39b573cSmrg	if (memcmp(&referenceRec, &subresourceRec, sizeof(referenceRec))
1723e39b573cSmrg	    && !sameSubResources(&(screen->cacheVTFonts), &subresourceRec)) {
1724e39b573cSmrg
1725e39b573cSmrg	    screen->mergedVTFonts = True;
1726d522f475Smrg
17279a64e1c5Smrg	    /*
17289a64e1c5Smrg	     * To make it simple, reallocate the strings returned by
17299a64e1c5Smrg	     * XtGetSubresources.  We can free our own strings, but not theirs.
17309a64e1c5Smrg	     */
17319a64e1c5Smrg	    ALLOC_STRING(subresourceRec.default_font.f_n);
17329a64e1c5Smrg	    ALLOC_STRING(subresourceRec.default_font.f_b);
17339a64e1c5Smrg#if OPT_WIDE_CHARS
17349a64e1c5Smrg	    ALLOC_STRING(subresourceRec.default_font.f_w);
17359a64e1c5Smrg	    ALLOC_STRING(subresourceRec.default_font.f_wb);
17369a64e1c5Smrg#endif
17379a64e1c5Smrg	    for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) {
17389a64e1c5Smrg		ALLOC_STRING(subresourceRec.MenuFontName(n));
17399a64e1c5Smrg	    }
17409a64e1c5Smrg
1741d522f475Smrg	    /*
1742d522f475Smrg	     * If a particular resource value was not found, use the original.
1743d522f475Smrg	     */
1744956cc18dSsnj	    MERGE_SUBFONT(xw->misc, subresourceRec, default_font.f_n);
1745e39b573cSmrg	    INFER_SUBFONT(xw->misc, subresourceRec, default_font.f_b);
1746d522f475Smrg#if OPT_WIDE_CHARS
1747e39b573cSmrg	    INFER_SUBFONT(xw->misc, subresourceRec, default_font.f_w);
1748e39b573cSmrg	    INFER_SUBFONT(xw->misc, subresourceRec, default_font.f_wb);
1749d522f475Smrg#endif
17509a64e1c5Smrg	    for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) {
1751956cc18dSsnj		MERGE_SUBFONT(xw->screen, subresourceRec, MenuFontName(n));
17529a64e1c5Smrg	    }
1753d522f475Smrg
1754d522f475Smrg	    /*
1755d522f475Smrg	     * Finally, copy the subresource data to the widget.
1756d522f475Smrg	     */
17579a64e1c5Smrg	    COPY_DEFAULT_FONTS(xw->misc, subresourceRec);
17589a64e1c5Smrg	    FREE_MENU_FONTS(xw->screen);
1759956cc18dSsnj	    COPY_MENU_FONTS(subresourceRec, xw->screen);
17609a64e1c5Smrg
17619a64e1c5Smrg	    FREE_STRING(screen->MenuFontName(fontMenu_default));
17629a64e1c5Smrg	    FREE_STRING(screen->menu_font_names[0][fBold]);
1763492d43a5Smrg	    screen->MenuFontName(fontMenu_default) = x_strdup(xw->misc.default_font.f_n);
1764492d43a5Smrg	    screen->menu_font_names[0][fBold] = x_strdup(xw->misc.default_font.f_b);
1765d522f475Smrg#if OPT_WIDE_CHARS
17669a64e1c5Smrg	    FREE_STRING(screen->menu_font_names[0][fWide]);
17679a64e1c5Smrg	    FREE_STRING(screen->menu_font_names[0][fWBold]);
1768492d43a5Smrg	    screen->menu_font_names[0][fWide] = x_strdup(xw->misc.default_font.f_w);
1769492d43a5Smrg	    screen->menu_font_names[0][fWBold] = x_strdup(xw->misc.default_font.f_wb);
1770d522f475Smrg#endif
17719a64e1c5Smrg	    /*
17729a64e1c5Smrg	     * And remove our copies of strings.
17739a64e1c5Smrg	     */
17749a64e1c5Smrg	    FREE_STRING(subresourceRec.default_font.f_n);
17759a64e1c5Smrg	    FREE_STRING(subresourceRec.default_font.f_b);
17769a64e1c5Smrg#if OPT_WIDE_CHARS
17779a64e1c5Smrg	    FREE_STRING(subresourceRec.default_font.f_w);
17789a64e1c5Smrg	    FREE_STRING(subresourceRec.default_font.f_wb);
17799a64e1c5Smrg#endif
17809a64e1c5Smrg	    for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) {
17819a64e1c5Smrg		FREE_STRING(subresourceRec.MenuFontName(n));
17829a64e1c5Smrg	    }
1783d522f475Smrg	} else {
1784d522f475Smrg	    TRACE(("...no resources found\n"));
1785d522f475Smrg	    status = False;
1786d522f475Smrg	}
1787d522f475Smrg    }
1788d522f475Smrg    return status;
1789d522f475Smrg}
1790d522f475Smrg
1791d522f475Smrg#if OPT_WIDE_CHARS
1792d522f475Smrgstatic Bool
17939a64e1c5SmrgisWideFont(XFontStruct *fp, const char *tag, Bool nullOk)
1794d522f475Smrg{
1795d522f475Smrg    Bool result = False;
1796d522f475Smrg
1797d522f475Smrg    (void) tag;
1798d522f475Smrg    if (okFont(fp)) {
1799d522f475Smrg	unsigned count = countGlyphs(fp);
1800d522f475Smrg	TRACE(("isWideFont(%s) found %d cells\n", tag, count));
1801d522f475Smrg	result = (count > 256) ? True : False;
1802d522f475Smrg    } else {
1803d522f475Smrg	result = nullOk;
1804d522f475Smrg    }
1805d522f475Smrg    return result;
1806d522f475Smrg}
1807d522f475Smrg
1808d522f475Smrg/*
1809d522f475Smrg * If the current fonts are not wide, load the UTF8 fonts.
1810d522f475Smrg *
1811d522f475Smrg * Called during initialization (for wide-character mode), the fonts have not
1812d522f475Smrg * been setup, so we pass nullOk=True to isWideFont().
1813d522f475Smrg *
1814d522f475Smrg * Called after initialization, e.g., in response to the UTF-8 menu entry
1815d522f475Smrg * (starting from narrow character mode), it checks if the fonts are not wide.
1816d522f475Smrg */
1817d522f475SmrgBool
1818d522f475SmrgxtermLoadWideFonts(XtermWidget xw, Bool nullOk)
1819d522f475Smrg{
1820956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1821d522f475Smrg    Bool result;
1822d522f475Smrg
1823d522f475Smrg    if (EmptyFont(screen->fnts[fWide].fs)) {
1824d522f475Smrg	result = (isWideFont(screen->fnts[fNorm].fs, "normal", nullOk)
1825d522f475Smrg		  && isWideFont(screen->fnts[fBold].fs, "bold", nullOk));
1826d522f475Smrg    } else {
1827d522f475Smrg	result = (isWideFont(screen->fnts[fWide].fs, "wide", nullOk)
1828d522f475Smrg		  && isWideFont(screen->fnts[fWBold].fs, "wide-bold", nullOk));
1829d522f475Smrg	if (result && !screen->utf8_latin1) {
1830d522f475Smrg	    result = (isWideFont(screen->fnts[fNorm].fs, "normal", nullOk)
1831d522f475Smrg		      && isWideFont(screen->fnts[fBold].fs, "bold", nullOk));
1832d522f475Smrg	}
1833d522f475Smrg    }
1834d522f475Smrg    if (!result) {
1835d522f475Smrg	TRACE(("current fonts are not all wide%s\n", nullOk ? " nullOk" : ""));
1836e39b573cSmrg	result = xtermLoadVTFonts(xw, XtNutf8Fonts, XtCUtf8Fonts);
1837d522f475Smrg    }
1838d522f475Smrg    TRACE(("xtermLoadWideFonts:%d\n", result));
1839d522f475Smrg    return result;
1840d522f475Smrg}
1841d522f475Smrg#endif /* OPT_WIDE_CHARS */
1842d522f475Smrg
1843d522f475Smrg/*
1844d522f475Smrg * Restore the default fonts, i.e., if we had switched to wide-fonts.
1845d522f475Smrg */
1846d522f475SmrgBool
1847956cc18dSsnjxtermLoadDefaultFonts(XtermWidget xw)
1848d522f475Smrg{
1849d522f475Smrg    Bool result;
1850956cc18dSsnj    result = xtermLoadVTFonts(xw, NULL, NULL);
1851d522f475Smrg    TRACE(("xtermLoadDefaultFonts:%d\n", result));
1852d522f475Smrg    return result;
1853d522f475Smrg}
1854d522f475Smrg#endif /* OPT_LOAD_VTFONTS || OPT_WIDE_CHARS */
1855d522f475Smrg
1856d522f475Smrg#if OPT_LOAD_VTFONTS
1857d522f475Smrgvoid
1858d522f475SmrgHandleLoadVTFonts(Widget w,
18599a64e1c5Smrg		  XEvent *event GCC_UNUSED,
1860fa3f02f3Smrg		  String *params GCC_UNUSED,
1861d522f475Smrg		  Cardinal *param_count GCC_UNUSED)
1862d522f475Smrg{
1863d522f475Smrg    static char empty[] = "";	/* appease strict compilers */
1864d522f475Smrg
1865956cc18dSsnj    XtermWidget xw;
1866956cc18dSsnj
1867956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
1868956cc18dSsnj	TScreen *screen = TScreenOf(xw);
1869492d43a5Smrg	char name_buf[80];
1870492d43a5Smrg	char class_buf[80];
1871492d43a5Smrg	String name = (String) ((*param_count > 0) ? params[0] : empty);
18720bd37d32Smrg	char *myName = (char *) MyStackAlloc(strlen(name) + 1, name_buf);
1873492d43a5Smrg	String convert = (String) ((*param_count > 1) ? params[1] : myName);
18740bd37d32Smrg	char *myClass = (char *) MyStackAlloc(strlen(convert) + 1, class_buf);
1875d522f475Smrg	int n;
1876d522f475Smrg
1877d522f475Smrg	TRACE(("HandleLoadVTFonts(%d)\n", *param_count));
1878492d43a5Smrg	strcpy(myName, name);
1879d522f475Smrg	strcpy(myClass, convert);
18802eaa94a1Schristos	if (*param_count == 1)
18812eaa94a1Schristos	    myClass[0] = x_toupper(myClass[0]);
1882d522f475Smrg
1883d522f475Smrg	if (xtermLoadVTFonts(xw, myName, myClass)) {
1884d522f475Smrg	    /*
1885d522f475Smrg	     * When switching fonts, try to preserve the font-menu selection, since
1886d522f475Smrg	     * it is less surprising to do that (if the font-switching can be
1887d522f475Smrg	     * undone) than to switch to "Default".
1888d522f475Smrg	     */
1889956cc18dSsnj	    int font_number = screen->menu_font_number;
1890d522f475Smrg	    if (font_number > fontMenu_lastBuiltin)
1891d522f475Smrg		font_number = fontMenu_lastBuiltin;
18929a64e1c5Smrg	    for (n = 0; n < NMENUFONTS; ++n) {
1893956cc18dSsnj		screen->menu_font_sizes[n] = 0;
18949a64e1c5Smrg	    }
1895d522f475Smrg	    SetVTFont(xw, font_number, True,
1896d522f475Smrg		      ((font_number == fontMenu_default)
1897d522f475Smrg		       ? &(xw->misc.default_font)
1898d522f475Smrg		       : NULL));
1899d522f475Smrg	}
1900d522f475Smrg
1901492d43a5Smrg	MyStackFree(myName, name_buf);
1902492d43a5Smrg	MyStackFree(myClass, class_buf);
1903d522f475Smrg    }
1904d522f475Smrg}
1905d522f475Smrg#endif /* OPT_LOAD_VTFONTS */
1906d522f475Smrg
1907d522f475Smrg/*
1908d522f475Smrg * Set the limits for the box that outlines the cursor.
1909d522f475Smrg */
1910d522f475Smrgvoid
1911fa3f02f3SmrgxtermSetCursorBox(TScreen *screen)
1912d522f475Smrg{
1913d522f475Smrg    static XPoint VTbox[NBOX];
1914d522f475Smrg    XPoint *vp;
19152eaa94a1Schristos    int fw = FontWidth(screen) - 1;
19162eaa94a1Schristos    int fh = FontHeight(screen) - 1;
19170bd37d32Smrg    int ww = isCursorBar(screen) ? 1 : fw;
19180bd37d32Smrg    int hh = isCursorUnderline(screen) ? 1 : fh;
1919d522f475Smrg
1920d522f475Smrg    vp = &VTbox[1];
19210bd37d32Smrg    (vp++)->x = (short) ww;
19222eaa94a1Schristos    (vp++)->y = (short) hh;
19230bd37d32Smrg    (vp++)->x = (short) -ww;
19242eaa94a1Schristos    vp->y = (short) -hh;
19252eaa94a1Schristos
1926d522f475Smrg    screen->box = VTbox;
1927d522f475Smrg}
1928d522f475Smrg
1929d522f475Smrg#define CACHE_XFT(dst,src) if (src != 0) {\
1930956cc18dSsnj	    checkXft(xw, &(dst[fontnum]), src);\
19310bd37d32Smrg	    TRACE(("Xft metrics %s[%d] = %d (%d,%d)%s advance %d, actual %d%s\n",\
1932d522f475Smrg		#dst,\
1933d522f475Smrg	    	fontnum,\
1934d522f475Smrg		src->height,\
1935d522f475Smrg		src->ascent,\
1936d522f475Smrg		src->descent,\
19370bd37d32Smrg		((src->ascent + src->descent) > src->height ? "*" : ""),\
1938956cc18dSsnj		src->max_advance_width,\
1939956cc18dSsnj		dst[fontnum].map.min_width,\
1940956cc18dSsnj		dst[fontnum].map.mixed ? " mixed" : ""));\
1941d522f475Smrg	}
1942d522f475Smrg
1943d522f475Smrg#if OPT_RENDERFONT
1944956cc18dSsnj
194520d2c4d2Smrgstatic FcChar32
19469a64e1c5SmrgxtermXftFirstChar(XftFont *xft)
194720d2c4d2Smrg{
194820d2c4d2Smrg    FcChar32 map[FC_CHARSET_MAP_SIZE];
194920d2c4d2Smrg    FcChar32 next;
195020d2c4d2Smrg    FcChar32 first;
195120d2c4d2Smrg    int i;
195220d2c4d2Smrg
195320d2c4d2Smrg    first = FcCharSetFirstPage(xft->charset, map, &next);
19549a64e1c5Smrg    for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) {
195520d2c4d2Smrg	if (map[i]) {
195620d2c4d2Smrg	    FcChar32 bits = map[i];
1957fa3f02f3Smrg	    first += (FcChar32) i *32;
195820d2c4d2Smrg	    while (!(bits & 0x1)) {
195920d2c4d2Smrg		bits >>= 1;
196020d2c4d2Smrg		first++;
196120d2c4d2Smrg	    }
196220d2c4d2Smrg	    break;
196320d2c4d2Smrg	}
19649a64e1c5Smrg    }
196520d2c4d2Smrg    return first;
196620d2c4d2Smrg}
196720d2c4d2Smrg
196820d2c4d2Smrgstatic FcChar32
19699a64e1c5SmrgxtermXftLastChar(XftFont *xft)
197020d2c4d2Smrg{
197120d2c4d2Smrg    FcChar32 this, last, next;
197220d2c4d2Smrg    FcChar32 map[FC_CHARSET_MAP_SIZE];
197320d2c4d2Smrg    int i;
197420d2c4d2Smrg    last = FcCharSetFirstPage(xft->charset, map, &next);
197520d2c4d2Smrg    while ((this = FcCharSetNextPage(xft->charset, map, &next)) != FC_CHARSET_DONE)
197620d2c4d2Smrg	last = this;
1977fa3f02f3Smrg    last &= (FcChar32) ~ 0xff;
19789a64e1c5Smrg    for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--) {
197920d2c4d2Smrg	if (map[i]) {
198020d2c4d2Smrg	    FcChar32 bits = map[i];
1981fa3f02f3Smrg	    last += (FcChar32) i *32 + 31;
198220d2c4d2Smrg	    while (!(bits & 0x80000000)) {
198320d2c4d2Smrg		last--;
198420d2c4d2Smrg		bits <<= 1;
198520d2c4d2Smrg	    }
198620d2c4d2Smrg	    break;
198720d2c4d2Smrg	}
19889a64e1c5Smrg    }
198920d2c4d2Smrg    return (long) last;
199020d2c4d2Smrg}
199120d2c4d2Smrg
1992fa3f02f3Smrg#if OPT_TRACE > 1
199320d2c4d2Smrgstatic void
19949a64e1c5SmrgdumpXft(XtermWidget xw, XTermXftFonts *data)
199520d2c4d2Smrg{
199620d2c4d2Smrg    XftFont *xft = data->font;
199720d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
199820d2c4d2Smrg    VTwin *win = WhichVWin(screen);
199920d2c4d2Smrg
200020d2c4d2Smrg    FcChar32 c;
200120d2c4d2Smrg    FcChar32 first = xtermXftFirstChar(xft);
200220d2c4d2Smrg    FcChar32 last = xtermXftLastChar(xft);
200320d2c4d2Smrg    unsigned count = 0;
200420d2c4d2Smrg    unsigned outside = 0;
200520d2c4d2Smrg
200620d2c4d2Smrg    TRACE(("dumpXft {{\n"));
200720d2c4d2Smrg    TRACE(("   data range %#6x..%#6x\n", first, last));
200820d2c4d2Smrg    for (c = first; c <= last; ++c) {
200920d2c4d2Smrg	if (FcCharSetHasChar(xft->charset, c)) {
201020d2c4d2Smrg	    int width = my_wcwidth((int) c);
201120d2c4d2Smrg	    XGlyphInfo extents;
201220d2c4d2Smrg
201320d2c4d2Smrg	    XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents);
201420d2c4d2Smrg	    TRACE(("%#6x  %2d  %.1f\n", c, width,
201520d2c4d2Smrg		   ((double) extents.width) / win->f_width));
201620d2c4d2Smrg	    if (extents.width > win->f_width)
201720d2c4d2Smrg		++outside;
201820d2c4d2Smrg	    ++count;
201920d2c4d2Smrg	}
202020d2c4d2Smrg    }
202120d2c4d2Smrg    TRACE(("}} %u total, %u outside\n", count, outside));
202220d2c4d2Smrg}
202320d2c4d2Smrg#define DUMP_XFT(xw, data) dumpXft(xw, data)
202420d2c4d2Smrg#else
202520d2c4d2Smrg#define DUMP_XFT(xw, data)	/* nothing */
202620d2c4d2Smrg#endif
202720d2c4d2Smrg
2028956cc18dSsnjstatic void
20299a64e1c5SmrgcheckXft(XtermWidget xw, XTermXftFonts *data, XftFont *xft)
2030956cc18dSsnj{
2031956cc18dSsnj    FcChar32 c;
2032956cc18dSsnj    Dimension width = 0;
2033956cc18dSsnj
2034956cc18dSsnj    data->font = xft;
2035956cc18dSsnj    data->map.min_width = 0;
2036956cc18dSsnj    data->map.max_width = (Dimension) xft->max_advance_width;
2037956cc18dSsnj
203820d2c4d2Smrg    /*
203920d2c4d2Smrg     * For each ASCII or ISO-8859-1 printable code, ask what its width is.
204020d2c4d2Smrg     * Given the maximum width for those, we have a reasonable estimate of
204120d2c4d2Smrg     * the single-column width.
204220d2c4d2Smrg     *
204320d2c4d2Smrg     * Ignore control characters - their extent information is misleading.
204420d2c4d2Smrg     */
2045956cc18dSsnj    for (c = 32; c < 256; ++c) {
204620d2c4d2Smrg	if (c >= 127 && c <= 159)
204720d2c4d2Smrg	    continue;
2048956cc18dSsnj	if (FcCharSetHasChar(xft->charset, c)) {
2049956cc18dSsnj	    XGlyphInfo extents;
2050956cc18dSsnj
2051956cc18dSsnj	    XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents);
205220d2c4d2Smrg	    if (width < extents.width && extents.width <= data->map.max_width) {
2053956cc18dSsnj		width = extents.width;
205420d2c4d2Smrg	    }
2055956cc18dSsnj	}
2056956cc18dSsnj    }
2057956cc18dSsnj    data->map.min_width = width;
2058956cc18dSsnj    data->map.mixed = (data->map.max_width >= (data->map.min_width + 1));
2059956cc18dSsnj}
2060956cc18dSsnj
2061fa3f02f3Smrgstatic void
2062fa3f02f3SmrgreportXftFonts(XtermWidget xw,
20639a64e1c5Smrg	       XftFont *fp,
2064fa3f02f3Smrg	       const char *name,
2065fa3f02f3Smrg	       const char *tag,
20669a64e1c5Smrg	       XftPattern *match)
2067fa3f02f3Smrg{
2068fa3f02f3Smrg    if (resource.reportFonts) {
2069fa3f02f3Smrg	char buffer[1024];
2070fa3f02f3Smrg	FcChar32 first_char = xtermXftFirstChar(fp);
2071fa3f02f3Smrg	FcChar32 last_char = xtermXftLastChar(fp);
2072fa3f02f3Smrg	FcChar32 ch;
2073fa3f02f3Smrg	unsigned missing = 0;
2074fa3f02f3Smrg
2075fa3f02f3Smrg	printf("Loaded XftFonts(%s:%s)\n", name, tag);
2076fa3f02f3Smrg
2077fa3f02f3Smrg	for (ch = first_char; ch <= last_char; ++ch) {
2078fa3f02f3Smrg	    if (xtermXftMissing(xw, fp, ch)) {
2079fa3f02f3Smrg		++missing;
2080fa3f02f3Smrg	    }
2081fa3f02f3Smrg	}
2082fa3f02f3Smrg	printf("\t\tfirst char:    %u\n", first_char);
2083fa3f02f3Smrg	printf("\t\tlast char:     %u\n", last_char);
2084fa3f02f3Smrg	printf("\t\tmissing-chars: %u\n", missing);
2085fa3f02f3Smrg	printf("\t\tpresent-chars: %u\n", (last_char - first_char) + 1 - missing);
2086fa3f02f3Smrg
2087fa3f02f3Smrg	if (XftNameUnparse(match, buffer, (int) sizeof(buffer))) {
2088fa3f02f3Smrg	    char *target;
2089fa3f02f3Smrg	    char *source = buffer;
2090fa3f02f3Smrg	    while ((target = strtok(source, ":")) != 0) {
2091fa3f02f3Smrg		printf("\t%s\n", target);
2092fa3f02f3Smrg		source = 0;
2093fa3f02f3Smrg	    }
2094fa3f02f3Smrg	}
2095fa3f02f3Smrg    }
2096fa3f02f3Smrg}
2097fa3f02f3Smrg
2098d522f475Smrgstatic XftFont *
20999a64e1c5SmrgxtermOpenXft(XtermWidget xw, const char *name, XftPattern *pat, const char *tag)
2100d522f475Smrg{
2101956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2102956cc18dSsnj    Display *dpy = screen->display;
2103d522f475Smrg    XftPattern *match;
2104d522f475Smrg    XftResult status;
2105d522f475Smrg    XftFont *result = 0;
2106d522f475Smrg
2107d522f475Smrg    if (pat != 0) {
2108d522f475Smrg	match = XftFontMatch(dpy, DefaultScreen(dpy), pat, &status);
2109d522f475Smrg	if (match != 0) {
2110d522f475Smrg	    result = XftFontOpenPattern(dpy, match);
2111d522f475Smrg	    if (result != 0) {
2112d522f475Smrg		TRACE(("...matched %s font\n", tag));
2113fa3f02f3Smrg		reportXftFonts(xw, result, name, tag, match);
2114d522f475Smrg	    } else {
2115d522f475Smrg		TRACE(("...could did not open %s font\n", tag));
2116d522f475Smrg		XftPatternDestroy(match);
2117956cc18dSsnj		if (xw->misc.fontWarnings >= fwAlways) {
2118956cc18dSsnj		    TRACE(("OOPS cannot open %s font \"%s\"\n", tag, name));
21190bd37d32Smrg		    xtermWarning("cannot open %s font \"%s\"\n", tag, name);
2120956cc18dSsnj		}
2121d522f475Smrg	    }
2122d522f475Smrg	} else {
2123d522f475Smrg	    TRACE(("...did not match %s font\n", tag));
2124956cc18dSsnj	    if (xw->misc.fontWarnings >= fwResource) {
2125956cc18dSsnj		TRACE(("OOPS: cannot match %s font \"%s\"\n", tag, name));
21260bd37d32Smrg		xtermWarning("cannot match %s font \"%s\"\n", tag, name);
2127956cc18dSsnj	    }
2128d522f475Smrg	}
2129d522f475Smrg    }
2130d522f475Smrg    return result;
2131d522f475Smrg}
2132d522f475Smrg#endif
2133d522f475Smrg
2134d522f475Smrg#if OPT_RENDERFONT
2135d522f475Smrg#if OPT_SHIFT_FONTS
2136d522f475Smrg/*
2137d522f475Smrg * Don't make a dependency on the math library for a single function.
2138d522f475Smrg * (Newton Raphson).
2139d522f475Smrg */
2140d522f475Smrgstatic double
21410bd37d32SmrgdimSquareRoot(double value)
2142d522f475Smrg{
2143d522f475Smrg    double result = 0.0;
2144d522f475Smrg    if (value > 0.0) {
2145d522f475Smrg	int n;
2146d522f475Smrg	double older = value;
2147d522f475Smrg	for (n = 0; n < 10; ++n) {
2148d522f475Smrg	    double delta = (older * older - value) / (2.0 * older);
2149d522f475Smrg	    double newer = older - delta;
2150d522f475Smrg	    older = newer;
2151d522f475Smrg	    result = newer;
2152d522f475Smrg	    if (delta > -0.001 && delta < 0.001)
2153d522f475Smrg		break;
2154d522f475Smrg	}
2155d522f475Smrg    }
2156d522f475Smrg    return result;
2157d522f475Smrg}
2158d522f475Smrg#endif
2159d522f475Smrg
2160d522f475Smrg/*
2161d522f475Smrg * Given the Xft font metrics, determine the actual font size.  This is used
2162d522f475Smrg * for each font to ensure that normal, bold and italic fonts follow the same
2163d522f475Smrg * rule.
2164d522f475Smrg */
2165d522f475Smrgstatic void
21669a64e1c5SmrgsetRenderFontsize(TScreen *screen, VTwin *win, XftFont *font, const char *tag)
2167d522f475Smrg{
2168d522f475Smrg    if (font != 0) {
2169d522f475Smrg	int width, height, ascent, descent;
2170d522f475Smrg
2171d522f475Smrg	(void) screen;
2172d522f475Smrg
2173d522f475Smrg	width = font->max_advance_width;
2174d522f475Smrg	height = font->height;
2175d522f475Smrg	ascent = font->ascent;
2176d522f475Smrg	descent = font->descent;
2177d522f475Smrg	if (height < ascent + descent) {
2178d522f475Smrg	    TRACE(("...increase height from %d\n", height));
2179d522f475Smrg	    height = ascent + descent;
2180d522f475Smrg	}
2181d522f475Smrg	if (is_double_width_font_xft(screen->display, font)) {
2182d522f475Smrg	    TRACE(("...reduced width from %d\n", width));
2183d522f475Smrg	    width >>= 1;
2184d522f475Smrg	}
2185d522f475Smrg	if (tag == 0) {
21860bd37d32Smrg	    SetFontWidth(screen, win, width);
21870bd37d32Smrg	    SetFontHeight(screen, win, height);
2188d522f475Smrg	    win->f_ascent = ascent;
2189d522f475Smrg	    win->f_descent = descent;
2190d522f475Smrg	    TRACE(("setRenderFontsize result %dx%d (%d+%d)\n",
2191d522f475Smrg		   width, height, ascent, descent));
2192d522f475Smrg	} else if (win->f_width < width ||
2193d522f475Smrg		   win->f_height < height ||
2194d522f475Smrg		   win->f_ascent < ascent ||
2195d522f475Smrg		   win->f_descent < descent) {
2196d522f475Smrg	    TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n",
2197d522f475Smrg		   tag,
2198d522f475Smrg		   win->f_width, win->f_height, win->f_ascent, win->f_descent,
2199d522f475Smrg		   width, height, ascent, descent));
2200d522f475Smrg
22010bd37d32Smrg	    SetFontWidth(screen, win, width);
22020bd37d32Smrg	    SetFontHeight(screen, win, height);
2203d522f475Smrg	    win->f_ascent = ascent;
2204d522f475Smrg	    win->f_descent = descent;
2205d522f475Smrg	} else {
2206d522f475Smrg	    TRACE(("setRenderFontsize %s unchanged\n", tag));
2207d522f475Smrg	}
2208d522f475Smrg    }
2209d522f475Smrg}
2210d522f475Smrg#endif
2211d522f475Smrg
221220d2c4d2Smrgstatic void
221320d2c4d2SmrgcheckFontInfo(int value, const char *tag)
221420d2c4d2Smrg{
221520d2c4d2Smrg    if (value == 0) {
22160bd37d32Smrg	xtermWarning("Selected font has no non-zero %s for ISO-8859-1 encoding\n", tag);
221720d2c4d2Smrg	exit(1);
221820d2c4d2Smrg    }
221920d2c4d2Smrg}
222020d2c4d2Smrg
222120d2c4d2Smrg#if OPT_RENDERFONT
222220d2c4d2Smrgvoid
22239a64e1c5SmrgxtermCloseXft(TScreen *screen, XTermXftFonts *pub)
222420d2c4d2Smrg{
222520d2c4d2Smrg    if (pub->font != 0) {
222620d2c4d2Smrg	XftFontClose(screen->display, pub->font);
222720d2c4d2Smrg	pub->font = 0;
222820d2c4d2Smrg    }
222920d2c4d2Smrg}
223020d2c4d2Smrg
223120d2c4d2Smrg/*
223220d2c4d2Smrg * Get the faceName/faceDoublesize resource setting.  Strip off "xft:", which
22330bd37d32Smrg * is not recognized by XftNameParse().
223420d2c4d2Smrg */
2235492d43a5SmrgString
223620d2c4d2SmrggetFaceName(XtermWidget xw, Bool wideName GCC_UNUSED)
223720d2c4d2Smrg{
223820d2c4d2Smrg#if OPT_RENDERWIDE
2239492d43a5Smrg    String result = (wideName
2240492d43a5Smrg		     ? xw->misc.face_wide_name
2241492d43a5Smrg		     : xw->misc.face_name);
224220d2c4d2Smrg#else
2243492d43a5Smrg    String result = xw->misc.face_name;
224420d2c4d2Smrg#endif
224520d2c4d2Smrg    if (!IsEmpty(result) && !strncmp(result, "xft:", (size_t) 4))
224620d2c4d2Smrg	result += 4;
224720d2c4d2Smrg    return x_nonempty(result);
224820d2c4d2Smrg}
224920d2c4d2Smrg
225020d2c4d2Smrg/*
225120d2c4d2Smrg * If we change the faceName, we'll have to re-acquire all of the fonts that
225220d2c4d2Smrg * are derived from it.
225320d2c4d2Smrg */
225420d2c4d2Smrgvoid
225520d2c4d2SmrgsetFaceName(XtermWidget xw, const char *value)
225620d2c4d2Smrg{
225720d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
225820d2c4d2Smrg    int n;
22590bd37d32Smrg    Boolean changed = (Boolean) ((xw->misc.face_name == 0)
22600bd37d32Smrg				 || strcmp(xw->misc.face_name, value));
226120d2c4d2Smrg
22620bd37d32Smrg    if (changed) {
22630bd37d32Smrg	xw->misc.face_name = x_strdup(value);
22640bd37d32Smrg	for (n = 0; n < NMENUFONTS; ++n) {
22650bd37d32Smrg	    xw->misc.face_size[n] = -1.0;
22660bd37d32Smrg	    xtermCloseXft(screen, &(screen->renderFontNorm[n]));
22670bd37d32Smrg	    xtermCloseXft(screen, &(screen->renderFontBold[n]));
22680bd37d32Smrg	    xtermCloseXft(screen, &(screen->renderFontBold[n]));
226920d2c4d2Smrg#if OPT_RENDERWIDE
22700bd37d32Smrg	    xtermCloseXft(screen, &(screen->renderWideNorm[n]));
22710bd37d32Smrg	    xtermCloseXft(screen, &(screen->renderWideBold[n]));
22720bd37d32Smrg	    xtermCloseXft(screen, &(screen->renderWideItal[n]));
227320d2c4d2Smrg#endif
22740bd37d32Smrg	}
227520d2c4d2Smrg    }
227620d2c4d2Smrg}
227720d2c4d2Smrg#endif
227820d2c4d2Smrg
2279d522f475Smrg/*
2280d522f475Smrg * Compute useful values for the font/window sizes
2281d522f475Smrg */
2282d522f475Smrgvoid
2283d522f475SmrgxtermComputeFontInfo(XtermWidget xw,
22849a64e1c5Smrg		     VTwin *win,
22859a64e1c5Smrg		     XFontStruct *font,
2286d522f475Smrg		     int sbwidth)
2287d522f475Smrg{
2288956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2289d522f475Smrg
2290d522f475Smrg    int i, j, width, height;
2291492d43a5Smrg#if OPT_RENDERFONT
2292492d43a5Smrg    int fontnum = screen->menu_font_number;
2293492d43a5Smrg#endif
2294d522f475Smrg
2295d522f475Smrg#if OPT_RENDERFONT
2296d522f475Smrg    /*
2297d522f475Smrg     * xterm contains a lot of references to fonts, assuming they are fixed
2298d522f475Smrg     * size.  This chunk of code overrides the actual font-selection (see
2299d522f475Smrg     * drawXtermText()), if the user has selected render-font.  All of the
2300d522f475Smrg     * font-loading for fixed-fonts still goes on whether or not this chunk
2301d522f475Smrg     * overrides it.
2302d522f475Smrg     */
2303492d43a5Smrg    if (UsingRenderFont(xw) && fontnum >= 0) {
2304492d43a5Smrg	String face_name = getFaceName(xw, False);
2305956cc18dSsnj	XftFont *norm = screen->renderFontNorm[fontnum].font;
2306956cc18dSsnj	XftFont *bold = screen->renderFontBold[fontnum].font;
2307956cc18dSsnj	XftFont *ital = screen->renderFontItal[fontnum].font;
2308d522f475Smrg#if OPT_RENDERWIDE
2309956cc18dSsnj	XftFont *wnorm = screen->renderWideNorm[fontnum].font;
2310956cc18dSsnj	XftFont *wbold = screen->renderWideBold[fontnum].font;
2311956cc18dSsnj	XftFont *wital = screen->renderWideItal[fontnum].font;
2312d522f475Smrg#endif
2313d522f475Smrg
231420d2c4d2Smrg	if (norm == 0 && face_name) {
2315d522f475Smrg	    XftPattern *pat;
23160bd37d32Smrg	    double face_size;
2317d522f475Smrg
23180bd37d32Smrg	    TRACE(("xtermComputeFontInfo font %d: norm(face %s, size %.1f)\n",
2319492d43a5Smrg		   fontnum, face_name,
2320d522f475Smrg		   xw->misc.face_size[fontnum]));
2321d522f475Smrg
23220bd37d32Smrg	    fillInFaceSize(xw, fontnum);
23230bd37d32Smrg	    face_size = xw->misc.face_size[fontnum];
2324d522f475Smrg
2325d522f475Smrg	    /*
2326d522f475Smrg	     * By observation (there is no documentation), XftPatternBuild is
2327d522f475Smrg	     * cumulative.  Build the bold- and italic-patterns on top of the
2328d522f475Smrg	     * normal pattern.
2329d522f475Smrg	     */
2330d522f475Smrg#define NormXftPattern \
2331d522f475Smrg	    XFT_FAMILY, XftTypeString, "mono", \
2332d522f475Smrg	    XFT_SIZE, XftTypeDouble, face_size, \
2333d522f475Smrg	    XFT_SPACING, XftTypeInteger, XFT_MONO
2334d522f475Smrg
2335d522f475Smrg#define BoldXftPattern(norm) \
2336d522f475Smrg	    XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \
2337d522f475Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width
2338d522f475Smrg
2339d522f475Smrg#define ItalXftPattern(norm) \
2340d522f475Smrg	    XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \
2341d522f475Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width
2342d522f475Smrg
23439a64e1c5Smrg#if OPT_WIDE_ATTRS
23449a64e1c5Smrg#define HAVE_ITALICS 1
23459a64e1c5Smrg#define FIND_ITALICS ((pat = XftNameParse(face_name)) != 0)
23469a64e1c5Smrg#elif OPT_ISO_COLORS
23479a64e1c5Smrg#define HAVE_ITALICS 1
23489a64e1c5Smrg#define FIND_ITALICS (screen->italicULMode && (pat = XftNameParse(face_name)) != 0)
23499a64e1c5Smrg#else
23509a64e1c5Smrg#define HAVE_ITALICS 0
23519a64e1c5Smrg#endif
23529a64e1c5Smrg
235320d2c4d2Smrg	    if ((pat = XftNameParse(face_name)) != 0) {
235420d2c4d2Smrg#define OPEN_XFT(tag) xtermOpenXft(xw, face_name, pat, tag)
2355d522f475Smrg		XftPatternBuild(pat,
2356d522f475Smrg				NormXftPattern,
2357d522f475Smrg				(void *) 0);
2358956cc18dSsnj		norm = OPEN_XFT("normal");
2359d522f475Smrg
2360d522f475Smrg		if (norm != 0) {
2361d522f475Smrg		    XftPatternBuild(pat,
2362d522f475Smrg				    BoldXftPattern(norm),
2363d522f475Smrg				    (void *) 0);
2364956cc18dSsnj		    bold = OPEN_XFT("bold");
2365d522f475Smrg
23669a64e1c5Smrg#if HAVE_ITALICS
23679a64e1c5Smrg		    if (FIND_ITALICS) {
2368d522f475Smrg			XftPatternBuild(pat,
2369d522f475Smrg					NormXftPattern,
2370d522f475Smrg					ItalXftPattern(norm),
2371d522f475Smrg					(void *) 0);
2372956cc18dSsnj			ital = OPEN_XFT("italic");
2373d522f475Smrg		    }
23749a64e1c5Smrg#endif
2375956cc18dSsnj#undef OPEN_XFT
2376d522f475Smrg
2377d522f475Smrg		    /*
2378d522f475Smrg		     * FIXME:  just assume that the corresponding font has no
2379d522f475Smrg		     * graphics characters.
2380d522f475Smrg		     */
2381d522f475Smrg		    if (screen->fnt_boxes) {
2382d522f475Smrg			screen->fnt_boxes = False;
2383d522f475Smrg			TRACE(("Xft opened - will %suse internal line-drawing characters\n",
2384d522f475Smrg			       screen->fnt_boxes ? "not " : ""));
2385d522f475Smrg		    }
2386d522f475Smrg		}
2387d522f475Smrg
2388d522f475Smrg		XftPatternDestroy(pat);
2389d522f475Smrg	    }
2390d522f475Smrg
2391d522f475Smrg	    CACHE_XFT(screen->renderFontNorm, norm);
2392d522f475Smrg	    CACHE_XFT(screen->renderFontBold, bold);
2393d522f475Smrg	    CACHE_XFT(screen->renderFontItal, ital);
2394d522f475Smrg
2395d522f475Smrg	    /*
2396d522f475Smrg	     * See xtermXftDrawString().
2397d522f475Smrg	     */
2398d522f475Smrg#if OPT_RENDERWIDE
2399d522f475Smrg	    if (norm != 0 && screen->wide_chars) {
2400d522f475Smrg		int char_width = norm->max_advance_width * 2;
2401956cc18dSsnj#ifdef FC_ASPECT
2402956cc18dSsnj		double aspect = ((xw->misc.face_wide_name
2403956cc18dSsnj				  || screen->renderFontNorm[fontnum].map.mixed)
2404956cc18dSsnj				 ? 1.0
2405956cc18dSsnj				 : 2.0);
2406956cc18dSsnj#endif
2407d522f475Smrg
240820d2c4d2Smrg		face_name = getFaceName(xw, True);
2409d522f475Smrg		TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n",
241020d2c4d2Smrg		       NonNull(face_name),
2411d522f475Smrg		       char_width));
2412d522f475Smrg
2413d522f475Smrg#define WideXftPattern \
2414d522f475Smrg		XFT_FAMILY, XftTypeString, "mono", \
2415d522f475Smrg		XFT_SIZE, XftTypeDouble, face_size, \
2416d522f475Smrg		XFT_SPACING, XftTypeInteger, XFT_MONO
2417d522f475Smrg
241820d2c4d2Smrg		if (face_name && (pat = XftNameParse(face_name)) != 0) {
2419956cc18dSsnj#define OPEN_XFT(tag) xtermOpenXft(xw, face_name, pat, tag)
2420d522f475Smrg		    XftPatternBuild(pat,
2421d522f475Smrg				    WideXftPattern,
2422d522f475Smrg				    XFT_CHAR_WIDTH, XftTypeInteger, char_width,
2423956cc18dSsnj#ifdef FC_ASPECT
2424956cc18dSsnj				    FC_ASPECT, XftTypeDouble, aspect,
2425956cc18dSsnj#endif
2426d522f475Smrg				    (void *) 0);
2427956cc18dSsnj		    wnorm = OPEN_XFT("wide");
2428d522f475Smrg
2429d522f475Smrg		    if (wnorm != 0) {
2430d522f475Smrg			XftPatternBuild(pat,
2431d522f475Smrg					WideXftPattern,
2432d522f475Smrg					BoldXftPattern(wnorm),
2433d522f475Smrg					(void *) 0);
2434956cc18dSsnj			wbold = OPEN_XFT("wide-bold");
2435d522f475Smrg
24369a64e1c5Smrg#if HAVE_ITALICS
24379a64e1c5Smrg			if (FIND_ITALICS) {
2438d522f475Smrg			    XftPatternBuild(pat,
2439d522f475Smrg					    WideXftPattern,
2440d522f475Smrg					    ItalXftPattern(wnorm),
2441d522f475Smrg					    (void *) 0);
2442956cc18dSsnj			    wital = OPEN_XFT("wide-italic");
2443d522f475Smrg			}
2444d522f475Smrg#endif
2445956cc18dSsnj#undef OPEN_XFT
2446d522f475Smrg		    }
2447d522f475Smrg		    XftPatternDestroy(pat);
2448d522f475Smrg		}
2449d522f475Smrg
2450d522f475Smrg		CACHE_XFT(screen->renderWideNorm, wnorm);
2451d522f475Smrg		CACHE_XFT(screen->renderWideBold, wbold);
2452d522f475Smrg		CACHE_XFT(screen->renderWideItal, wital);
2453d522f475Smrg	    }
2454d522f475Smrg#endif /* OPT_RENDERWIDE */
2455d522f475Smrg	}
2456d522f475Smrg	if (norm == 0) {
24572eaa94a1Schristos	    TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum));
24580bd37d32Smrg	    xw->work.render_font = False;
2459d522f475Smrg	    update_font_renderfont();
2460d522f475Smrg	    /* now we will fall through into the bitmap fonts */
2461d522f475Smrg	} else {
2462d522f475Smrg	    setRenderFontsize(screen, win, norm, NULL);
2463d522f475Smrg	    setRenderFontsize(screen, win, bold, "bold");
2464d522f475Smrg	    setRenderFontsize(screen, win, ital, "ital");
246520d2c4d2Smrg#if OPT_BOX_CHARS
246620d2c4d2Smrg	    setupPackedFonts(xw);
246720d2c4d2Smrg
246820d2c4d2Smrg	    if (screen->force_packed) {
246920d2c4d2Smrg		XTermXftFonts *use = &(screen->renderFontNorm[fontnum]);
24700bd37d32Smrg		SetFontHeight(screen, win, use->font->ascent + use->font->descent);
24710bd37d32Smrg		SetFontWidth(screen, win, use->map.min_width);
247220d2c4d2Smrg		TRACE(("...packed TrueType font %dx%d vs %d\n",
247320d2c4d2Smrg		       win->f_height,
247420d2c4d2Smrg		       win->f_width,
247520d2c4d2Smrg		       use->map.max_width));
247620d2c4d2Smrg	    }
247720d2c4d2Smrg#endif
247820d2c4d2Smrg	    DUMP_XFT(xw, &(screen->renderFontNorm[fontnum]));
2479d522f475Smrg	}
2480d522f475Smrg    }
2481d522f475Smrg    /*
2482d522f475Smrg     * Are we handling a bitmap font?
2483d522f475Smrg     */
2484492d43a5Smrg    else
2485d522f475Smrg#endif /* OPT_RENDERFONT */
2486d522f475Smrg    {
248720d2c4d2Smrg	if (is_double_width_font(font) && !(screen->fnt_prop)) {
24880bd37d32Smrg	    SetFontWidth(screen, win, font->min_bounds.width);
2489d522f475Smrg	} else {
24900bd37d32Smrg	    SetFontWidth(screen, win, font->max_bounds.width);
2491d522f475Smrg	}
24920bd37d32Smrg	SetFontHeight(screen, win, font->ascent + font->descent);
2493d522f475Smrg	win->f_ascent = font->ascent;
2494d522f475Smrg	win->f_descent = font->descent;
2495d522f475Smrg    }
2496d522f475Smrg    i = 2 * screen->border + sbwidth;
2497d522f475Smrg    j = 2 * screen->border;
2498d522f475Smrg    width = MaxCols(screen) * win->f_width + i;
2499d522f475Smrg    height = MaxRows(screen) * win->f_height + j;
2500956cc18dSsnj    win->fullwidth = (Dimension) width;
2501956cc18dSsnj    win->fullheight = (Dimension) height;
2502d522f475Smrg    win->width = width - i;
2503d522f475Smrg    win->height = height - j;
2504d522f475Smrg
2505d522f475Smrg    TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n",
2506d522f475Smrg	   win->height,
2507d522f475Smrg	   win->width,
2508d522f475Smrg	   win->fullheight,
2509d522f475Smrg	   win->fullwidth,
2510d522f475Smrg	   win->f_height,
2511d522f475Smrg	   win->f_width,
2512d522f475Smrg	   win->f_ascent,
2513d522f475Smrg	   win->f_descent));
251420d2c4d2Smrg
251520d2c4d2Smrg    checkFontInfo(win->f_height, "height");
251620d2c4d2Smrg    checkFontInfo(win->f_width, "width");
2517d522f475Smrg}
2518d522f475Smrg
2519d522f475Smrg/* save this information as a side-effect for double-sized characters */
2520d522f475Smrgvoid
25219a64e1c5SmrgxtermSaveFontInfo(TScreen *screen, XFontStruct *font)
2522d522f475Smrg{
2523956cc18dSsnj    screen->fnt_wide = (Dimension) (font->max_bounds.width);
2524956cc18dSsnj    screen->fnt_high = (Dimension) (font->ascent + font->descent);
2525d522f475Smrg    TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide));
2526d522f475Smrg}
2527d522f475Smrg
2528d522f475Smrg/*
2529d522f475Smrg * After loading a new font, update the structures that use its size.
2530d522f475Smrg */
2531d522f475Smrgvoid
2532d522f475SmrgxtermUpdateFontInfo(XtermWidget xw, Bool doresize)
2533d522f475Smrg{
2534956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2535d522f475Smrg
2536d522f475Smrg    int scrollbar_width;
2537d522f475Smrg    VTwin *win = &(screen->fullVwin);
2538d522f475Smrg
2539d522f475Smrg    scrollbar_width = (xw->misc.scrollbar
2540d522f475Smrg		       ? (screen->scrollWidget->core.width +
2541d522f475Smrg			  BorderWidth(screen->scrollWidget))
2542d522f475Smrg		       : 0);
2543d522f475Smrg    xtermComputeFontInfo(xw, win, screen->fnts[fNorm].fs, scrollbar_width);
2544d522f475Smrg    xtermSaveFontInfo(screen, screen->fnts[fNorm].fs);
2545d522f475Smrg
2546d522f475Smrg    if (doresize) {
2547d522f475Smrg	if (VWindow(screen)) {
2548d522f475Smrg	    xtermClear(xw);
2549d522f475Smrg	}
2550d522f475Smrg	TRACE(("xtermUpdateFontInfo {{\n"));
2551d522f475Smrg	DoResizeScreen(xw);	/* set to the new natural size */
2552d522f475Smrg	ResizeScrollBar(xw);
2553d522f475Smrg	Redraw();
2554d522f475Smrg	TRACE(("... }} xtermUpdateFontInfo\n"));
2555d522f475Smrg#ifdef SCROLLBAR_RIGHT
2556d522f475Smrg	updateRightScrollbar(xw);
2557d522f475Smrg#endif
2558d522f475Smrg    }
2559d522f475Smrg    xtermSetCursorBox(screen);
2560d522f475Smrg}
2561d522f475Smrg
2562fa3f02f3Smrg#if OPT_BOX_CHARS || OPT_REPORT_FONTS
2563d522f475Smrg
2564d522f475Smrg/*
2565d522f475Smrg * Returns true if the given character is missing from the specified font.
2566d522f475Smrg */
2567d522f475SmrgBool
2568956cc18dSsnjxtermMissingChar(unsigned ch, XTermFonts * font)
2569d522f475Smrg{
2570956cc18dSsnj    Bool result = False;
2571956cc18dSsnj    XFontStruct *fs = font->fs;
2572fa3f02f3Smrg    XCharStruct *pc = 0;
2573d522f475Smrg
2574956cc18dSsnj    if (fs->max_byte1 == 0) {
2575d522f475Smrg#if OPT_WIDE_CHARS
2576fa3f02f3Smrg	if (ch < 256)
2577956cc18dSsnj#endif
2578fa3f02f3Smrg	{
2579fa3f02f3Smrg	    CI_GET_CHAR_INFO_1D(fs, E2A(ch), pc);
2580fa3f02f3Smrg	}
2581956cc18dSsnj    }
2582d522f475Smrg#if OPT_WIDE_CHARS
2583956cc18dSsnj    else {
2584fa3f02f3Smrg	unsigned row = (ch >> 8);
2585fa3f02f3Smrg	unsigned col = (ch & 0xff);
2586fa3f02f3Smrg	CI_GET_CHAR_INFO_2D(fs, row, col, pc);
2587956cc18dSsnj    }
2588d522f475Smrg#endif
2589d522f475Smrg
2590fa3f02f3Smrg    if (pc == 0 || CI_NONEXISTCHAR(pc)) {
2591956cc18dSsnj	TRACE(("xtermMissingChar %#04x (!exists)\n", ch));
2592956cc18dSsnj	result = True;
2593d522f475Smrg    }
2594fa3f02f3Smrg    if (ch < KNOWN_MISSING) {
2595956cc18dSsnj	font->known_missing[ch] = (Char) (result ? 2 : 1);
2596d522f475Smrg    }
2597956cc18dSsnj    return result;
2598d522f475Smrg}
2599fa3f02f3Smrg#endif
2600d522f475Smrg
2601fa3f02f3Smrg#if OPT_BOX_CHARS
2602d522f475Smrg/*
2603d522f475Smrg * The grid is arbitrary, enough resolution that nothing's lost in
2604d522f475Smrg * initialization.
2605d522f475Smrg */
2606d522f475Smrg#define BOX_HIGH 60
2607d522f475Smrg#define BOX_WIDE 60
2608d522f475Smrg
2609d522f475Smrg#define MID_HIGH (BOX_HIGH/2)
2610d522f475Smrg#define MID_WIDE (BOX_WIDE/2)
2611d522f475Smrg
2612d522f475Smrg#define CHR_WIDE ((9*BOX_WIDE)/10)
2613d522f475Smrg#define CHR_HIGH ((9*BOX_HIGH)/10)
2614d522f475Smrg
2615d522f475Smrg/*
2616d522f475Smrg * ...since we'll scale the values anyway.
2617d522f475Smrg */
2618e39b573cSmrg#define SCALED_X(n) ((int)(n) * (((int) font_width) - 1)) / (BOX_WIDE-1)
2619e39b573cSmrg#define SCALED_Y(n) ((int)(n) * (((int) font_height) - 1)) / (BOX_HIGH-1)
2620e39b573cSmrg#define SCALE_X(n) n = SCALED_X(n)
2621e39b573cSmrg#define SCALE_Y(n) n = SCALED_Y(n)
2622d522f475Smrg
2623d522f475Smrg#define SEG(x0,y0,x1,y1) x0,y0, x1,y1
2624d522f475Smrg
2625d522f475Smrg/*
2626d522f475Smrg * Draw the given graphic character, if it is simple enough (i.e., a
2627d522f475Smrg * line-drawing character).
2628d522f475Smrg */
2629d522f475Smrgvoid
2630d522f475SmrgxtermDrawBoxChar(XtermWidget xw,
2631d522f475Smrg		 unsigned ch,
26329a64e1c5Smrg		 unsigned attr_flags,
26339a64e1c5Smrg		 unsigned draw_flags,
2634d522f475Smrg		 GC gc,
2635d522f475Smrg		 int x,
2636d522f475Smrg		 int y,
2637d522f475Smrg		 int cells)
2638d522f475Smrg{
2639956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2640d522f475Smrg    /* *INDENT-OFF* */
2641d522f475Smrg    static const short glyph_ht[] = {
2642d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,5*MID_HIGH/6),	/* H */
2643d522f475Smrg	SEG(6*BOX_WIDE/10,  0,		6*BOX_WIDE/10,5*MID_HIGH/6),
2644d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12),
2645d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
2646d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
2647d522f475Smrg	-1
2648d522f475Smrg    }, glyph_ff[] = {
2649d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		6*BOX_WIDE/10,	0),		/* F */
2650d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12),
2651d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		0*BOX_WIDE/3, 5*MID_HIGH/6),
2652d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
2653d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
2654d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
2655d522f475Smrg	-1
2656d522f475Smrg    }, glyph_lf[] = {
2657d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,9*MID_HIGH/12),	/* L */
2658d522f475Smrg	SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12),
2659d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
2660d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
2661d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
2662d522f475Smrg	-1
2663d522f475Smrg    }, glyph_nl[] = {
2664d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10,	0),		/* N */
2665d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		5*BOX_WIDE/6, 5*MID_HIGH/6),
2666d522f475Smrg	SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
2667d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),	/* L */
2668d522f475Smrg	SEG(1*BOX_WIDE/3,   CHR_HIGH,	  CHR_WIDE,	CHR_HIGH),
2669d522f475Smrg	-1
2670d522f475Smrg    }, glyph_vt[] = {
2671d522f475Smrg	SEG(1*BOX_WIDE/10,   0,		5*BOX_WIDE/12,5*MID_HIGH/6),	/* V */
2672d522f475Smrg	SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
2673d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
2674d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
2675d522f475Smrg	-1
2676d522f475Smrg    }, plus_or_minus[] =
2677d522f475Smrg    {
2678d522f475Smrg	SEG(  0,	  5*BOX_HIGH/6,	  CHR_WIDE,   5*BOX_HIGH/6),
2679d522f475Smrg	SEG(  MID_WIDE,	  2*BOX_HIGH/6,	  MID_WIDE,   4*BOX_HIGH/6),
2680d522f475Smrg	SEG(  0,	  3*BOX_HIGH/6,	  CHR_WIDE,   3*BOX_HIGH/6),
2681d522f475Smrg	-1
2682d522f475Smrg    }, lower_right_corner[] =
2683d522f475Smrg    {
2684d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
2685d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	0),
2686d522f475Smrg	-1
2687d522f475Smrg    }, upper_right_corner[] =
2688d522f475Smrg    {
2689d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
2690d522f475Smrg	SEG( MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
2691d522f475Smrg	-1
2692d522f475Smrg    }, upper_left_corner[] =
2693d522f475Smrg    {
2694d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2695d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
2696d522f475Smrg	-1
2697d522f475Smrg    }, lower_left_corner[] =
2698d522f475Smrg    {
2699d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
2700d522f475Smrg	SEG(  MID_WIDE,	    MID_WIDE,	  BOX_WIDE,	MID_HIGH),
2701d522f475Smrg	-1
2702d522f475Smrg    }, cross[] =
2703d522f475Smrg    {
2704d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2705d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2706d522f475Smrg	-1
2707d522f475Smrg    }, scan_line_1[] =
2708d522f475Smrg    {
2709d522f475Smrg	SEG(  0,	    0,		  BOX_WIDE,	0),
2710d522f475Smrg	-1
2711d522f475Smrg    }, scan_line_3[] =
2712d522f475Smrg    {
2713d522f475Smrg	SEG(  0,	    BOX_HIGH/4,	  BOX_WIDE,	BOX_HIGH/4),
2714d522f475Smrg	-1
2715d522f475Smrg    }, scan_line_7[] =
2716d522f475Smrg    {
2717d522f475Smrg	SEG( 0,		    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2718d522f475Smrg	-1
2719d522f475Smrg    }, scan_line_9[] =
2720d522f475Smrg    {
2721d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  BOX_WIDE,   3*BOX_HIGH/4),
2722d522f475Smrg	-1
2723d522f475Smrg    }, horizontal_line[] =
2724d522f475Smrg    {
2725d522f475Smrg	SEG(  0,	    BOX_HIGH,	  BOX_WIDE,	BOX_HIGH),
2726d522f475Smrg	-1
2727d522f475Smrg    }, left_tee[] =
2728d522f475Smrg    {
2729d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2730d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2731d522f475Smrg	-1
2732d522f475Smrg    }, right_tee[] =
2733d522f475Smrg    {
2734d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2735d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  0,		MID_HIGH),
2736d522f475Smrg	-1
2737d522f475Smrg    }, bottom_tee[] =
2738d522f475Smrg    {
2739d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2740d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
2741d522f475Smrg	-1
2742d522f475Smrg    }, top_tee[] =
2743d522f475Smrg    {
2744d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2745d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
2746d522f475Smrg	-1
2747d522f475Smrg    }, vertical_line[] =
2748d522f475Smrg    {
2749d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2750d522f475Smrg	-1
2751d522f475Smrg    }, less_than_or_equal[] =
2752d522f475Smrg    {
2753d522f475Smrg	SEG(  CHR_WIDE,	    BOX_HIGH/3,	  0,		MID_HIGH),
2754d522f475Smrg	SEG(  CHR_WIDE,	  2*BOX_HIGH/3,	  0,		MID_HIGH),
2755d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
2756d522f475Smrg	-1
2757d522f475Smrg    }, greater_than_or_equal[] =
2758d522f475Smrg    {
2759d522f475Smrg	SEG(  0,	    BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
2760d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
2761d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
2762d522f475Smrg	-1
2763d522f475Smrg    }, greek_pi[] =
2764d522f475Smrg    {
2765d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
2766d522f475Smrg	SEG(5*CHR_WIDE/6,   MID_HIGH,	5*CHR_WIDE/6,	CHR_HIGH),
2767d522f475Smrg	SEG(2*CHR_WIDE/6,   MID_HIGH,	2*CHR_WIDE/6,	CHR_HIGH),
2768d522f475Smrg	-1
2769d522f475Smrg    }, not_equal_to[] =
2770d522f475Smrg    {
2771d522f475Smrg	SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3,	CHR_HIGH),
2772d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,   2*BOX_HIGH/3),
2773d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
2774d522f475Smrg	-1
2775d522f475Smrg    };
2776d522f475Smrg    /* *INDENT-ON* */
2777d522f475Smrg
2778d522f475Smrg    static const short *lines[] =
2779d522f475Smrg    {
2780d522f475Smrg	0,			/* 00 (unused) */
2781d522f475Smrg	0,			/* 01 diamond */
2782d522f475Smrg	0,			/* 02 box */
2783d522f475Smrg	glyph_ht,		/* 03 HT */
2784d522f475Smrg	glyph_ff,		/* 04 FF */
2785d522f475Smrg	0,			/* 05 CR */
2786d522f475Smrg	glyph_lf,		/* 06 LF */
2787d522f475Smrg	0,			/* 07 degrees (small circle) */
2788d522f475Smrg	plus_or_minus,		/* 08 */
2789d522f475Smrg	glyph_nl,		/* 09 */
2790d522f475Smrg	glyph_vt,		/* 0A */
2791d522f475Smrg	lower_right_corner,	/* 0B */
2792d522f475Smrg	upper_right_corner,	/* 0C */
2793d522f475Smrg	upper_left_corner,	/* 0D */
2794d522f475Smrg	lower_left_corner,	/* 0E */
2795d522f475Smrg	cross,			/* 0F */
2796d522f475Smrg	scan_line_1,		/* 10 */
2797d522f475Smrg	scan_line_3,		/* 11 */
2798d522f475Smrg	scan_line_7,		/* 12 */
2799d522f475Smrg	scan_line_9,		/* 13 */
2800d522f475Smrg	horizontal_line,	/* 14 */
2801d522f475Smrg	left_tee,		/* 15 */
2802d522f475Smrg	right_tee,		/* 16 */
2803d522f475Smrg	bottom_tee,		/* 17 */
2804d522f475Smrg	top_tee,		/* 18 */
2805d522f475Smrg	vertical_line,		/* 19 */
2806d522f475Smrg	less_than_or_equal,	/* 1A */
2807d522f475Smrg	greater_than_or_equal,	/* 1B */
2808d522f475Smrg	greek_pi,		/* 1C */
2809d522f475Smrg	not_equal_to,		/* 1D */
2810d522f475Smrg	0,			/* 1E LB */
2811d522f475Smrg	0,			/* 1F bullet */
2812d522f475Smrg    };
2813d522f475Smrg
2814d522f475Smrg    GC gc2;
2815d522f475Smrg    CgsEnum cgsId = (ch == 2) ? gcDots : gcLine;
2816d522f475Smrg    VTwin *cgsWin = WhichVWin(screen);
2817d522f475Smrg    const short *p;
28189a64e1c5Smrg    unsigned font_width = (unsigned) (((draw_flags & DOUBLEWFONT) ? 2 : 1)
28199a64e1c5Smrg				      * screen->fnt_wide);
28209a64e1c5Smrg    unsigned font_height = (unsigned) (((draw_flags & DOUBLEHFONT) ? 2 : 1)
28219a64e1c5Smrg				       * screen->fnt_high);
2822d522f475Smrg
2823d522f475Smrg    if (cells > 1)
2824956cc18dSsnj	font_width *= (unsigned) cells;
2825d522f475Smrg
2826d522f475Smrg#if OPT_WIDE_CHARS
2827d522f475Smrg    /*
2828d522f475Smrg     * Try to show line-drawing characters if we happen to be in UTF-8
2829d522f475Smrg     * mode, but have gotten an old-style font.
2830d522f475Smrg     */
2831d522f475Smrg    if (screen->utf8_mode
2832d522f475Smrg#if OPT_RENDERFONT
2833d522f475Smrg	&& !UsingRenderFont(xw)
2834d522f475Smrg#endif
2835d522f475Smrg	&& (ch > 127)
2836d522f475Smrg	&& (ch != UCS_REPL)) {
2837d522f475Smrg	unsigned n;
2838d522f475Smrg	for (n = 1; n < 32; n++) {
2839d522f475Smrg	    if (dec2ucs(n) == ch
28409a64e1c5Smrg		&& !((attr_flags & BOLD)
284120d2c4d2Smrg		     ? IsXtermMissingChar(screen, n, &screen->fnts[fBold])
284220d2c4d2Smrg		     : IsXtermMissingChar(screen, n, &screen->fnts[fNorm]))) {
2843d522f475Smrg		TRACE(("...use xterm-style linedrawing\n"));
2844d522f475Smrg		ch = n;
2845d522f475Smrg		break;
2846d522f475Smrg	    }
2847d522f475Smrg	}
2848d522f475Smrg    }
2849d522f475Smrg#endif
2850d522f475Smrg
2851d522f475Smrg    TRACE(("DRAW_BOX(%d) cell %dx%d at %d,%d%s\n",
2852d522f475Smrg	   ch, font_height, font_width, y, x,
2853d522f475Smrg	   (ch >= (sizeof(lines) / sizeof(lines[0]))
2854d522f475Smrg	    ? "-BAD"
2855d522f475Smrg	    : "")));
2856d522f475Smrg
2857d522f475Smrg    if (cgsId == gcDots) {
2858d522f475Smrg	setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2859d522f475Smrg	setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc));
2860d522f475Smrg	setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2861d522f475Smrg    } else {
2862d522f475Smrg	setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2863d522f475Smrg	setCgsFore(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2864d522f475Smrg	setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2865d522f475Smrg    }
2866d522f475Smrg    gc2 = getCgsGC(xw, cgsWin, cgsId);
2867d522f475Smrg
28689a64e1c5Smrg    if (!(draw_flags & NOBACKGROUND)) {
28690bd37d32Smrg	XFillRectangle(screen->display, VDrawable(screen), gc2, x, y,
2870d522f475Smrg		       font_width,
2871d522f475Smrg		       font_height);
2872d522f475Smrg    }
2873d522f475Smrg
2874d522f475Smrg    setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2875d522f475Smrg    setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc));
2876d522f475Smrg    setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2877d522f475Smrg    gc2 = getCgsGC(xw, cgsWin, cgsId);
2878d522f475Smrg
2879d522f475Smrg    XSetLineAttributes(screen->display, gc2,
28809a64e1c5Smrg		       (attr_flags & BOLD)
2881d522f475Smrg		       ? ((font_height > 12)
2882d522f475Smrg			  ? font_height / 12
2883d522f475Smrg			  : 1)
2884d522f475Smrg		       : ((font_height > 16)
2885d522f475Smrg			  ? font_height / 16
2886d522f475Smrg			  : 1),
2887d522f475Smrg		       LineSolid,
2888d522f475Smrg		       CapProjecting,
2889d522f475Smrg		       JoinMiter);
2890d522f475Smrg
2891d522f475Smrg    if (ch == 1) {		/* diamond */
2892d522f475Smrg	XPoint points[5];
2893d522f475Smrg	int npoints = 5, n;
2894d522f475Smrg
2895d522f475Smrg	points[0].x = MID_WIDE;
2896d522f475Smrg	points[0].y = BOX_HIGH / 4;
2897d522f475Smrg
2898d522f475Smrg	points[1].x = 8 * BOX_WIDE / 8;
2899d522f475Smrg	points[1].y = MID_HIGH;
2900d522f475Smrg
2901d522f475Smrg	points[2].x = points[0].x;
2902d522f475Smrg	points[2].y = 3 * BOX_HIGH / 4;
2903d522f475Smrg
2904d522f475Smrg	points[3].x = 0 * BOX_WIDE / 8;
2905d522f475Smrg	points[3].y = points[1].y;
2906d522f475Smrg
2907d522f475Smrg	points[4].x = points[0].x;
2908d522f475Smrg	points[4].y = points[0].y;
2909d522f475Smrg
2910d522f475Smrg	for (n = 0; n < npoints; ++n) {
2911e39b573cSmrg	    points[n].x = (short) SCALED_X(points[n].x);
2912e39b573cSmrg	    points[n].y = (short) SCALED_Y(points[n].y);
2913e39b573cSmrg	    points[n].x = (short) (points[n].x + x);
2914e39b573cSmrg	    points[n].y = (short) (points[n].y + y);
2915d522f475Smrg	}
2916d522f475Smrg
2917d522f475Smrg	XFillPolygon(screen->display,
29180bd37d32Smrg		     VDrawable(screen), gc2,
2919d522f475Smrg		     points, npoints,
2920d522f475Smrg		     Convex, CoordModeOrigin);
2921d522f475Smrg    } else if (ch == 7) {	/* degrees */
2922d522f475Smrg	unsigned width = (BOX_WIDE / 3);
2923956cc18dSsnj	int x_coord = MID_WIDE - (int) (width / 2);
2924956cc18dSsnj	int y_coord = MID_HIGH - (int) width;
2925d522f475Smrg
2926d522f475Smrg	SCALE_X(x_coord);
2927d522f475Smrg	SCALE_Y(y_coord);
2928e39b573cSmrg	width = (unsigned) SCALED_X(width);
2929d522f475Smrg
2930d522f475Smrg	XDrawArc(screen->display,
29310bd37d32Smrg		 VDrawable(screen), gc2,
2932d522f475Smrg		 x + x_coord, y + y_coord, width, width,
2933d522f475Smrg		 0,
2934d522f475Smrg		 360 * 64);
2935d522f475Smrg    } else if (ch == 0x1f) {	/* bullet */
2936d522f475Smrg	unsigned width = 7 * BOX_WIDE / 10;
2937956cc18dSsnj	int x_coord = MID_WIDE - (int) (width / 3);
2938956cc18dSsnj	int y_coord = MID_HIGH - (int) (width / 3);
2939d522f475Smrg
2940d522f475Smrg	SCALE_X(x_coord);
2941d522f475Smrg	SCALE_Y(y_coord);
2942e39b573cSmrg	width = (unsigned) SCALED_X(width);
2943d522f475Smrg
2944d522f475Smrg	XDrawArc(screen->display,
29450bd37d32Smrg		 VDrawable(screen), gc2,
2946d522f475Smrg		 x + x_coord, y + y_coord, width, width,
2947d522f475Smrg		 0,
2948d522f475Smrg		 360 * 64);
2949d522f475Smrg    } else if (ch < (sizeof(lines) / sizeof(lines[0]))
2950d522f475Smrg	       && (p = lines[ch]) != 0) {
2951956cc18dSsnj	int coord[4];
2952d522f475Smrg	int n = 0;
2953d522f475Smrg	while (*p >= 0) {
2954d522f475Smrg	    coord[n++] = *p++;
2955d522f475Smrg	    if (n == 4) {
2956d522f475Smrg		SCALE_X(coord[0]);
2957d522f475Smrg		SCALE_Y(coord[1]);
2958d522f475Smrg		SCALE_X(coord[2]);
2959d522f475Smrg		SCALE_Y(coord[3]);
2960d522f475Smrg		XDrawLine(screen->display,
29610bd37d32Smrg			  VDrawable(screen), gc2,
2962d522f475Smrg			  x + coord[0], y + coord[1],
2963d522f475Smrg			  x + coord[2], y + coord[3]);
2964d522f475Smrg		n = 0;
2965d522f475Smrg	    }
2966d522f475Smrg	}
2967d522f475Smrg    } else if (screen->force_all_chars) {
2968d522f475Smrg	/* bounding rectangle, for debugging */
29690bd37d32Smrg	XDrawRectangle(screen->display, VDrawable(screen), gc2, x, y,
2970d522f475Smrg		       font_width - 1,
2971d522f475Smrg		       font_height - 1);
2972d522f475Smrg    }
2973d522f475Smrg}
2974fa3f02f3Smrg#endif /* OPT_BOX_CHARS */
2975d522f475Smrg
2976d522f475Smrg#if OPT_RENDERFONT
2977d522f475Smrg
2978d522f475Smrg/*
2979d522f475Smrg * Check if the given character has a glyph known to Xft.
2980d522f475Smrg *
2981d522f475Smrg * see xc/lib/Xft/xftglyphs.c
2982d522f475Smrg */
2983d522f475SmrgBool
29849a64e1c5SmrgxtermXftMissing(XtermWidget xw, XftFont *font, unsigned wc)
2985d522f475Smrg{
2986d522f475Smrg    Bool result = False;
2987d522f475Smrg
2988d522f475Smrg    if (font != 0) {
2989956cc18dSsnj	TScreen *screen = TScreenOf(xw);
2990956cc18dSsnj	if (!XftGlyphExists(screen->display, font, wc)) {
2991d522f475Smrg#if OPT_WIDE_CHARS
2992d522f475Smrg	    TRACE(("xtermXftMissing %d (dec=%#x, ucs=%#x)\n",
2993d522f475Smrg		   wc, ucs2dec(wc), dec2ucs(wc)));
2994d522f475Smrg#else
2995d522f475Smrg	    TRACE(("xtermXftMissing %d\n", wc));
2996d522f475Smrg#endif
2997d522f475Smrg	    result = True;
2998d522f475Smrg	}
2999d522f475Smrg    }
3000d522f475Smrg    return result;
3001d522f475Smrg}
3002fa3f02f3Smrg#endif /* OPT_RENDERFONT */
3003d522f475Smrg
3004d522f475Smrg#if OPT_WIDE_CHARS
3005d522f475Smrg#define MY_UCS(ucs,dec) case ucs: result = dec; break
3006d522f475Smrgunsigned
3007d522f475Smrgucs2dec(unsigned ch)
3008d522f475Smrg{
3009d522f475Smrg    unsigned result = ch;
3010d522f475Smrg    if ((ch > 127)
3011d522f475Smrg	&& (ch != UCS_REPL)) {
3012d522f475Smrg	switch (ch) {
3013d522f475Smrg	    MY_UCS(0x25ae, 0);	/* black vertical rectangle                   */
3014d522f475Smrg	    MY_UCS(0x25c6, 1);	/* black diamond                              */
3015d522f475Smrg	    MY_UCS(0x2592, 2);	/* medium shade                               */
3016d522f475Smrg	    MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation           */
3017d522f475Smrg	    MY_UCS(0x240c, 4);	/* symbol for form feed                       */
3018d522f475Smrg	    MY_UCS(0x240d, 5);	/* symbol for carriage return                 */
3019d522f475Smrg	    MY_UCS(0x240a, 6);	/* symbol for line feed                       */
3020d522f475Smrg	    MY_UCS(0x00b0, 7);	/* degree sign                                */
3021d522f475Smrg	    MY_UCS(0x00b1, 8);	/* plus-minus sign                            */
3022d522f475Smrg	    MY_UCS(0x2424, 9);	/* symbol for newline                         */
3023d522f475Smrg	    MY_UCS(0x240b, 10);	/* symbol for vertical tabulation             */
3024d522f475Smrg	    MY_UCS(0x2518, 11);	/* box drawings light up and left             */
3025d522f475Smrg	    MY_UCS(0x2510, 12);	/* box drawings light down and left           */
3026d522f475Smrg	    MY_UCS(0x250c, 13);	/* box drawings light down and right          */
3027d522f475Smrg	    MY_UCS(0x2514, 14);	/* box drawings light up and right            */
3028d522f475Smrg	    MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
3029d522f475Smrg	    MY_UCS(0x23ba, 16);	/* box drawings scan 1                        */
3030d522f475Smrg	    MY_UCS(0x23bb, 17);	/* box drawings scan 3                        */
3031d522f475Smrg	    MY_UCS(0x2500, 18);	/* box drawings light horizontal              */
3032d522f475Smrg	    MY_UCS(0x23bc, 19);	/* box drawings scan 7                        */
3033d522f475Smrg	    MY_UCS(0x23bd, 20);	/* box drawings scan 9                        */
3034d522f475Smrg	    MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
3035d522f475Smrg	    MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
3036d522f475Smrg	    MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
3037d522f475Smrg	    MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
3038d522f475Smrg	    MY_UCS(0x2502, 25);	/* box drawings light vertical                */
3039d522f475Smrg	    MY_UCS(0x2264, 26);	/* less-than or equal to                      */
3040d522f475Smrg	    MY_UCS(0x2265, 27);	/* greater-than or equal to                   */
3041d522f475Smrg	    MY_UCS(0x03c0, 28);	/* greek small letter pi                      */
3042d522f475Smrg	    MY_UCS(0x2260, 29);	/* not equal to                               */
3043d522f475Smrg	    MY_UCS(0x00a3, 30);	/* pound sign                                 */
3044d522f475Smrg	    MY_UCS(0x00b7, 31);	/* middle dot                                 */
3045d522f475Smrg	}
3046d522f475Smrg    }
3047d522f475Smrg    return result;
3048d522f475Smrg}
3049d522f475Smrg
3050d522f475Smrg#undef  MY_UCS
3051d522f475Smrg#define MY_UCS(ucs,dec) case dec: result = ucs; break
3052d522f475Smrg
3053d522f475Smrgunsigned
3054d522f475Smrgdec2ucs(unsigned ch)
3055d522f475Smrg{
3056d522f475Smrg    unsigned result = ch;
3057d522f475Smrg    if (xtermIsDecGraphic(ch)) {
3058d522f475Smrg	switch (ch) {
3059d522f475Smrg	    MY_UCS(0x25ae, 0);	/* black vertical rectangle                   */
3060d522f475Smrg	    MY_UCS(0x25c6, 1);	/* black diamond                              */
3061d522f475Smrg	    MY_UCS(0x2592, 2);	/* medium shade                               */
3062d522f475Smrg	    MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation           */
3063d522f475Smrg	    MY_UCS(0x240c, 4);	/* symbol for form feed                       */
3064d522f475Smrg	    MY_UCS(0x240d, 5);	/* symbol for carriage return                 */
3065d522f475Smrg	    MY_UCS(0x240a, 6);	/* symbol for line feed                       */
3066d522f475Smrg	    MY_UCS(0x00b0, 7);	/* degree sign                                */
3067d522f475Smrg	    MY_UCS(0x00b1, 8);	/* plus-minus sign                            */
3068d522f475Smrg	    MY_UCS(0x2424, 9);	/* symbol for newline                         */
3069d522f475Smrg	    MY_UCS(0x240b, 10);	/* symbol for vertical tabulation             */
3070d522f475Smrg	    MY_UCS(0x2518, 11);	/* box drawings light up and left             */
3071d522f475Smrg	    MY_UCS(0x2510, 12);	/* box drawings light down and left           */
3072d522f475Smrg	    MY_UCS(0x250c, 13);	/* box drawings light down and right          */
3073d522f475Smrg	    MY_UCS(0x2514, 14);	/* box drawings light up and right            */
3074d522f475Smrg	    MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
3075d522f475Smrg	    MY_UCS(0x23ba, 16);	/* box drawings scan 1                        */
3076d522f475Smrg	    MY_UCS(0x23bb, 17);	/* box drawings scan 3                        */
3077d522f475Smrg	    MY_UCS(0x2500, 18);	/* box drawings light horizontal              */
3078d522f475Smrg	    MY_UCS(0x23bc, 19);	/* box drawings scan 7                        */
3079d522f475Smrg	    MY_UCS(0x23bd, 20);	/* box drawings scan 9                        */
3080d522f475Smrg	    MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
3081d522f475Smrg	    MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
3082d522f475Smrg	    MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
3083d522f475Smrg	    MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
3084d522f475Smrg	    MY_UCS(0x2502, 25);	/* box drawings light vertical                */
3085d522f475Smrg	    MY_UCS(0x2264, 26);	/* less-than or equal to                      */
3086d522f475Smrg	    MY_UCS(0x2265, 27);	/* greater-than or equal to                   */
3087d522f475Smrg	    MY_UCS(0x03c0, 28);	/* greek small letter pi                      */
3088d522f475Smrg	    MY_UCS(0x2260, 29);	/* not equal to                               */
3089d522f475Smrg	    MY_UCS(0x00a3, 30);	/* pound sign                                 */
3090d522f475Smrg	    MY_UCS(0x00b7, 31);	/* middle dot                                 */
3091d522f475Smrg	}
3092d522f475Smrg    }
3093d522f475Smrg    return result;
3094d522f475Smrg}
3095d522f475Smrg
3096d522f475Smrg#endif /* OPT_WIDE_CHARS */
3097d522f475Smrg
3098b6fea0ceSmrg#if OPT_RENDERFONT || OPT_SHIFT_FONTS
30990bd37d32Smrgstatic int
3100d522f475SmrglookupOneFontSize(XtermWidget xw, int fontnum)
3101d522f475Smrg{
3102d522f475Smrg    TScreen *screen = TScreenOf(xw);
3103d522f475Smrg
3104d522f475Smrg    if (screen->menu_font_sizes[fontnum] == 0) {
3105d522f475Smrg	XTermFonts fnt;
3106d522f475Smrg
3107d522f475Smrg	memset(&fnt, 0, sizeof(fnt));
3108d522f475Smrg	screen->menu_font_sizes[fontnum] = -1;
31090bd37d32Smrg	if (xtermOpenFont(xw,
31100bd37d32Smrg			  screen->MenuFontName(fontnum),
31110bd37d32Smrg			  &fnt,
31120bd37d32Smrg			  ((fontnum <= fontMenu_lastBuiltin)
31130bd37d32Smrg			   ? fwAlways
31140bd37d32Smrg			   : fwResource),
31150bd37d32Smrg			  True)) {
311620d2c4d2Smrg	    if (fontnum <= fontMenu_lastBuiltin
31170bd37d32Smrg		|| strcmp(fnt.fn, DEFFONT)) {
311820d2c4d2Smrg		screen->menu_font_sizes[fontnum] = FontSize(fnt.fs);
31190bd37d32Smrg		if (screen->menu_font_sizes[fontnum] <= 0)
31200bd37d32Smrg		    screen->menu_font_sizes[fontnum] = -1;
31210bd37d32Smrg	    }
3122d522f475Smrg	    xtermCloseFont(xw, &fnt);
3123d522f475Smrg	}
3124d522f475Smrg    }
31250bd37d32Smrg    return (screen->menu_font_sizes[fontnum] > 0);
3126d522f475Smrg}
3127d522f475Smrg
3128d522f475Smrg/*
3129d522f475Smrg * Cache the font-sizes so subsequent larger/smaller font actions will go fast.
3130d522f475Smrg */
3131d522f475Smrgstatic void
3132d522f475SmrglookupFontSizes(XtermWidget xw)
3133d522f475Smrg{
3134d522f475Smrg    int n;
3135d522f475Smrg
3136d522f475Smrg    for (n = 0; n < NMENUFONTS; n++) {
31370bd37d32Smrg	(void) lookupOneFontSize(xw, n);
3138d522f475Smrg    }
3139d522f475Smrg}
3140b6fea0ceSmrg#endif /* OPT_RENDERFONT || OPT_SHIFT_FONTS */
3141d522f475Smrg
31422eaa94a1Schristos#if OPT_RENDERFONT
31439a64e1c5Smrgstatic double
31449a64e1c5SmrgdefaultFaceSize(void)
31459a64e1c5Smrg{
31469a64e1c5Smrg    double result;
31479a64e1c5Smrg    float value;
31489a64e1c5Smrg
31499a64e1c5Smrg    if (sscanf(DEFFACESIZE, "%f", &value) == 1)
31509a64e1c5Smrg	result = value;
31519a64e1c5Smrg    else
31529a64e1c5Smrg	result = 14.0;
31539a64e1c5Smrg    return result;
31549a64e1c5Smrg}
31559a64e1c5Smrg
31560bd37d32Smrgstatic void
31570bd37d32SmrgfillInFaceSize(XtermWidget xw, int fontnum)
31580bd37d32Smrg{
31590bd37d32Smrg    TScreen *screen = TScreenOf(xw);
31600bd37d32Smrg    double face_size = xw->misc.face_size[fontnum];
31610bd37d32Smrg
31620bd37d32Smrg    if (face_size <= 0.0) {
31630bd37d32Smrg#if OPT_SHIFT_FONTS
31640bd37d32Smrg	/*
31650bd37d32Smrg	 * If the user is switching font-sizes, make it follow by
31660bd37d32Smrg	 * default the same ratios to the default as the fixed fonts
31670bd37d32Smrg	 * would, for easy comparison.  There will be some differences
31680bd37d32Smrg	 * since the fixed fonts have a variety of height/width ratios,
31690bd37d32Smrg	 * but this is simpler than adding another resource value - and
31700bd37d32Smrg	 * as noted above, the data for the fixed fonts are available.
31710bd37d32Smrg	 */
31720bd37d32Smrg	(void) lookupOneFontSize(xw, 0);
31730bd37d32Smrg	if (fontnum == fontMenu_default) {
31749a64e1c5Smrg	    face_size = defaultFaceSize();
31750bd37d32Smrg	} else if (lookupOneFontSize(xw, fontnum)
31760bd37d32Smrg		   && (screen->menu_font_sizes[0]
31770bd37d32Smrg		       != screen->menu_font_sizes[fontnum])) {
31780bd37d32Smrg	    double ratio;
31790bd37d32Smrg	    long num = screen->menu_font_sizes[fontnum];
31800bd37d32Smrg	    long den = screen->menu_font_sizes[0];
31810bd37d32Smrg
31820bd37d32Smrg	    if (den <= 0)
31830bd37d32Smrg		den = 1;
31840bd37d32Smrg	    ratio = dimSquareRoot((double) num / (double) den);
31850bd37d32Smrg
31860bd37d32Smrg	    face_size = (ratio * xw->misc.face_size[0]);
31870bd37d32Smrg	    TRACE(("scaled[%d] using %3ld/%ld = %.2f -> %f\n",
31880bd37d32Smrg		   fontnum, num, den, ratio, face_size));
31890bd37d32Smrg	} else
31900bd37d32Smrg#endif
31910bd37d32Smrg	{
31920bd37d32Smrg#define LikeBitmap(s) (((s) / 78.0) * xw->misc.face_size[fontMenu_default])
31930bd37d32Smrg	    switch (fontnum) {
31940bd37d32Smrg	    case fontMenu_font1:
31950bd37d32Smrg		face_size = LikeBitmap(2.0);
31960bd37d32Smrg		break;
31970bd37d32Smrg	    case fontMenu_font2:
31980bd37d32Smrg		face_size = LikeBitmap(35.0);
31990bd37d32Smrg		break;
32000bd37d32Smrg	    case fontMenu_font3:
32010bd37d32Smrg		face_size = LikeBitmap(60.0);
32020bd37d32Smrg		break;
32030bd37d32Smrg	    default:
32049a64e1c5Smrg		face_size = defaultFaceSize();
32050bd37d32Smrg		break;
32060bd37d32Smrg	    case fontMenu_font4:
32070bd37d32Smrg		face_size = LikeBitmap(90.0);
32080bd37d32Smrg		break;
32090bd37d32Smrg	    case fontMenu_font5:
32100bd37d32Smrg		face_size = LikeBitmap(135.0);
32110bd37d32Smrg		break;
32120bd37d32Smrg	    case fontMenu_font6:
32130bd37d32Smrg		face_size = LikeBitmap(200.0);
32140bd37d32Smrg		break;
32150bd37d32Smrg	    }
32160bd37d32Smrg	    TRACE(("builtin[%d] -> %f\n", fontnum, face_size));
32170bd37d32Smrg	}
32180bd37d32Smrg	xw->misc.face_size[fontnum] = (float) face_size;
32190bd37d32Smrg    }
32200bd37d32Smrg}
32210bd37d32Smrg
32220bd37d32Smrg/* no selection or escape */
32230bd37d32Smrg#define NMENU_RENDERFONTS (fontMenu_lastBuiltin + 1)
32240bd37d32Smrg
32250bd37d32Smrg/*
32260bd37d32Smrg * Workaround for breakage in font-packages - check if all of the bitmap font
32270bd37d32Smrg * sizes are the same, and if we're using TrueType fonts.
32280bd37d32Smrg */
32292eaa94a1Schristosstatic Boolean
32302eaa94a1SchristosuseFaceSizes(XtermWidget xw)
32312eaa94a1Schristos{
32322eaa94a1Schristos    Boolean result = False;
32332eaa94a1Schristos    int n;
32342eaa94a1Schristos
32350bd37d32Smrg    TRACE(("useFaceSizes {{\n"));
32362eaa94a1Schristos    if (UsingRenderFont(xw)) {
32370bd37d32Smrg	Boolean nonzero = True;
32380bd37d32Smrg
32392eaa94a1Schristos	for (n = 0; n < NMENU_RENDERFONTS; ++n) {
32402eaa94a1Schristos	    if (xw->misc.face_size[n] <= 0.0) {
32410bd37d32Smrg		nonzero = False;
32422eaa94a1Schristos		break;
32432eaa94a1Schristos	    }
32442eaa94a1Schristos	}
32450bd37d32Smrg	if (!nonzero) {
3246956cc18dSsnj	    Boolean broken_fonts = True;
3247956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
32480bd37d32Smrg	    long first;
3249956cc18dSsnj
3250956cc18dSsnj	    lookupFontSizes(xw);
32510bd37d32Smrg	    first = screen->menu_font_sizes[0];
3252956cc18dSsnj	    for (n = 0; n < NMENUFONTS; n++) {
3253956cc18dSsnj		if (screen->menu_font_sizes[n] > 0
3254956cc18dSsnj		    && screen->menu_font_sizes[n] != first) {
3255956cc18dSsnj		    broken_fonts = False;
3256956cc18dSsnj		    break;
3257956cc18dSsnj		}
3258956cc18dSsnj	    }
3259956cc18dSsnj
3260956cc18dSsnj	    if (broken_fonts) {
3261956cc18dSsnj
3262956cc18dSsnj		TRACE(("bitmap fonts are broken - set faceSize resources\n"));
3263956cc18dSsnj		for (n = 0; n < NMENUFONTS; n++) {
32640bd37d32Smrg		    fillInFaceSize(xw, n);
3265956cc18dSsnj		}
3266956cc18dSsnj
3267956cc18dSsnj	    }
3268956cc18dSsnj	}
32690bd37d32Smrg	result = True;
32702eaa94a1Schristos    }
32710bd37d32Smrg    TRACE(("...}}useFaceSizes %d\n", result));
32722eaa94a1Schristos    return result;
32732eaa94a1Schristos}
32740bd37d32Smrg#endif /* OPT_RENDERFONT */
32752eaa94a1Schristos
3276b6fea0ceSmrg#if OPT_SHIFT_FONTS
3277d522f475Smrg/*
3278d522f475Smrg * Find the index of a larger/smaller font (according to the sign of 'relative'
3279d522f475Smrg * and its magnitude), starting from the 'old' index.
3280d522f475Smrg */
3281d522f475Smrgint
3282d522f475SmrglookupRelativeFontSize(XtermWidget xw, int old, int relative)
3283d522f475Smrg{
3284d522f475Smrg    TScreen *screen = TScreenOf(xw);
3285d522f475Smrg    int n, m = -1;
3286d522f475Smrg
32872eaa94a1Schristos    TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative));
3288d522f475Smrg    if (!IsIcon(screen)) {
32892eaa94a1Schristos#if OPT_RENDERFONT
32902eaa94a1Schristos	if (useFaceSizes(xw)) {
32912eaa94a1Schristos	    TRACE(("...using FaceSize\n"));
32922eaa94a1Schristos	    if (relative != 0) {
32932eaa94a1Schristos		for (n = 0; n < NMENU_RENDERFONTS; ++n) {
32940bd37d32Smrg		    fillInFaceSize(xw, n);
32952eaa94a1Schristos		    if (xw->misc.face_size[n] > 0 &&
32962eaa94a1Schristos			xw->misc.face_size[n] != xw->misc.face_size[old]) {
32972eaa94a1Schristos			int cmp_0 = ((xw->misc.face_size[n] >
32982eaa94a1Schristos				      xw->misc.face_size[old])
32992eaa94a1Schristos				     ? relative
33002eaa94a1Schristos				     : -relative);
33012eaa94a1Schristos			int cmp_m = ((m < 0)
33022eaa94a1Schristos				     ? 1
33032eaa94a1Schristos				     : ((xw->misc.face_size[n] <
33042eaa94a1Schristos					 xw->misc.face_size[m])
33052eaa94a1Schristos					? relative
33062eaa94a1Schristos					: -relative));
33072eaa94a1Schristos			if (cmp_0 > 0 && cmp_m > 0) {
33082eaa94a1Schristos			    m = n;
33092eaa94a1Schristos			}
3310d522f475Smrg		    }
3311d522f475Smrg		}
3312d522f475Smrg	    }
33132eaa94a1Schristos	} else
33142eaa94a1Schristos#endif
33152eaa94a1Schristos	{
33162eaa94a1Schristos	    TRACE(("...using bitmap areas\n"));
33172eaa94a1Schristos	    lookupFontSizes(xw);
33182eaa94a1Schristos	    if (relative != 0) {
33192eaa94a1Schristos		for (n = 0; n < NMENUFONTS; ++n) {
33202eaa94a1Schristos		    if (screen->menu_font_sizes[n] > 0 &&
33212eaa94a1Schristos			screen->menu_font_sizes[n] !=
33222eaa94a1Schristos			screen->menu_font_sizes[old]) {
33232eaa94a1Schristos			int cmp_0 = ((screen->menu_font_sizes[n] >
33242eaa94a1Schristos				      screen->menu_font_sizes[old])
33252eaa94a1Schristos				     ? relative
33262eaa94a1Schristos				     : -relative);
33272eaa94a1Schristos			int cmp_m = ((m < 0)
33282eaa94a1Schristos				     ? 1
33292eaa94a1Schristos				     : ((screen->menu_font_sizes[n] <
33302eaa94a1Schristos					 screen->menu_font_sizes[m])
33312eaa94a1Schristos					? relative
33322eaa94a1Schristos					: -relative));
33332eaa94a1Schristos			if (cmp_0 > 0 && cmp_m > 0) {
33342eaa94a1Schristos			    m = n;
33352eaa94a1Schristos			}
33362eaa94a1Schristos		    }
33372eaa94a1Schristos		}
3338d522f475Smrg	    }
3339d522f475Smrg	}
33402eaa94a1Schristos	TRACE(("...new index %d\n", m));
33412eaa94a1Schristos	if (m >= 0) {
33422eaa94a1Schristos	    if (relative > 1)
33432eaa94a1Schristos		m = lookupRelativeFontSize(xw, m, relative - 1);
33442eaa94a1Schristos	    else if (relative < -1)
33452eaa94a1Schristos		m = lookupRelativeFontSize(xw, m, relative + 1);
33462eaa94a1Schristos	}
3347d522f475Smrg    }
3348d522f475Smrg    return m;
3349d522f475Smrg}
3350d522f475Smrg
3351d522f475Smrg/* ARGSUSED */
3352d522f475Smrgvoid
3353d522f475SmrgHandleLargerFont(Widget w GCC_UNUSED,
33549a64e1c5Smrg		 XEvent *event GCC_UNUSED,
3355fa3f02f3Smrg		 String *params GCC_UNUSED,
3356d522f475Smrg		 Cardinal *param_count GCC_UNUSED)
3357d522f475Smrg{
3358956cc18dSsnj    XtermWidget xw;
3359d522f475Smrg
336020d2c4d2Smrg    TRACE(("Handle larger-vt-font for %p\n", (void *) w));
3361956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
3362d522f475Smrg	if (xw->misc.shift_fonts) {
3363956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
3364d522f475Smrg	    int m;
3365d522f475Smrg
3366d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, 1);
3367d522f475Smrg	    if (m >= 0) {
3368d522f475Smrg		SetVTFont(xw, m, True, NULL);
3369d522f475Smrg	    } else {
337020d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
3371d522f475Smrg	    }
3372d522f475Smrg	}
3373d522f475Smrg    }
3374d522f475Smrg}
3375d522f475Smrg
3376d522f475Smrg/* ARGSUSED */
3377d522f475Smrgvoid
3378d522f475SmrgHandleSmallerFont(Widget w GCC_UNUSED,
33799a64e1c5Smrg		  XEvent *event GCC_UNUSED,
3380fa3f02f3Smrg		  String *params GCC_UNUSED,
3381d522f475Smrg		  Cardinal *param_count GCC_UNUSED)
3382d522f475Smrg{
3383956cc18dSsnj    XtermWidget xw;
3384d522f475Smrg
338520d2c4d2Smrg    TRACE(("Handle smaller-vt-font for %p\n", (void *) w));
3386956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
3387d522f475Smrg	if (xw->misc.shift_fonts) {
3388956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
3389d522f475Smrg	    int m;
3390d522f475Smrg
3391d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, -1);
3392d522f475Smrg	    if (m >= 0) {
3393d522f475Smrg		SetVTFont(xw, m, True, NULL);
3394d522f475Smrg	    } else {
339520d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
3396d522f475Smrg	    }
3397d522f475Smrg	}
3398d522f475Smrg    }
3399d522f475Smrg}
3400b6fea0ceSmrg#endif /* OPT_SHIFT_FONTS */
3401d522f475Smrg
3402d522f475Smrgint
3403d522f475SmrgxtermGetFont(const char *param)
3404d522f475Smrg{
3405d522f475Smrg    int fontnum;
3406d522f475Smrg
3407d522f475Smrg    switch (param[0]) {
3408d522f475Smrg    case 'd':
3409d522f475Smrg    case 'D':
3410d522f475Smrg    case '0':
3411d522f475Smrg	fontnum = fontMenu_default;
3412d522f475Smrg	break;
3413d522f475Smrg    case '1':
3414d522f475Smrg	fontnum = fontMenu_font1;
3415d522f475Smrg	break;
3416d522f475Smrg    case '2':
3417d522f475Smrg	fontnum = fontMenu_font2;
3418d522f475Smrg	break;
3419d522f475Smrg    case '3':
3420d522f475Smrg	fontnum = fontMenu_font3;
3421d522f475Smrg	break;
3422d522f475Smrg    case '4':
3423d522f475Smrg	fontnum = fontMenu_font4;
3424d522f475Smrg	break;
3425d522f475Smrg    case '5':
3426d522f475Smrg	fontnum = fontMenu_font5;
3427d522f475Smrg	break;
3428d522f475Smrg    case '6':
3429d522f475Smrg	fontnum = fontMenu_font6;
3430d522f475Smrg	break;
3431d522f475Smrg    case 'e':
3432d522f475Smrg    case 'E':
3433d522f475Smrg	fontnum = fontMenu_fontescape;
3434d522f475Smrg	break;
3435d522f475Smrg    case 's':
3436d522f475Smrg    case 'S':
3437d522f475Smrg	fontnum = fontMenu_fontsel;
3438d522f475Smrg	break;
3439d522f475Smrg    default:
3440d522f475Smrg	fontnum = -1;
3441d522f475Smrg	break;
3442d522f475Smrg    }
3443d522f475Smrg    return fontnum;
3444d522f475Smrg}
3445d522f475Smrg
3446d522f475Smrg/* ARGSUSED */
3447d522f475Smrgvoid
3448d522f475SmrgHandleSetFont(Widget w GCC_UNUSED,
34499a64e1c5Smrg	      XEvent *event GCC_UNUSED,
3450fa3f02f3Smrg	      String *params,
3451d522f475Smrg	      Cardinal *param_count)
3452d522f475Smrg{
3453956cc18dSsnj    XtermWidget xw;
3454956cc18dSsnj
3455956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
3456d522f475Smrg	int fontnum;
3457d522f475Smrg	VTFontNames fonts;
3458d522f475Smrg
3459d522f475Smrg	memset(&fonts, 0, sizeof(fonts));
3460d522f475Smrg
3461d522f475Smrg	if (*param_count == 0) {
3462d522f475Smrg	    fontnum = fontMenu_default;
3463d522f475Smrg	} else {
3464d522f475Smrg	    Cardinal maxparams = 1;	/* total number of params allowed */
3465d522f475Smrg	    int result = xtermGetFont(params[0]);
3466d522f475Smrg
3467d522f475Smrg	    switch (result) {
3468d522f475Smrg	    case fontMenu_default:	/* FALLTHRU */
3469d522f475Smrg	    case fontMenu_font1:	/* FALLTHRU */
3470d522f475Smrg	    case fontMenu_font2:	/* FALLTHRU */
3471d522f475Smrg	    case fontMenu_font3:	/* FALLTHRU */
3472d522f475Smrg	    case fontMenu_font4:	/* FALLTHRU */
3473d522f475Smrg	    case fontMenu_font5:	/* FALLTHRU */
3474d522f475Smrg	    case fontMenu_font6:	/* FALLTHRU */
3475d522f475Smrg		break;
3476d522f475Smrg	    case fontMenu_fontescape:
3477d522f475Smrg#if OPT_WIDE_CHARS
3478d522f475Smrg		maxparams = 5;
3479d522f475Smrg#else
3480d522f475Smrg		maxparams = 3;
3481d522f475Smrg#endif
3482d522f475Smrg		break;
3483d522f475Smrg	    case fontMenu_fontsel:
3484d522f475Smrg		maxparams = 2;
3485d522f475Smrg		break;
3486d522f475Smrg	    default:
348720d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
3488d522f475Smrg		return;
3489d522f475Smrg	    }
3490d522f475Smrg	    fontnum = result;
3491d522f475Smrg
3492d522f475Smrg	    if (*param_count > maxparams) {	/* see if extra args given */
349320d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
3494d522f475Smrg		return;
3495d522f475Smrg	    }
3496d522f475Smrg	    switch (*param_count) {	/* assign 'em */
3497d522f475Smrg#if OPT_WIDE_CHARS
3498d522f475Smrg	    case 5:
3499d522f475Smrg		fonts.f_wb = params[4];
3500d522f475Smrg		/* FALLTHRU */
3501d522f475Smrg	    case 4:
3502d522f475Smrg		fonts.f_w = params[3];
3503d522f475Smrg		/* FALLTHRU */
3504d522f475Smrg#endif
3505d522f475Smrg	    case 3:
3506d522f475Smrg		fonts.f_b = params[2];
3507d522f475Smrg		/* FALLTHRU */
3508d522f475Smrg	    case 2:
3509d522f475Smrg		fonts.f_n = params[1];
3510d522f475Smrg		break;
3511d522f475Smrg	    }
3512d522f475Smrg	}
3513d522f475Smrg
3514956cc18dSsnj	SetVTFont(xw, fontnum, True, &fonts);
3515d522f475Smrg    }
3516d522f475Smrg}
3517d522f475Smrg
3518d522f475Smrgvoid
3519d522f475SmrgSetVTFont(XtermWidget xw,
3520d522f475Smrg	  int which,
3521d522f475Smrg	  Bool doresize,
3522d522f475Smrg	  const VTFontNames * fonts)
3523d522f475Smrg{
3524956cc18dSsnj    TScreen *screen = TScreenOf(xw);
3525d522f475Smrg
3526d522f475Smrg    TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which,
3527d522f475Smrg	   (fonts && fonts->f_n) ? fonts->f_n : "<null>",
3528d522f475Smrg	   (fonts && fonts->f_b) ? fonts->f_b : "<null>"));
3529d522f475Smrg
3530d522f475Smrg    if (IsIcon(screen)) {
353120d2c4d2Smrg	Bell(xw, XkbBI_MinorError, 0);
3532d522f475Smrg    } else if (which >= 0 && which < NMENUFONTS) {
3533d522f475Smrg	VTFontNames myfonts;
3534d522f475Smrg
3535d522f475Smrg	memset(&myfonts, 0, sizeof(myfonts));
3536d522f475Smrg	if (fonts != 0)
3537d522f475Smrg	    myfonts = *fonts;
3538d522f475Smrg
3539d522f475Smrg	if (which == fontMenu_fontsel) {	/* go get the selection */
3540d522f475Smrg	    FindFontSelection(xw, myfonts.f_n, False);
3541d522f475Smrg	} else {
3542d522f475Smrg	    int oldFont = screen->menu_font_number;
3543d522f475Smrg
3544d522f475Smrg#define USE_CACHED(field, name) \
3545d522f475Smrg	    if (myfonts.field == 0) { \
3546492d43a5Smrg		myfonts.field = x_strdup(screen->menu_font_names[which][name]); \
3547d522f475Smrg		TRACE(("set myfonts." #field " from menu_font_names[%d][" #name "] %s\n", \
3548d522f475Smrg		       which, NonNull(myfonts.field))); \
3549d522f475Smrg	    } else { \
3550d522f475Smrg		TRACE(("set myfonts." #field " reused\n")); \
3551d522f475Smrg	    }
355220d2c4d2Smrg#define SAVE_FNAME(field, name) \
355320d2c4d2Smrg	    if (myfonts.field != 0) { \
355420d2c4d2Smrg		if (screen->menu_font_names[which][name] == 0 \
355520d2c4d2Smrg		 || strcmp(screen->menu_font_names[which][name], myfonts.field)) { \
355620d2c4d2Smrg		    TRACE(("updating menu_font_names[%d][" #name "] to %s\n", \
355720d2c4d2Smrg			   which, myfonts.field)); \
35589a64e1c5Smrg		    FREE_STRING(screen->menu_font_names[which][name]); \
355920d2c4d2Smrg		    screen->menu_font_names[which][name] = x_strdup(myfonts.field); \
356020d2c4d2Smrg		} \
356120d2c4d2Smrg	    }
356220d2c4d2Smrg
3563d522f475Smrg	    USE_CACHED(f_n, fNorm);
3564d522f475Smrg	    USE_CACHED(f_b, fBold);
3565d522f475Smrg#if OPT_WIDE_CHARS
3566d522f475Smrg	    USE_CACHED(f_w, fWide);
3567d522f475Smrg	    USE_CACHED(f_wb, fWBold);
3568d522f475Smrg#endif
3569d522f475Smrg	    if (xtermLoadFont(xw,
3570d522f475Smrg			      &myfonts,
3571d522f475Smrg			      doresize, which)) {
357220d2c4d2Smrg		/*
357320d2c4d2Smrg		 * If successful, save the data so that a subsequent query via
357420d2c4d2Smrg		 * OSC-50 will return the expected values.
357520d2c4d2Smrg		 */
357620d2c4d2Smrg		SAVE_FNAME(f_n, fNorm);
357720d2c4d2Smrg		SAVE_FNAME(f_b, fBold);
357820d2c4d2Smrg#if OPT_WIDE_CHARS
357920d2c4d2Smrg		SAVE_FNAME(f_w, fWide);
358020d2c4d2Smrg		SAVE_FNAME(f_wb, fWBold);
358120d2c4d2Smrg#endif
3582d522f475Smrg	    } else {
3583d522f475Smrg		xtermLoadFont(xw,
3584d522f475Smrg			      xtermFontName(screen->MenuFontName(oldFont)),
3585d522f475Smrg			      doresize, oldFont);
358620d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
3587d522f475Smrg	    }
35889a64e1c5Smrg	    FREE_FNAME(f_n);
35899a64e1c5Smrg	    FREE_FNAME(f_b);
35909a64e1c5Smrg#if OPT_WIDE_CHARS
35919a64e1c5Smrg	    FREE_FNAME(f_w);
35929a64e1c5Smrg	    FREE_FNAME(f_wb);
35939a64e1c5Smrg#endif
3594d522f475Smrg	}
359520d2c4d2Smrg    } else {
359620d2c4d2Smrg	Bell(xw, XkbBI_MinorError, 0);
3597d522f475Smrg    }
3598d522f475Smrg    return;
3599d522f475Smrg}
3600