fontutils.c revision 50027b5b
150027b5bSmrg/* $XTermId: fontutils.c,v 1.712 2022/02/23 00:46:08 tom Exp $ */
2d522f475Smrg
30bd37d32Smrg/*
450027b5bSmrg * Copyright 1998-2021,2022 by Thomas E. Dickey
50bd37d32Smrg *
60bd37d32Smrg *                         All Rights Reserved
70bd37d32Smrg *
80bd37d32Smrg * Permission is hereby granted, free of charge, to any person obtaining a
90bd37d32Smrg * copy of this software and associated documentation files (the
100bd37d32Smrg * "Software"), to deal in the Software without restriction, including
110bd37d32Smrg * without limitation the rights to use, copy, modify, merge, publish,
120bd37d32Smrg * distribute, sublicense, and/or sell copies of the Software, and to
130bd37d32Smrg * permit persons to whom the Software is furnished to do so, subject to
140bd37d32Smrg * the following conditions:
150bd37d32Smrg *
160bd37d32Smrg * The above copyright notice and this permission notice shall be included
170bd37d32Smrg * in all copies or substantial portions of the Software.
180bd37d32Smrg *
190bd37d32Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
200bd37d32Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
210bd37d32Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
220bd37d32Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
230bd37d32Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
240bd37d32Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
250bd37d32Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
260bd37d32Smrg *
270bd37d32Smrg * Except as contained in this notice, the name(s) of the above copyright
280bd37d32Smrg * holders shall not be used in advertising or otherwise to promote the
290bd37d32Smrg * sale, use or other dealings in this Software without prior written
300bd37d32Smrg * authorization.
310bd37d32Smrg */
32d522f475Smrg
33d522f475Smrg/*
34d522f475Smrg * A portion of this module (for FontNameProperties) was adapted from EMU 1.3;
35d522f475Smrg * it constructs font names with specific properties changed, e.g., for bold
36d522f475Smrg * and double-size characters.
37d522f475Smrg */
38d522f475Smrg
39d522f475Smrg#define RES_OFFSET(field)	XtOffsetOf(SubResourceRec, field)
40d522f475Smrg
41d522f475Smrg#include <fontutils.h>
42d522f475Smrg#include <X11/Xmu/Drawing.h>
4320d2c4d2Smrg#include <X11/Xmu/CharSet.h>
44d522f475Smrg
45d522f475Smrg#include <main.h>
46d522f475Smrg#include <data.h>
47d522f475Smrg#include <menu.h>
48d522f475Smrg#include <xstrings.h>
49d522f475Smrg#include <xterm.h>
50d522f475Smrg
51d522f475Smrg#include <stdio.h>
52d522f475Smrg#include <ctype.h>
53d522f475Smrg
54d4fba8b9Smrg#define NoFontWarning(data) (data)->warn = fwAlways
55d4fba8b9Smrg
560bd37d32Smrg#define SetFontWidth(screen,dst,src)  (dst)->f_width = (src)
57d4fba8b9Smrg#define SetFontHeight(screen,dst,src) (dst)->f_height = dimRound((double)((screen)->scale_height * (float) (src)))
580bd37d32Smrg
59d522f475Smrg/* from X11/Xlibint.h - not all vendors install this file */
60d522f475Smrg#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
61d522f475Smrg			     (((cs)->rbearing|(cs)->lbearing| \
62d522f475Smrg			       (cs)->ascent|(cs)->descent) == 0))
63d522f475Smrg
64fa3f02f3Smrg#define CI_GET_CHAR_INFO_1D(fs,col,cs) \
65d522f475Smrg{ \
66fa3f02f3Smrg    cs = 0; \
67d522f475Smrg    if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
68d522f475Smrg	if (fs->per_char == NULL) { \
69d522f475Smrg	    cs = &fs->min_bounds; \
70d522f475Smrg	} else { \
71d522f475Smrg	    cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
72d522f475Smrg	} \
73fa3f02f3Smrg	if (CI_NONEXISTCHAR(cs)) cs = 0; \
74d522f475Smrg    } \
75d522f475Smrg}
76d522f475Smrg
77fa3f02f3Smrg#define CI_GET_CHAR_INFO_2D(fs,row,col,cs) \
78d522f475Smrg{ \
79fa3f02f3Smrg    cs = 0; \
80d522f475Smrg    if (row >= fs->min_byte1 && row <= fs->max_byte1 && \
81d522f475Smrg	col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
82d522f475Smrg	if (fs->per_char == NULL) { \
83d522f475Smrg	    cs = &fs->min_bounds; \
84d522f475Smrg	} else { \
85d522f475Smrg	    cs = &fs->per_char[((row - fs->min_byte1) * \
86d522f475Smrg				(fs->max_char_or_byte2 - \
87d522f475Smrg				 fs->min_char_or_byte2 + 1)) + \
88d522f475Smrg			       (col - fs->min_char_or_byte2)]; \
89d522f475Smrg	} \
90fa3f02f3Smrg	if (CI_NONEXISTCHAR(cs)) cs = 0; \
91d522f475Smrg    } \
92d522f475Smrg}
93d522f475Smrg
949a64e1c5Smrg#define FREE_FNAME(field) \
959a64e1c5Smrg	    if (fonts == 0 || myfonts.field != fonts->field) { \
969a64e1c5Smrg		FREE_STRING(myfonts.field); \
979a64e1c5Smrg		myfonts.field = 0; \
989a64e1c5Smrg	    }
999a64e1c5Smrg
100d522f475Smrg/*
101d522f475Smrg * A structure to hold the relevant properties from a font
102d522f475Smrg * we need to make a well formed font name for it.
103d522f475Smrg */
104d522f475Smrgtypedef struct {
105d522f475Smrg    /* registry, foundry, family */
1069a64e1c5Smrg    const char *beginning;
107d522f475Smrg    /* weight */
1089a64e1c5Smrg    const char *weight;
109d522f475Smrg    /* slant */
1109a64e1c5Smrg    const char *slant;
111d522f475Smrg    /* wideness */
1129a64e1c5Smrg    const char *wideness;
113d522f475Smrg    /* add style */
1149a64e1c5Smrg    const char *add_style;
115d522f475Smrg    int pixel_size;
1169a64e1c5Smrg    const char *point_size;
117d522f475Smrg    int res_x;
118d522f475Smrg    int res_y;
1199a64e1c5Smrg    const char *spacing;
120d522f475Smrg    int average_width;
121d522f475Smrg    /* charset registry, charset encoding */
122d522f475Smrg    char *end;
123d522f475Smrg} FontNameProperties;
124d522f475Smrg
125d4fba8b9Smrg#if OPT_WIDE_CHARS && (OPT_RENDERFONT || (OPT_TRACE > 1))
126d4fba8b9Smrg#define MY_UCS(code,high,wide,name) { code, high, wide, #name }
127d4fba8b9Smrgstatic const struct {
128d4fba8b9Smrg    unsigned code, high, wide;
129d4fba8b9Smrg    const char *name;
130d4fba8b9Smrg} unicode_boxes[] = {
131d4fba8b9Smrg
132d4fba8b9Smrg    MY_UCS(0x2500, 0, 1, box drawings light horizontal),
133d4fba8b9Smrg	MY_UCS(0x2502, 1, 0, box drawings light vertical),
134d4fba8b9Smrg	MY_UCS(0x250c, 2, 2, box drawings light down and right),
135d4fba8b9Smrg	MY_UCS(0x2510, 2, 2, box drawings light down and left),
136d4fba8b9Smrg	MY_UCS(0x2514, 2, 2, box drawings light up and right),
137d4fba8b9Smrg	MY_UCS(0x2518, 2, 2, box drawings light up and left),
138d4fba8b9Smrg	MY_UCS(0x251c, 1, 2, box drawings light vertical and right),
139d4fba8b9Smrg	MY_UCS(0x2524, 1, 2, box drawings light vertical and left),
140d4fba8b9Smrg	MY_UCS(0x252c, 2, 1, box drawings light down and horizontal),
141d4fba8b9Smrg	MY_UCS(0x2534, 2, 1, box drawings light up and horizontal),
142d4fba8b9Smrg	MY_UCS(0x253c, 1, 1, box drawings light vertical and horizontal),
143d4fba8b9Smrg    {
144d4fba8b9Smrg	0, 0, 0, NULL
145d4fba8b9Smrg    }
146d4fba8b9Smrg};
147d4fba8b9Smrg
148d4fba8b9Smrg#undef MY_UCS
149d4fba8b9Smrg#endif /* OPT_WIDE_CHARS */
150d4fba8b9Smrg
151dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
152dfb07bc7Smrgstatic Boolean merge_sublist(char ***, char **);
153dfb07bc7Smrg#endif
154dfb07bc7Smrg
155dfb07bc7Smrgstatic void save2FontList(XtermWidget, const char *, XtermFontNames *,
156dfb07bc7Smrg			  VTFontEnum, const char *, Bool);
157dfb07bc7Smrg
1580bd37d32Smrg#if OPT_RENDERFONT
1590bd37d32Smrgstatic void fillInFaceSize(XtermWidget, int);
1600bd37d32Smrg#endif
1610bd37d32Smrg
162d522f475Smrg#if OPT_SHIFT_FONTS
1630bd37d32Smrgstatic int lookupOneFontSize(XtermWidget, int);
164d522f475Smrg#endif
165d522f475Smrg
166d4fba8b9Smrg#if OPT_TRACE
167d4fba8b9Smrgstatic void
168d4fba8b9Smrgset_font_height(TScreen *screen, VTwin *win, int height)
169d4fba8b9Smrg{
170d4fba8b9Smrg    SetFontHeight(screen, win, height);
171d4fba8b9Smrg    TRACE(("SetFontHeight %d\n", win->f_height));
172d4fba8b9Smrg#undef SetFontHeight
173d4fba8b9Smrg#define SetFontHeight(screen, win, height) set_font_height(screen, win, height)
174d4fba8b9Smrg}
175d4fba8b9Smrg
176d4fba8b9Smrgstatic void
177d4fba8b9Smrgset_font_width(TScreen *screen, VTwin *win, int width)
178d4fba8b9Smrg{
179d4fba8b9Smrg    (void) screen;
180d4fba8b9Smrg    SetFontWidth(screen, win, width);
181d4fba8b9Smrg    TRACE(("SetFontWidth  %d\n", win->f_width));
182d4fba8b9Smrg#undef  SetFontWidth
183c48a5815Smrg#define SetFontWidth(screen, win, width) set_font_width(screen, win, width)
184d4fba8b9Smrg}
185d4fba8b9Smrg#endif
186d4fba8b9Smrg
187fa3f02f3Smrg#if OPT_REPORT_FONTS || OPT_WIDE_CHARS
1882eaa94a1Schristosstatic unsigned
1899a64e1c5SmrgcountGlyphs(XFontStruct *fp)
190d522f475Smrg{
191d522f475Smrg    unsigned count = 0;
192d522f475Smrg
193d522f475Smrg    if (fp != 0) {
194d522f475Smrg	if (fp->min_byte1 == 0 && fp->max_byte1 == 0) {
195fa3f02f3Smrg	    count = fp->max_char_or_byte2 - fp->min_char_or_byte2 + 1;
196d522f475Smrg	} else if (fp->min_char_or_byte2 < 256
197d522f475Smrg		   && fp->max_char_or_byte2 < 256) {
198d522f475Smrg	    unsigned first = (fp->min_byte1 << 8) + fp->min_char_or_byte2;
199d522f475Smrg	    unsigned last = (fp->max_byte1 << 8) + fp->max_char_or_byte2;
200d522f475Smrg	    count = last + 1 - first;
201d522f475Smrg	}
202d522f475Smrg    }
203d522f475Smrg    return count;
204d522f475Smrg}
205fa3f02f3Smrg#endif
206d522f475Smrg
207fa3f02f3Smrg#if OPT_WIDE_CHARS
208d522f475Smrg/*
209d522f475Smrg * Verify that the wide-bold font is at least a bold font with roughly as many
210d522f475Smrg * glyphs as the wide font.  The counts should be the same, but settle for
211d522f475Smrg * filtering out the worst of the font mismatches.
212d522f475Smrg */
213d522f475Smrgstatic Bool
2149a64e1c5SmrgcompatibleWideCounts(XFontStruct *wfs, XFontStruct *wbfs)
215d522f475Smrg{
216d522f475Smrg    unsigned count_w = countGlyphs(wfs);
217d522f475Smrg    unsigned count_wb = countGlyphs(wbfs);
218d522f475Smrg    if (count_w <= 256 ||
219d522f475Smrg	count_wb <= 256 ||
220d522f475Smrg	((count_w / 4) * 3) > count_wb) {
221d522f475Smrg	TRACE(("...font server lied (count wide %u vs wide-bold %u)\n",
222d522f475Smrg	       count_w, count_wb));
223d522f475Smrg	return False;
224d522f475Smrg    }
225d522f475Smrg    return True;
226d522f475Smrg}
227d522f475Smrg#endif /* OPT_WIDE_CHARS */
228d522f475Smrg
22920d2c4d2Smrg#if OPT_BOX_CHARS
23020d2c4d2Smrgstatic void
23120d2c4d2SmrgsetupPackedFonts(XtermWidget xw)
23220d2c4d2Smrg{
23320d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
23420d2c4d2Smrg    Bool value = False;
23520d2c4d2Smrg
23620d2c4d2Smrg#if OPT_RENDERFONT
2370bd37d32Smrg    if (xw->work.render_font == True) {
238dfb07bc7Smrg	int e;
23920d2c4d2Smrg
240dfb07bc7Smrg	for (e = 0; e < fMAX; ++e) {
241dfb07bc7Smrg	    XTermXftFonts *data = getMyXftFont(xw, e, screen->menu_font_number);
242dfb07bc7Smrg	    if (data != 0) {
243dfb07bc7Smrg		if (data->map.mixed) {
244dfb07bc7Smrg		    screen->allow_packing = True;
245dfb07bc7Smrg		    break;
246dfb07bc7Smrg		}
247dfb07bc7Smrg	    }
248dfb07bc7Smrg	}
24920d2c4d2Smrg    }
25020d2c4d2Smrg#endif /* OPT_RENDERFONT */
25120d2c4d2Smrg
25220d2c4d2Smrg    value = screen->allow_packing;
25320d2c4d2Smrg
25420d2c4d2Smrg    SetItemSensitivity(fontMenuEntries[fontMenu_font_packedfont].widget, value);
25520d2c4d2Smrg}
25620d2c4d2Smrg#endif
25720d2c4d2Smrg
258d4fba8b9Smrgtypedef struct _nameList {
259d4fba8b9Smrg    struct _nameList *next;
260d4fba8b9Smrg    char *name;
261d4fba8b9Smrg} NameList;
262d4fba8b9Smrg
263d4fba8b9Smrgstatic NameList *derived_fonts;
264d4fba8b9Smrg
265d4fba8b9Smrgstatic Boolean
266d4fba8b9Smrgis_derived_font_name(const char *name)
267d4fba8b9Smrg{
268d4fba8b9Smrg    Boolean result = False;
269d4fba8b9Smrg    NameList *list;
270d4fba8b9Smrg    if (!IsEmpty(name)) {
271d4fba8b9Smrg	for (list = derived_fonts; list != 0; list = list->next) {
272d4fba8b9Smrg	    if (!x_strcasecmp(name, list->name)) {
273d4fba8b9Smrg		result = True;
274d4fba8b9Smrg		break;
275d4fba8b9Smrg	    }
276d4fba8b9Smrg	}
277d4fba8b9Smrg    }
278d4fba8b9Smrg    return result;
279d4fba8b9Smrg}
280d4fba8b9Smrg
281d4fba8b9Smrgvoid
282d4fba8b9SmrgxtermDerivedFont(const char *name)
283d4fba8b9Smrg{
284d4fba8b9Smrg    if (!IsEmpty(name) && !is_derived_font_name(name)) {
285d4fba8b9Smrg	NameList *list = TypeCalloc(NameList);
286d4fba8b9Smrg	list->name = x_strdup(name);
287d4fba8b9Smrg	list->next = derived_fonts;
288d4fba8b9Smrg	derived_fonts = list;
289d4fba8b9Smrg    }
290d4fba8b9Smrg}
291d4fba8b9Smrg
292d522f475Smrg/*
293d522f475Smrg * Returns the fields from start to stop in a dash- separated string.  This
2949a64e1c5Smrg * function will modify the source, putting '\0's in the appropriate place and
295d522f475Smrg * moving the beginning forward to after the '\0'
296d522f475Smrg *
297d522f475Smrg * This will NOT work for the last field (but we won't need it).
298d522f475Smrg */
299d522f475Smrgstatic char *
300d522f475Smrgn_fields(char **source, int start, int stop)
301d522f475Smrg{
302d522f475Smrg    int i;
303d522f475Smrg    char *str, *str1;
304d522f475Smrg
305d522f475Smrg    /*
306d522f475Smrg     * find the start-1th dash
307d522f475Smrg     */
3089a64e1c5Smrg    for (i = start - 1, str = *source; i; i--, str++) {
309d522f475Smrg	if ((str = strchr(str, '-')) == 0)
310d522f475Smrg	    return 0;
3119a64e1c5Smrg    }
312d522f475Smrg
313d522f475Smrg    /*
314d522f475Smrg     * find the stopth dash
315d522f475Smrg     */
3169a64e1c5Smrg    for (i = stop - start + 1, str1 = str; i; i--, str1++) {
317d522f475Smrg	if ((str1 = strchr(str1, '-')) == 0)
318d522f475Smrg	    return 0;
3199a64e1c5Smrg    }
320d522f475Smrg
321d522f475Smrg    /*
322d522f475Smrg     * put a \0 at the end of the fields
323d522f475Smrg     */
324d522f475Smrg    *(str1 - 1) = '\0';
325d522f475Smrg
326d522f475Smrg    /*
327d522f475Smrg     * move source forward
328d522f475Smrg     */
329d522f475Smrg    *source = str1;
330d522f475Smrg
331d522f475Smrg    return str;
332d522f475Smrg}
333d522f475Smrg
334956cc18dSsnjstatic Boolean
335956cc18dSsnjcheck_fontname(const char *name)
336956cc18dSsnj{
337956cc18dSsnj    Boolean result = True;
338956cc18dSsnj
339492d43a5Smrg    if (IsEmpty(name)) {
340956cc18dSsnj	TRACE(("fontname missing\n"));
341956cc18dSsnj	result = False;
342956cc18dSsnj    }
343956cc18dSsnj    return result;
344956cc18dSsnj}
345956cc18dSsnj
346d522f475Smrg/*
347d522f475Smrg * Gets the font properties from a given font structure.  We use the FONT name
348d522f475Smrg * to find them out, since that seems easier.
349d522f475Smrg *
350d522f475Smrg * Returns a pointer to a static FontNameProperties structure
351d522f475Smrg * or NULL on error.
352d522f475Smrg */
353d522f475Smrgstatic FontNameProperties *
3549a64e1c5Smrgget_font_name_props(Display *dpy, XFontStruct *fs, char **result)
355d522f475Smrg{
356d522f475Smrg    static FontNameProperties props;
357d522f475Smrg    static char *last_name;
358d522f475Smrg
359d4fba8b9Smrg    Atom fontatom;
360d4fba8b9Smrg    char *name;
361d522f475Smrg    char *str;
362d522f475Smrg
363d4fba8b9Smrg    if (fs == NULL)
364d4fba8b9Smrg	return NULL;
365d4fba8b9Smrg
366d522f475Smrg    /*
367d522f475Smrg     * first get the full font name
368d522f475Smrg     */
369d4fba8b9Smrg    name = 0;
370d4fba8b9Smrg    fontatom = XInternAtom(dpy, "FONT", False);
37120d2c4d2Smrg    if (fontatom != 0) {
372037a25ddSmrg	XFontProp *fp;
373037a25ddSmrg	int i;
374037a25ddSmrg
37520d2c4d2Smrg	for (i = 0, fp = fs->properties; i < fs->n_properties; i++, fp++) {
37620d2c4d2Smrg	    if (fp->name == fontatom) {
37720d2c4d2Smrg		name = XGetAtomName(dpy, fp->card32);
37820d2c4d2Smrg		break;
37920d2c4d2Smrg	    }
38020d2c4d2Smrg	}
38120d2c4d2Smrg    }
382d522f475Smrg
383d522f475Smrg    if (name == 0)
384d522f475Smrg	return 0;
385d522f475Smrg
386d522f475Smrg    /*
387d522f475Smrg     * XGetAtomName allocates memory - don't leak
388d522f475Smrg     */
389d4fba8b9Smrg    XFree(last_name);
390d522f475Smrg    last_name = name;
391d522f475Smrg
392d522f475Smrg    if (result != 0) {
393956cc18dSsnj	if (!check_fontname(name))
394d522f475Smrg	    return 0;
395d4fba8b9Smrg	free(*result);
3960bd37d32Smrg	*result = x_strdup(name);
397d522f475Smrg    }
398d522f475Smrg
399d522f475Smrg    /*
400d522f475Smrg     * Now split it up into parts and put them in
401d522f475Smrg     * their places. Since we are using parts of
402d522f475Smrg     * the original string, we must not free the Atom Name
403d522f475Smrg     */
404d522f475Smrg
405d522f475Smrg    /* registry, foundry, family */
406d522f475Smrg    if ((props.beginning = n_fields(&name, 1, 3)) == 0)
407d522f475Smrg	return 0;
408d522f475Smrg
409d522f475Smrg    /* weight is the next */
410d522f475Smrg    if ((props.weight = n_fields(&name, 1, 1)) == 0)
411d522f475Smrg	return 0;
412d522f475Smrg
413d522f475Smrg    /* slant */
414d522f475Smrg    if ((props.slant = n_fields(&name, 1, 1)) == 0)
415d522f475Smrg	return 0;
416d522f475Smrg
417d522f475Smrg    /* width */
418d522f475Smrg    if ((props.wideness = n_fields(&name, 1, 1)) == 0)
419d522f475Smrg	return 0;
420d522f475Smrg
421d522f475Smrg    /* add style */
422d522f475Smrg    if ((props.add_style = n_fields(&name, 1, 1)) == 0)
423d522f475Smrg	return 0;
424d522f475Smrg
425d522f475Smrg    /* pixel size */
426d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
427d522f475Smrg	return 0;
428d522f475Smrg    if ((props.pixel_size = atoi(str)) == 0)
429d522f475Smrg	return 0;
430d522f475Smrg
431d522f475Smrg    /* point size */
432d522f475Smrg    if ((props.point_size = n_fields(&name, 1, 1)) == 0)
433d522f475Smrg	return 0;
434d522f475Smrg
435d522f475Smrg    /* res_x */
436d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
437d522f475Smrg	return 0;
438d522f475Smrg    if ((props.res_x = atoi(str)) == 0)
439d522f475Smrg	return 0;
440d522f475Smrg
441d522f475Smrg    /* res_y */
442d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
443d522f475Smrg	return 0;
444d522f475Smrg    if ((props.res_y = atoi(str)) == 0)
445d522f475Smrg	return 0;
446d522f475Smrg
447d522f475Smrg    /* spacing */
448d522f475Smrg    if ((props.spacing = n_fields(&name, 1, 1)) == 0)
449d522f475Smrg	return 0;
450d522f475Smrg
451d522f475Smrg    /* average width */
452d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
453d522f475Smrg	return 0;
454d522f475Smrg    if ((props.average_width = atoi(str)) == 0)
455d522f475Smrg	return 0;
456d522f475Smrg
457d522f475Smrg    /* the rest: charset registry and charset encoding */
458d522f475Smrg    props.end = name;
459d522f475Smrg
460d522f475Smrg    return &props;
461d522f475Smrg}
462d522f475Smrg
463d522f475Smrg#define ALLOCHUNK(n) ((n | 127) + 1)
464d522f475Smrg
465d522f475Smrgstatic void
466956cc18dSsnjalloca_fontname(char **result, size_t next)
467d522f475Smrg{
468956cc18dSsnj    size_t last = (*result != 0) ? strlen(*result) : 0;
469956cc18dSsnj    size_t have = (*result != 0) ? ALLOCHUNK(last) : 0;
470956cc18dSsnj    size_t want = last + next + 2;
471d522f475Smrg
472d522f475Smrg    if (want >= have) {
47350027b5bSmrg	char *save = *result;
474d522f475Smrg	want = ALLOCHUNK(want);
475d522f475Smrg	if (last != 0) {
476d522f475Smrg	    *result = TypeRealloc(char, want, *result);
4779a64e1c5Smrg	    if (*result == 0)
4789a64e1c5Smrg		free(save);
479d522f475Smrg	} else {
48050027b5bSmrg	    if ((*result = TypeMallocN(char, want)) != 0) {
48150027b5bSmrg		free(save);
482d522f475Smrg		**result = '\0';
48350027b5bSmrg	    }
484d522f475Smrg	}
485d522f475Smrg    }
486d522f475Smrg}
487d522f475Smrg
488d522f475Smrgstatic void
48920d2c4d2Smrgappend_fontname_str(char **result, const char *value)
490d522f475Smrg{
491d522f475Smrg    if (value == 0)
492d522f475Smrg	value = "*";
493d522f475Smrg    alloca_fontname(result, strlen(value));
494d522f475Smrg    if (*result != 0) {
495d522f475Smrg	if (**result != '\0')
496d522f475Smrg	    strcat(*result, "-");
497d522f475Smrg	strcat(*result, value);
498d522f475Smrg    }
499d522f475Smrg}
500d522f475Smrg
501d522f475Smrgstatic void
502d522f475Smrgappend_fontname_num(char **result, int value)
503d522f475Smrg{
504d522f475Smrg    if (value < 0) {
505d522f475Smrg	append_fontname_str(result, "*");
506d522f475Smrg    } else {
507d522f475Smrg	char temp[100];
508d522f475Smrg	sprintf(temp, "%d", value);
509d522f475Smrg	append_fontname_str(result, temp);
510d522f475Smrg    }
511d522f475Smrg}
512d522f475Smrg
513d522f475Smrg/*
514d522f475Smrg * Take the given font props and try to make a well formed font name specifying
515d522f475Smrg * the same base font and size and everything, but with different weight/width
516d522f475Smrg * according to the parameters.  The return value is allocated, should be freed
517d522f475Smrg * by the caller.
518d522f475Smrg */
519d522f475Smrgstatic char *
5209a64e1c5Smrgderive_font_name(FontNameProperties *props,
52120d2c4d2Smrg		 const char *use_weight,
522d522f475Smrg		 int use_average_width,
52320d2c4d2Smrg		 const char *use_encoding)
524d522f475Smrg{
525d522f475Smrg    char *result = 0;
526d522f475Smrg
527d522f475Smrg    append_fontname_str(&result, props->beginning);
528d522f475Smrg    append_fontname_str(&result, use_weight);
529d522f475Smrg    append_fontname_str(&result, props->slant);
530d522f475Smrg    append_fontname_str(&result, 0);
531d522f475Smrg    append_fontname_str(&result, 0);
532d522f475Smrg    append_fontname_num(&result, props->pixel_size);
533d522f475Smrg    append_fontname_str(&result, props->point_size);
534d522f475Smrg    append_fontname_num(&result, props->res_x);
535d522f475Smrg    append_fontname_num(&result, props->res_y);
536d522f475Smrg    append_fontname_str(&result, props->spacing);
537d522f475Smrg    append_fontname_num(&result, use_average_width);
538d522f475Smrg    append_fontname_str(&result, use_encoding);
539d522f475Smrg
540d4fba8b9Smrg    xtermDerivedFont(result);
541d522f475Smrg    return result;
542d522f475Smrg}
543d522f475Smrg
544d522f475Smrgstatic char *
5459a64e1c5Smrgbold_font_name(FontNameProperties *props, int use_average_width)
546d522f475Smrg{
547d522f475Smrg    return derive_font_name(props, "bold", use_average_width, props->end);
548d522f475Smrg}
549d522f475Smrg
5509a64e1c5Smrg#if OPT_WIDE_ATTRS
5519a64e1c5Smrgstatic char *
552dfb07bc7Smrgitalic_font_name(FontNameProperties *props, const char *slant)
5539a64e1c5Smrg{
5549a64e1c5Smrg    FontNameProperties myprops = *props;
555dfb07bc7Smrg    myprops.slant = slant;
556dfb07bc7Smrg    return derive_font_name(&myprops, props->weight, myprops.average_width, props->end);
557dfb07bc7Smrg}
558dfb07bc7Smrg
559dfb07bc7Smrgstatic Boolean
560dfb07bc7Smrgopen_italic_font(XtermWidget xw, int n, FontNameProperties *fp, XTermFonts * data)
561dfb07bc7Smrg{
562dfb07bc7Smrg    static const char *slant[] =
563dfb07bc7Smrg    {
564dfb07bc7Smrg	"o",
565dfb07bc7Smrg	"i"
566dfb07bc7Smrg    };
567dfb07bc7Smrg    Cardinal pass;
568dfb07bc7Smrg    Boolean result = False;
569dfb07bc7Smrg
570d4fba8b9Smrg    NoFontWarning(data);
571dfb07bc7Smrg    for (pass = 0; pass < XtNumber(slant); ++pass) {
572d4fba8b9Smrg	char *name;
573dfb07bc7Smrg	if ((name = italic_font_name(fp, slant[pass])) != 0) {
574dfb07bc7Smrg	    TRACE(("open_italic_font %s %s\n",
575dfb07bc7Smrg		   whichFontEnum((VTFontEnum) n), name));
576dfb07bc7Smrg	    if (xtermOpenFont(xw, name, data, False)) {
577dfb07bc7Smrg		result = (data->fs != 0);
578dfb07bc7Smrg#if OPT_REPORT_FONTS
579dfb07bc7Smrg		if (resource.reportFonts) {
580dfb07bc7Smrg		    printf("opened italic version of %s:\n\t%s\n",
581d4fba8b9Smrg			   whichFontEnum((VTFontEnum) n),
582dfb07bc7Smrg			   name);
583dfb07bc7Smrg		}
584dfb07bc7Smrg#endif
585dfb07bc7Smrg	    }
586dfb07bc7Smrg	    free(name);
587dfb07bc7Smrg	    if (result)
588dfb07bc7Smrg		break;
589dfb07bc7Smrg	}
590dfb07bc7Smrg    }
591dfb07bc7Smrg#if OPT_TRACE
592dfb07bc7Smrg    if (result) {
593dfb07bc7Smrg	XFontStruct *fs = data->fs;
594dfb07bc7Smrg	if (fs != 0) {
595dfb07bc7Smrg	    TRACE(("...actual size %dx%d (ascent %d, descent %d)\n",
596dfb07bc7Smrg		   fs->ascent +
597dfb07bc7Smrg		   fs->descent,
598dfb07bc7Smrg		   fs->max_bounds.width,
599dfb07bc7Smrg		   fs->ascent,
600dfb07bc7Smrg		   fs->descent));
601dfb07bc7Smrg	}
602dfb07bc7Smrg    }
603dfb07bc7Smrg#endif
604dfb07bc7Smrg    return result;
6059a64e1c5Smrg}
6069a64e1c5Smrg#endif
6079a64e1c5Smrg
608d522f475Smrg#if OPT_WIDE_CHARS
609d522f475Smrg#define derive_wide_font(props, weight) \
610d522f475Smrg	derive_font_name(props, weight, props->average_width * 2, "ISO10646-1")
611d522f475Smrg
612d522f475Smrgstatic char *
6139a64e1c5Smrgwide_font_name(FontNameProperties *props)
614d522f475Smrg{
615d522f475Smrg    return derive_wide_font(props, "medium");
616d522f475Smrg}
617d522f475Smrg
618d522f475Smrgstatic char *
6199a64e1c5Smrgwidebold_font_name(FontNameProperties *props)
620d522f475Smrg{
621d522f475Smrg    return derive_wide_font(props, "bold");
622d522f475Smrg}
623d522f475Smrg#endif /* OPT_WIDE_CHARS */
624d522f475Smrg
625d522f475Smrg#if OPT_DEC_CHRSET
626d522f475Smrg/*
627d522f475Smrg * Take the given font props and try to make a well formed font name specifying
628d522f475Smrg * the same base font but changed depending on the given attributes and chrset.
629d522f475Smrg *
630d522f475Smrg * For double width fonts, we just double the X-resolution, for double height
631d522f475Smrg * fonts we double the pixel-size and Y-resolution
632d522f475Smrg */
633d522f475Smrgchar *
634d4fba8b9SmrgxtermSpecialFont(XTermDraw * params)
635d522f475Smrg{
636d4fba8b9Smrg    TScreen *screen = TScreenOf(params->xw);
637d522f475Smrg#if OPT_TRACE
638d522f475Smrg    static char old_spacing[80];
639d522f475Smrg    static FontNameProperties old_props;
640d522f475Smrg#endif
641d522f475Smrg    FontNameProperties *props;
642d522f475Smrg    char *result = 0;
64320d2c4d2Smrg    const char *weight;
644d522f475Smrg    int pixel_size;
645d522f475Smrg    int res_x;
646d522f475Smrg    int res_y;
647d522f475Smrg
648dfb07bc7Smrg    props = get_font_name_props(screen->display,
649d4fba8b9Smrg				GetNormalFont(screen, fNorm)->fs, 0);
650d522f475Smrg    if (props == 0)
651d522f475Smrg	return result;
652d522f475Smrg
653d522f475Smrg    pixel_size = props->pixel_size;
654d522f475Smrg    res_x = props->res_x;
655d522f475Smrg    res_y = props->res_y;
656d4fba8b9Smrg    if (params->attr_flags & BOLD)
657d522f475Smrg	weight = "bold";
658d522f475Smrg    else
659d522f475Smrg	weight = props->weight;
660d522f475Smrg
661d4fba8b9Smrg    if (CSET_DOUBLE(params->this_chrset))
662d522f475Smrg	res_x *= 2;
663d522f475Smrg
664d4fba8b9Smrg    if (params->this_chrset == CSET_DHL_TOP
665d4fba8b9Smrg	|| params->this_chrset == CSET_DHL_BOT) {
666d522f475Smrg	res_y *= 2;
667d522f475Smrg	pixel_size *= 2;
668d522f475Smrg    }
669d522f475Smrg#if OPT_TRACE
670d522f475Smrg    if (old_props.res_x != res_x
671d522f475Smrg	|| old_props.res_x != res_y
672d522f475Smrg	|| old_props.pixel_size != pixel_size
673d522f475Smrg	|| strcmp(old_props.spacing, props->spacing)) {
6749a64e1c5Smrg	TRACE(("xtermSpecialFont(atts = %#x, draw = %#x, chrset = %#x)\n",
675d4fba8b9Smrg	       params->attr_flags, params->draw_flags, params->this_chrset));
676d522f475Smrg	TRACE(("res_x      = %d\n", res_x));
677d522f475Smrg	TRACE(("res_y      = %d\n", res_y));
678d522f475Smrg	TRACE(("point_size = %s\n", props->point_size));
679d522f475Smrg	TRACE(("pixel_size = %d\n", pixel_size));
680d522f475Smrg	TRACE(("spacing    = %s\n", props->spacing));
681d522f475Smrg	old_props.res_x = res_x;
682037a25ddSmrg	old_props.res_y = res_y;
683d522f475Smrg	old_props.pixel_size = pixel_size;
6840bd37d32Smrg	old_props.spacing = old_spacing;
6850bd37d32Smrg	sprintf(old_spacing, "%.*s", (int) sizeof(old_spacing) - 2, props->spacing);
686d522f475Smrg    }
687d522f475Smrg#endif
688d522f475Smrg
689d522f475Smrg    append_fontname_str(&result, props->beginning);
690d522f475Smrg    append_fontname_str(&result, weight);
691d522f475Smrg    append_fontname_str(&result, props->slant);
692d522f475Smrg    append_fontname_str(&result, props->wideness);
693d522f475Smrg    append_fontname_str(&result, props->add_style);
694d522f475Smrg    append_fontname_num(&result, pixel_size);
695d522f475Smrg    append_fontname_str(&result, props->point_size);
696d4fba8b9Smrg    append_fontname_num(&result, (params->draw_flags & NORESOLUTION) ? -1 : res_x);
697d4fba8b9Smrg    append_fontname_num(&result, (params->draw_flags & NORESOLUTION) ? -1 : res_y);
698d522f475Smrg    append_fontname_str(&result, props->spacing);
699d522f475Smrg    append_fontname_str(&result, 0);
700d522f475Smrg    append_fontname_str(&result, props->end);
701d522f475Smrg
702d4fba8b9Smrg    xtermDerivedFont(result);
703d522f475Smrg    return result;
704d522f475Smrg}
705d522f475Smrg#endif /* OPT_DEC_CHRSET */
706d522f475Smrg
707d522f475Smrg/*
708d522f475Smrg * Case-independent comparison for font-names, including wildcards.
709d522f475Smrg * XLFD allows '?' as a wildcard, but we do not handle that (no one seems
710d522f475Smrg * to use it).
711d522f475Smrg */
712d522f475Smrgstatic Bool
713492d43a5Smrgsame_font_name(const char *pattern, const char *match)
714d522f475Smrg{
715956cc18dSsnj    Bool result = False;
716956cc18dSsnj
717956cc18dSsnj    if (pattern && match) {
718956cc18dSsnj	while (*pattern && *match) {
719956cc18dSsnj	    if (*pattern == *match) {
720956cc18dSsnj		pattern++;
721956cc18dSsnj		match++;
722956cc18dSsnj	    } else if (*pattern == '*' || *match == '*') {
723956cc18dSsnj		if (same_font_name(pattern + 1, match)) {
724956cc18dSsnj		    return True;
725956cc18dSsnj		} else if (same_font_name(pattern, match + 1)) {
726956cc18dSsnj		    return True;
727956cc18dSsnj		} else {
728956cc18dSsnj		    return False;
729956cc18dSsnj		}
730d522f475Smrg	    } else {
731956cc18dSsnj		int p = x_toupper(*pattern++);
732956cc18dSsnj		int m = x_toupper(*match++);
733956cc18dSsnj		if (p != m)
734956cc18dSsnj		    return False;
735d522f475Smrg	    }
736d522f475Smrg	}
737956cc18dSsnj	result = (*pattern == *match);	/* both should be NUL */
738d522f475Smrg    }
739956cc18dSsnj    return result;
740d522f475Smrg}
741d522f475Smrg
742d522f475Smrg/*
743d522f475Smrg * Double-check the fontname that we asked for versus what the font server
744d522f475Smrg * actually gave us.  The larger fixed fonts do not always have a matching bold
745d522f475Smrg * font, and the font server may try to scale another font or otherwise
746d522f475Smrg * substitute a mismatched font.
747d522f475Smrg *
748d522f475Smrg * If we cannot get what we requested, we will fallback to the original
749d522f475Smrg * behavior, which simulates bold by overstriking each character at one pixel
750d522f475Smrg * offset.
751d522f475Smrg */
752d522f475Smrgstatic int
7539a64e1c5Smrggot_bold_font(Display *dpy, XFontStruct *fs, String requested)
754d522f475Smrg{
7550bd37d32Smrg    char *actual = 0;
756d522f475Smrg    int got;
757d522f475Smrg
7580bd37d32Smrg    if (get_font_name_props(dpy, fs, &actual) == 0)
759d522f475Smrg	got = 0;
760d522f475Smrg    else
761d522f475Smrg	got = same_font_name(requested, actual);
7620bd37d32Smrg    free(actual);
763d522f475Smrg    return got;
764d522f475Smrg}
765d522f475Smrg
7669a64e1c5Smrg/*
7679a64e1c5Smrg * Check normal/bold (or wide/wide-bold) font pairs to see if we will be able
7689a64e1c5Smrg * to check for missing glyphs in a comparable manner.
7699a64e1c5Smrg */
7709a64e1c5Smrgstatic int
7719a64e1c5Smrgcomparable_metrics(XFontStruct *normal, XFontStruct *bold)
7729a64e1c5Smrg{
7739a64e1c5Smrg#define DATA "comparable_metrics: "
7749a64e1c5Smrg    int result = 0;
7759a64e1c5Smrg
776dfb07bc7Smrg    if (normal == 0 || bold == 0) {
777dfb07bc7Smrg	;
778dfb07bc7Smrg    } else if (normal->all_chars_exist) {
7799a64e1c5Smrg	if (bold->all_chars_exist) {
7809a64e1c5Smrg	    result = 1;
7819a64e1c5Smrg	} else {
7829a64e1c5Smrg	    TRACE((DATA "all chars exist in normal font, but not in bold\n"));
7839a64e1c5Smrg	}
7849a64e1c5Smrg    } else if (normal->per_char != 0) {
7859a64e1c5Smrg	if (bold->per_char != 0) {
7869a64e1c5Smrg	    result = 1;
7879a64e1c5Smrg	} else {
7889a64e1c5Smrg	    TRACE((DATA "normal font has per-char metrics, but not bold\n"));
7899a64e1c5Smrg	}
7909a64e1c5Smrg    } else {
7919a64e1c5Smrg	TRACE((DATA "normal font is not very good!\n"));
7929a64e1c5Smrg	result = 1;		/* give in (we're not going in reverse) */
7939a64e1c5Smrg    }
7949a64e1c5Smrg    return result;
7959a64e1c5Smrg#undef DATA
7969a64e1c5Smrg}
7979a64e1c5Smrg
798d522f475Smrg/*
799d522f475Smrg * If the font server tries to adjust another font, it may not adjust it
800d522f475Smrg * properly.  Check that the bounding boxes are compatible.  Otherwise we'll
801d522f475Smrg * leave trash on the display when we mix normal and bold fonts.
802d522f475Smrg */
803d522f475Smrgstatic int
8049a64e1c5Smrgsame_font_size(XtermWidget xw, XFontStruct *nfs, XFontStruct *bfs)
805d522f475Smrg{
806956cc18dSsnj    TScreen *screen = TScreenOf(xw);
807dfb07bc7Smrg    int result = 0;
808dfb07bc7Smrg
809dfb07bc7Smrg    if (nfs != 0 && bfs != 0) {
810dfb07bc7Smrg	TRACE(("same_font_size height %d/%d, min %d/%d max %d/%d\n",
811dfb07bc7Smrg	       nfs->ascent + nfs->descent,
812dfb07bc7Smrg	       bfs->ascent + bfs->descent,
813dfb07bc7Smrg	       nfs->min_bounds.width, bfs->min_bounds.width,
814dfb07bc7Smrg	       nfs->max_bounds.width, bfs->max_bounds.width));
815dfb07bc7Smrg	result = screen->free_bold_box
816dfb07bc7Smrg	    || ((nfs->ascent + nfs->descent) == (bfs->ascent + bfs->descent)
817dfb07bc7Smrg		&& (nfs->min_bounds.width == bfs->min_bounds.width
818dfb07bc7Smrg		    || nfs->min_bounds.width == bfs->min_bounds.width + 1)
819dfb07bc7Smrg		&& (nfs->max_bounds.width == bfs->max_bounds.width
820dfb07bc7Smrg		    || nfs->max_bounds.width == bfs->max_bounds.width + 1));
821dfb07bc7Smrg    }
822dfb07bc7Smrg    return result;
823d522f475Smrg}
824d522f475Smrg
825d522f475Smrg/*
826d522f475Smrg * Check if the font looks like it has fixed width
827d522f475Smrg */
828d522f475Smrgstatic int
8299a64e1c5Smrgis_fixed_font(XFontStruct *fs)
830d522f475Smrg{
831d522f475Smrg    if (fs)
832d522f475Smrg	return (fs->min_bounds.width == fs->max_bounds.width);
833d522f475Smrg    return 1;
834d522f475Smrg}
835d522f475Smrg
836d4fba8b9Smrgstatic int
837d4fba8b9Smrgdiffering_widths(XFontStruct *a, XFontStruct *b)
838d4fba8b9Smrg{
839d4fba8b9Smrg    int result = 0;
840d4fba8b9Smrg    if (a != NULL && b != NULL && a->max_bounds.width != b->max_bounds.width)
841d4fba8b9Smrg	result = 1;
842d4fba8b9Smrg    return result;
843d4fba8b9Smrg}
844d4fba8b9Smrg
845d522f475Smrg/*
846d522f475Smrg * Check if the font looks like a double width font (i.e. contains
847d522f475Smrg * characters of width X and 2X
848d522f475Smrg */
849d522f475Smrg#if OPT_WIDE_CHARS
850d522f475Smrgstatic int
8519a64e1c5Smrgis_double_width_font(XFontStruct *fs)
852d522f475Smrg{
853d4fba8b9Smrg    return (fs != NULL && ((2 * fs->min_bounds.width) == fs->max_bounds.width));
854d522f475Smrg}
855d522f475Smrg#else
856d522f475Smrg#define is_double_width_font(fs) 0
857d522f475Smrg#endif
858d522f475Smrg
859d522f475Smrg#if OPT_WIDE_CHARS && OPT_RENDERFONT && defined(HAVE_TYPE_FCCHAR32)
860d522f475Smrg#define HALF_WIDTH_TEST_STRING "1234567890"
861d522f475Smrg
862d522f475Smrg/* '1234567890' in Chinese characters in UTF-8 */
863d522f475Smrg#define FULL_WIDTH_TEST_STRING "\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89" \
864d522f475Smrg                               "\xe5\x9b\x9b\xe4\xba\x94" \
865d522f475Smrg			       "\xef\xa7\x91\xe4\xb8\x83\xe5\x85\xab" \
866d522f475Smrg			       "\xe4\xb9\x9d\xef\xa6\xb2"
867d522f475Smrg
868d522f475Smrg/* '1234567890' in Korean script in UTF-8 */
869d522f475Smrg#define FULL_WIDTH_TEST_STRING2 "\xec\x9d\xbc\xec\x9d\xb4\xec\x82\xbc" \
870d522f475Smrg                                "\xec\x82\xac\xec\x98\xa4" \
871d522f475Smrg			        "\xec\x9c\xa1\xec\xb9\xa0\xed\x8c\x94" \
872d522f475Smrg			        "\xea\xb5\xac\xec\x98\x81"
873d522f475Smrg
874d522f475Smrg#define HALF_WIDTH_CHAR1  0x0031	/* '1' */
875d522f475Smrg#define HALF_WIDTH_CHAR2  0x0057	/* 'W' */
876d522f475Smrg#define FULL_WIDTH_CHAR1  0x4E00	/* CJK Ideograph 'number one' */
877d522f475Smrg#define FULL_WIDTH_CHAR2  0xAC00	/* Korean script syllable 'Ka' */
878d522f475Smrg
879d522f475Smrgstatic Bool
8809a64e1c5Smrgis_double_width_font_xft(Display *dpy, XftFont *font)
881d522f475Smrg{
882d522f475Smrg    XGlyphInfo gi1, gi2;
883d522f475Smrg    FcChar32 c1 = HALF_WIDTH_CHAR1, c2 = HALF_WIDTH_CHAR2;
8840bd37d32Smrg    String fwstr = FULL_WIDTH_TEST_STRING;
8850bd37d32Smrg    String hwstr = HALF_WIDTH_TEST_STRING;
886d522f475Smrg
887d522f475Smrg    /* Some Korean fonts don't have Chinese characters at all. */
888d522f475Smrg    if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR1)) {
889d522f475Smrg	if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR2))
890d522f475Smrg	    return False;	/* Not a CJK font */
891d522f475Smrg	else			/* a Korean font without CJK Ideographs */
892d522f475Smrg	    fwstr = FULL_WIDTH_TEST_STRING2;
893d522f475Smrg    }
894d522f475Smrg
895d522f475Smrg    XftTextExtents32(dpy, font, &c1, 1, &gi1);
896d522f475Smrg    XftTextExtents32(dpy, font, &c2, 1, &gi2);
897d522f475Smrg    if (gi1.xOff != gi2.xOff)	/* Not a fixed-width font */
898d522f475Smrg	return False;
899d522f475Smrg
9000bd37d32Smrg    XftTextExtentsUtf8(dpy,
9010bd37d32Smrg		       font,
9020bd37d32Smrg		       (_Xconst FcChar8 *) hwstr,
9030bd37d32Smrg		       (int) strlen(hwstr),
9040bd37d32Smrg		       &gi1);
9050bd37d32Smrg    XftTextExtentsUtf8(dpy,
9060bd37d32Smrg		       font,
9070bd37d32Smrg		       (_Xconst FcChar8 *) fwstr,
9080bd37d32Smrg		       (int) strlen(fwstr),
9090bd37d32Smrg		       &gi2);
910d522f475Smrg
911d522f475Smrg    /*
912d522f475Smrg     * fontconfig and Xft prior to 2.2(?) set the width of half-width
913d522f475Smrg     * characters identical to that of full-width character in CJK double-width
914d522f475Smrg     * (bi-width / monospace) font even though the former is half as wide as
915d522f475Smrg     * the latter.  This was fixed sometime before the release of fontconfig
916d522f475Smrg     * 2.2 in early 2003.  See
917d522f475Smrg     *  http://bugzilla.mozilla.org/show_bug.cgi?id=196312
918d522f475Smrg     * In the meantime, we have to check both possibilities.
919d522f475Smrg     */
920d522f475Smrg    return ((2 * gi1.xOff == gi2.xOff) || (gi1.xOff == gi2.xOff));
921d522f475Smrg}
922d522f475Smrg#else
923d522f475Smrg#define is_double_width_font_xft(dpy, xftfont) 0
924d522f475Smrg#endif
925d522f475Smrg
926d522f475Smrg#define EmptyFont(fs) (fs != 0 \
927d522f475Smrg		   && ((fs)->ascent + (fs)->descent == 0 \
928d522f475Smrg		    || (fs)->max_bounds.width == 0))
929d522f475Smrg
930d522f475Smrg#define FontSize(fs) (((fs)->ascent + (fs)->descent) \
931d522f475Smrg		    *  (fs)->max_bounds.width)
932d522f475Smrg
933d522f475Smrgconst VTFontNames *
93420d2c4d2SmrgxtermFontName(const char *normal)
935d522f475Smrg{
936d522f475Smrg    static VTFontNames data;
9379a64e1c5Smrg    FREE_STRING(data.f_n);
938d522f475Smrg    memset(&data, 0, sizeof(data));
939dfb07bc7Smrg    if (normal)
940dfb07bc7Smrg	data.f_n = x_strdup(normal);
941dfb07bc7Smrg    return &data;
942dfb07bc7Smrg}
943dfb07bc7Smrg
944dfb07bc7Smrgconst VTFontNames *
945dfb07bc7SmrgdefaultVTFontNames(XtermWidget xw)
946dfb07bc7Smrg{
947dfb07bc7Smrg    static VTFontNames data;
948dfb07bc7Smrg    memset(&data, 0, sizeof(data));
949dfb07bc7Smrg    data.f_n = DefaultFontN(xw);
950dfb07bc7Smrg    data.f_b = DefaultFontB(xw);
951dfb07bc7Smrg#if OPT_WIDE_CHARS
952dfb07bc7Smrg    data.f_w = DefaultFontW(xw);
953dfb07bc7Smrg    data.f_wb = DefaultFontWB(xw);
954dfb07bc7Smrg#endif
955d522f475Smrg    return &data;
956d522f475Smrg}
957d522f475Smrg
958d522f475Smrgstatic void
959fa3f02f3Smrgcache_menu_font_name(TScreen *screen, int fontnum, int which, const char *name)
960d522f475Smrg{
961d522f475Smrg    if (name != 0) {
9629a64e1c5Smrg	String last = screen->menu_font_names[fontnum][which];
963d522f475Smrg	if (last != 0) {
964d522f475Smrg	    if (strcmp(last, name)) {
9659a64e1c5Smrg		FREE_STRING(last);
966d522f475Smrg		TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name));
967d522f475Smrg		screen->menu_font_names[fontnum][which] = x_strdup(name);
968d522f475Smrg	    }
969d522f475Smrg	} else {
970d522f475Smrg	    TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name));
971d522f475Smrg	    screen->menu_font_names[fontnum][which] = x_strdup(name);
972d522f475Smrg	}
973d522f475Smrg    }
974d522f475Smrg}
975d522f475Smrg
976dfb07bc7Smrgstatic void
977d4fba8b9SmrgcannotFont(XtermWidget xw, const char *who, const char *tag, const char *name)
978dfb07bc7Smrg{
979d4fba8b9Smrg    static NameList *reported;
980d4fba8b9Smrg    NameList *list;
981dfb07bc7Smrg
982dfb07bc7Smrg    switch (xw->misc.fontWarnings) {
983dfb07bc7Smrg    case fwNever:
984dfb07bc7Smrg	return;
985dfb07bc7Smrg    case fwResource:
986d4fba8b9Smrg	if (is_derived_font_name(name))
987d4fba8b9Smrg	    return;
988dfb07bc7Smrg	break;
989dfb07bc7Smrg    case fwAlways:
990dfb07bc7Smrg	break;
991dfb07bc7Smrg    }
992d4fba8b9Smrg    for (list = reported; list != 0; list = list->next) {
993d4fba8b9Smrg	if (!x_strcasecmp(name, list->name)) {
994d4fba8b9Smrg	    return;
995d4fba8b9Smrg	}
996d4fba8b9Smrg    }
997d4fba8b9Smrg    if ((list = TypeMalloc(NameList)) != 0) {
998d4fba8b9Smrg	list->name = x_strdup(name);
999d4fba8b9Smrg	list->next = reported;
1000d4fba8b9Smrg	reported = list;
1001d4fba8b9Smrg    }
1002d4fba8b9Smrg    xtermWarning("cannot %s%s%s %sfont \"%s\"\n",
1003d4fba8b9Smrg		 who, *tag ? " " : "", tag,
1004d4fba8b9Smrg		 is_derived_font_name(name) ? "derived " : "",
1005d4fba8b9Smrg		 name);
1006dfb07bc7Smrg}
1007dfb07bc7Smrg
1008d4fba8b9Smrg#if OPT_RENDERFONT
1009d4fba8b9Smrgstatic void
1010d4fba8b9SmrgnoUsableXft(XtermWidget xw, const char *name)
1011d4fba8b9Smrg{
1012d4fba8b9Smrg    switch (xw->misc.fontWarnings) {
1013d4fba8b9Smrg    case fwNever:
1014d4fba8b9Smrg	return;
1015d4fba8b9Smrg    case fwResource:
1016d4fba8b9Smrg	/* these combinations of wide/bold/italic are all "derived" */
1017d4fba8b9Smrg	return;
1018d4fba8b9Smrg    case fwAlways:
1019d4fba8b9Smrg	break;
1020d4fba8b9Smrg    }
1021d4fba8b9Smrg    xtermWarning("did not find a usable %s TrueType font\n", name);
1022d4fba8b9Smrg}
1023d4fba8b9Smrg#endif
1024d4fba8b9Smrg
10258f44fb3bSmrgXFontStruct *
10268f44fb3bSmrgxtermLoadQueryFont(XtermWidget xw, const char *name)
10278f44fb3bSmrg{
10288f44fb3bSmrg    XFontStruct *result = NULL;
10298f44fb3bSmrg    size_t have = strlen(name);
10308f44fb3bSmrg    if (have == 0 || have > MAX_U_STRING) {
10318f44fb3bSmrg	;			/* just ignore it */
10328f44fb3bSmrg    } else {
10338f44fb3bSmrg	TScreen *screen = TScreenOf(xw);
10348f44fb3bSmrg	result = XLoadQueryFont(screen->display, name);
10358f44fb3bSmrg    }
10368f44fb3bSmrg    return result;
10378f44fb3bSmrg}
10388f44fb3bSmrg
1039d522f475Smrg/*
1040d522f475Smrg * Open the given font and verify that it is non-empty.  Return a null on
1041d522f475Smrg * failure.
1042d522f475Smrg */
1043d522f475SmrgBool
1044956cc18dSsnjxtermOpenFont(XtermWidget xw,
1045956cc18dSsnj	      const char *name,
1046956cc18dSsnj	      XTermFonts * result,
1047956cc18dSsnj	      Bool force)
1048d522f475Smrg{
1049d522f475Smrg    Bool code = False;
1050d522f475Smrg
1051d4fba8b9Smrg    TRACE(("xtermOpenFont %d:%d '%s'\n",
1052d4fba8b9Smrg	   result->warn, xw->misc.fontWarnings, NonNull(name)));
1053492d43a5Smrg    if (!IsEmpty(name)) {
10548f44fb3bSmrg	if ((result->fs = xtermLoadQueryFont(xw, name)) != 0) {
1055956cc18dSsnj	    code = True;
1056956cc18dSsnj	    if (EmptyFont(result->fs)) {
1057dfb07bc7Smrg		xtermCloseFont(xw, result);
1058956cc18dSsnj		code = False;
1059956cc18dSsnj	    } else {
1060956cc18dSsnj		result->fn = x_strdup(name);
1061956cc18dSsnj	    }
106220d2c4d2Smrg	} else if (XmuCompareISOLatin1(name, DEFFONT) != 0) {
1063dfb07bc7Smrg	    if (result->warn <= xw->misc.fontWarnings
1064956cc18dSsnj#if OPT_RENDERFONT
1065956cc18dSsnj		&& !UsingRenderFont(xw)
1066956cc18dSsnj#endif
1067956cc18dSsnj		) {
1068dfb07bc7Smrg		cannotFont(xw, "load", "", name);
1069956cc18dSsnj	    } else {
1070492d43a5Smrg		TRACE(("xtermOpenFont: cannot load font '%s'\n", name));
1071956cc18dSsnj	    }
1072956cc18dSsnj	    if (force) {
1073d4fba8b9Smrg		NoFontWarning(result);
1074dfb07bc7Smrg		code = xtermOpenFont(xw, DEFFONT, result, True);
1075956cc18dSsnj	    }
1076d522f475Smrg	}
1077d522f475Smrg    }
1078d4fba8b9Smrg    NoFontWarning(result);
1079d522f475Smrg    return code;
1080d522f475Smrg}
1081d522f475Smrg
1082d522f475Smrg/*
1083956cc18dSsnj * Close the font and free the font info.
1084d522f475Smrg */
1085dfb07bc7Smrgvoid
1086d522f475SmrgxtermCloseFont(XtermWidget xw, XTermFonts * fnt)
1087d522f475Smrg{
1088d522f475Smrg    if (fnt != 0 && fnt->fs != 0) {
1089d522f475Smrg	TScreen *screen = TScreenOf(xw);
1090d522f475Smrg
1091d522f475Smrg	clrCgsFonts(xw, WhichVWin(screen), fnt);
1092d522f475Smrg	XFreeFont(screen->display, fnt->fs);
1093d522f475Smrg	xtermFreeFontInfo(fnt);
1094d522f475Smrg    }
1095d522f475Smrg}
1096d522f475Smrg
1097037a25ddSmrg/*
1098037a25ddSmrg * Close and free the font (as well as any aliases).
1099037a25ddSmrg */
1100037a25ddSmrgstatic void
1101037a25ddSmrgxtermCloseFont2(XtermWidget xw, XTermFonts * fnts, int which)
1102037a25ddSmrg{
1103037a25ddSmrg    XFontStruct *thisFont = fnts[which].fs;
1104037a25ddSmrg
1105037a25ddSmrg    if (thisFont != 0) {
1106037a25ddSmrg	int k;
1107037a25ddSmrg
1108037a25ddSmrg	xtermCloseFont(xw, &fnts[which]);
1109037a25ddSmrg	for (k = 0; k < fMAX; ++k) {
1110037a25ddSmrg	    if (k != which) {
1111037a25ddSmrg		if (thisFont == fnts[k].fs) {
1112037a25ddSmrg		    xtermFreeFontInfo(&fnts[k]);
1113037a25ddSmrg		}
1114037a25ddSmrg	    }
1115037a25ddSmrg	}
1116037a25ddSmrg    }
1117037a25ddSmrg}
1118037a25ddSmrg
1119d522f475Smrg/*
1120d522f475Smrg * Close the listed fonts, noting that some may use copies of the pointer.
1121d522f475Smrg */
1122d522f475Smrgvoid
1123d522f475SmrgxtermCloseFonts(XtermWidget xw, XTermFonts * fnts)
1124d522f475Smrg{
1125037a25ddSmrg    int j;
1126d522f475Smrg
1127d522f475Smrg    for (j = 0; j < fMAX; ++j) {
1128037a25ddSmrg	xtermCloseFont2(xw, fnts, j);
1129d522f475Smrg    }
1130d522f475Smrg}
1131d522f475Smrg
1132d522f475Smrg/*
1133d522f475Smrg * Make a copy of the source, assuming the XFontStruct's to be unique, but
1134d522f475Smrg * ensuring that the names are reallocated to simplify freeing.
1135d522f475Smrg */
1136d522f475Smrgvoid
1137d522f475SmrgxtermCopyFontInfo(XTermFonts * target, XTermFonts * source)
1138d522f475Smrg{
1139d522f475Smrg    xtermFreeFontInfo(target);
1140d522f475Smrg    target->chrset = source->chrset;
1141d522f475Smrg    target->flags = source->flags;
1142d522f475Smrg    target->fn = x_strdup(source->fn);
1143d522f475Smrg    target->fs = source->fs;
1144dfb07bc7Smrg    target->warn = source->warn;
1145d522f475Smrg}
1146d522f475Smrg
1147d522f475Smrgvoid
1148d522f475SmrgxtermFreeFontInfo(XTermFonts * target)
1149d522f475Smrg{
1150d522f475Smrg    target->chrset = 0;
1151d522f475Smrg    target->flags = 0;
1152d4fba8b9Smrg    FreeAndNull(target->fn);
1153d522f475Smrg    target->fs = 0;
1154d522f475Smrg}
1155d522f475Smrg
1156fa3f02f3Smrg#if OPT_REPORT_FONTS
1157fa3f02f3Smrgstatic void
1158fa3f02f3SmrgreportXCharStruct(const char *tag, XCharStruct * cs)
1159fa3f02f3Smrg{
1160fa3f02f3Smrg    printf("\t\t%s:\n", tag);
1161fa3f02f3Smrg    printf("\t\t\tlbearing: %d\n", cs->lbearing);
1162fa3f02f3Smrg    printf("\t\t\trbearing: %d\n", cs->rbearing);
1163fa3f02f3Smrg    printf("\t\t\twidth:    %d\n", cs->width);
1164fa3f02f3Smrg    printf("\t\t\tascent:   %d\n", cs->ascent);
1165fa3f02f3Smrg    printf("\t\t\tdescent:  %d\n", cs->descent);
1166fa3f02f3Smrg}
1167fa3f02f3Smrg
1168fa3f02f3Smrgstatic void
1169fa3f02f3SmrgreportOneVTFont(const char *tag,
1170fa3f02f3Smrg		XTermFonts * fnt)
1171fa3f02f3Smrg{
1172dfb07bc7Smrg    if (!IsEmpty(fnt->fn) && fnt->fs != 0) {
1173fa3f02f3Smrg	XFontStruct *fs = fnt->fs;
1174fa3f02f3Smrg	unsigned first_char = 0;
1175fa3f02f3Smrg	unsigned last_char = 0;
1176fa3f02f3Smrg
1177fa3f02f3Smrg	if (fs->max_byte1 == 0) {
1178fa3f02f3Smrg	    first_char = fs->min_char_or_byte2;
1179fa3f02f3Smrg	    last_char = fs->max_char_or_byte2;
1180fa3f02f3Smrg	} else {
1181fa3f02f3Smrg	    first_char = (fs->min_byte1 * 256) + fs->min_char_or_byte2;
1182fa3f02f3Smrg	    last_char = (fs->max_byte1 * 256) + fs->max_char_or_byte2;
1183fa3f02f3Smrg	}
1184fa3f02f3Smrg
1185fa3f02f3Smrg	printf("\t%s: %s\n", tag, NonNull(fnt->fn));
1186fa3f02f3Smrg	printf("\t\tall chars:     %s\n", fs->all_chars_exist ? "yes" : "no");
1187fa3f02f3Smrg	printf("\t\tdefault char:  %d\n", fs->default_char);
1188fa3f02f3Smrg	printf("\t\tdirection:     %d\n", fs->direction);
1189fa3f02f3Smrg	printf("\t\tascent:        %d\n", fs->ascent);
1190fa3f02f3Smrg	printf("\t\tdescent:       %d\n", fs->descent);
1191fa3f02f3Smrg	printf("\t\tfirst char:    %u\n", first_char);
1192fa3f02f3Smrg	printf("\t\tlast char:     %u\n", last_char);
1193fa3f02f3Smrg	printf("\t\tmaximum-chars: %u\n", countGlyphs(fs));
11949a64e1c5Smrg	if (FontLacksMetrics(fnt)) {
11959a64e1c5Smrg	    printf("\t\tmissing-chars: ?\n");
11969a64e1c5Smrg	    printf("\t\tpresent-chars: ?\n");
11979a64e1c5Smrg	} else {
11989a64e1c5Smrg	    unsigned missing = 0;
1199037a25ddSmrg	    unsigned ch;
12009a64e1c5Smrg	    for (ch = first_char; ch <= last_char; ++ch) {
12019a64e1c5Smrg		if (xtermMissingChar(ch, fnt)) {
12029a64e1c5Smrg		    ++missing;
12039a64e1c5Smrg		}
12049a64e1c5Smrg	    }
12059a64e1c5Smrg	    printf("\t\tmissing-chars: %u\n", missing);
12069a64e1c5Smrg	    printf("\t\tpresent-chars: %u\n", countGlyphs(fs) - missing);
12079a64e1c5Smrg	}
1208fa3f02f3Smrg	printf("\t\tmin_byte1:     %d\n", fs->min_byte1);
1209fa3f02f3Smrg	printf("\t\tmax_byte1:     %d\n", fs->max_byte1);
1210fa3f02f3Smrg	printf("\t\tproperties:    %d\n", fs->n_properties);
1211fa3f02f3Smrg	reportXCharStruct("min_bounds", &(fs->min_bounds));
1212fa3f02f3Smrg	reportXCharStruct("max_bounds", &(fs->max_bounds));
1213fa3f02f3Smrg	/* TODO: report fs->properties and fs->per_char */
1214fa3f02f3Smrg    }
1215fa3f02f3Smrg}
1216fa3f02f3Smrg
1217fa3f02f3Smrgstatic void
1218fa3f02f3SmrgreportVTFontInfo(XtermWidget xw, int fontnum)
1219fa3f02f3Smrg{
1220fa3f02f3Smrg    if (resource.reportFonts) {
1221fa3f02f3Smrg	TScreen *screen = TScreenOf(xw);
1222fa3f02f3Smrg
1223fa3f02f3Smrg	if (fontnum) {
1224fa3f02f3Smrg	    printf("Loaded VTFonts(font%d)\n", fontnum);
1225fa3f02f3Smrg	} else {
1226fa3f02f3Smrg	    printf("Loaded VTFonts(default)\n");
1227fa3f02f3Smrg	}
1228dfb07bc7Smrg
1229d4fba8b9Smrg	reportOneVTFont("fNorm", GetNormalFont(screen, fNorm));
1230d4fba8b9Smrg	reportOneVTFont("fBold", GetNormalFont(screen, fBold));
1231fa3f02f3Smrg#if OPT_WIDE_CHARS
1232d4fba8b9Smrg	reportOneVTFont("fWide", GetNormalFont(screen, fWide));
1233d4fba8b9Smrg	reportOneVTFont("fWBold", GetNormalFont(screen, fWBold));
1234fa3f02f3Smrg#endif
1235fa3f02f3Smrg    }
1236fa3f02f3Smrg}
1237fa3f02f3Smrg#endif
1238fa3f02f3Smrg
12399a64e1c5Smrgvoid
1240d4fba8b9SmrgxtermUpdateFontGCs(XtermWidget xw, MyGetFont myfunc)
12419a64e1c5Smrg{
12429a64e1c5Smrg    TScreen *screen = TScreenOf(xw);
12439a64e1c5Smrg    VTwin *win = WhichVWin(screen);
1244d4fba8b9Smrg    Pixel new_normal = getXtermFG(xw, xw->flags, xw->cur_foreground);
1245d4fba8b9Smrg    Pixel new_revers = getXtermBG(xw, xw->flags, xw->cur_background);
1246dfb07bc7Smrg
12479a64e1c5Smrg    setCgsFore(xw, win, gcNorm, new_normal);
12489a64e1c5Smrg    setCgsBack(xw, win, gcNorm, new_revers);
1249dfb07bc7Smrg    setCgsFont(xw, win, gcNorm, myfunc(screen, fNorm));
12509a64e1c5Smrg
12519a64e1c5Smrg    copyCgs(xw, win, gcBold, gcNorm);
1252d4fba8b9Smrg    setCgsFont2(xw, win, gcBold, myfunc(screen, fBold), fBold);
12539a64e1c5Smrg
12549a64e1c5Smrg    setCgsFore(xw, win, gcNormReverse, new_revers);
12559a64e1c5Smrg    setCgsBack(xw, win, gcNormReverse, new_normal);
1256dfb07bc7Smrg    setCgsFont(xw, win, gcNormReverse, myfunc(screen, fNorm));
12579a64e1c5Smrg
12589a64e1c5Smrg    copyCgs(xw, win, gcBoldReverse, gcNormReverse);
1259d4fba8b9Smrg    setCgsFont2(xw, win, gcBoldReverse, myfunc(screen, fBold), fBold);
12609a64e1c5Smrg
12619a64e1c5Smrg    if_OPT_WIDE_CHARS(screen, {
1262dfb07bc7Smrg	XTermFonts *wide_xx = myfunc(screen, fWide);
1263dfb07bc7Smrg	XTermFonts *bold_xx = myfunc(screen, fWBold);
1264dfb07bc7Smrg	if (wide_xx->fs != 0
1265dfb07bc7Smrg	    && bold_xx->fs != 0) {
12669a64e1c5Smrg	    setCgsFore(xw, win, gcWide, new_normal);
12679a64e1c5Smrg	    setCgsBack(xw, win, gcWide, new_revers);
1268dfb07bc7Smrg	    setCgsFont(xw, win, gcWide, wide_xx);
12699a64e1c5Smrg
12709a64e1c5Smrg	    copyCgs(xw, win, gcWBold, gcWide);
1271dfb07bc7Smrg	    setCgsFont(xw, win, gcWBold, bold_xx);
12729a64e1c5Smrg
12739a64e1c5Smrg	    setCgsFore(xw, win, gcWideReverse, new_revers);
12749a64e1c5Smrg	    setCgsBack(xw, win, gcWideReverse, new_normal);
1275dfb07bc7Smrg	    setCgsFont(xw, win, gcWideReverse, wide_xx);
12769a64e1c5Smrg
12779a64e1c5Smrg	    copyCgs(xw, win, gcWBoldReverse, gcWideReverse);
1278dfb07bc7Smrg	    setCgsFont(xw, win, gcWBoldReverse, bold_xx);
12799a64e1c5Smrg	}
12809a64e1c5Smrg    });
12819a64e1c5Smrg}
12829a64e1c5Smrg
1283d4fba8b9Smrg#if OPT_WIDE_ATTRS
1284d4fba8b9Smrgunsigned
1285d4fba8b9SmrgxtermUpdateItalics(XtermWidget xw, unsigned new_attrs, unsigned old_attrs)
1286d4fba8b9Smrg{
1287c48a5815Smrg    TScreen *screen = TScreenOf(xw);
1288c48a5815Smrg
128950027b5bSmrg    (void) screen;
1290c48a5815Smrg    if (UseItalicFont(screen)) {
1291c48a5815Smrg	if ((new_attrs & ATR_ITALIC) && !(old_attrs & ATR_ITALIC)) {
1292c48a5815Smrg	    xtermLoadItalics(xw);
1293c48a5815Smrg	    xtermUpdateFontGCs(xw, getItalicFont);
1294c48a5815Smrg	} else if (!(new_attrs & ATR_ITALIC) && (old_attrs & ATR_ITALIC)) {
1295c48a5815Smrg	    xtermUpdateFontGCs(xw, getNormalFont);
1296c48a5815Smrg	}
1297d4fba8b9Smrg    }
1298d4fba8b9Smrg    return new_attrs;
1299d4fba8b9Smrg}
1300d4fba8b9Smrg#endif
1301d4fba8b9Smrg
1302d4fba8b9Smrg#if OPT_TRACE && OPT_BOX_CHARS
13039a64e1c5Smrgstatic void
13049a64e1c5Smrgshow_font_misses(const char *name, XTermFonts * fp)
13059a64e1c5Smrg{
13069a64e1c5Smrg    if (fp->fs != 0) {
13079a64e1c5Smrg	if (FontLacksMetrics(fp)) {
13089a64e1c5Smrg	    TRACE(("%s font lacks metrics\n", name));
13099a64e1c5Smrg	} else if (FontIsIncomplete(fp)) {
13109a64e1c5Smrg	    TRACE(("%s font is incomplete\n", name));
13119a64e1c5Smrg	} else {
13129a64e1c5Smrg	    TRACE(("%s font is complete\n", name));
13139a64e1c5Smrg	}
13149a64e1c5Smrg    } else {
13159a64e1c5Smrg	TRACE(("%s font is missing\n", name));
13169a64e1c5Smrg    }
13179a64e1c5Smrg}
13189a64e1c5Smrg#endif
13199a64e1c5Smrg
1320dfb07bc7Smrgstatic Bool
1321dfb07bc7SmrgloadNormFP(XtermWidget xw,
1322dfb07bc7Smrg	   char **nameOutP,
1323dfb07bc7Smrg	   XTermFonts * infoOut,
1324dfb07bc7Smrg	   int fontnum)
1325dfb07bc7Smrg{
1326dfb07bc7Smrg    Bool status = True;
1327dfb07bc7Smrg
1328dfb07bc7Smrg    TRACE(("loadNormFP (%s)\n", NonNull(*nameOutP)));
1329dfb07bc7Smrg
1330dfb07bc7Smrg    if (!xtermOpenFont(xw,
1331dfb07bc7Smrg		       *nameOutP,
1332dfb07bc7Smrg		       infoOut,
1333dfb07bc7Smrg		       (fontnum == fontMenu_default))) {
1334dfb07bc7Smrg	/*
1335dfb07bc7Smrg	 * If we are opening the default font, and it happens to be missing,
1336dfb07bc7Smrg	 * force that to the compiled-in default font, e.g., "fixed".  If we
1337dfb07bc7Smrg	 * cannot open the font, disable it from the menu.
1338dfb07bc7Smrg	 */
1339dfb07bc7Smrg	if (fontnum != fontMenu_fontsel) {
1340dfb07bc7Smrg	    SetItemSensitivity(fontMenuEntries[fontnum].widget, False);
1341dfb07bc7Smrg	}
1342dfb07bc7Smrg	status = False;
1343dfb07bc7Smrg    }
1344dfb07bc7Smrg    return status;
1345dfb07bc7Smrg}
1346dfb07bc7Smrg
1347dfb07bc7Smrgstatic Bool
1348dfb07bc7SmrgloadBoldFP(XtermWidget xw,
1349dfb07bc7Smrg	   char **nameOutP,
1350dfb07bc7Smrg	   XTermFonts * infoOut,
1351dfb07bc7Smrg	   const char *nameRef,
1352dfb07bc7Smrg	   XTermFonts * infoRef,
1353dfb07bc7Smrg	   int fontnum)
1354dfb07bc7Smrg{
1355dfb07bc7Smrg    TScreen *screen = TScreenOf(xw);
1356dfb07bc7Smrg    Bool status = True;
1357dfb07bc7Smrg
1358dfb07bc7Smrg    TRACE(("loadBoldFP (%s)\n", NonNull(*nameOutP)));
1359dfb07bc7Smrg
1360dfb07bc7Smrg    if (!check_fontname(*nameOutP)) {
1361dfb07bc7Smrg	FontNameProperties *fp;
1362dfb07bc7Smrg	char *normal = x_strdup(nameRef);
1363dfb07bc7Smrg
1364dfb07bc7Smrg	fp = get_font_name_props(screen->display, infoRef->fs, &normal);
1365dfb07bc7Smrg	if (fp != 0) {
1366d4fba8b9Smrg	    NoFontWarning(infoOut);
1367dfb07bc7Smrg	    *nameOutP = bold_font_name(fp, fp->average_width);
1368dfb07bc7Smrg	    if (!xtermOpenFont(xw, *nameOutP, infoOut, False)) {
1369dfb07bc7Smrg		free(*nameOutP);
1370dfb07bc7Smrg		*nameOutP = bold_font_name(fp, -1);
1371dfb07bc7Smrg		xtermOpenFont(xw, *nameOutP, infoOut, False);
1372dfb07bc7Smrg	    }
1373dfb07bc7Smrg	    TRACE(("...derived bold '%s'\n", NonNull(*nameOutP)));
1374dfb07bc7Smrg	}
1375dfb07bc7Smrg	if (fp == 0 || infoOut->fs == 0) {
1376dfb07bc7Smrg	    xtermCopyFontInfo(infoOut, infoRef);
1377dfb07bc7Smrg	    TRACE(("...cannot load a matching bold font\n"));
1378dfb07bc7Smrg	} else if (comparable_metrics(infoRef->fs, infoOut->fs)
1379dfb07bc7Smrg		   && same_font_size(xw, infoRef->fs, infoOut->fs)
1380dfb07bc7Smrg		   && got_bold_font(screen->display, infoOut->fs, *nameOutP)) {
1381dfb07bc7Smrg	    TRACE(("...got a matching bold font\n"));
1382dfb07bc7Smrg	    cache_menu_font_name(screen, fontnum, fBold, *nameOutP);
1383dfb07bc7Smrg	} else {
1384dfb07bc7Smrg	    xtermCloseFont2(xw, infoOut - fBold, fBold);
1385dfb07bc7Smrg	    *infoOut = *infoRef;
1386dfb07bc7Smrg	    TRACE(("...did not get a matching bold font\n"));
1387dfb07bc7Smrg	}
1388dfb07bc7Smrg	free(normal);
1389dfb07bc7Smrg    } else if (!xtermOpenFont(xw, *nameOutP, infoOut, False)) {
1390dfb07bc7Smrg	xtermCopyFontInfo(infoOut, infoRef);
1391dfb07bc7Smrg	TRACE(("...cannot load bold font '%s'\n", NonNull(*nameOutP)));
1392dfb07bc7Smrg    } else {
1393dfb07bc7Smrg	cache_menu_font_name(screen, fontnum, fBold, *nameOutP);
1394dfb07bc7Smrg    }
1395dfb07bc7Smrg
1396dfb07bc7Smrg    /*
1397dfb07bc7Smrg     * Most of the time this call to load the font will succeed, even if
1398dfb07bc7Smrg     * there is no wide font :  the X server doubles the width of the
1399dfb07bc7Smrg     * normal font, or similar.
1400dfb07bc7Smrg     *
1401dfb07bc7Smrg     * But if it did fail for some reason, then nevermind.
1402dfb07bc7Smrg     */
1403dfb07bc7Smrg    if (EmptyFont(infoOut->fs))
1404dfb07bc7Smrg	status = False;		/* can't use a 0-sized font */
1405dfb07bc7Smrg
1406dfb07bc7Smrg    if (!same_font_size(xw, infoRef->fs, infoOut->fs)
1407dfb07bc7Smrg	&& (is_fixed_font(infoRef->fs) && is_fixed_font(infoOut->fs))) {
1408dfb07bc7Smrg	TRACE(("...ignoring mismatched normal/bold fonts\n"));
1409dfb07bc7Smrg	xtermCloseFont2(xw, infoOut - fBold, fBold);
1410dfb07bc7Smrg	xtermCopyFontInfo(infoOut, infoRef);
1411dfb07bc7Smrg    }
1412dfb07bc7Smrg
1413dfb07bc7Smrg    return status;
1414dfb07bc7Smrg}
1415dfb07bc7Smrg
1416dfb07bc7Smrg#if OPT_WIDE_CHARS
1417dfb07bc7Smrgstatic Bool
1418dfb07bc7SmrgloadWideFP(XtermWidget xw,
1419dfb07bc7Smrg	   char **nameOutP,
1420dfb07bc7Smrg	   XTermFonts * infoOut,
1421dfb07bc7Smrg	   const char *nameRef,
1422dfb07bc7Smrg	   XTermFonts * infoRef,
1423dfb07bc7Smrg	   int fontnum)
1424dfb07bc7Smrg{
1425dfb07bc7Smrg    TScreen *screen = TScreenOf(xw);
1426dfb07bc7Smrg    Bool status = True;
1427dfb07bc7Smrg
1428dfb07bc7Smrg    TRACE(("loadWideFP (%s)\n", NonNull(*nameOutP)));
1429dfb07bc7Smrg
1430d4fba8b9Smrg    if (!check_fontname(*nameOutP)
1431d4fba8b9Smrg	&& (screen->utf8_fonts && !is_double_width_font(infoRef->fs))) {
1432dfb07bc7Smrg	char *normal = x_strdup(nameRef);
1433d4fba8b9Smrg	FontNameProperties *fp = get_font_name_props(screen->display,
1434d4fba8b9Smrg						     infoRef->fs, &normal);
1435dfb07bc7Smrg	if (fp != 0) {
1436dfb07bc7Smrg	    *nameOutP = wide_font_name(fp);
1437d4fba8b9Smrg	    NoFontWarning(infoOut);
1438dfb07bc7Smrg	}
1439dfb07bc7Smrg	free(normal);
1440dfb07bc7Smrg    }
1441dfb07bc7Smrg
1442dfb07bc7Smrg    if (check_fontname(*nameOutP)) {
1443d4fba8b9Smrg	if (xtermOpenFont(xw, *nameOutP, infoOut, False)
1444d4fba8b9Smrg	    && is_derived_font_name(*nameOutP)
1445d4fba8b9Smrg	    && EmptyFont(infoOut->fs)) {
1446d4fba8b9Smrg	    xtermCloseFont2(xw, infoOut - fWide, fWide);
1447d4fba8b9Smrg	}
1448d4fba8b9Smrg	if (infoOut->fs == 0) {
1449dfb07bc7Smrg	    xtermCopyFontInfo(infoOut, infoRef);
1450d4fba8b9Smrg	} else {
1451d4fba8b9Smrg	    TRACE(("...%s wide %s\n",
1452d4fba8b9Smrg		   is_derived_font_name(*nameOutP) ? "derived" : "given",
1453d4fba8b9Smrg		   NonNull(*nameOutP)));
1454d4fba8b9Smrg	    cache_menu_font_name(screen, fontnum, fWide, *nameOutP);
1455dfb07bc7Smrg	}
1456dfb07bc7Smrg    } else {
1457dfb07bc7Smrg	xtermCopyFontInfo(infoOut, infoRef);
1458dfb07bc7Smrg    }
1459c48a5815Smrg#define MinWidthOf(fs) fs->min_bounds.width
1460c48a5815Smrg#define MaxWidthOf(fs) fs->max_bounds.width
1461c48a5815Smrg    xw->work.force_wideFont = False;
1462c48a5815Smrg    if (MaxWidthOf(infoOut->fs) != (2 * MaxWidthOf(infoRef->fs))) {
1463c48a5815Smrg	TRACE(("...reference width %d\n", MaxWidthOf(infoRef->fs)));
1464c48a5815Smrg	TRACE(("...?? double-width %d\n", 2 * MaxWidthOf(infoRef->fs)));
1465c48a5815Smrg	TRACE(("...actual width    %d\n", MaxWidthOf(infoOut->fs)));
1466c48a5815Smrg	xw->work.force_wideFont = True;
1467c48a5815Smrg    }
1468dfb07bc7Smrg    return status;
1469dfb07bc7Smrg}
1470dfb07bc7Smrg
1471dfb07bc7Smrgstatic Bool
1472dfb07bc7SmrgloadWBoldFP(XtermWidget xw,
1473dfb07bc7Smrg	    char **nameOutP,
1474dfb07bc7Smrg	    XTermFonts * infoOut,
1475dfb07bc7Smrg	    const char *wideNameRef, XTermFonts * wideInfoRef,
1476dfb07bc7Smrg	    const char *boldNameRef, XTermFonts * boldInfoRef,
1477dfb07bc7Smrg	    int fontnum)
1478dfb07bc7Smrg{
1479dfb07bc7Smrg    TScreen *screen = TScreenOf(xw);
1480dfb07bc7Smrg    Bool status = True;
1481dfb07bc7Smrg    char *bold = NULL;
1482dfb07bc7Smrg
1483dfb07bc7Smrg    TRACE(("loadWBoldFP (%s)\n", NonNull(*nameOutP)));
1484dfb07bc7Smrg
1485dfb07bc7Smrg    if (!check_fontname(*nameOutP)) {
1486dfb07bc7Smrg	FontNameProperties *fp;
1487dfb07bc7Smrg	fp = get_font_name_props(screen->display, boldInfoRef->fs, &bold);
1488dfb07bc7Smrg	if (fp != 0) {
1489dfb07bc7Smrg	    *nameOutP = widebold_font_name(fp);
1490d4fba8b9Smrg	    NoFontWarning(infoOut);
1491dfb07bc7Smrg	}
1492dfb07bc7Smrg    }
1493dfb07bc7Smrg
1494dfb07bc7Smrg    if (check_fontname(*nameOutP)) {
1495dfb07bc7Smrg
1496dfb07bc7Smrg	if (xtermOpenFont(xw, *nameOutP, infoOut, False)
1497d4fba8b9Smrg	    && is_derived_font_name(*nameOutP)
1498dfb07bc7Smrg	    && !compatibleWideCounts(wideInfoRef->fs, infoOut->fs)) {
1499dfb07bc7Smrg	    xtermCloseFont2(xw, infoOut - fWBold, fWBold);
1500dfb07bc7Smrg	}
1501dfb07bc7Smrg
1502dfb07bc7Smrg	if (infoOut->fs == 0) {
1503d4fba8b9Smrg	    if (is_derived_font_name(*nameOutP))
1504dfb07bc7Smrg		free(*nameOutP);
1505dfb07bc7Smrg	    if (IsEmpty(wideNameRef)) {
1506dfb07bc7Smrg		*nameOutP = x_strdup(boldNameRef);
1507dfb07bc7Smrg		xtermCopyFontInfo(infoOut, boldInfoRef);
1508dfb07bc7Smrg		TRACE(("...cannot load wide-bold, use bold %s\n",
1509dfb07bc7Smrg		       NonNull(boldNameRef)));
1510dfb07bc7Smrg	    } else {
1511dfb07bc7Smrg		*nameOutP = x_strdup(wideNameRef);
1512dfb07bc7Smrg		xtermCopyFontInfo(infoOut, wideInfoRef);
1513dfb07bc7Smrg		TRACE(("...cannot load wide-bold, use wide %s\n",
1514dfb07bc7Smrg		       NonNull(wideNameRef)));
1515dfb07bc7Smrg	    }
1516dfb07bc7Smrg	} else {
1517dfb07bc7Smrg	    TRACE(("...%s wide/bold %s\n",
1518d4fba8b9Smrg		   is_derived_font_name(*nameOutP) ? "derived" : "given",
1519dfb07bc7Smrg		   NonNull(*nameOutP)));
1520dfb07bc7Smrg	    cache_menu_font_name(screen, fontnum, fWBold, *nameOutP);
1521dfb07bc7Smrg	}
1522dfb07bc7Smrg    } else if (is_double_width_font(boldInfoRef->fs)) {
1523dfb07bc7Smrg	xtermCopyFontInfo(infoOut, boldInfoRef);
1524dfb07bc7Smrg	TRACE(("...bold font is double-width, use it %s\n", NonNull(boldNameRef)));
1525dfb07bc7Smrg    } else {
1526dfb07bc7Smrg	xtermCopyFontInfo(infoOut, wideInfoRef);
1527dfb07bc7Smrg	TRACE(("...cannot load wide bold font, use wide %s\n", NonNull(wideNameRef)));
1528dfb07bc7Smrg    }
1529dfb07bc7Smrg
1530dfb07bc7Smrg    free(bold);
1531dfb07bc7Smrg
1532dfb07bc7Smrg    if (EmptyFont(infoOut->fs)) {
1533dfb07bc7Smrg	status = False;		/* can't use a 0-sized font */
1534dfb07bc7Smrg    } else {
1535dfb07bc7Smrg	if ((!comparable_metrics(wideInfoRef->fs, infoOut->fs)
1536dfb07bc7Smrg	     || (!same_font_size(xw, wideInfoRef->fs, infoOut->fs)
1537dfb07bc7Smrg		 && is_fixed_font(wideInfoRef->fs)
1538dfb07bc7Smrg		 && is_fixed_font(infoOut->fs)))) {
1539dfb07bc7Smrg	    TRACE(("...ignoring mismatched normal/bold wide fonts\n"));
1540dfb07bc7Smrg	    xtermCloseFont2(xw, infoOut - fWBold, fWBold);
1541dfb07bc7Smrg	    xtermCopyFontInfo(infoOut, wideInfoRef);
1542dfb07bc7Smrg	}
1543dfb07bc7Smrg    }
1544dfb07bc7Smrg
1545dfb07bc7Smrg    return status;
1546dfb07bc7Smrg}
1547dfb07bc7Smrg#endif
1548dfb07bc7Smrg
1549d522f475Smrgint
1550d522f475SmrgxtermLoadFont(XtermWidget xw,
1551d522f475Smrg	      const VTFontNames * fonts,
1552d522f475Smrg	      Bool doresize,
1553d522f475Smrg	      int fontnum)
1554d522f475Smrg{
1555956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1556d522f475Smrg    VTwin *win = WhichVWin(screen);
1557d522f475Smrg
1558d522f475Smrg    VTFontNames myfonts;
1559d522f475Smrg    XTermFonts fnts[fMAX];
1560d522f475Smrg    char *tmpname = NULL;
1561956cc18dSsnj    Boolean proportional = False;
1562d522f475Smrg
1563d522f475Smrg    memset(&myfonts, 0, sizeof(myfonts));
1564d522f475Smrg    memset(fnts, 0, sizeof(fnts));
1565d522f475Smrg
1566d522f475Smrg    if (fonts != 0)
1567d522f475Smrg	myfonts = *fonts;
1568956cc18dSsnj    if (!check_fontname(myfonts.f_n))
1569d522f475Smrg	return 0;
1570d522f475Smrg
1571d522f475Smrg    if (fontnum == fontMenu_fontescape
1572d522f475Smrg	&& myfonts.f_n != screen->MenuFontName(fontnum)) {
1573d522f475Smrg	if ((tmpname = x_strdup(myfonts.f_n)) == 0)
1574d522f475Smrg	    return 0;
1575d522f475Smrg    }
1576d522f475Smrg
1577d522f475Smrg    TRACE(("Begin Cgs - xtermLoadFont(%s)\n", myfonts.f_n));
1578d522f475Smrg    releaseWindowGCs(xw, win);
1579d522f475Smrg
1580956cc18dSsnj#define DbgResource(name, field, index) \
1581956cc18dSsnj    TRACE(("xtermLoadFont #%d "name" %s%s\n", \
1582956cc18dSsnj    	   fontnum, \
1583dfb07bc7Smrg	   (fnts[index].warn == fwResource) ? "*" : " ", \
1584492d43a5Smrg	   NonNull(myfonts.field)))
1585956cc18dSsnj    DbgResource("normal", f_n, fNorm);
1586956cc18dSsnj    DbgResource("bold  ", f_b, fBold);
1587d522f475Smrg#if OPT_WIDE_CHARS
1588956cc18dSsnj    DbgResource("wide  ", f_w, fWide);
1589956cc18dSsnj    DbgResource("w/bold", f_wb, fWBold);
1590d522f475Smrg#endif
1591d522f475Smrg
1592dfb07bc7Smrg    if (!loadNormFP(xw,
1593dfb07bc7Smrg		    &myfonts.f_n,
1594dfb07bc7Smrg		    &fnts[fNorm],
1595dfb07bc7Smrg		    fontnum))
1596d522f475Smrg	goto bad;
1597d522f475Smrg
1598dfb07bc7Smrg    if (!loadBoldFP(xw,
1599dfb07bc7Smrg		    &myfonts.f_b,
1600dfb07bc7Smrg		    &fnts[fBold],
1601dfb07bc7Smrg		    myfonts.f_n,
1602dfb07bc7Smrg		    &fnts[fNorm],
1603dfb07bc7Smrg		    fontnum))
1604dfb07bc7Smrg	goto bad;
1605d522f475Smrg
1606d522f475Smrg    /*
1607d522f475Smrg     * If there is no widefont specified, fake it by doubling AVERAGE_WIDTH
1608d522f475Smrg     * of normal fonts XLFD, and asking for it.  This plucks out 18x18ja
1609d522f475Smrg     * and 12x13ja as the corresponding fonts for 9x18 and 6x13.
1610d522f475Smrg     */
1611d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
1612d522f475Smrg
1613dfb07bc7Smrg	if (!loadWideFP(xw,
1614dfb07bc7Smrg			&myfonts.f_w,
1615dfb07bc7Smrg			&fnts[fWide],
1616dfb07bc7Smrg			myfonts.f_n,
1617dfb07bc7Smrg			&fnts[fNorm],
1618dfb07bc7Smrg			fontnum))
1619dfb07bc7Smrg	    goto bad;
1620dfb07bc7Smrg
1621dfb07bc7Smrg	if (!loadWBoldFP(xw,
1622dfb07bc7Smrg			 &myfonts.f_wb,
1623dfb07bc7Smrg			 &fnts[fWBold],
1624dfb07bc7Smrg			 myfonts.f_w,
1625dfb07bc7Smrg			 &fnts[fWide],
1626dfb07bc7Smrg			 myfonts.f_b,
1627dfb07bc7Smrg			 &fnts[fBold],
1628dfb07bc7Smrg			 fontnum))
1629dfb07bc7Smrg	    goto bad;
1630d522f475Smrg
1631d522f475Smrg    });
1632d522f475Smrg
1633d522f475Smrg    /*
1634d522f475Smrg     * Normal/bold fonts should be the same width.  Also, the min/max
1635d522f475Smrg     * values should be the same.
1636d522f475Smrg     */
1637d4fba8b9Smrg    if (fnts[fNorm].fs != 0
1638d4fba8b9Smrg	&& fnts[fBold].fs != 0
1639d4fba8b9Smrg	&& (!is_fixed_font(fnts[fNorm].fs)
1640d4fba8b9Smrg	    || !is_fixed_font(fnts[fBold].fs)
1641d4fba8b9Smrg	    || differing_widths(fnts[fNorm].fs, fnts[fBold].fs))) {
1642d522f475Smrg	TRACE(("Proportional font! normal %d/%d, bold %d/%d\n",
1643d522f475Smrg	       fnts[fNorm].fs->min_bounds.width,
1644d522f475Smrg	       fnts[fNorm].fs->max_bounds.width,
1645d522f475Smrg	       fnts[fBold].fs->min_bounds.width,
1646d522f475Smrg	       fnts[fBold].fs->max_bounds.width));
1647d522f475Smrg	proportional = True;
1648d522f475Smrg    }
1649d522f475Smrg
1650d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
1651d522f475Smrg	if (fnts[fWide].fs != 0
1652d522f475Smrg	    && fnts[fWBold].fs != 0
1653d522f475Smrg	    && (!is_fixed_font(fnts[fWide].fs)
1654d522f475Smrg		|| !is_fixed_font(fnts[fWBold].fs)
1655d4fba8b9Smrg		|| differing_widths(fnts[fWide].fs, fnts[fWBold].fs))) {
1656d522f475Smrg	    TRACE(("Proportional font! wide %d/%d, wide bold %d/%d\n",
1657d522f475Smrg		   fnts[fWide].fs->min_bounds.width,
1658d522f475Smrg		   fnts[fWide].fs->max_bounds.width,
1659d522f475Smrg		   fnts[fWBold].fs->min_bounds.width,
1660d522f475Smrg		   fnts[fWBold].fs->max_bounds.width));
1661d522f475Smrg	    proportional = True;
1662d522f475Smrg	}
1663d522f475Smrg    });
1664d522f475Smrg
1665d522f475Smrg    /* TODO : enforce that the width of the wide font is 2* the width
1666d522f475Smrg       of the narrow font */
1667d522f475Smrg
1668d522f475Smrg    /*
1669d522f475Smrg     * If we're switching fonts, free the old ones.  Otherwise we'll leak
1670d522f475Smrg     * the memory that is associated with the old fonts.  The
1671d522f475Smrg     * XLoadQueryFont call allocates a new XFontStruct.
1672d522f475Smrg     */
1673d522f475Smrg    xtermCloseFonts(xw, screen->fnts);
16749a64e1c5Smrg#if OPT_WIDE_ATTRS
16759a64e1c5Smrg    xtermCloseFonts(xw, screen->ifnts);
16769a64e1c5Smrg    screen->ifnts_ok = False;
16779a64e1c5Smrg#endif
1678d522f475Smrg
1679d4fba8b9Smrg    xtermCopyFontInfo(GetNormalFont(screen, fNorm), &fnts[fNorm]);
1680d4fba8b9Smrg    xtermCopyFontInfo(GetNormalFont(screen, fBold), &fnts[fBold]);
1681d522f475Smrg#if OPT_WIDE_CHARS
1682d4fba8b9Smrg    xtermCopyFontInfo(GetNormalFont(screen, fWide), &fnts[fWide]);
1683d522f475Smrg    if (fnts[fWBold].fs == NULL)
1684d4fba8b9Smrg	xtermCopyFontInfo(GetNormalFont(screen, fWide), &fnts[fWide]);
1685d4fba8b9Smrg    xtermCopyFontInfo(GetNormalFont(screen, fWBold), &fnts[fWBold]);
1686d522f475Smrg#endif
1687d522f475Smrg
1688d4fba8b9Smrg    xtermUpdateFontGCs(xw, getNormalFont);
1689d522f475Smrg
169020d2c4d2Smrg#if OPT_BOX_CHARS
169120d2c4d2Smrg    screen->allow_packing = proportional;
169220d2c4d2Smrg    setupPackedFonts(xw);
169320d2c4d2Smrg#endif
169420d2c4d2Smrg    screen->fnt_prop = (Boolean) (proportional && !(screen->force_packed));
1695d4fba8b9Smrg    screen->fnt_boxes = 1;
1696d522f475Smrg
1697d522f475Smrg#if OPT_BOX_CHARS
1698d522f475Smrg    /*
16999a64e1c5Smrg     * xterm uses character positions 1-31 of a font for the line-drawing
1700d522f475Smrg     * characters.  Check that they are all present.  The null character
1701d522f475Smrg     * (0) is special, and is not used.
1702d522f475Smrg     */
1703d522f475Smrg#if OPT_RENDERFONT
1704d522f475Smrg    if (UsingRenderFont(xw)) {
1705d522f475Smrg	/*
1706d522f475Smrg	 * FIXME: we shouldn't even be here if we're using Xft.
1707d522f475Smrg	 */
1708d4fba8b9Smrg	screen->fnt_boxes = 0;
1709d522f475Smrg	TRACE(("assume Xft missing line-drawing chars\n"));
1710d522f475Smrg    } else
1711d522f475Smrg#endif
1712d522f475Smrg    {
1713d522f475Smrg	unsigned ch;
1714d522f475Smrg
17159a64e1c5Smrg#if OPT_TRACE
17169a64e1c5Smrg#define TRACE_MISS(index) show_font_misses(#index, &fnts[index])
17179a64e1c5Smrg	TRACE_MISS(fNorm);
17189a64e1c5Smrg	TRACE_MISS(fBold);
17199a64e1c5Smrg#if OPT_WIDE_CHARS
17209a64e1c5Smrg	TRACE_MISS(fWide);
17219a64e1c5Smrg	TRACE_MISS(fWBold);
17229a64e1c5Smrg#endif
17239a64e1c5Smrg#endif
1724fa3f02f3Smrg
1725d522f475Smrg#if OPT_WIDE_CHARS
1726d4fba8b9Smrg	if (screen->utf8_mode || screen->unicode_font) {
1727d4fba8b9Smrg	    UIntSet(screen->fnt_boxes, 2);
1728d4fba8b9Smrg	    for (ch = 1; ch < 32; ch++) {
1729d4fba8b9Smrg		unsigned n = dec2ucs(screen, ch);
1730d4fba8b9Smrg		if ((n != UCS_REPL)
1731d4fba8b9Smrg		    && (n != ch)
1732d4fba8b9Smrg		    && (screen->fnt_boxes & 2)) {
1733d4fba8b9Smrg		    if (xtermMissingChar(n, &fnts[fNorm]) ||
1734d4fba8b9Smrg			xtermMissingChar(n, &fnts[fBold])) {
1735d4fba8b9Smrg			UIntClr(screen->fnt_boxes, 2);
1736d4fba8b9Smrg			TRACE(("missing graphics character #%d, U+%04X\n",
1737d4fba8b9Smrg			       ch, n));
1738d4fba8b9Smrg			break;
1739d4fba8b9Smrg		    }
1740d4fba8b9Smrg		}
1741d522f475Smrg	    }
1742d4fba8b9Smrg	}
1743d522f475Smrg#endif
1744d4fba8b9Smrg
1745d4fba8b9Smrg	for (ch = 1; ch < 32; ch++) {
1746d4fba8b9Smrg	    if (xtermMissingChar(ch, &fnts[fNorm])) {
1747d4fba8b9Smrg		TRACE(("missing normal char #%d\n", ch));
1748d4fba8b9Smrg		UIntClr(screen->fnt_boxes, 1);
1749d522f475Smrg		break;
1750d522f475Smrg	    }
1751d4fba8b9Smrg	    if (xtermMissingChar(ch, &fnts[fBold])) {
1752d4fba8b9Smrg		TRACE(("missing bold   char #%d\n", ch));
1753d4fba8b9Smrg		UIntClr(screen->fnt_boxes, 1);
1754d522f475Smrg		break;
1755d522f475Smrg	    }
1756d522f475Smrg	}
1757d4fba8b9Smrg
1758d4fba8b9Smrg	TRACE(("Will %suse internal line-drawing characters (mode %d)\n",
1759d4fba8b9Smrg	       screen->fnt_boxes ? "not " : "",
1760d4fba8b9Smrg	       screen->fnt_boxes));
1761d522f475Smrg    }
1762d522f475Smrg#endif
1763d522f475Smrg
1764d522f475Smrg    if (screen->always_bold_mode) {
1765d522f475Smrg	screen->enbolden = screen->bold_mode;
1766d522f475Smrg    } else {
1767d522f475Smrg	screen->enbolden = screen->bold_mode
1768d522f475Smrg	    && ((fnts[fNorm].fs == fnts[fBold].fs)
1769dfb07bc7Smrg		|| same_font_name(myfonts.f_n, myfonts.f_b));
1770d522f475Smrg    }
1771d522f475Smrg    TRACE(("Will %suse 1-pixel offset/overstrike to simulate bold\n",
1772d522f475Smrg	   screen->enbolden ? "" : "not "));
1773d522f475Smrg
1774d522f475Smrg    set_menu_font(False);
1775d522f475Smrg    screen->menu_font_number = fontnum;
1776d522f475Smrg    set_menu_font(True);
1777d522f475Smrg    if (tmpname) {		/* if setting escape or sel */
1778d522f475Smrg	if (screen->MenuFontName(fontnum))
17799a64e1c5Smrg	    FREE_STRING(screen->MenuFontName(fontnum));
1780d522f475Smrg	screen->MenuFontName(fontnum) = tmpname;
1781d522f475Smrg	if (fontnum == fontMenu_fontescape) {
178294644356Smrg	    update_font_escape();
1783d522f475Smrg	}
1784d522f475Smrg#if OPT_SHIFT_FONTS
1785d522f475Smrg	screen->menu_font_sizes[fontnum] = FontSize(fnts[fNorm].fs);
1786d522f475Smrg#endif
1787d522f475Smrg    }
1788d522f475Smrg    set_cursor_gcs(xw);
1789d522f475Smrg    xtermUpdateFontInfo(xw, doresize);
1790d522f475Smrg    TRACE(("Success Cgs - xtermLoadFont\n"));
1791fa3f02f3Smrg#if OPT_REPORT_FONTS
1792fa3f02f3Smrg    reportVTFontInfo(xw, fontnum);
17939a64e1c5Smrg#endif
17949a64e1c5Smrg    FREE_FNAME(f_n);
17959a64e1c5Smrg    FREE_FNAME(f_b);
17969a64e1c5Smrg#if OPT_WIDE_CHARS
17979a64e1c5Smrg    FREE_FNAME(f_w);
17989a64e1c5Smrg    FREE_FNAME(f_wb);
17999a64e1c5Smrg#endif
18009a64e1c5Smrg    if (fnts[fNorm].fn == fnts[fBold].fn) {
18019a64e1c5Smrg	free(fnts[fNorm].fn);
18029a64e1c5Smrg    } else {
18039a64e1c5Smrg	free(fnts[fNorm].fn);
18049a64e1c5Smrg	free(fnts[fBold].fn);
18059a64e1c5Smrg    }
18069a64e1c5Smrg#if OPT_WIDE_CHARS
18079a64e1c5Smrg    free(fnts[fWide].fn);
18089a64e1c5Smrg    free(fnts[fWBold].fn);
1809fa3f02f3Smrg#endif
1810dfb07bc7Smrg    xtermSetWinSize(xw);
1811d522f475Smrg    return 1;
1812d522f475Smrg
1813d522f475Smrg  bad:
1814d4fba8b9Smrg    free(tmpname);
18150bd37d32Smrg
18160bd37d32Smrg#if OPT_RENDERFONT
181794644356Smrg    if ((fontnum == fontMenu_fontsel) && (fontnum != screen->menu_font_number)) {
18189a64e1c5Smrg	int old_fontnum = screen->menu_font_number;
18199a64e1c5Smrg#if OPT_TOOLBAR
18209a64e1c5Smrg	SetItemSensitivity(fontMenuEntries[fontnum].widget, True);
18219a64e1c5Smrg#endif
18229a64e1c5Smrg	Bell(xw, XkbBI_MinorError, 0);
18239a64e1c5Smrg	myfonts.f_n = screen->MenuFontName(old_fontnum);
18249a64e1c5Smrg	return xtermLoadFont(xw, &myfonts, doresize, old_fontnum);
18259a64e1c5Smrg    } else if (x_strcasecmp(myfonts.f_n, DEFFONT)) {
18260bd37d32Smrg	int code;
18270bd37d32Smrg
1828dfb07bc7Smrg	myfonts.f_n = x_strdup(DEFFONT);
18290bd37d32Smrg	TRACE(("...recovering for TrueType fonts\n"));
18300bd37d32Smrg	code = xtermLoadFont(xw, &myfonts, doresize, fontnum);
18310bd37d32Smrg	if (code) {
183294644356Smrg	    if (fontnum != fontMenu_fontsel) {
183394644356Smrg		SetItemSensitivity(fontMenuEntries[fontnum].widget,
183494644356Smrg				   UsingRenderFont(xw));
183594644356Smrg	    }
18360bd37d32Smrg	    TRACE(("...recovered size %dx%d\n",
18370bd37d32Smrg		   FontHeight(screen),
18380bd37d32Smrg		   FontWidth(screen)));
18390bd37d32Smrg	}
18400bd37d32Smrg	return code;
18410bd37d32Smrg    }
18420bd37d32Smrg#endif
18430bd37d32Smrg
1844d522f475Smrg    releaseWindowGCs(xw, win);
1845d522f475Smrg
1846d522f475Smrg    xtermCloseFonts(xw, fnts);
1847d522f475Smrg    TRACE(("Fail Cgs - xtermLoadFont\n"));
1848d522f475Smrg    return 0;
1849d522f475Smrg}
1850d522f475Smrg
18519a64e1c5Smrg#if OPT_WIDE_ATTRS
18529a64e1c5Smrg/*
18539a64e1c5Smrg * (Attempt to) load matching italics for the current normal/bold/etc fonts.
18549a64e1c5Smrg * If the attempt fails for a given style, use the non-italic font.
18559a64e1c5Smrg */
18569a64e1c5Smrgvoid
18579a64e1c5SmrgxtermLoadItalics(XtermWidget xw)
18589a64e1c5Smrg{
18599a64e1c5Smrg    TScreen *screen = TScreenOf(xw);
18609a64e1c5Smrg
1861c48a5815Smrg    if (UseItalicFont(screen) && !screen->ifnts_ok) {
1862037a25ddSmrg	int n;
1863dfb07bc7Smrg	FontNameProperties *fp;
1864dfb07bc7Smrg	XTermFonts *data;
1865037a25ddSmrg
18669a64e1c5Smrg	screen->ifnts_ok = True;
18679a64e1c5Smrg	for (n = 0; n < fMAX; ++n) {
1868dfb07bc7Smrg	    switch (n) {
1869dfb07bc7Smrg	    case fNorm:
1870dfb07bc7Smrg		/* FALLTHRU */
1871dfb07bc7Smrg	    case fBold:
1872dfb07bc7Smrg		/* FALLTHRU */
1873dfb07bc7Smrg#if OPT_WIDE_CHARS
1874dfb07bc7Smrg	    case fWide:
1875dfb07bc7Smrg		/* FALLTHRU */
1876dfb07bc7Smrg	    case fWBold:
1877dfb07bc7Smrg#endif
1878dfb07bc7Smrg		/* FALLTHRU */
1879dfb07bc7Smrg		data = getItalicFont(screen, n);
1880037a25ddSmrg
1881dfb07bc7Smrg		/*
1882dfb07bc7Smrg		 * FIXME - need to handle font-leaks
1883dfb07bc7Smrg		 */
1884dfb07bc7Smrg		data->fs = 0;
1885dfb07bc7Smrg		if (getNormalFont(screen, n)->fs != 0 &&
1886dfb07bc7Smrg		    (fp = get_font_name_props(screen->display,
1887dfb07bc7Smrg					      getNormalFont(screen, n)->fs,
1888dfb07bc7Smrg					      0)) != 0) {
1889dfb07bc7Smrg		    if (!open_italic_font(xw, n, fp, data)) {
1890dfb07bc7Smrg			if (n > 0) {
1891dfb07bc7Smrg			    xtermCopyFontInfo(data,
1892dfb07bc7Smrg					      getItalicFont(screen, n - 1));
1893dfb07bc7Smrg			} else {
1894dfb07bc7Smrg			    xtermOpenFont(xw,
1895dfb07bc7Smrg					  getNormalFont(screen, n)->fn,
1896dfb07bc7Smrg					  data, False);
18979a64e1c5Smrg			}
18989a64e1c5Smrg		    }
18999a64e1c5Smrg		}
1900dfb07bc7Smrg		break;
19019a64e1c5Smrg	    }
19029a64e1c5Smrg	}
19039a64e1c5Smrg    }
19049a64e1c5Smrg}
19059a64e1c5Smrg#endif
19069a64e1c5Smrg
1907d522f475Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
1908d522f475Smrg/*
1909d522f475Smrg * Collect font-names that we can modify with the load-vt-fonts() action.
1910d522f475Smrg */
1911dfb07bc7Smrg#define MERGE_SUBFONT(dst,src,name) \
1912492d43a5Smrg	if (IsEmpty(dst.name)) { \
1913dfb07bc7Smrg	    TRACE(("MERGE_SUBFONT " #dst "." #name " merge \"%s\"\n", NonNull(src.name))); \
19149a64e1c5Smrg	    dst.name = x_strdup(src.name); \
1915d522f475Smrg	} else { \
1916dfb07bc7Smrg	    TRACE(("MERGE_SUBFONT " #dst "." #name " found \"%s\"\n", NonNull(dst.name))); \
1917dfb07bc7Smrg	}
1918dfb07bc7Smrg#define MERGE_SUBLIST(dst,src,name) \
1919dfb07bc7Smrg	if (merge_sublist(&(dst.fonts.x11.name), src.fonts.x11.name)) { \
1920dfb07bc7Smrg	    TRACE(("MERGE_SUBLIST " #dst "." #name " merge \"%s\"\n", src.fonts.x11.name[0])); \
1921dfb07bc7Smrg	} else { \
1922dfb07bc7Smrg	    TRACE(("MERGE_SUBLIST " #dst "." #name " found \"%s\"\n", dst.fonts.x11.name[0])); \
1923d522f475Smrg	}
1924d522f475Smrg
1925dfb07bc7Smrg#define INFER_SUBFONT(dst,src,name) \
1926e39b573cSmrg	if (IsEmpty(dst.name)) { \
1927e39b573cSmrg	    TRACE(("INFER_SUBFONT " #dst "." #name " will infer\n")); \
1928e39b573cSmrg	    dst.name = x_strdup(""); \
1929e39b573cSmrg	} else { \
1930dfb07bc7Smrg	    TRACE(("INFER_SUBFONT " #dst "." #name " found \"%s\"\n", NonNull(dst.name))); \
1931e39b573cSmrg	}
1932e39b573cSmrg
19339a64e1c5Smrg#define FREE_MENU_FONTS(dst) \
19349a64e1c5Smrg	TRACE(("FREE_MENU_FONTS " #dst "\n")); \
19359a64e1c5Smrg	for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \
19369a64e1c5Smrg	    for (m = 0; m < fMAX; ++m) { \
19379a64e1c5Smrg		FREE_STRING(dst.menu_font_names[n][m]); \
19389a64e1c5Smrg		dst.menu_font_names[n][m] = 0; \
19399a64e1c5Smrg	    } \
19409a64e1c5Smrg	}
19419a64e1c5Smrg
1942dfb07bc7Smrg#define COPY_MENU_FONTS(dst,src) \
1943d522f475Smrg	TRACE(("COPY_MENU_FONTS " #src " to " #dst "\n")); \
1944d522f475Smrg	for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \
1945d522f475Smrg	    for (m = 0; m < fMAX; ++m) { \
19469a64e1c5Smrg		FREE_STRING(dst.menu_font_names[n][m]); \
1947492d43a5Smrg		dst.menu_font_names[n][m] = x_strdup(src.menu_font_names[n][m]); \
1948d522f475Smrg	    } \
194994644356Smrg	    TRACE((".. " #dst ".menu_fonts_names[%d] = %s\n", n, NonNull(dst.menu_font_names[n][fNorm]))); \
1950e39b573cSmrg	}
1951e39b573cSmrg
19529a64e1c5Smrg#define COPY_DEFAULT_FONTS(target, source) \
1953dfb07bc7Smrg	TRACE(("COPY_DEFAULT_FONTS " #source " to " #target "\n")); \
19549a64e1c5Smrg	xtermCopyVTFontNames(&target.default_font, &source.default_font)
19559a64e1c5Smrg
1956dfb07bc7Smrg#define COPY_X11_FONTLISTS(target, source) \
1957dfb07bc7Smrg	TRACE(("COPY_X11_FONTLISTS " #source " to " #target "\n")); \
1958dfb07bc7Smrg	xtermCopyFontLists(xw, &target.fonts.x11, &source.fonts.x11)
1959dfb07bc7Smrg
1960dfb07bc7Smrgstatic void
1961dfb07bc7SmrgxtermCopyVTFontNames(VTFontNames * target, VTFontNames * source)
1962dfb07bc7Smrg{
1963dfb07bc7Smrg#define COPY_IT(name,field) \
1964dfb07bc7Smrg    TRACE((".. "#name" = %s\n", NonNull(source->field))); \
1965dfb07bc7Smrg    free(target->field); \
1966dfb07bc7Smrg    target->field = x_strdup(source->field)
1967dfb07bc7Smrg
1968dfb07bc7Smrg    TRACE(("xtermCopyVTFontNames\n"));
1969dfb07bc7Smrg
1970dfb07bc7Smrg    COPY_IT(font, f_n);
1971dfb07bc7Smrg    COPY_IT(boldFont, f_b);
1972dfb07bc7Smrg
1973dfb07bc7Smrg#if OPT_WIDE_CHARS
1974dfb07bc7Smrg    COPY_IT(wideFont, f_w);
1975dfb07bc7Smrg    COPY_IT(wideBoldFont, f_wb);
1976dfb07bc7Smrg#endif
1977dfb07bc7Smrg#undef COPY_IT
1978dfb07bc7Smrg}
1979dfb07bc7Smrg
19809a64e1c5Smrgstatic void
1981dfb07bc7SmrgxtermCopyFontLists(XtermWidget xw, VTFontList * target, VTFontList * source)
19829a64e1c5Smrg{
1983dfb07bc7Smrg#define COPY_IT(name,field) \
1984dfb07bc7Smrg    copyFontList(&(target->field), source->field); \
1985dfb07bc7Smrg    TRACE_ARGV(".. " #name, source->field)
1986dfb07bc7Smrg
1987dfb07bc7Smrg    (void) xw;
1988dfb07bc7Smrg    TRACE(("xtermCopyFontLists %s ->%s\n",
1989dfb07bc7Smrg	   whichFontList(xw, source),
1990dfb07bc7Smrg	   whichFontList(xw, target)));
1991dfb07bc7Smrg
1992dfb07bc7Smrg    COPY_IT(font, list_n);
1993dfb07bc7Smrg    COPY_IT(fontBold, list_b);
1994dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
1995dfb07bc7Smrg    COPY_IT(fontItal, list_i);
1996d4fba8b9Smrg    COPY_IT(fontBtal, list_bi);
1997dfb07bc7Smrg#endif
19989a64e1c5Smrg#if OPT_WIDE_CHARS
1999dfb07bc7Smrg    COPY_IT(wideFont, list_w);
2000dfb07bc7Smrg    COPY_IT(wideBoldFont, list_wb);
2001dfb07bc7Smrg    COPY_IT(wideItalFont, list_wi);
2002d4fba8b9Smrg    COPY_IT(wideBtalFont, list_wbi);
20039a64e1c5Smrg#endif
2004dfb07bc7Smrg#undef COPY_IT
20059a64e1c5Smrg}
20069a64e1c5Smrg
2007e39b573cSmrgvoid
2008e39b573cSmrgxtermSaveVTFonts(XtermWidget xw)
2009e39b573cSmrg{
2010e39b573cSmrg    TScreen *screen = TScreenOf(xw);
2011e39b573cSmrg    Cardinal n, m;
2012e39b573cSmrg
2013e39b573cSmrg    if (!screen->savedVTFonts) {
2014e39b573cSmrg
2015e39b573cSmrg	screen->savedVTFonts = True;
2016e39b573cSmrg	TRACE(("xtermSaveVTFonts saving original\n"));
20179a64e1c5Smrg	COPY_DEFAULT_FONTS(screen->cacheVTFonts, xw->misc);
2018dfb07bc7Smrg	COPY_X11_FONTLISTS(screen->cacheVTFonts, xw->work);
2019dfb07bc7Smrg	COPY_MENU_FONTS(screen->cacheVTFonts, xw->screen);
2020e39b573cSmrg    }
2021e39b573cSmrg}
2022e39b573cSmrg
2023e39b573cSmrg#define SAME_STRING(x,y) ((x) == (y) || ((x) && (y) && !strcmp(x, y)))
2024e39b573cSmrg#define SAME_MEMBER(n)   SAME_STRING(a->n, b->n)
2025e39b573cSmrg
2026e39b573cSmrgstatic Boolean
2027e39b573cSmrgsameSubResources(SubResourceRec * a, SubResourceRec * b)
2028e39b573cSmrg{
2029e39b573cSmrg    Boolean result = True;
2030e39b573cSmrg
2031e39b573cSmrg    if (!SAME_MEMBER(default_font.f_n)
2032e39b573cSmrg	|| !SAME_MEMBER(default_font.f_b)
20330bd37d32Smrg#if OPT_WIDE_CHARS
2034e39b573cSmrg	|| !SAME_MEMBER(default_font.f_w)
20350bd37d32Smrg	|| !SAME_MEMBER(default_font.f_wb)
20360bd37d32Smrg#endif
20370bd37d32Smrg	) {
2038e39b573cSmrg	TRACE(("sameSubResources: default_font differs\n"));
2039e39b573cSmrg	result = False;
2040e39b573cSmrg    } else {
2041037a25ddSmrg	int n;
2042037a25ddSmrg
2043e39b573cSmrg	for (n = 0; n < NMENUFONTS; ++n) {
2044e39b573cSmrg	    if (!SAME_MEMBER(menu_font_names[n][fNorm])) {
2045e39b573cSmrg		TRACE(("sameSubResources: menu_font_names[%d] differs\n", n));
2046e39b573cSmrg		result = False;
2047e39b573cSmrg		break;
2048e39b573cSmrg	    }
2049d522f475Smrg	}
2050e39b573cSmrg    }
2051e39b573cSmrg
2052e39b573cSmrg    return result;
2053e39b573cSmrg}
2054d522f475Smrg
2055d522f475Smrg/*
2056d522f475Smrg * Load the "VT" font names from the given subresource name/class.  These
2057d522f475Smrg * correspond to the VT100 resources.
2058d522f475Smrg */
2059d522f475Smrgstatic Bool
206020d2c4d2SmrgxtermLoadVTFonts(XtermWidget xw, String myName, String myClass)
2061d522f475Smrg{
2062e39b573cSmrg    SubResourceRec subresourceRec;
2063e39b573cSmrg    SubResourceRec referenceRec;
2064d522f475Smrg
2065d522f475Smrg    /*
2066d522f475Smrg     * These are duplicates of the VT100 font resources, but with a special
2067d522f475Smrg     * application/classname passed in to distinguish them.
2068d522f475Smrg     */
2069d522f475Smrg    static XtResource font_resources[] =
2070d522f475Smrg    {
2071d522f475Smrg	Sres(XtNfont, XtCFont, default_font.f_n, DEFFONT),
2072d522f475Smrg	Sres(XtNboldFont, XtCBoldFont, default_font.f_b, DEFBOLDFONT),
2073d522f475Smrg#if OPT_WIDE_CHARS
2074d522f475Smrg	Sres(XtNwideFont, XtCWideFont, default_font.f_w, DEFWIDEFONT),
2075d522f475Smrg	Sres(XtNwideBoldFont, XtCWideBoldFont, default_font.f_wb, DEFWIDEBOLDFONT),
2076d522f475Smrg#endif
2077d522f475Smrg	Sres(XtNfont1, XtCFont1, MenuFontName(fontMenu_font1), NULL),
2078d522f475Smrg	Sres(XtNfont2, XtCFont2, MenuFontName(fontMenu_font2), NULL),
2079d522f475Smrg	Sres(XtNfont3, XtCFont3, MenuFontName(fontMenu_font3), NULL),
2080d522f475Smrg	Sres(XtNfont4, XtCFont4, MenuFontName(fontMenu_font4), NULL),
2081d522f475Smrg	Sres(XtNfont5, XtCFont5, MenuFontName(fontMenu_font5), NULL),
2082d522f475Smrg	Sres(XtNfont6, XtCFont6, MenuFontName(fontMenu_font6), NULL),
2083d4fba8b9Smrg	Sres(XtNfont7, XtCFont7, MenuFontName(fontMenu_font7), NULL),
2084d522f475Smrg    };
2085d522f475Smrg    Cardinal n, m;
2086d522f475Smrg    Bool status = True;
2087956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2088d522f475Smrg
2089e39b573cSmrg    TRACE(("called xtermLoadVTFonts(name=%s, class=%s)\n",
2090e39b573cSmrg	   NonNull(myName), NonNull(myClass)));
2091d522f475Smrg
2092e39b573cSmrg    xtermSaveVTFonts(xw);
2093d522f475Smrg
2094492d43a5Smrg    if (IsEmpty(myName)) {
2095d522f475Smrg	TRACE(("xtermLoadVTFonts restoring original\n"));
20969a64e1c5Smrg	COPY_DEFAULT_FONTS(xw->misc, screen->cacheVTFonts);
2097dfb07bc7Smrg	COPY_X11_FONTLISTS(xw->work, screen->cacheVTFonts);
20989a64e1c5Smrg	FREE_MENU_FONTS(xw->screen);
2099dfb07bc7Smrg	COPY_MENU_FONTS(xw->screen, screen->cacheVTFonts);
2100d522f475Smrg    } else {
2101d522f475Smrg	TRACE(("xtermLoadVTFonts(%s, %s)\n", myName, myClass));
2102d522f475Smrg
2103e39b573cSmrg	memset(&referenceRec, 0, sizeof(referenceRec));
2104d522f475Smrg	memset(&subresourceRec, 0, sizeof(subresourceRec));
2105956cc18dSsnj	XtGetSubresources((Widget) xw, (XtPointer) &subresourceRec,
2106d522f475Smrg			  myName, myClass,
2107d522f475Smrg			  font_resources,
2108d522f475Smrg			  (Cardinal) XtNumber(font_resources),
2109d522f475Smrg			  NULL, (Cardinal) 0);
2110d522f475Smrg
2111e39b573cSmrg	/*
2112e39b573cSmrg	 * XtGetSubresources returns no status, so we compare the returned
2113e39b573cSmrg	 * data against a zero'd struct to see if any data is returned.
2114e39b573cSmrg	 */
2115e39b573cSmrg	if (memcmp(&referenceRec, &subresourceRec, sizeof(referenceRec))
2116e39b573cSmrg	    && !sameSubResources(&(screen->cacheVTFonts), &subresourceRec)) {
2117e39b573cSmrg
2118e39b573cSmrg	    screen->mergedVTFonts = True;
2119d522f475Smrg
21209a64e1c5Smrg	    /*
21219a64e1c5Smrg	     * To make it simple, reallocate the strings returned by
21229a64e1c5Smrg	     * XtGetSubresources.  We can free our own strings, but not theirs.
21239a64e1c5Smrg	     */
21249a64e1c5Smrg	    ALLOC_STRING(subresourceRec.default_font.f_n);
21259a64e1c5Smrg	    ALLOC_STRING(subresourceRec.default_font.f_b);
21269a64e1c5Smrg#if OPT_WIDE_CHARS
21279a64e1c5Smrg	    ALLOC_STRING(subresourceRec.default_font.f_w);
21289a64e1c5Smrg	    ALLOC_STRING(subresourceRec.default_font.f_wb);
21299a64e1c5Smrg#endif
21309a64e1c5Smrg	    for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) {
21319a64e1c5Smrg		ALLOC_STRING(subresourceRec.MenuFontName(n));
21329a64e1c5Smrg	    }
21339a64e1c5Smrg
2134dfb07bc7Smrg	    /*
2135dfb07bc7Smrg	     * Now, save the string to a font-list for consistency
2136dfb07bc7Smrg	     */
2137dfb07bc7Smrg#define ALLOC_SUBLIST(which,field) \
2138dfb07bc7Smrg	    save2FontList(xw, "cached", \
2139dfb07bc7Smrg			  &(subresourceRec.fonts), \
2140dfb07bc7Smrg			  which, \
2141dfb07bc7Smrg			  subresourceRec.default_font.field, False)
2142dfb07bc7Smrg
2143dfb07bc7Smrg	    ALLOC_SUBLIST(fNorm, f_n);
2144dfb07bc7Smrg	    ALLOC_SUBLIST(fBold, f_b);
2145dfb07bc7Smrg#if OPT_WIDE_CHARS
2146dfb07bc7Smrg	    ALLOC_SUBLIST(fWide, f_w);
2147dfb07bc7Smrg	    ALLOC_SUBLIST(fWBold, f_wb);
2148dfb07bc7Smrg#endif
2149dfb07bc7Smrg
2150d522f475Smrg	    /*
2151d522f475Smrg	     * If a particular resource value was not found, use the original.
2152d522f475Smrg	     */
2153dfb07bc7Smrg	    MERGE_SUBFONT(subresourceRec, xw->misc, default_font.f_n);
2154dfb07bc7Smrg	    INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_b);
2155dfb07bc7Smrg	    MERGE_SUBLIST(subresourceRec, xw->work, list_n);
2156dfb07bc7Smrg	    MERGE_SUBLIST(subresourceRec, xw->work, list_b);
2157d522f475Smrg#if OPT_WIDE_CHARS
2158dfb07bc7Smrg	    INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_w);
2159dfb07bc7Smrg	    INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_wb);
2160dfb07bc7Smrg	    MERGE_SUBLIST(subresourceRec, xw->work, list_w);
2161dfb07bc7Smrg	    MERGE_SUBLIST(subresourceRec, xw->work, list_wb);
2162d522f475Smrg#endif
21639a64e1c5Smrg	    for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) {
2164dfb07bc7Smrg		MERGE_SUBFONT(subresourceRec, xw->screen, MenuFontName(n));
21659a64e1c5Smrg	    }
2166d522f475Smrg
2167d522f475Smrg	    /*
2168d522f475Smrg	     * Finally, copy the subresource data to the widget.
2169d522f475Smrg	     */
21709a64e1c5Smrg	    COPY_DEFAULT_FONTS(xw->misc, subresourceRec);
2171dfb07bc7Smrg	    COPY_X11_FONTLISTS(xw->work, subresourceRec);
21729a64e1c5Smrg	    FREE_MENU_FONTS(xw->screen);
2173dfb07bc7Smrg	    COPY_MENU_FONTS(xw->screen, subresourceRec);
21749a64e1c5Smrg
21759a64e1c5Smrg	    FREE_STRING(screen->MenuFontName(fontMenu_default));
21769a64e1c5Smrg	    FREE_STRING(screen->menu_font_names[0][fBold]);
2177dfb07bc7Smrg	    screen->MenuFontName(fontMenu_default) = x_strdup(DefaultFontN(xw));
2178dfb07bc7Smrg	    screen->menu_font_names[0][fBold] = x_strdup(DefaultFontB(xw));
2179d522f475Smrg#if OPT_WIDE_CHARS
21809a64e1c5Smrg	    FREE_STRING(screen->menu_font_names[0][fWide]);
21819a64e1c5Smrg	    FREE_STRING(screen->menu_font_names[0][fWBold]);
2182dfb07bc7Smrg	    screen->menu_font_names[0][fWide] = x_strdup(DefaultFontW(xw));
2183dfb07bc7Smrg	    screen->menu_font_names[0][fWBold] = x_strdup(DefaultFontWB(xw));
2184d522f475Smrg#endif
21859a64e1c5Smrg	    /*
21869a64e1c5Smrg	     * And remove our copies of strings.
21879a64e1c5Smrg	     */
21889a64e1c5Smrg	    FREE_STRING(subresourceRec.default_font.f_n);
21899a64e1c5Smrg	    FREE_STRING(subresourceRec.default_font.f_b);
21909a64e1c5Smrg#if OPT_WIDE_CHARS
21919a64e1c5Smrg	    FREE_STRING(subresourceRec.default_font.f_w);
21929a64e1c5Smrg	    FREE_STRING(subresourceRec.default_font.f_wb);
21939a64e1c5Smrg#endif
21949a64e1c5Smrg	    for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) {
21959a64e1c5Smrg		FREE_STRING(subresourceRec.MenuFontName(n));
21969a64e1c5Smrg	    }
2197d522f475Smrg	} else {
2198d522f475Smrg	    TRACE(("...no resources found\n"));
2199d522f475Smrg	    status = False;
2200d522f475Smrg	}
2201d522f475Smrg    }
2202dfb07bc7Smrg    TRACE((".. xtermLoadVTFonts: %d\n", status));
2203d522f475Smrg    return status;
2204d522f475Smrg}
2205d522f475Smrg
2206d522f475Smrg#if OPT_WIDE_CHARS
2207d522f475Smrgstatic Bool
22089a64e1c5SmrgisWideFont(XFontStruct *fp, const char *tag, Bool nullOk)
2209d522f475Smrg{
2210d522f475Smrg    Bool result = False;
2211d522f475Smrg
2212d522f475Smrg    (void) tag;
2213d522f475Smrg    if (okFont(fp)) {
2214d522f475Smrg	unsigned count = countGlyphs(fp);
2215d522f475Smrg	TRACE(("isWideFont(%s) found %d cells\n", tag, count));
2216d522f475Smrg	result = (count > 256) ? True : False;
2217d522f475Smrg    } else {
2218d522f475Smrg	result = nullOk;
2219d522f475Smrg    }
2220d522f475Smrg    return result;
2221d522f475Smrg}
2222d522f475Smrg
2223d522f475Smrg/*
2224d522f475Smrg * If the current fonts are not wide, load the UTF8 fonts.
2225d522f475Smrg *
2226d522f475Smrg * Called during initialization (for wide-character mode), the fonts have not
2227d522f475Smrg * been setup, so we pass nullOk=True to isWideFont().
2228d522f475Smrg *
2229d522f475Smrg * Called after initialization, e.g., in response to the UTF-8 menu entry
2230d522f475Smrg * (starting from narrow character mode), it checks if the fonts are not wide.
2231d522f475Smrg */
2232d522f475SmrgBool
2233d522f475SmrgxtermLoadWideFonts(XtermWidget xw, Bool nullOk)
2234d522f475Smrg{
2235956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2236d522f475Smrg    Bool result;
2237d522f475Smrg
2238d4fba8b9Smrg    if (EmptyFont(GetNormalFont(screen, fWide)->fs)) {
2239d4fba8b9Smrg	result = (isWideFont(GetNormalFont(screen, fNorm)->fs, "normal", nullOk)
2240d4fba8b9Smrg		  && isWideFont(GetNormalFont(screen, fBold)->fs, "bold", nullOk));
2241d522f475Smrg    } else {
2242d4fba8b9Smrg	result = (isWideFont(GetNormalFont(screen, fWide)->fs, "wide", nullOk)
2243d4fba8b9Smrg		  && isWideFont(GetNormalFont(screen, fWBold)->fs,
2244dfb07bc7Smrg				"wide-bold", nullOk));
2245d522f475Smrg	if (result && !screen->utf8_latin1) {
2246d4fba8b9Smrg	    result = (isWideFont(GetNormalFont(screen, fNorm)->fs, "normal", nullOk)
2247d4fba8b9Smrg		      && isWideFont(GetNormalFont(screen, fBold)->fs,
2248dfb07bc7Smrg				    "bold", nullOk));
2249d522f475Smrg	}
2250d522f475Smrg    }
2251d522f475Smrg    if (!result) {
2252d522f475Smrg	TRACE(("current fonts are not all wide%s\n", nullOk ? " nullOk" : ""));
2253e39b573cSmrg	result = xtermLoadVTFonts(xw, XtNutf8Fonts, XtCUtf8Fonts);
2254d522f475Smrg    }
2255d522f475Smrg    TRACE(("xtermLoadWideFonts:%d\n", result));
2256d522f475Smrg    return result;
2257d522f475Smrg}
2258d522f475Smrg#endif /* OPT_WIDE_CHARS */
2259d522f475Smrg
2260d522f475Smrg/*
2261d522f475Smrg * Restore the default fonts, i.e., if we had switched to wide-fonts.
2262d522f475Smrg */
2263d522f475SmrgBool
2264956cc18dSsnjxtermLoadDefaultFonts(XtermWidget xw)
2265d522f475Smrg{
2266d522f475Smrg    Bool result;
2267956cc18dSsnj    result = xtermLoadVTFonts(xw, NULL, NULL);
2268d522f475Smrg    TRACE(("xtermLoadDefaultFonts:%d\n", result));
2269d522f475Smrg    return result;
2270d522f475Smrg}
2271d522f475Smrg#endif /* OPT_LOAD_VTFONTS || OPT_WIDE_CHARS */
2272d522f475Smrg
2273d522f475Smrg#if OPT_LOAD_VTFONTS
2274d522f475Smrgvoid
2275d522f475SmrgHandleLoadVTFonts(Widget w,
22769a64e1c5Smrg		  XEvent *event GCC_UNUSED,
2277d4fba8b9Smrg		  String *params,
2278d4fba8b9Smrg		  Cardinal *param_count)
2279d522f475Smrg{
2280956cc18dSsnj    XtermWidget xw;
2281956cc18dSsnj
2282956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
2283037a25ddSmrg	static char empty[] = "";	/* appease strict compilers */
2284037a25ddSmrg
2285956cc18dSsnj	TScreen *screen = TScreenOf(xw);
2286492d43a5Smrg	char name_buf[80];
2287492d43a5Smrg	String name = (String) ((*param_count > 0) ? params[0] : empty);
228894644356Smrg	char *myName = MyStackAlloc(strlen(name) + 1, name_buf);
2289d522f475Smrg
2290d522f475Smrg	TRACE(("HandleLoadVTFonts(%d)\n", *param_count));
229194644356Smrg	if (myName != 0) {
2292037a25ddSmrg	    char class_buf[80];
229394644356Smrg	    String convert = (String) ((*param_count > 1) ? params[1] : myName);
229494644356Smrg	    char *myClass = MyStackAlloc(strlen(convert) + 1, class_buf);
229594644356Smrg
229694644356Smrg	    strcpy(myName, name);
229794644356Smrg	    if (myClass != 0) {
229894644356Smrg		strcpy(myClass, convert);
229994644356Smrg		if (*param_count == 1)
230094644356Smrg		    myClass[0] = x_toupper(myClass[0]);
230194644356Smrg
230294644356Smrg		if (xtermLoadVTFonts(xw, myName, myClass)) {
2303037a25ddSmrg		    int n;
230494644356Smrg		    /*
230594644356Smrg		     * When switching fonts, try to preserve the font-menu
230694644356Smrg		     * selection, since it is less surprising to do that (if
230794644356Smrg		     * the font-switching can be undone) than to switch to
230894644356Smrg		     * "Default".
230994644356Smrg		     */
231094644356Smrg		    int font_number = screen->menu_font_number;
231194644356Smrg		    if (font_number > fontMenu_lastBuiltin)
231294644356Smrg			font_number = fontMenu_lastBuiltin;
231394644356Smrg		    for (n = 0; n < NMENUFONTS; ++n) {
231494644356Smrg			screen->menu_font_sizes[n] = 0;
231594644356Smrg		    }
2316dfb07bc7Smrg		    if (font_number == fontMenu_default) {
2317dfb07bc7Smrg			SetVTFont(xw, font_number, True, defaultVTFontNames(xw));
2318dfb07bc7Smrg		    } else {
2319dfb07bc7Smrg			SetVTFont(xw, font_number, True, NULL);
2320dfb07bc7Smrg		    }
232194644356Smrg		}
232294644356Smrg		MyStackFree(myClass, class_buf);
23239a64e1c5Smrg	    }
232494644356Smrg	    MyStackFree(myName, name_buf);
2325d522f475Smrg	}
2326d522f475Smrg    }
2327d522f475Smrg}
2328d522f475Smrg#endif /* OPT_LOAD_VTFONTS */
2329d522f475Smrg
2330d522f475Smrg/*
2331d522f475Smrg * Set the limits for the box that outlines the cursor.
2332d522f475Smrg */
2333d522f475Smrgvoid
2334fa3f02f3SmrgxtermSetCursorBox(TScreen *screen)
2335d522f475Smrg{
2336d522f475Smrg    static XPoint VTbox[NBOX];
2337d522f475Smrg    XPoint *vp;
23382eaa94a1Schristos    int fw = FontWidth(screen) - 1;
23392eaa94a1Schristos    int fh = FontHeight(screen) - 1;
23400bd37d32Smrg    int ww = isCursorBar(screen) ? 1 : fw;
23410bd37d32Smrg    int hh = isCursorUnderline(screen) ? 1 : fh;
2342d522f475Smrg
2343d522f475Smrg    vp = &VTbox[1];
23440bd37d32Smrg    (vp++)->x = (short) ww;
23452eaa94a1Schristos    (vp++)->y = (short) hh;
23460bd37d32Smrg    (vp++)->x = (short) -ww;
23472eaa94a1Schristos    vp->y = (short) -hh;
23482eaa94a1Schristos
2349d522f475Smrg    screen->box = VTbox;
2350d522f475Smrg}
2351d522f475Smrg
2352d4fba8b9Smrg#if OPT_RENDERFONT
2353d4fba8b9Smrg
2354d4fba8b9Smrg#define CACHE_XFT(dst,src) if (src.font != 0) {\
2355d4fba8b9Smrg	    int err = checkXftWidth(xw, &(dst[fontnum]), &src);\
2356d4fba8b9Smrg	    TRACE(("Xft metrics %s[%d] = %d (%d,%d)%s advance %d, actual %d%s%s\n",\
2357d522f475Smrg		#dst,\
2358d4fba8b9Smrg		fontnum,\
2359d4fba8b9Smrg		src.font->height,\
2360d4fba8b9Smrg		src.font->ascent,\
2361d4fba8b9Smrg		src.font->descent,\
2362d4fba8b9Smrg		((src.font->ascent + src.font->descent) > src.font->height ? "*" : ""),\
2363d4fba8b9Smrg		src.font->max_advance_width,\
2364956cc18dSsnj		dst[fontnum].map.min_width,\
2365d4fba8b9Smrg		dst[fontnum].map.mixed ? " mixed" : "",\
2366d4fba8b9Smrg		err ? " ERROR" : ""));\
2367d4fba8b9Smrg	    if (err) {\
2368d4fba8b9Smrg		xtermCloseXft(screen, &src);\
2369d4fba8b9Smrg		memset((&dst[fontnum]), 0, sizeof(dst[fontnum]));\
2370d4fba8b9Smrg		failed += err;\
2371d4fba8b9Smrg	    }\
2372d522f475Smrg	}
2373d522f475Smrg
2374dfb07bc7Smrg#if OPT_REPORT_FONTS
237520d2c4d2Smrgstatic FcChar32
23769a64e1c5SmrgxtermXftFirstChar(XftFont *xft)
237720d2c4d2Smrg{
237820d2c4d2Smrg    FcChar32 map[FC_CHARSET_MAP_SIZE];
237920d2c4d2Smrg    FcChar32 next;
238020d2c4d2Smrg    FcChar32 first;
238120d2c4d2Smrg    int i;
238220d2c4d2Smrg
238320d2c4d2Smrg    first = FcCharSetFirstPage(xft->charset, map, &next);
23849a64e1c5Smrg    for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) {
238520d2c4d2Smrg	if (map[i]) {
238620d2c4d2Smrg	    FcChar32 bits = map[i];
2387fa3f02f3Smrg	    first += (FcChar32) i *32;
238820d2c4d2Smrg	    while (!(bits & 0x1)) {
238920d2c4d2Smrg		bits >>= 1;
239020d2c4d2Smrg		first++;
239120d2c4d2Smrg	    }
239220d2c4d2Smrg	    break;
239320d2c4d2Smrg	}
23949a64e1c5Smrg    }
239520d2c4d2Smrg    return first;
239620d2c4d2Smrg}
239720d2c4d2Smrg
239820d2c4d2Smrgstatic FcChar32
23999a64e1c5SmrgxtermXftLastChar(XftFont *xft)
240020d2c4d2Smrg{
240120d2c4d2Smrg    FcChar32 this, last, next;
240220d2c4d2Smrg    FcChar32 map[FC_CHARSET_MAP_SIZE];
240320d2c4d2Smrg    int i;
240420d2c4d2Smrg    last = FcCharSetFirstPage(xft->charset, map, &next);
240520d2c4d2Smrg    while ((this = FcCharSetNextPage(xft->charset, map, &next)) != FC_CHARSET_DONE)
240620d2c4d2Smrg	last = this;
2407fa3f02f3Smrg    last &= (FcChar32) ~ 0xff;
24089a64e1c5Smrg    for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--) {
240920d2c4d2Smrg	if (map[i]) {
241020d2c4d2Smrg	    FcChar32 bits = map[i];
2411fa3f02f3Smrg	    last += (FcChar32) i *32 + 31;
241220d2c4d2Smrg	    while (!(bits & 0x80000000)) {
241320d2c4d2Smrg		last--;
241420d2c4d2Smrg		bits <<= 1;
241520d2c4d2Smrg	    }
241620d2c4d2Smrg	    break;
241720d2c4d2Smrg	}
24189a64e1c5Smrg    }
2419dfb07bc7Smrg    return (FcChar32) last;
242020d2c4d2Smrg}
2421dfb07bc7Smrg#endif /* OPT_REPORT_FONTS */
242220d2c4d2Smrg
2423d4fba8b9Smrg#if OPT_TRACE
2424d4fba8b9Smrg
2425d4fba8b9Smrg#if !OPT_WIDE_CHARS
2426d4fba8b9Smrgstatic Char *
2427d4fba8b9SmrgconvertToUTF8(Char *buffer, int c)
2428d4fba8b9Smrg{
2429d4fba8b9Smrg    buffer[0] = (Char) c;
2430d4fba8b9Smrg    buffer[1] = 0;
2431d4fba8b9Smrg    return buffer;
2432d4fba8b9Smrg}
2433d4fba8b9Smrg#endif
2434d4fba8b9Smrg
243520d2c4d2Smrgstatic void
24369a64e1c5SmrgdumpXft(XtermWidget xw, XTermXftFonts *data)
243720d2c4d2Smrg{
243820d2c4d2Smrg    XftFont *xft = data->font;
243920d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
244020d2c4d2Smrg    VTwin *win = WhichVWin(screen);
244120d2c4d2Smrg
244220d2c4d2Smrg    FcChar32 c;
244320d2c4d2Smrg    FcChar32 first = xtermXftFirstChar(xft);
244420d2c4d2Smrg    FcChar32 last = xtermXftLastChar(xft);
2445d4fba8b9Smrg    FcChar32 dump;
244620d2c4d2Smrg    unsigned count = 0;
2447d4fba8b9Smrg    unsigned too_high = 0;
2448d4fba8b9Smrg    unsigned too_wide = 0;
2449d4fba8b9Smrg    Boolean skip = False;
2450d4fba8b9Smrg
2451d4fba8b9Smrg    TRACE(("dumpXft " TRACE_L "\n"));
2452d4fba8b9Smrg    TRACE(("\tdata range U+%04X..U+%04X\n", first, last));
2453d4fba8b9Smrg    TRACE(("\tcode\tcells\tdimensions\n"));
2454d4fba8b9Smrg#if OPT_TRACE < 2
2455d4fba8b9Smrg    dump = 255;
2456d4fba8b9Smrg#else
2457d4fba8b9Smrg    dump = last;
2458d4fba8b9Smrg#endif
245920d2c4d2Smrg    for (c = first; c <= last; ++c) {
246020d2c4d2Smrg	if (FcCharSetHasChar(xft->charset, c)) {
2461c48a5815Smrg	    int width = CharWidth(screen, c);
246220d2c4d2Smrg	    XGlyphInfo extents;
2463d4fba8b9Smrg	    Boolean big_x;
2464d4fba8b9Smrg	    Boolean big_y;
246520d2c4d2Smrg
246620d2c4d2Smrg	    XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents);
2467d4fba8b9Smrg	    big_x = (extents.width > win->f_width);
2468d4fba8b9Smrg	    big_y = (extents.height > win->f_height);
2469d4fba8b9Smrg
2470d4fba8b9Smrg	    if (c <= dump) {
2471d4fba8b9Smrg		Char buffer[80];
2472d4fba8b9Smrg
2473d4fba8b9Smrg		*convertToUTF8(buffer, c) = '\0';
2474d4fba8b9Smrg		TRACE(("%s%s\tU+%04X\t%d\t%.1f x %.1f\t%s\n",
2475d4fba8b9Smrg		       (big_y ? "y" : ""),
2476d4fba8b9Smrg		       (big_x ? "x" : ""),
2477d4fba8b9Smrg		       c, width,
2478d4fba8b9Smrg		       ((double) extents.height) / win->f_height,
2479d4fba8b9Smrg		       ((double) extents.width) / win->f_width,
2480d4fba8b9Smrg		       buffer));
2481d4fba8b9Smrg	    } else if (!skip) {
2482d4fba8b9Smrg		skip = True;
2483d4fba8b9Smrg		TRACE(("\t...skipping\n"));
2484d4fba8b9Smrg	    }
2485d4fba8b9Smrg	    if (big_y)
2486d4fba8b9Smrg		++too_high;
2487d4fba8b9Smrg	    if (big_x)
2488d4fba8b9Smrg		++too_wide;
248920d2c4d2Smrg	    ++count;
249020d2c4d2Smrg	}
249120d2c4d2Smrg    }
2492d4fba8b9Smrg    TRACE((TRACE_R " %u total, %u too-high, %u too-wide\n", count, too_high, too_wide));
249320d2c4d2Smrg}
249420d2c4d2Smrg#define DUMP_XFT(xw, data) dumpXft(xw, data)
249520d2c4d2Smrg#else
249620d2c4d2Smrg#define DUMP_XFT(xw, data)	/* nothing */
249720d2c4d2Smrg#endif
249820d2c4d2Smrg
2499d4fba8b9Smrg/*
2500d4fba8b9Smrg * Check if this is a FC_COLOR font, which fontconfig misrepresents to "fix" a
2501d4fba8b9Smrg * problem with web browsers.  As of 2018/12 (4 years later), Xft does not work
2502d4fba8b9Smrg * with that.  Even with this workaround, fontconfig has at least one bug which
2503d4fba8b9Smrg * causes it to crash (Debian #917034).
2504d4fba8b9Smrg */
2505d4fba8b9Smrg#ifdef FC_COLOR
2506d4fba8b9Smrg#define GetFcBool(pattern, what) \
2507d4fba8b9Smrg    (FcPatternGetBool(pattern, what, 0, &fcbogus) == FcResultMatch)
2508d4fba8b9Smrg
2509d4fba8b9Smrgstatic Boolean
2510d4fba8b9SmrgisBogusXft(XftFont *font)
2511d4fba8b9Smrg{
2512d4fba8b9Smrg    Boolean result = False;
2513d4fba8b9Smrg    if (font != 0) {
2514d4fba8b9Smrg	FcBool fcbogus;
2515d4fba8b9Smrg	if (GetFcBool(font->pattern, FC_COLOR) && fcbogus) {
2516d4fba8b9Smrg	    TRACE(("...matched color-bitmap font\n"));
2517d4fba8b9Smrg	    result = True;
2518d4fba8b9Smrg	} else if (GetFcBool(font->pattern, FC_OUTLINE) && !fcbogus) {
2519d4fba8b9Smrg	    TRACE(("...matched non-outline font\n"));
2520d4fba8b9Smrg	    /* This is legal for regular bitmap fonts - fontconfig attempts to
2521d4fba8b9Smrg	     * find a match - but problematic for misencoded color-bitmap fonts.
2522d4fba8b9Smrg	     */
2523d4fba8b9Smrg	}
2524d4fba8b9Smrg    }
2525d4fba8b9Smrg    return result;
2526d4fba8b9Smrg}
2527d4fba8b9Smrg#endif
2528d4fba8b9Smrg
2529d4fba8b9Smrg#if OPT_BOX_CHARS
2530956cc18dSsnjstatic void
2531d4fba8b9SmrgsetBrokenBoxChars(XtermWidget xw, Bool state)
2532d4fba8b9Smrg{
2533d4fba8b9Smrg    TRACE(("setBrokenBoxChars %s\n", BtoS(state)));
2534d4fba8b9Smrg    term->work.broken_box_chars = (Boolean) state;
2535d4fba8b9Smrg    TScreenOf(xw)->broken_box_chars = (Boolean) state;
2536d4fba8b9Smrg    update_font_boxchars();
2537d4fba8b9Smrg}
2538d4fba8b9Smrg
2539d4fba8b9Smrg#else
2540d4fba8b9Smrg#define setBrokenBoxChars(xw, state)	/* nothing */
2541d4fba8b9Smrg#endif
2542d4fba8b9Smrg
2543d4fba8b9Smrgstatic Boolean
2544d4fba8b9SmrgcheckedXftWidth(Display *dpy,
2545d4fba8b9Smrg		XTermXftFonts *source,
2546d4fba8b9Smrg		unsigned limit,
2547d4fba8b9Smrg		Dimension *width,
2548d4fba8b9Smrg		FcChar32 c)
2549d4fba8b9Smrg{
2550d4fba8b9Smrg    Boolean result = False;
2551d4fba8b9Smrg
2552d4fba8b9Smrg    if (FcCharSetHasChar(source->font->charset, c)) {
2553d4fba8b9Smrg	XGlyphInfo extents;
2554d4fba8b9Smrg
2555d4fba8b9Smrg	result = True;
2556d4fba8b9Smrg	XftTextExtents32(dpy, source->font, &c, 1, &extents);
2557d4fba8b9Smrg	if (*width < extents.width && extents.width <= limit) {
2558d4fba8b9Smrg	    *width = extents.width;
2559d4fba8b9Smrg	}
2560d4fba8b9Smrg    }
2561d4fba8b9Smrg    return result;
2562d4fba8b9Smrg}
2563d4fba8b9Smrg
2564d4fba8b9Smrgstatic int
2565d4fba8b9SmrgcheckXftWidth(XtermWidget xw, XTermXftFonts *target, XTermXftFonts *source)
2566956cc18dSsnj{
2567956cc18dSsnj    FcChar32 c;
2568d4fba8b9Smrg    FcChar32 last = xtermXftLastChar(source->font);
2569d4fba8b9Smrg    Dimension limit = (Dimension) source->font->max_advance_width;
2570956cc18dSsnj    Dimension width = 0;
2571d4fba8b9Smrg    Dimension width2 = 0;
2572d4fba8b9Smrg    int failed = 0;
2573d4fba8b9Smrg#if OPT_WIDE_CHARS
2574d4fba8b9Smrg    Cardinal n;
2575d4fba8b9Smrg#endif
2576956cc18dSsnj
2577d4fba8b9Smrg    target->font = source->font;
2578d4fba8b9Smrg    target->pattern = source->pattern;
2579d4fba8b9Smrg    target->map.min_width = 0;
2580d4fba8b9Smrg    target->map.max_width = limit;
2581d4fba8b9Smrg
2582d4fba8b9Smrg#if OPT_WIDE_CHARS
2583d4fba8b9Smrg    /*
2584d4fba8b9Smrg     * Check if the line-drawing characters are all provided in the font.
2585d4fba8b9Smrg     * If so, take that into account for the cell-widths.
2586d4fba8b9Smrg     */
2587d4fba8b9Smrg    for (n = 0; n < XtNumber(unicode_boxes) - 1; ++n) {
2588d4fba8b9Smrg	if (!checkedXftWidth(XtDisplay(xw),
2589d4fba8b9Smrg			     source,
2590d4fba8b9Smrg			     limit,
2591d4fba8b9Smrg			     &width2, unicode_boxes[n].code)) {
2592d4fba8b9Smrg	    width2 = 0;
2593d4fba8b9Smrg	    TRACE(("font omits U+%04X line-drawing symbol\n",
2594d4fba8b9Smrg		   unicode_boxes[n].code));
2595d4fba8b9Smrg	    break;
2596d4fba8b9Smrg	}
2597d4fba8b9Smrg    }
2598d4fba8b9Smrg#else
2599d4fba8b9Smrg    (void) width2;
2600d4fba8b9Smrg#endif
2601d4fba8b9Smrg
2602d4fba8b9Smrg    if (width2 > 0) {
2603d4fba8b9Smrg	Dimension check = (Dimension) (limit + 1) / 2;
2604d4fba8b9Smrg	TRACE(("font provides VT100-style line-drawing\n"));
2605d4fba8b9Smrg	/*
2606d4fba8b9Smrg	 * The "VT100 line-drawing" characters happen to be all "ambiguous
2607d4fba8b9Smrg	 * width" in Unicode's scheme.  That means that they could be twice as
2608d4fba8b9Smrg	 * wide as the Latin-1 characters.
2609d4fba8b9Smrg	 */
2610d4fba8b9Smrg#define FC_ERR(n) (1.2 * (n))
2611d4fba8b9Smrg	if (width2 > FC_ERR(check)) {
2612d4fba8b9Smrg	    TRACE(("line-drawing characters appear to be double-width (ignore)\n"));
2613d4fba8b9Smrg	    setBrokenBoxChars(xw, True);
2614d4fba8b9Smrg	} else if (width2 > width) {
2615d4fba8b9Smrg	    width = width2;
2616d4fba8b9Smrg	}
2617d4fba8b9Smrg    } else {
2618d4fba8b9Smrg	TRACE(("font does NOT provide VT100-style line-drawing\n"));
2619d4fba8b9Smrg	setBrokenBoxChars(xw, True);
2620d4fba8b9Smrg    }
2621956cc18dSsnj
262220d2c4d2Smrg    /*
2623d4fba8b9Smrg     * For each printable code, ask what its width is.  Given the maximum width
2624d4fba8b9Smrg     * for those, we have a reasonable estimate of the single-column width.
262520d2c4d2Smrg     *
262620d2c4d2Smrg     * Ignore control characters - their extent information is misleading.
262720d2c4d2Smrg     */
2628956cc18dSsnj    for (c = 32; c < 256; ++c) {
2629c48a5815Smrg	if (CharWidth(TScreenOf(xw), c) <= 0)
263020d2c4d2Smrg	    continue;
2631d4fba8b9Smrg	if (FcCharSetHasChar(source->font->charset, c)) {
2632d4fba8b9Smrg	    (void) checkedXftWidth(XtDisplay(xw),
2633d4fba8b9Smrg				   source,
2634d4fba8b9Smrg				   target->map.max_width,
2635d4fba8b9Smrg				   &width, c);
2636d4fba8b9Smrg	}
2637d4fba8b9Smrg    }
2638956cc18dSsnj
2639d4fba8b9Smrg    /*
2640d4fba8b9Smrg     * Sometimes someone uses a symbol font which has no useful ASCII or
2641d4fba8b9Smrg     * Latin-1 characters.  Allow that, in case they did it intentionally.
2642d4fba8b9Smrg     */
2643d4fba8b9Smrg    if (width == 0) {
2644d4fba8b9Smrg	failed = 1;
2645d4fba8b9Smrg	if (last >= 256) {
2646d4fba8b9Smrg	    width = target->map.max_width;
2647956cc18dSsnj	}
2648956cc18dSsnj    }
2649d4fba8b9Smrg    target->map.min_width = width;
2650d4fba8b9Smrg    target->map.mixed = (target->map.max_width >= (target->map.min_width + 1));
2651d4fba8b9Smrg    return failed;
2652956cc18dSsnj}
2653956cc18dSsnj
2654dfb07bc7Smrg#if OPT_REPORT_FONTS
2655fa3f02f3Smrgstatic void
2656fa3f02f3SmrgreportXftFonts(XtermWidget xw,
26579a64e1c5Smrg	       XftFont *fp,
2658fa3f02f3Smrg	       const char *name,
2659fa3f02f3Smrg	       const char *tag,
26609a64e1c5Smrg	       XftPattern *match)
2661fa3f02f3Smrg{
2662fa3f02f3Smrg    if (resource.reportFonts) {
2663fa3f02f3Smrg	char buffer[1024];
2664fa3f02f3Smrg	FcChar32 first_char = xtermXftFirstChar(fp);
2665fa3f02f3Smrg	FcChar32 last_char = xtermXftLastChar(fp);
2666fa3f02f3Smrg	FcChar32 ch;
2667fa3f02f3Smrg	unsigned missing = 0;
2668fa3f02f3Smrg
266994644356Smrg	printf("Loaded XftFonts(%s[%s])\n", name, tag);
2670fa3f02f3Smrg
2671fa3f02f3Smrg	for (ch = first_char; ch <= last_char; ++ch) {
2672fa3f02f3Smrg	    if (xtermXftMissing(xw, fp, ch)) {
2673fa3f02f3Smrg		++missing;
2674fa3f02f3Smrg	    }
2675fa3f02f3Smrg	}
2676fa3f02f3Smrg	printf("\t\tfirst char:    %u\n", first_char);
2677fa3f02f3Smrg	printf("\t\tlast char:     %u\n", last_char);
2678fa3f02f3Smrg	printf("\t\tmissing-chars: %u\n", missing);
2679fa3f02f3Smrg	printf("\t\tpresent-chars: %u\n", (last_char - first_char) + 1 - missing);
2680fa3f02f3Smrg
2681fa3f02f3Smrg	if (XftNameUnparse(match, buffer, (int) sizeof(buffer))) {
2682fa3f02f3Smrg	    char *target;
2683fa3f02f3Smrg	    char *source = buffer;
2684fa3f02f3Smrg	    while ((target = strtok(source, ":")) != 0) {
2685fa3f02f3Smrg		printf("\t%s\n", target);
2686fa3f02f3Smrg		source = 0;
2687fa3f02f3Smrg	    }
2688fa3f02f3Smrg	}
2689d4fba8b9Smrg	fflush(stdout);
2690fa3f02f3Smrg    }
2691fa3f02f3Smrg}
2692dfb07bc7Smrg#else
2693dfb07bc7Smrg#define reportXftFonts(xw, result, name, tag, match)	/* empty */
2694dfb07bc7Smrg#endif /* OPT_REPORT_FONTS */
2695fa3f02f3Smrg
2696d4fba8b9Smrg/*
2697d4fba8b9Smrg * Xft discards the pattern-match during open-pattern if the result happens to
2698d4fba8b9Smrg * match a currently-open file, but provides no clue to the caller when it does
2699d4fba8b9Smrg * this.  That is, closing a font-file may leave the data in Xft's cache, while
2700d4fba8b9Smrg * opening a file may free the data used for the match.
2701d4fba8b9Smrg *
2702d4fba8b9Smrg * Because of this problem, we cannot reliably refer to the pattern-match data
2703d4fba8b9Smrg * if it may have been seen before.
2704d4fba8b9Smrg */
2705d4fba8b9SmrgBoolean
2706d4fba8b9SmrgmaybeXftCache(XtermWidget xw, XftFont *font)
2707d4fba8b9Smrg{
2708d4fba8b9Smrg    Boolean result = False;
2709d4fba8b9Smrg    if (font != 0) {
2710d4fba8b9Smrg	TScreen *screen = TScreenOf(xw);
2711d4fba8b9Smrg	ListXftFonts *p;
2712d4fba8b9Smrg	for (p = screen->list_xft_fonts; p != 0; p = p->next) {
2713d4fba8b9Smrg	    if (p->font == font) {
2714d4fba8b9Smrg		result = True;
2715d4fba8b9Smrg		break;
2716d4fba8b9Smrg	    }
2717d4fba8b9Smrg	}
2718d4fba8b9Smrg	if (!result) {
2719d4fba8b9Smrg	    p = TypeXtMalloc(ListXftFonts);
2720d4fba8b9Smrg	    if (p != 0) {
2721d4fba8b9Smrg		p->font = font;
2722d4fba8b9Smrg		p->next = screen->list_xft_fonts;
2723d4fba8b9Smrg		screen->list_xft_fonts = p;
2724d4fba8b9Smrg	    }
2725d4fba8b9Smrg	}
2726d4fba8b9Smrg    }
2727d4fba8b9Smrg    return result;
2728d4fba8b9Smrg}
2729d4fba8b9Smrg
2730d4fba8b9Smrg/*
2731d4fba8b9Smrg * Drop an entry from the cache, and close the font.
2732d4fba8b9Smrg */
2733d4fba8b9Smrgvoid
2734d4fba8b9SmrgcloseCachedXft(TScreen *screen, XftFont *font)
2735d4fba8b9Smrg{
2736d4fba8b9Smrg    if (font != 0) {
2737d4fba8b9Smrg	ListXftFonts *p, *q;
2738d4fba8b9Smrg
2739d4fba8b9Smrg	for (p = screen->list_xft_fonts, q = 0; p != 0; q = p, p = p->next) {
2740d4fba8b9Smrg	    if (p->font == font) {
2741d4fba8b9Smrg		XftFontClose(screen->display, font);
2742d4fba8b9Smrg		if (q != 0) {
2743d4fba8b9Smrg		    q->next = p->next;
2744d4fba8b9Smrg		} else {
2745d4fba8b9Smrg		    screen->list_xft_fonts = p->next;
2746d4fba8b9Smrg		}
2747d4fba8b9Smrg		free(p);
2748d4fba8b9Smrg		break;
2749d4fba8b9Smrg	    }
2750d4fba8b9Smrg	}
2751d4fba8b9Smrg    }
2752d4fba8b9Smrg}
2753d4fba8b9Smrg
2754d522f475Smrgstatic XftFont *
27559a64e1c5SmrgxtermOpenXft(XtermWidget xw, const char *name, XftPattern *pat, const char *tag)
2756d522f475Smrg{
2757956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2758956cc18dSsnj    Display *dpy = screen->display;
2759d522f475Smrg    XftResult status;
2760d522f475Smrg    XftFont *result = 0;
2761d522f475Smrg
2762d4fba8b9Smrg    TRACE(("xtermOpenXft(name=%s, tag=%s)\n", name, tag));
2763d522f475Smrg    if (pat != 0) {
2764d4fba8b9Smrg	XftPattern *match;
2765d4fba8b9Smrg
2766d4fba8b9Smrg	FcConfigSubstitute(NULL, pat, FcMatchPattern);
2767d4fba8b9Smrg	XftDefaultSubstitute(dpy, DefaultScreen(dpy), pat);
2768d4fba8b9Smrg
2769d4fba8b9Smrg	match = FcFontMatch(NULL, pat, &status);
2770d522f475Smrg	if (match != 0) {
2771d4fba8b9Smrg	    Boolean maybeReopened = False;
2772d522f475Smrg	    result = XftFontOpenPattern(dpy, match);
2773d4fba8b9Smrg#ifdef FC_COLOR
2774d4fba8b9Smrg	    if (result != 0) {
2775d4fba8b9Smrg		if (isBogusXft(result)) {
2776d4fba8b9Smrg		    XftFontClose(dpy, result);
2777d4fba8b9Smrg		    result = 0;
2778d4fba8b9Smrg		    maybeReopened = True;
2779d4fba8b9Smrg		}
2780d4fba8b9Smrg	    }
2781d4fba8b9Smrg#endif
2782d522f475Smrg	    if (result != 0) {
2783d522f475Smrg		TRACE(("...matched %s font\n", tag));
2784d4fba8b9Smrg		if (!maybeXftCache(xw, result)) {
2785d4fba8b9Smrg		    reportXftFonts(xw, result, name, tag, match);
2786d4fba8b9Smrg		}
2787d522f475Smrg	    } else {
2788d4fba8b9Smrg		TRACE(("...could not open %s font\n", tag));
2789d4fba8b9Smrg		if (!maybeReopened)
2790d4fba8b9Smrg		    XftPatternDestroy(match);
2791956cc18dSsnj		if (xw->misc.fontWarnings >= fwAlways) {
2792dfb07bc7Smrg		    cannotFont(xw, "open", tag, name);
2793956cc18dSsnj		}
2794d522f475Smrg	    }
2795d522f475Smrg	} else {
2796d522f475Smrg	    TRACE(("...did not match %s font\n", tag));
2797956cc18dSsnj	    if (xw->misc.fontWarnings >= fwResource) {
2798dfb07bc7Smrg		cannotFont(xw, "match", tag, name);
2799956cc18dSsnj	    }
2800d522f475Smrg	}
2801d522f475Smrg    }
2802d522f475Smrg    return result;
2803d522f475Smrg}
2804d522f475Smrg
2805d522f475Smrg#if OPT_SHIFT_FONTS
2806d522f475Smrg/*
2807d522f475Smrg * Don't make a dependency on the math library for a single function.
2808d522f475Smrg * (Newton Raphson).
2809d522f475Smrg */
2810d522f475Smrgstatic double
28110bd37d32SmrgdimSquareRoot(double value)
2812d522f475Smrg{
2813d522f475Smrg    double result = 0.0;
2814d522f475Smrg    if (value > 0.0) {
2815d522f475Smrg	int n;
2816d522f475Smrg	double older = value;
2817d522f475Smrg	for (n = 0; n < 10; ++n) {
2818d522f475Smrg	    double delta = (older * older - value) / (2.0 * older);
2819d522f475Smrg	    double newer = older - delta;
2820d522f475Smrg	    older = newer;
2821d522f475Smrg	    result = newer;
2822d522f475Smrg	    if (delta > -0.001 && delta < 0.001)
2823d522f475Smrg		break;
2824d522f475Smrg	}
2825d522f475Smrg    }
2826d522f475Smrg    return result;
2827d522f475Smrg}
2828d522f475Smrg#endif
2829d522f475Smrg
2830d4fba8b9Smrg#ifdef DEBUG_XFT
2831d4fba8b9Smrgstatic void
2832d4fba8b9Smrgtrace_xft_glyph(TScreen *screen, XftFont *font, FT_Face face, int code, const char *name)
2833d4fba8b9Smrg{
2834d4fba8b9Smrg    if (!XftGlyphExists(screen->display, font, code)) {
2835d4fba8b9Smrg	TRACE(("Xft glyph U+%04X missing :%s\n", code, name));
2836d4fba8b9Smrg    } else if (FT_Load_Char(face, code, FT_LOAD_RENDER) == 0) {
2837d4fba8b9Smrg	FT_GlyphSlot g = face->glyph;
2838d4fba8b9Smrg	TRACE(("Xft glyph U+%04X size(%3d,%3d) at(%3d,%3d) :%s\n",
2839d4fba8b9Smrg	       code,
2840d4fba8b9Smrg	       g->bitmap.rows, g->bitmap.width,
2841d4fba8b9Smrg	       g->bitmap_top, g->bitmap_left,
2842d4fba8b9Smrg	       name));
2843d4fba8b9Smrg    }
2844d4fba8b9Smrg}
2845d4fba8b9Smrg
2846d4fba8b9Smrg#if OPT_WIDE_CHARS
2847d4fba8b9Smrgstatic void
2848d4fba8b9Smrgtrace_xft_line_drawing(TScreen *screen, XftFont *font, FT_Face face)
2849d4fba8b9Smrg{
2850d4fba8b9Smrg    int n;
2851d4fba8b9Smrg    for (n = 0; unicode_boxes[n].code != 0; ++n) {
2852d4fba8b9Smrg	trace_xft_glyph(screen, font, face, unicode_boxes[n].code,
2853d4fba8b9Smrg			unicode_boxes[n].name);
2854d4fba8b9Smrg    }
2855d4fba8b9Smrg}
2856d4fba8b9Smrg#else
2857d4fba8b9Smrg#define trace_xft_line_drawing(screen, font, face)	/* nothing */
2858d4fba8b9Smrg#endif
2859d4fba8b9Smrg#endif /* DEBUG_XFT */
2860d4fba8b9Smrg
2861d4fba8b9Smrg/*
2862d4fba8b9Smrg * Check if the line-drawing characters do not fill the bounding box.  If so,
2863d4fba8b9Smrg * they're not useful.
2864d4fba8b9Smrg */
2865d4fba8b9Smrg#if OPT_BOX_CHARS
2866d4fba8b9Smrgstatic void
2867d4fba8b9Smrglinedrawing_gaps(XtermWidget xw, XftFont *font)
2868d4fba8b9Smrg{
2869d4fba8b9Smrg    Boolean broken;
2870d4fba8b9Smrg
2871d4fba8b9Smrg#if OPT_WIDE_CHARS
2872d4fba8b9Smrg    TScreen *screen = TScreenOf(xw);
2873d4fba8b9Smrg    int n;
2874d4fba8b9Smrg    FT_Face face;
2875d4fba8b9Smrg    face = XftLockFace(font);
2876d4fba8b9Smrg    broken = False;
2877d4fba8b9Smrg    for (n = 0; unicode_boxes[n].code; ++n) {
2878d4fba8b9Smrg	unsigned code = unicode_boxes[n].code;
2879d4fba8b9Smrg
2880d4fba8b9Smrg	if (!XftGlyphExists(screen->display, font, code)) {
2881d4fba8b9Smrg	    TRACE(("Xft glyph U+%04X is missing\n", code));
2882d4fba8b9Smrg	    broken = True;
2883d4fba8b9Smrg	    break;
2884d4fba8b9Smrg	}
2885d4fba8b9Smrg
2886d4fba8b9Smrg	if (FT_Load_Char(face, code, FT_LOAD_RENDER) == 0) {
2887d4fba8b9Smrg	    FT_GlyphSlot g = face->glyph;
2888d4fba8b9Smrg	    TRACE(("Xft glyph U+%04X size(%3d,%3d) at(%3d,%3d) :%s\n",
2889d4fba8b9Smrg		   code,
2890d4fba8b9Smrg		   g->bitmap.rows, g->bitmap.width,
2891d4fba8b9Smrg		   g->bitmap_top, g->bitmap_left,
2892d4fba8b9Smrg		   unicode_boxes[n].name));
2893d4fba8b9Smrg	    /*
2894d4fba8b9Smrg	     * While it is possible for badly-designed fonts to have line
2895d4fba8b9Smrg	     * drawing characters which do not meet, FreeType aggravates the
2896d4fba8b9Smrg	     * situation with its rounding.  Check for an obvious case where
2897d4fba8b9Smrg	     * the weights at the ends of a vertical line do not add up.  That
2898d4fba8b9Smrg	     * shows up as two under-weight rows at the beginning/end of the
2899d4fba8b9Smrg	     * bitmap.
2900d4fba8b9Smrg	     */
2901d4fba8b9Smrg	    if (code == 0x2502) {
2902d4fba8b9Smrg		unsigned r, c;
2903d4fba8b9Smrg		unsigned mids = 0, ends = 0;
2904d4fba8b9Smrg		unsigned char *data = g->bitmap.buffer;
2905d4fba8b9Smrg
2906d4fba8b9Smrg		switch (g->bitmap.pixel_mode) {
2907d4fba8b9Smrg		case FT_PIXEL_MODE_MONO:
2908d4fba8b9Smrg		    /* FALLTHRU */
2909d4fba8b9Smrg		case FT_PIXEL_MODE_GRAY:
2910d4fba8b9Smrg		    for (r = 0; r < (unsigned) g->bitmap.rows; ++r) {
2911d4fba8b9Smrg			unsigned k = r * (unsigned) g->bitmap.pitch;
2912d4fba8b9Smrg			unsigned sum = 0;
2913d4fba8b9Smrg			for (c = 0; c < (unsigned) g->bitmap.width; ++c) {
2914d4fba8b9Smrg			    unsigned xx = 0;
2915d4fba8b9Smrg			    switch (g->bitmap.pixel_mode) {
2916d4fba8b9Smrg			    case FT_PIXEL_MODE_MONO:
2917d4fba8b9Smrg				xx = (unsigned) ((data[k + (c / 8)]
2918d4fba8b9Smrg						  >> (c % 8)) & 1);
2919d4fba8b9Smrg				break;
2920d4fba8b9Smrg			    case FT_PIXEL_MODE_GRAY:
2921d4fba8b9Smrg				xx = data[k + c];
2922d4fba8b9Smrg				break;
2923d4fba8b9Smrg			    }
2924d4fba8b9Smrg			    sum += xx;
2925d4fba8b9Smrg			    TRACE2((" %2x", xx));
2926d4fba8b9Smrg			}
2927d4fba8b9Smrg			TRACE2((" = %u\n", sum));
2928d4fba8b9Smrg			if (r > 0 && (r + 1) < (unsigned) g->bitmap.rows) {
2929d4fba8b9Smrg			    mids = sum;
2930d4fba8b9Smrg			} else {
2931d4fba8b9Smrg			    ends += sum;
2932d4fba8b9Smrg			}
2933d4fba8b9Smrg		    }
2934d4fba8b9Smrg		    TRACE(("...compare middle %u vs ends %u\n", mids, ends));
2935d4fba8b9Smrg		    if ((mids > ends) && (g->bitmap.rows < 16))
2936d4fba8b9Smrg			broken = True;
2937d4fba8b9Smrg		    break;
2938d4fba8b9Smrg		default:
2939d4fba8b9Smrg		    TRACE(("FIXME pixel_mode %d not handled\n",
2940d4fba8b9Smrg			   g->bitmap.pixel_mode));
2941d4fba8b9Smrg		    break;
2942d4fba8b9Smrg		}
2943d4fba8b9Smrg		if (broken)
2944d4fba8b9Smrg		    break;
2945d4fba8b9Smrg	    }
2946d4fba8b9Smrg	    /*
2947d4fba8b9Smrg	     * The factor of two accounts for line-drawing that goes through
2948d4fba8b9Smrg	     * the middle of a cell, possibly leaving half of the cell unused.
2949d4fba8b9Smrg	     * A horizontal line has to extend the full width of the cell.
2950d4fba8b9Smrg	     */
2951d4fba8b9Smrg	    switch (unicode_boxes[n].high) {
2952d4fba8b9Smrg	    case 1:
2953d4fba8b9Smrg		if ((unsigned) g->bitmap.rows < (unsigned) FontHeight(screen)) {
2954d4fba8b9Smrg		    TRACE(("...bitmap is shorter than full-cell (%u vs %u)\n",
2955d4fba8b9Smrg			   (unsigned) g->bitmap.rows,
2956d4fba8b9Smrg			   (unsigned) FontHeight(screen)));
2957d4fba8b9Smrg		    broken = True;
2958d4fba8b9Smrg		}
2959d4fba8b9Smrg		break;
2960d4fba8b9Smrg	    case 2:
2961d4fba8b9Smrg		if ((unsigned) (g->bitmap.rows * 2) < (unsigned) FontHeight(screen)) {
2962d4fba8b9Smrg		    TRACE(("...bitmap is too short for half-cell (%u vs %u)\n",
2963d4fba8b9Smrg			   (unsigned) (g->bitmap.rows * 2),
2964d4fba8b9Smrg			   (unsigned) FontHeight(screen)));
2965d4fba8b9Smrg		    broken = True;
2966d4fba8b9Smrg		}
2967d4fba8b9Smrg		break;
2968d4fba8b9Smrg	    }
2969d4fba8b9Smrg	    switch (unicode_boxes[n].wide) {
2970d4fba8b9Smrg	    case 1:
2971d4fba8b9Smrg		if ((unsigned) g->bitmap.width < (unsigned) FontWidth(screen)) {
2972d4fba8b9Smrg		    TRACE(("...bitmap is narrower than full-cell (%u vs %u)\n",
2973d4fba8b9Smrg			   (unsigned) g->bitmap.width,
2974d4fba8b9Smrg			   (unsigned) FontWidth(screen)));
2975d4fba8b9Smrg		    broken = True;
2976d4fba8b9Smrg		}
2977d4fba8b9Smrg		break;
2978d4fba8b9Smrg	    case 2:
2979d4fba8b9Smrg		if ((unsigned) (g->bitmap.width * 2) < (unsigned) FontWidth(screen)) {
2980d4fba8b9Smrg		    TRACE(("...bitmap is too narrow for half-cell (%u vs %u)\n",
2981d4fba8b9Smrg			   (unsigned) (g->bitmap.width * 2),
2982d4fba8b9Smrg			   (unsigned) FontWidth(screen)));
2983d4fba8b9Smrg		    broken = True;
2984d4fba8b9Smrg		}
2985d4fba8b9Smrg		break;
2986d4fba8b9Smrg	    }
2987d4fba8b9Smrg	    if (broken)
2988d4fba8b9Smrg		break;
2989d4fba8b9Smrg	}
2990d4fba8b9Smrg    }
2991d4fba8b9Smrg    XftUnlockFace(font);
2992d4fba8b9Smrg#else
2993d4fba8b9Smrg    (void) font;
2994d4fba8b9Smrg    broken = True;
2995d4fba8b9Smrg#endif
2996d4fba8b9Smrg
2997d4fba8b9Smrg    if (broken) {
2998d4fba8b9Smrg	TRACE(("Xft line-drawing would not work\n"));
2999d4fba8b9Smrg	setBrokenBoxChars(xw, True);
3000d4fba8b9Smrg    }
3001d4fba8b9Smrg}
3002d4fba8b9Smrg#endif /* OPT_BOX_CHARS */
3003d4fba8b9Smrg
3004d522f475Smrg/*
3005d522f475Smrg * Given the Xft font metrics, determine the actual font size.  This is used
3006d522f475Smrg * for each font to ensure that normal, bold and italic fonts follow the same
3007d522f475Smrg * rule.
3008d522f475Smrg */
3009d522f475Smrgstatic void
3010d4fba8b9SmrgsetRenderFontsize(XtermWidget xw, VTwin *win, XftFont *font, const char *tag)
3011d522f475Smrg{
3012d522f475Smrg    if (font != 0) {
3013d4fba8b9Smrg	TScreen *screen = TScreenOf(xw);
3014d522f475Smrg	int width, height, ascent, descent;
3015d4fba8b9Smrg#ifdef DEBUG_XFT
3016d4fba8b9Smrg	int n;
3017d4fba8b9Smrg	FT_Face face;
3018d4fba8b9Smrg	FT_Size size;
3019d4fba8b9Smrg	FT_Size_Metrics metrics;
3020d4fba8b9Smrg	Boolean scalable;
3021d4fba8b9Smrg	Boolean is_fixed;
3022d4fba8b9Smrg	Boolean debug_xft = False;
3023d4fba8b9Smrg
3024d4fba8b9Smrg	face = XftLockFace(font);
3025d4fba8b9Smrg	size = face->size;
3026d4fba8b9Smrg	metrics = size->metrics;
3027d4fba8b9Smrg	is_fixed = FT_IS_FIXED_WIDTH(face);
3028d4fba8b9Smrg	scalable = FT_IS_SCALABLE(face);
3029d4fba8b9Smrg	trace_xft_line_drawing(screen, font, face);
3030d4fba8b9Smrg	for (n = 32; n < 127; ++n) {
3031d4fba8b9Smrg	    char name[80];
3032d4fba8b9Smrg	    sprintf(name, "letter \"%c\"", n);
3033d4fba8b9Smrg	    trace_xft_glyph(screen, font, face, n, name);
3034d4fba8b9Smrg	}
3035d4fba8b9Smrg	XftUnlockFace(font);
3036d4fba8b9Smrg
3037d4fba8b9Smrg	/* freetype's inconsistent for this sign */
3038d4fba8b9Smrg	metrics.descender = -metrics.descender;
3039d4fba8b9Smrg
3040d4fba8b9Smrg#define TR_XFT	   "Xft metrics: "
3041d4fba8b9Smrg#define D_64(name) ((double)(metrics.name)/64.0)
3042d4fba8b9Smrg#define M_64(a,b)  ((font->a * 64) != metrics.b)
3043d4fba8b9Smrg#define BOTH(a,b)  D_64(b), M_64(a,b) ? "*" : ""
3044d4fba8b9Smrg
3045d4fba8b9Smrg	debug_xft = (M_64(ascent, ascender)
3046d4fba8b9Smrg		     || M_64(descent, descender)
3047d4fba8b9Smrg		     || M_64(height, height)
3048d4fba8b9Smrg		     || M_64(max_advance_width, max_advance));
3049d4fba8b9Smrg
3050d4fba8b9Smrg	TRACE(("Xft font is %sscalable, %sfixed-width\n",
3051d4fba8b9Smrg	       is_fixed ? "" : "not ",
3052d4fba8b9Smrg	       scalable ? "" : "not "));
3053d4fba8b9Smrg
3054d4fba8b9Smrg	if (debug_xft) {
3055d4fba8b9Smrg	    TRACE(("Xft font size %d+%d vs %d by %d\n",
3056d4fba8b9Smrg		   font->ascent,
3057d4fba8b9Smrg		   font->descent,
3058d4fba8b9Smrg		   font->height,
3059d4fba8b9Smrg		   font->max_advance_width));
3060d4fba8b9Smrg	    TRACE((TR_XFT "ascender    %6.2f%s\n", BOTH(ascent, ascender)));
3061d4fba8b9Smrg	    TRACE((TR_XFT "descender   %6.2f%s\n", BOTH(descent, descender)));
3062d4fba8b9Smrg	    TRACE((TR_XFT "height      %6.2f%s\n", BOTH(height, height)));
3063d4fba8b9Smrg	    TRACE((TR_XFT "max_advance %6.2f%s\n", BOTH(max_advance_width, max_advance)));
3064d4fba8b9Smrg	} else {
3065d4fba8b9Smrg	    TRACE((TR_XFT "matches font\n"));
3066d4fba8b9Smrg	}
3067d4fba8b9Smrg#endif
3068d522f475Smrg
3069d522f475Smrg	width = font->max_advance_width;
3070d522f475Smrg	height = font->height;
3071d522f475Smrg	ascent = font->ascent;
3072d522f475Smrg	descent = font->descent;
3073d4fba8b9Smrg	if (screen->force_xft_height && height < ascent + descent) {
3074d4fba8b9Smrg	    TRACE(("...height is less than ascent + descent (%u vs %u)\n",
3075d4fba8b9Smrg		   height, ascent + descent));
3076d4fba8b9Smrg	    if ((ascent + descent) > (height + 1)) {
3077d4fba8b9Smrg		/* this happens less than 10% of the time */
3078d4fba8b9Smrg		--ascent;
3079d4fba8b9Smrg		--descent;
3080d4fba8b9Smrg		TRACE(("...decrement both ascent and descent before retry\n"));
3081d4fba8b9Smrg	    } else if (ascent > descent) {
3082d4fba8b9Smrg		/* this is the usual case */
3083d4fba8b9Smrg		--ascent;
3084d4fba8b9Smrg		TRACE(("...decrement ascent before retry\n"));
3085d4fba8b9Smrg	    } else {
3086d4fba8b9Smrg		/* this could happen, though rare... */
3087d4fba8b9Smrg		--descent;
3088d4fba8b9Smrg		TRACE(("...decrement descent before retry\n"));
3089d4fba8b9Smrg	    }
3090d522f475Smrg	    height = ascent + descent;
3091d4fba8b9Smrg	    font->ascent = ascent;
3092d4fba8b9Smrg	    font->descent = descent;
3093d4fba8b9Smrg	    TRACE(("...updated height %d vs %d (ascent %d, descent %d)\n",
3094d4fba8b9Smrg		   height, ascent + descent, ascent, descent));
3095d522f475Smrg	}
3096d522f475Smrg	if (is_double_width_font_xft(screen->display, font)) {
3097d4fba8b9Smrg	    TRACE(("...reduce width from %d to %d\n", width, width >> 1));
3098d522f475Smrg	    width >>= 1;
3099d522f475Smrg	}
3100d522f475Smrg	if (tag == 0) {
31010bd37d32Smrg	    SetFontWidth(screen, win, width);
31020bd37d32Smrg	    SetFontHeight(screen, win, height);
3103d522f475Smrg	    win->f_ascent = ascent;
3104d522f475Smrg	    win->f_descent = descent;
3105d522f475Smrg	    TRACE(("setRenderFontsize result %dx%d (%d+%d)\n",
3106d522f475Smrg		   width, height, ascent, descent));
3107d522f475Smrg	} else if (win->f_width < width ||
3108d522f475Smrg		   win->f_height < height ||
3109d522f475Smrg		   win->f_ascent < ascent ||
3110d522f475Smrg		   win->f_descent < descent) {
3111d522f475Smrg	    TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n",
3112d522f475Smrg		   tag,
3113d522f475Smrg		   win->f_width, win->f_height, win->f_ascent, win->f_descent,
3114d522f475Smrg		   width, height, ascent, descent));
3115d522f475Smrg
31160bd37d32Smrg	    SetFontWidth(screen, win, width);
31170bd37d32Smrg	    SetFontHeight(screen, win, height);
3118d522f475Smrg	    win->f_ascent = ascent;
3119d522f475Smrg	    win->f_descent = descent;
3120d522f475Smrg	} else {
3121d522f475Smrg	    TRACE(("setRenderFontsize %s unchanged\n", tag));
3122d522f475Smrg	}
3123d4fba8b9Smrg#if OPT_BOX_CHARS
3124d4fba8b9Smrg	if (!screen->broken_box_chars && (tag == 0)) {
3125d4fba8b9Smrg	    linedrawing_gaps(xw, font);
3126d4fba8b9Smrg	}
3127d4fba8b9Smrg#endif
3128d522f475Smrg    }
3129d522f475Smrg}
3130d522f475Smrg#endif
3131d522f475Smrg
313220d2c4d2Smrgstatic void
3133d4fba8b9SmrgcheckFontInfo(int value, const char *tag, int failed)
313420d2c4d2Smrg{
3135d4fba8b9Smrg    if (value == 0 || failed) {
3136d4fba8b9Smrg	if (value == 0) {
3137d4fba8b9Smrg	    xtermWarning("Selected font has no non-zero %s for ISO-8859-1 encoding\n", tag);
3138d4fba8b9Smrg	    exit(1);
3139d4fba8b9Smrg	} else {
3140d4fba8b9Smrg	    xtermWarning("Selected font has no valid %s for ISO-8859-1 encoding\n", tag);
3141d4fba8b9Smrg	}
314220d2c4d2Smrg    }
314320d2c4d2Smrg}
314420d2c4d2Smrg
314520d2c4d2Smrg#if OPT_RENDERFONT
314620d2c4d2Smrgvoid
31479a64e1c5SmrgxtermCloseXft(TScreen *screen, XTermXftFonts *pub)
314820d2c4d2Smrg{
314920d2c4d2Smrg    if (pub->font != 0) {
3150d4fba8b9Smrg	Cardinal n;
3151d4fba8b9Smrg
3152d4fba8b9Smrg	closeCachedXft(screen, pub->font);
315320d2c4d2Smrg	pub->font = 0;
3154d4fba8b9Smrg
3155d4fba8b9Smrg	if (pub->pattern) {
3156d4fba8b9Smrg	    XftPatternDestroy(pub->pattern);
3157d4fba8b9Smrg	    pub->pattern = 0;
3158d4fba8b9Smrg	}
3159d4fba8b9Smrg	if (pub->fontset) {
3160d4fba8b9Smrg	    XftFontSetDestroy(pub->fontset);
3161d4fba8b9Smrg	    pub->fontset = 0;
3162d4fba8b9Smrg	}
3163d4fba8b9Smrg
3164d4fba8b9Smrg	for (n = 0; n < pub->limit; ++n) {
3165d4fba8b9Smrg	    if (pub->cache[n].font) {
3166d4fba8b9Smrg		closeCachedXft(screen, pub->cache[n].font);
3167d4fba8b9Smrg		pub->cache[n].font = 0;
3168d4fba8b9Smrg	    }
3169d4fba8b9Smrg	}
3170d4fba8b9Smrg	free(pub->cache);
3171d4fba8b9Smrg	pub->cache = NULL;
317220d2c4d2Smrg    }
317320d2c4d2Smrg}
317420d2c4d2Smrg
317520d2c4d2Smrg/*
3176d4fba8b9Smrg * Get the faceName/faceNameDoublesize resource setting.
317720d2c4d2Smrg */
3178492d43a5SmrgString
3179d4fba8b9SmrggetFaceName(XtermWidget xw, Bool wideName)
318020d2c4d2Smrg{
318120d2c4d2Smrg#if OPT_RENDERWIDE
3182492d43a5Smrg    String result = (wideName
3183dfb07bc7Smrg		     ? FirstItemOf(xw->work.fonts.xft.list_w)
3184dfb07bc7Smrg		     : CurrentXftFont(xw));
318520d2c4d2Smrg#else
3186dfb07bc7Smrg    String result = CurrentXftFont(xw);
3187d4fba8b9Smrg    (void) wideName;
318820d2c4d2Smrg#endif
318920d2c4d2Smrg    return x_nonempty(result);
319020d2c4d2Smrg}
319120d2c4d2Smrg
319220d2c4d2Smrg/*
319320d2c4d2Smrg * If we change the faceName, we'll have to re-acquire all of the fonts that
319420d2c4d2Smrg * are derived from it.
319520d2c4d2Smrg */
319620d2c4d2Smrgvoid
319720d2c4d2SmrgsetFaceName(XtermWidget xw, const char *value)
319820d2c4d2Smrg{
319920d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
3200dfb07bc7Smrg    Boolean changed = (Boolean) ((CurrentXftFont(xw) == 0)
3201dfb07bc7Smrg				 || strcmp(CurrentXftFont(xw), value));
320220d2c4d2Smrg
32030bd37d32Smrg    if (changed) {
3204037a25ddSmrg	int n;
3205037a25ddSmrg
3206dfb07bc7Smrg	CurrentXftFont(xw) = x_strdup(value);
32070bd37d32Smrg	for (n = 0; n < NMENUFONTS; ++n) {
3208dfb07bc7Smrg	    int e;
32090bd37d32Smrg	    xw->misc.face_size[n] = -1.0;
3210dfb07bc7Smrg	    for (e = 0; e < fMAX; ++e) {
3211dfb07bc7Smrg		xtermCloseXft(screen, getMyXftFont(xw, e, n));
3212dfb07bc7Smrg	    }
32130bd37d32Smrg	}
321420d2c4d2Smrg    }
321520d2c4d2Smrg}
321620d2c4d2Smrg#endif
321720d2c4d2Smrg
3218d522f475Smrg/*
3219d522f475Smrg * Compute useful values for the font/window sizes
3220d522f475Smrg */
3221d522f475Smrgvoid
3222d522f475SmrgxtermComputeFontInfo(XtermWidget xw,
32239a64e1c5Smrg		     VTwin *win,
32249a64e1c5Smrg		     XFontStruct *font,
3225d522f475Smrg		     int sbwidth)
3226d522f475Smrg{
3227956cc18dSsnj    TScreen *screen = TScreenOf(xw);
3228d522f475Smrg
3229d522f475Smrg    int i, j, width, height;
3230492d43a5Smrg#if OPT_RENDERFONT
3231492d43a5Smrg    int fontnum = screen->menu_font_number;
3232492d43a5Smrg#endif
3233d4fba8b9Smrg    int failed = 0;
3234d522f475Smrg
3235d522f475Smrg#if OPT_RENDERFONT
3236d522f475Smrg    /*
3237d522f475Smrg     * xterm contains a lot of references to fonts, assuming they are fixed
3238d522f475Smrg     * size.  This chunk of code overrides the actual font-selection (see
3239d522f475Smrg     * drawXtermText()), if the user has selected render-font.  All of the
3240d522f475Smrg     * font-loading for fixed-fonts still goes on whether or not this chunk
3241d522f475Smrg     * overrides it.
3242d522f475Smrg     */
3243492d43a5Smrg    if (UsingRenderFont(xw) && fontnum >= 0) {
3244492d43a5Smrg	String face_name = getFaceName(xw, False);
3245d4fba8b9Smrg	XTermXftFonts norm = screen->renderFontNorm[fontnum];
3246d4fba8b9Smrg	XTermXftFonts bold = screen->renderFontBold[fontnum];
3247d4fba8b9Smrg	XTermXftFonts ital = screen->renderFontItal[fontnum];
3248d4fba8b9Smrg	XTermXftFonts btal = screen->renderFontBtal[fontnum];
3249d522f475Smrg#if OPT_RENDERWIDE
3250d4fba8b9Smrg	XTermXftFonts wnorm = screen->renderWideNorm[fontnum];
3251d4fba8b9Smrg	XTermXftFonts wbold = screen->renderWideBold[fontnum];
3252d4fba8b9Smrg	XTermXftFonts wital = screen->renderWideItal[fontnum];
3253d4fba8b9Smrg	XTermXftFonts wbtal = screen->renderWideBtal[fontnum];
3254d522f475Smrg#endif
3255d522f475Smrg
3256d4fba8b9Smrg	if (norm.font == 0 && !IsEmpty(face_name)) {
3257d522f475Smrg	    XftPattern *pat;
32580bd37d32Smrg	    double face_size;
3259d522f475Smrg
32600bd37d32Smrg	    TRACE(("xtermComputeFontInfo font %d: norm(face %s, size %.1f)\n",
3261492d43a5Smrg		   fontnum, face_name,
3262d522f475Smrg		   xw->misc.face_size[fontnum]));
3263d522f475Smrg
3264d4fba8b9Smrg	    TRACE(("Using Xft %d\n", XftVersion));
3265d4fba8b9Smrg	    TRACE(("Using FontConfig %d\n", FC_VERSION));
3266d4fba8b9Smrg
32670bd37d32Smrg	    fillInFaceSize(xw, fontnum);
3268d4fba8b9Smrg	    face_size = (double) xw->misc.face_size[fontnum];
3269d522f475Smrg
3270d522f475Smrg	    /*
3271d522f475Smrg	     * By observation (there is no documentation), XftPatternBuild is
3272d522f475Smrg	     * cumulative.  Build the bold- and italic-patterns on top of the
3273d522f475Smrg	     * normal pattern.
3274d522f475Smrg	     */
3275d4fba8b9Smrg#ifdef FC_COLOR
3276d522f475Smrg#define NormXftPattern \
3277d4fba8b9Smrg	    XFT_FAMILY,     XftTypeString, "mono", \
3278d4fba8b9Smrg	    FC_COLOR,       XftTypeBool,   FcFalse, \
3279d4fba8b9Smrg	    FC_OUTLINE,     XftTypeBool,   FcTrue, \
3280d4fba8b9Smrg	    XFT_SIZE,       XftTypeDouble, face_size
3281d4fba8b9Smrg#else
3282d4fba8b9Smrg#define NormXftPattern \
3283d4fba8b9Smrg	    XFT_FAMILY,     XftTypeString, "mono", \
3284d4fba8b9Smrg	    XFT_SIZE,       XftTypeDouble, face_size
3285d4fba8b9Smrg#endif
3286d522f475Smrg
3287d522f475Smrg#define BoldXftPattern(norm) \
3288d4fba8b9Smrg	    XFT_WEIGHT,     XftTypeInteger, XFT_WEIGHT_BOLD, \
3289d4fba8b9Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm.font->max_advance_width
3290d522f475Smrg
3291d522f475Smrg#define ItalXftPattern(norm) \
3292d4fba8b9Smrg	    XFT_SLANT,      XftTypeInteger, XFT_SLANT_ITALIC, \
3293d4fba8b9Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm.font->max_advance_width
3294d4fba8b9Smrg
3295d4fba8b9Smrg#define BtalXftPattern(norm) \
3296d4fba8b9Smrg	    XFT_WEIGHT,     XftTypeInteger, XFT_WEIGHT_BOLD, \
3297d4fba8b9Smrg	    XFT_SLANT,      XftTypeInteger, XFT_SLANT_ITALIC, \
3298d4fba8b9Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm.font->max_advance_width
3299d522f475Smrg
33009a64e1c5Smrg#if OPT_WIDE_ATTRS
33019a64e1c5Smrg#define HAVE_ITALICS 1
33029a64e1c5Smrg#define FIND_ITALICS ((pat = XftNameParse(face_name)) != 0)
33039a64e1c5Smrg#elif OPT_ISO_COLORS
33049a64e1c5Smrg#define HAVE_ITALICS 1
33059a64e1c5Smrg#define FIND_ITALICS (screen->italicULMode && (pat = XftNameParse(face_name)) != 0)
33069a64e1c5Smrg#else
33079a64e1c5Smrg#define HAVE_ITALICS 0
33089a64e1c5Smrg#endif
33099a64e1c5Smrg
3310d4fba8b9Smrg#if OPT_DEC_CHRSET
3311d4fba8b9Smrg	    freeall_DoubleFT(xw);
3312d4fba8b9Smrg#endif
331320d2c4d2Smrg	    if ((pat = XftNameParse(face_name)) != 0) {
3314d4fba8b9Smrg#define OPEN_XFT(name, tag) name.font = xtermOpenXft(xw, face_name, name.pattern, tag)
3315d4fba8b9Smrg		norm.pattern = XftPatternDuplicate(pat);
3316d4fba8b9Smrg		XftPatternBuild(norm.pattern,
3317d522f475Smrg				NormXftPattern,
3318d522f475Smrg				(void *) 0);
3319d4fba8b9Smrg		OPEN_XFT(norm, "normal");
3320d522f475Smrg
3321d4fba8b9Smrg		if (norm.font != 0) {
3322d4fba8b9Smrg		    bold.pattern = XftPatternDuplicate(pat);
3323d4fba8b9Smrg		    XftPatternBuild(bold.pattern,
3324d4fba8b9Smrg				    NormXftPattern,
3325d522f475Smrg				    BoldXftPattern(norm),
3326d522f475Smrg				    (void *) 0);
3327d4fba8b9Smrg		    OPEN_XFT(bold, "bold");
3328d522f475Smrg
33299a64e1c5Smrg#if HAVE_ITALICS
33309a64e1c5Smrg		    if (FIND_ITALICS) {
3331d4fba8b9Smrg			ital.pattern = XftPatternDuplicate(pat);
3332d4fba8b9Smrg			XftPatternBuild(ital.pattern,
3333d522f475Smrg					NormXftPattern,
3334d522f475Smrg					ItalXftPattern(norm),
3335d522f475Smrg					(void *) 0);
3336d4fba8b9Smrg			OPEN_XFT(ital, "italic");
3337d4fba8b9Smrg			btal.pattern = XftPatternDuplicate(pat);
3338d4fba8b9Smrg			XftPatternBuild(btal.pattern,
3339d4fba8b9Smrg					NormXftPattern,
3340d4fba8b9Smrg					BtalXftPattern(norm),
3341d4fba8b9Smrg					(void *) 0);
3342d4fba8b9Smrg			OPEN_XFT(btal, "bold-italic");
3343d522f475Smrg		    }
33449a64e1c5Smrg#endif
3345d522f475Smrg
3346d522f475Smrg		    /*
3347d522f475Smrg		     * FIXME:  just assume that the corresponding font has no
3348d522f475Smrg		     * graphics characters.
3349d522f475Smrg		     */
3350d522f475Smrg		    if (screen->fnt_boxes) {
3351d4fba8b9Smrg			screen->fnt_boxes = 0;
3352d522f475Smrg			TRACE(("Xft opened - will %suse internal line-drawing characters\n",
3353d522f475Smrg			       screen->fnt_boxes ? "not " : ""));
3354d522f475Smrg		    }
3355d522f475Smrg		}
3356d522f475Smrg
3357d4fba8b9Smrg		CACHE_XFT(screen->renderFontNorm, norm);
3358d4fba8b9Smrg
3359d4fba8b9Smrg		CACHE_XFT(screen->renderFontBold, bold);
3360d4fba8b9Smrg		if (norm.font != 0 && !bold.font) {
3361d4fba8b9Smrg		    noUsableXft(xw, "bold");
3362d4fba8b9Smrg		    XftPatternDestroy(bold.pattern);
3363d4fba8b9Smrg		    bold.pattern = XftPatternDuplicate(pat);
3364d4fba8b9Smrg		    XftPatternBuild(bold.pattern,
3365d4fba8b9Smrg				    NormXftPattern,
3366d4fba8b9Smrg				    (void *) 0);
3367d4fba8b9Smrg		    OPEN_XFT(bold, "bold");
3368d4fba8b9Smrg		    failed = 0;
3369d4fba8b9Smrg		    CACHE_XFT(screen->renderFontBold, bold);
3370d4fba8b9Smrg		}
3371d4fba8b9Smrg#if HAVE_ITALICS
3372d4fba8b9Smrg		CACHE_XFT(screen->renderFontItal, ital);
3373d4fba8b9Smrg		if (norm.font != 0 && !ital.font) {
3374d4fba8b9Smrg		    noUsableXft(xw, "italic");
3375d4fba8b9Smrg		    XftPatternDestroy(ital.pattern);
3376d4fba8b9Smrg		    ital.pattern = XftPatternDuplicate(pat);
3377d4fba8b9Smrg		    XftPatternBuild(ital.pattern,
3378d4fba8b9Smrg				    NormXftPattern,
3379d4fba8b9Smrg				    (void *) 0);
3380d4fba8b9Smrg		    OPEN_XFT(ital, "italics");
3381d4fba8b9Smrg		    failed = 0;
3382d4fba8b9Smrg		    CACHE_XFT(screen->renderFontItal, ital);
3383d4fba8b9Smrg		}
3384d4fba8b9Smrg		CACHE_XFT(screen->renderFontBtal, btal);
3385d4fba8b9Smrg		if (norm.font != 0 && !btal.font) {
3386d4fba8b9Smrg		    noUsableXft(xw, "bold italic");
3387d4fba8b9Smrg		    XftPatternDestroy(btal.pattern);
3388d4fba8b9Smrg		    btal.pattern = XftPatternDuplicate(pat);
3389d4fba8b9Smrg		    XftPatternBuild(btal.pattern,
3390d4fba8b9Smrg				    NormXftPattern,
3391d4fba8b9Smrg				    (void *) 0);
3392d4fba8b9Smrg		    OPEN_XFT(btal, "bold-italics");
3393d4fba8b9Smrg		    failed = 0;
3394d4fba8b9Smrg		    CACHE_XFT(screen->renderFontBtal, btal);
3395d4fba8b9Smrg		}
3396d4fba8b9Smrg#endif
3397d522f475Smrg		XftPatternDestroy(pat);
3398d4fba8b9Smrg	    } else {
3399d4fba8b9Smrg		failed = 1;
3400d522f475Smrg	    }
3401d4fba8b9Smrg#undef OPEN_XFT
3402d522f475Smrg
3403d522f475Smrg	    /*
3404d4fba8b9Smrg	     * See xtermXftDrawString().  A separate double-width font is nice
3405d4fba8b9Smrg	     * to have, but not essential.
3406d522f475Smrg	     */
3407d522f475Smrg#if OPT_RENDERWIDE
3408d4fba8b9Smrg	    if (norm.font != 0 && screen->wide_chars) {
3409d4fba8b9Smrg		int char_width = norm.font->max_advance_width * 2;
3410dfb07bc7Smrg		double aspect = ((FirstItemOf(xw->work.fonts.xft.list_w)
3411956cc18dSsnj				  || screen->renderFontNorm[fontnum].map.mixed)
3412956cc18dSsnj				 ? 1.0
3413956cc18dSsnj				 : 2.0);
3414d522f475Smrg
341520d2c4d2Smrg		face_name = getFaceName(xw, True);
3416d522f475Smrg		TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n",
341720d2c4d2Smrg		       NonNull(face_name),
3418d522f475Smrg		       char_width));
3419d522f475Smrg
3420d522f475Smrg#define WideXftPattern \
3421d4fba8b9Smrg		XFT_FAMILY,     XftTypeString,   "mono", \
3422d4fba8b9Smrg		XFT_SIZE,       XftTypeDouble,   face_size, \
3423d4fba8b9Smrg		XFT_SPACING,    XftTypeInteger,  XFT_MONO, \
3424d4fba8b9Smrg		XFT_CHAR_WIDTH, XftTypeInteger,  char_width, \
3425d4fba8b9Smrg		FC_ASPECT,      XftTypeDouble,   aspect
3426d4fba8b9Smrg
3427d4fba8b9Smrg		if (!IsEmpty(face_name) && (pat = XftNameParse(face_name))
3428d4fba8b9Smrg		    != 0) {
3429d4fba8b9Smrg#define OPEN_XFT(name, tag) name.font = xtermOpenXft(xw, face_name, name.pattern, tag)
3430d4fba8b9Smrg		    wnorm.pattern = XftPatternDuplicate(pat);
3431d4fba8b9Smrg		    XftPatternBuild(wnorm.pattern,
3432d522f475Smrg				    WideXftPattern,
3433d522f475Smrg				    (void *) 0);
3434d4fba8b9Smrg		    OPEN_XFT(wnorm, "wide");
3435d522f475Smrg
3436d4fba8b9Smrg		    if (wnorm.font != 0) {
3437d4fba8b9Smrg			wbold.pattern = XftPatternDuplicate(pat);
3438d4fba8b9Smrg			XftPatternBuild(wbold.pattern,
3439d522f475Smrg					WideXftPattern,
3440d522f475Smrg					BoldXftPattern(wnorm),
3441d522f475Smrg					(void *) 0);
3442d4fba8b9Smrg			OPEN_XFT(wbold, "wide-bold");
3443d522f475Smrg
34449a64e1c5Smrg#if HAVE_ITALICS
34459a64e1c5Smrg			if (FIND_ITALICS) {
3446d4fba8b9Smrg			    wital.pattern = XftPatternDuplicate(pat);
3447d4fba8b9Smrg			    XftPatternBuild(wital.pattern,
3448d522f475Smrg					    WideXftPattern,
3449d522f475Smrg					    ItalXftPattern(wnorm),
3450d522f475Smrg					    (void *) 0);
3451d4fba8b9Smrg			    OPEN_XFT(wital, "wide-italic");
3452d4fba8b9Smrg			}
3453d4fba8b9Smrg			CACHE_XFT(screen->renderWideBtal, wbtal);
3454d4fba8b9Smrg			if (!wbtal.font) {
3455d4fba8b9Smrg			    noUsableXft(xw, "wide bold");
3456d4fba8b9Smrg			    XftPatternDestroy(wbtal.pattern);
3457d4fba8b9Smrg			    wbtal.pattern = XftPatternDuplicate(pat);
3458d4fba8b9Smrg			    XftPatternBuild(wbtal.pattern,
3459d4fba8b9Smrg					    WideXftPattern,
3460d4fba8b9Smrg					    (void *) 0);
3461d4fba8b9Smrg			    OPEN_XFT(wbtal, "wide-bold-italics");
3462d4fba8b9Smrg			    failed = 0;
3463d4fba8b9Smrg			    CACHE_XFT(screen->renderWideBtal, wbtal);
3464d522f475Smrg			}
3465d522f475Smrg#endif
3466d522f475Smrg		    }
3467d4fba8b9Smrg
3468d4fba8b9Smrg		    CACHE_XFT(screen->renderWideNorm, wnorm);
3469d4fba8b9Smrg
3470d4fba8b9Smrg		    CACHE_XFT(screen->renderWideBold, wbold);
3471d4fba8b9Smrg		    if (wnorm.font != 0 && !wbold.font) {
3472d4fba8b9Smrg			noUsableXft(xw, "wide-bold");
3473d4fba8b9Smrg			XftPatternDestroy(wbold.pattern);
3474d4fba8b9Smrg			wbold.pattern = XftPatternDuplicate(pat);
3475d4fba8b9Smrg			XftPatternBuild(bold.pattern,
3476d4fba8b9Smrg					WideXftPattern,
3477d4fba8b9Smrg					(void *) 0);
3478d4fba8b9Smrg			OPEN_XFT(wbold, "wide-bold");
3479d4fba8b9Smrg			failed = 0;
3480d4fba8b9Smrg			CACHE_XFT(screen->renderWideBold, bold);
3481d4fba8b9Smrg		    }
3482d4fba8b9Smrg
3483d4fba8b9Smrg		    CACHE_XFT(screen->renderWideItal, wital);
3484d4fba8b9Smrg		    if (wnorm.font != 0 && !wital.font) {
3485d4fba8b9Smrg			noUsableXft(xw, "wide-italic");
3486d4fba8b9Smrg			XftPatternDestroy(wital.pattern);
3487d4fba8b9Smrg			wital.pattern = XftPatternDuplicate(pat);
3488d4fba8b9Smrg			XftPatternBuild(wital.pattern,
3489d4fba8b9Smrg					WideXftPattern,
3490d4fba8b9Smrg					(void *) 0);
3491d4fba8b9Smrg			OPEN_XFT(wital, "wide-italic");
3492d4fba8b9Smrg			failed = 0;
3493d4fba8b9Smrg			CACHE_XFT(screen->renderWideItal, wital);
3494d4fba8b9Smrg		    }
3495d4fba8b9Smrg
3496d522f475Smrg		    XftPatternDestroy(pat);
3497d522f475Smrg		}
3498d4fba8b9Smrg#undef OPEN_XFT
3499d522f475Smrg	    }
3500d522f475Smrg#endif /* OPT_RENDERWIDE */
3501d522f475Smrg	}
3502d4fba8b9Smrg	if (norm.font == 0) {
35032eaa94a1Schristos	    TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum));
35040bd37d32Smrg	    xw->work.render_font = False;
3505d522f475Smrg	    update_font_renderfont();
3506d522f475Smrg	    /* now we will fall through into the bitmap fonts */
3507d522f475Smrg	} else {
3508d4fba8b9Smrg	    setBrokenBoxChars(xw, False);
3509d4fba8b9Smrg	    setRenderFontsize(xw, win, norm.font, NULL);
3510d4fba8b9Smrg	    setRenderFontsize(xw, win, bold.font, "bold");
3511d4fba8b9Smrg	    setRenderFontsize(xw, win, ital.font, "ital");
3512d4fba8b9Smrg	    setRenderFontsize(xw, win, btal.font, "btal");
351320d2c4d2Smrg#if OPT_BOX_CHARS
351420d2c4d2Smrg	    setupPackedFonts(xw);
351520d2c4d2Smrg
351620d2c4d2Smrg	    if (screen->force_packed) {
351720d2c4d2Smrg		XTermXftFonts *use = &(screen->renderFontNorm[fontnum]);
35180bd37d32Smrg		SetFontHeight(screen, win, use->font->ascent + use->font->descent);
35190bd37d32Smrg		SetFontWidth(screen, win, use->map.min_width);
352020d2c4d2Smrg		TRACE(("...packed TrueType font %dx%d vs %d\n",
352120d2c4d2Smrg		       win->f_height,
352220d2c4d2Smrg		       win->f_width,
352320d2c4d2Smrg		       use->map.max_width));
352420d2c4d2Smrg	    }
352520d2c4d2Smrg#endif
352620d2c4d2Smrg	    DUMP_XFT(xw, &(screen->renderFontNorm[fontnum]));
3527d522f475Smrg	}
3528d522f475Smrg    }
3529d522f475Smrg    /*
3530d522f475Smrg     * Are we handling a bitmap font?
3531d522f475Smrg     */
3532492d43a5Smrg    else
3533d522f475Smrg#endif /* OPT_RENDERFONT */
3534d522f475Smrg    {
353520d2c4d2Smrg	if (is_double_width_font(font) && !(screen->fnt_prop)) {
35360bd37d32Smrg	    SetFontWidth(screen, win, font->min_bounds.width);
3537d522f475Smrg	} else {
35380bd37d32Smrg	    SetFontWidth(screen, win, font->max_bounds.width);
3539d522f475Smrg	}
35400bd37d32Smrg	SetFontHeight(screen, win, font->ascent + font->descent);
3541d522f475Smrg	win->f_ascent = font->ascent;
3542d522f475Smrg	win->f_descent = font->descent;
3543d522f475Smrg    }
3544d522f475Smrg    i = 2 * screen->border + sbwidth;
3545d522f475Smrg    j = 2 * screen->border;
3546d522f475Smrg    width = MaxCols(screen) * win->f_width + i;
3547d522f475Smrg    height = MaxRows(screen) * win->f_height + j;
3548956cc18dSsnj    win->fullwidth = (Dimension) width;
3549956cc18dSsnj    win->fullheight = (Dimension) height;
3550d522f475Smrg    win->width = width - i;
3551d522f475Smrg    win->height = height - j;
3552d522f475Smrg
3553d522f475Smrg    TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n",
3554d522f475Smrg	   win->height,
3555d522f475Smrg	   win->width,
3556d522f475Smrg	   win->fullheight,
3557d522f475Smrg	   win->fullwidth,
3558d522f475Smrg	   win->f_height,
3559d522f475Smrg	   win->f_width,
3560d522f475Smrg	   win->f_ascent,
3561d522f475Smrg	   win->f_descent));
356220d2c4d2Smrg
3563d4fba8b9Smrg    checkFontInfo(win->f_height, "height", failed);
3564d4fba8b9Smrg    checkFontInfo(win->f_width, "width", failed);
3565d522f475Smrg}
3566d522f475Smrg
3567d522f475Smrg/* save this information as a side-effect for double-sized characters */
3568d4fba8b9Smrgstatic void
35699a64e1c5SmrgxtermSaveFontInfo(TScreen *screen, XFontStruct *font)
3570d522f475Smrg{
3571956cc18dSsnj    screen->fnt_wide = (Dimension) (font->max_bounds.width);
3572956cc18dSsnj    screen->fnt_high = (Dimension) (font->ascent + font->descent);
3573d522f475Smrg    TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide));
3574d522f475Smrg}
3575d522f475Smrg
3576d522f475Smrg/*
3577d522f475Smrg * After loading a new font, update the structures that use its size.
3578d522f475Smrg */
3579d522f475Smrgvoid
3580d522f475SmrgxtermUpdateFontInfo(XtermWidget xw, Bool doresize)
3581d522f475Smrg{
3582956cc18dSsnj    TScreen *screen = TScreenOf(xw);
3583d522f475Smrg
3584d522f475Smrg    int scrollbar_width;
3585d522f475Smrg    VTwin *win = &(screen->fullVwin);
3586d522f475Smrg
3587d4fba8b9Smrg#if USE_DOUBLE_BUFFER
3588d4fba8b9Smrg    discardRenderDraw(TScreenOf(xw));
3589d4fba8b9Smrg#endif /* USE_DOUBLE_BUFFER */
3590d4fba8b9Smrg
3591d522f475Smrg    scrollbar_width = (xw->misc.scrollbar
3592d522f475Smrg		       ? (screen->scrollWidget->core.width +
3593d522f475Smrg			  BorderWidth(screen->scrollWidget))
3594d522f475Smrg		       : 0);
3595d4fba8b9Smrg    xtermComputeFontInfo(xw, win, GetNormalFont(screen, fNorm)->fs, scrollbar_width);
3596d4fba8b9Smrg    xtermSaveFontInfo(screen, GetNormalFont(screen, fNorm)->fs);
3597d522f475Smrg
3598d522f475Smrg    if (doresize) {
3599d522f475Smrg	if (VWindow(screen)) {
3600d522f475Smrg	    xtermClear(xw);
3601d522f475Smrg	}
3602d4fba8b9Smrg	TRACE(("xtermUpdateFontInfo " TRACE_L "\n"));
3603d522f475Smrg	DoResizeScreen(xw);	/* set to the new natural size */
3604d522f475Smrg	ResizeScrollBar(xw);
3605d522f475Smrg	Redraw();
3606d4fba8b9Smrg	TRACE((TRACE_R " xtermUpdateFontInfo\n"));
3607d522f475Smrg#ifdef SCROLLBAR_RIGHT
3608d522f475Smrg	updateRightScrollbar(xw);
3609d522f475Smrg#endif
3610d522f475Smrg    }
3611d522f475Smrg    xtermSetCursorBox(screen);
3612d522f475Smrg}
3613d522f475Smrg
3614fa3f02f3Smrg#if OPT_BOX_CHARS || OPT_REPORT_FONTS
3615d522f475Smrg
3616d522f475Smrg/*
3617d522f475Smrg * Returns true if the given character is missing from the specified font.
3618d522f475Smrg */
3619d522f475SmrgBool
3620956cc18dSsnjxtermMissingChar(unsigned ch, XTermFonts * font)
3621d522f475Smrg{
3622956cc18dSsnj    Bool result = False;
3623956cc18dSsnj    XFontStruct *fs = font->fs;
3624fa3f02f3Smrg    XCharStruct *pc = 0;
3625d522f475Smrg
3626d4fba8b9Smrg    if (fs == NULL) {
3627d4fba8b9Smrg	result = True;
3628d4fba8b9Smrg    } else if (fs->max_byte1 == 0) {
3629d522f475Smrg#if OPT_WIDE_CHARS
3630fa3f02f3Smrg	if (ch < 256)
3631956cc18dSsnj#endif
3632fa3f02f3Smrg	{
3633fa3f02f3Smrg	    CI_GET_CHAR_INFO_1D(fs, E2A(ch), pc);
3634fa3f02f3Smrg	}
3635956cc18dSsnj    }
3636d522f475Smrg#if OPT_WIDE_CHARS
3637956cc18dSsnj    else {
3638fa3f02f3Smrg	unsigned row = (ch >> 8);
3639fa3f02f3Smrg	unsigned col = (ch & 0xff);
3640fa3f02f3Smrg	CI_GET_CHAR_INFO_2D(fs, row, col, pc);
3641956cc18dSsnj    }
3642d522f475Smrg#endif
3643d522f475Smrg
3644fa3f02f3Smrg    if (pc == 0 || CI_NONEXISTCHAR(pc)) {
3645c48a5815Smrg	TRACE2(("xtermMissingChar %#04x (!exists)\n", ch));
3646956cc18dSsnj	result = True;
3647d522f475Smrg    }
3648fa3f02f3Smrg    if (ch < KNOWN_MISSING) {
3649956cc18dSsnj	font->known_missing[ch] = (Char) (result ? 2 : 1);
3650d522f475Smrg    }
3651956cc18dSsnj    return result;
3652d522f475Smrg}
3653fa3f02f3Smrg#endif
3654d522f475Smrg
3655fa3f02f3Smrg#if OPT_BOX_CHARS
3656d522f475Smrg/*
3657d522f475Smrg * The grid is arbitrary, enough resolution that nothing's lost in
3658d522f475Smrg * initialization.
3659d522f475Smrg */
3660d522f475Smrg#define BOX_HIGH 60
3661d522f475Smrg#define BOX_WIDE 60
3662d522f475Smrg
3663d522f475Smrg#define MID_HIGH (BOX_HIGH/2)
3664d522f475Smrg#define MID_WIDE (BOX_WIDE/2)
3665d522f475Smrg
3666d522f475Smrg#define CHR_WIDE ((9*BOX_WIDE)/10)
3667d522f475Smrg#define CHR_HIGH ((9*BOX_HIGH)/10)
3668d522f475Smrg
3669d522f475Smrg/*
3670d522f475Smrg * ...since we'll scale the values anyway.
3671d522f475Smrg */
3672d4fba8b9Smrg#define Scale_XY(n,d,f) ((int)(n) * ((int)(f))) / (d)
3673d4fba8b9Smrg#define SCALED_X(n) Scale_XY(n, BOX_WIDE, font_width)
3674d4fba8b9Smrg#define SCALED_Y(n) Scale_XY(n, BOX_HIGH, font_height)
3675e39b573cSmrg#define SCALE_X(n) n = SCALED_X(n)
3676e39b573cSmrg#define SCALE_Y(n) n = SCALED_Y(n)
3677d522f475Smrg
3678d522f475Smrg#define SEG(x0,y0,x1,y1) x0,y0, x1,y1
3679d522f475Smrg
3680d522f475Smrg/*
3681d522f475Smrg * Draw the given graphic character, if it is simple enough (i.e., a
3682d522f475Smrg * line-drawing character).
3683d522f475Smrg */
3684d522f475Smrgvoid
3685d4fba8b9SmrgxtermDrawBoxChar(XTermDraw * params,
3686d522f475Smrg		 unsigned ch,
3687d522f475Smrg		 GC gc,
3688d522f475Smrg		 int x,
3689d522f475Smrg		 int y,
3690d4fba8b9Smrg		 int cells,
3691d4fba8b9Smrg		 Bool xftords)
3692d522f475Smrg{
3693d4fba8b9Smrg    TScreen *screen = TScreenOf(params->xw);
3694d522f475Smrg    /* *INDENT-OFF* */
3695d522f475Smrg    static const short glyph_ht[] = {
3696d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,5*MID_HIGH/6),	/* H */
3697d522f475Smrg	SEG(6*BOX_WIDE/10,  0,		6*BOX_WIDE/10,5*MID_HIGH/6),
3698d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12),
3699d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
3700d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
3701d522f475Smrg	-1
3702d522f475Smrg    }, glyph_ff[] = {
3703d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		6*BOX_WIDE/10,	0),		/* F */
3704d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12),
3705d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		0*BOX_WIDE/3, 5*MID_HIGH/6),
3706d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
3707d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
3708d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
3709d522f475Smrg	-1
3710d522f475Smrg    }, glyph_lf[] = {
3711d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,9*MID_HIGH/12),	/* L */
3712d522f475Smrg	SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12),
3713d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
3714d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
3715d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
3716d522f475Smrg	-1
3717d522f475Smrg    }, glyph_nl[] = {
3718d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10,	0),		/* N */
3719d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		5*BOX_WIDE/6, 5*MID_HIGH/6),
3720d522f475Smrg	SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
3721d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),	/* L */
3722d522f475Smrg	SEG(1*BOX_WIDE/3,   CHR_HIGH,	  CHR_WIDE,	CHR_HIGH),
3723d522f475Smrg	-1
3724d522f475Smrg    }, glyph_vt[] = {
3725d522f475Smrg	SEG(1*BOX_WIDE/10,   0,		5*BOX_WIDE/12,5*MID_HIGH/6),	/* V */
3726d522f475Smrg	SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
3727d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
3728d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
3729d522f475Smrg	-1
3730d522f475Smrg    }, plus_or_minus[] =
3731d522f475Smrg    {
3732d522f475Smrg	SEG(  0,	  5*BOX_HIGH/6,	  CHR_WIDE,   5*BOX_HIGH/6),
3733d522f475Smrg	SEG(  MID_WIDE,	  2*BOX_HIGH/6,	  MID_WIDE,   4*BOX_HIGH/6),
3734d522f475Smrg	SEG(  0,	  3*BOX_HIGH/6,	  CHR_WIDE,   3*BOX_HIGH/6),
3735d522f475Smrg	-1
3736d522f475Smrg    }, lower_right_corner[] =
3737d522f475Smrg    {
3738d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
3739d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	0),
3740d522f475Smrg	-1
3741d522f475Smrg    }, upper_right_corner[] =
3742d522f475Smrg    {
3743d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
3744d522f475Smrg	SEG( MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
3745d522f475Smrg	-1
3746d522f475Smrg    }, upper_left_corner[] =
3747d522f475Smrg    {
3748d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
3749d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
3750d522f475Smrg	-1
3751d522f475Smrg    }, lower_left_corner[] =
3752d522f475Smrg    {
3753d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
3754d522f475Smrg	SEG(  MID_WIDE,	    MID_WIDE,	  BOX_WIDE,	MID_HIGH),
3755d522f475Smrg	-1
3756d522f475Smrg    }, cross[] =
3757d522f475Smrg    {
3758d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
3759d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
3760d522f475Smrg	-1
3761d522f475Smrg    }, scan_line_1[] =
3762d522f475Smrg    {
3763d522f475Smrg	SEG(  0,	    0,		  BOX_WIDE,	0),
3764d522f475Smrg	-1
3765d522f475Smrg    }, scan_line_3[] =
3766d522f475Smrg    {
3767d522f475Smrg	SEG(  0,	    BOX_HIGH/4,	  BOX_WIDE,	BOX_HIGH/4),
3768d522f475Smrg	-1
3769d522f475Smrg    }, scan_line_7[] =
3770d522f475Smrg    {
3771d522f475Smrg	SEG( 0,		    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
3772d522f475Smrg	-1
3773d522f475Smrg    }, scan_line_9[] =
3774d522f475Smrg    {
3775d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  BOX_WIDE,   3*BOX_HIGH/4),
3776d522f475Smrg	-1
3777d522f475Smrg    }, horizontal_line[] =
3778d522f475Smrg    {
3779d522f475Smrg	SEG(  0,	    BOX_HIGH,	  BOX_WIDE,	BOX_HIGH),
3780d522f475Smrg	-1
3781d522f475Smrg    }, left_tee[] =
3782d522f475Smrg    {
3783d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
3784d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
3785d522f475Smrg	-1
3786d522f475Smrg    }, right_tee[] =
3787d522f475Smrg    {
3788d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
3789d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  0,		MID_HIGH),
3790d522f475Smrg	-1
3791d522f475Smrg    }, bottom_tee[] =
3792d522f475Smrg    {
3793d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
3794d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
3795d522f475Smrg	-1
3796d522f475Smrg    }, top_tee[] =
3797d522f475Smrg    {
3798d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
3799d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
3800d522f475Smrg	-1
3801d522f475Smrg    }, vertical_line[] =
3802d522f475Smrg    {
3803d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
3804d522f475Smrg	-1
3805d522f475Smrg    }, less_than_or_equal[] =
3806d522f475Smrg    {
3807d522f475Smrg	SEG(  CHR_WIDE,	    BOX_HIGH/3,	  0,		MID_HIGH),
3808d522f475Smrg	SEG(  CHR_WIDE,	  2*BOX_HIGH/3,	  0,		MID_HIGH),
3809d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
3810d522f475Smrg	-1
3811d522f475Smrg    }, greater_than_or_equal[] =
3812d522f475Smrg    {
3813d522f475Smrg	SEG(  0,	    BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
3814d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
3815d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
3816d522f475Smrg	-1
3817d522f475Smrg    }, greek_pi[] =
3818d522f475Smrg    {
3819d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
3820d522f475Smrg	SEG(5*CHR_WIDE/6,   MID_HIGH,	5*CHR_WIDE/6,	CHR_HIGH),
3821d522f475Smrg	SEG(2*CHR_WIDE/6,   MID_HIGH,	2*CHR_WIDE/6,	CHR_HIGH),
3822d522f475Smrg	-1
3823d522f475Smrg    }, not_equal_to[] =
3824d522f475Smrg    {
3825d522f475Smrg	SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3,	CHR_HIGH),
3826d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,   2*BOX_HIGH/3),
3827d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
3828d522f475Smrg	-1
3829d522f475Smrg    };
3830d522f475Smrg
3831d4fba8b9Smrg    static const struct {
3832d4fba8b9Smrg	const int mode;			/* 1=y, 2=x, 3=both */
3833d4fba8b9Smrg	const short *data;
3834d4fba8b9Smrg    } lines[] =
3835d522f475Smrg    {
3836d4fba8b9Smrg	{ 0, 0 },			/* 00 (unused) */
3837d4fba8b9Smrg	{ 0, 0 },			/* 01 diamond */
3838d4fba8b9Smrg	{ 0, 0 },			/* 02 box */
3839d4fba8b9Smrg	{ 0, glyph_ht },		/* 03 HT */
3840d4fba8b9Smrg	{ 0, glyph_ff },		/* 04 FF */
3841d4fba8b9Smrg	{ 0, 0 },			/* 05 CR */
3842d4fba8b9Smrg	{ 0, glyph_lf },		/* 06 LF */
3843d4fba8b9Smrg	{ 0, 0 },			/* 07 degrees (small circle) */
3844d4fba8b9Smrg	{ 3, plus_or_minus },		/* 08 */
3845d4fba8b9Smrg	{ 0, glyph_nl },		/* 09 */
3846d4fba8b9Smrg	{ 0, glyph_vt },		/* 0A */
3847d4fba8b9Smrg	{ 3, lower_right_corner },	/* 0B */
3848d4fba8b9Smrg	{ 3, upper_right_corner },	/* 0C */
3849d4fba8b9Smrg	{ 3, upper_left_corner },	/* 0D */
3850d4fba8b9Smrg	{ 3, lower_left_corner },	/* 0E */
3851d4fba8b9Smrg	{ 3, cross },			/* 0F */
3852d4fba8b9Smrg	{ 2, scan_line_1 },		/* 10 */
3853d4fba8b9Smrg	{ 2, scan_line_3 },		/* 11 */
3854d4fba8b9Smrg	{ 2, scan_line_7 },		/* 12 */
3855d4fba8b9Smrg	{ 2, scan_line_9 },		/* 13 */
3856d4fba8b9Smrg	{ 2, horizontal_line },		/* 14 */
3857d4fba8b9Smrg	{ 3, left_tee },		/* 15 */
3858d4fba8b9Smrg	{ 3, right_tee },		/* 16 */
3859d4fba8b9Smrg	{ 3, bottom_tee },		/* 17 */
3860d4fba8b9Smrg	{ 3, top_tee },			/* 18 */
3861d4fba8b9Smrg	{ 1, vertical_line },		/* 19 */
3862d4fba8b9Smrg	{ 0, less_than_or_equal },	/* 1A */
3863d4fba8b9Smrg	{ 0, greater_than_or_equal },	/* 1B */
3864d4fba8b9Smrg	{ 0, greek_pi },		/* 1C */
3865d4fba8b9Smrg	{ 0, not_equal_to },		/* 1D */
3866d4fba8b9Smrg	{ 0, 0 },			/* 1E LB */
3867d4fba8b9Smrg	{ 0, 0 },			/* 1F bullet */
3868d522f475Smrg    };
3869d4fba8b9Smrg    /* *INDENT-ON* */
3870d522f475Smrg
3871d522f475Smrg    GC gc2;
3872d522f475Smrg    CgsEnum cgsId = (ch == 2) ? gcDots : gcLine;
3873d522f475Smrg    VTwin *cgsWin = WhichVWin(screen);
3874d522f475Smrg    const short *p;
3875d4fba8b9Smrg    unsigned font_width = (((params->draw_flags & DOUBLEWFONT) ? 2U : 1U)
3876d4fba8b9Smrg			   * screen->fnt_wide);
3877d4fba8b9Smrg    unsigned font_height = (((params->draw_flags & DOUBLEHFONT) ? 2U : 1U)
3878d4fba8b9Smrg			    * screen->fnt_high);
3879d522f475Smrg
3880d522f475Smrg    if (cells > 1)
3881956cc18dSsnj	font_width *= (unsigned) cells;
3882d522f475Smrg
3883d522f475Smrg#if OPT_WIDE_CHARS
3884d522f475Smrg    /*
3885d522f475Smrg     * Try to show line-drawing characters if we happen to be in UTF-8
3886d522f475Smrg     * mode, but have gotten an old-style font.
3887d522f475Smrg     */
3888d522f475Smrg    if (screen->utf8_mode
3889d522f475Smrg#if OPT_RENDERFONT
3890d4fba8b9Smrg	&& !UsingRenderFont(params->xw)
3891d522f475Smrg#endif
3892d522f475Smrg	&& (ch > 127)
3893d522f475Smrg	&& (ch != UCS_REPL)) {
3894d4fba8b9Smrg	int which = (params->attr_flags & BOLD) ? fBold : fNorm;
3895d522f475Smrg	unsigned n;
3896d522f475Smrg	for (n = 1; n < 32; n++) {
3897d4fba8b9Smrg	    if (xtermMissingChar(n, getNormalFont(screen, which)))
3898d4fba8b9Smrg		continue;
3899d4fba8b9Smrg	    if (dec2ucs(screen, n) != ch)
3900d4fba8b9Smrg		continue;
3901d4fba8b9Smrg	    TRACE(("...use xterm-style linedrawing U+%04X ->%d\n", ch, n));
3902d4fba8b9Smrg	    ch = n;
3903d4fba8b9Smrg	    break;
3904d522f475Smrg	}
3905d522f475Smrg    }
3906d522f475Smrg#endif
3907d522f475Smrg
3908d4fba8b9Smrg#if OPT_VT52_MODE
3909d4fba8b9Smrg    if (!(screen->vtXX_level)) {
3910d4fba8b9Smrg	switch (ch) {
3911d4fba8b9Smrg	case 6:
3912d4fba8b9Smrg	    ch = 7;
3913d4fba8b9Smrg	    break;
3914d4fba8b9Smrg	default:
3915d4fba8b9Smrg	    ch = 256;
3916d4fba8b9Smrg	    break;
3917d4fba8b9Smrg	}
3918d4fba8b9Smrg    }
3919d4fba8b9Smrg#endif
3920d4fba8b9Smrg
3921d4fba8b9Smrg    /*
3922d4fba8b9Smrg     * Line-drawing characters show use the full (scaled) cellsize, while
3923d4fba8b9Smrg     * other characters should be shifted to center them vertically.
3924d4fba8b9Smrg     */
3925d4fba8b9Smrg    if (!xftords) {
3926d4fba8b9Smrg	if ((ch < XtNumber(lines)) && (lines[ch].mode & 3) != 0) {
3927d4fba8b9Smrg	    font_height = (unsigned) ((float) font_height * screen->scale_height);
3928d4fba8b9Smrg	} else {
3929d4fba8b9Smrg	    y += ScaleShift(screen);
3930d4fba8b9Smrg	}
3931d4fba8b9Smrg    }
3932d4fba8b9Smrg
3933d4fba8b9Smrg    TRACE(("DRAW_BOX(%02X) cell %dx%d at %d,%d%s\n",
3934d522f475Smrg	   ch, font_height, font_width, y, x,
3935d4fba8b9Smrg	   ((ch >= XtNumber(lines))
3936d522f475Smrg	    ? "-BAD"
3937d522f475Smrg	    : "")));
3938d522f475Smrg
3939d522f475Smrg    if (cgsId == gcDots) {
3940d4fba8b9Smrg	setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc));
3941d4fba8b9Smrg	setCgsFore(params->xw, cgsWin, cgsId, getCgsFore(params->xw, cgsWin, gc));
3942d4fba8b9Smrg	setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc));
3943d522f475Smrg    } else {
3944d4fba8b9Smrg	setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc));
3945d4fba8b9Smrg	setCgsFore(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc));
3946d4fba8b9Smrg	setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc));
3947d522f475Smrg    }
3948d4fba8b9Smrg    gc2 = getCgsGC(params->xw, cgsWin, cgsId);
3949d522f475Smrg
3950d4fba8b9Smrg    if (!(params->draw_flags & NOBACKGROUND)) {
39510bd37d32Smrg	XFillRectangle(screen->display, VDrawable(screen), gc2, x, y,
3952d522f475Smrg		       font_width,
3953d522f475Smrg		       font_height);
3954d522f475Smrg    }
3955d522f475Smrg
3956d4fba8b9Smrg    setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc));
3957d4fba8b9Smrg    setCgsFore(params->xw, cgsWin, cgsId, getCgsFore(params->xw, cgsWin, gc));
3958d4fba8b9Smrg    setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc));
3959d4fba8b9Smrg    gc2 = getCgsGC(params->xw, cgsWin, cgsId);
3960d522f475Smrg
3961d522f475Smrg    XSetLineAttributes(screen->display, gc2,
3962d4fba8b9Smrg		       (params->attr_flags & BOLD)
3963d522f475Smrg		       ? ((font_height > 12)
3964d522f475Smrg			  ? font_height / 12
3965d522f475Smrg			  : 1)
3966d522f475Smrg		       : ((font_height > 16)
3967d522f475Smrg			  ? font_height / 16
3968d522f475Smrg			  : 1),
3969d522f475Smrg		       LineSolid,
3970d522f475Smrg		       CapProjecting,
3971d522f475Smrg		       JoinMiter);
3972d522f475Smrg
3973d522f475Smrg    if (ch == 1) {		/* diamond */
3974d522f475Smrg	XPoint points[5];
3975d522f475Smrg	int npoints = 5, n;
3976d522f475Smrg
3977d522f475Smrg	points[0].x = MID_WIDE;
3978d522f475Smrg	points[0].y = BOX_HIGH / 4;
3979d522f475Smrg
3980d522f475Smrg	points[1].x = 8 * BOX_WIDE / 8;
3981d522f475Smrg	points[1].y = MID_HIGH;
3982d522f475Smrg
3983d522f475Smrg	points[2].x = points[0].x;
3984d522f475Smrg	points[2].y = 3 * BOX_HIGH / 4;
3985d522f475Smrg
3986d522f475Smrg	points[3].x = 0 * BOX_WIDE / 8;
3987d522f475Smrg	points[3].y = points[1].y;
3988d522f475Smrg
3989d522f475Smrg	points[4].x = points[0].x;
3990d522f475Smrg	points[4].y = points[0].y;
3991d522f475Smrg
3992d522f475Smrg	for (n = 0; n < npoints; ++n) {
3993d4fba8b9Smrg	    points[n].x = (short) (SCALED_X(points[n].x));
3994d4fba8b9Smrg	    points[n].y = (short) (SCALED_Y(points[n].y));
3995e39b573cSmrg	    points[n].x = (short) (points[n].x + x);
3996e39b573cSmrg	    points[n].y = (short) (points[n].y + y);
3997d522f475Smrg	}
3998d522f475Smrg
3999d522f475Smrg	XFillPolygon(screen->display,
40000bd37d32Smrg		     VDrawable(screen), gc2,
4001d522f475Smrg		     points, npoints,
4002d522f475Smrg		     Convex, CoordModeOrigin);
4003d522f475Smrg    } else if (ch == 7) {	/* degrees */
4004d522f475Smrg	unsigned width = (BOX_WIDE / 3);
4005956cc18dSsnj	int x_coord = MID_WIDE - (int) (width / 2);
4006956cc18dSsnj	int y_coord = MID_HIGH - (int) width;
4007d522f475Smrg
4008d522f475Smrg	SCALE_X(x_coord);
4009d522f475Smrg	SCALE_Y(y_coord);
4010e39b573cSmrg	width = (unsigned) SCALED_X(width);
4011d522f475Smrg
4012d522f475Smrg	XDrawArc(screen->display,
40130bd37d32Smrg		 VDrawable(screen), gc2,
4014d522f475Smrg		 x + x_coord, y + y_coord, width, width,
4015d522f475Smrg		 0,
4016d522f475Smrg		 360 * 64);
4017d522f475Smrg    } else if (ch == 0x1f) {	/* bullet */
4018d522f475Smrg	unsigned width = 7 * BOX_WIDE / 10;
4019956cc18dSsnj	int x_coord = MID_WIDE - (int) (width / 3);
4020956cc18dSsnj	int y_coord = MID_HIGH - (int) (width / 3);
4021d522f475Smrg
4022d522f475Smrg	SCALE_X(x_coord);
4023d522f475Smrg	SCALE_Y(y_coord);
4024e39b573cSmrg	width = (unsigned) SCALED_X(width);
4025d522f475Smrg
4026d522f475Smrg	XDrawArc(screen->display,
40270bd37d32Smrg		 VDrawable(screen), gc2,
4028d522f475Smrg		 x + x_coord, y + y_coord, width, width,
4029d522f475Smrg		 0,
4030d522f475Smrg		 360 * 64);
4031d4fba8b9Smrg    } else if (ch < XtNumber(lines)
4032d4fba8b9Smrg	       && (p = lines[ch].data) != 0) {
4033956cc18dSsnj	int coord[4];
4034d522f475Smrg	int n = 0;
4035d522f475Smrg	while (*p >= 0) {
4036d522f475Smrg	    coord[n++] = *p++;
4037d522f475Smrg	    if (n == 4) {
4038d522f475Smrg		SCALE_X(coord[0]);
4039d522f475Smrg		SCALE_Y(coord[1]);
4040d522f475Smrg		SCALE_X(coord[2]);
4041d522f475Smrg		SCALE_Y(coord[3]);
4042d522f475Smrg		XDrawLine(screen->display,
40430bd37d32Smrg			  VDrawable(screen), gc2,
4044d522f475Smrg			  x + coord[0], y + coord[1],
4045d522f475Smrg			  x + coord[2], y + coord[3]);
4046d522f475Smrg		n = 0;
4047d522f475Smrg	    }
4048d522f475Smrg	}
4049d522f475Smrg    } else if (screen->force_all_chars) {
4050d522f475Smrg	/* bounding rectangle, for debugging */
40510bd37d32Smrg	XDrawRectangle(screen->display, VDrawable(screen), gc2, x, y,
4052d522f475Smrg		       font_width - 1,
4053d522f475Smrg		       font_height - 1);
4054d522f475Smrg    }
4055d522f475Smrg}
4056fa3f02f3Smrg#endif /* OPT_BOX_CHARS */
4057d522f475Smrg
4058d522f475Smrg#if OPT_RENDERFONT
4059d4fba8b9Smrg/*
4060d4fba8b9Smrg * Check if the glyph is defined in the given font, and (try to) filter out
4061d4fba8b9Smrg * cases where double-width glyphs are stuffed into a single-width outline.
4062d4fba8b9Smrg */
4063d4fba8b9Smrgstatic Boolean
4064d4fba8b9SmrgfoundXftGlyph(XtermWidget xw, XftFont *font, unsigned wc)
4065d4fba8b9Smrg{
4066d4fba8b9Smrg    TScreen *screen = TScreenOf(xw);
4067d4fba8b9Smrg    Boolean result = False;
4068d4fba8b9Smrg
4069d4fba8b9Smrg    if (font != 0 && XftGlyphExists(screen->display, font, wc)) {
4070d4fba8b9Smrg	int expect;
4071d4fba8b9Smrg
4072c48a5815Smrg	if ((expect = CharWidth(screen, wc)) > 0) {
4073d4fba8b9Smrg	    XGlyphInfo gi;
4074d4fba8b9Smrg	    int actual;
4075d4fba8b9Smrg
4076d4fba8b9Smrg	    XftTextExtents32(screen->display, font, &wc, 1, &gi);
4077d4fba8b9Smrg	    /*
4078d4fba8b9Smrg	     * Some (more than a few) fonts are sloppy; allow 10% outside
4079d4fba8b9Smrg	     * the bounding box to accommodate them.
4080d4fba8b9Smrg	     */
4081d4fba8b9Smrg	    actual = ((gi.xOff * 10) >= (11 * FontWidth(screen))) ? 2 : 1;
4082d4fba8b9Smrg	    if (actual <= expect) {
4083d4fba8b9Smrg		/* allow double-cell if wcwidth agrees */
4084d4fba8b9Smrg		result = True;
4085d4fba8b9Smrg	    } else {
4086d4fba8b9Smrg		TRACE(("SKIP U+%04X %d vs %d (%d vs %d)\n",
4087d4fba8b9Smrg		       wc, gi.xOff, FontWidth(screen), actual, expect));
4088d4fba8b9Smrg	    }
4089d4fba8b9Smrg	} else {
4090d4fba8b9Smrg	    result = True;
4091d4fba8b9Smrg	}
4092d4fba8b9Smrg    }
4093d4fba8b9Smrg    return result;
4094d4fba8b9Smrg}
4095d4fba8b9Smrg
4096d4fba8b9Smrgstatic void
4097d4fba8b9SmrgmarkXftOpened(XtermWidget xw, XTermXftFonts *which, Cardinal n, unsigned wc)
4098d4fba8b9Smrg{
4099d4fba8b9Smrg    if (which->cache[n].usage != xcOpened) {
4100d4fba8b9Smrg	which->opened++;
4101d4fba8b9Smrg	which->cache[n].usage = xcOpened;
4102d4fba8b9Smrg	/* XFT_DEBUG=3 will show useful context for this */
4103d4fba8b9Smrg	if (getenv("XFT_DEBUG") != 0) {
4104d4fba8b9Smrg	    printf("xterm: matched U+%04X in fontset #%d [%u:%u]\n",
4105d4fba8b9Smrg		   wc, n + 1,
4106d4fba8b9Smrg		   which->opened,
4107d4fba8b9Smrg		   xw->work.max_fontsets);
4108d4fba8b9Smrg	}
4109d4fba8b9Smrg    }
4110d4fba8b9Smrg}
4111d4fba8b9Smrg
4112d4fba8b9Smrg/*
4113d4fba8b9Smrg * Check if the given character has a glyph known to Xft.  If it is missing,
4114d4fba8b9Smrg * try first to replace the font with a fallback that provides the glyph.
4115d4fba8b9Smrg */
4116d4fba8b9SmrgXftFont *
4117d4fba8b9SmrgfindXftGlyph(XtermWidget xw, XftFont *given, unsigned wc)
4118d4fba8b9Smrg{
4119d4fba8b9Smrg    TScreen *screen = TScreenOf(xw);
4120d4fba8b9Smrg    XTermXftFonts *which = 0;
4121d4fba8b9Smrg    XftFont *result = 0;
4122d4fba8b9Smrg    /* workaround for interface changes... */
4123d4fba8b9Smrg    int fontnum = screen->menu_font_number;
4124d4fba8b9Smrg    static int table[] =
4125d4fba8b9Smrg    {
4126d4fba8b9Smrg	offsetof(TScreen, renderFontNorm),
4127d4fba8b9Smrg	offsetof(TScreen, renderFontBold),
4128d4fba8b9Smrg	offsetof(TScreen, renderFontItal),
4129d4fba8b9Smrg	offsetof(TScreen, renderFontBtal),
4130d4fba8b9Smrg#if OPT_RENDERWIDE
4131d4fba8b9Smrg	offsetof(TScreen, renderWideNorm),
4132d4fba8b9Smrg	offsetof(TScreen, renderWideBold),
4133d4fba8b9Smrg	offsetof(TScreen, renderWideItal),
4134d4fba8b9Smrg	offsetof(TScreen, renderWideBtal),
4135d4fba8b9Smrg#endif
4136d4fba8b9Smrg    };
4137d4fba8b9Smrg    Cardinal n;
4138d4fba8b9Smrg    FcResult status;
4139d4fba8b9Smrg    const char *tag = 0;
4140d4fba8b9Smrg
4141d4fba8b9Smrg    /* if fontsets are not wanted, just leave */
4142d4fba8b9Smrg    if (xw->work.max_fontsets == 0) {
4143d4fba8b9Smrg	return 0;
4144d4fba8b9Smrg    }
4145d4fba8b9Smrg
4146d4fba8b9Smrg    /* ignore codes in private use areas */
4147d4fba8b9Smrg    if ((wc >= 0xe000 && wc <= 0xf8ff)
4148d4fba8b9Smrg	|| (wc >= 0xf0000 && wc <= 0xffffd)
4149d4fba8b9Smrg	|| (wc >= 0x100000 && wc <= 0x10fffd)) {
4150d4fba8b9Smrg	return 0;
4151d4fba8b9Smrg    }
4152d4fba8b9Smrg    /* the end of the BMP is reserved for non-characters */
4153d4fba8b9Smrg    if (wc >= 0xfff0 && wc <= 0xffff) {
4154d4fba8b9Smrg	return 0;
4155d4fba8b9Smrg    }
4156d4fba8b9Smrg
4157d4fba8b9Smrg    for (n = 0; n < XtNumber(table); ++n) {
4158d4fba8b9Smrg	XTermXftFonts *check = (XTermXftFonts *) ((void *) ((char *) screen
4159d4fba8b9Smrg							    + table[n]));
4160d4fba8b9Smrg	if (check[fontnum].font == given) {
4161d4fba8b9Smrg	    which = &check[fontnum];
4162d4fba8b9Smrg	    tag = whichFontEnum((VTFontEnum) n);
4163d4fba8b9Smrg	    break;
4164d4fba8b9Smrg	}
4165d4fba8b9Smrg    }
4166d4fba8b9Smrg    if (which != 0) {
4167d4fba8b9Smrg	if (which->fontset == 0) {
4168d4fba8b9Smrg	    FcFontSet *sortedFonts;
4169d4fba8b9Smrg	    FcPattern *myPattern;
4170d4fba8b9Smrg	    int j;
4171d4fba8b9Smrg
4172d4fba8b9Smrg	    myPattern = FcPatternDuplicate(which->pattern);
4173d4fba8b9Smrg
4174d4fba8b9Smrg	    FcPatternAddBool(myPattern, FC_SCALABLE, FcTrue);
4175d4fba8b9Smrg	    FcPatternAddInteger(myPattern, FC_CHAR_WIDTH, given->max_advance_width);
4176d4fba8b9Smrg
4177d4fba8b9Smrg	    FcConfigSubstitute(FcConfigGetCurrent(),
4178d4fba8b9Smrg			       myPattern,
4179d4fba8b9Smrg			       FcMatchPattern);
4180d4fba8b9Smrg	    FcDefaultSubstitute(myPattern);
4181d4fba8b9Smrg
4182d4fba8b9Smrg	    which->fontset = FcFontSetCreate();
4183d4fba8b9Smrg
4184d4fba8b9Smrg	    sortedFonts = FcFontSort(0, myPattern, FcTrue, 0, &status);
4185d4fba8b9Smrg
4186d4fba8b9Smrg	    if (!sortedFonts || sortedFonts->nfont <= 0) {
4187d4fba8b9Smrg		xtermWarning("did not find any usable TrueType font\n");
4188d4fba8b9Smrg		return 0;
4189d4fba8b9Smrg	    }
4190d4fba8b9Smrg	    which->limit = (unsigned) sortedFonts->nfont;
4191d4fba8b9Smrg	    which->cache = TypeCallocN(XTermXftCache, (which->limit + 1));
4192d4fba8b9Smrg	    for (j = 0; j < sortedFonts->nfont; j++) {
4193d4fba8b9Smrg		FcPattern *font_pattern;
4194d4fba8b9Smrg
4195d4fba8b9Smrg		font_pattern = FcFontRenderPrepare(FcConfigGetCurrent(),
4196d4fba8b9Smrg						   myPattern,
4197d4fba8b9Smrg						   sortedFonts->fonts[j]);
4198d4fba8b9Smrg		if (font_pattern)
4199d4fba8b9Smrg		    FcFontSetAdd(which->fontset, font_pattern);
4200d4fba8b9Smrg	    }
4201d4fba8b9Smrg
4202d4fba8b9Smrg	    FcFontSetSortDestroy(sortedFonts);
4203d4fba8b9Smrg	    FcPatternDestroy(myPattern);
4204d4fba8b9Smrg	}
4205d4fba8b9Smrg	if (which->fontset != 0) {
4206d4fba8b9Smrg	    XftFont *check;
4207d4fba8b9Smrg	    Cardinal empty = which->limit;
4208d4fba8b9Smrg
4209d4fba8b9Smrg	    for (n = 0; n < which->limit; ++n) {
4210d4fba8b9Smrg		XftCache usage = which->cache[n].usage;
4211d4fba8b9Smrg		if (usage == xcEmpty) {
4212d4fba8b9Smrg		    if (empty > n)
4213d4fba8b9Smrg			empty = n;
4214d4fba8b9Smrg		} else if (usage == xcOpened
4215d4fba8b9Smrg			   || (usage == xcUnused
4216d4fba8b9Smrg			       && (which->opened < xw->work.max_fontsets))) {
4217d4fba8b9Smrg		    check = which->cache[n].font;
4218d4fba8b9Smrg		    if (foundXftGlyph(xw, check, wc)) {
4219d4fba8b9Smrg			markXftOpened(xw, which, n, wc);
4220d4fba8b9Smrg			result = check;
4221d4fba8b9Smrg			TRACE_FALLBACK(xw, "old", wc, (int) n, result);
4222d4fba8b9Smrg			break;
4223d4fba8b9Smrg		    }
4224d4fba8b9Smrg		}
4225d4fba8b9Smrg	    }
4226d4fba8b9Smrg
4227d4fba8b9Smrg	    if ((result == 0)
4228d4fba8b9Smrg		&& (empty < which->limit)
4229d4fba8b9Smrg		&& (which->opened < xw->work.max_fontsets)) {
4230d4fba8b9Smrg		FcPattern *myPattern = 0;
4231d4fba8b9Smrg		FcPattern *myReport = 0;
4232d4fba8b9Smrg
4233d4fba8b9Smrg		for (n = empty; n < which->limit; ++n) {
4234d4fba8b9Smrg		    if (which->cache[n].usage >= xcBogus)
4235d4fba8b9Smrg			continue;
4236d4fba8b9Smrg		    if (resource.reportFonts) {
4237d4fba8b9Smrg			myReport = FcPatternDuplicate(which->fontset->fonts[n]);
4238d4fba8b9Smrg		    }
4239d4fba8b9Smrg		    myPattern = FcPatternDuplicate(which->fontset->fonts[n]);
4240d4fba8b9Smrg		    check = XftFontOpenPattern(screen->display, myPattern);
4241d4fba8b9Smrg		    closeCachedXft(screen, which->cache[n].font);
4242d4fba8b9Smrg		    (void) maybeXftCache(xw, check);
4243d4fba8b9Smrg		    which->cache[n].font = check;
4244d4fba8b9Smrg		    which->cache[n].usage = xcBogus;
4245d4fba8b9Smrg		    if (check == 0)
4246d4fba8b9Smrg			continue;	/* shouldn't happen... */
4247d4fba8b9Smrg#ifdef FC_COLOR
4248d4fba8b9Smrg		    if (isBogusXft(check)) {
4249d4fba8b9Smrg			continue;
4250d4fba8b9Smrg		    }
4251d4fba8b9Smrg#endif
4252d4fba8b9Smrg		    if (foundXftGlyph(xw, check, wc)) {
4253d4fba8b9Smrg			markXftOpened(xw, which, n, wc);
4254d4fba8b9Smrg			reportXftFonts(xw, check, "fallback", tag, myReport);
4255d4fba8b9Smrg			result = check;
4256d4fba8b9Smrg			TRACE_FALLBACK(xw, "new", wc, (int) n, result);
4257d4fba8b9Smrg			break;
4258d4fba8b9Smrg		    }
4259d4fba8b9Smrg		    /*
4260d4fba8b9Smrg		     * The slot is opened, but we are not using it.
4261d4fba8b9Smrg		     */
4262d4fba8b9Smrg		    which->cache[n].usage = xcUnused;
4263d4fba8b9Smrg		}
4264d4fba8b9Smrg	    }
4265d4fba8b9Smrg	}
4266d4fba8b9Smrg    }
4267d4fba8b9Smrg    return result;
4268d4fba8b9Smrg}
4269d522f475Smrg
4270d522f475Smrg/*
4271d4fba8b9Smrg * Check if the given character has a glyph known to Xft.  If it is missing,
4272d4fba8b9Smrg * return true.
4273d522f475Smrg *
4274d522f475Smrg * see xc/lib/Xft/xftglyphs.c
4275d522f475Smrg */
4276d522f475SmrgBool
42779a64e1c5SmrgxtermXftMissing(XtermWidget xw, XftFont *font, unsigned wc)
4278d522f475Smrg{
4279d522f475Smrg    Bool result = False;
4280d522f475Smrg
4281d522f475Smrg    if (font != 0) {
4282956cc18dSsnj	TScreen *screen = TScreenOf(xw);
4283956cc18dSsnj	if (!XftGlyphExists(screen->display, font, wc)) {
4284d522f475Smrg#if OPT_WIDE_CHARS
4285dfb07bc7Smrg	    TRACE2(("xtermXftMissing %d (dec=%#x, ucs=%#x)\n",
4286d4fba8b9Smrg		    wc, ucs2dec(screen, wc), dec2ucs(screen, wc)));
4287d522f475Smrg#else
4288dfb07bc7Smrg	    TRACE2(("xtermXftMissing %d\n", wc));
4289d522f475Smrg#endif
4290d522f475Smrg	    result = True;
4291d522f475Smrg	}
4292d522f475Smrg    }
4293d522f475Smrg    return result;
4294d522f475Smrg}
4295fa3f02f3Smrg#endif /* OPT_RENDERFONT */
4296d522f475Smrg
4297d522f475Smrg#if OPT_WIDE_CHARS
4298d522f475Smrg#define MY_UCS(ucs,dec) case ucs: result = dec; break
4299d522f475Smrgunsigned
4300d4fba8b9Smrgucs2dec(TScreen *screen, unsigned ch)
4301d522f475Smrg{
4302d522f475Smrg    unsigned result = ch;
4303d4fba8b9Smrg
4304d4fba8b9Smrg    (void) screen;
4305d522f475Smrg    if ((ch > 127)
4306d522f475Smrg	&& (ch != UCS_REPL)) {
4307d4fba8b9Smrg#if OPT_VT52_MODE
4308d4fba8b9Smrg	if (screen != 0 && !(screen->vtXX_level)) {
4309d4fba8b9Smrg	    /*
4310d4fba8b9Smrg	     * Intentionally empty: it would be possible to use the built-in
4311d4fba8b9Smrg	     * line-drawing fallback in xtermDrawBoxChar(), but for testing
4312d4fba8b9Smrg	     * ncurses, this is good enough.
4313d4fba8b9Smrg	     */
4314d4fba8b9Smrg	    ;
4315d4fba8b9Smrg	} else
4316d4fba8b9Smrg#endif
4317d4fba8b9Smrg	    switch (ch) {
4318d4fba8b9Smrg		MY_UCS(0x25ae, 0);	/* black vertical rectangle           */
4319d4fba8b9Smrg		MY_UCS(0x25c6, 1);	/* black diamond                      */
4320d4fba8b9Smrg		MY_UCS(0x2592, 2);	/* medium shade                       */
4321d4fba8b9Smrg		MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation   */
4322d4fba8b9Smrg		MY_UCS(0x240c, 4);	/* symbol for form feed               */
4323d4fba8b9Smrg		MY_UCS(0x240d, 5);	/* symbol for carriage return         */
4324d4fba8b9Smrg		MY_UCS(0x240a, 6);	/* symbol for line feed               */
4325d4fba8b9Smrg		MY_UCS(0x00b0, 7);	/* degree sign                        */
4326d4fba8b9Smrg		MY_UCS(0x00b1, 8);	/* plus-minus sign                    */
4327d4fba8b9Smrg		MY_UCS(0x2424, 9);	/* symbol for newline                 */
4328d4fba8b9Smrg		MY_UCS(0x240b, 10);	/* symbol for vertical tabulation     */
4329d4fba8b9Smrg		MY_UCS(0x2518, 11);	/* box drawings light up and left     */
4330d4fba8b9Smrg		MY_UCS(0x2510, 12);	/* box drawings light down and left   */
4331d4fba8b9Smrg		MY_UCS(0x250c, 13);	/* box drawings light down and right  */
4332d4fba8b9Smrg		MY_UCS(0x2514, 14);	/* box drawings light up and right    */
4333d4fba8b9Smrg		MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
4334d4fba8b9Smrg		MY_UCS(0x23ba, 16);	/* box drawings scan 1                */
4335d4fba8b9Smrg		MY_UCS(0x23bb, 17);	/* box drawings scan 3                */
4336d4fba8b9Smrg		MY_UCS(0x2500, 18);	/* box drawings light horizontal      */
4337d4fba8b9Smrg		MY_UCS(0x23bc, 19);	/* box drawings scan 7                */
4338d4fba8b9Smrg		MY_UCS(0x23bd, 20);	/* box drawings scan 9                */
4339d4fba8b9Smrg		MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
4340d4fba8b9Smrg		MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
4341d4fba8b9Smrg		MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
4342d4fba8b9Smrg		MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
4343d4fba8b9Smrg		MY_UCS(0x2502, 25);	/* box drawings light vertical        */
4344d4fba8b9Smrg		MY_UCS(0x2264, 26);	/* less-than or equal to              */
4345d4fba8b9Smrg		MY_UCS(0x2265, 27);	/* greater-than or equal to           */
4346d4fba8b9Smrg		MY_UCS(0x03c0, 28);	/* greek small letter pi              */
4347d4fba8b9Smrg		MY_UCS(0x2260, 29);	/* not equal to                       */
4348d4fba8b9Smrg		MY_UCS(0x00a3, 30);	/* pound sign                         */
4349d4fba8b9Smrg		MY_UCS(0x00b7, 31);	/* middle dot                         */
4350d4fba8b9Smrg	    }
4351d522f475Smrg    }
4352d522f475Smrg    return result;
4353d522f475Smrg}
4354d522f475Smrg
4355d522f475Smrg#undef  MY_UCS
4356d522f475Smrg#define MY_UCS(ucs,dec) case dec: result = ucs; break
4357d522f475Smrg
4358d522f475Smrgunsigned
4359d4fba8b9Smrgdec2ucs(TScreen *screen, unsigned ch)
4360d522f475Smrg{
4361d522f475Smrg    unsigned result = ch;
4362d4fba8b9Smrg
4363d4fba8b9Smrg    (void) screen;
4364d522f475Smrg    if (xtermIsDecGraphic(ch)) {
4365d4fba8b9Smrg#if OPT_VT52_MODE
4366d4fba8b9Smrg	if (screen != 0 && !(screen->vtXX_level)) {
4367d4fba8b9Smrg	    switch (ch) {
4368d4fba8b9Smrg		MY_UCS(0x0020, 0);	/* nbsp, treat as blank           */
4369d4fba8b9Smrg		MY_UCS(0x0020, 1);	/* reserved, treat as blank       */
4370d4fba8b9Smrg		MY_UCS(0x25ae, 2);	/* black vertical rectangle       */
4371d4fba8b9Smrg		MY_UCS(0x215f, 3);	/* "1/"                           */
4372d4fba8b9Smrg		MY_UCS(0x0020, 4);	/* "3/", not in Unicode, ignore   */
4373d4fba8b9Smrg		MY_UCS(0x0020, 5);	/* "5/", not in Unicode, ignore   */
4374d4fba8b9Smrg		MY_UCS(0x0020, 6);	/* "7/", not in Unicode, ignore   */
4375d4fba8b9Smrg		MY_UCS(0x00b0, 7);	/* degree sign                    */
4376d4fba8b9Smrg		MY_UCS(0x00b1, 8);	/* plus-minus sign                */
4377d4fba8b9Smrg		MY_UCS(0x2192, 9);	/* right-arrow                    */
4378d4fba8b9Smrg		MY_UCS(0x2026, 10);	/* ellipsis                       */
4379d4fba8b9Smrg		MY_UCS(0x00f7, 11);	/* divide by                      */
4380d4fba8b9Smrg		MY_UCS(0x2193, 12);	/* down arrow                     */
4381d4fba8b9Smrg		MY_UCS(0x23ba, 13);	/* bar at scan 0                  */
4382d4fba8b9Smrg		MY_UCS(0x23ba, 14);	/* bar at scan 1                  */
4383d4fba8b9Smrg		MY_UCS(0x23bb, 15);	/* bar at scan 2                  */
4384d4fba8b9Smrg		MY_UCS(0x23bb, 16);	/* bar at scan 3                  */
4385d4fba8b9Smrg		MY_UCS(0x23bc, 17);	/* bar at scan 4                  */
4386d4fba8b9Smrg		MY_UCS(0x23bc, 18);	/* bar at scan 5                  */
4387d4fba8b9Smrg		MY_UCS(0x23bd, 19);	/* bar at scan 6                  */
4388d4fba8b9Smrg		MY_UCS(0x23bd, 20);	/* bar at scan 7                  */
4389d4fba8b9Smrg		MY_UCS(0x2080, 21);	/* subscript 0                    */
4390d4fba8b9Smrg		MY_UCS(0x2081, 22);	/* subscript 1                    */
4391d4fba8b9Smrg		MY_UCS(0x2082, 23);	/* subscript 2                    */
4392d4fba8b9Smrg		MY_UCS(0x2083, 24);	/* subscript 3                    */
4393d4fba8b9Smrg		MY_UCS(0x2084, 25);	/* subscript 4                    */
4394d4fba8b9Smrg		MY_UCS(0x2085, 26);	/* subscript 5                    */
4395d4fba8b9Smrg		MY_UCS(0x2086, 27);	/* subscript 6                    */
4396d4fba8b9Smrg		MY_UCS(0x2087, 28);	/* subscript 7                    */
4397d4fba8b9Smrg		MY_UCS(0x2088, 29);	/* subscript 8                    */
4398d4fba8b9Smrg		MY_UCS(0x2089, 30);	/* subscript 9                    */
4399d4fba8b9Smrg		MY_UCS(0x00b6, 31);	/* paragraph                      */
4400d4fba8b9Smrg	    }
4401d4fba8b9Smrg	} else
4402d4fba8b9Smrg#endif
4403d4fba8b9Smrg	    switch (ch) {
4404d4fba8b9Smrg		MY_UCS(0x25ae, 0);	/* black vertical rectangle           */
4405d4fba8b9Smrg		MY_UCS(0x25c6, 1);	/* black diamond                      */
4406d4fba8b9Smrg		MY_UCS(0x2592, 2);	/* medium shade                       */
4407d4fba8b9Smrg		MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation   */
4408d4fba8b9Smrg		MY_UCS(0x240c, 4);	/* symbol for form feed               */
4409d4fba8b9Smrg		MY_UCS(0x240d, 5);	/* symbol for carriage return         */
4410d4fba8b9Smrg		MY_UCS(0x240a, 6);	/* symbol for line feed               */
4411d4fba8b9Smrg		MY_UCS(0x00b0, 7);	/* degree sign                        */
4412d4fba8b9Smrg		MY_UCS(0x00b1, 8);	/* plus-minus sign                    */
4413d4fba8b9Smrg		MY_UCS(0x2424, 9);	/* symbol for newline                 */
4414d4fba8b9Smrg		MY_UCS(0x240b, 10);	/* symbol for vertical tabulation     */
4415d4fba8b9Smrg		MY_UCS(0x2518, 11);	/* box drawings light up and left     */
4416d4fba8b9Smrg		MY_UCS(0x2510, 12);	/* box drawings light down and left   */
4417d4fba8b9Smrg		MY_UCS(0x250c, 13);	/* box drawings light down and right  */
4418d4fba8b9Smrg		MY_UCS(0x2514, 14);	/* box drawings light up and right    */
4419d4fba8b9Smrg		MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
4420d4fba8b9Smrg		MY_UCS(0x23ba, 16);	/* box drawings scan 1                */
4421d4fba8b9Smrg		MY_UCS(0x23bb, 17);	/* box drawings scan 3                */
4422d4fba8b9Smrg		MY_UCS(0x2500, 18);	/* box drawings light horizontal      */
4423d4fba8b9Smrg		MY_UCS(0x23bc, 19);	/* box drawings scan 7                */
4424d4fba8b9Smrg		MY_UCS(0x23bd, 20);	/* box drawings scan 9                */
4425d4fba8b9Smrg		MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
4426d4fba8b9Smrg		MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
4427d4fba8b9Smrg		MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
4428d4fba8b9Smrg		MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
4429d4fba8b9Smrg		MY_UCS(0x2502, 25);	/* box drawings light vertical        */
4430d4fba8b9Smrg		MY_UCS(0x2264, 26);	/* less-than or equal to              */
4431d4fba8b9Smrg		MY_UCS(0x2265, 27);	/* greater-than or equal to           */
4432d4fba8b9Smrg		MY_UCS(0x03c0, 28);	/* greek small letter pi              */
4433d4fba8b9Smrg		MY_UCS(0x2260, 29);	/* not equal to                       */
4434d4fba8b9Smrg		MY_UCS(0x00a3, 30);	/* pound sign                         */
4435d4fba8b9Smrg		MY_UCS(0x00b7, 31);	/* middle dot                         */
4436d4fba8b9Smrg	    }
4437d522f475Smrg    }
4438d522f475Smrg    return result;
4439d522f475Smrg}
4440d522f475Smrg
4441d522f475Smrg#endif /* OPT_WIDE_CHARS */
4442d522f475Smrg
4443b6fea0ceSmrg#if OPT_RENDERFONT || OPT_SHIFT_FONTS
44440bd37d32Smrgstatic int
4445d522f475SmrglookupOneFontSize(XtermWidget xw, int fontnum)
4446d522f475Smrg{
4447d522f475Smrg    TScreen *screen = TScreenOf(xw);
4448d522f475Smrg
4449d522f475Smrg    if (screen->menu_font_sizes[fontnum] == 0) {
4450d522f475Smrg	XTermFonts fnt;
4451d522f475Smrg
4452d522f475Smrg	memset(&fnt, 0, sizeof(fnt));
4453d522f475Smrg	screen->menu_font_sizes[fontnum] = -1;
4454dfb07bc7Smrg	if (xtermOpenFont(xw, screen->MenuFontName(fontnum), &fnt, True)) {
445520d2c4d2Smrg	    if (fontnum <= fontMenu_lastBuiltin
44560bd37d32Smrg		|| strcmp(fnt.fn, DEFFONT)) {
445720d2c4d2Smrg		screen->menu_font_sizes[fontnum] = FontSize(fnt.fs);
44580bd37d32Smrg		if (screen->menu_font_sizes[fontnum] <= 0)
44590bd37d32Smrg		    screen->menu_font_sizes[fontnum] = -1;
44600bd37d32Smrg	    }
4461d522f475Smrg	    xtermCloseFont(xw, &fnt);
4462d522f475Smrg	}
4463d522f475Smrg    }
44640bd37d32Smrg    return (screen->menu_font_sizes[fontnum] > 0);
4465d522f475Smrg}
4466d522f475Smrg
4467d522f475Smrg/*
4468d522f475Smrg * Cache the font-sizes so subsequent larger/smaller font actions will go fast.
4469d522f475Smrg */
4470d522f475Smrgstatic void
4471d522f475SmrglookupFontSizes(XtermWidget xw)
4472d522f475Smrg{
4473d522f475Smrg    int n;
4474d522f475Smrg
4475d522f475Smrg    for (n = 0; n < NMENUFONTS; n++) {
44760bd37d32Smrg	(void) lookupOneFontSize(xw, n);
4477d522f475Smrg    }
4478d522f475Smrg}
4479b6fea0ceSmrg#endif /* OPT_RENDERFONT || OPT_SHIFT_FONTS */
4480d522f475Smrg
44812eaa94a1Schristos#if OPT_RENDERFONT
44829a64e1c5Smrgstatic double
44839a64e1c5SmrgdefaultFaceSize(void)
44849a64e1c5Smrg{
44859a64e1c5Smrg    double result;
44869a64e1c5Smrg    float value;
44879a64e1c5Smrg
44889a64e1c5Smrg    if (sscanf(DEFFACESIZE, "%f", &value) == 1)
4489d4fba8b9Smrg	result = (double) value;
44909a64e1c5Smrg    else
44919a64e1c5Smrg	result = 14.0;
44929a64e1c5Smrg    return result;
44939a64e1c5Smrg}
44949a64e1c5Smrg
44950bd37d32Smrgstatic void
44960bd37d32SmrgfillInFaceSize(XtermWidget xw, int fontnum)
44970bd37d32Smrg{
44980bd37d32Smrg    TScreen *screen = TScreenOf(xw);
4499d4fba8b9Smrg    double face_size = (double) xw->misc.face_size[fontnum];
45000bd37d32Smrg
45010bd37d32Smrg    if (face_size <= 0.0) {
45020bd37d32Smrg#if OPT_SHIFT_FONTS
45030bd37d32Smrg	/*
45040bd37d32Smrg	 * If the user is switching font-sizes, make it follow by
45050bd37d32Smrg	 * default the same ratios to the default as the fixed fonts
45060bd37d32Smrg	 * would, for easy comparison.  There will be some differences
45070bd37d32Smrg	 * since the fixed fonts have a variety of height/width ratios,
45080bd37d32Smrg	 * but this is simpler than adding another resource value - and
45090bd37d32Smrg	 * as noted above, the data for the fixed fonts are available.
45100bd37d32Smrg	 */
45110bd37d32Smrg	(void) lookupOneFontSize(xw, 0);
45120bd37d32Smrg	if (fontnum == fontMenu_default) {
45139a64e1c5Smrg	    face_size = defaultFaceSize();
45140bd37d32Smrg	} else if (lookupOneFontSize(xw, fontnum)
45150bd37d32Smrg		   && (screen->menu_font_sizes[0]
45160bd37d32Smrg		       != screen->menu_font_sizes[fontnum])) {
45170bd37d32Smrg	    double ratio;
45180bd37d32Smrg	    long num = screen->menu_font_sizes[fontnum];
45190bd37d32Smrg	    long den = screen->menu_font_sizes[0];
45200bd37d32Smrg
45210bd37d32Smrg	    if (den <= 0)
45220bd37d32Smrg		den = 1;
45230bd37d32Smrg	    ratio = dimSquareRoot((double) num / (double) den);
45240bd37d32Smrg
4525d4fba8b9Smrg	    face_size = (ratio * (double) xw->misc.face_size[0]);
45260bd37d32Smrg	    TRACE(("scaled[%d] using %3ld/%ld = %.2f -> %f\n",
45270bd37d32Smrg		   fontnum, num, den, ratio, face_size));
45280bd37d32Smrg	} else
45290bd37d32Smrg#endif
45300bd37d32Smrg	{
4531d4fba8b9Smrg#define LikeBitmap(s) (((s) / 78.0) * (double) xw->misc.face_size[fontMenu_default])
45320bd37d32Smrg	    switch (fontnum) {
45330bd37d32Smrg	    case fontMenu_font1:
45340bd37d32Smrg		face_size = LikeBitmap(2.0);
45350bd37d32Smrg		break;
45360bd37d32Smrg	    case fontMenu_font2:
45370bd37d32Smrg		face_size = LikeBitmap(35.0);
45380bd37d32Smrg		break;
45390bd37d32Smrg	    case fontMenu_font3:
45400bd37d32Smrg		face_size = LikeBitmap(60.0);
45410bd37d32Smrg		break;
45420bd37d32Smrg	    default:
45439a64e1c5Smrg		face_size = defaultFaceSize();
45440bd37d32Smrg		break;
45450bd37d32Smrg	    case fontMenu_font4:
45460bd37d32Smrg		face_size = LikeBitmap(90.0);
45470bd37d32Smrg		break;
45480bd37d32Smrg	    case fontMenu_font5:
45490bd37d32Smrg		face_size = LikeBitmap(135.0);
45500bd37d32Smrg		break;
45510bd37d32Smrg	    case fontMenu_font6:
45520bd37d32Smrg		face_size = LikeBitmap(200.0);
45530bd37d32Smrg		break;
4554d4fba8b9Smrg	    case fontMenu_font7:
4555d4fba8b9Smrg		face_size = LikeBitmap(240.0);
4556d4fba8b9Smrg		break;
45570bd37d32Smrg	    }
45580bd37d32Smrg	    TRACE(("builtin[%d] -> %f\n", fontnum, face_size));
45590bd37d32Smrg	}
45600bd37d32Smrg	xw->misc.face_size[fontnum] = (float) face_size;
45610bd37d32Smrg    }
45620bd37d32Smrg}
45630bd37d32Smrg
45640bd37d32Smrg/* no selection or escape */
45650bd37d32Smrg#define NMENU_RENDERFONTS (fontMenu_lastBuiltin + 1)
45660bd37d32Smrg
45670bd37d32Smrg/*
45680bd37d32Smrg * Workaround for breakage in font-packages - check if all of the bitmap font
45690bd37d32Smrg * sizes are the same, and if we're using TrueType fonts.
45700bd37d32Smrg */
45712eaa94a1Schristosstatic Boolean
45722eaa94a1SchristosuseFaceSizes(XtermWidget xw)
45732eaa94a1Schristos{
45742eaa94a1Schristos    Boolean result = False;
45752eaa94a1Schristos
4576d4fba8b9Smrg    TRACE(("useFaceSizes " TRACE_L "\n"));
45772eaa94a1Schristos    if (UsingRenderFont(xw)) {
45780bd37d32Smrg	Boolean nonzero = True;
4579037a25ddSmrg	int n;
45800bd37d32Smrg
45812eaa94a1Schristos	for (n = 0; n < NMENU_RENDERFONTS; ++n) {
4582d4fba8b9Smrg	    if (xw->misc.face_size[n] <= 0.0f) {
45830bd37d32Smrg		nonzero = False;
45842eaa94a1Schristos		break;
45852eaa94a1Schristos	    }
45862eaa94a1Schristos	}
45870bd37d32Smrg	if (!nonzero) {
4588956cc18dSsnj	    Boolean broken_fonts = True;
4589956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
45900bd37d32Smrg	    long first;
4591956cc18dSsnj
4592956cc18dSsnj	    lookupFontSizes(xw);
45930bd37d32Smrg	    first = screen->menu_font_sizes[0];
4594956cc18dSsnj	    for (n = 0; n < NMENUFONTS; n++) {
4595956cc18dSsnj		if (screen->menu_font_sizes[n] > 0
4596956cc18dSsnj		    && screen->menu_font_sizes[n] != first) {
4597956cc18dSsnj		    broken_fonts = False;
4598956cc18dSsnj		    break;
4599956cc18dSsnj		}
4600956cc18dSsnj	    }
4601956cc18dSsnj
4602956cc18dSsnj	    if (broken_fonts) {
4603956cc18dSsnj
4604956cc18dSsnj		TRACE(("bitmap fonts are broken - set faceSize resources\n"));
4605956cc18dSsnj		for (n = 0; n < NMENUFONTS; n++) {
46060bd37d32Smrg		    fillInFaceSize(xw, n);
4607956cc18dSsnj		}
4608956cc18dSsnj
4609956cc18dSsnj	    }
4610956cc18dSsnj	}
46110bd37d32Smrg	result = True;
46122eaa94a1Schristos    }
4613d4fba8b9Smrg    TRACE((TRACE_R " useFaceSizes %d\n", result));
46142eaa94a1Schristos    return result;
46152eaa94a1Schristos}
46160bd37d32Smrg#endif /* OPT_RENDERFONT */
46172eaa94a1Schristos
4618b6fea0ceSmrg#if OPT_SHIFT_FONTS
4619d522f475Smrg/*
4620d522f475Smrg * Find the index of a larger/smaller font (according to the sign of 'relative'
4621d522f475Smrg * and its magnitude), starting from the 'old' index.
4622d522f475Smrg */
4623d522f475Smrgint
4624d522f475SmrglookupRelativeFontSize(XtermWidget xw, int old, int relative)
4625d522f475Smrg{
4626d522f475Smrg    TScreen *screen = TScreenOf(xw);
4627037a25ddSmrg    int m = -1;
4628d522f475Smrg
46292eaa94a1Schristos    TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative));
4630d522f475Smrg    if (!IsIcon(screen)) {
46312eaa94a1Schristos#if OPT_RENDERFONT
46322eaa94a1Schristos	if (useFaceSizes(xw)) {
46332eaa94a1Schristos	    TRACE(("...using FaceSize\n"));
46342eaa94a1Schristos	    if (relative != 0) {
4635037a25ddSmrg		int n;
46362eaa94a1Schristos		for (n = 0; n < NMENU_RENDERFONTS; ++n) {
46370bd37d32Smrg		    fillInFaceSize(xw, n);
46382eaa94a1Schristos		    if (xw->misc.face_size[n] > 0 &&
46392eaa94a1Schristos			xw->misc.face_size[n] != xw->misc.face_size[old]) {
46402eaa94a1Schristos			int cmp_0 = ((xw->misc.face_size[n] >
46412eaa94a1Schristos				      xw->misc.face_size[old])
46422eaa94a1Schristos				     ? relative
46432eaa94a1Schristos				     : -relative);
46442eaa94a1Schristos			int cmp_m = ((m < 0)
46452eaa94a1Schristos				     ? 1
46462eaa94a1Schristos				     : ((xw->misc.face_size[n] <
46472eaa94a1Schristos					 xw->misc.face_size[m])
46482eaa94a1Schristos					? relative
46492eaa94a1Schristos					: -relative));
46502eaa94a1Schristos			if (cmp_0 > 0 && cmp_m > 0) {
46512eaa94a1Schristos			    m = n;
46522eaa94a1Schristos			}
4653d522f475Smrg		    }
4654d522f475Smrg		}
4655d522f475Smrg	    }
46562eaa94a1Schristos	} else
46572eaa94a1Schristos#endif
46582eaa94a1Schristos	{
46592eaa94a1Schristos	    TRACE(("...using bitmap areas\n"));
46602eaa94a1Schristos	    lookupFontSizes(xw);
46612eaa94a1Schristos	    if (relative != 0) {
4662037a25ddSmrg		int n;
46632eaa94a1Schristos		for (n = 0; n < NMENUFONTS; ++n) {
46642eaa94a1Schristos		    if (screen->menu_font_sizes[n] > 0 &&
46652eaa94a1Schristos			screen->menu_font_sizes[n] !=
46662eaa94a1Schristos			screen->menu_font_sizes[old]) {
46672eaa94a1Schristos			int cmp_0 = ((screen->menu_font_sizes[n] >
46682eaa94a1Schristos				      screen->menu_font_sizes[old])
46692eaa94a1Schristos				     ? relative
46702eaa94a1Schristos				     : -relative);
46712eaa94a1Schristos			int cmp_m = ((m < 0)
46722eaa94a1Schristos				     ? 1
46732eaa94a1Schristos				     : ((screen->menu_font_sizes[n] <
46742eaa94a1Schristos					 screen->menu_font_sizes[m])
46752eaa94a1Schristos					? relative
46762eaa94a1Schristos					: -relative));
46772eaa94a1Schristos			if (cmp_0 > 0 && cmp_m > 0) {
46782eaa94a1Schristos			    m = n;
46792eaa94a1Schristos			}
46802eaa94a1Schristos		    }
46812eaa94a1Schristos		}
4682d522f475Smrg	    }
4683d522f475Smrg	}
46842eaa94a1Schristos	TRACE(("...new index %d\n", m));
46852eaa94a1Schristos	if (m >= 0) {
46862eaa94a1Schristos	    if (relative > 1)
46872eaa94a1Schristos		m = lookupRelativeFontSize(xw, m, relative - 1);
46882eaa94a1Schristos	    else if (relative < -1)
46892eaa94a1Schristos		m = lookupRelativeFontSize(xw, m, relative + 1);
46902eaa94a1Schristos	}
4691d522f475Smrg    }
4692d522f475Smrg    return m;
4693d522f475Smrg}
4694d522f475Smrg
4695d522f475Smrg/* ARGSUSED */
4696d522f475Smrgvoid
4697d4fba8b9SmrgHandleLargerFont(Widget w,
46989a64e1c5Smrg		 XEvent *event GCC_UNUSED,
4699fa3f02f3Smrg		 String *params GCC_UNUSED,
4700d522f475Smrg		 Cardinal *param_count GCC_UNUSED)
4701d522f475Smrg{
4702956cc18dSsnj    XtermWidget xw;
4703d522f475Smrg
470420d2c4d2Smrg    TRACE(("Handle larger-vt-font for %p\n", (void *) w));
4705956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
4706d522f475Smrg	if (xw->misc.shift_fonts) {
4707956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
4708d522f475Smrg	    int m;
4709d522f475Smrg
4710d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, 1);
4711d522f475Smrg	    if (m >= 0) {
4712d522f475Smrg		SetVTFont(xw, m, True, NULL);
4713d522f475Smrg	    } else {
471420d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
4715d522f475Smrg	    }
4716d522f475Smrg	}
4717d522f475Smrg    }
4718d522f475Smrg}
4719d522f475Smrg
4720d522f475Smrg/* ARGSUSED */
4721d522f475Smrgvoid
4722d4fba8b9SmrgHandleSmallerFont(Widget w,
47239a64e1c5Smrg		  XEvent *event GCC_UNUSED,
4724fa3f02f3Smrg		  String *params GCC_UNUSED,
4725d522f475Smrg		  Cardinal *param_count GCC_UNUSED)
4726d522f475Smrg{
4727956cc18dSsnj    XtermWidget xw;
4728d522f475Smrg
472920d2c4d2Smrg    TRACE(("Handle smaller-vt-font for %p\n", (void *) w));
4730956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
4731d522f475Smrg	if (xw->misc.shift_fonts) {
4732956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
4733d522f475Smrg	    int m;
4734d522f475Smrg
4735d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, -1);
4736d522f475Smrg	    if (m >= 0) {
4737d522f475Smrg		SetVTFont(xw, m, True, NULL);
4738d522f475Smrg	    } else {
473920d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
4740d522f475Smrg	    }
4741d522f475Smrg	}
4742d522f475Smrg    }
4743d522f475Smrg}
4744b6fea0ceSmrg#endif /* OPT_SHIFT_FONTS */
4745d522f475Smrg
4746d522f475Smrgint
4747d522f475SmrgxtermGetFont(const char *param)
4748d522f475Smrg{
4749d522f475Smrg    int fontnum;
4750d522f475Smrg
4751d522f475Smrg    switch (param[0]) {
4752d522f475Smrg    case 'd':
4753d522f475Smrg    case 'D':
4754d522f475Smrg    case '0':
4755d522f475Smrg	fontnum = fontMenu_default;
4756d522f475Smrg	break;
4757d522f475Smrg    case '1':
4758d522f475Smrg	fontnum = fontMenu_font1;
4759d522f475Smrg	break;
4760d522f475Smrg    case '2':
4761d522f475Smrg	fontnum = fontMenu_font2;
4762d522f475Smrg	break;
4763d522f475Smrg    case '3':
4764d522f475Smrg	fontnum = fontMenu_font3;
4765d522f475Smrg	break;
4766d522f475Smrg    case '4':
4767d522f475Smrg	fontnum = fontMenu_font4;
4768d522f475Smrg	break;
4769d522f475Smrg    case '5':
4770d522f475Smrg	fontnum = fontMenu_font5;
4771d522f475Smrg	break;
4772d522f475Smrg    case '6':
4773d522f475Smrg	fontnum = fontMenu_font6;
4774d522f475Smrg	break;
4775d4fba8b9Smrg    case '7':
4776d4fba8b9Smrg	fontnum = fontMenu_font7;
4777d4fba8b9Smrg	break;
4778d522f475Smrg    case 'e':
4779d522f475Smrg    case 'E':
4780d522f475Smrg	fontnum = fontMenu_fontescape;
4781d522f475Smrg	break;
4782d522f475Smrg    case 's':
4783d522f475Smrg    case 'S':
4784d522f475Smrg	fontnum = fontMenu_fontsel;
4785d522f475Smrg	break;
4786d522f475Smrg    default:
4787d522f475Smrg	fontnum = -1;
4788d522f475Smrg	break;
4789d522f475Smrg    }
4790d4fba8b9Smrg    TRACE(("xtermGetFont(%s) ->%d\n", NonNull(param), fontnum));
4791d522f475Smrg    return fontnum;
4792d522f475Smrg}
4793d522f475Smrg
4794d522f475Smrg/* ARGSUSED */
4795d522f475Smrgvoid
4796d4fba8b9SmrgHandleSetFont(Widget w,
47979a64e1c5Smrg	      XEvent *event GCC_UNUSED,
4798fa3f02f3Smrg	      String *params,
4799d522f475Smrg	      Cardinal *param_count)
4800d522f475Smrg{
4801956cc18dSsnj    XtermWidget xw;
4802956cc18dSsnj
4803956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
4804d522f475Smrg	int fontnum;
4805d522f475Smrg	VTFontNames fonts;
4806d522f475Smrg
4807d522f475Smrg	memset(&fonts, 0, sizeof(fonts));
4808d522f475Smrg
4809d522f475Smrg	if (*param_count == 0) {
4810d522f475Smrg	    fontnum = fontMenu_default;
4811d522f475Smrg	} else {
4812d522f475Smrg	    Cardinal maxparams = 1;	/* total number of params allowed */
4813d522f475Smrg	    int result = xtermGetFont(params[0]);
4814d522f475Smrg
4815d522f475Smrg	    switch (result) {
4816d522f475Smrg	    case fontMenu_default:	/* FALLTHRU */
4817d522f475Smrg	    case fontMenu_font1:	/* FALLTHRU */
4818d522f475Smrg	    case fontMenu_font2:	/* FALLTHRU */
4819d522f475Smrg	    case fontMenu_font3:	/* FALLTHRU */
4820d522f475Smrg	    case fontMenu_font4:	/* FALLTHRU */
4821d522f475Smrg	    case fontMenu_font5:	/* FALLTHRU */
4822d522f475Smrg	    case fontMenu_font6:	/* FALLTHRU */
4823d4fba8b9Smrg	    case fontMenu_font7:	/* FALLTHRU */
4824d522f475Smrg		break;
4825d522f475Smrg	    case fontMenu_fontescape:
4826d522f475Smrg#if OPT_WIDE_CHARS
4827d522f475Smrg		maxparams = 5;
4828d522f475Smrg#else
4829d522f475Smrg		maxparams = 3;
4830d522f475Smrg#endif
4831d522f475Smrg		break;
4832d522f475Smrg	    case fontMenu_fontsel:
4833d522f475Smrg		maxparams = 2;
4834d522f475Smrg		break;
4835d522f475Smrg	    default:
483620d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
4837d522f475Smrg		return;
4838d522f475Smrg	    }
4839d522f475Smrg	    fontnum = result;
4840d522f475Smrg
4841d522f475Smrg	    if (*param_count > maxparams) {	/* see if extra args given */
484220d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
4843d522f475Smrg		return;
4844d522f475Smrg	    }
4845d522f475Smrg	    switch (*param_count) {	/* assign 'em */
4846d522f475Smrg#if OPT_WIDE_CHARS
4847d522f475Smrg	    case 5:
4848dfb07bc7Smrg		fonts.f_wb = x_strdup(params[4]);
4849d522f475Smrg		/* FALLTHRU */
4850d522f475Smrg	    case 4:
4851dfb07bc7Smrg		fonts.f_w = x_strdup(params[3]);
4852d522f475Smrg#endif
4853dfb07bc7Smrg		/* FALLTHRU */
4854d522f475Smrg	    case 3:
4855dfb07bc7Smrg		fonts.f_b = x_strdup(params[2]);
4856d522f475Smrg		/* FALLTHRU */
4857d522f475Smrg	    case 2:
4858dfb07bc7Smrg		fonts.f_n = x_strdup(params[1]);
4859d522f475Smrg		break;
4860d522f475Smrg	    }
4861d522f475Smrg	}
4862d522f475Smrg
4863956cc18dSsnj	SetVTFont(xw, fontnum, True, &fonts);
4864d522f475Smrg    }
4865d522f475Smrg}
4866d522f475Smrg
4867d522f475Smrgvoid
4868d522f475SmrgSetVTFont(XtermWidget xw,
4869d522f475Smrg	  int which,
4870d522f475Smrg	  Bool doresize,
4871d522f475Smrg	  const VTFontNames * fonts)
4872d522f475Smrg{
4873956cc18dSsnj    TScreen *screen = TScreenOf(xw);
4874d522f475Smrg
4875d522f475Smrg    TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which,
4876d522f475Smrg	   (fonts && fonts->f_n) ? fonts->f_n : "<null>",
4877d522f475Smrg	   (fonts && fonts->f_b) ? fonts->f_b : "<null>"));
4878d522f475Smrg
4879d522f475Smrg    if (IsIcon(screen)) {
488020d2c4d2Smrg	Bell(xw, XkbBI_MinorError, 0);
4881d522f475Smrg    } else if (which >= 0 && which < NMENUFONTS) {
4882d522f475Smrg	VTFontNames myfonts;
4883d522f475Smrg
4884d522f475Smrg	memset(&myfonts, 0, sizeof(myfonts));
4885d522f475Smrg	if (fonts != 0)
4886d522f475Smrg	    myfonts = *fonts;
4887d522f475Smrg
4888d522f475Smrg	if (which == fontMenu_fontsel) {	/* go get the selection */
4889d522f475Smrg	    FindFontSelection(xw, myfonts.f_n, False);
4890d522f475Smrg	} else {
4891d522f475Smrg	    int oldFont = screen->menu_font_number;
4892d522f475Smrg
4893d522f475Smrg#define USE_CACHED(field, name) \
4894d522f475Smrg	    if (myfonts.field == 0) { \
4895492d43a5Smrg		myfonts.field = x_strdup(screen->menu_font_names[which][name]); \
4896d522f475Smrg		TRACE(("set myfonts." #field " from menu_font_names[%d][" #name "] %s\n", \
4897d522f475Smrg		       which, NonNull(myfonts.field))); \
4898d522f475Smrg	    } else { \
4899d522f475Smrg		TRACE(("set myfonts." #field " reused\n")); \
4900d522f475Smrg	    }
490120d2c4d2Smrg#define SAVE_FNAME(field, name) \
490220d2c4d2Smrg	    if (myfonts.field != 0) { \
490320d2c4d2Smrg		if (screen->menu_font_names[which][name] == 0 \
490420d2c4d2Smrg		 || strcmp(screen->menu_font_names[which][name], myfonts.field)) { \
4905d4fba8b9Smrg		    TRACE(("updating menu_font_names[%d][" #name "] to \"%s\"\n", \
490620d2c4d2Smrg			   which, myfonts.field)); \
49079a64e1c5Smrg		    FREE_STRING(screen->menu_font_names[which][name]); \
490820d2c4d2Smrg		    screen->menu_font_names[which][name] = x_strdup(myfonts.field); \
490920d2c4d2Smrg		} \
491020d2c4d2Smrg	    }
491120d2c4d2Smrg
4912d522f475Smrg	    USE_CACHED(f_n, fNorm);
4913d522f475Smrg	    USE_CACHED(f_b, fBold);
4914d522f475Smrg#if OPT_WIDE_CHARS
4915d522f475Smrg	    USE_CACHED(f_w, fWide);
4916d522f475Smrg	    USE_CACHED(f_wb, fWBold);
4917d522f475Smrg#endif
4918d522f475Smrg	    if (xtermLoadFont(xw,
4919d522f475Smrg			      &myfonts,
4920d522f475Smrg			      doresize, which)) {
492120d2c4d2Smrg		/*
492220d2c4d2Smrg		 * If successful, save the data so that a subsequent query via
492320d2c4d2Smrg		 * OSC-50 will return the expected values.
492420d2c4d2Smrg		 */
492520d2c4d2Smrg		SAVE_FNAME(f_n, fNorm);
492620d2c4d2Smrg		SAVE_FNAME(f_b, fBold);
492720d2c4d2Smrg#if OPT_WIDE_CHARS
492820d2c4d2Smrg		SAVE_FNAME(f_w, fWide);
492920d2c4d2Smrg		SAVE_FNAME(f_wb, fWBold);
493020d2c4d2Smrg#endif
4931d522f475Smrg	    } else {
493294644356Smrg		(void) xtermLoadFont(xw,
493394644356Smrg				     xtermFontName(screen->MenuFontName(oldFont)),
493494644356Smrg				     doresize, oldFont);
493520d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
4936d522f475Smrg	    }
49379a64e1c5Smrg	    FREE_FNAME(f_n);
49389a64e1c5Smrg	    FREE_FNAME(f_b);
49399a64e1c5Smrg#if OPT_WIDE_CHARS
49409a64e1c5Smrg	    FREE_FNAME(f_w);
49419a64e1c5Smrg	    FREE_FNAME(f_wb);
49429a64e1c5Smrg#endif
4943d522f475Smrg	}
494420d2c4d2Smrg    } else {
494520d2c4d2Smrg	Bell(xw, XkbBI_MinorError, 0);
4946d522f475Smrg    }
4947d522f475Smrg    return;
4948d522f475Smrg}
4949dfb07bc7Smrg
4950dfb07bc7Smrg#if OPT_RENDERFONT
4951dfb07bc7Smrgstatic void
4952dfb07bc7SmrgtrimSizeFromFace(char *face_name, float *face_size)
4953dfb07bc7Smrg{
4954dfb07bc7Smrg    char *first = strstr(face_name, ":size=");
4955dfb07bc7Smrg    if (first == 0) {
4956dfb07bc7Smrg	first = face_name;
4957dfb07bc7Smrg    } else {
4958dfb07bc7Smrg	first++;
4959dfb07bc7Smrg    }
4960dfb07bc7Smrg    if (!strncmp(first, "size=", (size_t) 5)) {
4961dfb07bc7Smrg	char *last = strchr(first, ':');
4962dfb07bc7Smrg	char mark;
4963dfb07bc7Smrg	float value;
4964dfb07bc7Smrg	char extra;
4965dfb07bc7Smrg	TRACE(("...before trimming, font = \"%s\"\n", face_name));
4966dfb07bc7Smrg	if (last == 0)
4967dfb07bc7Smrg	    last = first + strlen(first);
4968dfb07bc7Smrg	mark = *last;
4969dfb07bc7Smrg	*last = '\0';
4970dfb07bc7Smrg	if (sscanf(first, "size=%g%c", &value, &extra) == 1) {
4971dfb07bc7Smrg	    TRACE(("...trimmed size from font: %g\n", value));
4972dfb07bc7Smrg	    if (face_size != 0)
4973dfb07bc7Smrg		*face_size = value;
4974dfb07bc7Smrg	}
4975dfb07bc7Smrg	if (mark) {
4976dfb07bc7Smrg	    while ((*first++ = *++last) != '\0') {
4977dfb07bc7Smrg		;
4978dfb07bc7Smrg	    }
4979dfb07bc7Smrg	} else {
4980dfb07bc7Smrg	    if (first != face_name)
4981dfb07bc7Smrg		--first;
4982dfb07bc7Smrg	    *first = '\0';
4983dfb07bc7Smrg	}
4984dfb07bc7Smrg	TRACE(("...after trimming, font = \"%s\"\n", face_name));
4985dfb07bc7Smrg    }
4986dfb07bc7Smrg}
4987dfb07bc7Smrg#endif
4988dfb07bc7Smrg
4989dfb07bc7Smrg/*
4990dfb07bc7Smrg * Save a font specification to the proper list.
4991dfb07bc7Smrg */
4992dfb07bc7Smrgstatic void
4993dfb07bc7Smrgsave2FontList(XtermWidget xw,
4994dfb07bc7Smrg	      const char *name,
4995dfb07bc7Smrg	      XtermFontNames * fontnames,
4996dfb07bc7Smrg	      VTFontEnum which,
4997dfb07bc7Smrg	      const char *source,
4998dfb07bc7Smrg	      Bool ttf)
4999dfb07bc7Smrg{
5000dfb07bc7Smrg    char *value;
5001dfb07bc7Smrg    size_t plen;
5002dfb07bc7Smrg    Bool marked = False;
5003dfb07bc7Smrg    Bool use_ttf = ttf;
5004dfb07bc7Smrg
5005dfb07bc7Smrg    (void) xw;
5006dfb07bc7Smrg
5007dfb07bc7Smrg    if (source == 0)
5008dfb07bc7Smrg	source = "";
5009dfb07bc7Smrg    while (isspace(CharOf(*source)))
5010dfb07bc7Smrg	++source;
5011dfb07bc7Smrg
5012dfb07bc7Smrg    /* fontconfig patterns can contain ':' separators, but we'll treat
5013dfb07bc7Smrg     * a leading prefix specially to denote whether the pattern might be
5014dfb07bc7Smrg     * XLFD ("x" or "xlfd") versus Xft ("xft").
5015dfb07bc7Smrg     */
5016dfb07bc7Smrg    for (plen = 0; source[plen] != '\0'; ++plen) {
5017dfb07bc7Smrg	if (source[plen] == ':') {
5018dfb07bc7Smrg	    marked = True;
5019dfb07bc7Smrg	    switch (plen) {
5020dfb07bc7Smrg	    case 0:
5021dfb07bc7Smrg		++plen;		/* trim leading ':' */
5022dfb07bc7Smrg		break;
5023dfb07bc7Smrg	    case 1:
5024dfb07bc7Smrg		if (!strncmp(source, "x", plen)) {
5025dfb07bc7Smrg		    ++plen;
5026dfb07bc7Smrg		    use_ttf = False;
5027dfb07bc7Smrg		} else {
5028dfb07bc7Smrg		    marked = False;
5029dfb07bc7Smrg		}
5030dfb07bc7Smrg		break;
5031dfb07bc7Smrg	    case 3:
5032dfb07bc7Smrg		if (!strncmp(source, "xft", plen)) {
5033dfb07bc7Smrg		    ++plen;
5034dfb07bc7Smrg		    use_ttf = True;
5035dfb07bc7Smrg		} else {
5036dfb07bc7Smrg		    marked = False;
5037dfb07bc7Smrg		}
5038dfb07bc7Smrg		break;
5039dfb07bc7Smrg	    case 4:
5040dfb07bc7Smrg		if (!strncmp(source, "xlfd", plen)) {
5041dfb07bc7Smrg		    ++plen;
5042dfb07bc7Smrg		    use_ttf = False;
5043dfb07bc7Smrg		} else {
5044dfb07bc7Smrg		    marked = False;
5045dfb07bc7Smrg		}
5046dfb07bc7Smrg		break;
5047dfb07bc7Smrg	    default:
5048dfb07bc7Smrg		marked = False;
5049dfb07bc7Smrg		plen = 0;
5050dfb07bc7Smrg		break;
5051dfb07bc7Smrg	    }
5052dfb07bc7Smrg	    break;
5053dfb07bc7Smrg	}
5054dfb07bc7Smrg    }
5055dfb07bc7Smrg    if (!marked)
5056dfb07bc7Smrg	plen = 0;
5057dfb07bc7Smrg    value = x_strtrim(source + plen);
5058dfb07bc7Smrg    if (value != 0) {
5059dfb07bc7Smrg	Bool success = False;
5060dfb07bc7Smrg#if OPT_RENDERFONT
5061dfb07bc7Smrg	VTFontList *target = (use_ttf
5062dfb07bc7Smrg			      ? &(fontnames->xft)
5063dfb07bc7Smrg			      : &(fontnames->x11));
5064dfb07bc7Smrg#else
5065dfb07bc7Smrg	VTFontList *target = &(fontnames->x11);
5066dfb07bc7Smrg#endif
5067dfb07bc7Smrg	char ***list = 0;
5068dfb07bc7Smrg	char **next = 0;
5069dfb07bc7Smrg	size_t count = 0;
5070dfb07bc7Smrg
5071dfb07bc7Smrg	(void) use_ttf;
5072dfb07bc7Smrg	switch (which) {
5073dfb07bc7Smrg	case fNorm:
5074dfb07bc7Smrg	    list = &(target->list_n);
5075dfb07bc7Smrg	    break;
5076dfb07bc7Smrg	case fBold:
5077dfb07bc7Smrg	    list = &(target->list_b);
5078dfb07bc7Smrg	    break;
5079dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
5080dfb07bc7Smrg	case fItal:
5081dfb07bc7Smrg	    list = &(target->list_i);
5082dfb07bc7Smrg	    break;
5083d4fba8b9Smrg	case fBtal:
5084d4fba8b9Smrg	    list = &(target->list_bi);
5085d4fba8b9Smrg	    break;
5086dfb07bc7Smrg#endif
5087dfb07bc7Smrg#if OPT_WIDE_CHARS
5088dfb07bc7Smrg	case fWide:
5089dfb07bc7Smrg	    list = &(target->list_w);
5090dfb07bc7Smrg	    break;
5091dfb07bc7Smrg	case fWBold:
5092dfb07bc7Smrg	    list = &(target->list_wb);
5093dfb07bc7Smrg	    break;
5094dfb07bc7Smrg	case fWItal:
5095dfb07bc7Smrg	    list = &(target->list_wi);
5096dfb07bc7Smrg	    break;
5097d4fba8b9Smrg	case fWBtal:
5098d4fba8b9Smrg	    list = &(target->list_wbi);
5099d4fba8b9Smrg	    break;
5100dfb07bc7Smrg#endif
5101dfb07bc7Smrg	case fMAX:
5102dfb07bc7Smrg	    list = 0;
5103dfb07bc7Smrg	    break;
5104dfb07bc7Smrg	}
5105dfb07bc7Smrg
5106dfb07bc7Smrg	if (list != 0) {
5107dfb07bc7Smrg	    success = True;
5108dfb07bc7Smrg	    if (*list != 0) {
5109dfb07bc7Smrg		while ((*list)[count] != 0) {
5110dfb07bc7Smrg		    if (IsEmpty((*list)[count])) {
5111dfb07bc7Smrg			TRACE(("... initial %s\n", value));
5112dfb07bc7Smrg			free((*list)[count]);
5113dfb07bc7Smrg			break;
5114dfb07bc7Smrg		    } else if (!strcmp(value, (*list)[count])) {
5115dfb07bc7Smrg			TRACE(("... duplicate %s\n", value));
5116dfb07bc7Smrg			success = False;
5117dfb07bc7Smrg			break;
5118dfb07bc7Smrg		    }
5119dfb07bc7Smrg		    ++count;
5120dfb07bc7Smrg		}
5121dfb07bc7Smrg	    }
5122dfb07bc7Smrg	    if (success) {
5123dfb07bc7Smrg		next = realloc(*list, sizeof(char *) * (count + 2));
5124dfb07bc7Smrg		if (next != 0) {
5125dfb07bc7Smrg#if OPT_RENDERFONT
5126dfb07bc7Smrg		    if (use_ttf) {
5127dfb07bc7Smrg			trimSizeFromFace(value,
5128dfb07bc7Smrg					 (count == 0 && which == fNorm)
5129dfb07bc7Smrg					 ? &(xw->misc.face_size[0])
5130dfb07bc7Smrg					 : (float *) 0);
5131dfb07bc7Smrg		    }
5132dfb07bc7Smrg#endif
5133dfb07bc7Smrg		    next[count++] = value;
5134dfb07bc7Smrg		    next[count] = 0;
5135dfb07bc7Smrg		    *list = next;
51368f44fb3bSmrg		    TRACE(("... saved \"%s\" \"%s\" %lu:\"%s\"\n",
5137dfb07bc7Smrg			   whichFontList(xw, target),
5138dfb07bc7Smrg			   whichFontList2(xw, *list),
5139dfb07bc7Smrg			   (unsigned long) count,
5140dfb07bc7Smrg			   value));
5141dfb07bc7Smrg		} else {
5142dfb07bc7Smrg		    fprintf(stderr,
5143dfb07bc7Smrg			    "realloc failure in save2FontList(%s)\n",
5144dfb07bc7Smrg			    name);
5145dfb07bc7Smrg		    freeFontList(list);
5146dfb07bc7Smrg		    success = False;
5147dfb07bc7Smrg		}
5148dfb07bc7Smrg	    }
5149dfb07bc7Smrg	}
5150dfb07bc7Smrg	if (success) {
5151d4fba8b9Smrg#if (MAX_XFT_FONTS == MAX_XLFD_FONTS)
5152d4fba8b9Smrg	    size_t limit = MAX_XFT_FONTS;
5153d4fba8b9Smrg#else
5154dfb07bc7Smrg	    size_t limit = use_ttf ? MAX_XFT_FONTS : MAX_XLFD_FONTS;
5155d4fba8b9Smrg#endif
5156d4fba8b9Smrg	    if (count > limit && *x_skip_blanks(value)) {
5157dfb07bc7Smrg		fprintf(stderr, "%s: too many fonts for %s, ignoring %s\n",
5158dfb07bc7Smrg			ProgramName,
5159dfb07bc7Smrg			whichFontEnum(which),
5160dfb07bc7Smrg			value);
5161dfb07bc7Smrg		if (list && *list) {
5162dfb07bc7Smrg		    free((*list)[limit]);
5163dfb07bc7Smrg		    (*list)[limit] = 0;
5164dfb07bc7Smrg		}
5165dfb07bc7Smrg	    }
5166dfb07bc7Smrg	} else {
5167dfb07bc7Smrg	    free(value);
5168dfb07bc7Smrg	}
5169dfb07bc7Smrg    }
5170dfb07bc7Smrg}
5171dfb07bc7Smrg
5172dfb07bc7Smrg/*
5173dfb07bc7Smrg * In principle, any of the font-name resources could be extended to be a list
5174dfb07bc7Smrg * of font-names.  That would be bad for performance, but as a basis for an
5175dfb07bc7Smrg * extension, parse the font-name as a comma-separated list, creating/updating
5176dfb07bc7Smrg * an array of font-names.
5177dfb07bc7Smrg */
5178dfb07bc7Smrgvoid
5179dfb07bc7SmrgallocFontList(XtermWidget xw,
5180dfb07bc7Smrg	      const char *name,
5181dfb07bc7Smrg	      XtermFontNames * target,
5182dfb07bc7Smrg	      VTFontEnum which,
5183dfb07bc7Smrg	      const char *source,
5184dfb07bc7Smrg	      Bool ttf)
5185dfb07bc7Smrg{
5186dfb07bc7Smrg    char *blob;
5187dfb07bc7Smrg
5188dfb07bc7Smrg    blob = x_strdup(source);
5189d4fba8b9Smrg    if (blob != 0) {
5190dfb07bc7Smrg	int n;
5191dfb07bc7Smrg	int pass;
5192dfb07bc7Smrg	char **list = 0;
5193dfb07bc7Smrg
51948f44fb3bSmrg	TRACE(("allocFontList %s name=\"%s\" source=\"%s\"\n",
51958f44fb3bSmrg	       whichFontEnum(which), name, blob));
5196dfb07bc7Smrg
5197dfb07bc7Smrg	for (pass = 0; pass < 2; ++pass) {
5198dfb07bc7Smrg	    unsigned count = 0;
5199dfb07bc7Smrg	    if (pass)
5200dfb07bc7Smrg		list[0] = blob;
5201dfb07bc7Smrg	    for (n = 0; blob[n] != '\0'; ++n) {
5202dfb07bc7Smrg		if (blob[n] == ',') {
5203dfb07bc7Smrg		    ++count;
5204dfb07bc7Smrg		    if (pass != 0) {
5205dfb07bc7Smrg			blob[n] = '\0';
5206dfb07bc7Smrg			list[count] = blob + n + 1;
5207dfb07bc7Smrg		    }
5208dfb07bc7Smrg		}
5209dfb07bc7Smrg	    }
5210dfb07bc7Smrg	    if (!pass) {
5211dfb07bc7Smrg		if (count == 0 && *blob == '\0')
5212dfb07bc7Smrg		    break;
5213dfb07bc7Smrg		list = TypeCallocN(char *, count + 2);
5214dfb07bc7Smrg		if (list == 0)
5215dfb07bc7Smrg		    break;
5216dfb07bc7Smrg	    }
5217dfb07bc7Smrg	}
5218dfb07bc7Smrg	if (list) {
5219dfb07bc7Smrg	    for (n = 0; list[n] != 0; ++n) {
5220dfb07bc7Smrg		if (*list[n]) {
5221dfb07bc7Smrg		    save2FontList(xw, name, target, which, list[n], ttf);
5222dfb07bc7Smrg		}
5223dfb07bc7Smrg	    }
5224dfb07bc7Smrg	    free(list);
5225dfb07bc7Smrg	}
5226dfb07bc7Smrg    }
5227dfb07bc7Smrg    free(blob);
5228dfb07bc7Smrg}
5229dfb07bc7Smrg
5230dfb07bc7Smrgstatic void
5231dfb07bc7SmrginitFontList(XtermWidget xw,
5232dfb07bc7Smrg	     const char *name,
5233dfb07bc7Smrg	     XtermFontNames * target,
5234dfb07bc7Smrg	     Bool ttf)
5235dfb07bc7Smrg{
5236dfb07bc7Smrg    int which;
5237dfb07bc7Smrg
5238dfb07bc7Smrg    TRACE(("initFontList(%s)\n", name));
5239dfb07bc7Smrg    for (which = 0; which < fMAX; ++which) {
5240dfb07bc7Smrg	save2FontList(xw, name, target, (VTFontEnum) which, "", ttf);
5241dfb07bc7Smrg    }
5242dfb07bc7Smrg}
5243dfb07bc7Smrg
5244dfb07bc7Smrgvoid
5245dfb07bc7SmrginitFontLists(XtermWidget xw)
5246dfb07bc7Smrg{
5247dfb07bc7Smrg    TRACE(("initFontLists\n"));
5248dfb07bc7Smrg    initFontList(xw, "x11 font", &(xw->work.fonts), False);
5249dfb07bc7Smrg#if OPT_RENDERFONT
5250dfb07bc7Smrg    initFontList(xw, "xft font", &(xw->work.fonts), True);
5251dfb07bc7Smrg#endif
5252dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
5253dfb07bc7Smrg    initFontList(xw, "cached font",
5254dfb07bc7Smrg		 &(xw->screen.cacheVTFonts.fonts), False);
5255dfb07bc7Smrg#endif
5256dfb07bc7Smrg}
5257dfb07bc7Smrg
5258dfb07bc7Smrgvoid
5259dfb07bc7SmrgcopyFontList(char ***targetp, char **source)
5260dfb07bc7Smrg{
5261dfb07bc7Smrg    freeFontList(targetp);
5262dfb07bc7Smrg
5263dfb07bc7Smrg    if (source != 0) {
5264dfb07bc7Smrg	int pass;
5265dfb07bc7Smrg	size_t count;
5266dfb07bc7Smrg
5267dfb07bc7Smrg	for (pass = 0; pass < 2; ++pass) {
5268dfb07bc7Smrg	    for (count = 0; source[count] != 0; ++count) {
5269dfb07bc7Smrg		if (pass)
5270dfb07bc7Smrg		    (*targetp)[count] = x_strdup(source[count]);
5271dfb07bc7Smrg	    }
5272dfb07bc7Smrg	    if (!pass) {
5273dfb07bc7Smrg		++count;
5274dfb07bc7Smrg		*targetp = TypeCallocN(char *, count);
5275dfb07bc7Smrg	    }
5276dfb07bc7Smrg	}
5277dfb07bc7Smrg    } else {
5278dfb07bc7Smrg	*targetp = TypeCallocN(char *, 2);
5279dfb07bc7Smrg	(*targetp)[0] = x_strdup("");
5280dfb07bc7Smrg    }
5281dfb07bc7Smrg}
5282dfb07bc7Smrg
5283dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
5284dfb07bc7Smrgstatic Boolean
5285dfb07bc7Smrgmerge_sublist(char ***targetp, char **source)
5286dfb07bc7Smrg{
5287dfb07bc7Smrg    Boolean result = False;
5288dfb07bc7Smrg    if ((*targetp == 0 || IsEmpty(**targetp)) && !IsEmpty(*source)) {
5289dfb07bc7Smrg	copyFontList(targetp, source);
5290dfb07bc7Smrg	result = True;
5291dfb07bc7Smrg    }
5292dfb07bc7Smrg    return result;
5293dfb07bc7Smrg}
5294dfb07bc7Smrg#endif
5295dfb07bc7Smrg
5296dfb07bc7Smrgvoid
5297dfb07bc7SmrgfreeFontList(char ***targetp)
5298dfb07bc7Smrg{
5299dfb07bc7Smrg    if (targetp != 0) {
5300dfb07bc7Smrg	char **target = *targetp;
5301dfb07bc7Smrg	if (target != 0) {
5302dfb07bc7Smrg	    int n;
5303dfb07bc7Smrg	    for (n = 0; target[n] != 0; ++n) {
5304dfb07bc7Smrg		free(target[n]);
5305dfb07bc7Smrg	    }
5306dfb07bc7Smrg	    free(target);
5307dfb07bc7Smrg	    *targetp = 0;
5308dfb07bc7Smrg	}
5309dfb07bc7Smrg    }
5310dfb07bc7Smrg}
5311dfb07bc7Smrg
5312dfb07bc7Smrgvoid
5313dfb07bc7SmrgfreeFontLists(VTFontList * lists)
5314dfb07bc7Smrg{
5315dfb07bc7Smrg    int which;
5316dfb07bc7Smrg
5317dfb07bc7Smrg    TRACE(("freeFontLists\n"));
5318dfb07bc7Smrg    for (which = 0; which < fMAX; ++which) {
5319dfb07bc7Smrg	char ***target = 0;
5320dfb07bc7Smrg	switch (which) {
5321dfb07bc7Smrg	case fNorm:
5322dfb07bc7Smrg	    target = &(lists->list_n);
5323dfb07bc7Smrg	    break;
5324dfb07bc7Smrg	case fBold:
5325dfb07bc7Smrg	    target = &(lists->list_b);
5326dfb07bc7Smrg	    break;
5327dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
5328dfb07bc7Smrg	case fItal:
5329dfb07bc7Smrg	    target = &(lists->list_i);
5330dfb07bc7Smrg	    break;
5331d4fba8b9Smrg	case fBtal:
5332d4fba8b9Smrg	    target = &(lists->list_bi);
5333d4fba8b9Smrg	    break;
5334dfb07bc7Smrg#endif
5335dfb07bc7Smrg#if OPT_WIDE_CHARS
5336dfb07bc7Smrg	case fWide:
5337dfb07bc7Smrg	    target = &(lists->list_w);
5338dfb07bc7Smrg	    break;
5339dfb07bc7Smrg	case fWBold:
5340dfb07bc7Smrg	    target = &(lists->list_wb);
5341dfb07bc7Smrg	    break;
5342dfb07bc7Smrg	case fWItal:
5343dfb07bc7Smrg	    target = &(lists->list_wi);
5344dfb07bc7Smrg	    break;
5345d4fba8b9Smrg	case fWBtal:
5346d4fba8b9Smrg	    target = &(lists->list_wbi);
5347d4fba8b9Smrg	    break;
5348dfb07bc7Smrg#endif
5349dfb07bc7Smrg	default:
5350dfb07bc7Smrg	    target = 0;
5351dfb07bc7Smrg	    break;
5352dfb07bc7Smrg	}
5353dfb07bc7Smrg	freeFontList(target);
5354dfb07bc7Smrg    }
5355dfb07bc7Smrg}
5356dfb07bc7Smrg
5357dfb07bc7Smrg/*
5358dfb07bc7Smrg * Return a pointer to the XLFD font information for a given font class.
5359dfb07bc7Smrg * XXX make this allocate the font on demand.
5360dfb07bc7Smrg */
5361dfb07bc7SmrgXTermFonts *
5362dfb07bc7SmrggetNormalFont(TScreen *screen, int which)
5363dfb07bc7Smrg{
5364dfb07bc7Smrg    XTermFonts *result = 0;
5365dfb07bc7Smrg    if (which >= 0 && which < fMAX)
5366d4fba8b9Smrg	result = GetNormalFont(screen, which);
5367dfb07bc7Smrg    return result;
5368dfb07bc7Smrg}
5369dfb07bc7Smrg
5370dfb07bc7Smrg#if OPT_DEC_CHRSET
5371dfb07bc7SmrgXTermFonts *
5372dfb07bc7SmrggetDoubleFont(TScreen *screen, int which)
5373dfb07bc7Smrg{
5374dfb07bc7Smrg    XTermFonts *result = 0;
5375dfb07bc7Smrg    if ((int) which >= 0 && which < NUM_CHRSET)
5376d4fba8b9Smrg	result = GetDoubleFont(screen, which);
5377d4fba8b9Smrg    return result;
5378d4fba8b9Smrg}
5379d4fba8b9Smrg
5380d4fba8b9Smrg#if OPT_RENDERFONT
5381d4fba8b9SmrgXftFont *
5382d4fba8b9SmrggetDoubleXftFont(XTermDraw * params, unsigned chrset, unsigned attr_flags)
5383d4fba8b9Smrg{
5384d4fba8b9Smrg    XftFont *result = 0;
5385d4fba8b9Smrg
5386d4fba8b9Smrg    XtermWidget xw = params->xw;
5387d4fba8b9Smrg    TScreen *screen = TScreenOf(xw);
5388d4fba8b9Smrg    XftPattern *top_pattern;
5389d4fba8b9Smrg    int fontnum = screen->menu_font_number;
5390d4fba8b9Smrg    const char *face_name = getFaceName(xw, False);
5391d4fba8b9Smrg
5392d4fba8b9Smrg    if (chrset != CSET_SWL
5393d4fba8b9Smrg	&& (top_pattern = XftNameParse(face_name)) != 0) {
5394d4fba8b9Smrg	double face_size = (double) xw->misc.face_size[fontnum];
5395d4fba8b9Smrg	XftPattern *sub_pattern = XftPatternDuplicate(top_pattern);
5396d4fba8b9Smrg
5397d4fba8b9Smrg	switch (chrset) {
5398d4fba8b9Smrg	case CSET_DHL_TOP:
5399d4fba8b9Smrg	    /* FALLTHRU */
5400d4fba8b9Smrg	case CSET_DHL_BOT:
5401d4fba8b9Smrg	    face_size *= 2;
5402d4fba8b9Smrg	    XftPatternBuild(sub_pattern,
5403d4fba8b9Smrg			    NormXftPattern,
5404d4fba8b9Smrg			    (void *) 0);
5405d4fba8b9Smrg	    break;
5406d4fba8b9Smrg	case CSET_DWL:
5407d4fba8b9Smrg	    XftPatternBuild(sub_pattern,
5408d4fba8b9Smrg			    NormXftPattern,
5409d4fba8b9Smrg			    FC_ASPECT, XftTypeDouble, 2.0,
5410d4fba8b9Smrg			    (void *) 0);
5411d4fba8b9Smrg	    break;
5412d4fba8b9Smrg	}
5413d4fba8b9Smrg	if (attr_flags & BOLD) {
5414d4fba8b9Smrg	    XftPatternBuild(sub_pattern,
5415d4fba8b9Smrg			    XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD,
5416d4fba8b9Smrg			    (void *) 0);
5417d4fba8b9Smrg	}
5418d4fba8b9Smrg	result = xtermOpenXft(xw, face_name, sub_pattern, "doublesize");
5419d4fba8b9Smrg    }
5420dfb07bc7Smrg    return result;
5421dfb07bc7Smrg}
5422dfb07bc7Smrg#endif
5423d4fba8b9Smrg#endif /* OPT_DEC_CHRSET */
5424dfb07bc7Smrg
5425dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
5426dfb07bc7SmrgXTermFonts *
5427dfb07bc7SmrggetItalicFont(TScreen *screen, int which)
5428dfb07bc7Smrg{
5429dfb07bc7Smrg    XTermFonts *result = 0;
5430dfb07bc7Smrg#if OPT_WIDE_ATTRS
5431dfb07bc7Smrg    if (which >= 0 && which < fMAX)
5432d4fba8b9Smrg	result = GetItalicFont(screen, which);
5433dfb07bc7Smrg#else
5434dfb07bc7Smrg    (void) screen;
5435dfb07bc7Smrg    (void) which;
5436dfb07bc7Smrg#endif
5437dfb07bc7Smrg    return result;
5438dfb07bc7Smrg}
5439dfb07bc7Smrg#endif
5440dfb07bc7Smrg
5441dfb07bc7Smrg#if OPT_RENDERFONT
5442dfb07bc7Smrg/*
5443dfb07bc7Smrg * This returns a pointer to everything known about a given Xft font.
5444dfb07bc7Smrg * XXX make this allocate the font on demand.
5445dfb07bc7Smrg */
5446dfb07bc7SmrgXTermXftFonts *
5447dfb07bc7SmrggetMyXftFont(XtermWidget xw, int which, int fontnum)
5448dfb07bc7Smrg{
5449dfb07bc7Smrg    TScreen *screen = TScreenOf(xw);
5450dfb07bc7Smrg    XTermXftFonts *result = 0;
5451dfb07bc7Smrg    if (fontnum >= 0 && fontnum < NMENUFONTS) {
5452dfb07bc7Smrg	switch ((VTFontEnum) which) {
5453dfb07bc7Smrg	case fNorm:
5454dfb07bc7Smrg	    result = &(screen->renderFontNorm[fontnum]);
5455dfb07bc7Smrg	    break;
5456dfb07bc7Smrg	case fBold:
5457dfb07bc7Smrg	    result = &(screen->renderFontBold[fontnum]);
5458dfb07bc7Smrg	    break;
5459dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
5460dfb07bc7Smrg	case fItal:
5461dfb07bc7Smrg	    result = &(screen->renderFontItal[fontnum]);
5462dfb07bc7Smrg	    break;
5463d4fba8b9Smrg	case fBtal:
5464d4fba8b9Smrg	    result = &(screen->renderFontBtal[fontnum]);
5465d4fba8b9Smrg	    break;
5466dfb07bc7Smrg#endif
5467dfb07bc7Smrg#if OPT_WIDE_CHARS
5468dfb07bc7Smrg	case fWide:
5469dfb07bc7Smrg	    result = &(screen->renderWideNorm[fontnum]);
5470dfb07bc7Smrg	    break;
5471dfb07bc7Smrg	case fWBold:
5472dfb07bc7Smrg	    result = &(screen->renderWideBold[fontnum]);
5473dfb07bc7Smrg	    break;
5474dfb07bc7Smrg	case fWItal:
5475dfb07bc7Smrg	    result = &(screen->renderWideItal[fontnum]);
5476dfb07bc7Smrg	    break;
5477d4fba8b9Smrg	case fWBtal:
5478d4fba8b9Smrg	    result = &(screen->renderWideBtal[fontnum]);
5479d4fba8b9Smrg	    break;
5480dfb07bc7Smrg#endif
5481dfb07bc7Smrg	case fMAX:
5482dfb07bc7Smrg	    break;
5483dfb07bc7Smrg	}
5484dfb07bc7Smrg    }
5485dfb07bc7Smrg    return result;
5486dfb07bc7Smrg}
5487dfb07bc7Smrg
5488dfb07bc7SmrgXftFont *
5489dfb07bc7SmrggetXftFont(XtermWidget xw, VTFontEnum which, int fontnum)
5490dfb07bc7Smrg{
5491d4fba8b9Smrg    XTermXftFonts *data = getMyXftFont(xw, (int) which, fontnum);
5492dfb07bc7Smrg    XftFont *result = 0;
5493dfb07bc7Smrg    if (data != 0)
5494dfb07bc7Smrg	result = data->font;
5495dfb07bc7Smrg    return result;
5496dfb07bc7Smrg}
5497dfb07bc7Smrg#endif
5498dfb07bc7Smrg
5499dfb07bc7Smrgconst char *
5500dfb07bc7SmrgwhichFontEnum(VTFontEnum value)
5501dfb07bc7Smrg{
5502dfb07bc7Smrg    const char *result = "?";
5503dfb07bc7Smrg#define DATA(name) case name: result = #name; break
5504dfb07bc7Smrg    switch (value) {
5505dfb07bc7Smrg	DATA(fNorm);
5506dfb07bc7Smrg	DATA(fBold);
5507dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
5508dfb07bc7Smrg	DATA(fItal);
5509d4fba8b9Smrg	DATA(fBtal);
5510dfb07bc7Smrg#endif
5511dfb07bc7Smrg#if OPT_WIDE_CHARS
5512dfb07bc7Smrg	DATA(fWide);
5513dfb07bc7Smrg	DATA(fWBold);
5514dfb07bc7Smrg	DATA(fWItal);
5515d4fba8b9Smrg	DATA(fWBtal);
5516dfb07bc7Smrg#endif
5517dfb07bc7Smrg	DATA(fMAX);
5518dfb07bc7Smrg    }
5519dfb07bc7Smrg#undef DATA
5520dfb07bc7Smrg    return result;
5521dfb07bc7Smrg}
5522dfb07bc7Smrg
5523dfb07bc7Smrgconst char *
5524dfb07bc7SmrgwhichFontList(XtermWidget xw, VTFontList * value)
5525dfb07bc7Smrg{
5526dfb07bc7Smrg    const char *result = "?";
5527dfb07bc7Smrg    if (value == &(xw->work.fonts.x11))
5528dfb07bc7Smrg	result = "x11_fontnames";
5529dfb07bc7Smrg#if OPT_RENDERFONT
5530dfb07bc7Smrg    else if (value == &(xw->work.fonts.xft))
5531dfb07bc7Smrg	result = "xft_fontnames";
5532dfb07bc7Smrg#endif
5533dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
5534dfb07bc7Smrg    else if (value == &(xw->screen.cacheVTFonts.fonts.x11))
5535dfb07bc7Smrg	result = "cached_fontnames";
5536dfb07bc7Smrg#endif
5537dfb07bc7Smrg    return result;
5538dfb07bc7Smrg}
5539dfb07bc7Smrg
5540dfb07bc7Smrgstatic const char *
5541dfb07bc7SmrgwhichFontList2s(VTFontList * list, char **value)
5542dfb07bc7Smrg{
5543dfb07bc7Smrg    const char *result = 0;
5544dfb07bc7Smrg#define DATA(name) if (value == (list->name)) result = #name
5545dfb07bc7Smrg    DATA(list_n);
5546dfb07bc7Smrg    DATA(list_b);
5547dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
5548dfb07bc7Smrg    DATA(list_i);
5549d4fba8b9Smrg    DATA(list_bi);
5550dfb07bc7Smrg#endif
5551dfb07bc7Smrg#if OPT_WIDE_CHARS
5552dfb07bc7Smrg    DATA(list_w);
5553dfb07bc7Smrg    DATA(list_wb);
5554dfb07bc7Smrg    DATA(list_wi);
5555d4fba8b9Smrg    DATA(list_wbi);
5556dfb07bc7Smrg#endif
5557dfb07bc7Smrg#undef DATA
5558dfb07bc7Smrg    return result;
5559dfb07bc7Smrg}
5560dfb07bc7Smrg
5561dfb07bc7Smrgconst char *
5562dfb07bc7SmrgwhichFontList2(XtermWidget xw, char **value)
5563dfb07bc7Smrg{
5564dfb07bc7Smrg    const char *result = 0;
5565dfb07bc7Smrg#define DATA(name) (result = whichFontList2s(&(xw->name), value))
5566dfb07bc7Smrg    if (DATA(work.fonts.x11) == 0) {
5567dfb07bc7Smrg#if OPT_RENDERFONT
5568dfb07bc7Smrg	if (DATA(work.fonts.xft) == 0)
5569dfb07bc7Smrg#endif
5570dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
5571dfb07bc7Smrg	    if (DATA(screen.cacheVTFonts.fonts.x11) == 0)
5572dfb07bc7Smrg#endif
5573dfb07bc7Smrg		result = "?";
5574dfb07bc7Smrg    }
5575dfb07bc7Smrg#undef DATA
5576dfb07bc7Smrg    return result;
5577dfb07bc7Smrg}
5578