1190d7dceSmrg/* $XTermId: fontutils.c,v 1.787 2024/12/01 20:29:42 tom Exp $ */
2d522f475Smrg
30bd37d32Smrg/*
4980988aeSmrg * Copyright 1998-2023,2024 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>
47980988aeSmrg#include <error.h>
48d522f475Smrg#include <menu.h>
49d522f475Smrg#include <xstrings.h>
50d522f475Smrg#include <xterm.h>
51d522f475Smrg
52d522f475Smrg#include <stdio.h>
53d522f475Smrg#include <ctype.h>
54d522f475Smrg
55d1603babSmrg#define USE_FC_COLOR 0
56d1603babSmrg#if OPT_RENDERFONT
57d1603babSmrg#if XftVersion > 20304
58d1603babSmrg#undef USE_FC_COLOR
59d1603babSmrg#define USE_FC_COLOR 1
60d1603babSmrg#endif
61d1603babSmrg#endif
62d1603babSmrg
63d1603babSmrg#define FcOK(func) (func == FcResultMatch)
64d1603babSmrg
65d4fba8b9Smrg#define NoFontWarning(data) (data)->warn = fwAlways
66d4fba8b9Smrg
670bd37d32Smrg#define SetFontWidth(screen,dst,src)  (dst)->f_width = (src)
68d4fba8b9Smrg#define SetFontHeight(screen,dst,src) (dst)->f_height = dimRound((double)((screen)->scale_height * (float) (src)))
690bd37d32Smrg
70d522f475Smrg/* from X11/Xlibint.h - not all vendors install this file */
71d522f475Smrg#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
72d522f475Smrg			     (((cs)->rbearing|(cs)->lbearing| \
73d522f475Smrg			       (cs)->ascent|(cs)->descent) == 0))
74d522f475Smrg
75fa3f02f3Smrg#define CI_GET_CHAR_INFO_1D(fs,col,cs) \
76d522f475Smrg{ \
77190d7dceSmrg    cs = NULL; \
78d522f475Smrg    if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
79d522f475Smrg	if (fs->per_char == NULL) { \
80d522f475Smrg	    cs = &fs->min_bounds; \
81d522f475Smrg	} else { \
82d522f475Smrg	    cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
83d522f475Smrg	} \
84190d7dceSmrg	if (CI_NONEXISTCHAR(cs)) cs = NULL; \
85d522f475Smrg    } \
86d522f475Smrg}
87d522f475Smrg
88fa3f02f3Smrg#define CI_GET_CHAR_INFO_2D(fs,row,col,cs) \
89d522f475Smrg{ \
90190d7dceSmrg    cs = NULL; \
91d522f475Smrg    if (row >= fs->min_byte1 && row <= fs->max_byte1 && \
92d522f475Smrg	col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
93d522f475Smrg	if (fs->per_char == NULL) { \
94d522f475Smrg	    cs = &fs->min_bounds; \
95d522f475Smrg	} else { \
96d522f475Smrg	    cs = &fs->per_char[((row - fs->min_byte1) * \
97d522f475Smrg				(fs->max_char_or_byte2 - \
98d522f475Smrg				 fs->min_char_or_byte2 + 1)) + \
99d522f475Smrg			       (col - fs->min_char_or_byte2)]; \
100d522f475Smrg	} \
101190d7dceSmrg	if (CI_NONEXISTCHAR(cs)) cs = NULL; \
102d522f475Smrg    } \
103d522f475Smrg}
104d522f475Smrg
1059a64e1c5Smrg#define FREE_FNAME(field) \
106190d7dceSmrg	    if (fonts == NULL || new_fnames.field != fonts->field) { \
107d1603babSmrg		FREE_STRING(new_fnames.field); \
108190d7dceSmrg		new_fnames.field = NULL; \
1099a64e1c5Smrg	    }
1109a64e1c5Smrg
111d522f475Smrg/*
112d522f475Smrg * A structure to hold the relevant properties from a font
113d522f475Smrg * we need to make a well formed font name for it.
114d522f475Smrg */
115d522f475Smrgtypedef struct {
116d522f475Smrg    /* registry, foundry, family */
1179a64e1c5Smrg    const char *beginning;
118d522f475Smrg    /* weight */
1199a64e1c5Smrg    const char *weight;
120d522f475Smrg    /* slant */
1219a64e1c5Smrg    const char *slant;
122d522f475Smrg    /* wideness */
1239a64e1c5Smrg    const char *wideness;
124d522f475Smrg    /* add style */
1259a64e1c5Smrg    const char *add_style;
126d522f475Smrg    int pixel_size;
1279a64e1c5Smrg    const char *point_size;
128d522f475Smrg    int res_x;
129d522f475Smrg    int res_y;
1309a64e1c5Smrg    const char *spacing;
131d522f475Smrg    int average_width;
132d522f475Smrg    /* charset registry, charset encoding */
133d522f475Smrg    char *end;
134d522f475Smrg} FontNameProperties;
135d522f475Smrg
136d4fba8b9Smrg#if OPT_WIDE_CHARS && (OPT_RENDERFONT || (OPT_TRACE > 1))
137d4fba8b9Smrg#define MY_UCS(code,high,wide,name) { code, high, wide, #name }
138d4fba8b9Smrgstatic const struct {
139d4fba8b9Smrg    unsigned code, high, wide;
140d4fba8b9Smrg    const char *name;
141d4fba8b9Smrg} unicode_boxes[] = {
142d4fba8b9Smrg
143d4fba8b9Smrg    MY_UCS(0x2500, 0, 1, box drawings light horizontal),
144d4fba8b9Smrg	MY_UCS(0x2502, 1, 0, box drawings light vertical),
145d4fba8b9Smrg	MY_UCS(0x250c, 2, 2, box drawings light down and right),
146d4fba8b9Smrg	MY_UCS(0x2510, 2, 2, box drawings light down and left),
147d4fba8b9Smrg	MY_UCS(0x2514, 2, 2, box drawings light up and right),
148d4fba8b9Smrg	MY_UCS(0x2518, 2, 2, box drawings light up and left),
149d4fba8b9Smrg	MY_UCS(0x251c, 1, 2, box drawings light vertical and right),
150d4fba8b9Smrg	MY_UCS(0x2524, 1, 2, box drawings light vertical and left),
151d4fba8b9Smrg	MY_UCS(0x252c, 2, 1, box drawings light down and horizontal),
152d4fba8b9Smrg	MY_UCS(0x2534, 2, 1, box drawings light up and horizontal),
153d4fba8b9Smrg	MY_UCS(0x253c, 1, 1, box drawings light vertical and horizontal),
154d4fba8b9Smrg    {
155d4fba8b9Smrg	0, 0, 0, NULL
156d4fba8b9Smrg    }
157d4fba8b9Smrg};
158d4fba8b9Smrg
159d4fba8b9Smrg#undef MY_UCS
160d4fba8b9Smrg#endif /* OPT_WIDE_CHARS */
161d4fba8b9Smrg
162dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
163dfb07bc7Smrgstatic Boolean merge_sublist(char ***, char **);
164dfb07bc7Smrg#endif
165dfb07bc7Smrg
166dfb07bc7Smrgstatic void save2FontList(XtermWidget, const char *, XtermFontNames *,
167d1603babSmrg			  VTFontEnum, const char *, Bool, Bool);
168dfb07bc7Smrg
1690bd37d32Smrg#if OPT_RENDERFONT
1700bd37d32Smrgstatic void fillInFaceSize(XtermWidget, int);
1710bd37d32Smrg#endif
1720bd37d32Smrg
173d1603babSmrg#if OPT_REPORT_FONTS && OPT_TRACE
174d1603babSmrgstatic void
175d1603babSmrgreport_fonts(const char *fmt, ...)
176d1603babSmrg{
177d1603babSmrg    va_list ap;
178d1603babSmrg    va_start(ap, fmt);
179d1603babSmrg    vfprintf(stdout, fmt, ap);
180d1603babSmrg    va_end(ap);
181d1603babSmrg#if OPT_TRACE
182d1603babSmrg    va_start(ap, fmt);
183d1603babSmrg    TraceVA(fmt, ap);
184d1603babSmrg    va_end(ap);
185d1603babSmrg#endif
186d1603babSmrg}
187d1603babSmrg
188d1603babSmrg#define ReportFonts report_fonts
189d1603babSmrg#else
190d1603babSmrg#define ReportFonts printf
191d522f475Smrg#endif
192d522f475Smrg
193d4fba8b9Smrg#if OPT_TRACE
194d4fba8b9Smrgstatic void
195d4fba8b9Smrgset_font_height(TScreen *screen, VTwin *win, int height)
196d4fba8b9Smrg{
197d4fba8b9Smrg    SetFontHeight(screen, win, height);
198d4fba8b9Smrg    TRACE(("SetFontHeight %d\n", win->f_height));
199d4fba8b9Smrg#undef SetFontHeight
200d4fba8b9Smrg#define SetFontHeight(screen, win, height) set_font_height(screen, win, height)
201d4fba8b9Smrg}
202d4fba8b9Smrg
203d4fba8b9Smrgstatic void
204d4fba8b9Smrgset_font_width(TScreen *screen, VTwin *win, int width)
205d4fba8b9Smrg{
206d4fba8b9Smrg    (void) screen;
207d4fba8b9Smrg    SetFontWidth(screen, win, width);
208d4fba8b9Smrg    TRACE(("SetFontWidth  %d\n", win->f_width));
209d4fba8b9Smrg#undef  SetFontWidth
210c48a5815Smrg#define SetFontWidth(screen, win, width) set_font_width(screen, win, width)
211d4fba8b9Smrg}
212d4fba8b9Smrg#endif
213d4fba8b9Smrg
214fa3f02f3Smrg#if OPT_REPORT_FONTS || OPT_WIDE_CHARS
2152eaa94a1Schristosstatic unsigned
2169a64e1c5SmrgcountGlyphs(XFontStruct *fp)
217d522f475Smrg{
218d522f475Smrg    unsigned count = 0;
219d522f475Smrg
220190d7dceSmrg    if (fp != NULL) {
221d522f475Smrg	if (fp->min_byte1 == 0 && fp->max_byte1 == 0) {
222fa3f02f3Smrg	    count = fp->max_char_or_byte2 - fp->min_char_or_byte2 + 1;
223d522f475Smrg	} else if (fp->min_char_or_byte2 < 256
224d522f475Smrg		   && fp->max_char_or_byte2 < 256) {
225d522f475Smrg	    unsigned first = (fp->min_byte1 << 8) + fp->min_char_or_byte2;
226d522f475Smrg	    unsigned last = (fp->max_byte1 << 8) + fp->max_char_or_byte2;
227d522f475Smrg	    count = last + 1 - first;
228d522f475Smrg	}
229d522f475Smrg    }
230d522f475Smrg    return count;
231d522f475Smrg}
232fa3f02f3Smrg#endif
233d522f475Smrg
234fa3f02f3Smrg#if OPT_WIDE_CHARS
235d522f475Smrg/*
236d522f475Smrg * Verify that the wide-bold font is at least a bold font with roughly as many
237d522f475Smrg * glyphs as the wide font.  The counts should be the same, but settle for
238d522f475Smrg * filtering out the worst of the font mismatches.
239d522f475Smrg */
240d522f475Smrgstatic Bool
2419a64e1c5SmrgcompatibleWideCounts(XFontStruct *wfs, XFontStruct *wbfs)
242d522f475Smrg{
243d522f475Smrg    unsigned count_w = countGlyphs(wfs);
244d522f475Smrg    unsigned count_wb = countGlyphs(wbfs);
245d522f475Smrg    if (count_w <= 256 ||
246d522f475Smrg	count_wb <= 256 ||
247d522f475Smrg	((count_w / 4) * 3) > count_wb) {
248d522f475Smrg	TRACE(("...font server lied (count wide %u vs wide-bold %u)\n",
249d522f475Smrg	       count_w, count_wb));
250d522f475Smrg	return False;
251d522f475Smrg    }
252d522f475Smrg    return True;
253d522f475Smrg}
254d522f475Smrg#endif /* OPT_WIDE_CHARS */
255d522f475Smrg
25620d2c4d2Smrg#if OPT_BOX_CHARS
25720d2c4d2Smrgstatic void
25820d2c4d2SmrgsetupPackedFonts(XtermWidget xw)
25920d2c4d2Smrg{
26020d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
26120d2c4d2Smrg    Bool value = False;
26220d2c4d2Smrg
26320d2c4d2Smrg#if OPT_RENDERFONT
2640bd37d32Smrg    if (xw->work.render_font == True) {
265dfb07bc7Smrg	int e;
26620d2c4d2Smrg
267dfb07bc7Smrg	for (e = 0; e < fMAX; ++e) {
268dfb07bc7Smrg	    XTermXftFonts *data = getMyXftFont(xw, e, screen->menu_font_number);
269190d7dceSmrg	    if (data != NULL) {
270d1603babSmrg		if (data->font_info.mixed) {
271dfb07bc7Smrg		    screen->allow_packing = True;
272dfb07bc7Smrg		    break;
273dfb07bc7Smrg		}
274dfb07bc7Smrg	    }
275dfb07bc7Smrg	}
27620d2c4d2Smrg    }
27720d2c4d2Smrg#endif /* OPT_RENDERFONT */
27820d2c4d2Smrg
27920d2c4d2Smrg    value = screen->allow_packing;
28020d2c4d2Smrg
28120d2c4d2Smrg    SetItemSensitivity(fontMenuEntries[fontMenu_font_packedfont].widget, value);
28220d2c4d2Smrg}
28320d2c4d2Smrg#endif
28420d2c4d2Smrg
285d4fba8b9Smrgtypedef struct _nameList {
286d4fba8b9Smrg    struct _nameList *next;
287d4fba8b9Smrg    char *name;
288d4fba8b9Smrg} NameList;
289d4fba8b9Smrg
290d4fba8b9Smrgstatic NameList *derived_fonts;
291d4fba8b9Smrg
292d4fba8b9Smrgstatic Boolean
293d4fba8b9Smrgis_derived_font_name(const char *name)
294d4fba8b9Smrg{
295d4fba8b9Smrg    Boolean result = False;
296d4fba8b9Smrg    NameList *list;
297d4fba8b9Smrg    if (!IsEmpty(name)) {
298190d7dceSmrg	for (list = derived_fonts; list != NULL; list = list->next) {
299d4fba8b9Smrg	    if (!x_strcasecmp(name, list->name)) {
300d4fba8b9Smrg		result = True;
301d4fba8b9Smrg		break;
302d4fba8b9Smrg	    }
303d4fba8b9Smrg	}
304d4fba8b9Smrg    }
305d4fba8b9Smrg    return result;
306d4fba8b9Smrg}
307d4fba8b9Smrg
308d4fba8b9Smrgvoid
309d4fba8b9SmrgxtermDerivedFont(const char *name)
310d4fba8b9Smrg{
311d4fba8b9Smrg    if (!IsEmpty(name) && !is_derived_font_name(name)) {
312d4fba8b9Smrg	NameList *list = TypeCalloc(NameList);
313d4fba8b9Smrg	list->name = x_strdup(name);
314d4fba8b9Smrg	list->next = derived_fonts;
315d4fba8b9Smrg	derived_fonts = list;
316d4fba8b9Smrg    }
317d4fba8b9Smrg}
318d4fba8b9Smrg
319d522f475Smrg/*
320d522f475Smrg * Returns the fields from start to stop in a dash- separated string.  This
3219a64e1c5Smrg * function will modify the source, putting '\0's in the appropriate place and
322d522f475Smrg * moving the beginning forward to after the '\0'
323d522f475Smrg *
324d522f475Smrg * This will NOT work for the last field (but we won't need it).
325d522f475Smrg */
326d522f475Smrgstatic char *
327d522f475Smrgn_fields(char **source, int start, int stop)
328d522f475Smrg{
329d522f475Smrg    int i;
330d522f475Smrg    char *str, *str1;
331d522f475Smrg
332d522f475Smrg    /*
333d522f475Smrg     * find the start-1th dash
334d522f475Smrg     */
3359a64e1c5Smrg    for (i = start - 1, str = *source; i; i--, str++) {
336190d7dceSmrg	if ((str = strchr(str, '-')) == NULL)
337190d7dceSmrg	    return NULL;
3389a64e1c5Smrg    }
339d522f475Smrg
340d522f475Smrg    /*
341d522f475Smrg     * find the stopth dash
342d522f475Smrg     */
3439a64e1c5Smrg    for (i = stop - start + 1, str1 = str; i; i--, str1++) {
344190d7dceSmrg	if ((str1 = strchr(str1, '-')) == NULL)
345190d7dceSmrg	    return NULL;
3469a64e1c5Smrg    }
347d522f475Smrg
348d522f475Smrg    /*
349d522f475Smrg     * put a \0 at the end of the fields
350d522f475Smrg     */
351d522f475Smrg    *(str1 - 1) = '\0';
352d522f475Smrg
353d522f475Smrg    /*
354d522f475Smrg     * move source forward
355d522f475Smrg     */
356d522f475Smrg    *source = str1;
357d522f475Smrg
358d522f475Smrg    return str;
359d522f475Smrg}
360d522f475Smrg
361956cc18dSsnjstatic Boolean
362956cc18dSsnjcheck_fontname(const char *name)
363956cc18dSsnj{
364956cc18dSsnj    Boolean result = True;
365956cc18dSsnj
366492d43a5Smrg    if (IsEmpty(name)) {
367956cc18dSsnj	TRACE(("fontname missing\n"));
368956cc18dSsnj	result = False;
369956cc18dSsnj    }
370956cc18dSsnj    return result;
371956cc18dSsnj}
372956cc18dSsnj
373d522f475Smrg/*
374d522f475Smrg * Gets the font properties from a given font structure.  We use the FONT name
375d522f475Smrg * to find them out, since that seems easier.
376d522f475Smrg *
377d522f475Smrg * Returns a pointer to a static FontNameProperties structure
378d522f475Smrg * or NULL on error.
379d522f475Smrg */
380d522f475Smrgstatic FontNameProperties *
3819a64e1c5Smrgget_font_name_props(Display *dpy, XFontStruct *fs, char **result)
382d522f475Smrg{
383d522f475Smrg    static FontNameProperties props;
384d522f475Smrg    static char *last_name;
385d522f475Smrg
386d4fba8b9Smrg    Atom fontatom;
387d4fba8b9Smrg    char *name;
388d522f475Smrg    char *str;
389d522f475Smrg
390d4fba8b9Smrg    if (fs == NULL)
391d4fba8b9Smrg	return NULL;
392d4fba8b9Smrg
393d522f475Smrg    /*
394d522f475Smrg     * first get the full font name
395d522f475Smrg     */
396190d7dceSmrg    name = NULL;
397980988aeSmrg    fontatom = CachedInternAtom(dpy, "FONT");
39820d2c4d2Smrg    if (fontatom != 0) {
399037a25ddSmrg	XFontProp *fp;
400037a25ddSmrg	int i;
401037a25ddSmrg
40220d2c4d2Smrg	for (i = 0, fp = fs->properties; i < fs->n_properties; i++, fp++) {
40320d2c4d2Smrg	    if (fp->name == fontatom) {
40420d2c4d2Smrg		name = XGetAtomName(dpy, fp->card32);
40520d2c4d2Smrg		break;
40620d2c4d2Smrg	    }
40720d2c4d2Smrg	}
40820d2c4d2Smrg    }
409d522f475Smrg
410190d7dceSmrg    if (name == NULL)
411190d7dceSmrg	return NULL;
412d522f475Smrg
413d522f475Smrg    /*
414d522f475Smrg     * XGetAtomName allocates memory - don't leak
415d522f475Smrg     */
416d4fba8b9Smrg    XFree(last_name);
417d522f475Smrg    last_name = name;
418d522f475Smrg
419190d7dceSmrg    if (result != NULL) {
420956cc18dSsnj	if (!check_fontname(name))
421190d7dceSmrg	    return NULL;
422d4fba8b9Smrg	free(*result);
4230bd37d32Smrg	*result = x_strdup(name);
424d522f475Smrg    }
425d522f475Smrg
426d522f475Smrg    /*
427d522f475Smrg     * Now split it up into parts and put them in
428d522f475Smrg     * their places. Since we are using parts of
429d522f475Smrg     * the original string, we must not free the Atom Name
430d522f475Smrg     */
431d522f475Smrg
432d522f475Smrg    /* registry, foundry, family */
433190d7dceSmrg    if ((props.beginning = n_fields(&name, 1, 3)) == NULL)
434190d7dceSmrg	return NULL;
435d522f475Smrg
436d522f475Smrg    /* weight is the next */
437190d7dceSmrg    if ((props.weight = n_fields(&name, 1, 1)) == NULL)
438190d7dceSmrg	return NULL;
439d522f475Smrg
440d522f475Smrg    /* slant */
441190d7dceSmrg    if ((props.slant = n_fields(&name, 1, 1)) == NULL)
442190d7dceSmrg	return NULL;
443d522f475Smrg
444d522f475Smrg    /* width */
445190d7dceSmrg    if ((props.wideness = n_fields(&name, 1, 1)) == NULL)
446190d7dceSmrg	return NULL;
447d522f475Smrg
448d522f475Smrg    /* add style */
449190d7dceSmrg    if ((props.add_style = n_fields(&name, 1, 1)) == NULL)
450190d7dceSmrg	return NULL;
451d522f475Smrg
452d522f475Smrg    /* pixel size */
453190d7dceSmrg    if ((str = n_fields(&name, 1, 1)) == NULL)
454190d7dceSmrg	return NULL;
455d522f475Smrg    if ((props.pixel_size = atoi(str)) == 0)
456190d7dceSmrg	return NULL;
457d522f475Smrg
458d522f475Smrg    /* point size */
459190d7dceSmrg    if ((props.point_size = n_fields(&name, 1, 1)) == NULL)
460190d7dceSmrg	return NULL;
461d522f475Smrg
462d522f475Smrg    /* res_x */
463190d7dceSmrg    if ((str = n_fields(&name, 1, 1)) == NULL)
464190d7dceSmrg	return NULL;
465d522f475Smrg    if ((props.res_x = atoi(str)) == 0)
466190d7dceSmrg	return NULL;
467d522f475Smrg
468d522f475Smrg    /* res_y */
469190d7dceSmrg    if ((str = n_fields(&name, 1, 1)) == NULL)
470190d7dceSmrg	return NULL;
471d522f475Smrg    if ((props.res_y = atoi(str)) == 0)
472190d7dceSmrg	return NULL;
473d522f475Smrg
474d522f475Smrg    /* spacing */
475190d7dceSmrg    if ((props.spacing = n_fields(&name, 1, 1)) == NULL)
476190d7dceSmrg	return NULL;
477d522f475Smrg
478d522f475Smrg    /* average width */
479190d7dceSmrg    if ((str = n_fields(&name, 1, 1)) == NULL)
480190d7dceSmrg	return NULL;
481d522f475Smrg    if ((props.average_width = atoi(str)) == 0)
482190d7dceSmrg	return NULL;
483d522f475Smrg
484d522f475Smrg    /* the rest: charset registry and charset encoding */
485d522f475Smrg    props.end = name;
486d522f475Smrg
487d522f475Smrg    return &props;
488d522f475Smrg}
489d522f475Smrg
490d522f475Smrg#define ALLOCHUNK(n) ((n | 127) + 1)
491d522f475Smrg
492d522f475Smrgstatic void
493956cc18dSsnjalloca_fontname(char **result, size_t next)
494d522f475Smrg{
495190d7dceSmrg    size_t last = (*result != NULL) ? strlen(*result) : 0;
496190d7dceSmrg    size_t have = (*result != NULL) ? ALLOCHUNK(last) : 0;
497956cc18dSsnj    size_t want = last + next + 2;
498d522f475Smrg
499d522f475Smrg    if (want >= have) {
50050027b5bSmrg	char *save = *result;
501d522f475Smrg	want = ALLOCHUNK(want);
502d522f475Smrg	if (last != 0) {
503d522f475Smrg	    *result = TypeRealloc(char, want, *result);
504190d7dceSmrg	    if (*result == NULL)
5059a64e1c5Smrg		free(save);
506d522f475Smrg	} else {
507190d7dceSmrg	    if ((*result = TypeMallocN(char, want)) != NULL) {
50850027b5bSmrg		free(save);
509d522f475Smrg		**result = '\0';
51050027b5bSmrg	    }
511d522f475Smrg	}
512d522f475Smrg    }
513d522f475Smrg}
514d522f475Smrg
515d522f475Smrgstatic void
51620d2c4d2Smrgappend_fontname_str(char **result, const char *value)
517d522f475Smrg{
518190d7dceSmrg    if (value == NULL)
519d522f475Smrg	value = "*";
520d522f475Smrg    alloca_fontname(result, strlen(value));
521190d7dceSmrg    if (*result != NULL) {
522d522f475Smrg	if (**result != '\0')
523d522f475Smrg	    strcat(*result, "-");
524d522f475Smrg	strcat(*result, value);
525d522f475Smrg    }
526d522f475Smrg}
527d522f475Smrg
528d522f475Smrgstatic void
529d522f475Smrgappend_fontname_num(char **result, int value)
530d522f475Smrg{
531d522f475Smrg    if (value < 0) {
532d522f475Smrg	append_fontname_str(result, "*");
533d522f475Smrg    } else {
534d522f475Smrg	char temp[100];
535d522f475Smrg	sprintf(temp, "%d", value);
536d522f475Smrg	append_fontname_str(result, temp);
537d522f475Smrg    }
538d522f475Smrg}
539d522f475Smrg
540d522f475Smrg/*
541d522f475Smrg * Take the given font props and try to make a well formed font name specifying
542d522f475Smrg * the same base font and size and everything, but with different weight/width
543d522f475Smrg * according to the parameters.  The return value is allocated, should be freed
544d522f475Smrg * by the caller.
545d522f475Smrg */
546d522f475Smrgstatic char *
5479a64e1c5Smrgderive_font_name(FontNameProperties *props,
54820d2c4d2Smrg		 const char *use_weight,
549d522f475Smrg		 int use_average_width,
55020d2c4d2Smrg		 const char *use_encoding)
551d522f475Smrg{
552190d7dceSmrg    char *result = NULL;
553d522f475Smrg
554d522f475Smrg    append_fontname_str(&result, props->beginning);
555d522f475Smrg    append_fontname_str(&result, use_weight);
556d522f475Smrg    append_fontname_str(&result, props->slant);
557190d7dceSmrg    append_fontname_str(&result, NULL);
558190d7dceSmrg    append_fontname_str(&result, NULL);
559d522f475Smrg    append_fontname_num(&result, props->pixel_size);
560d522f475Smrg    append_fontname_str(&result, props->point_size);
561d522f475Smrg    append_fontname_num(&result, props->res_x);
562d522f475Smrg    append_fontname_num(&result, props->res_y);
563d522f475Smrg    append_fontname_str(&result, props->spacing);
564d522f475Smrg    append_fontname_num(&result, use_average_width);
565d522f475Smrg    append_fontname_str(&result, use_encoding);
566d522f475Smrg
567d4fba8b9Smrg    xtermDerivedFont(result);
568d522f475Smrg    return result;
569d522f475Smrg}
570d522f475Smrg
571d522f475Smrgstatic char *
5729a64e1c5Smrgbold_font_name(FontNameProperties *props, int use_average_width)
573d522f475Smrg{
574d522f475Smrg    return derive_font_name(props, "bold", use_average_width, props->end);
575d522f475Smrg}
576d522f475Smrg
5779a64e1c5Smrg#if OPT_WIDE_ATTRS
5789a64e1c5Smrgstatic char *
579dfb07bc7Smrgitalic_font_name(FontNameProperties *props, const char *slant)
5809a64e1c5Smrg{
5819a64e1c5Smrg    FontNameProperties myprops = *props;
582dfb07bc7Smrg    myprops.slant = slant;
583dfb07bc7Smrg    return derive_font_name(&myprops, props->weight, myprops.average_width, props->end);
584dfb07bc7Smrg}
585dfb07bc7Smrg
586dfb07bc7Smrgstatic Boolean
587dfb07bc7Smrgopen_italic_font(XtermWidget xw, int n, FontNameProperties *fp, XTermFonts * data)
588dfb07bc7Smrg{
589d1603babSmrg    static const char *const slant[] =
590dfb07bc7Smrg    {
591dfb07bc7Smrg	"o",
592dfb07bc7Smrg	"i"
593dfb07bc7Smrg    };
594dfb07bc7Smrg    Cardinal pass;
595dfb07bc7Smrg    Boolean result = False;
596dfb07bc7Smrg
597d4fba8b9Smrg    NoFontWarning(data);
598dfb07bc7Smrg    for (pass = 0; pass < XtNumber(slant); ++pass) {
599d4fba8b9Smrg	char *name;
600190d7dceSmrg	if ((name = italic_font_name(fp, slant[pass])) != NULL) {
601dfb07bc7Smrg	    TRACE(("open_italic_font %s %s\n",
602dfb07bc7Smrg		   whichFontEnum((VTFontEnum) n), name));
603d1603babSmrg	    if (xtermOpenFont(xw, name, data, NULL, False)) {
604190d7dceSmrg		result = (data->fs != NULL);
605dfb07bc7Smrg#if OPT_REPORT_FONTS
606dfb07bc7Smrg		if (resource.reportFonts) {
607d1603babSmrg		    ReportFonts("opened italic version of %s:\n\t%s\n",
608d1603babSmrg				whichFontEnum((VTFontEnum) n),
609d1603babSmrg				name);
610dfb07bc7Smrg		}
611dfb07bc7Smrg#endif
612dfb07bc7Smrg	    }
613dfb07bc7Smrg	    free(name);
614dfb07bc7Smrg	    if (result)
615dfb07bc7Smrg		break;
616dfb07bc7Smrg	}
617dfb07bc7Smrg    }
618dfb07bc7Smrg#if OPT_TRACE
619dfb07bc7Smrg    if (result) {
620dfb07bc7Smrg	XFontStruct *fs = data->fs;
621190d7dceSmrg	if (fs != NULL) {
622dfb07bc7Smrg	    TRACE(("...actual size %dx%d (ascent %d, descent %d)\n",
623dfb07bc7Smrg		   fs->ascent +
624dfb07bc7Smrg		   fs->descent,
625dfb07bc7Smrg		   fs->max_bounds.width,
626dfb07bc7Smrg		   fs->ascent,
627dfb07bc7Smrg		   fs->descent));
628dfb07bc7Smrg	}
629dfb07bc7Smrg    }
630dfb07bc7Smrg#endif
631dfb07bc7Smrg    return result;
6329a64e1c5Smrg}
6339a64e1c5Smrg#endif
6349a64e1c5Smrg
635d522f475Smrg#if OPT_WIDE_CHARS
636d522f475Smrg#define derive_wide_font(props, weight) \
637d522f475Smrg	derive_font_name(props, weight, props->average_width * 2, "ISO10646-1")
638d522f475Smrg
639d522f475Smrgstatic char *
6409a64e1c5Smrgwide_font_name(FontNameProperties *props)
641d522f475Smrg{
642d522f475Smrg    return derive_wide_font(props, "medium");
643d522f475Smrg}
644d522f475Smrg
645d522f475Smrgstatic char *
6469a64e1c5Smrgwidebold_font_name(FontNameProperties *props)
647d522f475Smrg{
648d522f475Smrg    return derive_wide_font(props, "bold");
649d522f475Smrg}
650d522f475Smrg#endif /* OPT_WIDE_CHARS */
651d522f475Smrg
652d522f475Smrg#if OPT_DEC_CHRSET
653d522f475Smrg/*
654d522f475Smrg * Take the given font props and try to make a well formed font name specifying
655d522f475Smrg * the same base font but changed depending on the given attributes and chrset.
656d522f475Smrg *
657d522f475Smrg * For double width fonts, we just double the X-resolution, for double height
658d522f475Smrg * fonts we double the pixel-size and Y-resolution
659d522f475Smrg */
660d522f475Smrgchar *
661d4fba8b9SmrgxtermSpecialFont(XTermDraw * params)
662d522f475Smrg{
663d4fba8b9Smrg    TScreen *screen = TScreenOf(params->xw);
664d522f475Smrg#if OPT_TRACE
665d522f475Smrg    static char old_spacing[80];
666d522f475Smrg    static FontNameProperties old_props;
667d522f475Smrg#endif
668d522f475Smrg    FontNameProperties *props;
669190d7dceSmrg    char *result = NULL;
67020d2c4d2Smrg    const char *weight;
671d522f475Smrg    int pixel_size;
672d522f475Smrg    int res_x;
673d522f475Smrg    int res_y;
674d522f475Smrg
675dfb07bc7Smrg    props = get_font_name_props(screen->display,
676190d7dceSmrg				GetNormalFont(screen, fNorm)->fs, NULL);
677190d7dceSmrg    if (props == NULL)
678d522f475Smrg	return result;
679d522f475Smrg
680d522f475Smrg    pixel_size = props->pixel_size;
681d522f475Smrg    res_x = props->res_x;
682d522f475Smrg    res_y = props->res_y;
683d4fba8b9Smrg    if (params->attr_flags & BOLD)
684d522f475Smrg	weight = "bold";
685d522f475Smrg    else
686d522f475Smrg	weight = props->weight;
687d522f475Smrg
688d4fba8b9Smrg    if (CSET_DOUBLE(params->this_chrset))
689d522f475Smrg	res_x *= 2;
690d522f475Smrg
691d4fba8b9Smrg    if (params->this_chrset == CSET_DHL_TOP
692d4fba8b9Smrg	|| params->this_chrset == CSET_DHL_BOT) {
693d522f475Smrg	res_y *= 2;
694d522f475Smrg	pixel_size *= 2;
695d522f475Smrg    }
696d522f475Smrg#if OPT_TRACE
697d522f475Smrg    if (old_props.res_x != res_x
698d522f475Smrg	|| old_props.res_x != res_y
699d522f475Smrg	|| old_props.pixel_size != pixel_size
700d522f475Smrg	|| strcmp(old_props.spacing, props->spacing)) {
7019a64e1c5Smrg	TRACE(("xtermSpecialFont(atts = %#x, draw = %#x, chrset = %#x)\n",
702d4fba8b9Smrg	       params->attr_flags, params->draw_flags, params->this_chrset));
703d522f475Smrg	TRACE(("res_x      = %d\n", res_x));
704d522f475Smrg	TRACE(("res_y      = %d\n", res_y));
705d522f475Smrg	TRACE(("point_size = %s\n", props->point_size));
706d522f475Smrg	TRACE(("pixel_size = %d\n", pixel_size));
707d522f475Smrg	TRACE(("spacing    = %s\n", props->spacing));
708d522f475Smrg	old_props.res_x = res_x;
709037a25ddSmrg	old_props.res_y = res_y;
710d522f475Smrg	old_props.pixel_size = pixel_size;
7110bd37d32Smrg	old_props.spacing = old_spacing;
7120bd37d32Smrg	sprintf(old_spacing, "%.*s", (int) sizeof(old_spacing) - 2, props->spacing);
713d522f475Smrg    }
714d522f475Smrg#endif
715d522f475Smrg
716d522f475Smrg    append_fontname_str(&result, props->beginning);
717d522f475Smrg    append_fontname_str(&result, weight);
718d522f475Smrg    append_fontname_str(&result, props->slant);
719d522f475Smrg    append_fontname_str(&result, props->wideness);
720d522f475Smrg    append_fontname_str(&result, props->add_style);
721d522f475Smrg    append_fontname_num(&result, pixel_size);
722d522f475Smrg    append_fontname_str(&result, props->point_size);
723d4fba8b9Smrg    append_fontname_num(&result, (params->draw_flags & NORESOLUTION) ? -1 : res_x);
724d4fba8b9Smrg    append_fontname_num(&result, (params->draw_flags & NORESOLUTION) ? -1 : res_y);
725d522f475Smrg    append_fontname_str(&result, props->spacing);
726190d7dceSmrg    append_fontname_str(&result, NULL);
727d522f475Smrg    append_fontname_str(&result, props->end);
728d522f475Smrg
729d4fba8b9Smrg    xtermDerivedFont(result);
730d522f475Smrg    return result;
731d522f475Smrg}
732d522f475Smrg#endif /* OPT_DEC_CHRSET */
733d522f475Smrg
734d522f475Smrg/*
735d522f475Smrg * Case-independent comparison for font-names, including wildcards.
736d522f475Smrg * XLFD allows '?' as a wildcard, but we do not handle that (no one seems
737d522f475Smrg * to use it).
738d522f475Smrg */
739d522f475Smrgstatic Bool
740492d43a5Smrgsame_font_name(const char *pattern, const char *match)
741d522f475Smrg{
742956cc18dSsnj    Bool result = False;
743956cc18dSsnj
744956cc18dSsnj    if (pattern && match) {
745956cc18dSsnj	while (*pattern && *match) {
746956cc18dSsnj	    if (*pattern == *match) {
747956cc18dSsnj		pattern++;
748956cc18dSsnj		match++;
749956cc18dSsnj	    } else if (*pattern == '*' || *match == '*') {
750956cc18dSsnj		if (same_font_name(pattern + 1, match)) {
751956cc18dSsnj		    return True;
752956cc18dSsnj		} else if (same_font_name(pattern, match + 1)) {
753956cc18dSsnj		    return True;
754956cc18dSsnj		} else {
755956cc18dSsnj		    return False;
756956cc18dSsnj		}
757d522f475Smrg	    } else {
758956cc18dSsnj		int p = x_toupper(*pattern++);
759956cc18dSsnj		int m = x_toupper(*match++);
760956cc18dSsnj		if (p != m)
761956cc18dSsnj		    return False;
762d522f475Smrg	    }
763d522f475Smrg	}
764956cc18dSsnj	result = (*pattern == *match);	/* both should be NUL */
765d522f475Smrg    }
766956cc18dSsnj    return result;
767d522f475Smrg}
768d522f475Smrg
769d522f475Smrg/*
770d522f475Smrg * Double-check the fontname that we asked for versus what the font server
771d522f475Smrg * actually gave us.  The larger fixed fonts do not always have a matching bold
772d522f475Smrg * font, and the font server may try to scale another font or otherwise
773d522f475Smrg * substitute a mismatched font.
774d522f475Smrg *
775d522f475Smrg * If we cannot get what we requested, we will fallback to the original
776d522f475Smrg * behavior, which simulates bold by overstriking each character at one pixel
777d522f475Smrg * offset.
778d522f475Smrg */
779d522f475Smrgstatic int
7809a64e1c5Smrggot_bold_font(Display *dpy, XFontStruct *fs, String requested)
781d522f475Smrg{
782190d7dceSmrg    char *actual = NULL;
783d522f475Smrg    int got;
784d522f475Smrg
785190d7dceSmrg    if (get_font_name_props(dpy, fs, &actual) == NULL)
786d522f475Smrg	got = 0;
787d522f475Smrg    else
788d522f475Smrg	got = same_font_name(requested, actual);
7890bd37d32Smrg    free(actual);
790d522f475Smrg    return got;
791d522f475Smrg}
792d522f475Smrg
7939a64e1c5Smrg/*
7949a64e1c5Smrg * Check normal/bold (or wide/wide-bold) font pairs to see if we will be able
7959a64e1c5Smrg * to check for missing glyphs in a comparable manner.
7969a64e1c5Smrg */
7979a64e1c5Smrgstatic int
7989a64e1c5Smrgcomparable_metrics(XFontStruct *normal, XFontStruct *bold)
7999a64e1c5Smrg{
8009a64e1c5Smrg#define DATA "comparable_metrics: "
8019a64e1c5Smrg    int result = 0;
8029a64e1c5Smrg
803190d7dceSmrg    if (normal == NULL || bold == NULL) {
804dfb07bc7Smrg	;
805dfb07bc7Smrg    } else if (normal->all_chars_exist) {
8069a64e1c5Smrg	if (bold->all_chars_exist) {
8079a64e1c5Smrg	    result = 1;
8089a64e1c5Smrg	} else {
8099a64e1c5Smrg	    TRACE((DATA "all chars exist in normal font, but not in bold\n"));
8109a64e1c5Smrg	}
811190d7dceSmrg    } else if (normal->per_char != NULL) {
812190d7dceSmrg	if (bold->per_char != NULL) {
8139a64e1c5Smrg	    result = 1;
8149a64e1c5Smrg	} else {
8159a64e1c5Smrg	    TRACE((DATA "normal font has per-char metrics, but not bold\n"));
8169a64e1c5Smrg	}
8179a64e1c5Smrg    } else {
8189a64e1c5Smrg	TRACE((DATA "normal font is not very good!\n"));
8199a64e1c5Smrg	result = 1;		/* give in (we're not going in reverse) */
8209a64e1c5Smrg    }
8219a64e1c5Smrg    return result;
8229a64e1c5Smrg#undef DATA
8239a64e1c5Smrg}
8249a64e1c5Smrg
825d522f475Smrg/*
826d522f475Smrg * If the font server tries to adjust another font, it may not adjust it
827d522f475Smrg * properly.  Check that the bounding boxes are compatible.  Otherwise we'll
828d522f475Smrg * leave trash on the display when we mix normal and bold fonts.
829d522f475Smrg */
830d522f475Smrgstatic int
8319a64e1c5Smrgsame_font_size(XtermWidget xw, XFontStruct *nfs, XFontStruct *bfs)
832d522f475Smrg{
833956cc18dSsnj    TScreen *screen = TScreenOf(xw);
834dfb07bc7Smrg    int result = 0;
835dfb07bc7Smrg
836190d7dceSmrg    if (nfs != NULL && bfs != NULL) {
837dfb07bc7Smrg	TRACE(("same_font_size height %d/%d, min %d/%d max %d/%d\n",
838dfb07bc7Smrg	       nfs->ascent + nfs->descent,
839dfb07bc7Smrg	       bfs->ascent + bfs->descent,
840dfb07bc7Smrg	       nfs->min_bounds.width, bfs->min_bounds.width,
841dfb07bc7Smrg	       nfs->max_bounds.width, bfs->max_bounds.width));
842dfb07bc7Smrg	result = screen->free_bold_box
843dfb07bc7Smrg	    || ((nfs->ascent + nfs->descent) == (bfs->ascent + bfs->descent)
844dfb07bc7Smrg		&& (nfs->min_bounds.width == bfs->min_bounds.width
845dfb07bc7Smrg		    || nfs->min_bounds.width == bfs->min_bounds.width + 1)
846dfb07bc7Smrg		&& (nfs->max_bounds.width == bfs->max_bounds.width
847dfb07bc7Smrg		    || nfs->max_bounds.width == bfs->max_bounds.width + 1));
848dfb07bc7Smrg    }
849dfb07bc7Smrg    return result;
850d522f475Smrg}
851d522f475Smrg
852d522f475Smrg/*
853d522f475Smrg * Check if the font looks like it has fixed width
854d522f475Smrg */
855d522f475Smrgstatic int
8569a64e1c5Smrgis_fixed_font(XFontStruct *fs)
857d522f475Smrg{
858d522f475Smrg    if (fs)
859d522f475Smrg	return (fs->min_bounds.width == fs->max_bounds.width);
860d522f475Smrg    return 1;
861d522f475Smrg}
862d522f475Smrg
863d4fba8b9Smrgstatic int
864d4fba8b9Smrgdiffering_widths(XFontStruct *a, XFontStruct *b)
865d4fba8b9Smrg{
866d4fba8b9Smrg    int result = 0;
867d4fba8b9Smrg    if (a != NULL && b != NULL && a->max_bounds.width != b->max_bounds.width)
868d4fba8b9Smrg	result = 1;
869d4fba8b9Smrg    return result;
870d4fba8b9Smrg}
871d4fba8b9Smrg
872d522f475Smrg/*
873d522f475Smrg * Check if the font looks like a double width font (i.e. contains
874d522f475Smrg * characters of width X and 2X
875d522f475Smrg */
876d522f475Smrg#if OPT_WIDE_CHARS
877d522f475Smrgstatic int
8789a64e1c5Smrgis_double_width_font(XFontStruct *fs)
879d522f475Smrg{
880d4fba8b9Smrg    return (fs != NULL && ((2 * fs->min_bounds.width) == fs->max_bounds.width));
881d522f475Smrg}
882d522f475Smrg#else
883d522f475Smrg#define is_double_width_font(fs) 0
884d522f475Smrg#endif
885d522f475Smrg
886d522f475Smrg#if OPT_WIDE_CHARS && OPT_RENDERFONT && defined(HAVE_TYPE_FCCHAR32)
887d522f475Smrg#define HALF_WIDTH_TEST_STRING "1234567890"
888d522f475Smrg
889d522f475Smrg/* '1234567890' in Chinese characters in UTF-8 */
890d522f475Smrg#define FULL_WIDTH_TEST_STRING "\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89" \
891d522f475Smrg                               "\xe5\x9b\x9b\xe4\xba\x94" \
892d522f475Smrg			       "\xef\xa7\x91\xe4\xb8\x83\xe5\x85\xab" \
893d522f475Smrg			       "\xe4\xb9\x9d\xef\xa6\xb2"
894d522f475Smrg
895d522f475Smrg/* '1234567890' in Korean script in UTF-8 */
896d522f475Smrg#define FULL_WIDTH_TEST_STRING2 "\xec\x9d\xbc\xec\x9d\xb4\xec\x82\xbc" \
897d522f475Smrg                                "\xec\x82\xac\xec\x98\xa4" \
898d522f475Smrg			        "\xec\x9c\xa1\xec\xb9\xa0\xed\x8c\x94" \
899d522f475Smrg			        "\xea\xb5\xac\xec\x98\x81"
900d522f475Smrg
901d522f475Smrg#define HALF_WIDTH_CHAR1  0x0031	/* '1' */
902d522f475Smrg#define HALF_WIDTH_CHAR2  0x0057	/* 'W' */
903d522f475Smrg#define FULL_WIDTH_CHAR1  0x4E00	/* CJK Ideograph 'number one' */
904d522f475Smrg#define FULL_WIDTH_CHAR2  0xAC00	/* Korean script syllable 'Ka' */
905d522f475Smrg
906d522f475Smrgstatic Bool
9079a64e1c5Smrgis_double_width_font_xft(Display *dpy, XftFont *font)
908d522f475Smrg{
909d522f475Smrg    XGlyphInfo gi1, gi2;
910d522f475Smrg    FcChar32 c1 = HALF_WIDTH_CHAR1, c2 = HALF_WIDTH_CHAR2;
9110bd37d32Smrg    String fwstr = FULL_WIDTH_TEST_STRING;
9120bd37d32Smrg    String hwstr = HALF_WIDTH_TEST_STRING;
913d522f475Smrg
914d522f475Smrg    /* Some Korean fonts don't have Chinese characters at all. */
915d522f475Smrg    if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR1)) {
916d522f475Smrg	if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR2))
917d522f475Smrg	    return False;	/* Not a CJK font */
918d522f475Smrg	else			/* a Korean font without CJK Ideographs */
919d522f475Smrg	    fwstr = FULL_WIDTH_TEST_STRING2;
920d522f475Smrg    }
921d522f475Smrg
922d522f475Smrg    XftTextExtents32(dpy, font, &c1, 1, &gi1);
923d522f475Smrg    XftTextExtents32(dpy, font, &c2, 1, &gi2);
924d522f475Smrg    if (gi1.xOff != gi2.xOff)	/* Not a fixed-width font */
925d522f475Smrg	return False;
926d522f475Smrg
9270bd37d32Smrg    XftTextExtentsUtf8(dpy,
9280bd37d32Smrg		       font,
9290bd37d32Smrg		       (_Xconst FcChar8 *) hwstr,
9300bd37d32Smrg		       (int) strlen(hwstr),
9310bd37d32Smrg		       &gi1);
9320bd37d32Smrg    XftTextExtentsUtf8(dpy,
9330bd37d32Smrg		       font,
9340bd37d32Smrg		       (_Xconst FcChar8 *) fwstr,
9350bd37d32Smrg		       (int) strlen(fwstr),
9360bd37d32Smrg		       &gi2);
937d522f475Smrg
938d522f475Smrg    /*
939d522f475Smrg     * fontconfig and Xft prior to 2.2(?) set the width of half-width
940d522f475Smrg     * characters identical to that of full-width character in CJK double-width
941d522f475Smrg     * (bi-width / monospace) font even though the former is half as wide as
942d522f475Smrg     * the latter.  This was fixed sometime before the release of fontconfig
943d522f475Smrg     * 2.2 in early 2003.  See
944d522f475Smrg     *  http://bugzilla.mozilla.org/show_bug.cgi?id=196312
945d522f475Smrg     * In the meantime, we have to check both possibilities.
946d522f475Smrg     */
947d522f475Smrg    return ((2 * gi1.xOff == gi2.xOff) || (gi1.xOff == gi2.xOff));
948d522f475Smrg}
949d522f475Smrg#else
950d522f475Smrg#define is_double_width_font_xft(dpy, xftfont) 0
951d522f475Smrg#endif
952d522f475Smrg
953190d7dceSmrg#define EmptyFont(fs) (fs != NULL \
954d522f475Smrg		   && ((fs)->ascent + (fs)->descent == 0 \
955d522f475Smrg		    || (fs)->max_bounds.width == 0))
956d522f475Smrg
957d522f475Smrg#define FontSize(fs) (((fs)->ascent + (fs)->descent) \
958d522f475Smrg		    *  (fs)->max_bounds.width)
959d522f475Smrg
960d522f475Smrgconst VTFontNames *
96120d2c4d2SmrgxtermFontName(const char *normal)
962d522f475Smrg{
963d522f475Smrg    static VTFontNames data;
9649a64e1c5Smrg    FREE_STRING(data.f_n);
965d522f475Smrg    memset(&data, 0, sizeof(data));
966dfb07bc7Smrg    if (normal)
967dfb07bc7Smrg	data.f_n = x_strdup(normal);
968dfb07bc7Smrg    return &data;
969dfb07bc7Smrg}
970dfb07bc7Smrg
971dfb07bc7Smrgconst VTFontNames *
972dfb07bc7SmrgdefaultVTFontNames(XtermWidget xw)
973dfb07bc7Smrg{
974dfb07bc7Smrg    static VTFontNames data;
975dfb07bc7Smrg    memset(&data, 0, sizeof(data));
976dfb07bc7Smrg    data.f_n = DefaultFontN(xw);
977dfb07bc7Smrg    data.f_b = DefaultFontB(xw);
978dfb07bc7Smrg#if OPT_WIDE_CHARS
979dfb07bc7Smrg    data.f_w = DefaultFontW(xw);
980dfb07bc7Smrg    data.f_wb = DefaultFontWB(xw);
981dfb07bc7Smrg#endif
982d522f475Smrg    return &data;
983d522f475Smrg}
984d522f475Smrg
985d522f475Smrgstatic void
986fa3f02f3Smrgcache_menu_font_name(TScreen *screen, int fontnum, int which, const char *name)
987d522f475Smrg{
988190d7dceSmrg    if (name != NULL) {
9899a64e1c5Smrg	String last = screen->menu_font_names[fontnum][which];
990190d7dceSmrg	if (last != NULL) {
991d522f475Smrg	    if (strcmp(last, name)) {
9929a64e1c5Smrg		FREE_STRING(last);
993d522f475Smrg		TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name));
994d522f475Smrg		screen->menu_font_names[fontnum][which] = x_strdup(name);
995d522f475Smrg	    }
996d522f475Smrg	} else {
997d522f475Smrg	    TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name));
998d522f475Smrg	    screen->menu_font_names[fontnum][which] = x_strdup(name);
999d522f475Smrg	}
1000d522f475Smrg    }
1001d522f475Smrg}
1002d522f475Smrg
1003dfb07bc7Smrgstatic void
1004d4fba8b9SmrgcannotFont(XtermWidget xw, const char *who, const char *tag, const char *name)
1005dfb07bc7Smrg{
1006d4fba8b9Smrg    static NameList *reported;
1007d4fba8b9Smrg    NameList *list;
1008dfb07bc7Smrg
1009dfb07bc7Smrg    switch (xw->misc.fontWarnings) {
1010dfb07bc7Smrg    case fwNever:
1011dfb07bc7Smrg	return;
1012dfb07bc7Smrg    case fwResource:
1013d4fba8b9Smrg	if (is_derived_font_name(name))
1014d4fba8b9Smrg	    return;
1015dfb07bc7Smrg	break;
1016dfb07bc7Smrg    case fwAlways:
1017dfb07bc7Smrg	break;
1018dfb07bc7Smrg    }
1019190d7dceSmrg    for (list = reported; list != NULL; list = list->next) {
1020d4fba8b9Smrg	if (!x_strcasecmp(name, list->name)) {
1021d4fba8b9Smrg	    return;
1022d4fba8b9Smrg	}
1023d4fba8b9Smrg    }
1024190d7dceSmrg    if ((list = TypeMalloc(NameList)) != NULL) {
1025d4fba8b9Smrg	list->name = x_strdup(name);
1026d4fba8b9Smrg	list->next = reported;
1027d4fba8b9Smrg	reported = list;
1028d4fba8b9Smrg    }
1029d4fba8b9Smrg    xtermWarning("cannot %s%s%s %sfont \"%s\"\n",
1030d4fba8b9Smrg		 who, *tag ? " " : "", tag,
1031d4fba8b9Smrg		 is_derived_font_name(name) ? "derived " : "",
1032d4fba8b9Smrg		 name);
1033dfb07bc7Smrg}
1034dfb07bc7Smrg
1035d4fba8b9Smrg#if OPT_RENDERFONT
1036d4fba8b9Smrgstatic void
1037d4fba8b9SmrgnoUsableXft(XtermWidget xw, const char *name)
1038d4fba8b9Smrg{
1039d4fba8b9Smrg    switch (xw->misc.fontWarnings) {
1040d4fba8b9Smrg    case fwNever:
1041d4fba8b9Smrg	return;
1042d4fba8b9Smrg    case fwResource:
1043d4fba8b9Smrg	/* these combinations of wide/bold/italic are all "derived" */
1044d4fba8b9Smrg	return;
1045d4fba8b9Smrg    case fwAlways:
1046d4fba8b9Smrg	break;
1047d4fba8b9Smrg    }
1048d4fba8b9Smrg    xtermWarning("did not find a usable %s TrueType font\n", name);
1049d4fba8b9Smrg}
1050d4fba8b9Smrg#endif
1051d4fba8b9Smrg
10528f44fb3bSmrgXFontStruct *
10538f44fb3bSmrgxtermLoadQueryFont(XtermWidget xw, const char *name)
10548f44fb3bSmrg{
10558f44fb3bSmrg    XFontStruct *result = NULL;
10568f44fb3bSmrg    size_t have = strlen(name);
10578f44fb3bSmrg    if (have == 0 || have > MAX_U_STRING) {
10588f44fb3bSmrg	;			/* just ignore it */
10598f44fb3bSmrg    } else {
10608f44fb3bSmrg	TScreen *screen = TScreenOf(xw);
10618f44fb3bSmrg	result = XLoadQueryFont(screen->display, name);
10628f44fb3bSmrg    }
10638f44fb3bSmrg    return result;
10648f44fb3bSmrg}
10658f44fb3bSmrg
1066d522f475Smrg/*
1067d1603babSmrg * Open the given font and verify that it is non-empty.  Return false on
1068d522f475Smrg * failure.
1069d522f475Smrg */
1070d522f475SmrgBool
1071956cc18dSsnjxtermOpenFont(XtermWidget xw,
1072956cc18dSsnj	      const char *name,
1073956cc18dSsnj	      XTermFonts * result,
1074d1603babSmrg	      XTermFonts * current,
1075956cc18dSsnj	      Bool force)
1076d522f475Smrg{
1077d522f475Smrg    Bool code = False;
1078d522f475Smrg
1079d4fba8b9Smrg    TRACE(("xtermOpenFont %d:%d '%s'\n",
1080d4fba8b9Smrg	   result->warn, xw->misc.fontWarnings, NonNull(name)));
1081d1603babSmrg
1082492d43a5Smrg    if (!IsEmpty(name)) {
1083d1603babSmrg	Bool existing = (current != NULL
1084d1603babSmrg			 && current->fs != NULL
1085d1603babSmrg			 && current->fn != NULL);
1086d1603babSmrg
1087190d7dceSmrg	if ((result->fs = xtermLoadQueryFont(xw, name)) != NULL) {
1088956cc18dSsnj	    code = True;
1089956cc18dSsnj	    if (EmptyFont(result->fs)) {
1090dfb07bc7Smrg		xtermCloseFont(xw, result);
1091956cc18dSsnj		code = False;
1092956cc18dSsnj	    } else {
1093956cc18dSsnj		result->fn = x_strdup(name);
1094956cc18dSsnj	    }
109520d2c4d2Smrg	} else if (XmuCompareISOLatin1(name, DEFFONT) != 0) {
1096dfb07bc7Smrg	    if (result->warn <= xw->misc.fontWarnings
1097956cc18dSsnj#if OPT_RENDERFONT
1098956cc18dSsnj		&& !UsingRenderFont(xw)
1099956cc18dSsnj#endif
1100956cc18dSsnj		) {
1101dfb07bc7Smrg		cannotFont(xw, "load", "", name);
1102956cc18dSsnj	    } else {
1103492d43a5Smrg		TRACE(("xtermOpenFont: cannot load font '%s'\n", name));
1104956cc18dSsnj	    }
1105d1603babSmrg	    if (existing) {
1106d1603babSmrg		TRACE(("...continue using font '%s'\n", current->fn));
1107d1603babSmrg		result->fn = x_strdup(current->fn);
1108d1603babSmrg		result->fs = current->fs;
1109d1603babSmrg	    } else if (force) {
1110d4fba8b9Smrg		NoFontWarning(result);
1111d1603babSmrg		code = xtermOpenFont(xw, DEFFONT, result, NULL, True);
1112956cc18dSsnj	    }
1113d522f475Smrg	}
1114d522f475Smrg    }
1115d4fba8b9Smrg    NoFontWarning(result);
1116d522f475Smrg    return code;
1117d522f475Smrg}
1118d522f475Smrg
1119d522f475Smrg/*
1120956cc18dSsnj * Close the font and free the font info.
1121d522f475Smrg */
1122dfb07bc7Smrgvoid
1123d522f475SmrgxtermCloseFont(XtermWidget xw, XTermFonts * fnt)
1124d522f475Smrg{
1125190d7dceSmrg    if (fnt != NULL && fnt->fs != NULL) {
1126d522f475Smrg	TScreen *screen = TScreenOf(xw);
1127d522f475Smrg
1128d522f475Smrg	clrCgsFonts(xw, WhichVWin(screen), fnt);
1129d522f475Smrg	XFreeFont(screen->display, fnt->fs);
1130d522f475Smrg	xtermFreeFontInfo(fnt);
1131d522f475Smrg    }
1132d522f475Smrg}
1133d522f475Smrg
1134037a25ddSmrg/*
1135037a25ddSmrg * Close and free the font (as well as any aliases).
1136037a25ddSmrg */
1137037a25ddSmrgstatic void
1138037a25ddSmrgxtermCloseFont2(XtermWidget xw, XTermFonts * fnts, int which)
1139037a25ddSmrg{
1140037a25ddSmrg    XFontStruct *thisFont = fnts[which].fs;
1141037a25ddSmrg
1142190d7dceSmrg    if (thisFont != NULL) {
1143037a25ddSmrg	int k;
1144037a25ddSmrg
1145037a25ddSmrg	xtermCloseFont(xw, &fnts[which]);
1146037a25ddSmrg	for (k = 0; k < fMAX; ++k) {
1147037a25ddSmrg	    if (k != which) {
1148037a25ddSmrg		if (thisFont == fnts[k].fs) {
1149037a25ddSmrg		    xtermFreeFontInfo(&fnts[k]);
1150037a25ddSmrg		}
1151037a25ddSmrg	    }
1152037a25ddSmrg	}
1153037a25ddSmrg    }
1154037a25ddSmrg}
1155037a25ddSmrg
1156d522f475Smrg/*
1157d522f475Smrg * Close the listed fonts, noting that some may use copies of the pointer.
1158d522f475Smrg */
1159d522f475Smrgvoid
1160d522f475SmrgxtermCloseFonts(XtermWidget xw, XTermFonts * fnts)
1161d522f475Smrg{
1162037a25ddSmrg    int j;
1163d522f475Smrg
1164d522f475Smrg    for (j = 0; j < fMAX; ++j) {
1165037a25ddSmrg	xtermCloseFont2(xw, fnts, j);
1166d522f475Smrg    }
1167d522f475Smrg}
1168d522f475Smrg
1169d522f475Smrg/*
1170d522f475Smrg * Make a copy of the source, assuming the XFontStruct's to be unique, but
1171d522f475Smrg * ensuring that the names are reallocated to simplify freeing.
1172d522f475Smrg */
1173d522f475Smrgvoid
1174d522f475SmrgxtermCopyFontInfo(XTermFonts * target, XTermFonts * source)
1175d522f475Smrg{
1176d522f475Smrg    xtermFreeFontInfo(target);
1177d522f475Smrg    target->chrset = source->chrset;
1178d522f475Smrg    target->flags = source->flags;
1179d522f475Smrg    target->fn = x_strdup(source->fn);
1180d522f475Smrg    target->fs = source->fs;
1181dfb07bc7Smrg    target->warn = source->warn;
1182d522f475Smrg}
1183d522f475Smrg
1184d522f475Smrgvoid
1185d522f475SmrgxtermFreeFontInfo(XTermFonts * target)
1186d522f475Smrg{
1187d522f475Smrg    target->chrset = 0;
1188d522f475Smrg    target->flags = 0;
1189d4fba8b9Smrg    FreeAndNull(target->fn);
1190190d7dceSmrg    target->fs = NULL;
1191d522f475Smrg}
1192d522f475Smrg
1193fa3f02f3Smrg#if OPT_REPORT_FONTS
1194fa3f02f3Smrgstatic void
1195fa3f02f3SmrgreportXCharStruct(const char *tag, XCharStruct * cs)
1196fa3f02f3Smrg{
1197d1603babSmrg    ReportFonts("\t\t%s:\n", tag);
1198d1603babSmrg    ReportFonts("\t\t\tlbearing: %d\n", cs->lbearing);
1199d1603babSmrg    ReportFonts("\t\t\trbearing: %d\n", cs->rbearing);
1200d1603babSmrg    ReportFonts("\t\t\twidth:    %d\n", cs->width);
1201d1603babSmrg    ReportFonts("\t\t\tascent:   %d\n", cs->ascent);
1202d1603babSmrg    ReportFonts("\t\t\tdescent:  %d\n", cs->descent);
1203fa3f02f3Smrg}
1204fa3f02f3Smrg
1205190d7dceSmrgstatic void
1206190d7dceSmrgfillXCharStruct(XCharStruct * cs, short value)
1207190d7dceSmrg{
1208190d7dceSmrg    cs->lbearing = value;
1209190d7dceSmrg    cs->rbearing = value;
1210190d7dceSmrg    cs->width = value;
1211190d7dceSmrg    cs->ascent = value;
1212190d7dceSmrg    cs->descent = value;
1213190d7dceSmrg}
1214190d7dceSmrg
1215190d7dceSmrg/* if the per-character data differs from the summary, that is a problem */
1216190d7dceSmrgstatic void
1217190d7dceSmrgcompareXCharStruct(const char *tag, XCharStruct * actual, XCharStruct * expect)
1218190d7dceSmrg{
1219190d7dceSmrg#define CompareXCharStruct(field) \
1220190d7dceSmrg    if (actual->field != expect->field) \
1221190d7dceSmrg    	ReportFonts("\t\t%s %s differs: %d\n", tag, #field, actual->field)
1222190d7dceSmrg    CompareXCharStruct(lbearing);
1223190d7dceSmrg    CompareXCharStruct(rbearing);
1224190d7dceSmrg    CompareXCharStruct(width);
1225190d7dceSmrg    CompareXCharStruct(ascent);
1226190d7dceSmrg    CompareXCharStruct(descent);
1227190d7dceSmrg}
1228190d7dceSmrg
1229190d7dceSmrgstatic void
1230190d7dceSmrgreportXPerChar(XFontStruct *fs)
1231190d7dceSmrg{
1232190d7dceSmrg    XCharStruct *cs = fs->per_char;
1233190d7dceSmrg
1234190d7dceSmrg    if (cs != NULL) {
1235190d7dceSmrg	XCharStruct min_bounds;
1236190d7dceSmrg	XCharStruct max_bounds;
1237190d7dceSmrg	int valid = 0;
1238190d7dceSmrg	int total = 0;
1239190d7dceSmrg	unsigned first_char = 0;
1240190d7dceSmrg	unsigned last_char = 0;
1241190d7dceSmrg	unsigned ch;
1242190d7dceSmrg
1243190d7dceSmrg	if (fs->max_byte1 == 0) {
1244190d7dceSmrg	    first_char = fs->min_char_or_byte2;
1245190d7dceSmrg	    last_char = fs->max_char_or_byte2;
1246190d7dceSmrg	} else {
1247190d7dceSmrg	    first_char = (fs->min_byte1 * 256) + fs->min_char_or_byte2;
1248190d7dceSmrg	    last_char = (fs->max_byte1 * 256) + fs->max_char_or_byte2;
1249190d7dceSmrg	}
1250190d7dceSmrg
1251190d7dceSmrg	fillXCharStruct(&max_bounds, -32768);
1252190d7dceSmrg	fillXCharStruct(&min_bounds, 32767);
1253190d7dceSmrg	TRACE2(("\t\tCells: %d..%d\n", first_char, last_char));
1254190d7dceSmrg	for (ch = first_char; ch < last_char; ++ch) {
1255190d7dceSmrg	    XCharStruct *item = cs + ch - first_char;
1256190d7dceSmrg	    ++total;
1257190d7dceSmrg	    if (!CI_NONEXISTCHAR(item)) {
1258190d7dceSmrg		++valid;
1259190d7dceSmrg#define MIN_BOUNDS(field) min_bounds.field = Min(min_bounds.field, item->field)
1260190d7dceSmrg		MIN_BOUNDS(lbearing);
1261190d7dceSmrg		MIN_BOUNDS(rbearing);
1262190d7dceSmrg		MIN_BOUNDS(width);
1263190d7dceSmrg		MIN_BOUNDS(ascent);
1264190d7dceSmrg		MIN_BOUNDS(descent);
1265190d7dceSmrg#define MAX_BOUNDS(field) max_bounds.field = Max(max_bounds.field, item->field)
1266190d7dceSmrg		MAX_BOUNDS(lbearing);
1267190d7dceSmrg		MAX_BOUNDS(rbearing);
1268190d7dceSmrg		MAX_BOUNDS(width);
1269190d7dceSmrg		MAX_BOUNDS(ascent);
1270190d7dceSmrg		MAX_BOUNDS(descent);
1271190d7dceSmrg		TRACE2(("\t\t\t%d: cell [%d .. %d] wide %d high %d / %d\n",
1272190d7dceSmrg			ch,
1273190d7dceSmrg			item->lbearing,
1274190d7dceSmrg			item->rbearing,
1275190d7dceSmrg			item->width,
1276190d7dceSmrg			item->ascent,
1277190d7dceSmrg			item->descent));
1278190d7dceSmrg	    } else {
1279190d7dceSmrg		TRACE(("\t\t\t%d: cell missing\n", ch));
1280190d7dceSmrg	    }
1281190d7dceSmrg	}
1282190d7dceSmrg	ReportFonts("\t\tPer-character: %d/%d\n", valid, total);
1283190d7dceSmrg	compareXCharStruct("Max", &max_bounds, &(fs->max_bounds));
1284190d7dceSmrg	compareXCharStruct("Min", &min_bounds, &(fs->min_bounds));
1285190d7dceSmrg    } else {
1286190d7dceSmrg	ReportFonts("\t\tPer-character: none\n");
1287190d7dceSmrg    }
1288190d7dceSmrg}
1289190d7dceSmrg
1290fa3f02f3Smrgstatic void
1291fa3f02f3SmrgreportOneVTFont(const char *tag,
1292fa3f02f3Smrg		XTermFonts * fnt)
1293fa3f02f3Smrg{
1294190d7dceSmrg    if (!IsEmpty(fnt->fn) && fnt->fs != NULL) {
1295fa3f02f3Smrg	XFontStruct *fs = fnt->fs;
1296fa3f02f3Smrg	unsigned first_char = 0;
1297fa3f02f3Smrg	unsigned last_char = 0;
1298fa3f02f3Smrg
1299fa3f02f3Smrg	if (fs->max_byte1 == 0) {
1300fa3f02f3Smrg	    first_char = fs->min_char_or_byte2;
1301fa3f02f3Smrg	    last_char = fs->max_char_or_byte2;
1302fa3f02f3Smrg	} else {
1303fa3f02f3Smrg	    first_char = (fs->min_byte1 * 256) + fs->min_char_or_byte2;
1304fa3f02f3Smrg	    last_char = (fs->max_byte1 * 256) + fs->max_char_or_byte2;
1305fa3f02f3Smrg	}
1306fa3f02f3Smrg
1307d1603babSmrg	ReportFonts("\t%s: %s\n", tag, NonNull(fnt->fn));
1308d1603babSmrg	ReportFonts("\t\tall chars:     %s\n", (fs->all_chars_exist
1309d1603babSmrg						? "yes"
1310d1603babSmrg						: "no"));
1311d1603babSmrg	ReportFonts("\t\tdefault char:  %u\n", fs->default_char);
1312d1603babSmrg	ReportFonts("\t\tdirection:     %u\n", fs->direction);
1313d1603babSmrg	ReportFonts("\t\tascent:        %d\n", fs->ascent);
1314d1603babSmrg	ReportFonts("\t\tdescent:       %d\n", fs->descent);
1315d1603babSmrg	ReportFonts("\t\tfirst char:    %u\n", first_char);
1316d1603babSmrg	ReportFonts("\t\tlast char:     %u\n", last_char);
1317d1603babSmrg	ReportFonts("\t\tmaximum-chars: %u\n", countGlyphs(fs));
13189a64e1c5Smrg	if (FontLacksMetrics(fnt)) {
1319d1603babSmrg	    ReportFonts("\t\tmissing-chars: ?\n");
1320d1603babSmrg	    ReportFonts("\t\tpresent-chars: ?\n");
13219a64e1c5Smrg	} else {
13229a64e1c5Smrg	    unsigned missing = 0;
1323037a25ddSmrg	    unsigned ch;
13249a64e1c5Smrg	    for (ch = first_char; ch <= last_char; ++ch) {
13259a64e1c5Smrg		if (xtermMissingChar(ch, fnt)) {
13269a64e1c5Smrg		    ++missing;
13279a64e1c5Smrg		}
13289a64e1c5Smrg	    }
1329d1603babSmrg	    ReportFonts("\t\tmissing-chars: %u\n", missing);
1330d1603babSmrg	    ReportFonts("\t\tpresent-chars: %u\n", countGlyphs(fs) - missing);
13319a64e1c5Smrg	}
1332d1603babSmrg	ReportFonts("\t\tmin_byte1:     %u\n", fs->min_byte1);
1333d1603babSmrg	ReportFonts("\t\tmax_byte1:     %u\n", fs->max_byte1);
1334d1603babSmrg	ReportFonts("\t\tproperties:    %d\n", fs->n_properties);
1335fa3f02f3Smrg	reportXCharStruct("min_bounds", &(fs->min_bounds));
1336fa3f02f3Smrg	reportXCharStruct("max_bounds", &(fs->max_bounds));
1337190d7dceSmrg	reportXPerChar(fs);
1338190d7dceSmrg	/* TODO: report fs->properties */
1339fa3f02f3Smrg    }
1340fa3f02f3Smrg}
1341fa3f02f3Smrg
1342fa3f02f3Smrgstatic void
1343fa3f02f3SmrgreportVTFontInfo(XtermWidget xw, int fontnum)
1344fa3f02f3Smrg{
1345fa3f02f3Smrg    if (resource.reportFonts) {
1346fa3f02f3Smrg	TScreen *screen = TScreenOf(xw);
1347fa3f02f3Smrg
1348fa3f02f3Smrg	if (fontnum) {
1349d1603babSmrg	    ReportFonts("Loaded VTFonts(font%d)\n", fontnum);
1350fa3f02f3Smrg	} else {
1351d1603babSmrg	    ReportFonts("Loaded VTFonts(default)\n");
1352fa3f02f3Smrg	}
1353dfb07bc7Smrg
1354190d7dceSmrg#define ReportOneVTFont(name) reportOneVTFont(#name, screen->fnts + name)
1355190d7dceSmrg	ReportOneVTFont(fNorm);
1356190d7dceSmrg	ReportOneVTFont(fBold);
1357fa3f02f3Smrg#if OPT_WIDE_CHARS
1358190d7dceSmrg	ReportOneVTFont(fWide);
1359190d7dceSmrg	ReportOneVTFont(fWBold);
1360fa3f02f3Smrg#endif
1361fa3f02f3Smrg    }
1362fa3f02f3Smrg}
1363fa3f02f3Smrg#endif
1364fa3f02f3Smrg
13659a64e1c5Smrgvoid
1366d4fba8b9SmrgxtermUpdateFontGCs(XtermWidget xw, MyGetFont myfunc)
13679a64e1c5Smrg{
13689a64e1c5Smrg    TScreen *screen = TScreenOf(xw);
13699a64e1c5Smrg    VTwin *win = WhichVWin(screen);
1370d4fba8b9Smrg    Pixel new_normal = getXtermFG(xw, xw->flags, xw->cur_foreground);
1371d4fba8b9Smrg    Pixel new_revers = getXtermBG(xw, xw->flags, xw->cur_background);
1372dfb07bc7Smrg
13739a64e1c5Smrg    setCgsFore(xw, win, gcNorm, new_normal);
13749a64e1c5Smrg    setCgsBack(xw, win, gcNorm, new_revers);
1375dfb07bc7Smrg    setCgsFont(xw, win, gcNorm, myfunc(screen, fNorm));
13769a64e1c5Smrg
13779a64e1c5Smrg    copyCgs(xw, win, gcBold, gcNorm);
1378d4fba8b9Smrg    setCgsFont2(xw, win, gcBold, myfunc(screen, fBold), fBold);
13799a64e1c5Smrg
13809a64e1c5Smrg    setCgsFore(xw, win, gcNormReverse, new_revers);
13819a64e1c5Smrg    setCgsBack(xw, win, gcNormReverse, new_normal);
1382dfb07bc7Smrg    setCgsFont(xw, win, gcNormReverse, myfunc(screen, fNorm));
13839a64e1c5Smrg
13849a64e1c5Smrg    copyCgs(xw, win, gcBoldReverse, gcNormReverse);
1385d4fba8b9Smrg    setCgsFont2(xw, win, gcBoldReverse, myfunc(screen, fBold), fBold);
13869a64e1c5Smrg
13879a64e1c5Smrg    if_OPT_WIDE_CHARS(screen, {
1388dfb07bc7Smrg	XTermFonts *wide_xx = myfunc(screen, fWide);
1389dfb07bc7Smrg	XTermFonts *bold_xx = myfunc(screen, fWBold);
1390190d7dceSmrg	if (wide_xx->fs != NULL
1391190d7dceSmrg	    && bold_xx->fs != NULL) {
13929a64e1c5Smrg	    setCgsFore(xw, win, gcWide, new_normal);
13939a64e1c5Smrg	    setCgsBack(xw, win, gcWide, new_revers);
1394dfb07bc7Smrg	    setCgsFont(xw, win, gcWide, wide_xx);
13959a64e1c5Smrg
13969a64e1c5Smrg	    copyCgs(xw, win, gcWBold, gcWide);
1397dfb07bc7Smrg	    setCgsFont(xw, win, gcWBold, bold_xx);
13989a64e1c5Smrg
13999a64e1c5Smrg	    setCgsFore(xw, win, gcWideReverse, new_revers);
14009a64e1c5Smrg	    setCgsBack(xw, win, gcWideReverse, new_normal);
1401dfb07bc7Smrg	    setCgsFont(xw, win, gcWideReverse, wide_xx);
14029a64e1c5Smrg
14039a64e1c5Smrg	    copyCgs(xw, win, gcWBoldReverse, gcWideReverse);
1404dfb07bc7Smrg	    setCgsFont(xw, win, gcWBoldReverse, bold_xx);
14059a64e1c5Smrg	}
14069a64e1c5Smrg    });
14079a64e1c5Smrg}
14089a64e1c5Smrg
1409d4fba8b9Smrg#if OPT_WIDE_ATTRS
1410d4fba8b9Smrgunsigned
1411d4fba8b9SmrgxtermUpdateItalics(XtermWidget xw, unsigned new_attrs, unsigned old_attrs)
1412d4fba8b9Smrg{
1413c48a5815Smrg    TScreen *screen = TScreenOf(xw);
1414c48a5815Smrg
141550027b5bSmrg    (void) screen;
1416c48a5815Smrg    if (UseItalicFont(screen)) {
1417c48a5815Smrg	if ((new_attrs & ATR_ITALIC) && !(old_attrs & ATR_ITALIC)) {
1418c48a5815Smrg	    xtermLoadItalics(xw);
1419c48a5815Smrg	    xtermUpdateFontGCs(xw, getItalicFont);
1420c48a5815Smrg	} else if (!(new_attrs & ATR_ITALIC) && (old_attrs & ATR_ITALIC)) {
1421c48a5815Smrg	    xtermUpdateFontGCs(xw, getNormalFont);
1422c48a5815Smrg	}
1423d4fba8b9Smrg    }
1424d4fba8b9Smrg    return new_attrs;
1425d4fba8b9Smrg}
1426d4fba8b9Smrg#endif
1427d4fba8b9Smrg
1428d4fba8b9Smrg#if OPT_TRACE && OPT_BOX_CHARS
14299a64e1c5Smrgstatic void
14309a64e1c5Smrgshow_font_misses(const char *name, XTermFonts * fp)
14319a64e1c5Smrg{
1432190d7dceSmrg    if (fp->fs != NULL) {
14339a64e1c5Smrg	if (FontLacksMetrics(fp)) {
14349a64e1c5Smrg	    TRACE(("%s font lacks metrics\n", name));
14359a64e1c5Smrg	} else if (FontIsIncomplete(fp)) {
14369a64e1c5Smrg	    TRACE(("%s font is incomplete\n", name));
14379a64e1c5Smrg	} else {
14389a64e1c5Smrg	    TRACE(("%s font is complete\n", name));
14399a64e1c5Smrg	}
14409a64e1c5Smrg    } else {
14419a64e1c5Smrg	TRACE(("%s font is missing\n", name));
14429a64e1c5Smrg    }
14439a64e1c5Smrg}
14449a64e1c5Smrg#endif
14459a64e1c5Smrg
1446dfb07bc7Smrgstatic Bool
1447dfb07bc7SmrgloadNormFP(XtermWidget xw,
1448dfb07bc7Smrg	   char **nameOutP,
1449dfb07bc7Smrg	   XTermFonts * infoOut,
1450d1603babSmrg	   XTermFonts * current,
1451dfb07bc7Smrg	   int fontnum)
1452dfb07bc7Smrg{
1453dfb07bc7Smrg    Bool status = True;
1454dfb07bc7Smrg
1455dfb07bc7Smrg    TRACE(("loadNormFP (%s)\n", NonNull(*nameOutP)));
1456dfb07bc7Smrg
1457dfb07bc7Smrg    if (!xtermOpenFont(xw,
1458dfb07bc7Smrg		       *nameOutP,
1459dfb07bc7Smrg		       infoOut,
1460d1603babSmrg		       current, (fontnum == fontMenu_default))) {
1461dfb07bc7Smrg	/*
1462dfb07bc7Smrg	 * If we are opening the default font, and it happens to be missing,
1463dfb07bc7Smrg	 * force that to the compiled-in default font, e.g., "fixed".  If we
1464dfb07bc7Smrg	 * cannot open the font, disable it from the menu.
1465dfb07bc7Smrg	 */
1466dfb07bc7Smrg	if (fontnum != fontMenu_fontsel) {
1467dfb07bc7Smrg	    SetItemSensitivity(fontMenuEntries[fontnum].widget, False);
1468dfb07bc7Smrg	}
1469dfb07bc7Smrg	status = False;
1470dfb07bc7Smrg    }
1471dfb07bc7Smrg    return status;
1472dfb07bc7Smrg}
1473dfb07bc7Smrg
1474dfb07bc7Smrgstatic Bool
1475dfb07bc7SmrgloadBoldFP(XtermWidget xw,
1476dfb07bc7Smrg	   char **nameOutP,
1477dfb07bc7Smrg	   XTermFonts * infoOut,
1478dfb07bc7Smrg	   const char *nameRef,
1479dfb07bc7Smrg	   XTermFonts * infoRef,
1480dfb07bc7Smrg	   int fontnum)
1481dfb07bc7Smrg{
1482dfb07bc7Smrg    TScreen *screen = TScreenOf(xw);
1483dfb07bc7Smrg    Bool status = True;
1484dfb07bc7Smrg
1485dfb07bc7Smrg    TRACE(("loadBoldFP (%s)\n", NonNull(*nameOutP)));
1486dfb07bc7Smrg
1487dfb07bc7Smrg    if (!check_fontname(*nameOutP)) {
1488dfb07bc7Smrg	FontNameProperties *fp;
1489dfb07bc7Smrg	char *normal = x_strdup(nameRef);
1490dfb07bc7Smrg
1491dfb07bc7Smrg	fp = get_font_name_props(screen->display, infoRef->fs, &normal);
1492190d7dceSmrg	if (fp != NULL) {
1493d4fba8b9Smrg	    NoFontWarning(infoOut);
1494dfb07bc7Smrg	    *nameOutP = bold_font_name(fp, fp->average_width);
1495d1603babSmrg	    if (!xtermOpenFont(xw, *nameOutP, infoOut, NULL, False)) {
1496dfb07bc7Smrg		free(*nameOutP);
1497dfb07bc7Smrg		*nameOutP = bold_font_name(fp, -1);
1498d1603babSmrg		xtermOpenFont(xw, *nameOutP, infoOut, NULL, False);
1499dfb07bc7Smrg	    }
1500dfb07bc7Smrg	    TRACE(("...derived bold '%s'\n", NonNull(*nameOutP)));
1501dfb07bc7Smrg	}
1502190d7dceSmrg	if (fp == NULL || infoOut->fs == NULL) {
1503dfb07bc7Smrg	    xtermCopyFontInfo(infoOut, infoRef);
1504dfb07bc7Smrg	    TRACE(("...cannot load a matching bold font\n"));
1505dfb07bc7Smrg	} else if (comparable_metrics(infoRef->fs, infoOut->fs)
1506dfb07bc7Smrg		   && same_font_size(xw, infoRef->fs, infoOut->fs)
1507dfb07bc7Smrg		   && got_bold_font(screen->display, infoOut->fs, *nameOutP)) {
1508dfb07bc7Smrg	    TRACE(("...got a matching bold font\n"));
1509dfb07bc7Smrg	    cache_menu_font_name(screen, fontnum, fBold, *nameOutP);
1510dfb07bc7Smrg	} else {
1511dfb07bc7Smrg	    xtermCloseFont2(xw, infoOut - fBold, fBold);
1512dfb07bc7Smrg	    *infoOut = *infoRef;
1513dfb07bc7Smrg	    TRACE(("...did not get a matching bold font\n"));
1514dfb07bc7Smrg	}
1515dfb07bc7Smrg	free(normal);
1516d1603babSmrg    } else if (!xtermOpenFont(xw, *nameOutP, infoOut, NULL, False)) {
1517dfb07bc7Smrg	xtermCopyFontInfo(infoOut, infoRef);
1518dfb07bc7Smrg	TRACE(("...cannot load bold font '%s'\n", NonNull(*nameOutP)));
1519dfb07bc7Smrg    } else {
1520dfb07bc7Smrg	cache_menu_font_name(screen, fontnum, fBold, *nameOutP);
1521dfb07bc7Smrg    }
1522dfb07bc7Smrg
1523dfb07bc7Smrg    /*
1524dfb07bc7Smrg     * Most of the time this call to load the font will succeed, even if
1525dfb07bc7Smrg     * there is no wide font :  the X server doubles the width of the
1526dfb07bc7Smrg     * normal font, or similar.
1527dfb07bc7Smrg     *
1528dfb07bc7Smrg     * But if it did fail for some reason, then nevermind.
1529dfb07bc7Smrg     */
1530dfb07bc7Smrg    if (EmptyFont(infoOut->fs))
1531dfb07bc7Smrg	status = False;		/* can't use a 0-sized font */
1532dfb07bc7Smrg
1533dfb07bc7Smrg    if (!same_font_size(xw, infoRef->fs, infoOut->fs)
1534dfb07bc7Smrg	&& (is_fixed_font(infoRef->fs) && is_fixed_font(infoOut->fs))) {
1535dfb07bc7Smrg	TRACE(("...ignoring mismatched normal/bold fonts\n"));
1536dfb07bc7Smrg	xtermCloseFont2(xw, infoOut - fBold, fBold);
1537dfb07bc7Smrg	xtermCopyFontInfo(infoOut, infoRef);
1538dfb07bc7Smrg    }
1539dfb07bc7Smrg
1540dfb07bc7Smrg    return status;
1541dfb07bc7Smrg}
1542dfb07bc7Smrg
1543dfb07bc7Smrg#if OPT_WIDE_CHARS
1544dfb07bc7Smrgstatic Bool
1545dfb07bc7SmrgloadWideFP(XtermWidget xw,
1546dfb07bc7Smrg	   char **nameOutP,
1547dfb07bc7Smrg	   XTermFonts * infoOut,
1548dfb07bc7Smrg	   const char *nameRef,
1549dfb07bc7Smrg	   XTermFonts * infoRef,
1550dfb07bc7Smrg	   int fontnum)
1551dfb07bc7Smrg{
1552dfb07bc7Smrg    TScreen *screen = TScreenOf(xw);
1553dfb07bc7Smrg    Bool status = True;
1554dfb07bc7Smrg
1555dfb07bc7Smrg    TRACE(("loadWideFP (%s)\n", NonNull(*nameOutP)));
1556dfb07bc7Smrg
1557d4fba8b9Smrg    if (!check_fontname(*nameOutP)
1558d4fba8b9Smrg	&& (screen->utf8_fonts && !is_double_width_font(infoRef->fs))) {
1559dfb07bc7Smrg	char *normal = x_strdup(nameRef);
1560d4fba8b9Smrg	FontNameProperties *fp = get_font_name_props(screen->display,
1561d4fba8b9Smrg						     infoRef->fs, &normal);
1562190d7dceSmrg	if (fp != NULL) {
1563dfb07bc7Smrg	    *nameOutP = wide_font_name(fp);
1564d4fba8b9Smrg	    NoFontWarning(infoOut);
1565dfb07bc7Smrg	}
1566dfb07bc7Smrg	free(normal);
1567dfb07bc7Smrg    }
1568dfb07bc7Smrg
1569dfb07bc7Smrg    if (check_fontname(*nameOutP)) {
1570d1603babSmrg	if (xtermOpenFont(xw, *nameOutP, infoOut, NULL, False)
1571d4fba8b9Smrg	    && is_derived_font_name(*nameOutP)
1572d4fba8b9Smrg	    && EmptyFont(infoOut->fs)) {
1573d4fba8b9Smrg	    xtermCloseFont2(xw, infoOut - fWide, fWide);
1574d4fba8b9Smrg	}
1575190d7dceSmrg	if (infoOut->fs == NULL) {
1576dfb07bc7Smrg	    xtermCopyFontInfo(infoOut, infoRef);
1577d4fba8b9Smrg	} else {
1578d4fba8b9Smrg	    TRACE(("...%s wide %s\n",
1579d4fba8b9Smrg		   is_derived_font_name(*nameOutP) ? "derived" : "given",
1580d4fba8b9Smrg		   NonNull(*nameOutP)));
1581d4fba8b9Smrg	    cache_menu_font_name(screen, fontnum, fWide, *nameOutP);
1582dfb07bc7Smrg	}
1583dfb07bc7Smrg    } else {
1584dfb07bc7Smrg	xtermCopyFontInfo(infoOut, infoRef);
1585dfb07bc7Smrg    }
1586c48a5815Smrg#define MinWidthOf(fs) fs->min_bounds.width
1587c48a5815Smrg#define MaxWidthOf(fs) fs->max_bounds.width
1588c48a5815Smrg    xw->work.force_wideFont = False;
1589c48a5815Smrg    if (MaxWidthOf(infoOut->fs) != (2 * MaxWidthOf(infoRef->fs))) {
1590c48a5815Smrg	TRACE(("...reference width %d\n", MaxWidthOf(infoRef->fs)));
1591c48a5815Smrg	TRACE(("...?? double-width %d\n", 2 * MaxWidthOf(infoRef->fs)));
1592c48a5815Smrg	TRACE(("...actual width    %d\n", MaxWidthOf(infoOut->fs)));
1593c48a5815Smrg	xw->work.force_wideFont = True;
1594c48a5815Smrg    }
1595dfb07bc7Smrg    return status;
1596dfb07bc7Smrg}
1597dfb07bc7Smrg
1598dfb07bc7Smrgstatic Bool
1599dfb07bc7SmrgloadWBoldFP(XtermWidget xw,
1600dfb07bc7Smrg	    char **nameOutP,
1601dfb07bc7Smrg	    XTermFonts * infoOut,
1602dfb07bc7Smrg	    const char *wideNameRef, XTermFonts * wideInfoRef,
1603dfb07bc7Smrg	    const char *boldNameRef, XTermFonts * boldInfoRef,
1604dfb07bc7Smrg	    int fontnum)
1605dfb07bc7Smrg{
1606dfb07bc7Smrg    TScreen *screen = TScreenOf(xw);
1607dfb07bc7Smrg    Bool status = True;
1608dfb07bc7Smrg    char *bold = NULL;
1609dfb07bc7Smrg
1610dfb07bc7Smrg    TRACE(("loadWBoldFP (%s)\n", NonNull(*nameOutP)));
1611dfb07bc7Smrg
1612dfb07bc7Smrg    if (!check_fontname(*nameOutP)) {
1613dfb07bc7Smrg	FontNameProperties *fp;
1614dfb07bc7Smrg	fp = get_font_name_props(screen->display, boldInfoRef->fs, &bold);
1615190d7dceSmrg	if (fp != NULL) {
1616dfb07bc7Smrg	    *nameOutP = widebold_font_name(fp);
1617d4fba8b9Smrg	    NoFontWarning(infoOut);
1618dfb07bc7Smrg	}
1619dfb07bc7Smrg    }
1620dfb07bc7Smrg
1621dfb07bc7Smrg    if (check_fontname(*nameOutP)) {
1622dfb07bc7Smrg
1623d1603babSmrg	if (xtermOpenFont(xw, *nameOutP, infoOut, NULL, False)
1624d4fba8b9Smrg	    && is_derived_font_name(*nameOutP)
1625dfb07bc7Smrg	    && !compatibleWideCounts(wideInfoRef->fs, infoOut->fs)) {
1626dfb07bc7Smrg	    xtermCloseFont2(xw, infoOut - fWBold, fWBold);
1627dfb07bc7Smrg	}
1628dfb07bc7Smrg
1629190d7dceSmrg	if (infoOut->fs == NULL) {
1630d4fba8b9Smrg	    if (is_derived_font_name(*nameOutP))
1631dfb07bc7Smrg		free(*nameOutP);
1632dfb07bc7Smrg	    if (IsEmpty(wideNameRef)) {
1633dfb07bc7Smrg		*nameOutP = x_strdup(boldNameRef);
1634dfb07bc7Smrg		xtermCopyFontInfo(infoOut, boldInfoRef);
1635dfb07bc7Smrg		TRACE(("...cannot load wide-bold, use bold %s\n",
1636dfb07bc7Smrg		       NonNull(boldNameRef)));
1637dfb07bc7Smrg	    } else {
1638dfb07bc7Smrg		*nameOutP = x_strdup(wideNameRef);
1639dfb07bc7Smrg		xtermCopyFontInfo(infoOut, wideInfoRef);
1640dfb07bc7Smrg		TRACE(("...cannot load wide-bold, use wide %s\n",
1641dfb07bc7Smrg		       NonNull(wideNameRef)));
1642dfb07bc7Smrg	    }
1643dfb07bc7Smrg	} else {
1644dfb07bc7Smrg	    TRACE(("...%s wide/bold %s\n",
1645d4fba8b9Smrg		   is_derived_font_name(*nameOutP) ? "derived" : "given",
1646dfb07bc7Smrg		   NonNull(*nameOutP)));
1647dfb07bc7Smrg	    cache_menu_font_name(screen, fontnum, fWBold, *nameOutP);
1648dfb07bc7Smrg	}
1649dfb07bc7Smrg    } else if (is_double_width_font(boldInfoRef->fs)) {
1650dfb07bc7Smrg	xtermCopyFontInfo(infoOut, boldInfoRef);
1651dfb07bc7Smrg	TRACE(("...bold font is double-width, use it %s\n", NonNull(boldNameRef)));
1652dfb07bc7Smrg    } else {
1653dfb07bc7Smrg	xtermCopyFontInfo(infoOut, wideInfoRef);
1654dfb07bc7Smrg	TRACE(("...cannot load wide bold font, use wide %s\n", NonNull(wideNameRef)));
1655dfb07bc7Smrg    }
1656dfb07bc7Smrg
1657dfb07bc7Smrg    free(bold);
1658dfb07bc7Smrg
1659dfb07bc7Smrg    if (EmptyFont(infoOut->fs)) {
1660dfb07bc7Smrg	status = False;		/* can't use a 0-sized font */
1661dfb07bc7Smrg    } else {
1662dfb07bc7Smrg	if ((!comparable_metrics(wideInfoRef->fs, infoOut->fs)
1663dfb07bc7Smrg	     || (!same_font_size(xw, wideInfoRef->fs, infoOut->fs)
1664dfb07bc7Smrg		 && is_fixed_font(wideInfoRef->fs)
1665dfb07bc7Smrg		 && is_fixed_font(infoOut->fs)))) {
1666dfb07bc7Smrg	    TRACE(("...ignoring mismatched normal/bold wide fonts\n"));
1667dfb07bc7Smrg	    xtermCloseFont2(xw, infoOut - fWBold, fWBold);
1668dfb07bc7Smrg	    xtermCopyFontInfo(infoOut, wideInfoRef);
1669dfb07bc7Smrg	}
1670dfb07bc7Smrg    }
1671dfb07bc7Smrg
1672dfb07bc7Smrg    return status;
1673dfb07bc7Smrg}
1674dfb07bc7Smrg#endif
1675dfb07bc7Smrg
1676d1603babSmrg/*
1677d1603babSmrg * Load a given bitmap font, along with the bold/wide variants.
1678d1603babSmrg * Returns nonzero on success.
1679d1603babSmrg */
1680d522f475Smrgint
1681d522f475SmrgxtermLoadFont(XtermWidget xw,
1682d522f475Smrg	      const VTFontNames * fonts,
1683d522f475Smrg	      Bool doresize,
1684d522f475Smrg	      int fontnum)
1685d522f475Smrg{
1686956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1687d522f475Smrg    VTwin *win = WhichVWin(screen);
1688d522f475Smrg
1689d1603babSmrg    VTFontNames new_fnames;
1690d1603babSmrg    XTermFonts new_fonts[fMAX];
1691d1603babSmrg    XTermFonts old_fonts[fMAX];
1692d522f475Smrg    char *tmpname = NULL;
1693956cc18dSsnj    Boolean proportional = False;
1694d1603babSmrg    Boolean recovered;
1695d1603babSmrg    int code = 0;
1696d522f475Smrg
1697d1603babSmrg    memset(&new_fnames, 0, sizeof(new_fnames));
1698d1603babSmrg    memset(new_fonts, 0, sizeof(new_fonts));
1699d1603babSmrg    memcpy(&old_fonts, screen->fnts, sizeof(old_fonts));
1700d522f475Smrg
1701190d7dceSmrg    if (fonts != NULL)
1702d1603babSmrg	new_fnames = *fonts;
1703d1603babSmrg    if (!check_fontname(new_fnames.f_n))
1704d1603babSmrg	return code;
1705d522f475Smrg
1706d522f475Smrg    if (fontnum == fontMenu_fontescape
1707d1603babSmrg	&& new_fnames.f_n != screen->MenuFontName(fontnum)) {
1708190d7dceSmrg	if ((tmpname = x_strdup(new_fnames.f_n)) == NULL)
1709d1603babSmrg	    return code;
1710d522f475Smrg    }
1711d522f475Smrg
1712d1603babSmrg    TRACE(("Begin Cgs - xtermLoadFont(%s)\n", new_fnames.f_n));
1713d522f475Smrg    releaseWindowGCs(xw, win);
1714d522f475Smrg
1715956cc18dSsnj#define DbgResource(name, field, index) \
1716956cc18dSsnj    TRACE(("xtermLoadFont #%d "name" %s%s\n", \
1717956cc18dSsnj    	   fontnum, \
1718d1603babSmrg	   (new_fonts[index].warn == fwResource) ? "*" : " ", \
1719d1603babSmrg	   NonNull(new_fnames.field)))
1720956cc18dSsnj    DbgResource("normal", f_n, fNorm);
1721956cc18dSsnj    DbgResource("bold  ", f_b, fBold);
1722d522f475Smrg#if OPT_WIDE_CHARS
1723956cc18dSsnj    DbgResource("wide  ", f_w, fWide);
1724956cc18dSsnj    DbgResource("w/bold", f_wb, fWBold);
1725d522f475Smrg#endif
1726d522f475Smrg
1727dfb07bc7Smrg    if (!loadNormFP(xw,
1728d1603babSmrg		    &new_fnames.f_n,
1729d1603babSmrg		    &new_fonts[fNorm],
1730d1603babSmrg		    &old_fonts[fNorm],
1731dfb07bc7Smrg		    fontnum))
1732d522f475Smrg	goto bad;
1733d522f475Smrg
1734dfb07bc7Smrg    if (!loadBoldFP(xw,
1735d1603babSmrg		    &new_fnames.f_b,
1736d1603babSmrg		    &new_fonts[fBold],
1737d1603babSmrg		    new_fnames.f_n,
1738d1603babSmrg		    &new_fonts[fNorm],
1739dfb07bc7Smrg		    fontnum))
1740dfb07bc7Smrg	goto bad;
1741d522f475Smrg
1742d522f475Smrg    /*
1743d522f475Smrg     * If there is no widefont specified, fake it by doubling AVERAGE_WIDTH
1744d522f475Smrg     * of normal fonts XLFD, and asking for it.  This plucks out 18x18ja
1745d522f475Smrg     * and 12x13ja as the corresponding fonts for 9x18 and 6x13.
1746d522f475Smrg     */
1747d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
1748d522f475Smrg
1749dfb07bc7Smrg	if (!loadWideFP(xw,
1750d1603babSmrg			&new_fnames.f_w,
1751d1603babSmrg			&new_fonts[fWide],
1752d1603babSmrg			new_fnames.f_n,
1753d1603babSmrg			&new_fonts[fNorm],
1754dfb07bc7Smrg			fontnum))
1755dfb07bc7Smrg	    goto bad;
1756dfb07bc7Smrg
1757dfb07bc7Smrg	if (!loadWBoldFP(xw,
1758d1603babSmrg			 &new_fnames.f_wb,
1759d1603babSmrg			 &new_fonts[fWBold],
1760d1603babSmrg			 new_fnames.f_w,
1761d1603babSmrg			 &new_fonts[fWide],
1762d1603babSmrg			 new_fnames.f_b,
1763d1603babSmrg			 &new_fonts[fBold],
1764dfb07bc7Smrg			 fontnum))
1765dfb07bc7Smrg	    goto bad;
1766d522f475Smrg
1767d522f475Smrg    });
1768d522f475Smrg
1769d522f475Smrg    /*
1770d522f475Smrg     * Normal/bold fonts should be the same width.  Also, the min/max
1771d522f475Smrg     * values should be the same.
1772d522f475Smrg     */
1773190d7dceSmrg    if (new_fonts[fNorm].fs != NULL
1774190d7dceSmrg	&& new_fonts[fBold].fs != NULL
1775d1603babSmrg	&& (!is_fixed_font(new_fonts[fNorm].fs)
1776d1603babSmrg	    || !is_fixed_font(new_fonts[fBold].fs)
1777d1603babSmrg	    || differing_widths(new_fonts[fNorm].fs, new_fonts[fBold].fs))) {
1778d522f475Smrg	TRACE(("Proportional font! normal %d/%d, bold %d/%d\n",
1779d1603babSmrg	       new_fonts[fNorm].fs->min_bounds.width,
1780d1603babSmrg	       new_fonts[fNorm].fs->max_bounds.width,
1781d1603babSmrg	       new_fonts[fBold].fs->min_bounds.width,
1782d1603babSmrg	       new_fonts[fBold].fs->max_bounds.width));
1783d522f475Smrg	proportional = True;
1784d522f475Smrg    }
1785d522f475Smrg
1786d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
1787190d7dceSmrg	if (new_fonts[fWide].fs != NULL
1788190d7dceSmrg	    && new_fonts[fWBold].fs != NULL
1789d1603babSmrg	    && (!is_fixed_font(new_fonts[fWide].fs)
1790d1603babSmrg		|| !is_fixed_font(new_fonts[fWBold].fs)
1791d1603babSmrg		|| differing_widths(new_fonts[fWide].fs, new_fonts[fWBold].fs))) {
1792d522f475Smrg	    TRACE(("Proportional font! wide %d/%d, wide bold %d/%d\n",
1793d1603babSmrg		   new_fonts[fWide].fs->min_bounds.width,
1794d1603babSmrg		   new_fonts[fWide].fs->max_bounds.width,
1795d1603babSmrg		   new_fonts[fWBold].fs->min_bounds.width,
1796d1603babSmrg		   new_fonts[fWBold].fs->max_bounds.width));
1797d522f475Smrg	    proportional = True;
1798d522f475Smrg	}
1799d522f475Smrg    });
1800d522f475Smrg
1801d522f475Smrg    /* TODO : enforce that the width of the wide font is 2* the width
1802d522f475Smrg       of the narrow font */
1803d522f475Smrg
1804d522f475Smrg    /*
1805d522f475Smrg     * If we're switching fonts, free the old ones.  Otherwise we'll leak
1806d522f475Smrg     * the memory that is associated with the old fonts.  The
1807d522f475Smrg     * XLoadQueryFont call allocates a new XFontStruct.
1808d522f475Smrg     */
1809d522f475Smrg    xtermCloseFonts(xw, screen->fnts);
18109a64e1c5Smrg#if OPT_WIDE_ATTRS
18119a64e1c5Smrg    xtermCloseFonts(xw, screen->ifnts);
18129a64e1c5Smrg    screen->ifnts_ok = False;
18139a64e1c5Smrg#endif
1814d522f475Smrg
1815d1603babSmrg    xtermCopyFontInfo(GetNormalFont(screen, fNorm), &new_fonts[fNorm]);
1816d1603babSmrg    xtermCopyFontInfo(GetNormalFont(screen, fBold), &new_fonts[fBold]);
1817d522f475Smrg#if OPT_WIDE_CHARS
1818d1603babSmrg    xtermCopyFontInfo(GetNormalFont(screen, fWide), &new_fonts[fWide]);
1819d1603babSmrg    if (new_fonts[fWBold].fs == NULL)
1820d1603babSmrg	xtermCopyFontInfo(GetNormalFont(screen, fWide), &new_fonts[fWide]);
1821d1603babSmrg    xtermCopyFontInfo(GetNormalFont(screen, fWBold), &new_fonts[fWBold]);
1822d522f475Smrg#endif
1823d522f475Smrg
1824d4fba8b9Smrg    xtermUpdateFontGCs(xw, getNormalFont);
1825d522f475Smrg
182620d2c4d2Smrg#if OPT_BOX_CHARS
182720d2c4d2Smrg    screen->allow_packing = proportional;
182820d2c4d2Smrg    setupPackedFonts(xw);
182920d2c4d2Smrg#endif
183020d2c4d2Smrg    screen->fnt_prop = (Boolean) (proportional && !(screen->force_packed));
1831d4fba8b9Smrg    screen->fnt_boxes = 1;
1832d522f475Smrg
1833d522f475Smrg#if OPT_BOX_CHARS
1834d522f475Smrg    /*
18359a64e1c5Smrg     * xterm uses character positions 1-31 of a font for the line-drawing
1836d522f475Smrg     * characters.  Check that they are all present.  The null character
1837d522f475Smrg     * (0) is special, and is not used.
1838d522f475Smrg     */
1839d522f475Smrg#if OPT_RENDERFONT
1840d522f475Smrg    if (UsingRenderFont(xw)) {
1841d522f475Smrg	/*
1842d522f475Smrg	 * FIXME: we shouldn't even be here if we're using Xft.
1843d522f475Smrg	 */
1844d4fba8b9Smrg	screen->fnt_boxes = 0;
1845d522f475Smrg	TRACE(("assume Xft missing line-drawing chars\n"));
1846d522f475Smrg    } else
1847d522f475Smrg#endif
1848d522f475Smrg    {
1849d522f475Smrg	unsigned ch;
1850d522f475Smrg
18519a64e1c5Smrg#if OPT_TRACE
1852d1603babSmrg#define TRACE_MISS(index) show_font_misses(#index, &new_fonts[index])
18539a64e1c5Smrg	TRACE_MISS(fNorm);
18549a64e1c5Smrg	TRACE_MISS(fBold);
18559a64e1c5Smrg#if OPT_WIDE_CHARS
18569a64e1c5Smrg	TRACE_MISS(fWide);
18579a64e1c5Smrg	TRACE_MISS(fWBold);
18589a64e1c5Smrg#endif
18599a64e1c5Smrg#endif
1860fa3f02f3Smrg
1861d522f475Smrg#if OPT_WIDE_CHARS
1862d4fba8b9Smrg	if (screen->utf8_mode || screen->unicode_font) {
1863d4fba8b9Smrg	    UIntSet(screen->fnt_boxes, 2);
1864d4fba8b9Smrg	    for (ch = 1; ch < 32; ch++) {
1865d4fba8b9Smrg		unsigned n = dec2ucs(screen, ch);
1866980988aeSmrg		if (!is_UCS_SPECIAL(n)
1867d4fba8b9Smrg		    && (n != ch)
1868d4fba8b9Smrg		    && (screen->fnt_boxes & 2)) {
1869d1603babSmrg		    if (xtermMissingChar(n, &new_fonts[fNorm]) ||
1870d1603babSmrg			xtermMissingChar(n, &new_fonts[fBold])) {
1871d4fba8b9Smrg			UIntClr(screen->fnt_boxes, 2);
1872d4fba8b9Smrg			TRACE(("missing graphics character #%d, U+%04X\n",
1873d4fba8b9Smrg			       ch, n));
1874d4fba8b9Smrg			break;
1875d4fba8b9Smrg		    }
1876d4fba8b9Smrg		}
1877d522f475Smrg	    }
1878d4fba8b9Smrg	}
1879d522f475Smrg#endif
1880d4fba8b9Smrg
1881d4fba8b9Smrg	for (ch = 1; ch < 32; ch++) {
1882d1603babSmrg	    if (xtermMissingChar(ch, &new_fonts[fNorm])) {
1883d4fba8b9Smrg		TRACE(("missing normal char #%d\n", ch));
1884d4fba8b9Smrg		UIntClr(screen->fnt_boxes, 1);
1885d522f475Smrg		break;
1886d522f475Smrg	    }
1887d1603babSmrg	    if (xtermMissingChar(ch, &new_fonts[fBold])) {
1888d4fba8b9Smrg		TRACE(("missing bold   char #%d\n", ch));
1889d4fba8b9Smrg		UIntClr(screen->fnt_boxes, 1);
1890d522f475Smrg		break;
1891d522f475Smrg	    }
1892d522f475Smrg	}
1893d4fba8b9Smrg
1894d4fba8b9Smrg	TRACE(("Will %suse internal line-drawing characters (mode %d)\n",
1895d4fba8b9Smrg	       screen->fnt_boxes ? "not " : "",
1896d4fba8b9Smrg	       screen->fnt_boxes));
1897d522f475Smrg    }
1898d522f475Smrg#endif
1899d522f475Smrg
1900d522f475Smrg    if (screen->always_bold_mode) {
1901d522f475Smrg	screen->enbolden = screen->bold_mode;
1902d522f475Smrg    } else {
1903d522f475Smrg	screen->enbolden = screen->bold_mode
1904d1603babSmrg	    && ((new_fonts[fNorm].fs == new_fonts[fBold].fs)
1905d1603babSmrg		|| same_font_name(new_fnames.f_n, new_fnames.f_b));
1906d522f475Smrg    }
1907d522f475Smrg    TRACE(("Will %suse 1-pixel offset/overstrike to simulate bold\n",
1908d522f475Smrg	   screen->enbolden ? "" : "not "));
1909d522f475Smrg
1910d522f475Smrg    set_menu_font(False);
1911d522f475Smrg    screen->menu_font_number = fontnum;
1912d522f475Smrg    set_menu_font(True);
1913d522f475Smrg    if (tmpname) {		/* if setting escape or sel */
1914d522f475Smrg	if (screen->MenuFontName(fontnum))
19159a64e1c5Smrg	    FREE_STRING(screen->MenuFontName(fontnum));
1916d522f475Smrg	screen->MenuFontName(fontnum) = tmpname;
1917d522f475Smrg	if (fontnum == fontMenu_fontescape) {
191894644356Smrg	    update_font_escape();
1919d522f475Smrg	}
1920d522f475Smrg#if OPT_SHIFT_FONTS
1921d1603babSmrg	screen->menu_font_sizes[fontnum] = FontSize(new_fonts[fNorm].fs);
1922d522f475Smrg#endif
1923d522f475Smrg    }
1924d522f475Smrg    set_cursor_gcs(xw);
1925d522f475Smrg    xtermUpdateFontInfo(xw, doresize);
1926d522f475Smrg    TRACE(("Success Cgs - xtermLoadFont\n"));
1927fa3f02f3Smrg#if OPT_REPORT_FONTS
1928fa3f02f3Smrg    reportVTFontInfo(xw, fontnum);
19299a64e1c5Smrg#endif
19309a64e1c5Smrg    FREE_FNAME(f_n);
19319a64e1c5Smrg    FREE_FNAME(f_b);
19329a64e1c5Smrg#if OPT_WIDE_CHARS
19339a64e1c5Smrg    FREE_FNAME(f_w);
19349a64e1c5Smrg    FREE_FNAME(f_wb);
19359a64e1c5Smrg#endif
1936d1603babSmrg    if (new_fonts[fNorm].fn == new_fonts[fBold].fn) {
1937d1603babSmrg	free(new_fonts[fNorm].fn);
19389a64e1c5Smrg    } else {
1939d1603babSmrg	free(new_fonts[fNorm].fn);
1940d1603babSmrg	free(new_fonts[fBold].fn);
19419a64e1c5Smrg    }
19429a64e1c5Smrg#if OPT_WIDE_CHARS
1943d1603babSmrg    free(new_fonts[fWide].fn);
1944d1603babSmrg    free(new_fonts[fWBold].fn);
1945fa3f02f3Smrg#endif
1946dfb07bc7Smrg    xtermSetWinSize(xw);
1947d522f475Smrg    return 1;
1948d522f475Smrg
1949d522f475Smrg  bad:
1950d1603babSmrg    recovered = False;
1951d4fba8b9Smrg    free(tmpname);
19520bd37d32Smrg
19530bd37d32Smrg#if OPT_RENDERFONT
195494644356Smrg    if ((fontnum == fontMenu_fontsel) && (fontnum != screen->menu_font_number)) {
19559a64e1c5Smrg	int old_fontnum = screen->menu_font_number;
19569a64e1c5Smrg#if OPT_TOOLBAR
19579a64e1c5Smrg	SetItemSensitivity(fontMenuEntries[fontnum].widget, True);
19589a64e1c5Smrg#endif
19599a64e1c5Smrg	Bell(xw, XkbBI_MinorError, 0);
1960d1603babSmrg	new_fnames.f_n = screen->MenuFontName(old_fontnum);
1961d1603babSmrg	if (xtermLoadFont(xw, &new_fnames, doresize, old_fontnum))
1962d1603babSmrg	    recovered = True;
1963d1603babSmrg    } else if (x_strcasecmp(new_fnames.f_n, DEFFONT)
1964d1603babSmrg	       && x_strcasecmp(new_fnames.f_n, old_fonts[fNorm].fn)) {
1965d1603babSmrg	new_fnames.f_n = x_strdup(old_fonts[fNorm].fn);
1966d1603babSmrg	TRACE(("...recovering from failed font-load\n"));
1967d1603babSmrg	if (xtermLoadFont(xw, &new_fnames, doresize, fontnum)) {
1968d1603babSmrg	    recovered = True;
196994644356Smrg	    if (fontnum != fontMenu_fontsel) {
197094644356Smrg		SetItemSensitivity(fontMenuEntries[fontnum].widget,
197194644356Smrg				   UsingRenderFont(xw));
197294644356Smrg	    }
19730bd37d32Smrg	    TRACE(("...recovered size %dx%d\n",
19740bd37d32Smrg		   FontHeight(screen),
19750bd37d32Smrg		   FontWidth(screen)));
19760bd37d32Smrg	}
19770bd37d32Smrg    }
19780bd37d32Smrg#endif
1979d1603babSmrg    if (!recovered) {
1980d1603babSmrg	releaseWindowGCs(xw, win);
1981d1603babSmrg	xtermCloseFonts(xw, new_fonts);
1982d1603babSmrg	TRACE(("Fail Cgs - xtermLoadFont\n"));
1983d1603babSmrg	code = 0;
1984d1603babSmrg    }
1985d1603babSmrg    return code;
1986d522f475Smrg}
1987d522f475Smrg
19889a64e1c5Smrg#if OPT_WIDE_ATTRS
19899a64e1c5Smrg/*
19909a64e1c5Smrg * (Attempt to) load matching italics for the current normal/bold/etc fonts.
19919a64e1c5Smrg * If the attempt fails for a given style, use the non-italic font.
19929a64e1c5Smrg */
19939a64e1c5Smrgvoid
19949a64e1c5SmrgxtermLoadItalics(XtermWidget xw)
19959a64e1c5Smrg{
19969a64e1c5Smrg    TScreen *screen = TScreenOf(xw);
19979a64e1c5Smrg
1998c48a5815Smrg    if (UseItalicFont(screen) && !screen->ifnts_ok) {
1999037a25ddSmrg	int n;
2000dfb07bc7Smrg	FontNameProperties *fp;
2001dfb07bc7Smrg	XTermFonts *data;
2002037a25ddSmrg
20039a64e1c5Smrg	screen->ifnts_ok = True;
20049a64e1c5Smrg	for (n = 0; n < fMAX; ++n) {
2005dfb07bc7Smrg	    switch (n) {
2006dfb07bc7Smrg	    case fNorm:
2007dfb07bc7Smrg		/* FALLTHRU */
2008dfb07bc7Smrg	    case fBold:
2009dfb07bc7Smrg		/* FALLTHRU */
2010dfb07bc7Smrg#if OPT_WIDE_CHARS
2011dfb07bc7Smrg	    case fWide:
2012dfb07bc7Smrg		/* FALLTHRU */
2013dfb07bc7Smrg	    case fWBold:
2014dfb07bc7Smrg#endif
2015dfb07bc7Smrg		/* FALLTHRU */
2016dfb07bc7Smrg		data = getItalicFont(screen, n);
2017037a25ddSmrg
2018dfb07bc7Smrg		/*
2019dfb07bc7Smrg		 * FIXME - need to handle font-leaks
2020dfb07bc7Smrg		 */
2021190d7dceSmrg		data->fs = NULL;
2022190d7dceSmrg		if (getNormalFont(screen, n)->fs != NULL &&
2023dfb07bc7Smrg		    (fp = get_font_name_props(screen->display,
2024dfb07bc7Smrg					      getNormalFont(screen, n)->fs,
2025190d7dceSmrg					      NULL)) != NULL) {
2026dfb07bc7Smrg		    if (!open_italic_font(xw, n, fp, data)) {
2027dfb07bc7Smrg			if (n > 0) {
2028dfb07bc7Smrg			    xtermCopyFontInfo(data,
2029dfb07bc7Smrg					      getItalicFont(screen, n - 1));
2030dfb07bc7Smrg			} else {
2031dfb07bc7Smrg			    xtermOpenFont(xw,
2032dfb07bc7Smrg					  getNormalFont(screen, n)->fn,
2033d1603babSmrg					  data, NULL, False);
20349a64e1c5Smrg			}
20359a64e1c5Smrg		    }
20369a64e1c5Smrg		}
2037dfb07bc7Smrg		break;
20389a64e1c5Smrg	    }
20399a64e1c5Smrg	}
20409a64e1c5Smrg    }
20419a64e1c5Smrg}
20429a64e1c5Smrg#endif
20439a64e1c5Smrg
2044d522f475Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
2045d522f475Smrg/*
2046d522f475Smrg * Collect font-names that we can modify with the load-vt-fonts() action.
2047d522f475Smrg */
2048dfb07bc7Smrg#define MERGE_SUBFONT(dst,src,name) \
2049492d43a5Smrg	if (IsEmpty(dst.name)) { \
2050dfb07bc7Smrg	    TRACE(("MERGE_SUBFONT " #dst "." #name " merge \"%s\"\n", NonNull(src.name))); \
20519a64e1c5Smrg	    dst.name = x_strdup(src.name); \
2052d522f475Smrg	} else { \
2053dfb07bc7Smrg	    TRACE(("MERGE_SUBFONT " #dst "." #name " found \"%s\"\n", NonNull(dst.name))); \
2054dfb07bc7Smrg	}
2055dfb07bc7Smrg#define MERGE_SUBLIST(dst,src,name) \
2056d1603babSmrg	if (dst.fonts.x11.name == NULL) \
2057d1603babSmrg	    dst.fonts.x11.name = TypeCalloc(char *); \
2058dfb07bc7Smrg	if (merge_sublist(&(dst.fonts.x11.name), src.fonts.x11.name)) { \
2059dfb07bc7Smrg	    TRACE(("MERGE_SUBLIST " #dst "." #name " merge \"%s\"\n", src.fonts.x11.name[0])); \
2060dfb07bc7Smrg	} else { \
2061dfb07bc7Smrg	    TRACE(("MERGE_SUBLIST " #dst "." #name " found \"%s\"\n", dst.fonts.x11.name[0])); \
2062d522f475Smrg	}
2063d522f475Smrg
2064dfb07bc7Smrg#define INFER_SUBFONT(dst,src,name) \
2065e39b573cSmrg	if (IsEmpty(dst.name)) { \
2066e39b573cSmrg	    TRACE(("INFER_SUBFONT " #dst "." #name " will infer\n")); \
2067e39b573cSmrg	    dst.name = x_strdup(""); \
2068e39b573cSmrg	} else { \
2069dfb07bc7Smrg	    TRACE(("INFER_SUBFONT " #dst "." #name " found \"%s\"\n", NonNull(dst.name))); \
2070e39b573cSmrg	}
2071e39b573cSmrg
20729a64e1c5Smrg#define FREE_MENU_FONTS(dst) \
20739a64e1c5Smrg	TRACE(("FREE_MENU_FONTS " #dst "\n")); \
20749a64e1c5Smrg	for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \
20759a64e1c5Smrg	    for (m = 0; m < fMAX; ++m) { \
20769a64e1c5Smrg		FREE_STRING(dst.menu_font_names[n][m]); \
2077190d7dceSmrg		dst.menu_font_names[n][m] = NULL; \
20789a64e1c5Smrg	    } \
20799a64e1c5Smrg	}
20809a64e1c5Smrg
2081dfb07bc7Smrg#define COPY_MENU_FONTS(dst,src) \
2082d522f475Smrg	TRACE(("COPY_MENU_FONTS " #src " to " #dst "\n")); \
2083d522f475Smrg	for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \
2084d522f475Smrg	    for (m = 0; m < fMAX; ++m) { \
20859a64e1c5Smrg		FREE_STRING(dst.menu_font_names[n][m]); \
2086492d43a5Smrg		dst.menu_font_names[n][m] = x_strdup(src.menu_font_names[n][m]); \
2087d522f475Smrg	    } \
208894644356Smrg	    TRACE((".. " #dst ".menu_fonts_names[%d] = %s\n", n, NonNull(dst.menu_font_names[n][fNorm]))); \
2089e39b573cSmrg	}
2090e39b573cSmrg
20919a64e1c5Smrg#define COPY_DEFAULT_FONTS(target, source) \
2092dfb07bc7Smrg	TRACE(("COPY_DEFAULT_FONTS " #source " to " #target "\n")); \
20939a64e1c5Smrg	xtermCopyVTFontNames(&target.default_font, &source.default_font)
20949a64e1c5Smrg
2095dfb07bc7Smrg#define COPY_X11_FONTLISTS(target, source) \
2096dfb07bc7Smrg	TRACE(("COPY_X11_FONTLISTS " #source " to " #target "\n")); \
2097dfb07bc7Smrg	xtermCopyFontLists(xw, &target.fonts.x11, &source.fonts.x11)
2098dfb07bc7Smrg
2099dfb07bc7Smrgstatic void
2100dfb07bc7SmrgxtermCopyVTFontNames(VTFontNames * target, VTFontNames * source)
2101dfb07bc7Smrg{
2102dfb07bc7Smrg#define COPY_IT(name,field) \
2103dfb07bc7Smrg    TRACE((".. "#name" = %s\n", NonNull(source->field))); \
2104dfb07bc7Smrg    free(target->field); \
2105dfb07bc7Smrg    target->field = x_strdup(source->field)
2106dfb07bc7Smrg
2107dfb07bc7Smrg    TRACE(("xtermCopyVTFontNames\n"));
2108dfb07bc7Smrg
2109dfb07bc7Smrg    COPY_IT(font, f_n);
2110dfb07bc7Smrg    COPY_IT(boldFont, f_b);
2111dfb07bc7Smrg
2112dfb07bc7Smrg#if OPT_WIDE_CHARS
2113dfb07bc7Smrg    COPY_IT(wideFont, f_w);
2114dfb07bc7Smrg    COPY_IT(wideBoldFont, f_wb);
2115dfb07bc7Smrg#endif
2116dfb07bc7Smrg#undef COPY_IT
2117dfb07bc7Smrg}
2118dfb07bc7Smrg
21199a64e1c5Smrgstatic void
2120dfb07bc7SmrgxtermCopyFontLists(XtermWidget xw, VTFontList * target, VTFontList * source)
21219a64e1c5Smrg{
2122dfb07bc7Smrg#define COPY_IT(name,field) \
2123dfb07bc7Smrg    copyFontList(&(target->field), source->field); \
2124dfb07bc7Smrg    TRACE_ARGV(".. " #name, source->field)
2125dfb07bc7Smrg
2126dfb07bc7Smrg    (void) xw;
2127dfb07bc7Smrg    TRACE(("xtermCopyFontLists %s ->%s\n",
2128dfb07bc7Smrg	   whichFontList(xw, source),
2129dfb07bc7Smrg	   whichFontList(xw, target)));
2130dfb07bc7Smrg
2131dfb07bc7Smrg    COPY_IT(font, list_n);
2132dfb07bc7Smrg    COPY_IT(fontBold, list_b);
2133dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
2134dfb07bc7Smrg    COPY_IT(fontItal, list_i);
2135d4fba8b9Smrg    COPY_IT(fontBtal, list_bi);
2136dfb07bc7Smrg#endif
21379a64e1c5Smrg#if OPT_WIDE_CHARS
2138dfb07bc7Smrg    COPY_IT(wideFont, list_w);
2139dfb07bc7Smrg    COPY_IT(wideBoldFont, list_wb);
2140dfb07bc7Smrg    COPY_IT(wideItalFont, list_wi);
2141d4fba8b9Smrg    COPY_IT(wideBtalFont, list_wbi);
21429a64e1c5Smrg#endif
2143dfb07bc7Smrg#undef COPY_IT
21449a64e1c5Smrg}
21459a64e1c5Smrg
2146e39b573cSmrgvoid
2147e39b573cSmrgxtermSaveVTFonts(XtermWidget xw)
2148e39b573cSmrg{
2149e39b573cSmrg    TScreen *screen = TScreenOf(xw);
2150e39b573cSmrg    Cardinal n, m;
2151e39b573cSmrg
2152e39b573cSmrg    if (!screen->savedVTFonts) {
2153e39b573cSmrg
2154e39b573cSmrg	screen->savedVTFonts = True;
2155e39b573cSmrg	TRACE(("xtermSaveVTFonts saving original\n"));
21569a64e1c5Smrg	COPY_DEFAULT_FONTS(screen->cacheVTFonts, xw->misc);
2157dfb07bc7Smrg	COPY_X11_FONTLISTS(screen->cacheVTFonts, xw->work);
2158dfb07bc7Smrg	COPY_MENU_FONTS(screen->cacheVTFonts, xw->screen);
2159e39b573cSmrg    }
2160e39b573cSmrg}
2161e39b573cSmrg
2162e39b573cSmrg#define SAME_STRING(x,y) ((x) == (y) || ((x) && (y) && !strcmp(x, y)))
2163e39b573cSmrg#define SAME_MEMBER(n)   SAME_STRING(a->n, b->n)
2164e39b573cSmrg
2165e39b573cSmrgstatic Boolean
2166e39b573cSmrgsameSubResources(SubResourceRec * a, SubResourceRec * b)
2167e39b573cSmrg{
2168e39b573cSmrg    Boolean result = True;
2169e39b573cSmrg
2170e39b573cSmrg    if (!SAME_MEMBER(default_font.f_n)
2171e39b573cSmrg	|| !SAME_MEMBER(default_font.f_b)
21720bd37d32Smrg#if OPT_WIDE_CHARS
2173e39b573cSmrg	|| !SAME_MEMBER(default_font.f_w)
21740bd37d32Smrg	|| !SAME_MEMBER(default_font.f_wb)
21750bd37d32Smrg#endif
21760bd37d32Smrg	) {
2177e39b573cSmrg	TRACE(("sameSubResources: default_font differs\n"));
2178e39b573cSmrg	result = False;
2179e39b573cSmrg    } else {
2180037a25ddSmrg	int n;
2181037a25ddSmrg
2182e39b573cSmrg	for (n = 0; n < NMENUFONTS; ++n) {
2183e39b573cSmrg	    if (!SAME_MEMBER(menu_font_names[n][fNorm])) {
2184e39b573cSmrg		TRACE(("sameSubResources: menu_font_names[%d] differs\n", n));
2185e39b573cSmrg		result = False;
2186e39b573cSmrg		break;
2187e39b573cSmrg	    }
2188d522f475Smrg	}
2189e39b573cSmrg    }
2190e39b573cSmrg
2191e39b573cSmrg    return result;
2192e39b573cSmrg}
2193d522f475Smrg
2194d522f475Smrg/*
2195d522f475Smrg * Load the "VT" font names from the given subresource name/class.  These
2196d522f475Smrg * correspond to the VT100 resources.
2197d522f475Smrg */
2198d522f475Smrgstatic Bool
219920d2c4d2SmrgxtermLoadVTFonts(XtermWidget xw, String myName, String myClass)
2200d522f475Smrg{
2201e39b573cSmrg    SubResourceRec subresourceRec;
2202e39b573cSmrg    SubResourceRec referenceRec;
2203d522f475Smrg
2204d522f475Smrg    /*
2205d522f475Smrg     * These are duplicates of the VT100 font resources, but with a special
2206d522f475Smrg     * application/classname passed in to distinguish them.
2207d522f475Smrg     */
2208d522f475Smrg    static XtResource font_resources[] =
2209d522f475Smrg    {
2210d522f475Smrg	Sres(XtNfont, XtCFont, default_font.f_n, DEFFONT),
2211d522f475Smrg	Sres(XtNboldFont, XtCBoldFont, default_font.f_b, DEFBOLDFONT),
2212d522f475Smrg#if OPT_WIDE_CHARS
2213d522f475Smrg	Sres(XtNwideFont, XtCWideFont, default_font.f_w, DEFWIDEFONT),
2214d522f475Smrg	Sres(XtNwideBoldFont, XtCWideBoldFont, default_font.f_wb, DEFWIDEBOLDFONT),
2215d522f475Smrg#endif
2216d522f475Smrg	Sres(XtNfont1, XtCFont1, MenuFontName(fontMenu_font1), NULL),
2217d522f475Smrg	Sres(XtNfont2, XtCFont2, MenuFontName(fontMenu_font2), NULL),
2218d522f475Smrg	Sres(XtNfont3, XtCFont3, MenuFontName(fontMenu_font3), NULL),
2219d522f475Smrg	Sres(XtNfont4, XtCFont4, MenuFontName(fontMenu_font4), NULL),
2220d522f475Smrg	Sres(XtNfont5, XtCFont5, MenuFontName(fontMenu_font5), NULL),
2221d522f475Smrg	Sres(XtNfont6, XtCFont6, MenuFontName(fontMenu_font6), NULL),
2222d4fba8b9Smrg	Sres(XtNfont7, XtCFont7, MenuFontName(fontMenu_font7), NULL),
2223d522f475Smrg    };
2224d522f475Smrg    Cardinal n, m;
2225d522f475Smrg    Bool status = True;
2226956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2227d522f475Smrg
2228e39b573cSmrg    TRACE(("called xtermLoadVTFonts(name=%s, class=%s)\n",
2229e39b573cSmrg	   NonNull(myName), NonNull(myClass)));
2230d522f475Smrg
2231e39b573cSmrg    xtermSaveVTFonts(xw);
2232d522f475Smrg
2233492d43a5Smrg    if (IsEmpty(myName)) {
2234d522f475Smrg	TRACE(("xtermLoadVTFonts restoring original\n"));
22359a64e1c5Smrg	COPY_DEFAULT_FONTS(xw->misc, screen->cacheVTFonts);
2236dfb07bc7Smrg	COPY_X11_FONTLISTS(xw->work, screen->cacheVTFonts);
22379a64e1c5Smrg	FREE_MENU_FONTS(xw->screen);
2238dfb07bc7Smrg	COPY_MENU_FONTS(xw->screen, screen->cacheVTFonts);
2239d522f475Smrg    } else {
2240d522f475Smrg	TRACE(("xtermLoadVTFonts(%s, %s)\n", myName, myClass));
2241d522f475Smrg
2242e39b573cSmrg	memset(&referenceRec, 0, sizeof(referenceRec));
2243d522f475Smrg	memset(&subresourceRec, 0, sizeof(subresourceRec));
2244956cc18dSsnj	XtGetSubresources((Widget) xw, (XtPointer) &subresourceRec,
2245d522f475Smrg			  myName, myClass,
2246d522f475Smrg			  font_resources,
2247d522f475Smrg			  (Cardinal) XtNumber(font_resources),
2248d522f475Smrg			  NULL, (Cardinal) 0);
2249d522f475Smrg
2250e39b573cSmrg	/*
2251e39b573cSmrg	 * XtGetSubresources returns no status, so we compare the returned
2252e39b573cSmrg	 * data against a zero'd struct to see if any data is returned.
2253e39b573cSmrg	 */
2254e39b573cSmrg	if (memcmp(&referenceRec, &subresourceRec, sizeof(referenceRec))
2255e39b573cSmrg	    && !sameSubResources(&(screen->cacheVTFonts), &subresourceRec)) {
2256e39b573cSmrg
2257e39b573cSmrg	    screen->mergedVTFonts = True;
2258d522f475Smrg
22599a64e1c5Smrg	    /*
22609a64e1c5Smrg	     * To make it simple, reallocate the strings returned by
22619a64e1c5Smrg	     * XtGetSubresources.  We can free our own strings, but not theirs.
22629a64e1c5Smrg	     */
22639a64e1c5Smrg	    ALLOC_STRING(subresourceRec.default_font.f_n);
22649a64e1c5Smrg	    ALLOC_STRING(subresourceRec.default_font.f_b);
22659a64e1c5Smrg#if OPT_WIDE_CHARS
22669a64e1c5Smrg	    ALLOC_STRING(subresourceRec.default_font.f_w);
22679a64e1c5Smrg	    ALLOC_STRING(subresourceRec.default_font.f_wb);
22689a64e1c5Smrg#endif
22699a64e1c5Smrg	    for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) {
22709a64e1c5Smrg		ALLOC_STRING(subresourceRec.MenuFontName(n));
22719a64e1c5Smrg	    }
22729a64e1c5Smrg
2273dfb07bc7Smrg	    /*
2274dfb07bc7Smrg	     * Now, save the string to a font-list for consistency
2275dfb07bc7Smrg	     */
2276dfb07bc7Smrg#define ALLOC_SUBLIST(which,field) \
2277d1603babSmrg	    if (subresourceRec.default_font.field != NULL) { \
2278d1603babSmrg		char *blob = x_strdup(subresourceRec.default_font.field); \
2279d1603babSmrg		char *base; \
2280d1603babSmrg		for (base = blob; ; base = NULL) { \
2281d1603babSmrg		    char *item = strtok(base, ","); \
2282d1603babSmrg		    if (item == NULL) \
2283d1603babSmrg			break; \
2284d1603babSmrg		    save2FontList(xw, "cached", \
2285d1603babSmrg				  &(subresourceRec.fonts), \
2286d1603babSmrg				  which, \
2287d1603babSmrg				  item, False, False); \
2288d1603babSmrg		} \
2289d1603babSmrg		free(blob); \
2290d1603babSmrg	    }
2291dfb07bc7Smrg
2292dfb07bc7Smrg	    ALLOC_SUBLIST(fNorm, f_n);
2293dfb07bc7Smrg	    ALLOC_SUBLIST(fBold, f_b);
2294dfb07bc7Smrg#if OPT_WIDE_CHARS
2295dfb07bc7Smrg	    ALLOC_SUBLIST(fWide, f_w);
2296dfb07bc7Smrg	    ALLOC_SUBLIST(fWBold, f_wb);
2297dfb07bc7Smrg#endif
2298dfb07bc7Smrg
2299d522f475Smrg	    /*
2300d522f475Smrg	     * If a particular resource value was not found, use the original.
2301d522f475Smrg	     */
2302dfb07bc7Smrg	    MERGE_SUBFONT(subresourceRec, xw->misc, default_font.f_n);
2303dfb07bc7Smrg	    INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_b);
2304dfb07bc7Smrg	    MERGE_SUBLIST(subresourceRec, xw->work, list_n);
2305dfb07bc7Smrg	    MERGE_SUBLIST(subresourceRec, xw->work, list_b);
2306d522f475Smrg#if OPT_WIDE_CHARS
2307dfb07bc7Smrg	    INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_w);
2308dfb07bc7Smrg	    INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_wb);
2309dfb07bc7Smrg	    MERGE_SUBLIST(subresourceRec, xw->work, list_w);
2310dfb07bc7Smrg	    MERGE_SUBLIST(subresourceRec, xw->work, list_wb);
2311d522f475Smrg#endif
23129a64e1c5Smrg	    for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) {
2313dfb07bc7Smrg		MERGE_SUBFONT(subresourceRec, xw->screen, MenuFontName(n));
23149a64e1c5Smrg	    }
2315d522f475Smrg
2316d522f475Smrg	    /*
2317d522f475Smrg	     * Finally, copy the subresource data to the widget.
2318d522f475Smrg	     */
23199a64e1c5Smrg	    COPY_DEFAULT_FONTS(xw->misc, subresourceRec);
2320dfb07bc7Smrg	    COPY_X11_FONTLISTS(xw->work, subresourceRec);
23219a64e1c5Smrg	    FREE_MENU_FONTS(xw->screen);
2322dfb07bc7Smrg	    COPY_MENU_FONTS(xw->screen, subresourceRec);
23239a64e1c5Smrg
23249a64e1c5Smrg	    FREE_STRING(screen->MenuFontName(fontMenu_default));
23259a64e1c5Smrg	    FREE_STRING(screen->menu_font_names[0][fBold]);
2326dfb07bc7Smrg	    screen->MenuFontName(fontMenu_default) = x_strdup(DefaultFontN(xw));
2327dfb07bc7Smrg	    screen->menu_font_names[0][fBold] = x_strdup(DefaultFontB(xw));
2328d522f475Smrg#if OPT_WIDE_CHARS
23299a64e1c5Smrg	    FREE_STRING(screen->menu_font_names[0][fWide]);
23309a64e1c5Smrg	    FREE_STRING(screen->menu_font_names[0][fWBold]);
2331dfb07bc7Smrg	    screen->menu_font_names[0][fWide] = x_strdup(DefaultFontW(xw));
2332dfb07bc7Smrg	    screen->menu_font_names[0][fWBold] = x_strdup(DefaultFontWB(xw));
2333d522f475Smrg#endif
23349a64e1c5Smrg	    /*
23359a64e1c5Smrg	     * And remove our copies of strings.
23369a64e1c5Smrg	     */
23379a64e1c5Smrg	    FREE_STRING(subresourceRec.default_font.f_n);
23389a64e1c5Smrg	    FREE_STRING(subresourceRec.default_font.f_b);
23399a64e1c5Smrg#if OPT_WIDE_CHARS
23409a64e1c5Smrg	    FREE_STRING(subresourceRec.default_font.f_w);
23419a64e1c5Smrg	    FREE_STRING(subresourceRec.default_font.f_wb);
23429a64e1c5Smrg#endif
23439a64e1c5Smrg	    for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) {
23449a64e1c5Smrg		FREE_STRING(subresourceRec.MenuFontName(n));
23459a64e1c5Smrg	    }
2346d522f475Smrg	} else {
2347d522f475Smrg	    TRACE(("...no resources found\n"));
2348d522f475Smrg	    status = False;
2349d522f475Smrg	}
2350d522f475Smrg    }
2351dfb07bc7Smrg    TRACE((".. xtermLoadVTFonts: %d\n", status));
2352d522f475Smrg    return status;
2353d522f475Smrg}
2354d522f475Smrg
2355d522f475Smrg#if OPT_WIDE_CHARS
2356d522f475Smrgstatic Bool
23579a64e1c5SmrgisWideFont(XFontStruct *fp, const char *tag, Bool nullOk)
2358d522f475Smrg{
2359d522f475Smrg    Bool result = False;
2360d522f475Smrg
2361d522f475Smrg    (void) tag;
2362d522f475Smrg    if (okFont(fp)) {
2363d522f475Smrg	unsigned count = countGlyphs(fp);
2364d522f475Smrg	TRACE(("isWideFont(%s) found %d cells\n", tag, count));
2365d522f475Smrg	result = (count > 256) ? True : False;
2366d522f475Smrg    } else {
2367d522f475Smrg	result = nullOk;
2368d522f475Smrg    }
2369d522f475Smrg    return result;
2370d522f475Smrg}
2371d522f475Smrg
2372d522f475Smrg/*
2373d522f475Smrg * If the current fonts are not wide, load the UTF8 fonts.
2374d522f475Smrg *
2375d522f475Smrg * Called during initialization (for wide-character mode), the fonts have not
2376d522f475Smrg * been setup, so we pass nullOk=True to isWideFont().
2377d522f475Smrg *
2378d522f475Smrg * Called after initialization, e.g., in response to the UTF-8 menu entry
2379d522f475Smrg * (starting from narrow character mode), it checks if the fonts are not wide.
2380d522f475Smrg */
2381d522f475SmrgBool
2382d522f475SmrgxtermLoadWideFonts(XtermWidget xw, Bool nullOk)
2383d522f475Smrg{
2384956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2385d522f475Smrg    Bool result;
2386d522f475Smrg
2387d4fba8b9Smrg    if (EmptyFont(GetNormalFont(screen, fWide)->fs)) {
2388d4fba8b9Smrg	result = (isWideFont(GetNormalFont(screen, fNorm)->fs, "normal", nullOk)
2389d4fba8b9Smrg		  && isWideFont(GetNormalFont(screen, fBold)->fs, "bold", nullOk));
2390d522f475Smrg    } else {
2391d4fba8b9Smrg	result = (isWideFont(GetNormalFont(screen, fWide)->fs, "wide", nullOk)
2392d4fba8b9Smrg		  && isWideFont(GetNormalFont(screen, fWBold)->fs,
2393dfb07bc7Smrg				"wide-bold", nullOk));
2394d522f475Smrg	if (result && !screen->utf8_latin1) {
2395d4fba8b9Smrg	    result = (isWideFont(GetNormalFont(screen, fNorm)->fs, "normal", nullOk)
2396d4fba8b9Smrg		      && isWideFont(GetNormalFont(screen, fBold)->fs,
2397dfb07bc7Smrg				    "bold", nullOk));
2398d522f475Smrg	}
2399d522f475Smrg    }
2400d522f475Smrg    if (!result) {
2401d522f475Smrg	TRACE(("current fonts are not all wide%s\n", nullOk ? " nullOk" : ""));
2402e39b573cSmrg	result = xtermLoadVTFonts(xw, XtNutf8Fonts, XtCUtf8Fonts);
2403d522f475Smrg    }
2404d522f475Smrg    TRACE(("xtermLoadWideFonts:%d\n", result));
2405d522f475Smrg    return result;
2406d522f475Smrg}
2407d522f475Smrg#endif /* OPT_WIDE_CHARS */
2408d522f475Smrg
2409d522f475Smrg/*
2410d522f475Smrg * Restore the default fonts, i.e., if we had switched to wide-fonts.
2411d522f475Smrg */
2412d522f475SmrgBool
2413956cc18dSsnjxtermLoadDefaultFonts(XtermWidget xw)
2414d522f475Smrg{
2415d522f475Smrg    Bool result;
2416956cc18dSsnj    result = xtermLoadVTFonts(xw, NULL, NULL);
2417d522f475Smrg    TRACE(("xtermLoadDefaultFonts:%d\n", result));
2418d522f475Smrg    return result;
2419d522f475Smrg}
2420d522f475Smrg#endif /* OPT_LOAD_VTFONTS || OPT_WIDE_CHARS */
2421d522f475Smrg
2422d522f475Smrg#if OPT_LOAD_VTFONTS
2423d522f475Smrgvoid
2424d522f475SmrgHandleLoadVTFonts(Widget w,
24259a64e1c5Smrg		  XEvent *event GCC_UNUSED,
2426d4fba8b9Smrg		  String *params,
2427d4fba8b9Smrg		  Cardinal *param_count)
2428d522f475Smrg{
2429956cc18dSsnj    XtermWidget xw;
2430956cc18dSsnj
2431190d7dceSmrg    if ((xw = getXtermWidget(w)) != NULL) {
2432037a25ddSmrg	static char empty[] = "";	/* appease strict compilers */
2433037a25ddSmrg
2434956cc18dSsnj	TScreen *screen = TScreenOf(xw);
2435492d43a5Smrg	char name_buf[80];
2436492d43a5Smrg	String name = (String) ((*param_count > 0) ? params[0] : empty);
243794644356Smrg	char *myName = MyStackAlloc(strlen(name) + 1, name_buf);
2438d522f475Smrg
2439d522f475Smrg	TRACE(("HandleLoadVTFonts(%d)\n", *param_count));
2440190d7dceSmrg	if (myName != NULL) {
2441037a25ddSmrg	    char class_buf[80];
244294644356Smrg	    String convert = (String) ((*param_count > 1) ? params[1] : myName);
244394644356Smrg	    char *myClass = MyStackAlloc(strlen(convert) + 1, class_buf);
244494644356Smrg
244594644356Smrg	    strcpy(myName, name);
2446190d7dceSmrg	    if (myClass != NULL) {
244794644356Smrg		strcpy(myClass, convert);
244894644356Smrg		if (*param_count == 1)
244994644356Smrg		    myClass[0] = x_toupper(myClass[0]);
245094644356Smrg
245194644356Smrg		if (xtermLoadVTFonts(xw, myName, myClass)) {
2452037a25ddSmrg		    int n;
245394644356Smrg		    /*
245494644356Smrg		     * When switching fonts, try to preserve the font-menu
245594644356Smrg		     * selection, since it is less surprising to do that (if
245694644356Smrg		     * the font-switching can be undone) than to switch to
245794644356Smrg		     * "Default".
245894644356Smrg		     */
245994644356Smrg		    int font_number = screen->menu_font_number;
246094644356Smrg		    if (font_number > fontMenu_lastBuiltin)
246194644356Smrg			font_number = fontMenu_lastBuiltin;
246294644356Smrg		    for (n = 0; n < NMENUFONTS; ++n) {
246394644356Smrg			screen->menu_font_sizes[n] = 0;
246494644356Smrg		    }
2465dfb07bc7Smrg		    if (font_number == fontMenu_default) {
2466dfb07bc7Smrg			SetVTFont(xw, font_number, True, defaultVTFontNames(xw));
2467dfb07bc7Smrg		    } else {
2468dfb07bc7Smrg			SetVTFont(xw, font_number, True, NULL);
2469dfb07bc7Smrg		    }
247094644356Smrg		}
247194644356Smrg		MyStackFree(myClass, class_buf);
24729a64e1c5Smrg	    }
247394644356Smrg	    MyStackFree(myName, name_buf);
2474d522f475Smrg	}
2475d522f475Smrg    }
2476d522f475Smrg}
2477d522f475Smrg#endif /* OPT_LOAD_VTFONTS */
2478d522f475Smrg
2479d522f475Smrg/*
2480d522f475Smrg * Set the limits for the box that outlines the cursor.
2481d522f475Smrg */
2482d522f475Smrgvoid
2483fa3f02f3SmrgxtermSetCursorBox(TScreen *screen)
2484d522f475Smrg{
2485d522f475Smrg    static XPoint VTbox[NBOX];
2486d522f475Smrg    XPoint *vp;
24872eaa94a1Schristos    int fw = FontWidth(screen) - 1;
24882eaa94a1Schristos    int fh = FontHeight(screen) - 1;
2489d1603babSmrg    int ww = isCursorBar(screen) ? fw / 8 : fw;
2490d1603babSmrg    int hh = isCursorUnderline(screen) ? fh / 8 : fh;
2491d1603babSmrg    if (ww < 2)
2492d1603babSmrg	ww = 2;
2493d1603babSmrg    if (hh < 2)
2494d1603babSmrg	hh = 2;
2495d522f475Smrg
2496d522f475Smrg    vp = &VTbox[1];
24970bd37d32Smrg    (vp++)->x = (short) ww;
24982eaa94a1Schristos    (vp++)->y = (short) hh;
24990bd37d32Smrg    (vp++)->x = (short) -ww;
25002eaa94a1Schristos    vp->y = (short) -hh;
25012eaa94a1Schristos
2502d522f475Smrg    screen->box = VTbox;
2503d522f475Smrg}
2504d522f475Smrg
2505d4fba8b9Smrg#if OPT_RENDERFONT
2506d4fba8b9Smrg
2507d1603babSmrg#define CACHE_XFT(data) if (XftFp(data) != NULL) {\
2508d1603babSmrg	    int err = checkXftWidth(xw, data);\
2509d4fba8b9Smrg	    TRACE(("Xft metrics %s[%d] = %d (%d,%d)%s advance %d, actual %d%s%s\n",\
2510d1603babSmrg		#data,\
2511d4fba8b9Smrg		fontnum,\
2512d1603babSmrg		XftFp(data)->height,\
2513d1603babSmrg		XftFp(data)->ascent,\
2514d1603babSmrg		XftFp(data)->descent,\
2515d1603babSmrg		((XftFp(data)->ascent + XftFp(data)->descent) > XftFp(data)->height ? "*" : ""),\
2516d1603babSmrg		XftFp(data)->max_advance_width,\
2517d1603babSmrg		data->font_info.min_width,\
2518d1603babSmrg		data->font_info.mixed ? " mixed" : "",\
2519d4fba8b9Smrg		err ? " ERROR" : ""));\
2520d4fba8b9Smrg	    if (err) {\
2521d1603babSmrg		xtermCloseXft(screen, data);\
2522d1603babSmrg		memset((data), 0, sizeof(*data));\
2523d4fba8b9Smrg		failed += err;\
2524d4fba8b9Smrg	    }\
2525d522f475Smrg	}
2526d522f475Smrg
2527dfb07bc7Smrg#if OPT_REPORT_FONTS
252820d2c4d2Smrgstatic FcChar32
25299a64e1c5SmrgxtermXftFirstChar(XftFont *xft)
253020d2c4d2Smrg{
253120d2c4d2Smrg    FcChar32 map[FC_CHARSET_MAP_SIZE];
253220d2c4d2Smrg    FcChar32 next;
253320d2c4d2Smrg    FcChar32 first;
253420d2c4d2Smrg    int i;
253520d2c4d2Smrg
253620d2c4d2Smrg    first = FcCharSetFirstPage(xft->charset, map, &next);
25379a64e1c5Smrg    for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) {
253820d2c4d2Smrg	if (map[i]) {
253920d2c4d2Smrg	    FcChar32 bits = map[i];
2540fa3f02f3Smrg	    first += (FcChar32) i *32;
254120d2c4d2Smrg	    while (!(bits & 0x1)) {
254220d2c4d2Smrg		bits >>= 1;
254320d2c4d2Smrg		first++;
254420d2c4d2Smrg	    }
254520d2c4d2Smrg	    break;
254620d2c4d2Smrg	}
25479a64e1c5Smrg    }
254820d2c4d2Smrg    return first;
254920d2c4d2Smrg}
255020d2c4d2Smrg
255120d2c4d2Smrgstatic FcChar32
25529a64e1c5SmrgxtermXftLastChar(XftFont *xft)
255320d2c4d2Smrg{
2554d1603babSmrg    FcChar32 temp, last, next;
255520d2c4d2Smrg    FcChar32 map[FC_CHARSET_MAP_SIZE];
255620d2c4d2Smrg    int i;
255720d2c4d2Smrg    last = FcCharSetFirstPage(xft->charset, map, &next);
2558d1603babSmrg    while ((temp = FcCharSetNextPage(xft->charset, map, &next)) != FC_CHARSET_DONE)
2559d1603babSmrg	last = temp;
2560fa3f02f3Smrg    last &= (FcChar32) ~ 0xff;
25619a64e1c5Smrg    for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--) {
256220d2c4d2Smrg	if (map[i]) {
256320d2c4d2Smrg	    FcChar32 bits = map[i];
2564fa3f02f3Smrg	    last += (FcChar32) i *32 + 31;
256520d2c4d2Smrg	    while (!(bits & 0x80000000)) {
256620d2c4d2Smrg		last--;
256720d2c4d2Smrg		bits <<= 1;
256820d2c4d2Smrg	    }
256920d2c4d2Smrg	    break;
257020d2c4d2Smrg	}
25719a64e1c5Smrg    }
2572dfb07bc7Smrg    return (FcChar32) last;
257320d2c4d2Smrg}
2574dfb07bc7Smrg#endif /* OPT_REPORT_FONTS */
257520d2c4d2Smrg
2576d4fba8b9Smrg#if OPT_TRACE
2577d4fba8b9Smrg
2578d4fba8b9Smrg#if !OPT_WIDE_CHARS
2579d4fba8b9Smrgstatic Char *
2580d4fba8b9SmrgconvertToUTF8(Char *buffer, int c)
2581d4fba8b9Smrg{
2582d4fba8b9Smrg    buffer[0] = (Char) c;
2583d4fba8b9Smrg    buffer[1] = 0;
2584d4fba8b9Smrg    return buffer;
2585d4fba8b9Smrg}
2586d4fba8b9Smrg#endif
2587d4fba8b9Smrg
258820d2c4d2Smrgstatic void
25899a64e1c5SmrgdumpXft(XtermWidget xw, XTermXftFonts *data)
259020d2c4d2Smrg{
2591d1603babSmrg    XftFont *xft = XftFp(data);
259220d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
259320d2c4d2Smrg    VTwin *win = WhichVWin(screen);
259420d2c4d2Smrg
259520d2c4d2Smrg    FcChar32 c;
259620d2c4d2Smrg    FcChar32 first = xtermXftFirstChar(xft);
259720d2c4d2Smrg    FcChar32 last = xtermXftLastChar(xft);
2598d4fba8b9Smrg    FcChar32 dump;
259920d2c4d2Smrg    unsigned count = 0;
2600d4fba8b9Smrg    unsigned too_high = 0;
2601d4fba8b9Smrg    unsigned too_wide = 0;
2602d4fba8b9Smrg    Boolean skip = False;
2603d4fba8b9Smrg
2604d4fba8b9Smrg    TRACE(("dumpXft " TRACE_L "\n"));
2605d4fba8b9Smrg    TRACE(("\tdata range U+%04X..U+%04X\n", first, last));
2606d4fba8b9Smrg    TRACE(("\tcode\tcells\tdimensions\n"));
2607d4fba8b9Smrg#if OPT_TRACE < 2
2608d4fba8b9Smrg    dump = 255;
2609d4fba8b9Smrg#else
2610d4fba8b9Smrg    dump = last;
2611d4fba8b9Smrg#endif
261220d2c4d2Smrg    for (c = first; c <= last; ++c) {
261320d2c4d2Smrg	if (FcCharSetHasChar(xft->charset, c)) {
2614c48a5815Smrg	    int width = CharWidth(screen, c);
261520d2c4d2Smrg	    XGlyphInfo extents;
2616d4fba8b9Smrg	    Boolean big_x;
2617d4fba8b9Smrg	    Boolean big_y;
261820d2c4d2Smrg
261920d2c4d2Smrg	    XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents);
2620d4fba8b9Smrg	    big_x = (extents.width > win->f_width);
2621d4fba8b9Smrg	    big_y = (extents.height > win->f_height);
2622d4fba8b9Smrg
2623d4fba8b9Smrg	    if (c <= dump) {
2624d4fba8b9Smrg		Char buffer[80];
2625d4fba8b9Smrg
2626d4fba8b9Smrg		*convertToUTF8(buffer, c) = '\0';
2627d4fba8b9Smrg		TRACE(("%s%s\tU+%04X\t%d\t%.1f x %.1f\t%s\n",
2628d4fba8b9Smrg		       (big_y ? "y" : ""),
2629d4fba8b9Smrg		       (big_x ? "x" : ""),
2630d4fba8b9Smrg		       c, width,
2631d4fba8b9Smrg		       ((double) extents.height) / win->f_height,
2632d4fba8b9Smrg		       ((double) extents.width) / win->f_width,
2633d4fba8b9Smrg		       buffer));
2634d4fba8b9Smrg	    } else if (!skip) {
2635d4fba8b9Smrg		skip = True;
2636d4fba8b9Smrg		TRACE(("\t...skipping\n"));
2637d4fba8b9Smrg	    }
2638d4fba8b9Smrg	    if (big_y)
2639d4fba8b9Smrg		++too_high;
2640d4fba8b9Smrg	    if (big_x)
2641d4fba8b9Smrg		++too_wide;
264220d2c4d2Smrg	    ++count;
264320d2c4d2Smrg	}
264420d2c4d2Smrg    }
2645d4fba8b9Smrg    TRACE((TRACE_R " %u total, %u too-high, %u too-wide\n", count, too_high, too_wide));
264620d2c4d2Smrg}
264720d2c4d2Smrg#define DUMP_XFT(xw, data) dumpXft(xw, data)
264820d2c4d2Smrg#else
264920d2c4d2Smrg#define DUMP_XFT(xw, data)	/* nothing */
265020d2c4d2Smrg#endif
265120d2c4d2Smrg
2652d4fba8b9Smrg/*
2653d4fba8b9Smrg * Check if this is a FC_COLOR font, which fontconfig misrepresents to "fix" a
2654d4fba8b9Smrg * problem with web browsers.  As of 2018/12 (4 years later), Xft does not work
2655d4fba8b9Smrg * with that.  Even with this workaround, fontconfig has at least one bug which
2656d4fba8b9Smrg * causes it to crash (Debian #917034).
2657d4fba8b9Smrg */
2658d4fba8b9Smrg#ifdef FC_COLOR
2659d4fba8b9Smrg#define GetFcBool(pattern, what) \
2660d1603babSmrg    FcOK(FcPatternGetBool(pattern, what, 0, &fcbogus))
2661d4fba8b9Smrg
2662d4fba8b9Smrgstatic Boolean
2663d4fba8b9SmrgisBogusXft(XftFont *font)
2664d4fba8b9Smrg{
2665d4fba8b9Smrg    Boolean result = False;
2666190d7dceSmrg    if (font != NULL) {
2667d4fba8b9Smrg	FcBool fcbogus;
2668d4fba8b9Smrg	if (GetFcBool(font->pattern, FC_COLOR) && fcbogus) {
2669d4fba8b9Smrg	    TRACE(("...matched color-bitmap font\n"));
2670d1603babSmrg#if !USE_FC_COLOR
2671d4fba8b9Smrg	    result = True;
2672d1603babSmrg#endif
2673d4fba8b9Smrg	} else if (GetFcBool(font->pattern, FC_OUTLINE) && !fcbogus) {
2674d4fba8b9Smrg	    TRACE(("...matched non-outline font\n"));
2675d4fba8b9Smrg	    /* This is legal for regular bitmap fonts - fontconfig attempts to
2676d4fba8b9Smrg	     * find a match - but problematic for misencoded color-bitmap fonts.
2677d4fba8b9Smrg	     */
2678d4fba8b9Smrg	}
2679d4fba8b9Smrg    }
2680d4fba8b9Smrg    return result;
2681d4fba8b9Smrg}
2682d4fba8b9Smrg#endif
2683d4fba8b9Smrg
2684d4fba8b9Smrg#if OPT_BOX_CHARS
2685956cc18dSsnjstatic void
2686d4fba8b9SmrgsetBrokenBoxChars(XtermWidget xw, Bool state)
2687d4fba8b9Smrg{
2688d4fba8b9Smrg    TRACE(("setBrokenBoxChars %s\n", BtoS(state)));
2689d4fba8b9Smrg    term->work.broken_box_chars = (Boolean) state;
2690d4fba8b9Smrg    TScreenOf(xw)->broken_box_chars = (Boolean) state;
2691d4fba8b9Smrg    update_font_boxchars();
2692d4fba8b9Smrg}
2693d4fba8b9Smrg
2694d4fba8b9Smrg#else
2695d4fba8b9Smrg#define setBrokenBoxChars(xw, state)	/* nothing */
2696d4fba8b9Smrg#endif
2697d4fba8b9Smrg
2698d4fba8b9Smrgstatic Boolean
2699d4fba8b9SmrgcheckedXftWidth(Display *dpy,
2700d4fba8b9Smrg		XTermXftFonts *source,
2701d4fba8b9Smrg		unsigned limit,
2702d4fba8b9Smrg		Dimension *width,
2703d4fba8b9Smrg		FcChar32 c)
2704d4fba8b9Smrg{
2705d4fba8b9Smrg    Boolean result = False;
2706d4fba8b9Smrg
2707d1603babSmrg    if (FcCharSetHasChar(XftFp(source)->charset, c)) {
2708d4fba8b9Smrg	XGlyphInfo extents;
2709d4fba8b9Smrg
2710d4fba8b9Smrg	result = True;
2711d1603babSmrg	XftTextExtents32(dpy, XftFp(source), &c, 1, &extents);
2712d4fba8b9Smrg	if (*width < extents.width && extents.width <= limit) {
2713d4fba8b9Smrg	    *width = extents.width;
2714d4fba8b9Smrg	}
2715d4fba8b9Smrg    }
2716d4fba8b9Smrg    return result;
2717d4fba8b9Smrg}
2718d4fba8b9Smrg
2719d1603babSmrg/*
2720d1603babSmrg * Check if the given character has a glyph known to Xft.  This is likely to be
2721d1603babSmrg * slower than checking our cache.
2722d1603babSmrg *
2723d1603babSmrg * see xc/lib/Xft/xftglyphs.c
2724d1603babSmrg */
2725d1603babSmrgstatic Bool
2726d1603babSmrgslowXftMissing(XtermWidget xw, XftFont *font, unsigned wc)
2727d1603babSmrg{
2728d1603babSmrg    TScreen *screen = TScreenOf(xw);
2729d1603babSmrg    Bool result = False;
2730d1603babSmrg
2731d1603babSmrg    if (font != NULL) {
2732d1603babSmrg	if (XftCharIndex(screen->display, font, wc) == 0)
2733d1603babSmrg	    result = True;
2734d1603babSmrg    }
2735d1603babSmrg    return result;
2736d1603babSmrg}
2737d1603babSmrg
2738d4fba8b9Smrgstatic int
2739d1603babSmrgcheckXftWidth(XtermWidget xw, XTermXftFonts *data)
2740956cc18dSsnj{
2741956cc18dSsnj    FcChar32 c;
2742d1603babSmrg    FcChar32 last = xtermXftLastChar(XftFp(data));
2743d1603babSmrg    Dimension limit = (Dimension) XftFp(data)->max_advance_width;
2744956cc18dSsnj    Dimension width = 0;
2745d4fba8b9Smrg    Dimension width2 = 0;
2746d4fba8b9Smrg    int failed = 0;
2747d4fba8b9Smrg#if OPT_WIDE_CHARS
2748d4fba8b9Smrg    Cardinal n;
2749d4fba8b9Smrg#endif
2750956cc18dSsnj
2751d1603babSmrg    data->font_info.min_width = 0;
2752d1603babSmrg    data->font_info.max_width = limit;
2753d4fba8b9Smrg
2754d4fba8b9Smrg#if OPT_WIDE_CHARS
2755d4fba8b9Smrg    /*
2756d4fba8b9Smrg     * Check if the line-drawing characters are all provided in the font.
2757d4fba8b9Smrg     * If so, take that into account for the cell-widths.
2758d4fba8b9Smrg     */
2759d4fba8b9Smrg    for (n = 0; n < XtNumber(unicode_boxes) - 1; ++n) {
2760d4fba8b9Smrg	if (!checkedXftWidth(XtDisplay(xw),
2761d1603babSmrg			     data,
2762d4fba8b9Smrg			     limit,
2763d4fba8b9Smrg			     &width2, unicode_boxes[n].code)) {
2764d4fba8b9Smrg	    width2 = 0;
2765d4fba8b9Smrg	    TRACE(("font omits U+%04X line-drawing symbol\n",
2766d4fba8b9Smrg		   unicode_boxes[n].code));
2767d4fba8b9Smrg	    break;
2768d4fba8b9Smrg	}
2769d4fba8b9Smrg    }
2770d4fba8b9Smrg#else
2771d4fba8b9Smrg    (void) width2;
2772d4fba8b9Smrg#endif
2773d4fba8b9Smrg
2774d4fba8b9Smrg    if (width2 > 0) {
2775d4fba8b9Smrg	Dimension check = (Dimension) (limit + 1) / 2;
2776d4fba8b9Smrg	TRACE(("font provides VT100-style line-drawing\n"));
2777d4fba8b9Smrg	/*
2778d4fba8b9Smrg	 * The "VT100 line-drawing" characters happen to be all "ambiguous
2779d4fba8b9Smrg	 * width" in Unicode's scheme.  That means that they could be twice as
2780d4fba8b9Smrg	 * wide as the Latin-1 characters.
2781d4fba8b9Smrg	 */
2782d4fba8b9Smrg#define FC_ERR(n) (1.2 * (n))
2783d4fba8b9Smrg	if (width2 > FC_ERR(check)) {
2784d4fba8b9Smrg	    TRACE(("line-drawing characters appear to be double-width (ignore)\n"));
2785d4fba8b9Smrg	    setBrokenBoxChars(xw, True);
2786d4fba8b9Smrg	} else if (width2 > width) {
2787d4fba8b9Smrg	    width = width2;
2788d4fba8b9Smrg	}
2789d4fba8b9Smrg    } else {
2790d4fba8b9Smrg	TRACE(("font does NOT provide VT100-style line-drawing\n"));
2791d4fba8b9Smrg	setBrokenBoxChars(xw, True);
2792d4fba8b9Smrg    }
2793956cc18dSsnj
279420d2c4d2Smrg    /*
2795d4fba8b9Smrg     * For each printable code, ask what its width is.  Given the maximum width
2796d4fba8b9Smrg     * for those, we have a reasonable estimate of the single-column width.
279720d2c4d2Smrg     *
279820d2c4d2Smrg     * Ignore control characters - their extent information is misleading.
279920d2c4d2Smrg     */
2800956cc18dSsnj    for (c = 32; c < 256; ++c) {
2801c48a5815Smrg	if (CharWidth(TScreenOf(xw), c) <= 0)
280220d2c4d2Smrg	    continue;
2803d1603babSmrg	if (FcCharSetHasChar(XftFp(data)->charset, c)) {
2804d4fba8b9Smrg	    (void) checkedXftWidth(XtDisplay(xw),
2805d1603babSmrg				   data,
2806d1603babSmrg				   data->font_info.max_width,
2807d4fba8b9Smrg				   &width, c);
2808d4fba8b9Smrg	}
2809d4fba8b9Smrg    }
2810956cc18dSsnj
2811d4fba8b9Smrg    /*
2812d4fba8b9Smrg     * Sometimes someone uses a symbol font which has no useful ASCII or
2813d4fba8b9Smrg     * Latin-1 characters.  Allow that, in case they did it intentionally.
2814d4fba8b9Smrg     */
2815d4fba8b9Smrg    if (width == 0) {
2816d4fba8b9Smrg	failed = 1;
2817d4fba8b9Smrg	if (last >= 256) {
2818d1603babSmrg	    width = data->font_info.max_width;
2819956cc18dSsnj	}
2820956cc18dSsnj    }
2821d1603babSmrg    data->font_info.min_width = width;
2822d1603babSmrg    data->font_info.mixed = (data->font_info.max_width >=
2823d1603babSmrg			     (data->font_info.min_width + 1));
2824d4fba8b9Smrg    return failed;
2825956cc18dSsnj}
2826956cc18dSsnj
2827d1603babSmrg#if OPT_TRACE
2828d1603babSmrgstatic const char *
2829d1603babSmrgnameOfXftFont(XftFont *fp)
2830d1603babSmrg{
2831d1603babSmrg    static char *result;
2832d1603babSmrg    char buffer[1024];
2833d1603babSmrg    FreeAndNull(result);
2834d1603babSmrg    if (XftNameUnparse(fp->pattern, buffer, (int) sizeof(buffer))) {
2835d1603babSmrg	char *target;
2836d1603babSmrg	char *source = buffer;
2837190d7dceSmrg	if ((target = strtok(source, ":")) != NULL) {
2838d1603babSmrg	    result = x_strdup(target);
2839d1603babSmrg	}
2840d1603babSmrg    }
2841d1603babSmrg    return NonNull(result);
2842d1603babSmrg}
2843d1603babSmrg#endif
2844d1603babSmrg
2845dfb07bc7Smrg#if OPT_REPORT_FONTS
2846fa3f02f3Smrgstatic void
2847fa3f02f3SmrgreportXftFonts(XtermWidget xw,
2848d1603babSmrg	       XTermXftFonts *fontData,
2849d1603babSmrg	       int fontNum,
28509a64e1c5Smrg	       XftFont *fp,
2851fa3f02f3Smrg	       const char *name,
2852fa3f02f3Smrg	       const char *tag,
28539a64e1c5Smrg	       XftPattern *match)
2854fa3f02f3Smrg{
2855fa3f02f3Smrg    if (resource.reportFonts) {
2856fa3f02f3Smrg	char buffer[1024];
2857fa3f02f3Smrg	FcChar32 first_char = xtermXftFirstChar(fp);
2858fa3f02f3Smrg	FcChar32 last_char = xtermXftLastChar(fp);
2859fa3f02f3Smrg	FcChar32 ch;
2860fa3f02f3Smrg	unsigned missing = 0;
2861fa3f02f3Smrg
2862d1603babSmrg	ReportFonts("Loaded XftFonts(%s[%s])\n", name, tag);
2863fa3f02f3Smrg
2864fa3f02f3Smrg	for (ch = first_char; ch <= last_char; ++ch) {
2865d1603babSmrg	    if (xtermXftMissing(xw, fontData, fontNum, fp, ch)) {
2866fa3f02f3Smrg		++missing;
2867fa3f02f3Smrg	    }
2868fa3f02f3Smrg	}
2869d1603babSmrg	ReportFonts("\t\tfirst char:    %u\n", first_char);
2870d1603babSmrg	ReportFonts("\t\tlast char:     %u\n", last_char);
2871d1603babSmrg	ReportFonts("\t\tmissing-chars: %u\n", missing);
2872d1603babSmrg	ReportFonts("\t\tpresent-chars: %u\n", ((last_char - first_char)
2873d1603babSmrg						+ 1 - missing));
2874fa3f02f3Smrg
2875fa3f02f3Smrg	if (XftNameUnparse(match, buffer, (int) sizeof(buffer))) {
2876fa3f02f3Smrg	    char *target;
2877fa3f02f3Smrg	    char *source = buffer;
2878190d7dceSmrg	    while ((target = strtok(source, ":")) != NULL) {
2879d1603babSmrg		ReportFonts("\t%s\n", target);
2880190d7dceSmrg		source = NULL;
2881fa3f02f3Smrg	    }
2882fa3f02f3Smrg	}
2883d4fba8b9Smrg	fflush(stdout);
2884fa3f02f3Smrg    }
2885fa3f02f3Smrg}
2886d1603babSmrg
2887d1603babSmrgstatic void
2888d1603babSmrgreportXftFallbackFont(XtermWidget xw,
2889d1603babSmrg		      XTermXftFonts *fontData,
2890d1603babSmrg		      int fontNum,
2891d1603babSmrg		      XftFont *font,
2892d1603babSmrg		      XftPattern *match)
2893d1603babSmrg{
2894d1603babSmrg    if (resource.reportFonts) {
2895d1603babSmrg	char tag[80];
2896d1603babSmrg	sprintf(tag, "%s#%d",
2897d1603babSmrg		whichXftFonts(xw, fontData),
2898d1603babSmrg		fontNum + 1);
2899d1603babSmrg	reportXftFonts(xw, fontData, fontNum, font, "fallback", tag, match);
2900d1603babSmrg    }
2901d1603babSmrg}
2902d1603babSmrg
2903dfb07bc7Smrg#else
2904d1603babSmrg#define reportXftFonts(xw, fontData, fontNum, result, name, tag, match)		/* empty */
2905d1603babSmrg#define reportXftFallbackFont(xw, fontData, fontNum, font, match)	/* empty */
2906dfb07bc7Smrg#endif /* OPT_REPORT_FONTS */
2907fa3f02f3Smrg
2908d4fba8b9Smrg/*
2909d4fba8b9Smrg * Xft discards the pattern-match during open-pattern if the result happens to
2910d4fba8b9Smrg * match a currently-open file, but provides no clue to the caller when it does
2911d4fba8b9Smrg * this.  That is, closing a font-file may leave the data in Xft's cache, while
2912d4fba8b9Smrg * opening a file may free the data used for the match.
2913d4fba8b9Smrg *
2914d4fba8b9Smrg * Because of this problem, we cannot reliably refer to the pattern-match data
2915d4fba8b9Smrg * if it may have been seen before.
2916d4fba8b9Smrg */
2917d4fba8b9SmrgBoolean
2918d4fba8b9SmrgmaybeXftCache(XtermWidget xw, XftFont *font)
2919d4fba8b9Smrg{
2920d4fba8b9Smrg    Boolean result = False;
2921d1603babSmrg    if (font != NULL) {
2922d4fba8b9Smrg	TScreen *screen = TScreenOf(xw);
2923d4fba8b9Smrg	ListXftFonts *p;
2924d1603babSmrg	for (p = screen->list_xft_fonts; p != NULL; p = p->next) {
2925d4fba8b9Smrg	    if (p->font == font) {
2926d4fba8b9Smrg		result = True;
2927d4fba8b9Smrg		break;
2928d4fba8b9Smrg	    }
2929d4fba8b9Smrg	}
2930d4fba8b9Smrg	if (!result) {
2931d4fba8b9Smrg	    p = TypeXtMalloc(ListXftFonts);
2932d1603babSmrg	    if (p != NULL) {
2933d4fba8b9Smrg		p->font = font;
2934d4fba8b9Smrg		p->next = screen->list_xft_fonts;
2935d4fba8b9Smrg		screen->list_xft_fonts = p;
2936d4fba8b9Smrg	    }
2937d4fba8b9Smrg	}
2938d4fba8b9Smrg    }
2939d4fba8b9Smrg    return result;
2940d4fba8b9Smrg}
2941d4fba8b9Smrg
2942d4fba8b9Smrg/*
2943d4fba8b9Smrg * Drop an entry from the cache, and close the font.
2944d4fba8b9Smrg */
2945d4fba8b9Smrgvoid
2946d4fba8b9SmrgcloseCachedXft(TScreen *screen, XftFont *font)
2947d4fba8b9Smrg{
2948190d7dceSmrg    if (font != NULL) {
2949d4fba8b9Smrg	ListXftFonts *p, *q;
2950d4fba8b9Smrg
2951190d7dceSmrg	for (p = screen->list_xft_fonts, q = NULL; p != NULL; q = p, p = p->next) {
2952d4fba8b9Smrg	    if (p->font == font) {
2953d4fba8b9Smrg		XftFontClose(screen->display, font);
2954190d7dceSmrg		if (q != NULL) {
2955d4fba8b9Smrg		    q->next = p->next;
2956d4fba8b9Smrg		} else {
2957d4fba8b9Smrg		    screen->list_xft_fonts = p->next;
2958d4fba8b9Smrg		}
2959d4fba8b9Smrg		free(p);
2960d4fba8b9Smrg		break;
2961d4fba8b9Smrg	    }
2962d4fba8b9Smrg	}
2963d4fba8b9Smrg    }
2964d4fba8b9Smrg}
2965d4fba8b9Smrg
2966d1603babSmrgstatic void
2967d1603babSmrgxtermOpenXft(XtermWidget xw,
2968d1603babSmrg	     XTermXftFonts *fontData,
2969d1603babSmrg	     int fontNum,
2970d1603babSmrg	     const char *name,
2971d1603babSmrg	     XftPattern *pat,
2972d1603babSmrg	     const char *tag)
2973d522f475Smrg{
2974956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2975956cc18dSsnj    Display *dpy = screen->display;
2976d522f475Smrg    XftResult status;
2977190d7dceSmrg    XftFont *result = NULL;
2978d522f475Smrg
2979d4fba8b9Smrg    TRACE(("xtermOpenXft(name=%s, tag=%s)\n", name, tag));
2980190d7dceSmrg    if (pat != NULL && (fontNum <= MaxXftCache)) {
2981d4fba8b9Smrg	XftPattern *match;
2982d4fba8b9Smrg
2983d4fba8b9Smrg	FcConfigSubstitute(NULL, pat, FcMatchPattern);
2984d4fba8b9Smrg	XftDefaultSubstitute(dpy, DefaultScreen(dpy), pat);
2985d4fba8b9Smrg
2986d4fba8b9Smrg	match = FcFontMatch(NULL, pat, &status);
2987190d7dceSmrg	if (match != NULL) {
2988d4fba8b9Smrg	    Boolean maybeReopened = False;
2989d522f475Smrg	    result = XftFontOpenPattern(dpy, match);
2990d4fba8b9Smrg#ifdef FC_COLOR
2991d1603babSmrg	    if (result != NULL) {
2992d4fba8b9Smrg		if (isBogusXft(result)) {
2993d4fba8b9Smrg		    XftFontClose(dpy, result);
2994d1603babSmrg		    result = NULL;
2995d4fba8b9Smrg		    maybeReopened = True;
2996d4fba8b9Smrg		}
2997d4fba8b9Smrg	    }
2998d4fba8b9Smrg#endif
2999d1603babSmrg	    if (result != NULL) {
3000d522f475Smrg		TRACE(("...matched %s font\n", tag));
3001d1603babSmrg		if (fontData->fs_size < fontNum)
3002d1603babSmrg		    fontData->fs_size = fontNum;
3003d1603babSmrg		XftFpN(fontData, fontNum) = result;
3004d1603babSmrg		XftIsN(fontData, fontNum) = xcOpened;
3005d4fba8b9Smrg		if (!maybeXftCache(xw, result)) {
3006d1603babSmrg		    reportXftFonts(xw, fontData, fontNum, result, name, tag, match);
3007d4fba8b9Smrg		}
3008d522f475Smrg	    } else {
3009d4fba8b9Smrg		TRACE(("...could not open %s font\n", tag));
3010d4fba8b9Smrg		if (!maybeReopened)
3011d4fba8b9Smrg		    XftPatternDestroy(match);
3012956cc18dSsnj		if (xw->misc.fontWarnings >= fwAlways) {
3013dfb07bc7Smrg		    cannotFont(xw, "open", tag, name);
3014956cc18dSsnj		}
3015d522f475Smrg	    }
3016d522f475Smrg	} else {
3017d522f475Smrg	    TRACE(("...did not match %s font\n", tag));
3018956cc18dSsnj	    if (xw->misc.fontWarnings >= fwResource) {
3019dfb07bc7Smrg		cannotFont(xw, "match", tag, name);
3020956cc18dSsnj	    }
3021d522f475Smrg	}
3022d522f475Smrg    }
3023d1603babSmrg    if (result == NULL && (fontNum <= MaxXftCache)) {
3024d1603babSmrg	XftFpN(fontData, fontNum) = NULL;
3025d1603babSmrg	XftIsN(fontData, fontNum) = xcEmpty;
3026d1603babSmrg    }
3027d522f475Smrg}
3028d522f475Smrg
3029d522f475Smrg#if OPT_SHIFT_FONTS
3030d522f475Smrg/*
3031d522f475Smrg * Don't make a dependency on the math library for a single function.
3032d522f475Smrg * (Newton Raphson).
3033d522f475Smrg */
3034d522f475Smrgstatic double
30350bd37d32SmrgdimSquareRoot(double value)
3036d522f475Smrg{
3037d522f475Smrg    double result = 0.0;
3038d522f475Smrg    if (value > 0.0) {
3039d522f475Smrg	int n;
3040d522f475Smrg	double older = value;
3041d522f475Smrg	for (n = 0; n < 10; ++n) {
3042d522f475Smrg	    double delta = (older * older - value) / (2.0 * older);
3043d522f475Smrg	    double newer = older - delta;
3044d522f475Smrg	    older = newer;
3045d522f475Smrg	    result = newer;
3046d522f475Smrg	    if (delta > -0.001 && delta < 0.001)
3047d522f475Smrg		break;
3048d522f475Smrg	}
3049d522f475Smrg    }
3050d522f475Smrg    return result;
3051d522f475Smrg}
3052d522f475Smrg#endif
3053d522f475Smrg
3054d4fba8b9Smrg#ifdef DEBUG_XFT
3055d4fba8b9Smrgstatic void
3056d1603babSmrgtrace_xft_glyph(XtermWidget xw, XTermXftFonts *data, FT_Face face, int code, const char *name)
3057d4fba8b9Smrg{
3058d1603babSmrg    if (xtermXftMissing(xw, data, 0, XftFp(data), code)) {
3059d4fba8b9Smrg	TRACE(("Xft glyph U+%04X missing :%s\n", code, name));
3060d4fba8b9Smrg    } else if (FT_Load_Char(face, code, FT_LOAD_RENDER) == 0) {
3061d4fba8b9Smrg	FT_GlyphSlot g = face->glyph;
3062d4fba8b9Smrg	TRACE(("Xft glyph U+%04X size(%3d,%3d) at(%3d,%3d) :%s\n",
3063d4fba8b9Smrg	       code,
3064d4fba8b9Smrg	       g->bitmap.rows, g->bitmap.width,
3065d4fba8b9Smrg	       g->bitmap_top, g->bitmap_left,
3066d4fba8b9Smrg	       name));
3067d4fba8b9Smrg    }
3068d4fba8b9Smrg}
3069d4fba8b9Smrg
3070d4fba8b9Smrg#if OPT_WIDE_CHARS
3071d4fba8b9Smrgstatic void
3072d1603babSmrgtrace_xft_line_drawing(XtermWidget xw, XTermXftFonts *data, FT_Face face)
3073d4fba8b9Smrg{
3074d4fba8b9Smrg    int n;
3075d4fba8b9Smrg    for (n = 0; unicode_boxes[n].code != 0; ++n) {
3076d1603babSmrg	trace_xft_glyph(xw, data, face, unicode_boxes[n].code,
3077d4fba8b9Smrg			unicode_boxes[n].name);
3078d4fba8b9Smrg    }
3079d4fba8b9Smrg}
3080d4fba8b9Smrg#else
3081d1603babSmrg#define trace_xft_line_drawing(xw, data, face)	/* nothing */
3082d4fba8b9Smrg#endif
3083d4fba8b9Smrg#endif /* DEBUG_XFT */
3084d4fba8b9Smrg
3085d4fba8b9Smrg/*
3086d4fba8b9Smrg * Check if the line-drawing characters do not fill the bounding box.  If so,
3087d4fba8b9Smrg * they're not useful.
3088d4fba8b9Smrg */
3089d4fba8b9Smrg#if OPT_BOX_CHARS
3090d4fba8b9Smrgstatic void
3091d1603babSmrglinedrawing_gaps(XtermWidget xw, XTermXftFonts *data)
3092d4fba8b9Smrg{
3093d4fba8b9Smrg    Boolean broken;
3094d4fba8b9Smrg
3095d4fba8b9Smrg#if OPT_WIDE_CHARS
3096d4fba8b9Smrg    TScreen *screen = TScreenOf(xw);
3097d4fba8b9Smrg    int n;
3098d4fba8b9Smrg    FT_Face face;
3099d1603babSmrg    face = XftLockFace(XftFp(data));
3100d4fba8b9Smrg    broken = False;
3101d4fba8b9Smrg    for (n = 0; unicode_boxes[n].code; ++n) {
3102d4fba8b9Smrg	unsigned code = unicode_boxes[n].code;
3103d4fba8b9Smrg
3104d1603babSmrg	if (xtermXftMissing(xw, data, 0, XftFp(data), code)) {
3105d4fba8b9Smrg	    TRACE(("Xft glyph U+%04X is missing\n", code));
3106d4fba8b9Smrg	    broken = True;
3107d4fba8b9Smrg	    break;
3108d4fba8b9Smrg	}
3109d4fba8b9Smrg
3110d4fba8b9Smrg	if (FT_Load_Char(face, code, FT_LOAD_RENDER) == 0) {
3111d4fba8b9Smrg	    FT_GlyphSlot g = face->glyph;
3112d4fba8b9Smrg	    TRACE(("Xft glyph U+%04X size(%3d,%3d) at(%3d,%3d) :%s\n",
3113d4fba8b9Smrg		   code,
3114d4fba8b9Smrg		   g->bitmap.rows, g->bitmap.width,
3115d4fba8b9Smrg		   g->bitmap_top, g->bitmap_left,
3116d4fba8b9Smrg		   unicode_boxes[n].name));
3117d4fba8b9Smrg	    /*
3118d4fba8b9Smrg	     * While it is possible for badly-designed fonts to have line
3119d4fba8b9Smrg	     * drawing characters which do not meet, FreeType aggravates the
3120d4fba8b9Smrg	     * situation with its rounding.  Check for an obvious case where
3121d4fba8b9Smrg	     * the weights at the ends of a vertical line do not add up.  That
3122d4fba8b9Smrg	     * shows up as two under-weight rows at the beginning/end of the
3123d4fba8b9Smrg	     * bitmap.
3124d4fba8b9Smrg	     */
3125d4fba8b9Smrg	    if (code == 0x2502) {
3126d4fba8b9Smrg		unsigned r, c;
3127d4fba8b9Smrg		unsigned mids = 0, ends = 0;
3128d1603babSmrg		unsigned char *buffer = g->bitmap.buffer;
3129d4fba8b9Smrg
3130d4fba8b9Smrg		switch (g->bitmap.pixel_mode) {
3131d4fba8b9Smrg		case FT_PIXEL_MODE_MONO:
3132d4fba8b9Smrg		    /* FALLTHRU */
3133d4fba8b9Smrg		case FT_PIXEL_MODE_GRAY:
3134d4fba8b9Smrg		    for (r = 0; r < (unsigned) g->bitmap.rows; ++r) {
3135d4fba8b9Smrg			unsigned k = r * (unsigned) g->bitmap.pitch;
3136d4fba8b9Smrg			unsigned sum = 0;
3137d4fba8b9Smrg			for (c = 0; c < (unsigned) g->bitmap.width; ++c) {
3138d4fba8b9Smrg			    unsigned xx = 0;
3139d4fba8b9Smrg			    switch (g->bitmap.pixel_mode) {
3140d4fba8b9Smrg			    case FT_PIXEL_MODE_MONO:
3141d1603babSmrg				xx = (unsigned) ((buffer[k + (c / 8)]
3142d4fba8b9Smrg						  >> (c % 8)) & 1);
3143d4fba8b9Smrg				break;
3144d4fba8b9Smrg			    case FT_PIXEL_MODE_GRAY:
3145d1603babSmrg				xx = buffer[k + c];
3146d4fba8b9Smrg				break;
3147d4fba8b9Smrg			    }
3148d4fba8b9Smrg			    sum += xx;
3149d4fba8b9Smrg			    TRACE2((" %2x", xx));
3150d4fba8b9Smrg			}
3151d4fba8b9Smrg			TRACE2((" = %u\n", sum));
3152d4fba8b9Smrg			if (r > 0 && (r + 1) < (unsigned) g->bitmap.rows) {
3153d4fba8b9Smrg			    mids = sum;
3154d4fba8b9Smrg			} else {
3155d4fba8b9Smrg			    ends += sum;
3156d4fba8b9Smrg			}
3157d4fba8b9Smrg		    }
3158d4fba8b9Smrg		    TRACE(("...compare middle %u vs ends %u\n", mids, ends));
3159d4fba8b9Smrg		    if ((mids > ends) && (g->bitmap.rows < 16))
3160d4fba8b9Smrg			broken = True;
3161d4fba8b9Smrg		    break;
3162d4fba8b9Smrg		default:
3163d4fba8b9Smrg		    TRACE(("FIXME pixel_mode %d not handled\n",
3164d4fba8b9Smrg			   g->bitmap.pixel_mode));
3165d4fba8b9Smrg		    break;
3166d4fba8b9Smrg		}
3167d4fba8b9Smrg		if (broken)
3168d4fba8b9Smrg		    break;
3169d4fba8b9Smrg	    }
3170d4fba8b9Smrg	    /*
3171d4fba8b9Smrg	     * The factor of two accounts for line-drawing that goes through
3172d4fba8b9Smrg	     * the middle of a cell, possibly leaving half of the cell unused.
3173d4fba8b9Smrg	     * A horizontal line has to extend the full width of the cell.
3174d4fba8b9Smrg	     */
3175d4fba8b9Smrg	    switch (unicode_boxes[n].high) {
3176d4fba8b9Smrg	    case 1:
3177d4fba8b9Smrg		if ((unsigned) g->bitmap.rows < (unsigned) FontHeight(screen)) {
3178d4fba8b9Smrg		    TRACE(("...bitmap is shorter than full-cell (%u vs %u)\n",
3179d4fba8b9Smrg			   (unsigned) g->bitmap.rows,
3180d4fba8b9Smrg			   (unsigned) FontHeight(screen)));
3181d4fba8b9Smrg		    broken = True;
3182d4fba8b9Smrg		}
3183d4fba8b9Smrg		break;
3184d4fba8b9Smrg	    case 2:
3185d4fba8b9Smrg		if ((unsigned) (g->bitmap.rows * 2) < (unsigned) FontHeight(screen)) {
3186d4fba8b9Smrg		    TRACE(("...bitmap is too short for half-cell (%u vs %u)\n",
3187d4fba8b9Smrg			   (unsigned) (g->bitmap.rows * 2),
3188d4fba8b9Smrg			   (unsigned) FontHeight(screen)));
3189d4fba8b9Smrg		    broken = True;
3190d4fba8b9Smrg		}
3191d4fba8b9Smrg		break;
3192d4fba8b9Smrg	    }
3193d4fba8b9Smrg	    switch (unicode_boxes[n].wide) {
3194d4fba8b9Smrg	    case 1:
3195d4fba8b9Smrg		if ((unsigned) g->bitmap.width < (unsigned) FontWidth(screen)) {
3196d4fba8b9Smrg		    TRACE(("...bitmap is narrower than full-cell (%u vs %u)\n",
3197d4fba8b9Smrg			   (unsigned) g->bitmap.width,
3198d4fba8b9Smrg			   (unsigned) FontWidth(screen)));
3199d4fba8b9Smrg		    broken = True;
3200d4fba8b9Smrg		}
3201d4fba8b9Smrg		break;
3202d4fba8b9Smrg	    case 2:
3203d4fba8b9Smrg		if ((unsigned) (g->bitmap.width * 2) < (unsigned) FontWidth(screen)) {
3204d4fba8b9Smrg		    TRACE(("...bitmap is too narrow for half-cell (%u vs %u)\n",
3205d4fba8b9Smrg			   (unsigned) (g->bitmap.width * 2),
3206d4fba8b9Smrg			   (unsigned) FontWidth(screen)));
3207d4fba8b9Smrg		    broken = True;
3208d4fba8b9Smrg		}
3209d4fba8b9Smrg		break;
3210d4fba8b9Smrg	    }
3211d4fba8b9Smrg	    if (broken)
3212d4fba8b9Smrg		break;
3213d4fba8b9Smrg	}
3214d4fba8b9Smrg    }
3215d1603babSmrg    XftUnlockFace(XftFp(data));
3216d4fba8b9Smrg#else
3217d1603babSmrg    (void) data;
3218d4fba8b9Smrg    broken = True;
3219d4fba8b9Smrg#endif
3220d4fba8b9Smrg
3221d4fba8b9Smrg    if (broken) {
3222d4fba8b9Smrg	TRACE(("Xft line-drawing would not work\n"));
3223d4fba8b9Smrg	setBrokenBoxChars(xw, True);
3224d4fba8b9Smrg    }
3225d4fba8b9Smrg}
3226d4fba8b9Smrg#endif /* OPT_BOX_CHARS */
3227d4fba8b9Smrg
3228d522f475Smrg/*
3229d522f475Smrg * Given the Xft font metrics, determine the actual font size.  This is used
3230d522f475Smrg * for each font to ensure that normal, bold and italic fonts follow the same
3231d522f475Smrg * rule.
3232d522f475Smrg */
3233d522f475Smrgstatic void
3234d1603babSmrgsetRenderFontsize(XtermWidget xw, VTwin *win, XTermXftFonts *data, const char *tag)
3235d522f475Smrg{
3236d1603babSmrg    XftFont *font = XftFp(data);
3237d1603babSmrg    if (font != NULL) {
3238d4fba8b9Smrg	TScreen *screen = TScreenOf(xw);
3239d522f475Smrg	int width, height, ascent, descent;
3240d4fba8b9Smrg#ifdef DEBUG_XFT
3241d4fba8b9Smrg	int n;
3242d4fba8b9Smrg	FT_Face face;
3243d4fba8b9Smrg	FT_Size size;
3244d4fba8b9Smrg	FT_Size_Metrics metrics;
3245d4fba8b9Smrg	Boolean scalable;
3246d4fba8b9Smrg	Boolean is_fixed;
3247d4fba8b9Smrg	Boolean debug_xft = False;
3248d4fba8b9Smrg
3249d4fba8b9Smrg	face = XftLockFace(font);
3250d4fba8b9Smrg	size = face->size;
3251d4fba8b9Smrg	metrics = size->metrics;
3252d4fba8b9Smrg	is_fixed = FT_IS_FIXED_WIDTH(face);
3253d4fba8b9Smrg	scalable = FT_IS_SCALABLE(face);
3254d1603babSmrg	trace_xft_line_drawing(xw, data, face);
3255d4fba8b9Smrg	for (n = 32; n < 127; ++n) {
3256d4fba8b9Smrg	    char name[80];
3257d4fba8b9Smrg	    sprintf(name, "letter \"%c\"", n);
3258d1603babSmrg	    trace_xft_glyph(xw, data, face, n, name);
3259d4fba8b9Smrg	}
3260d4fba8b9Smrg	XftUnlockFace(font);
3261d4fba8b9Smrg
3262d4fba8b9Smrg	/* freetype's inconsistent for this sign */
3263d4fba8b9Smrg	metrics.descender = -metrics.descender;
3264d4fba8b9Smrg
3265d4fba8b9Smrg#define TR_XFT	   "Xft metrics: "
3266d4fba8b9Smrg#define D_64(name) ((double)(metrics.name)/64.0)
3267d4fba8b9Smrg#define M_64(a,b)  ((font->a * 64) != metrics.b)
3268d4fba8b9Smrg#define BOTH(a,b)  D_64(b), M_64(a,b) ? "*" : ""
3269d4fba8b9Smrg
3270d4fba8b9Smrg	debug_xft = (M_64(ascent, ascender)
3271d4fba8b9Smrg		     || M_64(descent, descender)
3272d4fba8b9Smrg		     || M_64(height, height)
3273d4fba8b9Smrg		     || M_64(max_advance_width, max_advance));
3274d4fba8b9Smrg
3275d4fba8b9Smrg	TRACE(("Xft font is %sscalable, %sfixed-width\n",
3276d4fba8b9Smrg	       is_fixed ? "" : "not ",
3277d4fba8b9Smrg	       scalable ? "" : "not "));
3278d4fba8b9Smrg
3279d4fba8b9Smrg	if (debug_xft) {
3280d4fba8b9Smrg	    TRACE(("Xft font size %d+%d vs %d by %d\n",
3281d4fba8b9Smrg		   font->ascent,
3282d4fba8b9Smrg		   font->descent,
3283d4fba8b9Smrg		   font->height,
3284d4fba8b9Smrg		   font->max_advance_width));
3285d4fba8b9Smrg	    TRACE((TR_XFT "ascender    %6.2f%s\n", BOTH(ascent, ascender)));
3286d4fba8b9Smrg	    TRACE((TR_XFT "descender   %6.2f%s\n", BOTH(descent, descender)));
3287d4fba8b9Smrg	    TRACE((TR_XFT "height      %6.2f%s\n", BOTH(height, height)));
3288d4fba8b9Smrg	    TRACE((TR_XFT "max_advance %6.2f%s\n", BOTH(max_advance_width, max_advance)));
3289d4fba8b9Smrg	} else {
3290d4fba8b9Smrg	    TRACE((TR_XFT "matches font\n"));
3291d4fba8b9Smrg	}
3292d4fba8b9Smrg#endif
3293d522f475Smrg
3294d522f475Smrg	width = font->max_advance_width;
3295d522f475Smrg	height = font->height;
3296d522f475Smrg	ascent = font->ascent;
3297d522f475Smrg	descent = font->descent;
3298d4fba8b9Smrg	if (screen->force_xft_height && height < ascent + descent) {
3299d4fba8b9Smrg	    TRACE(("...height is less than ascent + descent (%u vs %u)\n",
3300d4fba8b9Smrg		   height, ascent + descent));
3301d4fba8b9Smrg	    if ((ascent + descent) > (height + 1)) {
3302d4fba8b9Smrg		/* this happens less than 10% of the time */
3303d4fba8b9Smrg		--ascent;
3304d4fba8b9Smrg		--descent;
3305d4fba8b9Smrg		TRACE(("...decrement both ascent and descent before retry\n"));
3306d4fba8b9Smrg	    } else if (ascent > descent) {
3307d4fba8b9Smrg		/* this is the usual case */
3308d4fba8b9Smrg		--ascent;
3309d4fba8b9Smrg		TRACE(("...decrement ascent before retry\n"));
3310d4fba8b9Smrg	    } else {
3311d4fba8b9Smrg		/* this could happen, though rare... */
3312d4fba8b9Smrg		--descent;
3313d4fba8b9Smrg		TRACE(("...decrement descent before retry\n"));
3314d4fba8b9Smrg	    }
3315d522f475Smrg	    height = ascent + descent;
3316d4fba8b9Smrg	    font->ascent = ascent;
3317d4fba8b9Smrg	    font->descent = descent;
3318d4fba8b9Smrg	    TRACE(("...updated height %d vs %d (ascent %d, descent %d)\n",
3319d4fba8b9Smrg		   height, ascent + descent, ascent, descent));
3320d522f475Smrg	}
3321d522f475Smrg	if (is_double_width_font_xft(screen->display, font)) {
3322d4fba8b9Smrg	    TRACE(("...reduce width from %d to %d\n", width, width >> 1));
3323d522f475Smrg	    width >>= 1;
3324d522f475Smrg	}
3325190d7dceSmrg	if (tag == NULL) {
33260bd37d32Smrg	    SetFontWidth(screen, win, width);
33270bd37d32Smrg	    SetFontHeight(screen, win, height);
3328d522f475Smrg	    win->f_ascent = ascent;
3329d522f475Smrg	    win->f_descent = descent;
3330d522f475Smrg	    TRACE(("setRenderFontsize result %dx%d (%d+%d)\n",
3331d522f475Smrg		   width, height, ascent, descent));
3332d522f475Smrg	} else if (win->f_width < width ||
3333d522f475Smrg		   win->f_height < height ||
3334d522f475Smrg		   win->f_ascent < ascent ||
3335d522f475Smrg		   win->f_descent < descent) {
3336d522f475Smrg	    TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n",
3337d522f475Smrg		   tag,
3338d522f475Smrg		   win->f_width, win->f_height, win->f_ascent, win->f_descent,
3339d522f475Smrg		   width, height, ascent, descent));
3340d522f475Smrg
33410bd37d32Smrg	    SetFontWidth(screen, win, width);
33420bd37d32Smrg	    SetFontHeight(screen, win, height);
3343d522f475Smrg	    win->f_ascent = ascent;
3344d522f475Smrg	    win->f_descent = descent;
3345d522f475Smrg	} else {
3346d522f475Smrg	    TRACE(("setRenderFontsize %s unchanged\n", tag));
3347d522f475Smrg	}
3348d4fba8b9Smrg#if OPT_BOX_CHARS
3349190d7dceSmrg	if (!screen->broken_box_chars && (tag == NULL)) {
3350d1603babSmrg	    linedrawing_gaps(xw, data);
3351d4fba8b9Smrg	}
3352d4fba8b9Smrg#endif
3353d522f475Smrg    }
3354d522f475Smrg}
3355d522f475Smrg#endif
3356d522f475Smrg
335720d2c4d2Smrgstatic void
3358d4fba8b9SmrgcheckFontInfo(int value, const char *tag, int failed)
335920d2c4d2Smrg{
3360d4fba8b9Smrg    if (value == 0 || failed) {
3361d4fba8b9Smrg	if (value == 0) {
3362d4fba8b9Smrg	    xtermWarning("Selected font has no non-zero %s for ISO-8859-1 encoding\n", tag);
3363980988aeSmrg	    exit(ERROR_MISC);
3364d4fba8b9Smrg	} else {
3365d4fba8b9Smrg	    xtermWarning("Selected font has no valid %s for ISO-8859-1 encoding\n", tag);
3366d4fba8b9Smrg	}
336720d2c4d2Smrg    }
336820d2c4d2Smrg}
336920d2c4d2Smrg
337020d2c4d2Smrg#if OPT_RENDERFONT
337120d2c4d2Smrgvoid
33729a64e1c5SmrgxtermCloseXft(TScreen *screen, XTermXftFonts *pub)
337320d2c4d2Smrg{
3374d1603babSmrg    if (XftFp(pub) != NULL) {
3375d1603babSmrg	int n;
3376d4fba8b9Smrg
3377d4fba8b9Smrg	if (pub->pattern) {
3378d4fba8b9Smrg	    XftPatternDestroy(pub->pattern);
3379d1603babSmrg	    pub->pattern = NULL;
3380d4fba8b9Smrg	}
3381d4fba8b9Smrg	if (pub->fontset) {
3382d4fba8b9Smrg	    XftFontSetDestroy(pub->fontset);
3383d1603babSmrg	    pub->fontset = NULL;
3384d4fba8b9Smrg	}
3385d4fba8b9Smrg
3386d1603babSmrg	for (n = 0; n <= pub->fs_size; ++n) {
3387d1603babSmrg	    if (XftFpN(pub, n) != NULL) {
3388d1603babSmrg		closeCachedXft(screen, XftFpN(pub, n));
3389d1603babSmrg		XftFpN(pub, n) = NULL;
3390d1603babSmrg		XftIsN(pub, n) = xcEmpty;
3391d4fba8b9Smrg	    }
3392d4fba8b9Smrg	}
3393d1603babSmrg	FreeAndNull(pub->font_map.per_font);
3394d1603babSmrg	memset(pub, 0, sizeof(*pub));
339520d2c4d2Smrg    }
339620d2c4d2Smrg}
339720d2c4d2Smrg
339820d2c4d2Smrg/*
3399d4fba8b9Smrg * Get the faceName/faceNameDoublesize resource setting.
340020d2c4d2Smrg */
3401492d43a5SmrgString
3402d4fba8b9SmrggetFaceName(XtermWidget xw, Bool wideName)
340320d2c4d2Smrg{
340420d2c4d2Smrg#if OPT_RENDERWIDE
3405492d43a5Smrg    String result = (wideName
3406dfb07bc7Smrg		     ? FirstItemOf(xw->work.fonts.xft.list_w)
3407dfb07bc7Smrg		     : CurrentXftFont(xw));
340820d2c4d2Smrg#else
3409dfb07bc7Smrg    String result = CurrentXftFont(xw);
3410d4fba8b9Smrg    (void) wideName;
341120d2c4d2Smrg#endif
341220d2c4d2Smrg    return x_nonempty(result);
341320d2c4d2Smrg}
341420d2c4d2Smrg
341520d2c4d2Smrg/*
341620d2c4d2Smrg * If we change the faceName, we'll have to re-acquire all of the fonts that
341720d2c4d2Smrg * are derived from it.
341820d2c4d2Smrg */
341920d2c4d2Smrgvoid
342020d2c4d2SmrgsetFaceName(XtermWidget xw, const char *value)
342120d2c4d2Smrg{
342220d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
3423190d7dceSmrg    Boolean changed = (Boolean) ((CurrentXftFont(xw) == NULL)
3424dfb07bc7Smrg				 || strcmp(CurrentXftFont(xw), value));
342520d2c4d2Smrg
34260bd37d32Smrg    if (changed) {
3427037a25ddSmrg	int n;
3428037a25ddSmrg
3429dfb07bc7Smrg	CurrentXftFont(xw) = x_strdup(value);
34300bd37d32Smrg	for (n = 0; n < NMENUFONTS; ++n) {
3431dfb07bc7Smrg	    int e;
34320bd37d32Smrg	    xw->misc.face_size[n] = -1.0;
3433dfb07bc7Smrg	    for (e = 0; e < fMAX; ++e) {
3434dfb07bc7Smrg		xtermCloseXft(screen, getMyXftFont(xw, e, n));
3435dfb07bc7Smrg	    }
34360bd37d32Smrg	}
343720d2c4d2Smrg    }
343820d2c4d2Smrg}
343920d2c4d2Smrg#endif
344020d2c4d2Smrg
3441d522f475Smrg/*
3442d522f475Smrg * Compute useful values for the font/window sizes
3443d522f475Smrg */
3444d522f475Smrgvoid
3445d522f475SmrgxtermComputeFontInfo(XtermWidget xw,
34469a64e1c5Smrg		     VTwin *win,
34479a64e1c5Smrg		     XFontStruct *font,
3448d522f475Smrg		     int sbwidth)
3449d522f475Smrg{
3450956cc18dSsnj    TScreen *screen = TScreenOf(xw);
3451d522f475Smrg
3452d522f475Smrg    int i, j, width, height;
3453492d43a5Smrg#if OPT_RENDERFONT
3454492d43a5Smrg    int fontnum = screen->menu_font_number;
3455492d43a5Smrg#endif
3456d4fba8b9Smrg    int failed = 0;
3457d522f475Smrg
3458d522f475Smrg#if OPT_RENDERFONT
3459d522f475Smrg    /*
3460d522f475Smrg     * xterm contains a lot of references to fonts, assuming they are fixed
3461d522f475Smrg     * size.  This chunk of code overrides the actual font-selection (see
3462d522f475Smrg     * drawXtermText()), if the user has selected render-font.  All of the
3463d522f475Smrg     * font-loading for fixed-fonts still goes on whether or not this chunk
3464d522f475Smrg     * overrides it.
3465d522f475Smrg     */
3466492d43a5Smrg    if (UsingRenderFont(xw) && fontnum >= 0) {
3467492d43a5Smrg	String face_name = getFaceName(xw, False);
3468d1603babSmrg	XTermXftFonts *norm = &(screen->renderFontNorm[fontnum]);
3469d1603babSmrg	XTermXftFonts *bold = &(screen->renderFontBold[fontnum]);
3470d1603babSmrg	XTermXftFonts *ital = &(screen->renderFontItal[fontnum]);
3471d1603babSmrg	XTermXftFonts *btal = &(screen->renderFontBtal[fontnum]);
3472d522f475Smrg#if OPT_RENDERWIDE
3473d1603babSmrg	XTermXftFonts *wnorm = &(screen->renderWideNorm[fontnum]);
3474d1603babSmrg	XTermXftFonts *wbold = &(screen->renderWideBold[fontnum]);
3475d1603babSmrg	XTermXftFonts *wital = &(screen->renderWideItal[fontnum]);
3476d1603babSmrg	XTermXftFonts *wbtal = &(screen->renderWideBtal[fontnum]);
3477d522f475Smrg#endif
3478d522f475Smrg
3479190d7dceSmrg	if (XftFp(norm) == NULL && !IsEmpty(face_name)) {
3480d1603babSmrg	    Work *work = &(xw->work);
3481d522f475Smrg	    XftPattern *pat;
34820bd37d32Smrg	    double face_size;
3483d522f475Smrg
34840bd37d32Smrg	    TRACE(("xtermComputeFontInfo font %d: norm(face %s, size %.1f)\n",
3485492d43a5Smrg		   fontnum, face_name,
3486d522f475Smrg		   xw->misc.face_size[fontnum]));
3487d522f475Smrg
3488d1603babSmrg	    TRACE(("Using Xft %d\n", XftGetVersion()));
3489d4fba8b9Smrg	    TRACE(("Using FontConfig %d\n", FC_VERSION));
3490d4fba8b9Smrg
3491d1603babSmrg	    if (work->xft_defaults == NULL) {
3492d1603babSmrg		FcInit();
3493d1603babSmrg		work->xft_defaults = FcPatternCreate();
3494d1603babSmrg		XftDefaultSubstitute(screen->display,
3495d1603babSmrg				     XScreenNumberOfScreen(XtScreen(xw)),
3496d1603babSmrg				     work->xft_defaults);
3497d1603babSmrg		if (screen->xft_max_glyph_memory > 0) {
3498d1603babSmrg		    FcPatternAddInteger(work->xft_defaults,
3499d1603babSmrg					XFT_MAX_GLYPH_MEMORY,
3500d1603babSmrg					screen->xft_max_glyph_memory);
3501d1603babSmrg		}
3502d1603babSmrg		if (screen->xft_max_unref_fonts > 0) {
3503d1603babSmrg		    FcPatternAddInteger(work->xft_defaults,
3504d1603babSmrg					XFT_MAX_UNREF_FONTS,
3505d1603babSmrg					screen->xft_max_unref_fonts);
3506d1603babSmrg		}
3507d1603babSmrg#ifdef XFT_TRACK_MEM_USAGE
3508d1603babSmrg		FcPatternAddBool(work->xft_defaults,
3509d1603babSmrg				 XFT_TRACK_MEM_USAGE,
3510d1603babSmrg				 screen->xft_track_mem_usage);
3511d1603babSmrg#endif
3512d1603babSmrg		XftDefaultSet(screen->display, work->xft_defaults);
3513d1603babSmrg	    }
3514d1603babSmrg
35150bd37d32Smrg	    fillInFaceSize(xw, fontnum);
3516d4fba8b9Smrg	    face_size = (double) xw->misc.face_size[fontnum];
3517d522f475Smrg
3518d522f475Smrg	    /*
3519d522f475Smrg	     * By observation (there is no documentation), XftPatternBuild is
3520d522f475Smrg	     * cumulative.  Build the bold- and italic-patterns on top of the
3521d522f475Smrg	     * normal pattern.
3522d522f475Smrg	     */
3523d4fba8b9Smrg#ifdef FC_COLOR
3524d1603babSmrg#if USE_FC_COLOR
3525d1603babSmrg#define NormXftPattern \
3526d1603babSmrg	    XFT_FAMILY,     XftTypeString, "mono", \
3527d1603babSmrg	    FC_OUTLINE,     XftTypeBool,   FcTrue, \
3528d1603babSmrg	    XFT_SIZE,       XftTypeDouble, face_size
3529d1603babSmrg#else
3530d522f475Smrg#define NormXftPattern \
3531d4fba8b9Smrg	    XFT_FAMILY,     XftTypeString, "mono", \
3532d4fba8b9Smrg	    FC_COLOR,       XftTypeBool,   FcFalse, \
3533d4fba8b9Smrg	    FC_OUTLINE,     XftTypeBool,   FcTrue, \
3534d4fba8b9Smrg	    XFT_SIZE,       XftTypeDouble, face_size
3535d1603babSmrg#endif
3536d4fba8b9Smrg#else
3537d4fba8b9Smrg#define NormXftPattern \
3538d4fba8b9Smrg	    XFT_FAMILY,     XftTypeString, "mono", \
3539d4fba8b9Smrg	    XFT_SIZE,       XftTypeDouble, face_size
3540d4fba8b9Smrg#endif
3541d522f475Smrg
3542d522f475Smrg#define BoldXftPattern(norm) \
3543d4fba8b9Smrg	    XFT_WEIGHT,     XftTypeInteger, XFT_WEIGHT_BOLD, \
3544d1603babSmrg	    XFT_CHAR_WIDTH, XftTypeInteger, XftFp(norm)->max_advance_width
3545d522f475Smrg
3546d522f475Smrg#define ItalXftPattern(norm) \
3547d4fba8b9Smrg	    XFT_SLANT,      XftTypeInteger, XFT_SLANT_ITALIC, \
3548d1603babSmrg	    XFT_CHAR_WIDTH, XftTypeInteger, XftFp(norm)->max_advance_width
3549d4fba8b9Smrg
3550d4fba8b9Smrg#define BtalXftPattern(norm) \
3551d4fba8b9Smrg	    XFT_WEIGHT,     XftTypeInteger, XFT_WEIGHT_BOLD, \
3552d4fba8b9Smrg	    XFT_SLANT,      XftTypeInteger, XFT_SLANT_ITALIC, \
3553d1603babSmrg	    XFT_CHAR_WIDTH, XftTypeInteger, XftFp(norm)->max_advance_width
3554d522f475Smrg
35559a64e1c5Smrg#if OPT_WIDE_ATTRS
35569a64e1c5Smrg#define HAVE_ITALICS 1
3557190d7dceSmrg#define FIND_ITALICS ((pat = XftNameParse(face_name)) != NULL)
35589a64e1c5Smrg#elif OPT_ISO_COLORS
35599a64e1c5Smrg#define HAVE_ITALICS 1
35609a64e1c5Smrg#define FIND_ITALICS (screen->italicULMode && (pat = XftNameParse(face_name)) != 0)
35619a64e1c5Smrg#else
35629a64e1c5Smrg#define HAVE_ITALICS 0
35639a64e1c5Smrg#endif
35649a64e1c5Smrg
3565d4fba8b9Smrg#if OPT_DEC_CHRSET
3566d4fba8b9Smrg	    freeall_DoubleFT(xw);
3567d4fba8b9Smrg#endif
3568190d7dceSmrg	    if ((pat = XftNameParse(face_name)) != NULL) {
3569d1603babSmrg#define OPEN_XFT(data, tag) xtermOpenXft(xw, data, 0, face_name, data->pattern, tag)
3570d1603babSmrg		norm->pattern = XftPatternDuplicate(pat);
3571d1603babSmrg		XftPatternBuild(norm->pattern,
3572d522f475Smrg				NormXftPattern,
3573d522f475Smrg				(void *) 0);
3574d4fba8b9Smrg		OPEN_XFT(norm, "normal");
3575d522f475Smrg
3576190d7dceSmrg		if (XftFp(norm) != NULL) {
3577d1603babSmrg		    bold->pattern = XftPatternDuplicate(pat);
3578d1603babSmrg		    XftPatternBuild(bold->pattern,
3579d4fba8b9Smrg				    NormXftPattern,
3580d522f475Smrg				    BoldXftPattern(norm),
3581d522f475Smrg				    (void *) 0);
3582d4fba8b9Smrg		    OPEN_XFT(bold, "bold");
3583d522f475Smrg
35849a64e1c5Smrg#if HAVE_ITALICS
35859a64e1c5Smrg		    if (FIND_ITALICS) {
3586d1603babSmrg			ital->pattern = XftPatternDuplicate(pat);
3587d1603babSmrg			XftPatternBuild(ital->pattern,
3588d522f475Smrg					NormXftPattern,
3589d522f475Smrg					ItalXftPattern(norm),
3590d522f475Smrg					(void *) 0);
3591d4fba8b9Smrg			OPEN_XFT(ital, "italic");
3592d1603babSmrg			btal->pattern = XftPatternDuplicate(pat);
3593d1603babSmrg			XftPatternBuild(btal->pattern,
3594d4fba8b9Smrg					NormXftPattern,
3595d4fba8b9Smrg					BtalXftPattern(norm),
3596d4fba8b9Smrg					(void *) 0);
3597d4fba8b9Smrg			OPEN_XFT(btal, "bold-italic");
3598d522f475Smrg		    }
35999a64e1c5Smrg#endif
3600d522f475Smrg
3601d522f475Smrg		    /*
3602d522f475Smrg		     * FIXME:  just assume that the corresponding font has no
3603d522f475Smrg		     * graphics characters.
3604d522f475Smrg		     */
3605d522f475Smrg		    if (screen->fnt_boxes) {
3606d4fba8b9Smrg			screen->fnt_boxes = 0;
3607d1603babSmrg			TRACE(("Xft opened - will not use internal line-drawing characters\n"));
3608d522f475Smrg		    }
3609d522f475Smrg		}
3610d522f475Smrg
3611d1603babSmrg		CACHE_XFT(norm);
3612d4fba8b9Smrg
3613d1603babSmrg		CACHE_XFT(bold);
3614190d7dceSmrg		if (XftFp(norm) != NULL && !XftFp(bold)) {
3615d4fba8b9Smrg		    noUsableXft(xw, "bold");
3616d1603babSmrg		    XftPatternDestroy(bold->pattern);
3617d1603babSmrg		    bold->pattern = XftPatternDuplicate(pat);
3618d1603babSmrg		    XftPatternBuild(bold->pattern,
3619d4fba8b9Smrg				    NormXftPattern,
3620d4fba8b9Smrg				    (void *) 0);
3621d4fba8b9Smrg		    OPEN_XFT(bold, "bold");
3622d4fba8b9Smrg		    failed = 0;
3623d1603babSmrg		    CACHE_XFT(bold);
3624d4fba8b9Smrg		}
3625d4fba8b9Smrg#if HAVE_ITALICS
3626d1603babSmrg		CACHE_XFT(ital);
3627190d7dceSmrg		if (XftFp(norm) != NULL && !XftFp(ital)) {
3628d4fba8b9Smrg		    noUsableXft(xw, "italic");
3629d1603babSmrg		    XftPatternDestroy(ital->pattern);
3630d1603babSmrg		    ital->pattern = XftPatternDuplicate(pat);
3631d1603babSmrg		    XftPatternBuild(ital->pattern,
3632d4fba8b9Smrg				    NormXftPattern,
3633d4fba8b9Smrg				    (void *) 0);
3634d4fba8b9Smrg		    OPEN_XFT(ital, "italics");
3635d4fba8b9Smrg		    failed = 0;
3636d1603babSmrg		    CACHE_XFT(ital);
3637d4fba8b9Smrg		}
3638d1603babSmrg		CACHE_XFT(btal);
3639190d7dceSmrg		if (XftFp(norm) != NULL && !XftFp(btal)) {
3640d4fba8b9Smrg		    noUsableXft(xw, "bold italic");
3641d1603babSmrg		    XftPatternDestroy(btal->pattern);
3642d1603babSmrg		    btal->pattern = XftPatternDuplicate(pat);
3643d1603babSmrg		    XftPatternBuild(btal->pattern,
3644d4fba8b9Smrg				    NormXftPattern,
3645d4fba8b9Smrg				    (void *) 0);
3646d4fba8b9Smrg		    OPEN_XFT(btal, "bold-italics");
3647d4fba8b9Smrg		    failed = 0;
3648d1603babSmrg		    CACHE_XFT(btal);
3649d4fba8b9Smrg		}
3650d4fba8b9Smrg#endif
3651d522f475Smrg		XftPatternDestroy(pat);
3652d4fba8b9Smrg	    } else {
3653d4fba8b9Smrg		failed = 1;
3654d522f475Smrg	    }
3655d522f475Smrg
3656d522f475Smrg	    /*
3657d4fba8b9Smrg	     * See xtermXftDrawString().  A separate double-width font is nice
3658d4fba8b9Smrg	     * to have, but not essential.
3659d522f475Smrg	     */
3660d522f475Smrg#if OPT_RENDERWIDE
3661190d7dceSmrg	    if (XftFp(norm) != NULL && screen->wide_chars) {
3662d1603babSmrg		int char_width = XftFp(norm)->max_advance_width * 2;
3663dfb07bc7Smrg		double aspect = ((FirstItemOf(xw->work.fonts.xft.list_w)
3664d1603babSmrg				  || screen->renderFontNorm[fontnum].font_info.mixed)
3665956cc18dSsnj				 ? 1.0
3666956cc18dSsnj				 : 2.0);
3667d522f475Smrg
366820d2c4d2Smrg		face_name = getFaceName(xw, True);
3669d522f475Smrg		TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n",
367020d2c4d2Smrg		       NonNull(face_name),
3671d522f475Smrg		       char_width));
3672d522f475Smrg
3673d522f475Smrg#define WideXftPattern \
3674d4fba8b9Smrg		XFT_FAMILY,     XftTypeString,   "mono", \
3675d4fba8b9Smrg		XFT_SIZE,       XftTypeDouble,   face_size, \
3676d4fba8b9Smrg		XFT_SPACING,    XftTypeInteger,  XFT_MONO, \
3677d4fba8b9Smrg		XFT_CHAR_WIDTH, XftTypeInteger,  char_width, \
3678d4fba8b9Smrg		FC_ASPECT,      XftTypeDouble,   aspect
3679d4fba8b9Smrg
3680d4fba8b9Smrg		if (!IsEmpty(face_name) && (pat = XftNameParse(face_name))
3681190d7dceSmrg		    != NULL) {
3682d1603babSmrg		    wnorm->pattern = XftPatternDuplicate(pat);
3683d1603babSmrg		    XftPatternBuild(wnorm->pattern,
3684d522f475Smrg				    WideXftPattern,
3685d522f475Smrg				    (void *) 0);
3686d4fba8b9Smrg		    OPEN_XFT(wnorm, "wide");
3687d522f475Smrg
3688190d7dceSmrg		    if (XftFp(wnorm) != NULL) {
3689d1603babSmrg			wbold->pattern = XftPatternDuplicate(pat);
3690d1603babSmrg			XftPatternBuild(wbold->pattern,
3691d522f475Smrg					WideXftPattern,
3692d522f475Smrg					BoldXftPattern(wnorm),
3693d522f475Smrg					(void *) 0);
3694d4fba8b9Smrg			OPEN_XFT(wbold, "wide-bold");
3695d522f475Smrg
36969a64e1c5Smrg#if HAVE_ITALICS
36979a64e1c5Smrg			if (FIND_ITALICS) {
3698d1603babSmrg			    wital->pattern = XftPatternDuplicate(pat);
3699d1603babSmrg			    XftPatternBuild(wital->pattern,
3700d522f475Smrg					    WideXftPattern,
3701d522f475Smrg					    ItalXftPattern(wnorm),
3702d522f475Smrg					    (void *) 0);
3703d4fba8b9Smrg			    OPEN_XFT(wital, "wide-italic");
3704d4fba8b9Smrg			}
3705d1603babSmrg			CACHE_XFT(wbtal);
3706d1603babSmrg			if (!XftFp(wbtal)) {
3707d4fba8b9Smrg			    noUsableXft(xw, "wide bold");
3708d1603babSmrg			    XftPatternDestroy(wbtal->pattern);
3709d1603babSmrg			    wbtal->pattern = XftPatternDuplicate(pat);
3710d1603babSmrg			    XftPatternBuild(wbtal->pattern,
3711d4fba8b9Smrg					    WideXftPattern,
3712d4fba8b9Smrg					    (void *) 0);
3713d4fba8b9Smrg			    OPEN_XFT(wbtal, "wide-bold-italics");
3714d4fba8b9Smrg			    failed = 0;
3715d1603babSmrg			    CACHE_XFT(wbtal);
3716d522f475Smrg			}
3717d522f475Smrg#endif
3718d522f475Smrg		    }
3719d4fba8b9Smrg
3720d1603babSmrg		    CACHE_XFT(wnorm);
3721d4fba8b9Smrg
3722d1603babSmrg		    CACHE_XFT(wbold);
3723190d7dceSmrg		    if (XftFp(wnorm) != NULL && !XftFp(wbold)) {
3724d4fba8b9Smrg			noUsableXft(xw, "wide-bold");
3725d1603babSmrg			XftPatternDestroy(wbold->pattern);
3726d1603babSmrg			wbold->pattern = XftPatternDuplicate(pat);
3727d1603babSmrg			XftPatternBuild(bold->pattern,
3728d4fba8b9Smrg					WideXftPattern,
3729d4fba8b9Smrg					(void *) 0);
3730d4fba8b9Smrg			OPEN_XFT(wbold, "wide-bold");
3731d4fba8b9Smrg			failed = 0;
3732d1603babSmrg			CACHE_XFT(bold);
3733d4fba8b9Smrg		    }
3734d4fba8b9Smrg
3735d1603babSmrg		    CACHE_XFT(wital);
3736190d7dceSmrg		    if (XftFp(wnorm) != NULL && !XftFp(wital)) {
3737d4fba8b9Smrg			noUsableXft(xw, "wide-italic");
3738d1603babSmrg			XftPatternDestroy(wital->pattern);
3739d1603babSmrg			wital->pattern = XftPatternDuplicate(pat);
3740d1603babSmrg			XftPatternBuild(wital->pattern,
3741d4fba8b9Smrg					WideXftPattern,
3742d4fba8b9Smrg					(void *) 0);
3743d4fba8b9Smrg			OPEN_XFT(wital, "wide-italic");
3744d4fba8b9Smrg			failed = 0;
3745d1603babSmrg			CACHE_XFT(wital);
3746d4fba8b9Smrg		    }
3747d4fba8b9Smrg
3748d522f475Smrg		    XftPatternDestroy(pat);
3749d522f475Smrg		}
3750d4fba8b9Smrg#undef OPEN_XFT
3751d522f475Smrg	    }
3752d522f475Smrg#endif /* OPT_RENDERWIDE */
3753d522f475Smrg	}
3754190d7dceSmrg	if (XftFp(norm) == NULL) {
37552eaa94a1Schristos	    TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum));
37560bd37d32Smrg	    xw->work.render_font = False;
3757d522f475Smrg	    update_font_renderfont();
3758d522f475Smrg	    /* now we will fall through into the bitmap fonts */
3759d522f475Smrg	} else {
3760d4fba8b9Smrg	    setBrokenBoxChars(xw, False);
3761d1603babSmrg	    setRenderFontsize(xw, win, norm, NULL);
3762d1603babSmrg	    setRenderFontsize(xw, win, bold, "bold");
3763d1603babSmrg	    setRenderFontsize(xw, win, ital, "ital");
3764d1603babSmrg	    setRenderFontsize(xw, win, btal, "btal");
376520d2c4d2Smrg#if OPT_BOX_CHARS
376620d2c4d2Smrg	    setupPackedFonts(xw);
376720d2c4d2Smrg
376820d2c4d2Smrg	    if (screen->force_packed) {
376920d2c4d2Smrg		XTermXftFonts *use = &(screen->renderFontNorm[fontnum]);
3770d1603babSmrg		SetFontHeight(screen, win, XftFp(use)->ascent + XftFp(use)->descent);
3771d1603babSmrg		SetFontWidth(screen, win, use->font_info.min_width);
377220d2c4d2Smrg		TRACE(("...packed TrueType font %dx%d vs %d\n",
377320d2c4d2Smrg		       win->f_height,
377420d2c4d2Smrg		       win->f_width,
3775d1603babSmrg		       use->font_info.max_width));
377620d2c4d2Smrg	    }
377720d2c4d2Smrg#endif
377820d2c4d2Smrg	    DUMP_XFT(xw, &(screen->renderFontNorm[fontnum]));
3779d522f475Smrg	}
3780d522f475Smrg    }
3781d522f475Smrg    /*
3782d522f475Smrg     * Are we handling a bitmap font?
3783d522f475Smrg     */
3784492d43a5Smrg    else
3785d522f475Smrg#endif /* OPT_RENDERFONT */
3786d522f475Smrg    {
378720d2c4d2Smrg	if (is_double_width_font(font) && !(screen->fnt_prop)) {
37880bd37d32Smrg	    SetFontWidth(screen, win, font->min_bounds.width);
3789d522f475Smrg	} else {
37900bd37d32Smrg	    SetFontWidth(screen, win, font->max_bounds.width);
3791d522f475Smrg	}
37920bd37d32Smrg	SetFontHeight(screen, win, font->ascent + font->descent);
3793d522f475Smrg	win->f_ascent = font->ascent;
3794d522f475Smrg	win->f_descent = font->descent;
3795d522f475Smrg    }
3796d522f475Smrg    i = 2 * screen->border + sbwidth;
3797d522f475Smrg    j = 2 * screen->border;
3798d522f475Smrg    width = MaxCols(screen) * win->f_width + i;
3799d522f475Smrg    height = MaxRows(screen) * win->f_height + j;
3800956cc18dSsnj    win->fullwidth = (Dimension) width;
3801956cc18dSsnj    win->fullheight = (Dimension) height;
3802d522f475Smrg    win->width = width - i;
3803d522f475Smrg    win->height = height - j;
3804d522f475Smrg
3805d522f475Smrg    TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n",
3806d522f475Smrg	   win->height,
3807d522f475Smrg	   win->width,
3808d522f475Smrg	   win->fullheight,
3809d522f475Smrg	   win->fullwidth,
3810d522f475Smrg	   win->f_height,
3811d522f475Smrg	   win->f_width,
3812d522f475Smrg	   win->f_ascent,
3813d522f475Smrg	   win->f_descent));
381420d2c4d2Smrg
3815d4fba8b9Smrg    checkFontInfo(win->f_height, "height", failed);
3816d4fba8b9Smrg    checkFontInfo(win->f_width, "width", failed);
3817d522f475Smrg}
3818d522f475Smrg
3819d522f475Smrg/* save this information as a side-effect for double-sized characters */
3820d4fba8b9Smrgstatic void
38219a64e1c5SmrgxtermSaveFontInfo(TScreen *screen, XFontStruct *font)
3822d522f475Smrg{
3823956cc18dSsnj    screen->fnt_wide = (Dimension) (font->max_bounds.width);
3824956cc18dSsnj    screen->fnt_high = (Dimension) (font->ascent + font->descent);
3825d522f475Smrg    TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide));
3826d522f475Smrg}
3827d522f475Smrg
3828d522f475Smrg/*
3829d522f475Smrg * After loading a new font, update the structures that use its size.
3830d522f475Smrg */
3831d522f475Smrgvoid
3832d522f475SmrgxtermUpdateFontInfo(XtermWidget xw, Bool doresize)
3833d522f475Smrg{
3834956cc18dSsnj    TScreen *screen = TScreenOf(xw);
3835d522f475Smrg
3836d522f475Smrg    int scrollbar_width;
3837d522f475Smrg    VTwin *win = &(screen->fullVwin);
3838d522f475Smrg
3839d4fba8b9Smrg#if USE_DOUBLE_BUFFER
3840d4fba8b9Smrg    discardRenderDraw(TScreenOf(xw));
3841d4fba8b9Smrg#endif /* USE_DOUBLE_BUFFER */
3842d4fba8b9Smrg
3843d522f475Smrg    scrollbar_width = (xw->misc.scrollbar
3844d522f475Smrg		       ? (screen->scrollWidget->core.width +
3845d522f475Smrg			  BorderWidth(screen->scrollWidget))
3846d522f475Smrg		       : 0);
3847d4fba8b9Smrg    xtermComputeFontInfo(xw, win, GetNormalFont(screen, fNorm)->fs, scrollbar_width);
3848d4fba8b9Smrg    xtermSaveFontInfo(screen, GetNormalFont(screen, fNorm)->fs);
3849d522f475Smrg
3850d522f475Smrg    if (doresize) {
3851d522f475Smrg	if (VWindow(screen)) {
3852d522f475Smrg	    xtermClear(xw);
3853d522f475Smrg	}
3854d4fba8b9Smrg	TRACE(("xtermUpdateFontInfo " TRACE_L "\n"));
3855d522f475Smrg	DoResizeScreen(xw);	/* set to the new natural size */
3856d522f475Smrg	ResizeScrollBar(xw);
3857d522f475Smrg	Redraw();
3858d4fba8b9Smrg	TRACE((TRACE_R " xtermUpdateFontInfo\n"));
3859d522f475Smrg#ifdef SCROLLBAR_RIGHT
3860d522f475Smrg	updateRightScrollbar(xw);
3861d522f475Smrg#endif
3862d522f475Smrg    }
3863d522f475Smrg    xtermSetCursorBox(screen);
3864d522f475Smrg}
3865d522f475Smrg
3866fa3f02f3Smrg#if OPT_BOX_CHARS || OPT_REPORT_FONTS
3867d522f475Smrg
3868d522f475Smrg/*
3869d522f475Smrg * Returns true if the given character is missing from the specified font.
3870d522f475Smrg */
3871d522f475SmrgBool
3872956cc18dSsnjxtermMissingChar(unsigned ch, XTermFonts * font)
3873d522f475Smrg{
3874956cc18dSsnj    Bool result = False;
3875956cc18dSsnj    XFontStruct *fs = font->fs;
3876190d7dceSmrg    XCharStruct *pc = NULL;
3877d522f475Smrg
3878d4fba8b9Smrg    if (fs == NULL) {
3879d4fba8b9Smrg	result = True;
3880d4fba8b9Smrg    } else if (fs->max_byte1 == 0) {
3881d522f475Smrg#if OPT_WIDE_CHARS
3882fa3f02f3Smrg	if (ch < 256)
3883956cc18dSsnj#endif
3884fa3f02f3Smrg	{
3885190d7dceSmrg	    CI_GET_CHAR_INFO_1D(fs, ch, pc);
3886fa3f02f3Smrg	}
3887956cc18dSsnj    }
3888d522f475Smrg#if OPT_WIDE_CHARS
3889956cc18dSsnj    else {
3890fa3f02f3Smrg	unsigned row = (ch >> 8);
3891fa3f02f3Smrg	unsigned col = (ch & 0xff);
3892fa3f02f3Smrg	CI_GET_CHAR_INFO_2D(fs, row, col, pc);
3893956cc18dSsnj    }
3894d522f475Smrg#endif
3895d522f475Smrg
3896190d7dceSmrg    if (pc == NULL || CI_NONEXISTCHAR(pc)) {
3897c48a5815Smrg	TRACE2(("xtermMissingChar %#04x (!exists)\n", ch));
3898956cc18dSsnj	result = True;
3899d522f475Smrg    }
3900d1603babSmrg    if (ch < MaxUChar) {
3901956cc18dSsnj	font->known_missing[ch] = (Char) (result ? 2 : 1);
3902d522f475Smrg    }
3903956cc18dSsnj    return result;
3904d522f475Smrg}
3905fa3f02f3Smrg#endif
3906d522f475Smrg
3907980988aeSmrg#if OPT_BOX_CHARS || OPT_WIDE_CHARS
3908d522f475Smrg/*
3909d522f475Smrg * The grid is arbitrary, enough resolution that nothing's lost in
3910d522f475Smrg * initialization.
3911d522f475Smrg */
3912d522f475Smrg#define BOX_HIGH 60
3913d522f475Smrg#define BOX_WIDE 60
3914d522f475Smrg
3915d522f475Smrg#define MID_HIGH (BOX_HIGH/2)
3916d522f475Smrg#define MID_WIDE (BOX_WIDE/2)
3917d522f475Smrg
3918d522f475Smrg#define CHR_WIDE ((9*BOX_WIDE)/10)
3919d522f475Smrg#define CHR_HIGH ((9*BOX_HIGH)/10)
3920d522f475Smrg
3921d522f475Smrg/*
3922d522f475Smrg * ...since we'll scale the values anyway.
3923d522f475Smrg */
3924d4fba8b9Smrg#define Scale_XY(n,d,f) ((int)(n) * ((int)(f))) / (d)
3925d4fba8b9Smrg#define SCALED_X(n) Scale_XY(n, BOX_WIDE, font_width)
3926d4fba8b9Smrg#define SCALED_Y(n) Scale_XY(n, BOX_HIGH, font_height)
3927e39b573cSmrg#define SCALE_X(n) n = SCALED_X(n)
3928e39b573cSmrg#define SCALE_Y(n) n = SCALED_Y(n)
3929d522f475Smrg
3930d522f475Smrg#define SEG(x0,y0,x1,y1) x0,y0, x1,y1
3931d522f475Smrg
3932d522f475Smrg/*
3933d522f475Smrg * Draw the given graphic character, if it is simple enough (i.e., a
3934d522f475Smrg * line-drawing character).
3935d522f475Smrg */
3936d522f475Smrgvoid
3937d4fba8b9SmrgxtermDrawBoxChar(XTermDraw * params,
3938d522f475Smrg		 unsigned ch,
3939d522f475Smrg		 GC gc,
3940d522f475Smrg		 int x,
3941d522f475Smrg		 int y,
3942d4fba8b9Smrg		 int cells,
3943d4fba8b9Smrg		 Bool xftords)
3944d522f475Smrg{
3945d4fba8b9Smrg    TScreen *screen = TScreenOf(params->xw);
3946d522f475Smrg    /* *INDENT-OFF* */
3947d522f475Smrg    static const short glyph_ht[] = {
3948d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,5*MID_HIGH/6),	/* H */
3949d522f475Smrg	SEG(6*BOX_WIDE/10,  0,		6*BOX_WIDE/10,5*MID_HIGH/6),
3950d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12),
3951d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
3952d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
3953d522f475Smrg	-1
3954d522f475Smrg    }, glyph_ff[] = {
3955d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		6*BOX_WIDE/10,	0),		/* F */
3956d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12),
3957d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		0*BOX_WIDE/3, 5*MID_HIGH/6),
3958d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
3959d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
3960d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
3961d522f475Smrg	-1
3962d522f475Smrg    }, glyph_lf[] = {
3963d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,9*MID_HIGH/12),	/* L */
3964d522f475Smrg	SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12),
3965d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
3966d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
3967d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
3968d522f475Smrg	-1
3969d522f475Smrg    }, glyph_nl[] = {
3970d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10,	0),		/* N */
3971d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		5*BOX_WIDE/6, 5*MID_HIGH/6),
3972d522f475Smrg	SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
3973d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),	/* L */
3974d522f475Smrg	SEG(1*BOX_WIDE/3,   CHR_HIGH,	  CHR_WIDE,	CHR_HIGH),
3975d522f475Smrg	-1
3976d522f475Smrg    }, glyph_vt[] = {
3977d522f475Smrg	SEG(1*BOX_WIDE/10,   0,		5*BOX_WIDE/12,5*MID_HIGH/6),	/* V */
3978d522f475Smrg	SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
3979d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
3980d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
3981d522f475Smrg	-1
3982d522f475Smrg    }, plus_or_minus[] =
3983d522f475Smrg    {
3984d522f475Smrg	SEG(  0,	  5*BOX_HIGH/6,	  CHR_WIDE,   5*BOX_HIGH/6),
3985d522f475Smrg	SEG(  MID_WIDE,	  2*BOX_HIGH/6,	  MID_WIDE,   4*BOX_HIGH/6),
3986d522f475Smrg	SEG(  0,	  3*BOX_HIGH/6,	  CHR_WIDE,   3*BOX_HIGH/6),
3987d522f475Smrg	-1
3988d522f475Smrg    }, lower_right_corner[] =
3989d522f475Smrg    {
3990d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
3991d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	0),
3992d522f475Smrg	-1
3993d522f475Smrg    }, upper_right_corner[] =
3994d522f475Smrg    {
3995d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
3996d522f475Smrg	SEG( MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
3997d522f475Smrg	-1
3998d522f475Smrg    }, upper_left_corner[] =
3999d522f475Smrg    {
4000d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
4001d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
4002d522f475Smrg	-1
4003d522f475Smrg    }, lower_left_corner[] =
4004d522f475Smrg    {
4005d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
4006d522f475Smrg	SEG(  MID_WIDE,	    MID_WIDE,	  BOX_WIDE,	MID_HIGH),
4007d522f475Smrg	-1
4008d522f475Smrg    }, cross[] =
4009d522f475Smrg    {
4010d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
4011d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
4012d522f475Smrg	-1
4013d522f475Smrg    }, scan_line_1[] =
4014d522f475Smrg    {
4015d522f475Smrg	SEG(  0,	    0,		  BOX_WIDE,	0),
4016d522f475Smrg	-1
4017d522f475Smrg    }, scan_line_3[] =
4018d522f475Smrg    {
4019d522f475Smrg	SEG(  0,	    BOX_HIGH/4,	  BOX_WIDE,	BOX_HIGH/4),
4020d522f475Smrg	-1
4021d522f475Smrg    }, scan_line_7[] =
4022d522f475Smrg    {
4023d522f475Smrg	SEG( 0,		    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
4024d522f475Smrg	-1
4025d522f475Smrg    }, scan_line_9[] =
4026d522f475Smrg    {
4027d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  BOX_WIDE,   3*BOX_HIGH/4),
4028d522f475Smrg	-1
4029d522f475Smrg    }, horizontal_line[] =
4030d522f475Smrg    {
4031d522f475Smrg	SEG(  0,	    BOX_HIGH,	  BOX_WIDE,	BOX_HIGH),
4032d522f475Smrg	-1
4033d522f475Smrg    }, left_tee[] =
4034d522f475Smrg    {
4035d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
4036d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
4037d522f475Smrg	-1
4038d522f475Smrg    }, right_tee[] =
4039d522f475Smrg    {
4040d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
4041d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  0,		MID_HIGH),
4042d522f475Smrg	-1
4043d522f475Smrg    }, bottom_tee[] =
4044d522f475Smrg    {
4045d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
4046d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
4047d522f475Smrg	-1
4048d522f475Smrg    }, top_tee[] =
4049d522f475Smrg    {
4050d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
4051d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
4052d522f475Smrg	-1
4053d522f475Smrg    }, vertical_line[] =
4054d522f475Smrg    {
4055d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
4056d522f475Smrg	-1
4057d522f475Smrg    }, less_than_or_equal[] =
4058d522f475Smrg    {
4059d522f475Smrg	SEG(  CHR_WIDE,	    BOX_HIGH/3,	  0,		MID_HIGH),
4060d522f475Smrg	SEG(  CHR_WIDE,	  2*BOX_HIGH/3,	  0,		MID_HIGH),
4061d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
4062d522f475Smrg	-1
4063d522f475Smrg    }, greater_than_or_equal[] =
4064d522f475Smrg    {
4065d522f475Smrg	SEG(  0,	    BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
4066d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
4067d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
4068d522f475Smrg	-1
4069d522f475Smrg    }, greek_pi[] =
4070d522f475Smrg    {
4071d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
4072d522f475Smrg	SEG(5*CHR_WIDE/6,   MID_HIGH,	5*CHR_WIDE/6,	CHR_HIGH),
4073d522f475Smrg	SEG(2*CHR_WIDE/6,   MID_HIGH,	2*CHR_WIDE/6,	CHR_HIGH),
4074d522f475Smrg	-1
4075d522f475Smrg    }, not_equal_to[] =
4076d522f475Smrg    {
4077d522f475Smrg	SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3,	CHR_HIGH),
4078d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,   2*BOX_HIGH/3),
4079d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
4080d522f475Smrg	-1
4081980988aeSmrg    }, sigma_1[] =
4082980988aeSmrg    {
4083980988aeSmrg	SEG(BOX_WIDE,	    MID_HIGH,	  BOX_WIDE/2,	MID_HIGH),
4084980988aeSmrg	SEG(BOX_WIDE/2,	    MID_HIGH,	  BOX_WIDE,	BOX_HIGH),
4085980988aeSmrg	-1
4086980988aeSmrg    }, sigma_2[] =
4087980988aeSmrg    {
4088980988aeSmrg	SEG(BOX_WIDE,	    MID_HIGH,	  BOX_WIDE/2,	MID_HIGH),
4089980988aeSmrg	SEG(BOX_WIDE/2,	    MID_HIGH,	  BOX_WIDE,	0),
4090980988aeSmrg	-1
4091980988aeSmrg    }, sigma_3[] =
4092980988aeSmrg    {
4093980988aeSmrg	SEG(  0,	    0,	  	  BOX_WIDE,	BOX_HIGH),
4094980988aeSmrg	-1
4095980988aeSmrg    }, sigma_4[] =
4096980988aeSmrg    {
4097980988aeSmrg	SEG(  0,	    BOX_HIGH,	  BOX_WIDE,	0),
4098980988aeSmrg	-1
4099980988aeSmrg    }, sigma_5[] =
4100980988aeSmrg    {
4101980988aeSmrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
4102980988aeSmrg	SEG(MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
4103980988aeSmrg	-1
4104980988aeSmrg    }, sigma_6[] =
4105980988aeSmrg    {
4106980988aeSmrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
4107980988aeSmrg	SEG(MID_WIDE,	    MID_HIGH,	  MID_WIDE,	0),
4108980988aeSmrg	-1
4109980988aeSmrg    }, sigma_7[] =
4110980988aeSmrg    {
4111980988aeSmrg	SEG(  0,	    0,		  MID_WIDE,	MID_HIGH),
4112980988aeSmrg	SEG(  0,	    BOX_HIGH,	  MID_WIDE,	MID_HIGH),
4113980988aeSmrg	-1
4114d522f475Smrg    };
4115d522f475Smrg
4116d4fba8b9Smrg    static const struct {
4117d4fba8b9Smrg	const int mode;			/* 1=y, 2=x, 3=both */
4118d1603babSmrg	const short *const data;
4119d4fba8b9Smrg    } lines[] =
4120d522f475Smrg    {
4121190d7dceSmrg	{ 0, NULL },			/* 00 (unused) */
4122190d7dceSmrg	{ 0, NULL },			/* 01 diamond */
4123190d7dceSmrg	{ 0, NULL },			/* 02 box */
4124d4fba8b9Smrg	{ 0, glyph_ht },		/* 03 HT */
4125d4fba8b9Smrg	{ 0, glyph_ff },		/* 04 FF */
4126190d7dceSmrg	{ 0, NULL },			/* 05 CR */
4127d4fba8b9Smrg	{ 0, glyph_lf },		/* 06 LF */
4128190d7dceSmrg	{ 0, NULL },			/* 07 degrees (small circle) */
4129d4fba8b9Smrg	{ 3, plus_or_minus },		/* 08 */
4130d4fba8b9Smrg	{ 0, glyph_nl },		/* 09 */
4131d4fba8b9Smrg	{ 0, glyph_vt },		/* 0A */
4132d4fba8b9Smrg	{ 3, lower_right_corner },	/* 0B */
4133d4fba8b9Smrg	{ 3, upper_right_corner },	/* 0C */
4134d4fba8b9Smrg	{ 3, upper_left_corner },	/* 0D */
4135d4fba8b9Smrg	{ 3, lower_left_corner },	/* 0E */
4136d4fba8b9Smrg	{ 3, cross },			/* 0F */
4137d4fba8b9Smrg	{ 2, scan_line_1 },		/* 10 */
4138d4fba8b9Smrg	{ 2, scan_line_3 },		/* 11 */
4139d4fba8b9Smrg	{ 2, scan_line_7 },		/* 12 */
4140d4fba8b9Smrg	{ 2, scan_line_9 },		/* 13 */
4141d4fba8b9Smrg	{ 2, horizontal_line },		/* 14 */
4142d4fba8b9Smrg	{ 3, left_tee },		/* 15 */
4143d4fba8b9Smrg	{ 3, right_tee },		/* 16 */
4144d4fba8b9Smrg	{ 3, bottom_tee },		/* 17 */
4145d4fba8b9Smrg	{ 3, top_tee },			/* 18 */
4146d4fba8b9Smrg	{ 1, vertical_line },		/* 19 */
4147d4fba8b9Smrg	{ 0, less_than_or_equal },	/* 1A */
4148d4fba8b9Smrg	{ 0, greater_than_or_equal },	/* 1B */
4149d4fba8b9Smrg	{ 0, greek_pi },		/* 1C */
4150d4fba8b9Smrg	{ 0, not_equal_to },		/* 1D */
4151190d7dceSmrg	{ 0, NULL },			/* 1E LB */
4152190d7dceSmrg	{ 0, NULL },			/* 1F bullet */
4153190d7dceSmrg	{ 0, NULL },			/* 20 space */
4154980988aeSmrg	{ 3, sigma_1 },			/* PUA(0) */
4155980988aeSmrg	{ 3, sigma_2 },			/* PUA(1) */
4156980988aeSmrg	{ 3, sigma_3 },			/* PUA(2) */
4157980988aeSmrg	{ 3, sigma_4 },			/* PUA(3) */
4158980988aeSmrg	{ 3, sigma_5 },			/* PUA(4) */
4159980988aeSmrg	{ 3, sigma_6 },			/* PUA(5) */
4160980988aeSmrg	{ 3, sigma_7 },			/* PUA(6) */
4161d522f475Smrg    };
4162d4fba8b9Smrg    /* *INDENT-ON* */
4163d522f475Smrg
4164d522f475Smrg    GC gc2;
4165d522f475Smrg    CgsEnum cgsId = (ch == 2) ? gcDots : gcLine;
4166d522f475Smrg    VTwin *cgsWin = WhichVWin(screen);
4167d522f475Smrg    const short *p;
4168d4fba8b9Smrg    unsigned font_width = (((params->draw_flags & DOUBLEWFONT) ? 2U : 1U)
4169d4fba8b9Smrg			   * screen->fnt_wide);
4170d4fba8b9Smrg    unsigned font_height = (((params->draw_flags & DOUBLEHFONT) ? 2U : 1U)
4171d4fba8b9Smrg			    * screen->fnt_high);
4172d1603babSmrg    unsigned thick;
4173d522f475Smrg
4174d522f475Smrg    if (cells > 1)
4175956cc18dSsnj	font_width *= (unsigned) cells;
4176d522f475Smrg
4177d522f475Smrg#if OPT_WIDE_CHARS
4178d522f475Smrg    /*
4179d522f475Smrg     * Try to show line-drawing characters if we happen to be in UTF-8
4180d522f475Smrg     * mode, but have gotten an old-style font.
4181d522f475Smrg     */
4182d522f475Smrg    if (screen->utf8_mode
4183d522f475Smrg#if OPT_RENDERFONT
4184d4fba8b9Smrg	&& !UsingRenderFont(params->xw)
4185d522f475Smrg#endif
4186d522f475Smrg	&& (ch > 127)
4187980988aeSmrg	&& !is_UCS_SPECIAL(ch)) {
4188d4fba8b9Smrg	int which = (params->attr_flags & BOLD) ? fBold : fNorm;
4189d522f475Smrg	unsigned n;
4190d522f475Smrg	for (n = 1; n < 32; n++) {
4191190d7dceSmrg	    if (xtermMissingChar(n, XTermFontsRef(screen->fnts, which)))
4192d4fba8b9Smrg		continue;
4193d4fba8b9Smrg	    if (dec2ucs(screen, n) != ch)
4194d4fba8b9Smrg		continue;
4195d4fba8b9Smrg	    TRACE(("...use xterm-style linedrawing U+%04X ->%d\n", ch, n));
4196d4fba8b9Smrg	    ch = n;
4197d4fba8b9Smrg	    break;
4198d522f475Smrg	}
4199d522f475Smrg    }
4200d522f475Smrg#endif
4201d522f475Smrg
4202d4fba8b9Smrg#if OPT_VT52_MODE
4203d4fba8b9Smrg    if (!(screen->vtXX_level)) {
4204d4fba8b9Smrg	switch (ch) {
4205d4fba8b9Smrg	case 6:
4206d4fba8b9Smrg	    ch = 7;
4207d4fba8b9Smrg	    break;
4208d4fba8b9Smrg	default:
4209d4fba8b9Smrg	    ch = 256;
4210d4fba8b9Smrg	    break;
4211d4fba8b9Smrg	}
4212d4fba8b9Smrg    }
4213d4fba8b9Smrg#endif
4214d4fba8b9Smrg
4215d4fba8b9Smrg    /*
4216980988aeSmrg     * Line-drawing characters display using the full (scaled) cellsize, while
4217d4fba8b9Smrg     * other characters should be shifted to center them vertically.
4218d4fba8b9Smrg     */
4219d4fba8b9Smrg    if (!xftords) {
4220d4fba8b9Smrg	if ((ch < XtNumber(lines)) && (lines[ch].mode & 3) != 0) {
4221d4fba8b9Smrg	    font_height = (unsigned) ((float) font_height * screen->scale_height);
4222d4fba8b9Smrg	} else {
4223d4fba8b9Smrg	    y += ScaleShift(screen);
4224d4fba8b9Smrg	}
4225d4fba8b9Smrg    }
4226d4fba8b9Smrg
4227980988aeSmrg    if (xtermIsDecTechnical(ch)) {
4228980988aeSmrg	ch -= XTERM_PUA;
4229980988aeSmrg	ch += 33;
4230980988aeSmrg    }
4231980988aeSmrg
4232d4fba8b9Smrg    TRACE(("DRAW_BOX(%02X) cell %dx%d at %d,%d%s\n",
4233d522f475Smrg	   ch, font_height, font_width, y, x,
4234d4fba8b9Smrg	   ((ch >= XtNumber(lines))
4235d522f475Smrg	    ? "-BAD"
4236d522f475Smrg	    : "")));
4237d522f475Smrg
4238d522f475Smrg    if (cgsId == gcDots) {
4239d4fba8b9Smrg	setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc));
4240d4fba8b9Smrg	setCgsFore(params->xw, cgsWin, cgsId, getCgsFore(params->xw, cgsWin, gc));
4241d4fba8b9Smrg	setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc));
4242d522f475Smrg    } else {
4243d4fba8b9Smrg	setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc));
4244d4fba8b9Smrg	setCgsFore(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc));
4245d4fba8b9Smrg	setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc));
4246d522f475Smrg    }
4247d4fba8b9Smrg    gc2 = getCgsGC(params->xw, cgsWin, cgsId);
4248d522f475Smrg
4249d4fba8b9Smrg    if (!(params->draw_flags & NOBACKGROUND)) {
42500bd37d32Smrg	XFillRectangle(screen->display, VDrawable(screen), gc2, x, y,
4251d522f475Smrg		       font_width,
4252d522f475Smrg		       font_height);
4253d522f475Smrg    }
4254d522f475Smrg
4255d4fba8b9Smrg    setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc));
4256d4fba8b9Smrg    setCgsFore(params->xw, cgsWin, cgsId, getCgsFore(params->xw, cgsWin, gc));
4257d4fba8b9Smrg    setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc));
4258d4fba8b9Smrg    gc2 = getCgsGC(params->xw, cgsWin, cgsId);
4259d522f475Smrg
4260d1603babSmrg    thick = ((params->attr_flags & BOLD)
4261d1603babSmrg	     ? (Max((unsigned) screen->fnt_high / 12, 1))
4262980988aeSmrg	     : (Max((unsigned) screen->fnt_high / 16, 1)));
4263980988aeSmrg    setXtermLineAttributes(screen->display, gc2,
4264d1603babSmrg			   thick,
4265d1603babSmrg			   ((ch < XtNumber(lines))
4266d1603babSmrg			    ? LineSolid
4267980988aeSmrg			    : LineOnOffDash));
4268d522f475Smrg
4269980988aeSmrg    if (ch == 32) {		/* space! */
4270980988aeSmrg	;			/* boxing a missing space is pointless */
4271980988aeSmrg    } else if (ch == 1) {	/* diamond */
4272d522f475Smrg	XPoint points[5];
4273d522f475Smrg	int npoints = 5, n;
4274d522f475Smrg
4275d522f475Smrg	points[0].x = MID_WIDE;
4276d522f475Smrg	points[0].y = BOX_HIGH / 4;
4277d522f475Smrg
4278d522f475Smrg	points[1].x = 8 * BOX_WIDE / 8;
4279d522f475Smrg	points[1].y = MID_HIGH;
4280d522f475Smrg
4281d522f475Smrg	points[2].x = points[0].x;
4282d522f475Smrg	points[2].y = 3 * BOX_HIGH / 4;
4283d522f475Smrg
4284d522f475Smrg	points[3].x = 0 * BOX_WIDE / 8;
4285d522f475Smrg	points[3].y = points[1].y;
4286d522f475Smrg
4287d522f475Smrg	points[4].x = points[0].x;
4288d522f475Smrg	points[4].y = points[0].y;
4289d522f475Smrg
4290d522f475Smrg	for (n = 0; n < npoints; ++n) {
4291d4fba8b9Smrg	    points[n].x = (short) (SCALED_X(points[n].x));
4292d4fba8b9Smrg	    points[n].y = (short) (SCALED_Y(points[n].y));
4293e39b573cSmrg	    points[n].x = (short) (points[n].x + x);
4294e39b573cSmrg	    points[n].y = (short) (points[n].y + y);
4295d522f475Smrg	}
4296d522f475Smrg
4297d522f475Smrg	XFillPolygon(screen->display,
42980bd37d32Smrg		     VDrawable(screen), gc2,
4299d522f475Smrg		     points, npoints,
4300d522f475Smrg		     Convex, CoordModeOrigin);
4301d522f475Smrg    } else if (ch == 7) {	/* degrees */
4302d522f475Smrg	unsigned width = (BOX_WIDE / 3);
4303956cc18dSsnj	int x_coord = MID_WIDE - (int) (width / 2);
4304956cc18dSsnj	int y_coord = MID_HIGH - (int) width;
4305d522f475Smrg
4306d522f475Smrg	SCALE_X(x_coord);
4307d522f475Smrg	SCALE_Y(y_coord);
4308e39b573cSmrg	width = (unsigned) SCALED_X(width);
4309d522f475Smrg
4310d522f475Smrg	XDrawArc(screen->display,
43110bd37d32Smrg		 VDrawable(screen), gc2,
4312d522f475Smrg		 x + x_coord, y + y_coord, width, width,
4313d522f475Smrg		 0,
4314d522f475Smrg		 360 * 64);
4315d522f475Smrg    } else if (ch == 0x1f) {	/* bullet */
4316d522f475Smrg	unsigned width = 7 * BOX_WIDE / 10;
4317956cc18dSsnj	int x_coord = MID_WIDE - (int) (width / 3);
4318956cc18dSsnj	int y_coord = MID_HIGH - (int) (width / 3);
4319d522f475Smrg
4320d522f475Smrg	SCALE_X(x_coord);
4321d522f475Smrg	SCALE_Y(y_coord);
4322e39b573cSmrg	width = (unsigned) SCALED_X(width);
4323d522f475Smrg
4324d522f475Smrg	XDrawArc(screen->display,
43250bd37d32Smrg		 VDrawable(screen), gc2,
4326d522f475Smrg		 x + x_coord, y + y_coord, width, width,
4327d522f475Smrg		 0,
4328d522f475Smrg		 360 * 64);
4329d4fba8b9Smrg    } else if (ch < XtNumber(lines)
4330190d7dceSmrg	       && (p = lines[ch].data) != NULL) {
4331956cc18dSsnj	int coord[4];
4332d522f475Smrg	int n = 0;
4333d522f475Smrg	while (*p >= 0) {
4334d522f475Smrg	    coord[n++] = *p++;
4335d522f475Smrg	    if (n == 4) {
4336d522f475Smrg		SCALE_X(coord[0]);
4337d522f475Smrg		SCALE_Y(coord[1]);
4338d522f475Smrg		SCALE_X(coord[2]);
4339d522f475Smrg		SCALE_Y(coord[3]);
4340d522f475Smrg		XDrawLine(screen->display,
43410bd37d32Smrg			  VDrawable(screen), gc2,
4342d522f475Smrg			  x + coord[0], y + coord[1],
4343d522f475Smrg			  x + coord[2], y + coord[3]);
4344d522f475Smrg		n = 0;
4345d522f475Smrg	    }
4346d522f475Smrg	}
4347d522f475Smrg    } else if (screen->force_all_chars) {
4348d522f475Smrg	/* bounding rectangle, for debugging */
4349d1603babSmrg	if ((params->draw_flags & DOUBLEHFONT)) {
4350d1603babSmrg	    XRectangle clip;
4351d1603babSmrg
4352d1603babSmrg	    clip.x = 0;
4353d1603babSmrg	    clip.y = 0;
4354d1603babSmrg	    clip.width = (unsigned short) ((font_width - 1) + (unsigned) thick);
4355d1603babSmrg	    clip.height = (unsigned short) ((unsigned) FontHeight(screen) + thick);
4356d1603babSmrg
4357d1603babSmrg	    if ((params->draw_flags & DOUBLEFIRST)) {
4358d1603babSmrg		y -= (2 * FontDescent(screen));
4359d1603babSmrg		clip.height =
4360d1603babSmrg		    (unsigned short) (clip.height
4361d1603babSmrg				      - ((unsigned short) FontDescent(screen)));
4362d1603babSmrg	    } else {
4363d1603babSmrg		y -= FontHeight(screen);
4364d1603babSmrg		y += FontDescent(screen);
4365d1603babSmrg		clip.y = (short) FontHeight(screen);
4366d1603babSmrg	    }
4367d1603babSmrg	    XSetClipRectangles(screen->display, gc2, x, y, &clip, 1, Unsorted);
4368d1603babSmrg	}
4369d1603babSmrg	XDrawRectangle(screen->display, VDrawable(screen), gc2,
4370d1603babSmrg		       x + (int) thick, y + (int) thick,
4371d1603babSmrg		       font_width - (2 * thick),
4372d1603babSmrg		       font_height - (2 * thick));
4373d1603babSmrg	if ((params->draw_flags & DOUBLEHFONT)) {
4374d1603babSmrg	    XSetClipMask(screen->display, gc2, None);
4375d1603babSmrg	}
4376d522f475Smrg    }
4377980988aeSmrg    resetXtermLineAttributes(screen->display, gc2);
4378d522f475Smrg}
4379980988aeSmrg#endif /* OPT_BOX_CHARS || OPT_WIDE_CHARS */
4380d522f475Smrg
4381d522f475Smrg#if OPT_RENDERFONT
4382d1603babSmrgstatic int
4383d1603babSmrgcheckXftGlyph(XtermWidget xw, XftFont *font, unsigned wc)
4384d1603babSmrg{
4385d1603babSmrg    TScreen *screen = TScreenOf(xw);
4386d1603babSmrg    int result = 0;
4387d1603babSmrg    int expect;
4388d1603babSmrg
4389d1603babSmrg    if ((expect = CharWidth(screen, wc)) > 0) {
4390d1603babSmrg	XGlyphInfo gi;
4391d1603babSmrg	int actual;
4392d1603babSmrg	int limit = (100 + xw->misc.limit_fontwidth);
4393d1603babSmrg
4394d1603babSmrg	XftTextExtents32(screen->display, font, &wc, 1, &gi);
4395d1603babSmrg	/*
4396d1603babSmrg	 * Some (more than a few) fonts are sloppy; allow 10% outside
4397d1603babSmrg	 * the bounding box to accommodate them.
4398d1603babSmrg	 */
4399d1603babSmrg	actual = ((gi.xOff * 100) >= (limit * FontWidth(screen))) ? 2 : 1;
4400d1603babSmrg	if (actual <= expect) {
4401d1603babSmrg	    /* allow double-cell if wcwidth agrees */
4402d1603babSmrg	    result = 1;
4403d1603babSmrg	} else {
4404d1603babSmrg	    /*
4405d1603babSmrg	     * Do not use this font for this specific character, but
4406d1603babSmrg	     * possibly other characters can be used.
4407d1603babSmrg	     */
4408d1603babSmrg	    result = -1;
4409d1603babSmrg	    TRACE(("SKIP U+%04X %d vs %d (%d vs %d) %s\n",
4410d1603babSmrg		   wc, gi.xOff, FontWidth(screen), actual, expect,
4411d1603babSmrg		   nameOfXftFont(font)));
4412d1603babSmrg	}
4413d1603babSmrg    } else {
4414d1603babSmrg	result = 1;
4415d1603babSmrg    }
4416d1603babSmrg    return result;
4417d1603babSmrg}
4418d1603babSmrg
4419d4fba8b9Smrg/*
4420d4fba8b9Smrg * Check if the glyph is defined in the given font, and (try to) filter out
4421d4fba8b9Smrg * cases where double-width glyphs are stuffed into a single-width outline.
4422d4fba8b9Smrg */
4423d1603babSmrgstatic int
4424d1603babSmrgfoundXftGlyph(XtermWidget xw, XTermXftFonts *data, int fontNum, unsigned wc)
4425d4fba8b9Smrg{
4426d1603babSmrg    XftFont *font = XftFpN(data, fontNum);
4427d1603babSmrg    int result = 0;
4428d4fba8b9Smrg
4429190d7dceSmrg    if (font != NULL) {
4430d1603babSmrg	if (!xtermXftMissing(xw, data, fontNum, font, wc)) {
4431d4fba8b9Smrg
4432d1603babSmrg	    if (XftIsN(data, fontNum) == xcBogus) {
4433d1603babSmrg		;
4434d1603babSmrg	    } else if (XftIsN(data, fontNum) == xcOpened) {
4435d1603babSmrg		result = 1;
4436d4fba8b9Smrg	    } else {
4437d1603babSmrg		result = checkXftGlyph(xw, font, wc);
4438d4fba8b9Smrg	    }
4439d4fba8b9Smrg	}
4440d4fba8b9Smrg    }
4441d4fba8b9Smrg    return result;
4442d4fba8b9Smrg}
4443d4fba8b9Smrg
4444d4fba8b9Smrgstatic void
4445d1603babSmrgmarkXftOpened(XtermWidget xw, XTermXftFonts *which, int n, unsigned wc)
4446d4fba8b9Smrg{
4447d1603babSmrg    if (XftIsN(which, n) != xcOpened) {
4448d4fba8b9Smrg	which->opened++;
4449d1603babSmrg	XftIsN(which, n) = xcOpened;
4450d4fba8b9Smrg	/* XFT_DEBUG=3 will show useful context for this */
4451190d7dceSmrg	if (getenv("XFT_DEBUG") != NULL) {
4452d1603babSmrg	    printf("%s: matched U+%04X in fontset #%d [%u:%u]\n",
4453d1603babSmrg		   ProgramName,
4454d4fba8b9Smrg		   wc, n + 1,
4455d4fba8b9Smrg		   which->opened,
4456d4fba8b9Smrg		   xw->work.max_fontsets);
4457d4fba8b9Smrg	}
4458d4fba8b9Smrg    }
4459d4fba8b9Smrg}
4460d4fba8b9Smrg
4461d1603babSmrgstatic char **
4462190d7dceSmrgxftData2List(XtermWidget xw, const XTermXftFonts *fontData)
4463d1603babSmrg{
4464d1603babSmrg    TScreen *screen = TScreenOf(xw);
4465d1603babSmrg    VTFontList *lists = &xw->work.fonts.xft;
4466d1603babSmrg    char **result = NULL;
4467d1603babSmrg    int n = screen->menu_font_number;
4468d1603babSmrg
4469d1603babSmrg    if (fontData == &screen->renderFontNorm[n])
4470d1603babSmrg	result = lists->list_n;
4471d1603babSmrg    else if (fontData == &screen->renderFontBold[n])
4472d1603babSmrg	result = lists->list_b;
4473d1603babSmrg    else if (fontData == &screen->renderFontItal[n])
4474d1603babSmrg	result = lists->list_i;
4475d1603babSmrg    else if (fontData == &screen->renderFontBtal[n])
4476d1603babSmrg	result = lists->list_bi;
4477d1603babSmrg#if OPT_RENDERWIDE
4478d1603babSmrg    if (fontData == &screen->renderWideNorm[n])
4479d1603babSmrg	result = lists->list_w;
4480d1603babSmrg    else if (fontData == &screen->renderWideBold[n])
4481d1603babSmrg	result = lists->list_wb;
4482d1603babSmrg    else if (fontData == &screen->renderWideItal[n])
4483d1603babSmrg	result = lists->list_wi;
4484d1603babSmrg    else if (fontData == &screen->renderWideBtal[n])
4485d1603babSmrg	result = lists->list_wbi;
4486d1603babSmrg#endif
4487d1603babSmrg    return result;
4488d1603babSmrg}
4489d1603babSmrg
4490d1603babSmrgstatic FcPattern *
4491d1603babSmrgmergeXftStyle(XtermWidget xw, FcPattern * myPattern, XTermXftFonts *fontData)
4492d1603babSmrg{
4493d1603babSmrg    TScreen *screen = TScreenOf(xw);
4494d1603babSmrg    Display *dpy = screen->display;
4495d1603babSmrg    XftFont *given = XftFp(fontData);
4496d1603babSmrg    XftResult mStatus;
4497d1603babSmrg    int iValue;
4498d1603babSmrg    double dValue;
4499d1603babSmrg
4500d1603babSmrg    if (FcOK(FcPatternGetInteger(fontData->pattern, XFT_WEIGHT, 0, &iValue))) {
4501d1603babSmrg	FcPatternAddInteger(myPattern, XFT_WEIGHT, iValue);
4502d1603babSmrg    }
4503d1603babSmrg    if (FcOK(FcPatternGetInteger(fontData->pattern, XFT_SLANT, 0, &iValue))) {
4504d1603babSmrg	FcPatternAddInteger(myPattern, XFT_SLANT, iValue);
4505d1603babSmrg    }
4506d1603babSmrg    if (FcOK(FcPatternGetDouble(fontData->pattern, FC_ASPECT, 0, &dValue))) {
4507d1603babSmrg	FcPatternAddDouble(myPattern, FC_ASPECT, dValue);
4508d1603babSmrg    }
4509d1603babSmrg    if (FcOK(FcPatternGetDouble(fontData->pattern, XFT_SIZE, 0, &dValue))) {
4510d1603babSmrg	FcPatternAddDouble(myPattern, XFT_SIZE, dValue);
4511d1603babSmrg    }
4512d1603babSmrg    FcPatternAddBool(myPattern, FC_SCALABLE, FcTrue);
4513d1603babSmrg    FcPatternAddInteger(myPattern, XFT_SPACING, XFT_MONO);
4514d1603babSmrg    FcPatternAddInteger(myPattern, FC_CHAR_WIDTH, given->max_advance_width);
4515d1603babSmrg#ifdef FC_COLOR
4516d1603babSmrg#if !USE_FC_COLOR
4517d1603babSmrg    FcPatternAddBool(myPattern, FC_COLOR, FcFalse);
4518d1603babSmrg#endif
4519d1603babSmrg    FcPatternAddBool(myPattern, FC_OUTLINE, FcTrue);
4520d1603babSmrg#endif
4521d1603babSmrg
4522d1603babSmrg    FcConfigSubstitute(NULL, myPattern, FcMatchPattern);
4523d1603babSmrg    XftDefaultSubstitute(dpy, DefaultScreen(dpy), myPattern);
4524d1603babSmrg
4525d1603babSmrg    return FcFontMatch(NULL, myPattern, &mStatus);
4526d1603babSmrg}
4527d1603babSmrg
4528d4fba8b9Smrg/*
4529d4fba8b9Smrg * Check if the given character has a glyph known to Xft.  If it is missing,
4530d4fba8b9Smrg * try first to replace the font with a fallback that provides the glyph.
4531d1603babSmrg *
4532d1603babSmrg * Return -1 if nothing is found.  Otherwise, return the index in the cache.
4533d4fba8b9Smrg */
4534d1603babSmrgint
4535d1603babSmrgfindXftGlyph(XtermWidget xw, XTermXftFonts *fontData, unsigned wc)
4536d4fba8b9Smrg{
4537d4fba8b9Smrg    TScreen *screen = TScreenOf(xw);
4538d1603babSmrg    XftFont *given;
4539d1603babSmrg    XftFont *actual = NULL;
4540d4fba8b9Smrg    FcResult status;
4541d1603babSmrg    int n;
4542d1603babSmrg    int result = -1;
4543d1603babSmrg
4544d1603babSmrg    /* sanity-check */
4545d1603babSmrg    if (fontData == NULL)
4546d1603babSmrg	return result;
4547d1603babSmrg    given = XftFp(fontData);
4548d4fba8b9Smrg
4549d4fba8b9Smrg    /* if fontsets are not wanted, just leave */
4550d4fba8b9Smrg    if (xw->work.max_fontsets == 0) {
4551d1603babSmrg	return result;
4552d4fba8b9Smrg    }
4553d4fba8b9Smrg
4554d4fba8b9Smrg    /* ignore codes in private use areas */
4555d4fba8b9Smrg    if ((wc >= 0xe000 && wc <= 0xf8ff)
4556d4fba8b9Smrg	|| (wc >= 0xf0000 && wc <= 0xffffd)
4557d4fba8b9Smrg	|| (wc >= 0x100000 && wc <= 0x10fffd)) {
4558d1603babSmrg	return result;
4559d4fba8b9Smrg    }
4560d4fba8b9Smrg    /* the end of the BMP is reserved for non-characters */
4561d4fba8b9Smrg    if (wc >= 0xfff0 && wc <= 0xffff) {
4562d1603babSmrg	return result;
4563d4fba8b9Smrg    }
4564d4fba8b9Smrg
4565d1603babSmrg    /* initialize on the first call */
4566d1603babSmrg    if (fontData->fontset == NULL && fontData->pattern != NULL) {
4567d1603babSmrg	FcFontSet *sortedFonts;
4568d1603babSmrg	FcPattern *myPattern;
4569d1603babSmrg	int j;
4570d1603babSmrg	char **my_list;
4571d4fba8b9Smrg
4572d1603babSmrg	myPattern = FcPatternDuplicate(fontData->pattern);
4573d4fba8b9Smrg
4574d1603babSmrg	FcPatternAddBool(myPattern, FC_SCALABLE, FcTrue);
4575d1603babSmrg	FcPatternAddInteger(myPattern, FC_CHAR_WIDTH, given->max_advance_width);
4576d4fba8b9Smrg
4577d1603babSmrg	FcConfigSubstitute(FcConfigGetCurrent(),
4578d1603babSmrg			   myPattern,
4579d1603babSmrg			   FcMatchPattern);
4580d1603babSmrg	FcDefaultSubstitute(myPattern);
4581d4fba8b9Smrg
4582d1603babSmrg	sortedFonts = FcFontSort(NULL, myPattern, FcTrue, NULL, &status);
4583d4fba8b9Smrg
4584d1603babSmrg	fontData->fontset = FcFontSetCreate();
4585d4fba8b9Smrg
4586190d7dceSmrg	if (fontData->fontset == NULL
4587190d7dceSmrg	    || !sortedFonts
4588190d7dceSmrg	    || sortedFonts->nfont <= 0) {
4589d1603babSmrg	    xtermWarning("did not find any usable TrueType font\n");
4590d1603babSmrg	    return 0;
4591d1603babSmrg	}
4592d1603babSmrg
4593d1603babSmrg	/*
4594d1603babSmrg	 * Check if there are additional fonts in the XtermFontNames.xft for
4595d1603babSmrg	 * this font-data.
4596d1603babSmrg	 */
4597d1603babSmrg	if ((my_list = xftData2List(xw, fontData)) != NULL
4598d1603babSmrg	    && *++my_list != NULL) {
4599d1603babSmrg	    for (j = 0; my_list[j] != NULL; ++j) {
4600d1603babSmrg		FcPattern *extraPattern;
4601190d7dceSmrg		if ((extraPattern = XftNameParse(my_list[j])) != NULL) {
4602d1603babSmrg		    FcPattern *match;
4603d1603babSmrg
4604d1603babSmrg		    match = mergeXftStyle(xw, extraPattern, fontData);
4605d1603babSmrg
4606d1603babSmrg		    if (match != NULL) {
4607d1603babSmrg			FcFontSetAdd(fontData->fontset, match);
4608d1603babSmrg		    }
4609d1603babSmrg		    FcPatternDestroy(extraPattern);
4610d1603babSmrg		}
4611d4fba8b9Smrg	    }
4612d1603babSmrg	}
4613d1603babSmrg
4614d1603babSmrg	for (j = 0; j < sortedFonts->nfont; j++) {
4615d1603babSmrg	    FcPattern *font_pattern;
4616d4fba8b9Smrg
4617d1603babSmrg	    font_pattern = FcFontRenderPrepare(FcConfigGetCurrent(),
4618d1603babSmrg					       myPattern,
4619d1603babSmrg					       sortedFonts->fonts[j]);
4620d1603babSmrg	    if (font_pattern) {
4621d1603babSmrg		FcFontSetAdd(fontData->fontset, font_pattern);
4622d1603babSmrg	    }
4623d4fba8b9Smrg	}
4624d1603babSmrg
4625d1603babSmrg	FcFontSetSortDestroy(sortedFonts);
4626d1603babSmrg	FcPatternDestroy(myPattern);
4627d1603babSmrg
4628d1603babSmrg	fontData->fs_size = Min(MaxXftCache, fontData->fontset->nfont);
4629d1603babSmrg    }
4630d1603babSmrg    if (fontData->fontset != NULL && fontData->fs_size > 0) {
4631d1603babSmrg	XftFont *check;
4632d1603babSmrg	int empty = fontData->fs_size;
4633d1603babSmrg
4634d1603babSmrg	for (n = 1; n <= fontData->fs_size; ++n) {
4635d1603babSmrg	    XTermXftState usage = XftIsN(fontData, n);
4636d1603babSmrg	    if (usage == xcEmpty) {
4637d1603babSmrg		if (empty > n)
4638d1603babSmrg		    empty = n;
4639d1603babSmrg	    } else if (usage == xcOpened
4640d1603babSmrg		       || (usage == xcUnused
4641d1603babSmrg			   && (fontData->opened < xw->work.max_fontsets))) {
4642d1603babSmrg		check = XftFpN(fontData, n);
4643d1603babSmrg		if (foundXftGlyph(xw, fontData, (int) n, wc)) {
4644d1603babSmrg		    markXftOpened(xw, fontData, n, wc);
4645d1603babSmrg		    actual = check;
4646d1603babSmrg		    result = (int) n;
4647d1603babSmrg		    TRACE_FALLBACK(xw, "old", wc, result, actual);
4648d1603babSmrg		    break;
4649d4fba8b9Smrg		}
4650d4fba8b9Smrg	    }
4651d1603babSmrg	}
4652d4fba8b9Smrg
4653d1603babSmrg	if ((actual == NULL)
4654d1603babSmrg	    && (empty <= fontData->fs_size)
4655d1603babSmrg	    && (fontData->opened < xw->work.max_fontsets)) {
4656d1603babSmrg	    FcPattern *myPattern = NULL;
4657d1603babSmrg	    FcPattern *myReport = NULL;
4658d1603babSmrg	    int defer = -1;
4659d1603babSmrg
4660d1603babSmrg	    if (empty == 0)	/* should not happen */
4661d1603babSmrg		empty++;
4662d1603babSmrg
4663d1603babSmrg	    for (n = empty; n <= fontData->fs_size; ++n) {
4664d1603babSmrg		int found;
4665d1603babSmrg		int nn = n - 1;
4666d1603babSmrg
4667d1603babSmrg		if (XftIsN(fontData, n) != xcEmpty) {
4668d1603babSmrg		    continue;
4669d1603babSmrg		}
4670d1603babSmrg		if (resource.reportFonts) {
4671d1603babSmrg		    if (myReport != NULL)
4672d1603babSmrg			FcPatternDestroy(myReport);
4673d1603babSmrg		    myReport = FcPatternDuplicate(fontData->fontset->fonts[nn]);
4674d1603babSmrg		}
4675d1603babSmrg		myPattern = FcPatternDuplicate(fontData->fontset->fonts[nn]);
4676d1603babSmrg		check = XftFontOpenPattern(screen->display, myPattern);
4677d1603babSmrg		(void) maybeXftCache(xw, check);
4678d1603babSmrg		XftFpN(fontData, n) = check;
4679d1603babSmrg		if (check == NULL) {
4680d1603babSmrg		    ;		/* shouldn't happen... */
4681d1603babSmrg		} else
4682d4fba8b9Smrg#ifdef FC_COLOR
4683d1603babSmrg		if (isBogusXft(check)) {
4684d1603babSmrg		    XftIsN(fontData, n) = xcBogus;
4685d1603babSmrg		} else
4686d4fba8b9Smrg#endif
4687d1603babSmrg		    if ((found = foundXftGlyph(xw, fontData, (int) n, wc))
4688d1603babSmrg			!= 0) {
4689d1603babSmrg		    markXftOpened(xw, fontData, n, wc);
4690d1603babSmrg		    reportXftFallbackFont(xw, fontData, (int) n, check, myReport);
4691d1603babSmrg		    if (found < 0) {
4692d1603babSmrg			if (defer < 0) {
4693d1603babSmrg			    defer = (int) n;
4694d1603babSmrg			    TRACE(("Deferring font choice #%d\n", n + 1));
4695d1603babSmrg			    continue;
4696d1603babSmrg			} else if (slowXftMissing(xw, check, wc)) {
4697d1603babSmrg			    TRACE(("Deferred, continuing  #%d\n", n + 1));
4698d1603babSmrg			    continue;
4699d1603babSmrg			}
4700d1603babSmrg		    } else if (defer >= 0) {
4701d1603babSmrg			defer = -1;
4702d1603babSmrg			TRACE(("Deferred, replacing %d with %d\n",
4703d1603babSmrg			       defer + 1, n + 1));
4704d1603babSmrg		    }
4705d1603babSmrg		    actual = check;
4706d1603babSmrg		    result = (int) n;
4707d1603babSmrg		    TRACE_FALLBACK(xw, "new", wc, result, actual);
4708d1603babSmrg		    break;
4709d1603babSmrg		} else {
4710d1603babSmrg		    if (defer >= 0
4711980988aeSmrg			&& !slowXftMissing(xw, check, wc)
4712d1603babSmrg			&& checkXftGlyph(xw, check, wc)) {
4713d1603babSmrg			XTermFontMap *font_map = &(fontData->font_map);
4714d1603babSmrg			TRACE(("checkrecover2 %d\n", n));
4715d1603babSmrg			markXftOpened(xw, fontData, n, wc);
4716d1603babSmrg			reportXftFallbackFont(xw, fontData, (int) n, check, myReport);
4717d1603babSmrg			actual = check;
4718d1603babSmrg			result = (int) n;
4719d1603babSmrg			TRACE_FALLBACK(xw, "fix", wc, result, actual);
4720d1603babSmrg			font_map->per_font[wc] = (XTfontNum) (result + 1);
4721d4fba8b9Smrg			break;
4722d1603babSmrg		    } else {
4723d1603babSmrg			/*
4724d1603babSmrg			 * The slot is opened, but we are not using it yet.
4725d1603babSmrg			 */
4726d1603babSmrg			XftIsN(fontData, n) = xcUnused;
4727d4fba8b9Smrg		    }
4728d4fba8b9Smrg		}
4729d4fba8b9Smrg	    }
4730d1603babSmrg	    if (myReport != NULL)
4731d1603babSmrg		FcPatternDestroy(myReport);
4732d4fba8b9Smrg	}
4733d4fba8b9Smrg    }
4734d4fba8b9Smrg    return result;
4735d4fba8b9Smrg}
4736d522f475Smrg
4737d522f475Smrg/*
4738d4fba8b9Smrg * Check if the given character has a glyph known to Xft.  If it is missing,
4739d4fba8b9Smrg * return true.
4740d522f475Smrg *
4741d522f475Smrg * see xc/lib/Xft/xftglyphs.c
4742d522f475Smrg */
4743d522f475SmrgBool
4744d1603babSmrgxtermXftMissing(XtermWidget xw,
4745d1603babSmrg		XTermXftFonts *data,
4746d1603babSmrg		int fontNum,	/* 0=primary, 1+ is fallback */
4747d1603babSmrg		XftFont *font,	/* actual font if no data */
4748d1603babSmrg		unsigned wc)
4749d522f475Smrg{
4750d1603babSmrg    Bool result = True;
4751d522f475Smrg
4752d1603babSmrg    (void) xw;
4753d1603babSmrg    if (data != NULL && font != NULL) {
4754d1603babSmrg	XTermFontMap *font_map = &(data->font_map);
4755d1603babSmrg	/*
4756d1603babSmrg	 * Each fallback font has one chance to be scanned/cached.
4757d1603babSmrg	 * We record in per_font[] the index of the first font containing a
4758d1603babSmrg	 * given glyph.
4759d1603babSmrg	 */
4760d1603babSmrg	if (font_map->depth <= fontNum) {
4761d1603babSmrg	    FcChar32 last = (xtermXftLastChar(font) | 255) + 1;
4762d1603babSmrg	    FcChar32 base;
4763d1603babSmrg	    FcChar32 nextPage;
4764d1603babSmrg	    FcChar32 map[FC_CHARSET_MAP_SIZE];
4765d1603babSmrg	    unsigned added = 0;
4766d1603babSmrg	    unsigned actual = 0;
4767d1603babSmrg
4768d1603babSmrg	    font_map->depth = (fontNum + 1);
4769d1603babSmrg	    /* allocate space */
4770d1603babSmrg	    if (last > font_map->last_char) {
4771d1603babSmrg		size_t need = (last * sizeof(XTfontNum));
4772d1603babSmrg		size_t c1st = (font_map->last_char * sizeof(XTfontNum));
4773d1603babSmrg		font_map->per_font = realloc(font_map->per_font, need);
4774d1603babSmrg		memset(font_map->per_font + font_map->last_char, 0, (need - c1st));
4775d1603babSmrg		font_map->last_char = last;
4776d1603babSmrg	    }
4777d1603babSmrg
4778d1603babSmrg	    /* scan new font */
4779d1603babSmrg	    base = FcCharSetFirstPage(font->charset, map, &nextPage);
4780d1603babSmrg	    do {
4781d1603babSmrg		unsigned row;
4782d1603babSmrg		unsigned col;
4783d1603babSmrg		FcChar32 bits;
4784d1603babSmrg		for (row = 0; row < FC_CHARSET_MAP_SIZE; ++row) {
4785d1603babSmrg		    bits = map[row];
4786d1603babSmrg		    for (col = 0; col < 32; ++col) {
4787d1603babSmrg			if ((bits & 1) != 0) {
4788d1603babSmrg			    actual++;
4789d1603babSmrg			    if (!font_map->per_font[base]) {
4790d1603babSmrg				font_map->per_font[base] = (Char) font_map->depth;
4791d1603babSmrg				++added;
4792d1603babSmrg			    }
4793d1603babSmrg			}
4794d1603babSmrg			bits >>= 1;
4795d1603babSmrg			++base;
4796d1603babSmrg		    }
4797d1603babSmrg		}
4798d1603babSmrg	    } while ((base = FcCharSetNextPage(font->charset, map,
4799d1603babSmrg					       &nextPage)) != FC_CHARSET_DONE);
4800d1603babSmrg	    (void) added;
4801d1603babSmrg	    (void) actual;
4802d1603babSmrg	    TRACE(("xtermXftMissing U+%04X #%-3d %6u added vs %6u of %6ld %s: %s\n",
4803d1603babSmrg		   wc,
4804d1603babSmrg		   font_map->depth,
4805d1603babSmrg		   added, actual,
4806d1603babSmrg		   font_map->last_char + 1,
4807d1603babSmrg		   whichXftFonts(xw, data),
4808d1603babSmrg		   nameOfXftFont(font)));
4809d1603babSmrg	}
4810d1603babSmrg	if (wc < font_map->last_char) {
4811d1603babSmrg	    result = (font_map->per_font[wc] != (fontNum + 1));
4812d522f475Smrg	}
4813d522f475Smrg    }
4814d522f475Smrg    return result;
4815d522f475Smrg}
4816fa3f02f3Smrg#endif /* OPT_RENDERFONT */
4817d522f475Smrg
4818d522f475Smrg#if OPT_WIDE_CHARS
4819d522f475Smrg#define MY_UCS(ucs,dec) case ucs: result = dec; break
4820d522f475Smrgunsigned
4821d4fba8b9Smrgucs2dec(TScreen *screen, unsigned ch)
4822d522f475Smrg{
4823d522f475Smrg    unsigned result = ch;
4824d4fba8b9Smrg
4825d4fba8b9Smrg    (void) screen;
4826d522f475Smrg    if ((ch > 127)
4827980988aeSmrg	&& !is_UCS_SPECIAL(ch)) {
4828d4fba8b9Smrg#if OPT_VT52_MODE
4829190d7dceSmrg	if (screen != NULL && !(screen->vtXX_level)) {
4830d4fba8b9Smrg	    /*
4831d4fba8b9Smrg	     * Intentionally empty: it would be possible to use the built-in
4832d4fba8b9Smrg	     * line-drawing fallback in xtermDrawBoxChar(), but for testing
4833d4fba8b9Smrg	     * ncurses, this is good enough.
4834d4fba8b9Smrg	     */
4835d4fba8b9Smrg	    ;
4836d4fba8b9Smrg	} else
4837d4fba8b9Smrg#endif
4838d4fba8b9Smrg	    switch (ch) {
4839d4fba8b9Smrg		MY_UCS(0x25ae, 0);	/* black vertical rectangle           */
4840d4fba8b9Smrg		MY_UCS(0x25c6, 1);	/* black diamond                      */
4841d4fba8b9Smrg		MY_UCS(0x2592, 2);	/* medium shade                       */
4842d4fba8b9Smrg		MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation   */
4843d4fba8b9Smrg		MY_UCS(0x240c, 4);	/* symbol for form feed               */
4844d4fba8b9Smrg		MY_UCS(0x240d, 5);	/* symbol for carriage return         */
4845d4fba8b9Smrg		MY_UCS(0x240a, 6);	/* symbol for line feed               */
4846d4fba8b9Smrg		MY_UCS(0x00b0, 7);	/* degree sign                        */
4847d4fba8b9Smrg		MY_UCS(0x00b1, 8);	/* plus-minus sign                    */
4848d4fba8b9Smrg		MY_UCS(0x2424, 9);	/* symbol for newline                 */
4849d4fba8b9Smrg		MY_UCS(0x240b, 10);	/* symbol for vertical tabulation     */
4850d4fba8b9Smrg		MY_UCS(0x2518, 11);	/* box drawings light up and left     */
4851d4fba8b9Smrg		MY_UCS(0x2510, 12);	/* box drawings light down and left   */
4852d4fba8b9Smrg		MY_UCS(0x250c, 13);	/* box drawings light down and right  */
4853d4fba8b9Smrg		MY_UCS(0x2514, 14);	/* box drawings light up and right    */
4854d4fba8b9Smrg		MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
4855d4fba8b9Smrg		MY_UCS(0x23ba, 16);	/* box drawings scan 1                */
4856d4fba8b9Smrg		MY_UCS(0x23bb, 17);	/* box drawings scan 3                */
4857d4fba8b9Smrg		MY_UCS(0x2500, 18);	/* box drawings light horizontal      */
4858d4fba8b9Smrg		MY_UCS(0x23bc, 19);	/* box drawings scan 7                */
4859d4fba8b9Smrg		MY_UCS(0x23bd, 20);	/* box drawings scan 9                */
4860d4fba8b9Smrg		MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
4861d4fba8b9Smrg		MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
4862d4fba8b9Smrg		MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
4863d4fba8b9Smrg		MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
4864d4fba8b9Smrg		MY_UCS(0x2502, 25);	/* box drawings light vertical        */
4865d4fba8b9Smrg		MY_UCS(0x2264, 26);	/* less-than or equal to              */
4866d4fba8b9Smrg		MY_UCS(0x2265, 27);	/* greater-than or equal to           */
4867d4fba8b9Smrg		MY_UCS(0x03c0, 28);	/* greek small letter pi              */
4868d4fba8b9Smrg		MY_UCS(0x2260, 29);	/* not equal to                       */
4869d4fba8b9Smrg		MY_UCS(0x00a3, 30);	/* pound sign                         */
4870d4fba8b9Smrg		MY_UCS(0x00b7, 31);	/* middle dot                         */
4871d4fba8b9Smrg	    }
4872d522f475Smrg    }
4873d522f475Smrg    return result;
4874d522f475Smrg}
4875d522f475Smrg
4876d522f475Smrg#undef  MY_UCS
4877d522f475Smrg#define MY_UCS(ucs,dec) case dec: result = ucs; break
4878d522f475Smrg
4879d522f475Smrgunsigned
4880d4fba8b9Smrgdec2ucs(TScreen *screen, unsigned ch)
4881d522f475Smrg{
4882d522f475Smrg    unsigned result = ch;
4883d4fba8b9Smrg
4884d4fba8b9Smrg    (void) screen;
4885d522f475Smrg    if (xtermIsDecGraphic(ch)) {
4886d4fba8b9Smrg#if OPT_VT52_MODE
4887190d7dceSmrg	if (screen != NULL && !(screen->vtXX_level)) {
4888d4fba8b9Smrg	    switch (ch) {
4889d4fba8b9Smrg		MY_UCS(0x0020, 0);	/* nbsp, treat as blank           */
4890d4fba8b9Smrg		MY_UCS(0x0020, 1);	/* reserved, treat as blank       */
4891d4fba8b9Smrg		MY_UCS(0x25ae, 2);	/* black vertical rectangle       */
4892d4fba8b9Smrg		MY_UCS(0x215f, 3);	/* "1/"                           */
4893d4fba8b9Smrg		MY_UCS(0x0020, 4);	/* "3/", not in Unicode, ignore   */
4894d4fba8b9Smrg		MY_UCS(0x0020, 5);	/* "5/", not in Unicode, ignore   */
4895d4fba8b9Smrg		MY_UCS(0x0020, 6);	/* "7/", not in Unicode, ignore   */
4896d4fba8b9Smrg		MY_UCS(0x00b0, 7);	/* degree sign                    */
4897d4fba8b9Smrg		MY_UCS(0x00b1, 8);	/* plus-minus sign                */
4898d4fba8b9Smrg		MY_UCS(0x2192, 9);	/* right-arrow                    */
4899d4fba8b9Smrg		MY_UCS(0x2026, 10);	/* ellipsis                       */
4900d4fba8b9Smrg		MY_UCS(0x00f7, 11);	/* divide by                      */
4901d4fba8b9Smrg		MY_UCS(0x2193, 12);	/* down arrow                     */
4902d4fba8b9Smrg		MY_UCS(0x23ba, 13);	/* bar at scan 0                  */
4903d4fba8b9Smrg		MY_UCS(0x23ba, 14);	/* bar at scan 1                  */
4904d4fba8b9Smrg		MY_UCS(0x23bb, 15);	/* bar at scan 2                  */
4905d4fba8b9Smrg		MY_UCS(0x23bb, 16);	/* bar at scan 3                  */
4906d4fba8b9Smrg		MY_UCS(0x23bc, 17);	/* bar at scan 4                  */
4907d4fba8b9Smrg		MY_UCS(0x23bc, 18);	/* bar at scan 5                  */
4908d4fba8b9Smrg		MY_UCS(0x23bd, 19);	/* bar at scan 6                  */
4909d4fba8b9Smrg		MY_UCS(0x23bd, 20);	/* bar at scan 7                  */
4910d4fba8b9Smrg		MY_UCS(0x2080, 21);	/* subscript 0                    */
4911d4fba8b9Smrg		MY_UCS(0x2081, 22);	/* subscript 1                    */
4912d4fba8b9Smrg		MY_UCS(0x2082, 23);	/* subscript 2                    */
4913d4fba8b9Smrg		MY_UCS(0x2083, 24);	/* subscript 3                    */
4914d4fba8b9Smrg		MY_UCS(0x2084, 25);	/* subscript 4                    */
4915d4fba8b9Smrg		MY_UCS(0x2085, 26);	/* subscript 5                    */
4916d4fba8b9Smrg		MY_UCS(0x2086, 27);	/* subscript 6                    */
4917d4fba8b9Smrg		MY_UCS(0x2087, 28);	/* subscript 7                    */
4918d4fba8b9Smrg		MY_UCS(0x2088, 29);	/* subscript 8                    */
4919d4fba8b9Smrg		MY_UCS(0x2089, 30);	/* subscript 9                    */
4920d4fba8b9Smrg		MY_UCS(0x00b6, 31);	/* paragraph                      */
4921d4fba8b9Smrg	    }
4922d4fba8b9Smrg	} else
4923d4fba8b9Smrg#endif
4924d4fba8b9Smrg	    switch (ch) {
4925d4fba8b9Smrg		MY_UCS(0x25ae, 0);	/* black vertical rectangle           */
4926d4fba8b9Smrg		MY_UCS(0x25c6, 1);	/* black diamond                      */
4927d4fba8b9Smrg		MY_UCS(0x2592, 2);	/* medium shade                       */
4928d4fba8b9Smrg		MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation   */
4929d4fba8b9Smrg		MY_UCS(0x240c, 4);	/* symbol for form feed               */
4930d4fba8b9Smrg		MY_UCS(0x240d, 5);	/* symbol for carriage return         */
4931d4fba8b9Smrg		MY_UCS(0x240a, 6);	/* symbol for line feed               */
4932d4fba8b9Smrg		MY_UCS(0x00b0, 7);	/* degree sign                        */
4933d4fba8b9Smrg		MY_UCS(0x00b1, 8);	/* plus-minus sign                    */
4934d4fba8b9Smrg		MY_UCS(0x2424, 9);	/* symbol for newline                 */
4935d4fba8b9Smrg		MY_UCS(0x240b, 10);	/* symbol for vertical tabulation     */
4936d4fba8b9Smrg		MY_UCS(0x2518, 11);	/* box drawings light up and left     */
4937d4fba8b9Smrg		MY_UCS(0x2510, 12);	/* box drawings light down and left   */
4938d4fba8b9Smrg		MY_UCS(0x250c, 13);	/* box drawings light down and right  */
4939d4fba8b9Smrg		MY_UCS(0x2514, 14);	/* box drawings light up and right    */
4940d4fba8b9Smrg		MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
4941d4fba8b9Smrg		MY_UCS(0x23ba, 16);	/* box drawings scan 1                */
4942d4fba8b9Smrg		MY_UCS(0x23bb, 17);	/* box drawings scan 3                */
4943d4fba8b9Smrg		MY_UCS(0x2500, 18);	/* box drawings light horizontal      */
4944d4fba8b9Smrg		MY_UCS(0x23bc, 19);	/* box drawings scan 7                */
4945d4fba8b9Smrg		MY_UCS(0x23bd, 20);	/* box drawings scan 9                */
4946d4fba8b9Smrg		MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
4947d4fba8b9Smrg		MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
4948d4fba8b9Smrg		MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
4949d4fba8b9Smrg		MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
4950d4fba8b9Smrg		MY_UCS(0x2502, 25);	/* box drawings light vertical        */
4951d4fba8b9Smrg		MY_UCS(0x2264, 26);	/* less-than or equal to              */
4952d4fba8b9Smrg		MY_UCS(0x2265, 27);	/* greater-than or equal to           */
4953d4fba8b9Smrg		MY_UCS(0x03c0, 28);	/* greek small letter pi              */
4954d4fba8b9Smrg		MY_UCS(0x2260, 29);	/* not equal to                       */
4955d4fba8b9Smrg		MY_UCS(0x00a3, 30);	/* pound sign                         */
4956d4fba8b9Smrg		MY_UCS(0x00b7, 31);	/* middle dot                         */
4957d4fba8b9Smrg	    }
4958d522f475Smrg    }
4959d522f475Smrg    return result;
4960d522f475Smrg}
4961d522f475Smrg
4962d522f475Smrg#endif /* OPT_WIDE_CHARS */
4963d522f475Smrg
4964b6fea0ceSmrg#if OPT_RENDERFONT || OPT_SHIFT_FONTS
49650bd37d32Smrgstatic int
4966d522f475SmrglookupOneFontSize(XtermWidget xw, int fontnum)
4967d522f475Smrg{
4968d522f475Smrg    TScreen *screen = TScreenOf(xw);
4969d522f475Smrg
4970d522f475Smrg    if (screen->menu_font_sizes[fontnum] == 0) {
4971d522f475Smrg	XTermFonts fnt;
4972d522f475Smrg
4973d522f475Smrg	memset(&fnt, 0, sizeof(fnt));
4974d522f475Smrg	screen->menu_font_sizes[fontnum] = -1;
4975d1603babSmrg	if (xtermOpenFont(xw, screen->MenuFontName(fontnum), &fnt, NULL, True)) {
497620d2c4d2Smrg	    if (fontnum <= fontMenu_lastBuiltin
49770bd37d32Smrg		|| strcmp(fnt.fn, DEFFONT)) {
497820d2c4d2Smrg		screen->menu_font_sizes[fontnum] = FontSize(fnt.fs);
49790bd37d32Smrg		if (screen->menu_font_sizes[fontnum] <= 0)
49800bd37d32Smrg		    screen->menu_font_sizes[fontnum] = -1;
49810bd37d32Smrg	    }
4982d522f475Smrg	    xtermCloseFont(xw, &fnt);
4983d522f475Smrg	}
4984d522f475Smrg    }
49850bd37d32Smrg    return (screen->menu_font_sizes[fontnum] > 0);
4986d522f475Smrg}
4987d522f475Smrg
4988d522f475Smrg/*
4989d522f475Smrg * Cache the font-sizes so subsequent larger/smaller font actions will go fast.
4990d522f475Smrg */
4991d522f475Smrgstatic void
4992d522f475SmrglookupFontSizes(XtermWidget xw)
4993d522f475Smrg{
4994d522f475Smrg    int n;
4995d522f475Smrg
4996d522f475Smrg    for (n = 0; n < NMENUFONTS; n++) {
49970bd37d32Smrg	(void) lookupOneFontSize(xw, n);
4998d522f475Smrg    }
4999d522f475Smrg}
5000b6fea0ceSmrg#endif /* OPT_RENDERFONT || OPT_SHIFT_FONTS */
5001d522f475Smrg
50022eaa94a1Schristos#if OPT_RENDERFONT
50039a64e1c5Smrgstatic double
50049a64e1c5SmrgdefaultFaceSize(void)
50059a64e1c5Smrg{
50069a64e1c5Smrg    double result;
50079a64e1c5Smrg    float value;
50089a64e1c5Smrg
50099a64e1c5Smrg    if (sscanf(DEFFACESIZE, "%f", &value) == 1)
5010d4fba8b9Smrg	result = (double) value;
50119a64e1c5Smrg    else
50129a64e1c5Smrg	result = 14.0;
50139a64e1c5Smrg    return result;
50149a64e1c5Smrg}
50159a64e1c5Smrg
50160bd37d32Smrgstatic void
50170bd37d32SmrgfillInFaceSize(XtermWidget xw, int fontnum)
50180bd37d32Smrg{
50190bd37d32Smrg    TScreen *screen = TScreenOf(xw);
5020d4fba8b9Smrg    double face_size = (double) xw->misc.face_size[fontnum];
50210bd37d32Smrg
50220bd37d32Smrg    if (face_size <= 0.0) {
50230bd37d32Smrg#if OPT_SHIFT_FONTS
50240bd37d32Smrg	/*
50250bd37d32Smrg	 * If the user is switching font-sizes, make it follow by
50260bd37d32Smrg	 * default the same ratios to the default as the fixed fonts
50270bd37d32Smrg	 * would, for easy comparison.  There will be some differences
50280bd37d32Smrg	 * since the fixed fonts have a variety of height/width ratios,
50290bd37d32Smrg	 * but this is simpler than adding another resource value - and
50300bd37d32Smrg	 * as noted above, the data for the fixed fonts are available.
50310bd37d32Smrg	 */
50320bd37d32Smrg	(void) lookupOneFontSize(xw, 0);
50330bd37d32Smrg	if (fontnum == fontMenu_default) {
50349a64e1c5Smrg	    face_size = defaultFaceSize();
50350bd37d32Smrg	} else if (lookupOneFontSize(xw, fontnum)
50360bd37d32Smrg		   && (screen->menu_font_sizes[0]
50370bd37d32Smrg		       != screen->menu_font_sizes[fontnum])) {
50380bd37d32Smrg	    double ratio;
50390bd37d32Smrg	    long num = screen->menu_font_sizes[fontnum];
50400bd37d32Smrg	    long den = screen->menu_font_sizes[0];
50410bd37d32Smrg
50420bd37d32Smrg	    if (den <= 0)
50430bd37d32Smrg		den = 1;
50440bd37d32Smrg	    ratio = dimSquareRoot((double) num / (double) den);
50450bd37d32Smrg
5046d4fba8b9Smrg	    face_size = (ratio * (double) xw->misc.face_size[0]);
50470bd37d32Smrg	    TRACE(("scaled[%d] using %3ld/%ld = %.2f -> %f\n",
50480bd37d32Smrg		   fontnum, num, den, ratio, face_size));
50490bd37d32Smrg	} else
50500bd37d32Smrg#endif
50510bd37d32Smrg	{
5052d4fba8b9Smrg#define LikeBitmap(s) (((s) / 78.0) * (double) xw->misc.face_size[fontMenu_default])
50530bd37d32Smrg	    switch (fontnum) {
50540bd37d32Smrg	    case fontMenu_font1:
50550bd37d32Smrg		face_size = LikeBitmap(2.0);
50560bd37d32Smrg		break;
50570bd37d32Smrg	    case fontMenu_font2:
50580bd37d32Smrg		face_size = LikeBitmap(35.0);
50590bd37d32Smrg		break;
50600bd37d32Smrg	    case fontMenu_font3:
50610bd37d32Smrg		face_size = LikeBitmap(60.0);
50620bd37d32Smrg		break;
50630bd37d32Smrg	    default:
50649a64e1c5Smrg		face_size = defaultFaceSize();
50650bd37d32Smrg		break;
50660bd37d32Smrg	    case fontMenu_font4:
50670bd37d32Smrg		face_size = LikeBitmap(90.0);
50680bd37d32Smrg		break;
50690bd37d32Smrg	    case fontMenu_font5:
50700bd37d32Smrg		face_size = LikeBitmap(135.0);
50710bd37d32Smrg		break;
50720bd37d32Smrg	    case fontMenu_font6:
50730bd37d32Smrg		face_size = LikeBitmap(200.0);
50740bd37d32Smrg		break;
5075d4fba8b9Smrg	    case fontMenu_font7:
5076d4fba8b9Smrg		face_size = LikeBitmap(240.0);
5077d4fba8b9Smrg		break;
50780bd37d32Smrg	    }
50790bd37d32Smrg	    TRACE(("builtin[%d] -> %f\n", fontnum, face_size));
50800bd37d32Smrg	}
50810bd37d32Smrg	xw->misc.face_size[fontnum] = (float) face_size;
50820bd37d32Smrg    }
50830bd37d32Smrg}
50840bd37d32Smrg
50850bd37d32Smrg/* no selection or escape */
50860bd37d32Smrg#define NMENU_RENDERFONTS (fontMenu_lastBuiltin + 1)
50870bd37d32Smrg
50880bd37d32Smrg/*
50890bd37d32Smrg * Workaround for breakage in font-packages - check if all of the bitmap font
50900bd37d32Smrg * sizes are the same, and if we're using TrueType fonts.
50910bd37d32Smrg */
50922eaa94a1Schristosstatic Boolean
50932eaa94a1SchristosuseFaceSizes(XtermWidget xw)
50942eaa94a1Schristos{
50952eaa94a1Schristos    Boolean result = False;
50962eaa94a1Schristos
5097d4fba8b9Smrg    TRACE(("useFaceSizes " TRACE_L "\n"));
50982eaa94a1Schristos    if (UsingRenderFont(xw)) {
50990bd37d32Smrg	Boolean nonzero = True;
5100037a25ddSmrg	int n;
51010bd37d32Smrg
51022eaa94a1Schristos	for (n = 0; n < NMENU_RENDERFONTS; ++n) {
5103d4fba8b9Smrg	    if (xw->misc.face_size[n] <= 0.0f) {
51040bd37d32Smrg		nonzero = False;
51052eaa94a1Schristos		break;
51062eaa94a1Schristos	    }
51072eaa94a1Schristos	}
51080bd37d32Smrg	if (!nonzero) {
5109956cc18dSsnj	    Boolean broken_fonts = True;
5110956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
51110bd37d32Smrg	    long first;
5112956cc18dSsnj
5113956cc18dSsnj	    lookupFontSizes(xw);
51140bd37d32Smrg	    first = screen->menu_font_sizes[0];
5115956cc18dSsnj	    for (n = 0; n < NMENUFONTS; n++) {
5116956cc18dSsnj		if (screen->menu_font_sizes[n] > 0
5117956cc18dSsnj		    && screen->menu_font_sizes[n] != first) {
5118956cc18dSsnj		    broken_fonts = False;
5119956cc18dSsnj		    break;
5120956cc18dSsnj		}
5121956cc18dSsnj	    }
5122956cc18dSsnj
5123956cc18dSsnj	    if (broken_fonts) {
5124956cc18dSsnj
5125956cc18dSsnj		TRACE(("bitmap fonts are broken - set faceSize resources\n"));
5126956cc18dSsnj		for (n = 0; n < NMENUFONTS; n++) {
51270bd37d32Smrg		    fillInFaceSize(xw, n);
5128956cc18dSsnj		}
5129956cc18dSsnj
5130956cc18dSsnj	    }
5131956cc18dSsnj	}
51320bd37d32Smrg	result = True;
51332eaa94a1Schristos    }
5134d4fba8b9Smrg    TRACE((TRACE_R " useFaceSizes %d\n", result));
51352eaa94a1Schristos    return result;
51362eaa94a1Schristos}
51370bd37d32Smrg#endif /* OPT_RENDERFONT */
51382eaa94a1Schristos
5139b6fea0ceSmrg#if OPT_SHIFT_FONTS
5140d522f475Smrg/*
5141d522f475Smrg * Find the index of a larger/smaller font (according to the sign of 'relative'
5142d522f475Smrg * and its magnitude), starting from the 'old' index.
5143d522f475Smrg */
5144d522f475Smrgint
5145d522f475SmrglookupRelativeFontSize(XtermWidget xw, int old, int relative)
5146d522f475Smrg{
5147d522f475Smrg    TScreen *screen = TScreenOf(xw);
5148037a25ddSmrg    int m = -1;
5149d522f475Smrg
51502eaa94a1Schristos    TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative));
5151d522f475Smrg    if (!IsIcon(screen)) {
51522eaa94a1Schristos#if OPT_RENDERFONT
51532eaa94a1Schristos	if (useFaceSizes(xw)) {
51542eaa94a1Schristos	    TRACE(("...using FaceSize\n"));
51552eaa94a1Schristos	    if (relative != 0) {
5156037a25ddSmrg		int n;
51572eaa94a1Schristos		for (n = 0; n < NMENU_RENDERFONTS; ++n) {
51580bd37d32Smrg		    fillInFaceSize(xw, n);
51592eaa94a1Schristos		    if (xw->misc.face_size[n] > 0 &&
51602eaa94a1Schristos			xw->misc.face_size[n] != xw->misc.face_size[old]) {
51612eaa94a1Schristos			int cmp_0 = ((xw->misc.face_size[n] >
51622eaa94a1Schristos				      xw->misc.face_size[old])
51632eaa94a1Schristos				     ? relative
51642eaa94a1Schristos				     : -relative);
51652eaa94a1Schristos			int cmp_m = ((m < 0)
51662eaa94a1Schristos				     ? 1
51672eaa94a1Schristos				     : ((xw->misc.face_size[n] <
51682eaa94a1Schristos					 xw->misc.face_size[m])
51692eaa94a1Schristos					? relative
51702eaa94a1Schristos					: -relative));
51712eaa94a1Schristos			if (cmp_0 > 0 && cmp_m > 0) {
51722eaa94a1Schristos			    m = n;
51732eaa94a1Schristos			}
5174d522f475Smrg		    }
5175d522f475Smrg		}
5176d522f475Smrg	    }
51772eaa94a1Schristos	} else
51782eaa94a1Schristos#endif
51792eaa94a1Schristos	{
51802eaa94a1Schristos	    TRACE(("...using bitmap areas\n"));
51812eaa94a1Schristos	    lookupFontSizes(xw);
51822eaa94a1Schristos	    if (relative != 0) {
5183037a25ddSmrg		int n;
51842eaa94a1Schristos		for (n = 0; n < NMENUFONTS; ++n) {
51852eaa94a1Schristos		    if (screen->menu_font_sizes[n] > 0 &&
51862eaa94a1Schristos			screen->menu_font_sizes[n] !=
51872eaa94a1Schristos			screen->menu_font_sizes[old]) {
51882eaa94a1Schristos			int cmp_0 = ((screen->menu_font_sizes[n] >
51892eaa94a1Schristos				      screen->menu_font_sizes[old])
51902eaa94a1Schristos				     ? relative
51912eaa94a1Schristos				     : -relative);
51922eaa94a1Schristos			int cmp_m = ((m < 0)
51932eaa94a1Schristos				     ? 1
51942eaa94a1Schristos				     : ((screen->menu_font_sizes[n] <
51952eaa94a1Schristos					 screen->menu_font_sizes[m])
51962eaa94a1Schristos					? relative
51972eaa94a1Schristos					: -relative));
51982eaa94a1Schristos			if (cmp_0 > 0 && cmp_m > 0) {
51992eaa94a1Schristos			    m = n;
52002eaa94a1Schristos			}
52012eaa94a1Schristos		    }
52022eaa94a1Schristos		}
5203d522f475Smrg	    }
5204d522f475Smrg	}
52052eaa94a1Schristos	TRACE(("...new index %d\n", m));
52062eaa94a1Schristos	if (m >= 0) {
52072eaa94a1Schristos	    if (relative > 1)
52082eaa94a1Schristos		m = lookupRelativeFontSize(xw, m, relative - 1);
52092eaa94a1Schristos	    else if (relative < -1)
52102eaa94a1Schristos		m = lookupRelativeFontSize(xw, m, relative + 1);
52112eaa94a1Schristos	}
5212d522f475Smrg    }
5213d522f475Smrg    return m;
5214d522f475Smrg}
5215d522f475Smrg
5216d522f475Smrg/* ARGSUSED */
5217d522f475Smrgvoid
5218d4fba8b9SmrgHandleLargerFont(Widget w,
52199a64e1c5Smrg		 XEvent *event GCC_UNUSED,
5220fa3f02f3Smrg		 String *params GCC_UNUSED,
5221d522f475Smrg		 Cardinal *param_count GCC_UNUSED)
5222d522f475Smrg{
5223956cc18dSsnj    XtermWidget xw;
5224d522f475Smrg
522520d2c4d2Smrg    TRACE(("Handle larger-vt-font for %p\n", (void *) w));
5226190d7dceSmrg    if ((xw = getXtermWidget(w)) != NULL) {
5227d522f475Smrg	if (xw->misc.shift_fonts) {
5228956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
5229d522f475Smrg	    int m;
5230d522f475Smrg
5231d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, 1);
5232d522f475Smrg	    if (m >= 0) {
5233d522f475Smrg		SetVTFont(xw, m, True, NULL);
5234d522f475Smrg	    } else {
523520d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
5236d522f475Smrg	    }
5237d522f475Smrg	}
5238d522f475Smrg    }
5239d522f475Smrg}
5240d522f475Smrg
5241d522f475Smrg/* ARGSUSED */
5242d522f475Smrgvoid
5243d4fba8b9SmrgHandleSmallerFont(Widget w,
52449a64e1c5Smrg		  XEvent *event GCC_UNUSED,
5245fa3f02f3Smrg		  String *params GCC_UNUSED,
5246d522f475Smrg		  Cardinal *param_count GCC_UNUSED)
5247d522f475Smrg{
5248956cc18dSsnj    XtermWidget xw;
5249d522f475Smrg
525020d2c4d2Smrg    TRACE(("Handle smaller-vt-font for %p\n", (void *) w));
5251190d7dceSmrg    if ((xw = getXtermWidget(w)) != NULL) {
5252d522f475Smrg	if (xw->misc.shift_fonts) {
5253956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
5254d522f475Smrg	    int m;
5255d522f475Smrg
5256d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, -1);
5257d522f475Smrg	    if (m >= 0) {
5258d522f475Smrg		SetVTFont(xw, m, True, NULL);
5259d522f475Smrg	    } else {
526020d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
5261d522f475Smrg	    }
5262d522f475Smrg	}
5263d522f475Smrg    }
5264d522f475Smrg}
5265b6fea0ceSmrg#endif /* OPT_SHIFT_FONTS */
5266d522f475Smrg
5267d522f475Smrgint
5268d522f475SmrgxtermGetFont(const char *param)
5269d522f475Smrg{
5270d522f475Smrg    int fontnum;
5271d522f475Smrg
5272d1603babSmrg    if (param == NULL)
5273d1603babSmrg	param = "";
5274d1603babSmrg
5275d522f475Smrg    switch (param[0]) {
5276d522f475Smrg    case 'd':
5277d522f475Smrg    case 'D':
5278d522f475Smrg    case '0':
5279d522f475Smrg	fontnum = fontMenu_default;
5280d522f475Smrg	break;
5281d522f475Smrg    case '1':
5282d522f475Smrg	fontnum = fontMenu_font1;
5283d522f475Smrg	break;
5284d522f475Smrg    case '2':
5285d522f475Smrg	fontnum = fontMenu_font2;
5286d522f475Smrg	break;
5287d522f475Smrg    case '3':
5288d522f475Smrg	fontnum = fontMenu_font3;
5289d522f475Smrg	break;
5290d522f475Smrg    case '4':
5291d522f475Smrg	fontnum = fontMenu_font4;
5292d522f475Smrg	break;
5293d522f475Smrg    case '5':
5294d522f475Smrg	fontnum = fontMenu_font5;
5295d522f475Smrg	break;
5296d522f475Smrg    case '6':
5297d522f475Smrg	fontnum = fontMenu_font6;
5298d522f475Smrg	break;
5299d4fba8b9Smrg    case '7':
5300d4fba8b9Smrg	fontnum = fontMenu_font7;
5301d4fba8b9Smrg	break;
5302d522f475Smrg    case 'e':
5303d522f475Smrg    case 'E':
5304d522f475Smrg	fontnum = fontMenu_fontescape;
5305d522f475Smrg	break;
5306d522f475Smrg    case 's':
5307d522f475Smrg    case 'S':
5308d522f475Smrg	fontnum = fontMenu_fontsel;
5309d522f475Smrg	break;
5310d522f475Smrg    default:
5311d522f475Smrg	fontnum = -1;
5312d522f475Smrg	break;
5313d522f475Smrg    }
5314d1603babSmrg    TRACE(("xtermGetFont(%s) ->%d\n", param, fontnum));
5315d522f475Smrg    return fontnum;
5316d522f475Smrg}
5317d522f475Smrg
5318d522f475Smrg/* ARGSUSED */
5319d522f475Smrgvoid
5320d4fba8b9SmrgHandleSetFont(Widget w,
53219a64e1c5Smrg	      XEvent *event GCC_UNUSED,
5322fa3f02f3Smrg	      String *params,
5323d522f475Smrg	      Cardinal *param_count)
5324d522f475Smrg{
5325956cc18dSsnj    XtermWidget xw;
5326956cc18dSsnj
5327190d7dceSmrg    if ((xw = getXtermWidget(w)) != NULL) {
5328d522f475Smrg	int fontnum;
5329d522f475Smrg	VTFontNames fonts;
5330d522f475Smrg
5331d522f475Smrg	memset(&fonts, 0, sizeof(fonts));
5332d522f475Smrg
5333d522f475Smrg	if (*param_count == 0) {
5334d522f475Smrg	    fontnum = fontMenu_default;
5335d522f475Smrg	} else {
5336d522f475Smrg	    Cardinal maxparams = 1;	/* total number of params allowed */
5337d522f475Smrg	    int result = xtermGetFont(params[0]);
5338d522f475Smrg
5339d522f475Smrg	    switch (result) {
5340d522f475Smrg	    case fontMenu_default:	/* FALLTHRU */
5341d522f475Smrg	    case fontMenu_font1:	/* FALLTHRU */
5342d522f475Smrg	    case fontMenu_font2:	/* FALLTHRU */
5343d522f475Smrg	    case fontMenu_font3:	/* FALLTHRU */
5344d522f475Smrg	    case fontMenu_font4:	/* FALLTHRU */
5345d522f475Smrg	    case fontMenu_font5:	/* FALLTHRU */
5346d522f475Smrg	    case fontMenu_font6:	/* FALLTHRU */
5347d4fba8b9Smrg	    case fontMenu_font7:	/* FALLTHRU */
5348d522f475Smrg		break;
5349d522f475Smrg	    case fontMenu_fontescape:
5350d522f475Smrg#if OPT_WIDE_CHARS
5351d522f475Smrg		maxparams = 5;
5352d522f475Smrg#else
5353d522f475Smrg		maxparams = 3;
5354d522f475Smrg#endif
5355d522f475Smrg		break;
5356d522f475Smrg	    case fontMenu_fontsel:
5357d522f475Smrg		maxparams = 2;
5358d522f475Smrg		break;
5359d522f475Smrg	    default:
536020d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
5361d522f475Smrg		return;
5362d522f475Smrg	    }
5363d522f475Smrg	    fontnum = result;
5364d522f475Smrg
5365d522f475Smrg	    if (*param_count > maxparams) {	/* see if extra args given */
536620d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
5367d522f475Smrg		return;
5368d522f475Smrg	    }
5369d522f475Smrg	    switch (*param_count) {	/* assign 'em */
5370d522f475Smrg#if OPT_WIDE_CHARS
5371d522f475Smrg	    case 5:
5372dfb07bc7Smrg		fonts.f_wb = x_strdup(params[4]);
5373d522f475Smrg		/* FALLTHRU */
5374d522f475Smrg	    case 4:
5375dfb07bc7Smrg		fonts.f_w = x_strdup(params[3]);
5376d522f475Smrg#endif
5377dfb07bc7Smrg		/* FALLTHRU */
5378d522f475Smrg	    case 3:
5379dfb07bc7Smrg		fonts.f_b = x_strdup(params[2]);
5380d522f475Smrg		/* FALLTHRU */
5381d522f475Smrg	    case 2:
5382dfb07bc7Smrg		fonts.f_n = x_strdup(params[1]);
5383d522f475Smrg		break;
5384d522f475Smrg	    }
5385d522f475Smrg	}
5386d522f475Smrg
5387956cc18dSsnj	SetVTFont(xw, fontnum, True, &fonts);
5388d522f475Smrg    }
5389d522f475Smrg}
5390d522f475Smrg
5391d1603babSmrgBool
5392d522f475SmrgSetVTFont(XtermWidget xw,
5393d522f475Smrg	  int which,
5394d522f475Smrg	  Bool doresize,
5395d522f475Smrg	  const VTFontNames * fonts)
5396d522f475Smrg{
5397956cc18dSsnj    TScreen *screen = TScreenOf(xw);
5398d1603babSmrg    Bool result = False;
5399d522f475Smrg
5400d522f475Smrg    TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which,
5401d522f475Smrg	   (fonts && fonts->f_n) ? fonts->f_n : "<null>",
5402d522f475Smrg	   (fonts && fonts->f_b) ? fonts->f_b : "<null>"));
5403d522f475Smrg
5404d522f475Smrg    if (IsIcon(screen)) {
540520d2c4d2Smrg	Bell(xw, XkbBI_MinorError, 0);
5406d522f475Smrg    } else if (which >= 0 && which < NMENUFONTS) {
5407d1603babSmrg	VTFontNames new_fnames;
5408d522f475Smrg
5409d1603babSmrg	memset(&new_fnames, 0, sizeof(new_fnames));
5410190d7dceSmrg	if (fonts != NULL)
5411d1603babSmrg	    new_fnames = *fonts;
5412d522f475Smrg
5413d522f475Smrg	if (which == fontMenu_fontsel) {	/* go get the selection */
5414d1603babSmrg	    result = FindFontSelection(xw, new_fnames.f_n, False);
5415d522f475Smrg	} else {
5416d522f475Smrg#define USE_CACHED(field, name) \
5417d1603babSmrg	    if (new_fnames.field == NULL) { \
5418d1603babSmrg		new_fnames.field = x_strdup(screen->menu_font_names[which][name]); \
5419d1603babSmrg		TRACE(("set new_fnames." #field " from menu_font_names[%d][" #name "] %s\n", \
5420d1603babSmrg		       which, NonNull(new_fnames.field))); \
5421d522f475Smrg	    } else { \
5422d1603babSmrg		TRACE(("set new_fnames." #field " reused\n")); \
5423d522f475Smrg	    }
542420d2c4d2Smrg#define SAVE_FNAME(field, name) \
5425d1603babSmrg	    if (new_fnames.field != NULL \
5426d1603babSmrg		&& (screen->menu_font_names[which][name] == NULL \
5427d1603babSmrg		 || strcmp(screen->menu_font_names[which][name], new_fnames.field))) { \
5428d1603babSmrg		TRACE(("updating menu_font_names[%d][" #name "] to \"%s\"\n", \
5429d1603babSmrg		       which, new_fnames.field)); \
5430d1603babSmrg		FREE_STRING(screen->menu_font_names[which][name]); \
5431d1603babSmrg		screen->menu_font_names[which][name] = x_strdup(new_fnames.field); \
543220d2c4d2Smrg	    }
543320d2c4d2Smrg
5434d522f475Smrg	    USE_CACHED(f_n, fNorm);
5435d522f475Smrg	    USE_CACHED(f_b, fBold);
5436d522f475Smrg#if OPT_WIDE_CHARS
5437d522f475Smrg	    USE_CACHED(f_w, fWide);
5438d522f475Smrg	    USE_CACHED(f_wb, fWBold);
5439d522f475Smrg#endif
5440d522f475Smrg	    if (xtermLoadFont(xw,
5441d1603babSmrg			      &new_fnames,
5442d522f475Smrg			      doresize, which)) {
544320d2c4d2Smrg		/*
544420d2c4d2Smrg		 * If successful, save the data so that a subsequent query via
544520d2c4d2Smrg		 * OSC-50 will return the expected values.
544620d2c4d2Smrg		 */
544720d2c4d2Smrg		SAVE_FNAME(f_n, fNorm);
544820d2c4d2Smrg		SAVE_FNAME(f_b, fBold);
544920d2c4d2Smrg#if OPT_WIDE_CHARS
545020d2c4d2Smrg		SAVE_FNAME(f_w, fWide);
545120d2c4d2Smrg		SAVE_FNAME(f_wb, fWBold);
545220d2c4d2Smrg#endif
5453d1603babSmrg		result = True;
5454d522f475Smrg	    } else {
545520d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
5456d522f475Smrg	    }
54579a64e1c5Smrg	    FREE_FNAME(f_n);
54589a64e1c5Smrg	    FREE_FNAME(f_b);
54599a64e1c5Smrg#if OPT_WIDE_CHARS
54609a64e1c5Smrg	    FREE_FNAME(f_w);
54619a64e1c5Smrg	    FREE_FNAME(f_wb);
54629a64e1c5Smrg#endif
5463d522f475Smrg	}
546420d2c4d2Smrg    } else {
546520d2c4d2Smrg	Bell(xw, XkbBI_MinorError, 0);
5466d522f475Smrg    }
5467d1603babSmrg    TRACE(("...SetVTFont: %d\n", result));
5468d1603babSmrg    return result;
5469d522f475Smrg}
5470dfb07bc7Smrg
5471dfb07bc7Smrg#if OPT_RENDERFONT
5472dfb07bc7Smrgstatic void
5473dfb07bc7SmrgtrimSizeFromFace(char *face_name, float *face_size)
5474dfb07bc7Smrg{
5475dfb07bc7Smrg    char *first = strstr(face_name, ":size=");
5476190d7dceSmrg    if (first == NULL) {
5477dfb07bc7Smrg	first = face_name;
5478dfb07bc7Smrg    } else {
5479dfb07bc7Smrg	first++;
5480dfb07bc7Smrg    }
5481dfb07bc7Smrg    if (!strncmp(first, "size=", (size_t) 5)) {
5482dfb07bc7Smrg	char *last = strchr(first, ':');
5483dfb07bc7Smrg	char mark;
5484dfb07bc7Smrg	float value;
5485dfb07bc7Smrg	char extra;
5486dfb07bc7Smrg	TRACE(("...before trimming, font = \"%s\"\n", face_name));
5487190d7dceSmrg	if (last == NULL)
5488dfb07bc7Smrg	    last = first + strlen(first);
5489dfb07bc7Smrg	mark = *last;
5490dfb07bc7Smrg	*last = '\0';
5491dfb07bc7Smrg	if (sscanf(first, "size=%g%c", &value, &extra) == 1) {
5492dfb07bc7Smrg	    TRACE(("...trimmed size from font: %g\n", value));
5493190d7dceSmrg	    if (face_size != NULL)
5494dfb07bc7Smrg		*face_size = value;
5495dfb07bc7Smrg	}
5496dfb07bc7Smrg	if (mark) {
5497dfb07bc7Smrg	    while ((*first++ = *++last) != '\0') {
5498dfb07bc7Smrg		;
5499dfb07bc7Smrg	    }
5500dfb07bc7Smrg	} else {
5501dfb07bc7Smrg	    if (first != face_name)
5502dfb07bc7Smrg		--first;
5503dfb07bc7Smrg	    *first = '\0';
5504dfb07bc7Smrg	}
5505dfb07bc7Smrg	TRACE(("...after trimming, font = \"%s\"\n", face_name));
5506dfb07bc7Smrg    }
5507dfb07bc7Smrg}
5508dfb07bc7Smrg#endif
5509dfb07bc7Smrg
5510dfb07bc7Smrg/*
5511dfb07bc7Smrg * Save a font specification to the proper list.
5512dfb07bc7Smrg */
5513dfb07bc7Smrgstatic void
5514dfb07bc7Smrgsave2FontList(XtermWidget xw,
5515dfb07bc7Smrg	      const char *name,
5516dfb07bc7Smrg	      XtermFontNames * fontnames,
5517dfb07bc7Smrg	      VTFontEnum which,
5518dfb07bc7Smrg	      const char *source,
5519d1603babSmrg	      Bool check,
5520dfb07bc7Smrg	      Bool ttf)
5521dfb07bc7Smrg{
5522dfb07bc7Smrg    char *value;
5523dfb07bc7Smrg    size_t plen;
5524dfb07bc7Smrg    Bool marked = False;
5525dfb07bc7Smrg    Bool use_ttf = ttf;
5526dfb07bc7Smrg
5527dfb07bc7Smrg    (void) xw;
5528dfb07bc7Smrg
5529190d7dceSmrg    if (source == NULL)
5530dfb07bc7Smrg	source = "";
5531dfb07bc7Smrg    while (isspace(CharOf(*source)))
5532dfb07bc7Smrg	++source;
5533dfb07bc7Smrg
5534dfb07bc7Smrg    /* fontconfig patterns can contain ':' separators, but we'll treat
5535dfb07bc7Smrg     * a leading prefix specially to denote whether the pattern might be
5536dfb07bc7Smrg     * XLFD ("x" or "xlfd") versus Xft ("xft").
5537dfb07bc7Smrg     */
5538dfb07bc7Smrg    for (plen = 0; source[plen] != '\0'; ++plen) {
5539dfb07bc7Smrg	if (source[plen] == ':') {
5540dfb07bc7Smrg	    marked = True;
5541dfb07bc7Smrg	    switch (plen) {
5542dfb07bc7Smrg	    case 0:
5543dfb07bc7Smrg		++plen;		/* trim leading ':' */
5544dfb07bc7Smrg		break;
5545dfb07bc7Smrg	    case 1:
5546dfb07bc7Smrg		if (!strncmp(source, "x", plen)) {
5547dfb07bc7Smrg		    ++plen;
5548dfb07bc7Smrg		    use_ttf = False;
5549dfb07bc7Smrg		} else {
5550dfb07bc7Smrg		    marked = False;
5551dfb07bc7Smrg		}
5552dfb07bc7Smrg		break;
5553dfb07bc7Smrg	    case 3:
5554dfb07bc7Smrg		if (!strncmp(source, "xft", plen)) {
5555dfb07bc7Smrg		    ++plen;
5556dfb07bc7Smrg		    use_ttf = True;
5557dfb07bc7Smrg		} else {
5558dfb07bc7Smrg		    marked = False;
5559dfb07bc7Smrg		}
5560dfb07bc7Smrg		break;
5561dfb07bc7Smrg	    case 4:
5562dfb07bc7Smrg		if (!strncmp(source, "xlfd", plen)) {
5563dfb07bc7Smrg		    ++plen;
5564dfb07bc7Smrg		    use_ttf = False;
5565dfb07bc7Smrg		} else {
5566dfb07bc7Smrg		    marked = False;
5567dfb07bc7Smrg		}
5568dfb07bc7Smrg		break;
5569dfb07bc7Smrg	    default:
5570dfb07bc7Smrg		marked = False;
5571dfb07bc7Smrg		plen = 0;
5572dfb07bc7Smrg		break;
5573dfb07bc7Smrg	    }
5574dfb07bc7Smrg	    break;
5575dfb07bc7Smrg	}
5576dfb07bc7Smrg    }
5577dfb07bc7Smrg    if (!marked)
5578dfb07bc7Smrg	plen = 0;
5579dfb07bc7Smrg    value = x_strtrim(source + plen);
5580190d7dceSmrg    if (value != NULL) {
5581dfb07bc7Smrg	Bool success = False;
5582dfb07bc7Smrg#if OPT_RENDERFONT
5583dfb07bc7Smrg	VTFontList *target = (use_ttf
5584dfb07bc7Smrg			      ? &(fontnames->xft)
5585dfb07bc7Smrg			      : &(fontnames->x11));
5586dfb07bc7Smrg#else
5587dfb07bc7Smrg	VTFontList *target = &(fontnames->x11);
5588dfb07bc7Smrg#endif
5589190d7dceSmrg	char ***list = NULL;
5590190d7dceSmrg	char **next = NULL;
5591dfb07bc7Smrg	size_t count = 0;
5592dfb07bc7Smrg
5593dfb07bc7Smrg	(void) use_ttf;
5594dfb07bc7Smrg	switch (which) {
5595dfb07bc7Smrg	case fNorm:
5596dfb07bc7Smrg	    list = &(target->list_n);
5597dfb07bc7Smrg	    break;
5598dfb07bc7Smrg	case fBold:
5599dfb07bc7Smrg	    list = &(target->list_b);
5600dfb07bc7Smrg	    break;
5601dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
5602dfb07bc7Smrg	case fItal:
5603dfb07bc7Smrg	    list = &(target->list_i);
5604dfb07bc7Smrg	    break;
5605d4fba8b9Smrg	case fBtal:
5606d4fba8b9Smrg	    list = &(target->list_bi);
5607d4fba8b9Smrg	    break;
5608dfb07bc7Smrg#endif
5609dfb07bc7Smrg#if OPT_WIDE_CHARS
5610dfb07bc7Smrg	case fWide:
5611dfb07bc7Smrg	    list = &(target->list_w);
5612dfb07bc7Smrg	    break;
5613dfb07bc7Smrg	case fWBold:
5614dfb07bc7Smrg	    list = &(target->list_wb);
5615dfb07bc7Smrg	    break;
5616dfb07bc7Smrg	case fWItal:
5617dfb07bc7Smrg	    list = &(target->list_wi);
5618dfb07bc7Smrg	    break;
5619d4fba8b9Smrg	case fWBtal:
5620d4fba8b9Smrg	    list = &(target->list_wbi);
5621d4fba8b9Smrg	    break;
5622dfb07bc7Smrg#endif
5623dfb07bc7Smrg	case fMAX:
5624190d7dceSmrg	    list = NULL;
5625dfb07bc7Smrg	    break;
5626dfb07bc7Smrg	}
5627dfb07bc7Smrg
5628190d7dceSmrg	if (list != NULL) {
5629dfb07bc7Smrg	    success = True;
5630190d7dceSmrg	    if (*list != NULL) {
5631190d7dceSmrg		while ((*list)[count] != NULL) {
5632dfb07bc7Smrg		    if (IsEmpty((*list)[count])) {
5633dfb07bc7Smrg			TRACE(("... initial %s\n", value));
5634dfb07bc7Smrg			free((*list)[count]);
5635dfb07bc7Smrg			break;
5636dfb07bc7Smrg		    } else if (!strcmp(value, (*list)[count])) {
5637dfb07bc7Smrg			TRACE(("... duplicate %s\n", value));
5638dfb07bc7Smrg			success = False;
5639dfb07bc7Smrg			break;
5640dfb07bc7Smrg		    }
5641dfb07bc7Smrg		    ++count;
5642dfb07bc7Smrg		}
5643dfb07bc7Smrg	    }
5644dfb07bc7Smrg	    if (success) {
5645d1603babSmrg		next = (char **) realloc(*list, sizeof(char *) * (count + 2));
5646190d7dceSmrg		if (next != NULL) {
5647dfb07bc7Smrg#if OPT_RENDERFONT
5648dfb07bc7Smrg		    if (use_ttf) {
5649dfb07bc7Smrg			trimSizeFromFace(value,
5650dfb07bc7Smrg					 (count == 0 && which == fNorm)
5651dfb07bc7Smrg					 ? &(xw->misc.face_size[0])
5652dfb07bc7Smrg					 : (float *) 0);
5653dfb07bc7Smrg		    }
5654dfb07bc7Smrg#endif
5655dfb07bc7Smrg		    next[count++] = value;
5656190d7dceSmrg		    next[count] = NULL;
5657dfb07bc7Smrg		    *list = next;
56588f44fb3bSmrg		    TRACE(("... saved \"%s\" \"%s\" %lu:\"%s\"\n",
5659dfb07bc7Smrg			   whichFontList(xw, target),
5660dfb07bc7Smrg			   whichFontList2(xw, *list),
5661dfb07bc7Smrg			   (unsigned long) count,
5662dfb07bc7Smrg			   value));
5663dfb07bc7Smrg		} else {
5664d1603babSmrg		    xtermWarning("realloc failure in save2FontList(%s)\n", name);
5665dfb07bc7Smrg		    freeFontList(list);
5666dfb07bc7Smrg		    success = False;
5667dfb07bc7Smrg		}
5668dfb07bc7Smrg	    }
5669dfb07bc7Smrg	}
5670dfb07bc7Smrg	if (success) {
5671d4fba8b9Smrg#if (MAX_XFT_FONTS == MAX_XLFD_FONTS)
5672d4fba8b9Smrg	    size_t limit = MAX_XFT_FONTS;
5673d4fba8b9Smrg#else
5674dfb07bc7Smrg	    size_t limit = use_ttf ? MAX_XFT_FONTS : MAX_XLFD_FONTS;
5675d4fba8b9Smrg#endif
5676d4fba8b9Smrg	    if (count > limit && *x_skip_blanks(value)) {
5677d1603babSmrg		if (check) {
5678d1603babSmrg		    xtermWarning("too many fonts for %s, ignoring %s\n",
5679d1603babSmrg				 whichFontEnum(which),
5680d1603babSmrg				 value);
5681d1603babSmrg		}
5682dfb07bc7Smrg		if (list && *list) {
5683dfb07bc7Smrg		    free((*list)[limit]);
5684190d7dceSmrg		    (*list)[limit] = NULL;
5685dfb07bc7Smrg		}
5686dfb07bc7Smrg	    }
5687dfb07bc7Smrg	} else {
5688dfb07bc7Smrg	    free(value);
5689dfb07bc7Smrg	}
5690dfb07bc7Smrg    }
5691dfb07bc7Smrg}
5692dfb07bc7Smrg
5693dfb07bc7Smrg/*
5694dfb07bc7Smrg * In principle, any of the font-name resources could be extended to be a list
5695dfb07bc7Smrg * of font-names.  That would be bad for performance, but as a basis for an
5696dfb07bc7Smrg * extension, parse the font-name as a comma-separated list, creating/updating
5697dfb07bc7Smrg * an array of font-names.
5698dfb07bc7Smrg */
5699dfb07bc7Smrgvoid
5700dfb07bc7SmrgallocFontList(XtermWidget xw,
5701dfb07bc7Smrg	      const char *name,
5702dfb07bc7Smrg	      XtermFontNames * target,
5703dfb07bc7Smrg	      VTFontEnum which,
5704dfb07bc7Smrg	      const char *source,
5705dfb07bc7Smrg	      Bool ttf)
5706dfb07bc7Smrg{
5707dfb07bc7Smrg    char *blob;
5708dfb07bc7Smrg
5709dfb07bc7Smrg    blob = x_strdup(source);
5710190d7dceSmrg    if (blob != NULL) {
5711dfb07bc7Smrg	int n;
5712dfb07bc7Smrg	int pass;
5713190d7dceSmrg	char **list = NULL;
5714dfb07bc7Smrg
57158f44fb3bSmrg	TRACE(("allocFontList %s name=\"%s\" source=\"%s\"\n",
57168f44fb3bSmrg	       whichFontEnum(which), name, blob));
5717dfb07bc7Smrg
5718dfb07bc7Smrg	for (pass = 0; pass < 2; ++pass) {
5719dfb07bc7Smrg	    unsigned count = 0;
5720dfb07bc7Smrg	    if (pass)
5721dfb07bc7Smrg		list[0] = blob;
5722dfb07bc7Smrg	    for (n = 0; blob[n] != '\0'; ++n) {
5723dfb07bc7Smrg		if (blob[n] == ',') {
5724dfb07bc7Smrg		    ++count;
5725dfb07bc7Smrg		    if (pass != 0) {
5726dfb07bc7Smrg			blob[n] = '\0';
5727dfb07bc7Smrg			list[count] = blob + n + 1;
5728dfb07bc7Smrg		    }
5729dfb07bc7Smrg		}
5730dfb07bc7Smrg	    }
5731dfb07bc7Smrg	    if (!pass) {
5732dfb07bc7Smrg		if (count == 0 && *blob == '\0')
5733dfb07bc7Smrg		    break;
5734dfb07bc7Smrg		list = TypeCallocN(char *, count + 2);
5735190d7dceSmrg		if (list == NULL)
5736dfb07bc7Smrg		    break;
5737dfb07bc7Smrg	    }
5738dfb07bc7Smrg	}
5739dfb07bc7Smrg	if (list) {
5740190d7dceSmrg	    for (n = 0; list[n] != NULL; ++n) {
5741dfb07bc7Smrg		if (*list[n]) {
5742d1603babSmrg		    save2FontList(xw, name, target, which, list[n], True, ttf);
5743dfb07bc7Smrg		}
5744dfb07bc7Smrg	    }
5745dfb07bc7Smrg	    free(list);
5746dfb07bc7Smrg	}
5747dfb07bc7Smrg    }
5748dfb07bc7Smrg    free(blob);
5749dfb07bc7Smrg}
5750dfb07bc7Smrg
5751dfb07bc7Smrgstatic void
5752dfb07bc7SmrginitFontList(XtermWidget xw,
5753dfb07bc7Smrg	     const char *name,
5754dfb07bc7Smrg	     XtermFontNames * target,
5755dfb07bc7Smrg	     Bool ttf)
5756dfb07bc7Smrg{
5757dfb07bc7Smrg    int which;
5758dfb07bc7Smrg
5759dfb07bc7Smrg    TRACE(("initFontList(%s)\n", name));
5760dfb07bc7Smrg    for (which = 0; which < fMAX; ++which) {
5761d1603babSmrg	save2FontList(xw, name, target, (VTFontEnum) which, "", False, ttf);
5762dfb07bc7Smrg    }
5763dfb07bc7Smrg}
5764dfb07bc7Smrg
5765dfb07bc7Smrgvoid
5766dfb07bc7SmrginitFontLists(XtermWidget xw)
5767dfb07bc7Smrg{
5768dfb07bc7Smrg    TRACE(("initFontLists\n"));
5769dfb07bc7Smrg    initFontList(xw, "x11 font", &(xw->work.fonts), False);
5770dfb07bc7Smrg#if OPT_RENDERFONT
5771dfb07bc7Smrg    initFontList(xw, "xft font", &(xw->work.fonts), True);
5772dfb07bc7Smrg#endif
5773dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
5774dfb07bc7Smrg    initFontList(xw, "cached font",
5775dfb07bc7Smrg		 &(xw->screen.cacheVTFonts.fonts), False);
5776dfb07bc7Smrg#endif
5777dfb07bc7Smrg}
5778dfb07bc7Smrg
5779dfb07bc7Smrgvoid
5780dfb07bc7SmrgcopyFontList(char ***targetp, char **source)
5781dfb07bc7Smrg{
5782dfb07bc7Smrg    freeFontList(targetp);
5783dfb07bc7Smrg
5784190d7dceSmrg    if (source != NULL) {
5785dfb07bc7Smrg	int pass;
5786dfb07bc7Smrg	size_t count;
5787dfb07bc7Smrg
5788dfb07bc7Smrg	for (pass = 0; pass < 2; ++pass) {
5789190d7dceSmrg	    for (count = 0; source[count] != NULL; ++count) {
5790dfb07bc7Smrg		if (pass)
5791dfb07bc7Smrg		    (*targetp)[count] = x_strdup(source[count]);
5792dfb07bc7Smrg	    }
5793dfb07bc7Smrg	    if (!pass) {
5794dfb07bc7Smrg		++count;
5795dfb07bc7Smrg		*targetp = TypeCallocN(char *, count);
5796dfb07bc7Smrg	    }
5797dfb07bc7Smrg	}
5798dfb07bc7Smrg    } else {
5799dfb07bc7Smrg	*targetp = TypeCallocN(char *, 2);
5800dfb07bc7Smrg	(*targetp)[0] = x_strdup("");
5801dfb07bc7Smrg    }
5802dfb07bc7Smrg}
5803dfb07bc7Smrg
5804dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
5805dfb07bc7Smrgstatic Boolean
5806dfb07bc7Smrgmerge_sublist(char ***targetp, char **source)
5807dfb07bc7Smrg{
5808dfb07bc7Smrg    Boolean result = False;
5809190d7dceSmrg    if ((*targetp == NULL || IsEmpty(**targetp)) && !IsEmpty(*source)) {
5810dfb07bc7Smrg	copyFontList(targetp, source);
5811dfb07bc7Smrg	result = True;
5812dfb07bc7Smrg    }
5813dfb07bc7Smrg    return result;
5814dfb07bc7Smrg}
5815dfb07bc7Smrg#endif
5816dfb07bc7Smrg
5817dfb07bc7Smrgvoid
5818dfb07bc7SmrgfreeFontList(char ***targetp)
5819dfb07bc7Smrg{
5820190d7dceSmrg    if (targetp != NULL) {
5821dfb07bc7Smrg	char **target = *targetp;
5822190d7dceSmrg	if (target != NULL) {
5823dfb07bc7Smrg	    int n;
5824190d7dceSmrg	    for (n = 0; target[n] != NULL; ++n) {
5825dfb07bc7Smrg		free(target[n]);
5826dfb07bc7Smrg	    }
5827dfb07bc7Smrg	    free(target);
5828190d7dceSmrg	    *targetp = NULL;
5829dfb07bc7Smrg	}
5830dfb07bc7Smrg    }
5831dfb07bc7Smrg}
5832dfb07bc7Smrg
5833dfb07bc7Smrgvoid
5834dfb07bc7SmrgfreeFontLists(VTFontList * lists)
5835dfb07bc7Smrg{
5836dfb07bc7Smrg    int which;
5837dfb07bc7Smrg
5838dfb07bc7Smrg    TRACE(("freeFontLists\n"));
5839dfb07bc7Smrg    for (which = 0; which < fMAX; ++which) {
5840190d7dceSmrg	char ***target = NULL;
5841dfb07bc7Smrg	switch (which) {
5842dfb07bc7Smrg	case fNorm:
5843dfb07bc7Smrg	    target = &(lists->list_n);
5844dfb07bc7Smrg	    break;
5845dfb07bc7Smrg	case fBold:
5846dfb07bc7Smrg	    target = &(lists->list_b);
5847dfb07bc7Smrg	    break;
5848dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
5849dfb07bc7Smrg	case fItal:
5850dfb07bc7Smrg	    target = &(lists->list_i);
5851dfb07bc7Smrg	    break;
5852d4fba8b9Smrg	case fBtal:
5853d4fba8b9Smrg	    target = &(lists->list_bi);
5854d4fba8b9Smrg	    break;
5855dfb07bc7Smrg#endif
5856dfb07bc7Smrg#if OPT_WIDE_CHARS
5857dfb07bc7Smrg	case fWide:
5858dfb07bc7Smrg	    target = &(lists->list_w);
5859dfb07bc7Smrg	    break;
5860dfb07bc7Smrg	case fWBold:
5861dfb07bc7Smrg	    target = &(lists->list_wb);
5862dfb07bc7Smrg	    break;
5863dfb07bc7Smrg	case fWItal:
5864dfb07bc7Smrg	    target = &(lists->list_wi);
5865dfb07bc7Smrg	    break;
5866d4fba8b9Smrg	case fWBtal:
5867d4fba8b9Smrg	    target = &(lists->list_wbi);
5868d4fba8b9Smrg	    break;
5869dfb07bc7Smrg#endif
5870dfb07bc7Smrg	default:
5871190d7dceSmrg	    target = NULL;
5872dfb07bc7Smrg	    break;
5873dfb07bc7Smrg	}
5874dfb07bc7Smrg	freeFontList(target);
5875dfb07bc7Smrg    }
5876dfb07bc7Smrg}
5877dfb07bc7Smrg
5878dfb07bc7Smrg/*
5879dfb07bc7Smrg * Return a pointer to the XLFD font information for a given font class.
5880dfb07bc7Smrg * XXX make this allocate the font on demand.
5881dfb07bc7Smrg */
5882dfb07bc7SmrgXTermFonts *
5883dfb07bc7SmrggetNormalFont(TScreen *screen, int which)
5884dfb07bc7Smrg{
5885190d7dceSmrg    XTermFonts *result = NULL;
5886dfb07bc7Smrg    if (which >= 0 && which < fMAX)
5887d4fba8b9Smrg	result = GetNormalFont(screen, which);
5888dfb07bc7Smrg    return result;
5889dfb07bc7Smrg}
5890dfb07bc7Smrg
5891dfb07bc7Smrg#if OPT_DEC_CHRSET
5892dfb07bc7SmrgXTermFonts *
5893dfb07bc7SmrggetDoubleFont(TScreen *screen, int which)
5894dfb07bc7Smrg{
5895190d7dceSmrg    XTermFonts *result = NULL;
5896dfb07bc7Smrg    if ((int) which >= 0 && which < NUM_CHRSET)
5897d4fba8b9Smrg	result = GetDoubleFont(screen, which);
5898d4fba8b9Smrg    return result;
5899d4fba8b9Smrg}
5900d4fba8b9Smrg
5901d4fba8b9Smrg#if OPT_RENDERFONT
5902d1603babSmrgvoid
5903d1603babSmrggetDoubleXftFont(XTermDraw * params, XTermXftFonts *data, unsigned chrset, unsigned attr_flags)
5904d4fba8b9Smrg{
5905d4fba8b9Smrg    XtermWidget xw = params->xw;
5906d4fba8b9Smrg    TScreen *screen = TScreenOf(xw);
5907d4fba8b9Smrg    XftPattern *top_pattern;
5908d4fba8b9Smrg    int fontnum = screen->menu_font_number;
5909d4fba8b9Smrg    const char *face_name = getFaceName(xw, False);
5910d4fba8b9Smrg
5911d4fba8b9Smrg    if (chrset != CSET_SWL
5912190d7dceSmrg	&& (top_pattern = XftNameParse(face_name)) != NULL) {
5913d4fba8b9Smrg	double face_size = (double) xw->misc.face_size[fontnum];
5914d4fba8b9Smrg	XftPattern *sub_pattern = XftPatternDuplicate(top_pattern);
5915d1603babSmrg	const char *category = "doublesize";
5916d4fba8b9Smrg
5917d4fba8b9Smrg	switch (chrset) {
5918d4fba8b9Smrg	case CSET_DHL_TOP:
5919d1603babSmrg	    category = "DHL_TOP";
5920d1603babSmrg	    goto double_high;
5921d4fba8b9Smrg	case CSET_DHL_BOT:
5922d1603babSmrg	    category = "DHL_BOT";
5923d1603babSmrg	  double_high:
5924d4fba8b9Smrg	    face_size *= 2;
5925d4fba8b9Smrg	    XftPatternBuild(sub_pattern,
5926d4fba8b9Smrg			    NormXftPattern,
5927d4fba8b9Smrg			    (void *) 0);
5928d4fba8b9Smrg	    break;
5929d4fba8b9Smrg	case CSET_DWL:
5930d1603babSmrg	    category = "DWL";
5931d4fba8b9Smrg	    XftPatternBuild(sub_pattern,
5932d4fba8b9Smrg			    NormXftPattern,
5933d4fba8b9Smrg			    FC_ASPECT, XftTypeDouble, 2.0,
5934d4fba8b9Smrg			    (void *) 0);
5935d4fba8b9Smrg	    break;
5936d4fba8b9Smrg	}
5937d4fba8b9Smrg	if (attr_flags & BOLD) {
5938d4fba8b9Smrg	    XftPatternBuild(sub_pattern,
5939d4fba8b9Smrg			    XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD,
5940d4fba8b9Smrg			    (void *) 0);
5941d4fba8b9Smrg	}
5942d1603babSmrg	xtermOpenXft(xw, data, 0, face_name, sub_pattern, category);
5943d1603babSmrg	data->pattern = sub_pattern;
5944d4fba8b9Smrg    }
5945dfb07bc7Smrg}
5946dfb07bc7Smrg#endif
5947d4fba8b9Smrg#endif /* OPT_DEC_CHRSET */
5948dfb07bc7Smrg
5949dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
5950dfb07bc7SmrgXTermFonts *
5951dfb07bc7SmrggetItalicFont(TScreen *screen, int which)
5952dfb07bc7Smrg{
5953190d7dceSmrg    XTermFonts *result = NULL;
5954dfb07bc7Smrg#if OPT_WIDE_ATTRS
5955dfb07bc7Smrg    if (which >= 0 && which < fMAX)
5956d4fba8b9Smrg	result = GetItalicFont(screen, which);
5957dfb07bc7Smrg#else
5958dfb07bc7Smrg    (void) screen;
5959dfb07bc7Smrg    (void) which;
5960dfb07bc7Smrg#endif
5961dfb07bc7Smrg    return result;
5962dfb07bc7Smrg}
5963dfb07bc7Smrg#endif
5964dfb07bc7Smrg
5965dfb07bc7Smrg#if OPT_RENDERFONT
5966dfb07bc7Smrg/*
5967dfb07bc7Smrg * This returns a pointer to everything known about a given Xft font.
5968dfb07bc7Smrg * XXX make this allocate the font on demand.
5969dfb07bc7Smrg */
5970dfb07bc7SmrgXTermXftFonts *
5971dfb07bc7SmrggetMyXftFont(XtermWidget xw, int which, int fontnum)
5972dfb07bc7Smrg{
5973dfb07bc7Smrg    TScreen *screen = TScreenOf(xw);
5974190d7dceSmrg    XTermXftFonts *result = NULL;
5975dfb07bc7Smrg    if (fontnum >= 0 && fontnum < NMENUFONTS) {
5976dfb07bc7Smrg	switch ((VTFontEnum) which) {
5977dfb07bc7Smrg	case fNorm:
5978dfb07bc7Smrg	    result = &(screen->renderFontNorm[fontnum]);
5979dfb07bc7Smrg	    break;
5980dfb07bc7Smrg	case fBold:
5981dfb07bc7Smrg	    result = &(screen->renderFontBold[fontnum]);
5982dfb07bc7Smrg	    break;
5983dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
5984dfb07bc7Smrg	case fItal:
5985dfb07bc7Smrg	    result = &(screen->renderFontItal[fontnum]);
5986dfb07bc7Smrg	    break;
5987d4fba8b9Smrg	case fBtal:
5988d4fba8b9Smrg	    result = &(screen->renderFontBtal[fontnum]);
5989d4fba8b9Smrg	    break;
5990dfb07bc7Smrg#endif
5991dfb07bc7Smrg#if OPT_WIDE_CHARS
5992dfb07bc7Smrg	case fWide:
5993dfb07bc7Smrg	    result = &(screen->renderWideNorm[fontnum]);
5994dfb07bc7Smrg	    break;
5995dfb07bc7Smrg	case fWBold:
5996dfb07bc7Smrg	    result = &(screen->renderWideBold[fontnum]);
5997dfb07bc7Smrg	    break;
5998dfb07bc7Smrg	case fWItal:
5999dfb07bc7Smrg	    result = &(screen->renderWideItal[fontnum]);
6000dfb07bc7Smrg	    break;
6001d4fba8b9Smrg	case fWBtal:
6002d4fba8b9Smrg	    result = &(screen->renderWideBtal[fontnum]);
6003d4fba8b9Smrg	    break;
6004dfb07bc7Smrg#endif
6005dfb07bc7Smrg	case fMAX:
6006dfb07bc7Smrg	    break;
6007dfb07bc7Smrg	}
6008dfb07bc7Smrg    }
6009dfb07bc7Smrg    return result;
6010dfb07bc7Smrg}
6011dfb07bc7Smrg
6012d1603babSmrgconst char *
6013190d7dceSmrgwhichXftFonts(XtermWidget xw, const XTermXftFonts *data)
6014d1603babSmrg{
6015d1603babSmrg    TScreen *screen = TScreenOf(xw);
6016d1603babSmrg    const char *result = "?";
6017d1603babSmrg#define CHECK(name) ((data >= &(screen->name[0])) && (data < &(screen->name[NMENUFONTS]))) result = #name
6018d1603babSmrg    if CHECK
6019d1603babSmrg	(renderFontNorm);
6020d1603babSmrg    else if CHECK
6021d1603babSmrg	(renderFontBold);
6022d1603babSmrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
6023d1603babSmrg    else if CHECK
6024d1603babSmrg	(renderFontItal);
6025d1603babSmrg    else if CHECK
6026d1603babSmrg	(renderFontBtal);
6027d1603babSmrg#endif
6028d1603babSmrg#if OPT_WIDE_CHARS
6029d1603babSmrg    else if CHECK
6030d1603babSmrg	(renderWideNorm);
6031d1603babSmrg    else if CHECK
6032d1603babSmrg	(renderWideBold);
6033d1603babSmrg    else if CHECK
6034d1603babSmrg	(renderWideItal);
6035d1603babSmrg    else if CHECK
6036d1603babSmrg	(renderWideBtal);
6037d1603babSmrg#endif
6038d1603babSmrg#if OPT_DEC_CHRSET
6039d1603babSmrg#if OPT_RENDERFONT
6040d1603babSmrg    else {
6041d1603babSmrg	int n;
6042d1603babSmrg	for (n = 0; n < NUM_CHRSET; ++n) {
6043d1603babSmrg	    if (data == &screen->double_xft_fonts[n]) {
6044d1603babSmrg		result = "double_xft_fonts";
6045d1603babSmrg		break;
6046d1603babSmrg	    }
6047d1603babSmrg	}
6048d1603babSmrg    }
6049d1603babSmrg#endif
6050d1603babSmrg#endif /* OPT_DEC_CHRSET */
6051d1603babSmrg    return result;
6052d1603babSmrg}
6053d1603babSmrg
6054dfb07bc7SmrgXftFont *
6055dfb07bc7SmrggetXftFont(XtermWidget xw, VTFontEnum which, int fontnum)
6056dfb07bc7Smrg{
6057d4fba8b9Smrg    XTermXftFonts *data = getMyXftFont(xw, (int) which, fontnum);
6058190d7dceSmrg    XftFont *result = NULL;
6059190d7dceSmrg    if (data != NULL)
6060d1603babSmrg	result = XftFp(data);
6061dfb07bc7Smrg    return result;
6062dfb07bc7Smrg}
6063dfb07bc7Smrg#endif
6064dfb07bc7Smrg
6065dfb07bc7Smrgconst char *
6066dfb07bc7SmrgwhichFontEnum(VTFontEnum value)
6067dfb07bc7Smrg{
6068dfb07bc7Smrg    const char *result = "?";
6069dfb07bc7Smrg#define DATA(name) case name: result = #name; break
6070dfb07bc7Smrg    switch (value) {
6071dfb07bc7Smrg	DATA(fNorm);
6072dfb07bc7Smrg	DATA(fBold);
6073dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
6074dfb07bc7Smrg	DATA(fItal);
6075d4fba8b9Smrg	DATA(fBtal);
6076dfb07bc7Smrg#endif
6077dfb07bc7Smrg#if OPT_WIDE_CHARS
6078dfb07bc7Smrg	DATA(fWide);
6079dfb07bc7Smrg	DATA(fWBold);
6080dfb07bc7Smrg	DATA(fWItal);
6081d4fba8b9Smrg	DATA(fWBtal);
6082dfb07bc7Smrg#endif
6083dfb07bc7Smrg	DATA(fMAX);
6084dfb07bc7Smrg    }
6085dfb07bc7Smrg#undef DATA
6086dfb07bc7Smrg    return result;
6087dfb07bc7Smrg}
6088dfb07bc7Smrg
6089dfb07bc7Smrgconst char *
6090190d7dceSmrgwhichFontList(XtermWidget xw, const VTFontList * value)
6091dfb07bc7Smrg{
6092dfb07bc7Smrg    const char *result = "?";
6093dfb07bc7Smrg    if (value == &(xw->work.fonts.x11))
6094dfb07bc7Smrg	result = "x11_fontnames";
6095dfb07bc7Smrg#if OPT_RENDERFONT
6096dfb07bc7Smrg    else if (value == &(xw->work.fonts.xft))
6097dfb07bc7Smrg	result = "xft_fontnames";
6098dfb07bc7Smrg#endif
6099dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
6100dfb07bc7Smrg    else if (value == &(xw->screen.cacheVTFonts.fonts.x11))
6101dfb07bc7Smrg	result = "cached_fontnames";
6102dfb07bc7Smrg#endif
6103dfb07bc7Smrg    return result;
6104dfb07bc7Smrg}
6105dfb07bc7Smrg
6106dfb07bc7Smrgstatic const char *
6107dfb07bc7SmrgwhichFontList2s(VTFontList * list, char **value)
6108dfb07bc7Smrg{
6109190d7dceSmrg    const char *result = NULL;
6110dfb07bc7Smrg#define DATA(name) if (value == (list->name)) result = #name
6111dfb07bc7Smrg    DATA(list_n);
6112dfb07bc7Smrg    DATA(list_b);
6113dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
6114dfb07bc7Smrg    DATA(list_i);
6115d4fba8b9Smrg    DATA(list_bi);
6116dfb07bc7Smrg#endif
6117dfb07bc7Smrg#if OPT_WIDE_CHARS
6118dfb07bc7Smrg    DATA(list_w);
6119dfb07bc7Smrg    DATA(list_wb);
6120dfb07bc7Smrg    DATA(list_wi);
6121d4fba8b9Smrg    DATA(list_wbi);
6122dfb07bc7Smrg#endif
6123dfb07bc7Smrg#undef DATA
6124dfb07bc7Smrg    return result;
6125dfb07bc7Smrg}
6126dfb07bc7Smrg
6127dfb07bc7Smrgconst char *
6128dfb07bc7SmrgwhichFontList2(XtermWidget xw, char **value)
6129dfb07bc7Smrg{
6130190d7dceSmrg    const char *result = NULL;
6131dfb07bc7Smrg#define DATA(name) (result = whichFontList2s(&(xw->name), value))
6132190d7dceSmrg    if (DATA(work.fonts.x11) == NULL) {
6133dfb07bc7Smrg#if OPT_RENDERFONT
6134190d7dceSmrg	if (DATA(work.fonts.xft) == NULL)
6135dfb07bc7Smrg#endif
6136dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
6137190d7dceSmrg	    if (DATA(screen.cacheVTFonts.fonts.x11) == NULL)
6138dfb07bc7Smrg#endif
6139dfb07bc7Smrg		result = "?";
6140dfb07bc7Smrg    }
6141dfb07bc7Smrg#undef DATA
6142dfb07bc7Smrg    return result;
6143dfb07bc7Smrg}
6144