fontutils.c revision c48a5815
1c48a5815Smrg/* $XTermId: fontutils.c,v 1.709 2021/11/10 00:36:27 Rajeev.V.Pillai Exp $ */
2d522f475Smrg
30bd37d32Smrg/*
4d4fba8b9Smrg * Copyright 1998-2020,2021 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) {
473d522f475Smrg	want = ALLOCHUNK(want);
474d522f475Smrg	if (last != 0) {
4759a64e1c5Smrg	    char *save = *result;
476d522f475Smrg	    *result = TypeRealloc(char, want, *result);
4779a64e1c5Smrg	    if (*result == 0)
4789a64e1c5Smrg		free(save);
479d522f475Smrg	} else {
480d522f475Smrg	    if ((*result = TypeMallocN(char, want)) != 0)
481d522f475Smrg		**result = '\0';
482d522f475Smrg	}
483d522f475Smrg    }
484d522f475Smrg}
485d522f475Smrg
486d522f475Smrgstatic void
48720d2c4d2Smrgappend_fontname_str(char **result, const char *value)
488d522f475Smrg{
489d522f475Smrg    if (value == 0)
490d522f475Smrg	value = "*";
491d522f475Smrg    alloca_fontname(result, strlen(value));
492d522f475Smrg    if (*result != 0) {
493d522f475Smrg	if (**result != '\0')
494d522f475Smrg	    strcat(*result, "-");
495d522f475Smrg	strcat(*result, value);
496d522f475Smrg    }
497d522f475Smrg}
498d522f475Smrg
499d522f475Smrgstatic void
500d522f475Smrgappend_fontname_num(char **result, int value)
501d522f475Smrg{
502d522f475Smrg    if (value < 0) {
503d522f475Smrg	append_fontname_str(result, "*");
504d522f475Smrg    } else {
505d522f475Smrg	char temp[100];
506d522f475Smrg	sprintf(temp, "%d", value);
507d522f475Smrg	append_fontname_str(result, temp);
508d522f475Smrg    }
509d522f475Smrg}
510d522f475Smrg
511d522f475Smrg/*
512d522f475Smrg * Take the given font props and try to make a well formed font name specifying
513d522f475Smrg * the same base font and size and everything, but with different weight/width
514d522f475Smrg * according to the parameters.  The return value is allocated, should be freed
515d522f475Smrg * by the caller.
516d522f475Smrg */
517d522f475Smrgstatic char *
5189a64e1c5Smrgderive_font_name(FontNameProperties *props,
51920d2c4d2Smrg		 const char *use_weight,
520d522f475Smrg		 int use_average_width,
52120d2c4d2Smrg		 const char *use_encoding)
522d522f475Smrg{
523d522f475Smrg    char *result = 0;
524d522f475Smrg
525d522f475Smrg    append_fontname_str(&result, props->beginning);
526d522f475Smrg    append_fontname_str(&result, use_weight);
527d522f475Smrg    append_fontname_str(&result, props->slant);
528d522f475Smrg    append_fontname_str(&result, 0);
529d522f475Smrg    append_fontname_str(&result, 0);
530d522f475Smrg    append_fontname_num(&result, props->pixel_size);
531d522f475Smrg    append_fontname_str(&result, props->point_size);
532d522f475Smrg    append_fontname_num(&result, props->res_x);
533d522f475Smrg    append_fontname_num(&result, props->res_y);
534d522f475Smrg    append_fontname_str(&result, props->spacing);
535d522f475Smrg    append_fontname_num(&result, use_average_width);
536d522f475Smrg    append_fontname_str(&result, use_encoding);
537d522f475Smrg
538d4fba8b9Smrg    xtermDerivedFont(result);
539d522f475Smrg    return result;
540d522f475Smrg}
541d522f475Smrg
542d522f475Smrgstatic char *
5439a64e1c5Smrgbold_font_name(FontNameProperties *props, int use_average_width)
544d522f475Smrg{
545d522f475Smrg    return derive_font_name(props, "bold", use_average_width, props->end);
546d522f475Smrg}
547d522f475Smrg
5489a64e1c5Smrg#if OPT_WIDE_ATTRS
5499a64e1c5Smrgstatic char *
550dfb07bc7Smrgitalic_font_name(FontNameProperties *props, const char *slant)
5519a64e1c5Smrg{
5529a64e1c5Smrg    FontNameProperties myprops = *props;
553dfb07bc7Smrg    myprops.slant = slant;
554dfb07bc7Smrg    return derive_font_name(&myprops, props->weight, myprops.average_width, props->end);
555dfb07bc7Smrg}
556dfb07bc7Smrg
557dfb07bc7Smrgstatic Boolean
558dfb07bc7Smrgopen_italic_font(XtermWidget xw, int n, FontNameProperties *fp, XTermFonts * data)
559dfb07bc7Smrg{
560dfb07bc7Smrg    static const char *slant[] =
561dfb07bc7Smrg    {
562dfb07bc7Smrg	"o",
563dfb07bc7Smrg	"i"
564dfb07bc7Smrg    };
565dfb07bc7Smrg    Cardinal pass;
566dfb07bc7Smrg    Boolean result = False;
567dfb07bc7Smrg
568d4fba8b9Smrg    NoFontWarning(data);
569dfb07bc7Smrg    for (pass = 0; pass < XtNumber(slant); ++pass) {
570d4fba8b9Smrg	char *name;
571dfb07bc7Smrg	if ((name = italic_font_name(fp, slant[pass])) != 0) {
572dfb07bc7Smrg	    TRACE(("open_italic_font %s %s\n",
573dfb07bc7Smrg		   whichFontEnum((VTFontEnum) n), name));
574dfb07bc7Smrg	    if (xtermOpenFont(xw, name, data, False)) {
575dfb07bc7Smrg		result = (data->fs != 0);
576dfb07bc7Smrg#if OPT_REPORT_FONTS
577dfb07bc7Smrg		if (resource.reportFonts) {
578dfb07bc7Smrg		    printf("opened italic version of %s:\n\t%s\n",
579d4fba8b9Smrg			   whichFontEnum((VTFontEnum) n),
580dfb07bc7Smrg			   name);
581dfb07bc7Smrg		}
582dfb07bc7Smrg#endif
583dfb07bc7Smrg	    }
584dfb07bc7Smrg	    free(name);
585dfb07bc7Smrg	    if (result)
586dfb07bc7Smrg		break;
587dfb07bc7Smrg	}
588dfb07bc7Smrg    }
589dfb07bc7Smrg#if OPT_TRACE
590dfb07bc7Smrg    if (result) {
591dfb07bc7Smrg	XFontStruct *fs = data->fs;
592dfb07bc7Smrg	if (fs != 0) {
593dfb07bc7Smrg	    TRACE(("...actual size %dx%d (ascent %d, descent %d)\n",
594dfb07bc7Smrg		   fs->ascent +
595dfb07bc7Smrg		   fs->descent,
596dfb07bc7Smrg		   fs->max_bounds.width,
597dfb07bc7Smrg		   fs->ascent,
598dfb07bc7Smrg		   fs->descent));
599dfb07bc7Smrg	}
600dfb07bc7Smrg    }
601dfb07bc7Smrg#endif
602dfb07bc7Smrg    return result;
6039a64e1c5Smrg}
6049a64e1c5Smrg#endif
6059a64e1c5Smrg
606d522f475Smrg#if OPT_WIDE_CHARS
607d522f475Smrg#define derive_wide_font(props, weight) \
608d522f475Smrg	derive_font_name(props, weight, props->average_width * 2, "ISO10646-1")
609d522f475Smrg
610d522f475Smrgstatic char *
6119a64e1c5Smrgwide_font_name(FontNameProperties *props)
612d522f475Smrg{
613d522f475Smrg    return derive_wide_font(props, "medium");
614d522f475Smrg}
615d522f475Smrg
616d522f475Smrgstatic char *
6179a64e1c5Smrgwidebold_font_name(FontNameProperties *props)
618d522f475Smrg{
619d522f475Smrg    return derive_wide_font(props, "bold");
620d522f475Smrg}
621d522f475Smrg#endif /* OPT_WIDE_CHARS */
622d522f475Smrg
623d522f475Smrg#if OPT_DEC_CHRSET
624d522f475Smrg/*
625d522f475Smrg * Take the given font props and try to make a well formed font name specifying
626d522f475Smrg * the same base font but changed depending on the given attributes and chrset.
627d522f475Smrg *
628d522f475Smrg * For double width fonts, we just double the X-resolution, for double height
629d522f475Smrg * fonts we double the pixel-size and Y-resolution
630d522f475Smrg */
631d522f475Smrgchar *
632d4fba8b9SmrgxtermSpecialFont(XTermDraw * params)
633d522f475Smrg{
634d4fba8b9Smrg    TScreen *screen = TScreenOf(params->xw);
635d522f475Smrg#if OPT_TRACE
636d522f475Smrg    static char old_spacing[80];
637d522f475Smrg    static FontNameProperties old_props;
638d522f475Smrg#endif
639d522f475Smrg    FontNameProperties *props;
640d522f475Smrg    char *result = 0;
64120d2c4d2Smrg    const char *weight;
642d522f475Smrg    int pixel_size;
643d522f475Smrg    int res_x;
644d522f475Smrg    int res_y;
645d522f475Smrg
646dfb07bc7Smrg    props = get_font_name_props(screen->display,
647d4fba8b9Smrg				GetNormalFont(screen, fNorm)->fs, 0);
648d522f475Smrg    if (props == 0)
649d522f475Smrg	return result;
650d522f475Smrg
651d522f475Smrg    pixel_size = props->pixel_size;
652d522f475Smrg    res_x = props->res_x;
653d522f475Smrg    res_y = props->res_y;
654d4fba8b9Smrg    if (params->attr_flags & BOLD)
655d522f475Smrg	weight = "bold";
656d522f475Smrg    else
657d522f475Smrg	weight = props->weight;
658d522f475Smrg
659d4fba8b9Smrg    if (CSET_DOUBLE(params->this_chrset))
660d522f475Smrg	res_x *= 2;
661d522f475Smrg
662d4fba8b9Smrg    if (params->this_chrset == CSET_DHL_TOP
663d4fba8b9Smrg	|| params->this_chrset == CSET_DHL_BOT) {
664d522f475Smrg	res_y *= 2;
665d522f475Smrg	pixel_size *= 2;
666d522f475Smrg    }
667d522f475Smrg#if OPT_TRACE
668d522f475Smrg    if (old_props.res_x != res_x
669d522f475Smrg	|| old_props.res_x != res_y
670d522f475Smrg	|| old_props.pixel_size != pixel_size
671d522f475Smrg	|| strcmp(old_props.spacing, props->spacing)) {
6729a64e1c5Smrg	TRACE(("xtermSpecialFont(atts = %#x, draw = %#x, chrset = %#x)\n",
673d4fba8b9Smrg	       params->attr_flags, params->draw_flags, params->this_chrset));
674d522f475Smrg	TRACE(("res_x      = %d\n", res_x));
675d522f475Smrg	TRACE(("res_y      = %d\n", res_y));
676d522f475Smrg	TRACE(("point_size = %s\n", props->point_size));
677d522f475Smrg	TRACE(("pixel_size = %d\n", pixel_size));
678d522f475Smrg	TRACE(("spacing    = %s\n", props->spacing));
679d522f475Smrg	old_props.res_x = res_x;
680037a25ddSmrg	old_props.res_y = res_y;
681d522f475Smrg	old_props.pixel_size = pixel_size;
6820bd37d32Smrg	old_props.spacing = old_spacing;
6830bd37d32Smrg	sprintf(old_spacing, "%.*s", (int) sizeof(old_spacing) - 2, props->spacing);
684d522f475Smrg    }
685d522f475Smrg#endif
686d522f475Smrg
687d522f475Smrg    append_fontname_str(&result, props->beginning);
688d522f475Smrg    append_fontname_str(&result, weight);
689d522f475Smrg    append_fontname_str(&result, props->slant);
690d522f475Smrg    append_fontname_str(&result, props->wideness);
691d522f475Smrg    append_fontname_str(&result, props->add_style);
692d522f475Smrg    append_fontname_num(&result, pixel_size);
693d522f475Smrg    append_fontname_str(&result, props->point_size);
694d4fba8b9Smrg    append_fontname_num(&result, (params->draw_flags & NORESOLUTION) ? -1 : res_x);
695d4fba8b9Smrg    append_fontname_num(&result, (params->draw_flags & NORESOLUTION) ? -1 : res_y);
696d522f475Smrg    append_fontname_str(&result, props->spacing);
697d522f475Smrg    append_fontname_str(&result, 0);
698d522f475Smrg    append_fontname_str(&result, props->end);
699d522f475Smrg
700d4fba8b9Smrg    xtermDerivedFont(result);
701d522f475Smrg    return result;
702d522f475Smrg}
703d522f475Smrg#endif /* OPT_DEC_CHRSET */
704d522f475Smrg
705d522f475Smrg/*
706d522f475Smrg * Case-independent comparison for font-names, including wildcards.
707d522f475Smrg * XLFD allows '?' as a wildcard, but we do not handle that (no one seems
708d522f475Smrg * to use it).
709d522f475Smrg */
710d522f475Smrgstatic Bool
711492d43a5Smrgsame_font_name(const char *pattern, const char *match)
712d522f475Smrg{
713956cc18dSsnj    Bool result = False;
714956cc18dSsnj
715956cc18dSsnj    if (pattern && match) {
716956cc18dSsnj	while (*pattern && *match) {
717956cc18dSsnj	    if (*pattern == *match) {
718956cc18dSsnj		pattern++;
719956cc18dSsnj		match++;
720956cc18dSsnj	    } else if (*pattern == '*' || *match == '*') {
721956cc18dSsnj		if (same_font_name(pattern + 1, match)) {
722956cc18dSsnj		    return True;
723956cc18dSsnj		} else if (same_font_name(pattern, match + 1)) {
724956cc18dSsnj		    return True;
725956cc18dSsnj		} else {
726956cc18dSsnj		    return False;
727956cc18dSsnj		}
728d522f475Smrg	    } else {
729956cc18dSsnj		int p = x_toupper(*pattern++);
730956cc18dSsnj		int m = x_toupper(*match++);
731956cc18dSsnj		if (p != m)
732956cc18dSsnj		    return False;
733d522f475Smrg	    }
734d522f475Smrg	}
735956cc18dSsnj	result = (*pattern == *match);	/* both should be NUL */
736d522f475Smrg    }
737956cc18dSsnj    return result;
738d522f475Smrg}
739d522f475Smrg
740d522f475Smrg/*
741d522f475Smrg * Double-check the fontname that we asked for versus what the font server
742d522f475Smrg * actually gave us.  The larger fixed fonts do not always have a matching bold
743d522f475Smrg * font, and the font server may try to scale another font or otherwise
744d522f475Smrg * substitute a mismatched font.
745d522f475Smrg *
746d522f475Smrg * If we cannot get what we requested, we will fallback to the original
747d522f475Smrg * behavior, which simulates bold by overstriking each character at one pixel
748d522f475Smrg * offset.
749d522f475Smrg */
750d522f475Smrgstatic int
7519a64e1c5Smrggot_bold_font(Display *dpy, XFontStruct *fs, String requested)
752d522f475Smrg{
7530bd37d32Smrg    char *actual = 0;
754d522f475Smrg    int got;
755d522f475Smrg
7560bd37d32Smrg    if (get_font_name_props(dpy, fs, &actual) == 0)
757d522f475Smrg	got = 0;
758d522f475Smrg    else
759d522f475Smrg	got = same_font_name(requested, actual);
7600bd37d32Smrg    free(actual);
761d522f475Smrg    return got;
762d522f475Smrg}
763d522f475Smrg
7649a64e1c5Smrg/*
7659a64e1c5Smrg * Check normal/bold (or wide/wide-bold) font pairs to see if we will be able
7669a64e1c5Smrg * to check for missing glyphs in a comparable manner.
7679a64e1c5Smrg */
7689a64e1c5Smrgstatic int
7699a64e1c5Smrgcomparable_metrics(XFontStruct *normal, XFontStruct *bold)
7709a64e1c5Smrg{
7719a64e1c5Smrg#define DATA "comparable_metrics: "
7729a64e1c5Smrg    int result = 0;
7739a64e1c5Smrg
774dfb07bc7Smrg    if (normal == 0 || bold == 0) {
775dfb07bc7Smrg	;
776dfb07bc7Smrg    } else if (normal->all_chars_exist) {
7779a64e1c5Smrg	if (bold->all_chars_exist) {
7789a64e1c5Smrg	    result = 1;
7799a64e1c5Smrg	} else {
7809a64e1c5Smrg	    TRACE((DATA "all chars exist in normal font, but not in bold\n"));
7819a64e1c5Smrg	}
7829a64e1c5Smrg    } else if (normal->per_char != 0) {
7839a64e1c5Smrg	if (bold->per_char != 0) {
7849a64e1c5Smrg	    result = 1;
7859a64e1c5Smrg	} else {
7869a64e1c5Smrg	    TRACE((DATA "normal font has per-char metrics, but not bold\n"));
7879a64e1c5Smrg	}
7889a64e1c5Smrg    } else {
7899a64e1c5Smrg	TRACE((DATA "normal font is not very good!\n"));
7909a64e1c5Smrg	result = 1;		/* give in (we're not going in reverse) */
7919a64e1c5Smrg    }
7929a64e1c5Smrg    return result;
7939a64e1c5Smrg#undef DATA
7949a64e1c5Smrg}
7959a64e1c5Smrg
796d522f475Smrg/*
797d522f475Smrg * If the font server tries to adjust another font, it may not adjust it
798d522f475Smrg * properly.  Check that the bounding boxes are compatible.  Otherwise we'll
799d522f475Smrg * leave trash on the display when we mix normal and bold fonts.
800d522f475Smrg */
801d522f475Smrgstatic int
8029a64e1c5Smrgsame_font_size(XtermWidget xw, XFontStruct *nfs, XFontStruct *bfs)
803d522f475Smrg{
804956cc18dSsnj    TScreen *screen = TScreenOf(xw);
805dfb07bc7Smrg    int result = 0;
806dfb07bc7Smrg
807dfb07bc7Smrg    if (nfs != 0 && bfs != 0) {
808dfb07bc7Smrg	TRACE(("same_font_size height %d/%d, min %d/%d max %d/%d\n",
809dfb07bc7Smrg	       nfs->ascent + nfs->descent,
810dfb07bc7Smrg	       bfs->ascent + bfs->descent,
811dfb07bc7Smrg	       nfs->min_bounds.width, bfs->min_bounds.width,
812dfb07bc7Smrg	       nfs->max_bounds.width, bfs->max_bounds.width));
813dfb07bc7Smrg	result = screen->free_bold_box
814dfb07bc7Smrg	    || ((nfs->ascent + nfs->descent) == (bfs->ascent + bfs->descent)
815dfb07bc7Smrg		&& (nfs->min_bounds.width == bfs->min_bounds.width
816dfb07bc7Smrg		    || nfs->min_bounds.width == bfs->min_bounds.width + 1)
817dfb07bc7Smrg		&& (nfs->max_bounds.width == bfs->max_bounds.width
818dfb07bc7Smrg		    || nfs->max_bounds.width == bfs->max_bounds.width + 1));
819dfb07bc7Smrg    }
820dfb07bc7Smrg    return result;
821d522f475Smrg}
822d522f475Smrg
823d522f475Smrg/*
824d522f475Smrg * Check if the font looks like it has fixed width
825d522f475Smrg */
826d522f475Smrgstatic int
8279a64e1c5Smrgis_fixed_font(XFontStruct *fs)
828d522f475Smrg{
829d522f475Smrg    if (fs)
830d522f475Smrg	return (fs->min_bounds.width == fs->max_bounds.width);
831d522f475Smrg    return 1;
832d522f475Smrg}
833d522f475Smrg
834d4fba8b9Smrgstatic int
835d4fba8b9Smrgdiffering_widths(XFontStruct *a, XFontStruct *b)
836d4fba8b9Smrg{
837d4fba8b9Smrg    int result = 0;
838d4fba8b9Smrg    if (a != NULL && b != NULL && a->max_bounds.width != b->max_bounds.width)
839d4fba8b9Smrg	result = 1;
840d4fba8b9Smrg    return result;
841d4fba8b9Smrg}
842d4fba8b9Smrg
843d522f475Smrg/*
844d522f475Smrg * Check if the font looks like a double width font (i.e. contains
845d522f475Smrg * characters of width X and 2X
846d522f475Smrg */
847d522f475Smrg#if OPT_WIDE_CHARS
848d522f475Smrgstatic int
8499a64e1c5Smrgis_double_width_font(XFontStruct *fs)
850d522f475Smrg{
851d4fba8b9Smrg    return (fs != NULL && ((2 * fs->min_bounds.width) == fs->max_bounds.width));
852d522f475Smrg}
853d522f475Smrg#else
854d522f475Smrg#define is_double_width_font(fs) 0
855d522f475Smrg#endif
856d522f475Smrg
857d522f475Smrg#if OPT_WIDE_CHARS && OPT_RENDERFONT && defined(HAVE_TYPE_FCCHAR32)
858d522f475Smrg#define HALF_WIDTH_TEST_STRING "1234567890"
859d522f475Smrg
860d522f475Smrg/* '1234567890' in Chinese characters in UTF-8 */
861d522f475Smrg#define FULL_WIDTH_TEST_STRING "\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89" \
862d522f475Smrg                               "\xe5\x9b\x9b\xe4\xba\x94" \
863d522f475Smrg			       "\xef\xa7\x91\xe4\xb8\x83\xe5\x85\xab" \
864d522f475Smrg			       "\xe4\xb9\x9d\xef\xa6\xb2"
865d522f475Smrg
866d522f475Smrg/* '1234567890' in Korean script in UTF-8 */
867d522f475Smrg#define FULL_WIDTH_TEST_STRING2 "\xec\x9d\xbc\xec\x9d\xb4\xec\x82\xbc" \
868d522f475Smrg                                "\xec\x82\xac\xec\x98\xa4" \
869d522f475Smrg			        "\xec\x9c\xa1\xec\xb9\xa0\xed\x8c\x94" \
870d522f475Smrg			        "\xea\xb5\xac\xec\x98\x81"
871d522f475Smrg
872d522f475Smrg#define HALF_WIDTH_CHAR1  0x0031	/* '1' */
873d522f475Smrg#define HALF_WIDTH_CHAR2  0x0057	/* 'W' */
874d522f475Smrg#define FULL_WIDTH_CHAR1  0x4E00	/* CJK Ideograph 'number one' */
875d522f475Smrg#define FULL_WIDTH_CHAR2  0xAC00	/* Korean script syllable 'Ka' */
876d522f475Smrg
877d522f475Smrgstatic Bool
8789a64e1c5Smrgis_double_width_font_xft(Display *dpy, XftFont *font)
879d522f475Smrg{
880d522f475Smrg    XGlyphInfo gi1, gi2;
881d522f475Smrg    FcChar32 c1 = HALF_WIDTH_CHAR1, c2 = HALF_WIDTH_CHAR2;
8820bd37d32Smrg    String fwstr = FULL_WIDTH_TEST_STRING;
8830bd37d32Smrg    String hwstr = HALF_WIDTH_TEST_STRING;
884d522f475Smrg
885d522f475Smrg    /* Some Korean fonts don't have Chinese characters at all. */
886d522f475Smrg    if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR1)) {
887d522f475Smrg	if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR2))
888d522f475Smrg	    return False;	/* Not a CJK font */
889d522f475Smrg	else			/* a Korean font without CJK Ideographs */
890d522f475Smrg	    fwstr = FULL_WIDTH_TEST_STRING2;
891d522f475Smrg    }
892d522f475Smrg
893d522f475Smrg    XftTextExtents32(dpy, font, &c1, 1, &gi1);
894d522f475Smrg    XftTextExtents32(dpy, font, &c2, 1, &gi2);
895d522f475Smrg    if (gi1.xOff != gi2.xOff)	/* Not a fixed-width font */
896d522f475Smrg	return False;
897d522f475Smrg
8980bd37d32Smrg    XftTextExtentsUtf8(dpy,
8990bd37d32Smrg		       font,
9000bd37d32Smrg		       (_Xconst FcChar8 *) hwstr,
9010bd37d32Smrg		       (int) strlen(hwstr),
9020bd37d32Smrg		       &gi1);
9030bd37d32Smrg    XftTextExtentsUtf8(dpy,
9040bd37d32Smrg		       font,
9050bd37d32Smrg		       (_Xconst FcChar8 *) fwstr,
9060bd37d32Smrg		       (int) strlen(fwstr),
9070bd37d32Smrg		       &gi2);
908d522f475Smrg
909d522f475Smrg    /*
910d522f475Smrg     * fontconfig and Xft prior to 2.2(?) set the width of half-width
911d522f475Smrg     * characters identical to that of full-width character in CJK double-width
912d522f475Smrg     * (bi-width / monospace) font even though the former is half as wide as
913d522f475Smrg     * the latter.  This was fixed sometime before the release of fontconfig
914d522f475Smrg     * 2.2 in early 2003.  See
915d522f475Smrg     *  http://bugzilla.mozilla.org/show_bug.cgi?id=196312
916d522f475Smrg     * In the meantime, we have to check both possibilities.
917d522f475Smrg     */
918d522f475Smrg    return ((2 * gi1.xOff == gi2.xOff) || (gi1.xOff == gi2.xOff));
919d522f475Smrg}
920d522f475Smrg#else
921d522f475Smrg#define is_double_width_font_xft(dpy, xftfont) 0
922d522f475Smrg#endif
923d522f475Smrg
924d522f475Smrg#define EmptyFont(fs) (fs != 0 \
925d522f475Smrg		   && ((fs)->ascent + (fs)->descent == 0 \
926d522f475Smrg		    || (fs)->max_bounds.width == 0))
927d522f475Smrg
928d522f475Smrg#define FontSize(fs) (((fs)->ascent + (fs)->descent) \
929d522f475Smrg		    *  (fs)->max_bounds.width)
930d522f475Smrg
931d522f475Smrgconst VTFontNames *
93220d2c4d2SmrgxtermFontName(const char *normal)
933d522f475Smrg{
934d522f475Smrg    static VTFontNames data;
9359a64e1c5Smrg    FREE_STRING(data.f_n);
936d522f475Smrg    memset(&data, 0, sizeof(data));
937dfb07bc7Smrg    if (normal)
938dfb07bc7Smrg	data.f_n = x_strdup(normal);
939dfb07bc7Smrg    return &data;
940dfb07bc7Smrg}
941dfb07bc7Smrg
942dfb07bc7Smrgconst VTFontNames *
943dfb07bc7SmrgdefaultVTFontNames(XtermWidget xw)
944dfb07bc7Smrg{
945dfb07bc7Smrg    static VTFontNames data;
946dfb07bc7Smrg    memset(&data, 0, sizeof(data));
947dfb07bc7Smrg    data.f_n = DefaultFontN(xw);
948dfb07bc7Smrg    data.f_b = DefaultFontB(xw);
949dfb07bc7Smrg#if OPT_WIDE_CHARS
950dfb07bc7Smrg    data.f_w = DefaultFontW(xw);
951dfb07bc7Smrg    data.f_wb = DefaultFontWB(xw);
952dfb07bc7Smrg#endif
953d522f475Smrg    return &data;
954d522f475Smrg}
955d522f475Smrg
956d522f475Smrgstatic void
957fa3f02f3Smrgcache_menu_font_name(TScreen *screen, int fontnum, int which, const char *name)
958d522f475Smrg{
959d522f475Smrg    if (name != 0) {
9609a64e1c5Smrg	String last = screen->menu_font_names[fontnum][which];
961d522f475Smrg	if (last != 0) {
962d522f475Smrg	    if (strcmp(last, name)) {
9639a64e1c5Smrg		FREE_STRING(last);
964d522f475Smrg		TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name));
965d522f475Smrg		screen->menu_font_names[fontnum][which] = x_strdup(name);
966d522f475Smrg	    }
967d522f475Smrg	} else {
968d522f475Smrg	    TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name));
969d522f475Smrg	    screen->menu_font_names[fontnum][which] = x_strdup(name);
970d522f475Smrg	}
971d522f475Smrg    }
972d522f475Smrg}
973d522f475Smrg
974dfb07bc7Smrgstatic void
975d4fba8b9SmrgcannotFont(XtermWidget xw, const char *who, const char *tag, const char *name)
976dfb07bc7Smrg{
977d4fba8b9Smrg    static NameList *reported;
978d4fba8b9Smrg    NameList *list;
979dfb07bc7Smrg
980dfb07bc7Smrg    switch (xw->misc.fontWarnings) {
981dfb07bc7Smrg    case fwNever:
982dfb07bc7Smrg	return;
983dfb07bc7Smrg    case fwResource:
984d4fba8b9Smrg	if (is_derived_font_name(name))
985d4fba8b9Smrg	    return;
986dfb07bc7Smrg	break;
987dfb07bc7Smrg    case fwAlways:
988dfb07bc7Smrg	break;
989dfb07bc7Smrg    }
990d4fba8b9Smrg    for (list = reported; list != 0; list = list->next) {
991d4fba8b9Smrg	if (!x_strcasecmp(name, list->name)) {
992d4fba8b9Smrg	    return;
993d4fba8b9Smrg	}
994d4fba8b9Smrg    }
995d4fba8b9Smrg    if ((list = TypeMalloc(NameList)) != 0) {
996d4fba8b9Smrg	list->name = x_strdup(name);
997d4fba8b9Smrg	list->next = reported;
998d4fba8b9Smrg	reported = list;
999d4fba8b9Smrg    }
1000d4fba8b9Smrg    xtermWarning("cannot %s%s%s %sfont \"%s\"\n",
1001d4fba8b9Smrg		 who, *tag ? " " : "", tag,
1002d4fba8b9Smrg		 is_derived_font_name(name) ? "derived " : "",
1003d4fba8b9Smrg		 name);
1004dfb07bc7Smrg}
1005dfb07bc7Smrg
1006d4fba8b9Smrg#if OPT_RENDERFONT
1007d4fba8b9Smrgstatic void
1008d4fba8b9SmrgnoUsableXft(XtermWidget xw, const char *name)
1009d4fba8b9Smrg{
1010d4fba8b9Smrg    switch (xw->misc.fontWarnings) {
1011d4fba8b9Smrg    case fwNever:
1012d4fba8b9Smrg	return;
1013d4fba8b9Smrg    case fwResource:
1014d4fba8b9Smrg	/* these combinations of wide/bold/italic are all "derived" */
1015d4fba8b9Smrg	return;
1016d4fba8b9Smrg    case fwAlways:
1017d4fba8b9Smrg	break;
1018d4fba8b9Smrg    }
1019d4fba8b9Smrg    xtermWarning("did not find a usable %s TrueType font\n", name);
1020d4fba8b9Smrg}
1021d4fba8b9Smrg#endif
1022d4fba8b9Smrg
10238f44fb3bSmrgXFontStruct *
10248f44fb3bSmrgxtermLoadQueryFont(XtermWidget xw, const char *name)
10258f44fb3bSmrg{
10268f44fb3bSmrg    XFontStruct *result = NULL;
10278f44fb3bSmrg    size_t have = strlen(name);
10288f44fb3bSmrg    if (have == 0 || have > MAX_U_STRING) {
10298f44fb3bSmrg	;			/* just ignore it */
10308f44fb3bSmrg    } else {
10318f44fb3bSmrg	TScreen *screen = TScreenOf(xw);
10328f44fb3bSmrg	result = XLoadQueryFont(screen->display, name);
10338f44fb3bSmrg    }
10348f44fb3bSmrg    return result;
10358f44fb3bSmrg}
10368f44fb3bSmrg
1037d522f475Smrg/*
1038d522f475Smrg * Open the given font and verify that it is non-empty.  Return a null on
1039d522f475Smrg * failure.
1040d522f475Smrg */
1041d522f475SmrgBool
1042956cc18dSsnjxtermOpenFont(XtermWidget xw,
1043956cc18dSsnj	      const char *name,
1044956cc18dSsnj	      XTermFonts * result,
1045956cc18dSsnj	      Bool force)
1046d522f475Smrg{
1047d522f475Smrg    Bool code = False;
1048d522f475Smrg
1049d4fba8b9Smrg    TRACE(("xtermOpenFont %d:%d '%s'\n",
1050d4fba8b9Smrg	   result->warn, xw->misc.fontWarnings, NonNull(name)));
1051492d43a5Smrg    if (!IsEmpty(name)) {
10528f44fb3bSmrg	if ((result->fs = xtermLoadQueryFont(xw, name)) != 0) {
1053956cc18dSsnj	    code = True;
1054956cc18dSsnj	    if (EmptyFont(result->fs)) {
1055dfb07bc7Smrg		xtermCloseFont(xw, result);
1056956cc18dSsnj		code = False;
1057956cc18dSsnj	    } else {
1058956cc18dSsnj		result->fn = x_strdup(name);
1059956cc18dSsnj	    }
106020d2c4d2Smrg	} else if (XmuCompareISOLatin1(name, DEFFONT) != 0) {
1061dfb07bc7Smrg	    if (result->warn <= xw->misc.fontWarnings
1062956cc18dSsnj#if OPT_RENDERFONT
1063956cc18dSsnj		&& !UsingRenderFont(xw)
1064956cc18dSsnj#endif
1065956cc18dSsnj		) {
1066dfb07bc7Smrg		cannotFont(xw, "load", "", name);
1067956cc18dSsnj	    } else {
1068492d43a5Smrg		TRACE(("xtermOpenFont: cannot load font '%s'\n", name));
1069956cc18dSsnj	    }
1070956cc18dSsnj	    if (force) {
1071d4fba8b9Smrg		NoFontWarning(result);
1072dfb07bc7Smrg		code = xtermOpenFont(xw, DEFFONT, result, True);
1073956cc18dSsnj	    }
1074d522f475Smrg	}
1075d522f475Smrg    }
1076d4fba8b9Smrg    NoFontWarning(result);
1077d522f475Smrg    return code;
1078d522f475Smrg}
1079d522f475Smrg
1080d522f475Smrg/*
1081956cc18dSsnj * Close the font and free the font info.
1082d522f475Smrg */
1083dfb07bc7Smrgvoid
1084d522f475SmrgxtermCloseFont(XtermWidget xw, XTermFonts * fnt)
1085d522f475Smrg{
1086d522f475Smrg    if (fnt != 0 && fnt->fs != 0) {
1087d522f475Smrg	TScreen *screen = TScreenOf(xw);
1088d522f475Smrg
1089d522f475Smrg	clrCgsFonts(xw, WhichVWin(screen), fnt);
1090d522f475Smrg	XFreeFont(screen->display, fnt->fs);
1091d522f475Smrg	xtermFreeFontInfo(fnt);
1092d522f475Smrg    }
1093d522f475Smrg}
1094d522f475Smrg
1095037a25ddSmrg/*
1096037a25ddSmrg * Close and free the font (as well as any aliases).
1097037a25ddSmrg */
1098037a25ddSmrgstatic void
1099037a25ddSmrgxtermCloseFont2(XtermWidget xw, XTermFonts * fnts, int which)
1100037a25ddSmrg{
1101037a25ddSmrg    XFontStruct *thisFont = fnts[which].fs;
1102037a25ddSmrg
1103037a25ddSmrg    if (thisFont != 0) {
1104037a25ddSmrg	int k;
1105037a25ddSmrg
1106037a25ddSmrg	xtermCloseFont(xw, &fnts[which]);
1107037a25ddSmrg	for (k = 0; k < fMAX; ++k) {
1108037a25ddSmrg	    if (k != which) {
1109037a25ddSmrg		if (thisFont == fnts[k].fs) {
1110037a25ddSmrg		    xtermFreeFontInfo(&fnts[k]);
1111037a25ddSmrg		}
1112037a25ddSmrg	    }
1113037a25ddSmrg	}
1114037a25ddSmrg    }
1115037a25ddSmrg}
1116037a25ddSmrg
1117d522f475Smrg/*
1118d522f475Smrg * Close the listed fonts, noting that some may use copies of the pointer.
1119d522f475Smrg */
1120d522f475Smrgvoid
1121d522f475SmrgxtermCloseFonts(XtermWidget xw, XTermFonts * fnts)
1122d522f475Smrg{
1123037a25ddSmrg    int j;
1124d522f475Smrg
1125d522f475Smrg    for (j = 0; j < fMAX; ++j) {
1126037a25ddSmrg	xtermCloseFont2(xw, fnts, j);
1127d522f475Smrg    }
1128d522f475Smrg}
1129d522f475Smrg
1130d522f475Smrg/*
1131d522f475Smrg * Make a copy of the source, assuming the XFontStruct's to be unique, but
1132d522f475Smrg * ensuring that the names are reallocated to simplify freeing.
1133d522f475Smrg */
1134d522f475Smrgvoid
1135d522f475SmrgxtermCopyFontInfo(XTermFonts * target, XTermFonts * source)
1136d522f475Smrg{
1137d522f475Smrg    xtermFreeFontInfo(target);
1138d522f475Smrg    target->chrset = source->chrset;
1139d522f475Smrg    target->flags = source->flags;
1140d522f475Smrg    target->fn = x_strdup(source->fn);
1141d522f475Smrg    target->fs = source->fs;
1142dfb07bc7Smrg    target->warn = source->warn;
1143d522f475Smrg}
1144d522f475Smrg
1145d522f475Smrgvoid
1146d522f475SmrgxtermFreeFontInfo(XTermFonts * target)
1147d522f475Smrg{
1148d522f475Smrg    target->chrset = 0;
1149d522f475Smrg    target->flags = 0;
1150d4fba8b9Smrg    FreeAndNull(target->fn);
1151d522f475Smrg    target->fs = 0;
1152d522f475Smrg}
1153d522f475Smrg
1154fa3f02f3Smrg#if OPT_REPORT_FONTS
1155fa3f02f3Smrgstatic void
1156fa3f02f3SmrgreportXCharStruct(const char *tag, XCharStruct * cs)
1157fa3f02f3Smrg{
1158fa3f02f3Smrg    printf("\t\t%s:\n", tag);
1159fa3f02f3Smrg    printf("\t\t\tlbearing: %d\n", cs->lbearing);
1160fa3f02f3Smrg    printf("\t\t\trbearing: %d\n", cs->rbearing);
1161fa3f02f3Smrg    printf("\t\t\twidth:    %d\n", cs->width);
1162fa3f02f3Smrg    printf("\t\t\tascent:   %d\n", cs->ascent);
1163fa3f02f3Smrg    printf("\t\t\tdescent:  %d\n", cs->descent);
1164fa3f02f3Smrg}
1165fa3f02f3Smrg
1166fa3f02f3Smrgstatic void
1167fa3f02f3SmrgreportOneVTFont(const char *tag,
1168fa3f02f3Smrg		XTermFonts * fnt)
1169fa3f02f3Smrg{
1170dfb07bc7Smrg    if (!IsEmpty(fnt->fn) && fnt->fs != 0) {
1171fa3f02f3Smrg	XFontStruct *fs = fnt->fs;
1172fa3f02f3Smrg	unsigned first_char = 0;
1173fa3f02f3Smrg	unsigned last_char = 0;
1174fa3f02f3Smrg
1175fa3f02f3Smrg	if (fs->max_byte1 == 0) {
1176fa3f02f3Smrg	    first_char = fs->min_char_or_byte2;
1177fa3f02f3Smrg	    last_char = fs->max_char_or_byte2;
1178fa3f02f3Smrg	} else {
1179fa3f02f3Smrg	    first_char = (fs->min_byte1 * 256) + fs->min_char_or_byte2;
1180fa3f02f3Smrg	    last_char = (fs->max_byte1 * 256) + fs->max_char_or_byte2;
1181fa3f02f3Smrg	}
1182fa3f02f3Smrg
1183fa3f02f3Smrg	printf("\t%s: %s\n", tag, NonNull(fnt->fn));
1184fa3f02f3Smrg	printf("\t\tall chars:     %s\n", fs->all_chars_exist ? "yes" : "no");
1185fa3f02f3Smrg	printf("\t\tdefault char:  %d\n", fs->default_char);
1186fa3f02f3Smrg	printf("\t\tdirection:     %d\n", fs->direction);
1187fa3f02f3Smrg	printf("\t\tascent:        %d\n", fs->ascent);
1188fa3f02f3Smrg	printf("\t\tdescent:       %d\n", fs->descent);
1189fa3f02f3Smrg	printf("\t\tfirst char:    %u\n", first_char);
1190fa3f02f3Smrg	printf("\t\tlast char:     %u\n", last_char);
1191fa3f02f3Smrg	printf("\t\tmaximum-chars: %u\n", countGlyphs(fs));
11929a64e1c5Smrg	if (FontLacksMetrics(fnt)) {
11939a64e1c5Smrg	    printf("\t\tmissing-chars: ?\n");
11949a64e1c5Smrg	    printf("\t\tpresent-chars: ?\n");
11959a64e1c5Smrg	} else {
11969a64e1c5Smrg	    unsigned missing = 0;
1197037a25ddSmrg	    unsigned ch;
11989a64e1c5Smrg	    for (ch = first_char; ch <= last_char; ++ch) {
11999a64e1c5Smrg		if (xtermMissingChar(ch, fnt)) {
12009a64e1c5Smrg		    ++missing;
12019a64e1c5Smrg		}
12029a64e1c5Smrg	    }
12039a64e1c5Smrg	    printf("\t\tmissing-chars: %u\n", missing);
12049a64e1c5Smrg	    printf("\t\tpresent-chars: %u\n", countGlyphs(fs) - missing);
12059a64e1c5Smrg	}
1206fa3f02f3Smrg	printf("\t\tmin_byte1:     %d\n", fs->min_byte1);
1207fa3f02f3Smrg	printf("\t\tmax_byte1:     %d\n", fs->max_byte1);
1208fa3f02f3Smrg	printf("\t\tproperties:    %d\n", fs->n_properties);
1209fa3f02f3Smrg	reportXCharStruct("min_bounds", &(fs->min_bounds));
1210fa3f02f3Smrg	reportXCharStruct("max_bounds", &(fs->max_bounds));
1211fa3f02f3Smrg	/* TODO: report fs->properties and fs->per_char */
1212fa3f02f3Smrg    }
1213fa3f02f3Smrg}
1214fa3f02f3Smrg
1215fa3f02f3Smrgstatic void
1216fa3f02f3SmrgreportVTFontInfo(XtermWidget xw, int fontnum)
1217fa3f02f3Smrg{
1218fa3f02f3Smrg    if (resource.reportFonts) {
1219fa3f02f3Smrg	TScreen *screen = TScreenOf(xw);
1220fa3f02f3Smrg
1221fa3f02f3Smrg	if (fontnum) {
1222fa3f02f3Smrg	    printf("Loaded VTFonts(font%d)\n", fontnum);
1223fa3f02f3Smrg	} else {
1224fa3f02f3Smrg	    printf("Loaded VTFonts(default)\n");
1225fa3f02f3Smrg	}
1226dfb07bc7Smrg
1227d4fba8b9Smrg	reportOneVTFont("fNorm", GetNormalFont(screen, fNorm));
1228d4fba8b9Smrg	reportOneVTFont("fBold", GetNormalFont(screen, fBold));
1229fa3f02f3Smrg#if OPT_WIDE_CHARS
1230d4fba8b9Smrg	reportOneVTFont("fWide", GetNormalFont(screen, fWide));
1231d4fba8b9Smrg	reportOneVTFont("fWBold", GetNormalFont(screen, fWBold));
1232fa3f02f3Smrg#endif
1233fa3f02f3Smrg    }
1234fa3f02f3Smrg}
1235fa3f02f3Smrg#endif
1236fa3f02f3Smrg
12379a64e1c5Smrgvoid
1238d4fba8b9SmrgxtermUpdateFontGCs(XtermWidget xw, MyGetFont myfunc)
12399a64e1c5Smrg{
12409a64e1c5Smrg    TScreen *screen = TScreenOf(xw);
12419a64e1c5Smrg    VTwin *win = WhichVWin(screen);
1242d4fba8b9Smrg    Pixel new_normal = getXtermFG(xw, xw->flags, xw->cur_foreground);
1243d4fba8b9Smrg    Pixel new_revers = getXtermBG(xw, xw->flags, xw->cur_background);
1244dfb07bc7Smrg
12459a64e1c5Smrg    setCgsFore(xw, win, gcNorm, new_normal);
12469a64e1c5Smrg    setCgsBack(xw, win, gcNorm, new_revers);
1247dfb07bc7Smrg    setCgsFont(xw, win, gcNorm, myfunc(screen, fNorm));
12489a64e1c5Smrg
12499a64e1c5Smrg    copyCgs(xw, win, gcBold, gcNorm);
1250d4fba8b9Smrg    setCgsFont2(xw, win, gcBold, myfunc(screen, fBold), fBold);
12519a64e1c5Smrg
12529a64e1c5Smrg    setCgsFore(xw, win, gcNormReverse, new_revers);
12539a64e1c5Smrg    setCgsBack(xw, win, gcNormReverse, new_normal);
1254dfb07bc7Smrg    setCgsFont(xw, win, gcNormReverse, myfunc(screen, fNorm));
12559a64e1c5Smrg
12569a64e1c5Smrg    copyCgs(xw, win, gcBoldReverse, gcNormReverse);
1257d4fba8b9Smrg    setCgsFont2(xw, win, gcBoldReverse, myfunc(screen, fBold), fBold);
12589a64e1c5Smrg
12599a64e1c5Smrg    if_OPT_WIDE_CHARS(screen, {
1260dfb07bc7Smrg	XTermFonts *wide_xx = myfunc(screen, fWide);
1261dfb07bc7Smrg	XTermFonts *bold_xx = myfunc(screen, fWBold);
1262dfb07bc7Smrg	if (wide_xx->fs != 0
1263dfb07bc7Smrg	    && bold_xx->fs != 0) {
12649a64e1c5Smrg	    setCgsFore(xw, win, gcWide, new_normal);
12659a64e1c5Smrg	    setCgsBack(xw, win, gcWide, new_revers);
1266dfb07bc7Smrg	    setCgsFont(xw, win, gcWide, wide_xx);
12679a64e1c5Smrg
12689a64e1c5Smrg	    copyCgs(xw, win, gcWBold, gcWide);
1269dfb07bc7Smrg	    setCgsFont(xw, win, gcWBold, bold_xx);
12709a64e1c5Smrg
12719a64e1c5Smrg	    setCgsFore(xw, win, gcWideReverse, new_revers);
12729a64e1c5Smrg	    setCgsBack(xw, win, gcWideReverse, new_normal);
1273dfb07bc7Smrg	    setCgsFont(xw, win, gcWideReverse, wide_xx);
12749a64e1c5Smrg
12759a64e1c5Smrg	    copyCgs(xw, win, gcWBoldReverse, gcWideReverse);
1276dfb07bc7Smrg	    setCgsFont(xw, win, gcWBoldReverse, bold_xx);
12779a64e1c5Smrg	}
12789a64e1c5Smrg    });
12799a64e1c5Smrg}
12809a64e1c5Smrg
1281d4fba8b9Smrg#if OPT_WIDE_ATTRS
1282d4fba8b9Smrgunsigned
1283d4fba8b9SmrgxtermUpdateItalics(XtermWidget xw, unsigned new_attrs, unsigned old_attrs)
1284d4fba8b9Smrg{
1285c48a5815Smrg    TScreen *screen = TScreenOf(xw);
1286c48a5815Smrg
1287c48a5815Smrg    if (UseItalicFont(screen)) {
1288c48a5815Smrg	if ((new_attrs & ATR_ITALIC) && !(old_attrs & ATR_ITALIC)) {
1289c48a5815Smrg	    xtermLoadItalics(xw);
1290c48a5815Smrg	    xtermUpdateFontGCs(xw, getItalicFont);
1291c48a5815Smrg	} else if (!(new_attrs & ATR_ITALIC) && (old_attrs & ATR_ITALIC)) {
1292c48a5815Smrg	    xtermUpdateFontGCs(xw, getNormalFont);
1293c48a5815Smrg	}
1294d4fba8b9Smrg    }
1295d4fba8b9Smrg    return new_attrs;
1296d4fba8b9Smrg}
1297d4fba8b9Smrg#endif
1298d4fba8b9Smrg
1299d4fba8b9Smrg#if OPT_TRACE && OPT_BOX_CHARS
13009a64e1c5Smrgstatic void
13019a64e1c5Smrgshow_font_misses(const char *name, XTermFonts * fp)
13029a64e1c5Smrg{
13039a64e1c5Smrg    if (fp->fs != 0) {
13049a64e1c5Smrg	if (FontLacksMetrics(fp)) {
13059a64e1c5Smrg	    TRACE(("%s font lacks metrics\n", name));
13069a64e1c5Smrg	} else if (FontIsIncomplete(fp)) {
13079a64e1c5Smrg	    TRACE(("%s font is incomplete\n", name));
13089a64e1c5Smrg	} else {
13099a64e1c5Smrg	    TRACE(("%s font is complete\n", name));
13109a64e1c5Smrg	}
13119a64e1c5Smrg    } else {
13129a64e1c5Smrg	TRACE(("%s font is missing\n", name));
13139a64e1c5Smrg    }
13149a64e1c5Smrg}
13159a64e1c5Smrg#endif
13169a64e1c5Smrg
1317dfb07bc7Smrgstatic Bool
1318dfb07bc7SmrgloadNormFP(XtermWidget xw,
1319dfb07bc7Smrg	   char **nameOutP,
1320dfb07bc7Smrg	   XTermFonts * infoOut,
1321dfb07bc7Smrg	   int fontnum)
1322dfb07bc7Smrg{
1323dfb07bc7Smrg    Bool status = True;
1324dfb07bc7Smrg
1325dfb07bc7Smrg    TRACE(("loadNormFP (%s)\n", NonNull(*nameOutP)));
1326dfb07bc7Smrg
1327dfb07bc7Smrg    if (!xtermOpenFont(xw,
1328dfb07bc7Smrg		       *nameOutP,
1329dfb07bc7Smrg		       infoOut,
1330dfb07bc7Smrg		       (fontnum == fontMenu_default))) {
1331dfb07bc7Smrg	/*
1332dfb07bc7Smrg	 * If we are opening the default font, and it happens to be missing,
1333dfb07bc7Smrg	 * force that to the compiled-in default font, e.g., "fixed".  If we
1334dfb07bc7Smrg	 * cannot open the font, disable it from the menu.
1335dfb07bc7Smrg	 */
1336dfb07bc7Smrg	if (fontnum != fontMenu_fontsel) {
1337dfb07bc7Smrg	    SetItemSensitivity(fontMenuEntries[fontnum].widget, False);
1338dfb07bc7Smrg	}
1339dfb07bc7Smrg	status = False;
1340dfb07bc7Smrg    }
1341dfb07bc7Smrg    return status;
1342dfb07bc7Smrg}
1343dfb07bc7Smrg
1344dfb07bc7Smrgstatic Bool
1345dfb07bc7SmrgloadBoldFP(XtermWidget xw,
1346dfb07bc7Smrg	   char **nameOutP,
1347dfb07bc7Smrg	   XTermFonts * infoOut,
1348dfb07bc7Smrg	   const char *nameRef,
1349dfb07bc7Smrg	   XTermFonts * infoRef,
1350dfb07bc7Smrg	   int fontnum)
1351dfb07bc7Smrg{
1352dfb07bc7Smrg    TScreen *screen = TScreenOf(xw);
1353dfb07bc7Smrg    Bool status = True;
1354dfb07bc7Smrg
1355dfb07bc7Smrg    TRACE(("loadBoldFP (%s)\n", NonNull(*nameOutP)));
1356dfb07bc7Smrg
1357dfb07bc7Smrg    if (!check_fontname(*nameOutP)) {
1358dfb07bc7Smrg	FontNameProperties *fp;
1359dfb07bc7Smrg	char *normal = x_strdup(nameRef);
1360dfb07bc7Smrg
1361dfb07bc7Smrg	fp = get_font_name_props(screen->display, infoRef->fs, &normal);
1362dfb07bc7Smrg	if (fp != 0) {
1363d4fba8b9Smrg	    NoFontWarning(infoOut);
1364dfb07bc7Smrg	    *nameOutP = bold_font_name(fp, fp->average_width);
1365dfb07bc7Smrg	    if (!xtermOpenFont(xw, *nameOutP, infoOut, False)) {
1366dfb07bc7Smrg		free(*nameOutP);
1367dfb07bc7Smrg		*nameOutP = bold_font_name(fp, -1);
1368dfb07bc7Smrg		xtermOpenFont(xw, *nameOutP, infoOut, False);
1369dfb07bc7Smrg	    }
1370dfb07bc7Smrg	    TRACE(("...derived bold '%s'\n", NonNull(*nameOutP)));
1371dfb07bc7Smrg	}
1372dfb07bc7Smrg	if (fp == 0 || infoOut->fs == 0) {
1373dfb07bc7Smrg	    xtermCopyFontInfo(infoOut, infoRef);
1374dfb07bc7Smrg	    TRACE(("...cannot load a matching bold font\n"));
1375dfb07bc7Smrg	} else if (comparable_metrics(infoRef->fs, infoOut->fs)
1376dfb07bc7Smrg		   && same_font_size(xw, infoRef->fs, infoOut->fs)
1377dfb07bc7Smrg		   && got_bold_font(screen->display, infoOut->fs, *nameOutP)) {
1378dfb07bc7Smrg	    TRACE(("...got a matching bold font\n"));
1379dfb07bc7Smrg	    cache_menu_font_name(screen, fontnum, fBold, *nameOutP);
1380dfb07bc7Smrg	} else {
1381dfb07bc7Smrg	    xtermCloseFont2(xw, infoOut - fBold, fBold);
1382dfb07bc7Smrg	    *infoOut = *infoRef;
1383dfb07bc7Smrg	    TRACE(("...did not get a matching bold font\n"));
1384dfb07bc7Smrg	}
1385dfb07bc7Smrg	free(normal);
1386dfb07bc7Smrg    } else if (!xtermOpenFont(xw, *nameOutP, infoOut, False)) {
1387dfb07bc7Smrg	xtermCopyFontInfo(infoOut, infoRef);
1388dfb07bc7Smrg	TRACE(("...cannot load bold font '%s'\n", NonNull(*nameOutP)));
1389dfb07bc7Smrg    } else {
1390dfb07bc7Smrg	cache_menu_font_name(screen, fontnum, fBold, *nameOutP);
1391dfb07bc7Smrg    }
1392dfb07bc7Smrg
1393dfb07bc7Smrg    /*
1394dfb07bc7Smrg     * Most of the time this call to load the font will succeed, even if
1395dfb07bc7Smrg     * there is no wide font :  the X server doubles the width of the
1396dfb07bc7Smrg     * normal font, or similar.
1397dfb07bc7Smrg     *
1398dfb07bc7Smrg     * But if it did fail for some reason, then nevermind.
1399dfb07bc7Smrg     */
1400dfb07bc7Smrg    if (EmptyFont(infoOut->fs))
1401dfb07bc7Smrg	status = False;		/* can't use a 0-sized font */
1402dfb07bc7Smrg
1403dfb07bc7Smrg    if (!same_font_size(xw, infoRef->fs, infoOut->fs)
1404dfb07bc7Smrg	&& (is_fixed_font(infoRef->fs) && is_fixed_font(infoOut->fs))) {
1405dfb07bc7Smrg	TRACE(("...ignoring mismatched normal/bold fonts\n"));
1406dfb07bc7Smrg	xtermCloseFont2(xw, infoOut - fBold, fBold);
1407dfb07bc7Smrg	xtermCopyFontInfo(infoOut, infoRef);
1408dfb07bc7Smrg    }
1409dfb07bc7Smrg
1410dfb07bc7Smrg    return status;
1411dfb07bc7Smrg}
1412dfb07bc7Smrg
1413dfb07bc7Smrg#if OPT_WIDE_CHARS
1414dfb07bc7Smrgstatic Bool
1415dfb07bc7SmrgloadWideFP(XtermWidget xw,
1416dfb07bc7Smrg	   char **nameOutP,
1417dfb07bc7Smrg	   XTermFonts * infoOut,
1418dfb07bc7Smrg	   const char *nameRef,
1419dfb07bc7Smrg	   XTermFonts * infoRef,
1420dfb07bc7Smrg	   int fontnum)
1421dfb07bc7Smrg{
1422dfb07bc7Smrg    TScreen *screen = TScreenOf(xw);
1423dfb07bc7Smrg    Bool status = True;
1424dfb07bc7Smrg
1425dfb07bc7Smrg    TRACE(("loadWideFP (%s)\n", NonNull(*nameOutP)));
1426dfb07bc7Smrg
1427d4fba8b9Smrg    if (!check_fontname(*nameOutP)
1428d4fba8b9Smrg	&& (screen->utf8_fonts && !is_double_width_font(infoRef->fs))) {
1429dfb07bc7Smrg	char *normal = x_strdup(nameRef);
1430d4fba8b9Smrg	FontNameProperties *fp = get_font_name_props(screen->display,
1431d4fba8b9Smrg						     infoRef->fs, &normal);
1432dfb07bc7Smrg	if (fp != 0) {
1433dfb07bc7Smrg	    *nameOutP = wide_font_name(fp);
1434d4fba8b9Smrg	    NoFontWarning(infoOut);
1435dfb07bc7Smrg	}
1436dfb07bc7Smrg	free(normal);
1437dfb07bc7Smrg    }
1438dfb07bc7Smrg
1439dfb07bc7Smrg    if (check_fontname(*nameOutP)) {
1440d4fba8b9Smrg	if (xtermOpenFont(xw, *nameOutP, infoOut, False)
1441d4fba8b9Smrg	    && is_derived_font_name(*nameOutP)
1442d4fba8b9Smrg	    && EmptyFont(infoOut->fs)) {
1443d4fba8b9Smrg	    xtermCloseFont2(xw, infoOut - fWide, fWide);
1444d4fba8b9Smrg	}
1445d4fba8b9Smrg	if (infoOut->fs == 0) {
1446dfb07bc7Smrg	    xtermCopyFontInfo(infoOut, infoRef);
1447d4fba8b9Smrg	} else {
1448d4fba8b9Smrg	    TRACE(("...%s wide %s\n",
1449d4fba8b9Smrg		   is_derived_font_name(*nameOutP) ? "derived" : "given",
1450d4fba8b9Smrg		   NonNull(*nameOutP)));
1451d4fba8b9Smrg	    cache_menu_font_name(screen, fontnum, fWide, *nameOutP);
1452dfb07bc7Smrg	}
1453dfb07bc7Smrg    } else {
1454dfb07bc7Smrg	xtermCopyFontInfo(infoOut, infoRef);
1455dfb07bc7Smrg    }
1456c48a5815Smrg#define MinWidthOf(fs) fs->min_bounds.width
1457c48a5815Smrg#define MaxWidthOf(fs) fs->max_bounds.width
1458c48a5815Smrg    xw->work.force_wideFont = False;
1459c48a5815Smrg    if (MaxWidthOf(infoOut->fs) != (2 * MaxWidthOf(infoRef->fs))) {
1460c48a5815Smrg	TRACE(("...reference width %d\n", MaxWidthOf(infoRef->fs)));
1461c48a5815Smrg	TRACE(("...?? double-width %d\n", 2 * MaxWidthOf(infoRef->fs)));
1462c48a5815Smrg	TRACE(("...actual width    %d\n", MaxWidthOf(infoOut->fs)));
1463c48a5815Smrg	xw->work.force_wideFont = True;
1464c48a5815Smrg    }
1465dfb07bc7Smrg    return status;
1466dfb07bc7Smrg}
1467dfb07bc7Smrg
1468dfb07bc7Smrgstatic Bool
1469dfb07bc7SmrgloadWBoldFP(XtermWidget xw,
1470dfb07bc7Smrg	    char **nameOutP,
1471dfb07bc7Smrg	    XTermFonts * infoOut,
1472dfb07bc7Smrg	    const char *wideNameRef, XTermFonts * wideInfoRef,
1473dfb07bc7Smrg	    const char *boldNameRef, XTermFonts * boldInfoRef,
1474dfb07bc7Smrg	    int fontnum)
1475dfb07bc7Smrg{
1476dfb07bc7Smrg    TScreen *screen = TScreenOf(xw);
1477dfb07bc7Smrg    Bool status = True;
1478dfb07bc7Smrg    char *bold = NULL;
1479dfb07bc7Smrg
1480dfb07bc7Smrg    TRACE(("loadWBoldFP (%s)\n", NonNull(*nameOutP)));
1481dfb07bc7Smrg
1482dfb07bc7Smrg    if (!check_fontname(*nameOutP)) {
1483dfb07bc7Smrg	FontNameProperties *fp;
1484dfb07bc7Smrg	fp = get_font_name_props(screen->display, boldInfoRef->fs, &bold);
1485dfb07bc7Smrg	if (fp != 0) {
1486dfb07bc7Smrg	    *nameOutP = widebold_font_name(fp);
1487d4fba8b9Smrg	    NoFontWarning(infoOut);
1488dfb07bc7Smrg	}
1489dfb07bc7Smrg    }
1490dfb07bc7Smrg
1491dfb07bc7Smrg    if (check_fontname(*nameOutP)) {
1492dfb07bc7Smrg
1493dfb07bc7Smrg	if (xtermOpenFont(xw, *nameOutP, infoOut, False)
1494d4fba8b9Smrg	    && is_derived_font_name(*nameOutP)
1495dfb07bc7Smrg	    && !compatibleWideCounts(wideInfoRef->fs, infoOut->fs)) {
1496dfb07bc7Smrg	    xtermCloseFont2(xw, infoOut - fWBold, fWBold);
1497dfb07bc7Smrg	}
1498dfb07bc7Smrg
1499dfb07bc7Smrg	if (infoOut->fs == 0) {
1500d4fba8b9Smrg	    if (is_derived_font_name(*nameOutP))
1501dfb07bc7Smrg		free(*nameOutP);
1502dfb07bc7Smrg	    if (IsEmpty(wideNameRef)) {
1503dfb07bc7Smrg		*nameOutP = x_strdup(boldNameRef);
1504dfb07bc7Smrg		xtermCopyFontInfo(infoOut, boldInfoRef);
1505dfb07bc7Smrg		TRACE(("...cannot load wide-bold, use bold %s\n",
1506dfb07bc7Smrg		       NonNull(boldNameRef)));
1507dfb07bc7Smrg	    } else {
1508dfb07bc7Smrg		*nameOutP = x_strdup(wideNameRef);
1509dfb07bc7Smrg		xtermCopyFontInfo(infoOut, wideInfoRef);
1510dfb07bc7Smrg		TRACE(("...cannot load wide-bold, use wide %s\n",
1511dfb07bc7Smrg		       NonNull(wideNameRef)));
1512dfb07bc7Smrg	    }
1513dfb07bc7Smrg	} else {
1514dfb07bc7Smrg	    TRACE(("...%s wide/bold %s\n",
1515d4fba8b9Smrg		   is_derived_font_name(*nameOutP) ? "derived" : "given",
1516dfb07bc7Smrg		   NonNull(*nameOutP)));
1517dfb07bc7Smrg	    cache_menu_font_name(screen, fontnum, fWBold, *nameOutP);
1518dfb07bc7Smrg	}
1519dfb07bc7Smrg    } else if (is_double_width_font(boldInfoRef->fs)) {
1520dfb07bc7Smrg	xtermCopyFontInfo(infoOut, boldInfoRef);
1521dfb07bc7Smrg	TRACE(("...bold font is double-width, use it %s\n", NonNull(boldNameRef)));
1522dfb07bc7Smrg    } else {
1523dfb07bc7Smrg	xtermCopyFontInfo(infoOut, wideInfoRef);
1524dfb07bc7Smrg	TRACE(("...cannot load wide bold font, use wide %s\n", NonNull(wideNameRef)));
1525dfb07bc7Smrg    }
1526dfb07bc7Smrg
1527dfb07bc7Smrg    free(bold);
1528dfb07bc7Smrg
1529dfb07bc7Smrg    if (EmptyFont(infoOut->fs)) {
1530dfb07bc7Smrg	status = False;		/* can't use a 0-sized font */
1531dfb07bc7Smrg    } else {
1532dfb07bc7Smrg	if ((!comparable_metrics(wideInfoRef->fs, infoOut->fs)
1533dfb07bc7Smrg	     || (!same_font_size(xw, wideInfoRef->fs, infoOut->fs)
1534dfb07bc7Smrg		 && is_fixed_font(wideInfoRef->fs)
1535dfb07bc7Smrg		 && is_fixed_font(infoOut->fs)))) {
1536dfb07bc7Smrg	    TRACE(("...ignoring mismatched normal/bold wide fonts\n"));
1537dfb07bc7Smrg	    xtermCloseFont2(xw, infoOut - fWBold, fWBold);
1538dfb07bc7Smrg	    xtermCopyFontInfo(infoOut, wideInfoRef);
1539dfb07bc7Smrg	}
1540dfb07bc7Smrg    }
1541dfb07bc7Smrg
1542dfb07bc7Smrg    return status;
1543dfb07bc7Smrg}
1544dfb07bc7Smrg#endif
1545dfb07bc7Smrg
1546d522f475Smrgint
1547d522f475SmrgxtermLoadFont(XtermWidget xw,
1548d522f475Smrg	      const VTFontNames * fonts,
1549d522f475Smrg	      Bool doresize,
1550d522f475Smrg	      int fontnum)
1551d522f475Smrg{
1552956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1553d522f475Smrg    VTwin *win = WhichVWin(screen);
1554d522f475Smrg
1555d522f475Smrg    VTFontNames myfonts;
1556d522f475Smrg    XTermFonts fnts[fMAX];
1557d522f475Smrg    char *tmpname = NULL;
1558956cc18dSsnj    Boolean proportional = False;
1559d522f475Smrg
1560d522f475Smrg    memset(&myfonts, 0, sizeof(myfonts));
1561d522f475Smrg    memset(fnts, 0, sizeof(fnts));
1562d522f475Smrg
1563d522f475Smrg    if (fonts != 0)
1564d522f475Smrg	myfonts = *fonts;
1565956cc18dSsnj    if (!check_fontname(myfonts.f_n))
1566d522f475Smrg	return 0;
1567d522f475Smrg
1568d522f475Smrg    if (fontnum == fontMenu_fontescape
1569d522f475Smrg	&& myfonts.f_n != screen->MenuFontName(fontnum)) {
1570d522f475Smrg	if ((tmpname = x_strdup(myfonts.f_n)) == 0)
1571d522f475Smrg	    return 0;
1572d522f475Smrg    }
1573d522f475Smrg
1574d522f475Smrg    TRACE(("Begin Cgs - xtermLoadFont(%s)\n", myfonts.f_n));
1575d522f475Smrg    releaseWindowGCs(xw, win);
1576d522f475Smrg
1577956cc18dSsnj#define DbgResource(name, field, index) \
1578956cc18dSsnj    TRACE(("xtermLoadFont #%d "name" %s%s\n", \
1579956cc18dSsnj    	   fontnum, \
1580dfb07bc7Smrg	   (fnts[index].warn == fwResource) ? "*" : " ", \
1581492d43a5Smrg	   NonNull(myfonts.field)))
1582956cc18dSsnj    DbgResource("normal", f_n, fNorm);
1583956cc18dSsnj    DbgResource("bold  ", f_b, fBold);
1584d522f475Smrg#if OPT_WIDE_CHARS
1585956cc18dSsnj    DbgResource("wide  ", f_w, fWide);
1586956cc18dSsnj    DbgResource("w/bold", f_wb, fWBold);
1587d522f475Smrg#endif
1588d522f475Smrg
1589dfb07bc7Smrg    if (!loadNormFP(xw,
1590dfb07bc7Smrg		    &myfonts.f_n,
1591dfb07bc7Smrg		    &fnts[fNorm],
1592dfb07bc7Smrg		    fontnum))
1593d522f475Smrg	goto bad;
1594d522f475Smrg
1595dfb07bc7Smrg    if (!loadBoldFP(xw,
1596dfb07bc7Smrg		    &myfonts.f_b,
1597dfb07bc7Smrg		    &fnts[fBold],
1598dfb07bc7Smrg		    myfonts.f_n,
1599dfb07bc7Smrg		    &fnts[fNorm],
1600dfb07bc7Smrg		    fontnum))
1601dfb07bc7Smrg	goto bad;
1602d522f475Smrg
1603d522f475Smrg    /*
1604d522f475Smrg     * If there is no widefont specified, fake it by doubling AVERAGE_WIDTH
1605d522f475Smrg     * of normal fonts XLFD, and asking for it.  This plucks out 18x18ja
1606d522f475Smrg     * and 12x13ja as the corresponding fonts for 9x18 and 6x13.
1607d522f475Smrg     */
1608d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
1609d522f475Smrg
1610dfb07bc7Smrg	if (!loadWideFP(xw,
1611dfb07bc7Smrg			&myfonts.f_w,
1612dfb07bc7Smrg			&fnts[fWide],
1613dfb07bc7Smrg			myfonts.f_n,
1614dfb07bc7Smrg			&fnts[fNorm],
1615dfb07bc7Smrg			fontnum))
1616dfb07bc7Smrg	    goto bad;
1617dfb07bc7Smrg
1618dfb07bc7Smrg	if (!loadWBoldFP(xw,
1619dfb07bc7Smrg			 &myfonts.f_wb,
1620dfb07bc7Smrg			 &fnts[fWBold],
1621dfb07bc7Smrg			 myfonts.f_w,
1622dfb07bc7Smrg			 &fnts[fWide],
1623dfb07bc7Smrg			 myfonts.f_b,
1624dfb07bc7Smrg			 &fnts[fBold],
1625dfb07bc7Smrg			 fontnum))
1626dfb07bc7Smrg	    goto bad;
1627d522f475Smrg
1628d522f475Smrg    });
1629d522f475Smrg
1630d522f475Smrg    /*
1631d522f475Smrg     * Normal/bold fonts should be the same width.  Also, the min/max
1632d522f475Smrg     * values should be the same.
1633d522f475Smrg     */
1634d4fba8b9Smrg    if (fnts[fNorm].fs != 0
1635d4fba8b9Smrg	&& fnts[fBold].fs != 0
1636d4fba8b9Smrg	&& (!is_fixed_font(fnts[fNorm].fs)
1637d4fba8b9Smrg	    || !is_fixed_font(fnts[fBold].fs)
1638d4fba8b9Smrg	    || differing_widths(fnts[fNorm].fs, fnts[fBold].fs))) {
1639d522f475Smrg	TRACE(("Proportional font! normal %d/%d, bold %d/%d\n",
1640d522f475Smrg	       fnts[fNorm].fs->min_bounds.width,
1641d522f475Smrg	       fnts[fNorm].fs->max_bounds.width,
1642d522f475Smrg	       fnts[fBold].fs->min_bounds.width,
1643d522f475Smrg	       fnts[fBold].fs->max_bounds.width));
1644d522f475Smrg	proportional = True;
1645d522f475Smrg    }
1646d522f475Smrg
1647d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
1648d522f475Smrg	if (fnts[fWide].fs != 0
1649d522f475Smrg	    && fnts[fWBold].fs != 0
1650d522f475Smrg	    && (!is_fixed_font(fnts[fWide].fs)
1651d522f475Smrg		|| !is_fixed_font(fnts[fWBold].fs)
1652d4fba8b9Smrg		|| differing_widths(fnts[fWide].fs, fnts[fWBold].fs))) {
1653d522f475Smrg	    TRACE(("Proportional font! wide %d/%d, wide bold %d/%d\n",
1654d522f475Smrg		   fnts[fWide].fs->min_bounds.width,
1655d522f475Smrg		   fnts[fWide].fs->max_bounds.width,
1656d522f475Smrg		   fnts[fWBold].fs->min_bounds.width,
1657d522f475Smrg		   fnts[fWBold].fs->max_bounds.width));
1658d522f475Smrg	    proportional = True;
1659d522f475Smrg	}
1660d522f475Smrg    });
1661d522f475Smrg
1662d522f475Smrg    /* TODO : enforce that the width of the wide font is 2* the width
1663d522f475Smrg       of the narrow font */
1664d522f475Smrg
1665d522f475Smrg    /*
1666d522f475Smrg     * If we're switching fonts, free the old ones.  Otherwise we'll leak
1667d522f475Smrg     * the memory that is associated with the old fonts.  The
1668d522f475Smrg     * XLoadQueryFont call allocates a new XFontStruct.
1669d522f475Smrg     */
1670d522f475Smrg    xtermCloseFonts(xw, screen->fnts);
16719a64e1c5Smrg#if OPT_WIDE_ATTRS
16729a64e1c5Smrg    xtermCloseFonts(xw, screen->ifnts);
16739a64e1c5Smrg    screen->ifnts_ok = False;
16749a64e1c5Smrg#endif
1675d522f475Smrg
1676d4fba8b9Smrg    xtermCopyFontInfo(GetNormalFont(screen, fNorm), &fnts[fNorm]);
1677d4fba8b9Smrg    xtermCopyFontInfo(GetNormalFont(screen, fBold), &fnts[fBold]);
1678d522f475Smrg#if OPT_WIDE_CHARS
1679d4fba8b9Smrg    xtermCopyFontInfo(GetNormalFont(screen, fWide), &fnts[fWide]);
1680d522f475Smrg    if (fnts[fWBold].fs == NULL)
1681d4fba8b9Smrg	xtermCopyFontInfo(GetNormalFont(screen, fWide), &fnts[fWide]);
1682d4fba8b9Smrg    xtermCopyFontInfo(GetNormalFont(screen, fWBold), &fnts[fWBold]);
1683d522f475Smrg#endif
1684d522f475Smrg
1685d4fba8b9Smrg    xtermUpdateFontGCs(xw, getNormalFont);
1686d522f475Smrg
168720d2c4d2Smrg#if OPT_BOX_CHARS
168820d2c4d2Smrg    screen->allow_packing = proportional;
168920d2c4d2Smrg    setupPackedFonts(xw);
169020d2c4d2Smrg#endif
169120d2c4d2Smrg    screen->fnt_prop = (Boolean) (proportional && !(screen->force_packed));
1692d4fba8b9Smrg    screen->fnt_boxes = 1;
1693d522f475Smrg
1694d522f475Smrg#if OPT_BOX_CHARS
1695d522f475Smrg    /*
16969a64e1c5Smrg     * xterm uses character positions 1-31 of a font for the line-drawing
1697d522f475Smrg     * characters.  Check that they are all present.  The null character
1698d522f475Smrg     * (0) is special, and is not used.
1699d522f475Smrg     */
1700d522f475Smrg#if OPT_RENDERFONT
1701d522f475Smrg    if (UsingRenderFont(xw)) {
1702d522f475Smrg	/*
1703d522f475Smrg	 * FIXME: we shouldn't even be here if we're using Xft.
1704d522f475Smrg	 */
1705d4fba8b9Smrg	screen->fnt_boxes = 0;
1706d522f475Smrg	TRACE(("assume Xft missing line-drawing chars\n"));
1707d522f475Smrg    } else
1708d522f475Smrg#endif
1709d522f475Smrg    {
1710d522f475Smrg	unsigned ch;
1711d522f475Smrg
17129a64e1c5Smrg#if OPT_TRACE
17139a64e1c5Smrg#define TRACE_MISS(index) show_font_misses(#index, &fnts[index])
17149a64e1c5Smrg	TRACE_MISS(fNorm);
17159a64e1c5Smrg	TRACE_MISS(fBold);
17169a64e1c5Smrg#if OPT_WIDE_CHARS
17179a64e1c5Smrg	TRACE_MISS(fWide);
17189a64e1c5Smrg	TRACE_MISS(fWBold);
17199a64e1c5Smrg#endif
17209a64e1c5Smrg#endif
1721fa3f02f3Smrg
1722d522f475Smrg#if OPT_WIDE_CHARS
1723d4fba8b9Smrg	if (screen->utf8_mode || screen->unicode_font) {
1724d4fba8b9Smrg	    UIntSet(screen->fnt_boxes, 2);
1725d4fba8b9Smrg	    for (ch = 1; ch < 32; ch++) {
1726d4fba8b9Smrg		unsigned n = dec2ucs(screen, ch);
1727d4fba8b9Smrg		if ((n != UCS_REPL)
1728d4fba8b9Smrg		    && (n != ch)
1729d4fba8b9Smrg		    && (screen->fnt_boxes & 2)) {
1730d4fba8b9Smrg		    if (xtermMissingChar(n, &fnts[fNorm]) ||
1731d4fba8b9Smrg			xtermMissingChar(n, &fnts[fBold])) {
1732d4fba8b9Smrg			UIntClr(screen->fnt_boxes, 2);
1733d4fba8b9Smrg			TRACE(("missing graphics character #%d, U+%04X\n",
1734d4fba8b9Smrg			       ch, n));
1735d4fba8b9Smrg			break;
1736d4fba8b9Smrg		    }
1737d4fba8b9Smrg		}
1738d522f475Smrg	    }
1739d4fba8b9Smrg	}
1740d522f475Smrg#endif
1741d4fba8b9Smrg
1742d4fba8b9Smrg	for (ch = 1; ch < 32; ch++) {
1743d4fba8b9Smrg	    if (xtermMissingChar(ch, &fnts[fNorm])) {
1744d4fba8b9Smrg		TRACE(("missing normal char #%d\n", ch));
1745d4fba8b9Smrg		UIntClr(screen->fnt_boxes, 1);
1746d522f475Smrg		break;
1747d522f475Smrg	    }
1748d4fba8b9Smrg	    if (xtermMissingChar(ch, &fnts[fBold])) {
1749d4fba8b9Smrg		TRACE(("missing bold   char #%d\n", ch));
1750d4fba8b9Smrg		UIntClr(screen->fnt_boxes, 1);
1751d522f475Smrg		break;
1752d522f475Smrg	    }
1753d522f475Smrg	}
1754d4fba8b9Smrg
1755d4fba8b9Smrg	TRACE(("Will %suse internal line-drawing characters (mode %d)\n",
1756d4fba8b9Smrg	       screen->fnt_boxes ? "not " : "",
1757d4fba8b9Smrg	       screen->fnt_boxes));
1758d522f475Smrg    }
1759d522f475Smrg#endif
1760d522f475Smrg
1761d522f475Smrg    if (screen->always_bold_mode) {
1762d522f475Smrg	screen->enbolden = screen->bold_mode;
1763d522f475Smrg    } else {
1764d522f475Smrg	screen->enbolden = screen->bold_mode
1765d522f475Smrg	    && ((fnts[fNorm].fs == fnts[fBold].fs)
1766dfb07bc7Smrg		|| same_font_name(myfonts.f_n, myfonts.f_b));
1767d522f475Smrg    }
1768d522f475Smrg    TRACE(("Will %suse 1-pixel offset/overstrike to simulate bold\n",
1769d522f475Smrg	   screen->enbolden ? "" : "not "));
1770d522f475Smrg
1771d522f475Smrg    set_menu_font(False);
1772d522f475Smrg    screen->menu_font_number = fontnum;
1773d522f475Smrg    set_menu_font(True);
1774d522f475Smrg    if (tmpname) {		/* if setting escape or sel */
1775d522f475Smrg	if (screen->MenuFontName(fontnum))
17769a64e1c5Smrg	    FREE_STRING(screen->MenuFontName(fontnum));
1777d522f475Smrg	screen->MenuFontName(fontnum) = tmpname;
1778d522f475Smrg	if (fontnum == fontMenu_fontescape) {
177994644356Smrg	    update_font_escape();
1780d522f475Smrg	}
1781d522f475Smrg#if OPT_SHIFT_FONTS
1782d522f475Smrg	screen->menu_font_sizes[fontnum] = FontSize(fnts[fNorm].fs);
1783d522f475Smrg#endif
1784d522f475Smrg    }
1785d522f475Smrg    set_cursor_gcs(xw);
1786d522f475Smrg    xtermUpdateFontInfo(xw, doresize);
1787d522f475Smrg    TRACE(("Success Cgs - xtermLoadFont\n"));
1788fa3f02f3Smrg#if OPT_REPORT_FONTS
1789fa3f02f3Smrg    reportVTFontInfo(xw, fontnum);
17909a64e1c5Smrg#endif
17919a64e1c5Smrg    FREE_FNAME(f_n);
17929a64e1c5Smrg    FREE_FNAME(f_b);
17939a64e1c5Smrg#if OPT_WIDE_CHARS
17949a64e1c5Smrg    FREE_FNAME(f_w);
17959a64e1c5Smrg    FREE_FNAME(f_wb);
17969a64e1c5Smrg#endif
17979a64e1c5Smrg    if (fnts[fNorm].fn == fnts[fBold].fn) {
17989a64e1c5Smrg	free(fnts[fNorm].fn);
17999a64e1c5Smrg    } else {
18009a64e1c5Smrg	free(fnts[fNorm].fn);
18019a64e1c5Smrg	free(fnts[fBold].fn);
18029a64e1c5Smrg    }
18039a64e1c5Smrg#if OPT_WIDE_CHARS
18049a64e1c5Smrg    free(fnts[fWide].fn);
18059a64e1c5Smrg    free(fnts[fWBold].fn);
1806fa3f02f3Smrg#endif
1807dfb07bc7Smrg    xtermSetWinSize(xw);
1808d522f475Smrg    return 1;
1809d522f475Smrg
1810d522f475Smrg  bad:
1811d4fba8b9Smrg    free(tmpname);
18120bd37d32Smrg
18130bd37d32Smrg#if OPT_RENDERFONT
181494644356Smrg    if ((fontnum == fontMenu_fontsel) && (fontnum != screen->menu_font_number)) {
18159a64e1c5Smrg	int old_fontnum = screen->menu_font_number;
18169a64e1c5Smrg#if OPT_TOOLBAR
18179a64e1c5Smrg	SetItemSensitivity(fontMenuEntries[fontnum].widget, True);
18189a64e1c5Smrg#endif
18199a64e1c5Smrg	Bell(xw, XkbBI_MinorError, 0);
18209a64e1c5Smrg	myfonts.f_n = screen->MenuFontName(old_fontnum);
18219a64e1c5Smrg	return xtermLoadFont(xw, &myfonts, doresize, old_fontnum);
18229a64e1c5Smrg    } else if (x_strcasecmp(myfonts.f_n, DEFFONT)) {
18230bd37d32Smrg	int code;
18240bd37d32Smrg
1825dfb07bc7Smrg	myfonts.f_n = x_strdup(DEFFONT);
18260bd37d32Smrg	TRACE(("...recovering for TrueType fonts\n"));
18270bd37d32Smrg	code = xtermLoadFont(xw, &myfonts, doresize, fontnum);
18280bd37d32Smrg	if (code) {
182994644356Smrg	    if (fontnum != fontMenu_fontsel) {
183094644356Smrg		SetItemSensitivity(fontMenuEntries[fontnum].widget,
183194644356Smrg				   UsingRenderFont(xw));
183294644356Smrg	    }
18330bd37d32Smrg	    TRACE(("...recovered size %dx%d\n",
18340bd37d32Smrg		   FontHeight(screen),
18350bd37d32Smrg		   FontWidth(screen)));
18360bd37d32Smrg	}
18370bd37d32Smrg	return code;
18380bd37d32Smrg    }
18390bd37d32Smrg#endif
18400bd37d32Smrg
1841d522f475Smrg    releaseWindowGCs(xw, win);
1842d522f475Smrg
1843d522f475Smrg    xtermCloseFonts(xw, fnts);
1844d522f475Smrg    TRACE(("Fail Cgs - xtermLoadFont\n"));
1845d522f475Smrg    return 0;
1846d522f475Smrg}
1847d522f475Smrg
18489a64e1c5Smrg#if OPT_WIDE_ATTRS
18499a64e1c5Smrg/*
18509a64e1c5Smrg * (Attempt to) load matching italics for the current normal/bold/etc fonts.
18519a64e1c5Smrg * If the attempt fails for a given style, use the non-italic font.
18529a64e1c5Smrg */
18539a64e1c5Smrgvoid
18549a64e1c5SmrgxtermLoadItalics(XtermWidget xw)
18559a64e1c5Smrg{
18569a64e1c5Smrg    TScreen *screen = TScreenOf(xw);
18579a64e1c5Smrg
1858c48a5815Smrg    if (UseItalicFont(screen) && !screen->ifnts_ok) {
1859037a25ddSmrg	int n;
1860dfb07bc7Smrg	FontNameProperties *fp;
1861dfb07bc7Smrg	XTermFonts *data;
1862037a25ddSmrg
18639a64e1c5Smrg	screen->ifnts_ok = True;
18649a64e1c5Smrg	for (n = 0; n < fMAX; ++n) {
1865dfb07bc7Smrg	    switch (n) {
1866dfb07bc7Smrg	    case fNorm:
1867dfb07bc7Smrg		/* FALLTHRU */
1868dfb07bc7Smrg	    case fBold:
1869dfb07bc7Smrg		/* FALLTHRU */
1870dfb07bc7Smrg#if OPT_WIDE_CHARS
1871dfb07bc7Smrg	    case fWide:
1872dfb07bc7Smrg		/* FALLTHRU */
1873dfb07bc7Smrg	    case fWBold:
1874dfb07bc7Smrg#endif
1875dfb07bc7Smrg		/* FALLTHRU */
1876dfb07bc7Smrg		data = getItalicFont(screen, n);
1877037a25ddSmrg
1878dfb07bc7Smrg		/*
1879dfb07bc7Smrg		 * FIXME - need to handle font-leaks
1880dfb07bc7Smrg		 */
1881dfb07bc7Smrg		data->fs = 0;
1882dfb07bc7Smrg		if (getNormalFont(screen, n)->fs != 0 &&
1883dfb07bc7Smrg		    (fp = get_font_name_props(screen->display,
1884dfb07bc7Smrg					      getNormalFont(screen, n)->fs,
1885dfb07bc7Smrg					      0)) != 0) {
1886dfb07bc7Smrg		    if (!open_italic_font(xw, n, fp, data)) {
1887dfb07bc7Smrg			if (n > 0) {
1888dfb07bc7Smrg			    xtermCopyFontInfo(data,
1889dfb07bc7Smrg					      getItalicFont(screen, n - 1));
1890dfb07bc7Smrg			} else {
1891dfb07bc7Smrg			    xtermOpenFont(xw,
1892dfb07bc7Smrg					  getNormalFont(screen, n)->fn,
1893dfb07bc7Smrg					  data, False);
18949a64e1c5Smrg			}
18959a64e1c5Smrg		    }
18969a64e1c5Smrg		}
1897dfb07bc7Smrg		break;
18989a64e1c5Smrg	    }
18999a64e1c5Smrg	}
19009a64e1c5Smrg    }
19019a64e1c5Smrg}
19029a64e1c5Smrg#endif
19039a64e1c5Smrg
1904d522f475Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
1905d522f475Smrg/*
1906d522f475Smrg * Collect font-names that we can modify with the load-vt-fonts() action.
1907d522f475Smrg */
1908dfb07bc7Smrg#define MERGE_SUBFONT(dst,src,name) \
1909492d43a5Smrg	if (IsEmpty(dst.name)) { \
1910dfb07bc7Smrg	    TRACE(("MERGE_SUBFONT " #dst "." #name " merge \"%s\"\n", NonNull(src.name))); \
19119a64e1c5Smrg	    dst.name = x_strdup(src.name); \
1912d522f475Smrg	} else { \
1913dfb07bc7Smrg	    TRACE(("MERGE_SUBFONT " #dst "." #name " found \"%s\"\n", NonNull(dst.name))); \
1914dfb07bc7Smrg	}
1915dfb07bc7Smrg#define MERGE_SUBLIST(dst,src,name) \
1916dfb07bc7Smrg	if (merge_sublist(&(dst.fonts.x11.name), src.fonts.x11.name)) { \
1917dfb07bc7Smrg	    TRACE(("MERGE_SUBLIST " #dst "." #name " merge \"%s\"\n", src.fonts.x11.name[0])); \
1918dfb07bc7Smrg	} else { \
1919dfb07bc7Smrg	    TRACE(("MERGE_SUBLIST " #dst "." #name " found \"%s\"\n", dst.fonts.x11.name[0])); \
1920d522f475Smrg	}
1921d522f475Smrg
1922dfb07bc7Smrg#define INFER_SUBFONT(dst,src,name) \
1923e39b573cSmrg	if (IsEmpty(dst.name)) { \
1924e39b573cSmrg	    TRACE(("INFER_SUBFONT " #dst "." #name " will infer\n")); \
1925e39b573cSmrg	    dst.name = x_strdup(""); \
1926e39b573cSmrg	} else { \
1927dfb07bc7Smrg	    TRACE(("INFER_SUBFONT " #dst "." #name " found \"%s\"\n", NonNull(dst.name))); \
1928e39b573cSmrg	}
1929e39b573cSmrg
19309a64e1c5Smrg#define FREE_MENU_FONTS(dst) \
19319a64e1c5Smrg	TRACE(("FREE_MENU_FONTS " #dst "\n")); \
19329a64e1c5Smrg	for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \
19339a64e1c5Smrg	    for (m = 0; m < fMAX; ++m) { \
19349a64e1c5Smrg		FREE_STRING(dst.menu_font_names[n][m]); \
19359a64e1c5Smrg		dst.menu_font_names[n][m] = 0; \
19369a64e1c5Smrg	    } \
19379a64e1c5Smrg	}
19389a64e1c5Smrg
1939dfb07bc7Smrg#define COPY_MENU_FONTS(dst,src) \
1940d522f475Smrg	TRACE(("COPY_MENU_FONTS " #src " to " #dst "\n")); \
1941d522f475Smrg	for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \
1942d522f475Smrg	    for (m = 0; m < fMAX; ++m) { \
19439a64e1c5Smrg		FREE_STRING(dst.menu_font_names[n][m]); \
1944492d43a5Smrg		dst.menu_font_names[n][m] = x_strdup(src.menu_font_names[n][m]); \
1945d522f475Smrg	    } \
194694644356Smrg	    TRACE((".. " #dst ".menu_fonts_names[%d] = %s\n", n, NonNull(dst.menu_font_names[n][fNorm]))); \
1947e39b573cSmrg	}
1948e39b573cSmrg
19499a64e1c5Smrg#define COPY_DEFAULT_FONTS(target, source) \
1950dfb07bc7Smrg	TRACE(("COPY_DEFAULT_FONTS " #source " to " #target "\n")); \
19519a64e1c5Smrg	xtermCopyVTFontNames(&target.default_font, &source.default_font)
19529a64e1c5Smrg
1953dfb07bc7Smrg#define COPY_X11_FONTLISTS(target, source) \
1954dfb07bc7Smrg	TRACE(("COPY_X11_FONTLISTS " #source " to " #target "\n")); \
1955dfb07bc7Smrg	xtermCopyFontLists(xw, &target.fonts.x11, &source.fonts.x11)
1956dfb07bc7Smrg
1957dfb07bc7Smrgstatic void
1958dfb07bc7SmrgxtermCopyVTFontNames(VTFontNames * target, VTFontNames * source)
1959dfb07bc7Smrg{
1960dfb07bc7Smrg#define COPY_IT(name,field) \
1961dfb07bc7Smrg    TRACE((".. "#name" = %s\n", NonNull(source->field))); \
1962dfb07bc7Smrg    free(target->field); \
1963dfb07bc7Smrg    target->field = x_strdup(source->field)
1964dfb07bc7Smrg
1965dfb07bc7Smrg    TRACE(("xtermCopyVTFontNames\n"));
1966dfb07bc7Smrg
1967dfb07bc7Smrg    COPY_IT(font, f_n);
1968dfb07bc7Smrg    COPY_IT(boldFont, f_b);
1969dfb07bc7Smrg
1970dfb07bc7Smrg#if OPT_WIDE_CHARS
1971dfb07bc7Smrg    COPY_IT(wideFont, f_w);
1972dfb07bc7Smrg    COPY_IT(wideBoldFont, f_wb);
1973dfb07bc7Smrg#endif
1974dfb07bc7Smrg#undef COPY_IT
1975dfb07bc7Smrg}
1976dfb07bc7Smrg
19779a64e1c5Smrgstatic void
1978dfb07bc7SmrgxtermCopyFontLists(XtermWidget xw, VTFontList * target, VTFontList * source)
19799a64e1c5Smrg{
1980dfb07bc7Smrg#define COPY_IT(name,field) \
1981dfb07bc7Smrg    copyFontList(&(target->field), source->field); \
1982dfb07bc7Smrg    TRACE_ARGV(".. " #name, source->field)
1983dfb07bc7Smrg
1984dfb07bc7Smrg    (void) xw;
1985dfb07bc7Smrg    TRACE(("xtermCopyFontLists %s ->%s\n",
1986dfb07bc7Smrg	   whichFontList(xw, source),
1987dfb07bc7Smrg	   whichFontList(xw, target)));
1988dfb07bc7Smrg
1989dfb07bc7Smrg    COPY_IT(font, list_n);
1990dfb07bc7Smrg    COPY_IT(fontBold, list_b);
1991dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
1992dfb07bc7Smrg    COPY_IT(fontItal, list_i);
1993d4fba8b9Smrg    COPY_IT(fontBtal, list_bi);
1994dfb07bc7Smrg#endif
19959a64e1c5Smrg#if OPT_WIDE_CHARS
1996dfb07bc7Smrg    COPY_IT(wideFont, list_w);
1997dfb07bc7Smrg    COPY_IT(wideBoldFont, list_wb);
1998dfb07bc7Smrg    COPY_IT(wideItalFont, list_wi);
1999d4fba8b9Smrg    COPY_IT(wideBtalFont, list_wbi);
20009a64e1c5Smrg#endif
2001dfb07bc7Smrg#undef COPY_IT
20029a64e1c5Smrg}
20039a64e1c5Smrg
2004e39b573cSmrgvoid
2005e39b573cSmrgxtermSaveVTFonts(XtermWidget xw)
2006e39b573cSmrg{
2007e39b573cSmrg    TScreen *screen = TScreenOf(xw);
2008e39b573cSmrg    Cardinal n, m;
2009e39b573cSmrg
2010e39b573cSmrg    if (!screen->savedVTFonts) {
2011e39b573cSmrg
2012e39b573cSmrg	screen->savedVTFonts = True;
2013e39b573cSmrg	TRACE(("xtermSaveVTFonts saving original\n"));
20149a64e1c5Smrg	COPY_DEFAULT_FONTS(screen->cacheVTFonts, xw->misc);
2015dfb07bc7Smrg	COPY_X11_FONTLISTS(screen->cacheVTFonts, xw->work);
2016dfb07bc7Smrg	COPY_MENU_FONTS(screen->cacheVTFonts, xw->screen);
2017e39b573cSmrg    }
2018e39b573cSmrg}
2019e39b573cSmrg
2020e39b573cSmrg#define SAME_STRING(x,y) ((x) == (y) || ((x) && (y) && !strcmp(x, y)))
2021e39b573cSmrg#define SAME_MEMBER(n)   SAME_STRING(a->n, b->n)
2022e39b573cSmrg
2023e39b573cSmrgstatic Boolean
2024e39b573cSmrgsameSubResources(SubResourceRec * a, SubResourceRec * b)
2025e39b573cSmrg{
2026e39b573cSmrg    Boolean result = True;
2027e39b573cSmrg
2028e39b573cSmrg    if (!SAME_MEMBER(default_font.f_n)
2029e39b573cSmrg	|| !SAME_MEMBER(default_font.f_b)
20300bd37d32Smrg#if OPT_WIDE_CHARS
2031e39b573cSmrg	|| !SAME_MEMBER(default_font.f_w)
20320bd37d32Smrg	|| !SAME_MEMBER(default_font.f_wb)
20330bd37d32Smrg#endif
20340bd37d32Smrg	) {
2035e39b573cSmrg	TRACE(("sameSubResources: default_font differs\n"));
2036e39b573cSmrg	result = False;
2037e39b573cSmrg    } else {
2038037a25ddSmrg	int n;
2039037a25ddSmrg
2040e39b573cSmrg	for (n = 0; n < NMENUFONTS; ++n) {
2041e39b573cSmrg	    if (!SAME_MEMBER(menu_font_names[n][fNorm])) {
2042e39b573cSmrg		TRACE(("sameSubResources: menu_font_names[%d] differs\n", n));
2043e39b573cSmrg		result = False;
2044e39b573cSmrg		break;
2045e39b573cSmrg	    }
2046d522f475Smrg	}
2047e39b573cSmrg    }
2048e39b573cSmrg
2049e39b573cSmrg    return result;
2050e39b573cSmrg}
2051d522f475Smrg
2052d522f475Smrg/*
2053d522f475Smrg * Load the "VT" font names from the given subresource name/class.  These
2054d522f475Smrg * correspond to the VT100 resources.
2055d522f475Smrg */
2056d522f475Smrgstatic Bool
205720d2c4d2SmrgxtermLoadVTFonts(XtermWidget xw, String myName, String myClass)
2058d522f475Smrg{
2059e39b573cSmrg    SubResourceRec subresourceRec;
2060e39b573cSmrg    SubResourceRec referenceRec;
2061d522f475Smrg
2062d522f475Smrg    /*
2063d522f475Smrg     * These are duplicates of the VT100 font resources, but with a special
2064d522f475Smrg     * application/classname passed in to distinguish them.
2065d522f475Smrg     */
2066d522f475Smrg    static XtResource font_resources[] =
2067d522f475Smrg    {
2068d522f475Smrg	Sres(XtNfont, XtCFont, default_font.f_n, DEFFONT),
2069d522f475Smrg	Sres(XtNboldFont, XtCBoldFont, default_font.f_b, DEFBOLDFONT),
2070d522f475Smrg#if OPT_WIDE_CHARS
2071d522f475Smrg	Sres(XtNwideFont, XtCWideFont, default_font.f_w, DEFWIDEFONT),
2072d522f475Smrg	Sres(XtNwideBoldFont, XtCWideBoldFont, default_font.f_wb, DEFWIDEBOLDFONT),
2073d522f475Smrg#endif
2074d522f475Smrg	Sres(XtNfont1, XtCFont1, MenuFontName(fontMenu_font1), NULL),
2075d522f475Smrg	Sres(XtNfont2, XtCFont2, MenuFontName(fontMenu_font2), NULL),
2076d522f475Smrg	Sres(XtNfont3, XtCFont3, MenuFontName(fontMenu_font3), NULL),
2077d522f475Smrg	Sres(XtNfont4, XtCFont4, MenuFontName(fontMenu_font4), NULL),
2078d522f475Smrg	Sres(XtNfont5, XtCFont5, MenuFontName(fontMenu_font5), NULL),
2079d522f475Smrg	Sres(XtNfont6, XtCFont6, MenuFontName(fontMenu_font6), NULL),
2080d4fba8b9Smrg	Sres(XtNfont7, XtCFont7, MenuFontName(fontMenu_font7), NULL),
2081d522f475Smrg    };
2082d522f475Smrg    Cardinal n, m;
2083d522f475Smrg    Bool status = True;
2084956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2085d522f475Smrg
2086e39b573cSmrg    TRACE(("called xtermLoadVTFonts(name=%s, class=%s)\n",
2087e39b573cSmrg	   NonNull(myName), NonNull(myClass)));
2088d522f475Smrg
2089e39b573cSmrg    xtermSaveVTFonts(xw);
2090d522f475Smrg
2091492d43a5Smrg    if (IsEmpty(myName)) {
2092d522f475Smrg	TRACE(("xtermLoadVTFonts restoring original\n"));
20939a64e1c5Smrg	COPY_DEFAULT_FONTS(xw->misc, screen->cacheVTFonts);
2094dfb07bc7Smrg	COPY_X11_FONTLISTS(xw->work, screen->cacheVTFonts);
20959a64e1c5Smrg	FREE_MENU_FONTS(xw->screen);
2096dfb07bc7Smrg	COPY_MENU_FONTS(xw->screen, screen->cacheVTFonts);
2097d522f475Smrg    } else {
2098d522f475Smrg	TRACE(("xtermLoadVTFonts(%s, %s)\n", myName, myClass));
2099d522f475Smrg
2100e39b573cSmrg	memset(&referenceRec, 0, sizeof(referenceRec));
2101d522f475Smrg	memset(&subresourceRec, 0, sizeof(subresourceRec));
2102956cc18dSsnj	XtGetSubresources((Widget) xw, (XtPointer) &subresourceRec,
2103d522f475Smrg			  myName, myClass,
2104d522f475Smrg			  font_resources,
2105d522f475Smrg			  (Cardinal) XtNumber(font_resources),
2106d522f475Smrg			  NULL, (Cardinal) 0);
2107d522f475Smrg
2108e39b573cSmrg	/*
2109e39b573cSmrg	 * XtGetSubresources returns no status, so we compare the returned
2110e39b573cSmrg	 * data against a zero'd struct to see if any data is returned.
2111e39b573cSmrg	 */
2112e39b573cSmrg	if (memcmp(&referenceRec, &subresourceRec, sizeof(referenceRec))
2113e39b573cSmrg	    && !sameSubResources(&(screen->cacheVTFonts), &subresourceRec)) {
2114e39b573cSmrg
2115e39b573cSmrg	    screen->mergedVTFonts = True;
2116d522f475Smrg
21179a64e1c5Smrg	    /*
21189a64e1c5Smrg	     * To make it simple, reallocate the strings returned by
21199a64e1c5Smrg	     * XtGetSubresources.  We can free our own strings, but not theirs.
21209a64e1c5Smrg	     */
21219a64e1c5Smrg	    ALLOC_STRING(subresourceRec.default_font.f_n);
21229a64e1c5Smrg	    ALLOC_STRING(subresourceRec.default_font.f_b);
21239a64e1c5Smrg#if OPT_WIDE_CHARS
21249a64e1c5Smrg	    ALLOC_STRING(subresourceRec.default_font.f_w);
21259a64e1c5Smrg	    ALLOC_STRING(subresourceRec.default_font.f_wb);
21269a64e1c5Smrg#endif
21279a64e1c5Smrg	    for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) {
21289a64e1c5Smrg		ALLOC_STRING(subresourceRec.MenuFontName(n));
21299a64e1c5Smrg	    }
21309a64e1c5Smrg
2131dfb07bc7Smrg	    /*
2132dfb07bc7Smrg	     * Now, save the string to a font-list for consistency
2133dfb07bc7Smrg	     */
2134dfb07bc7Smrg#define ALLOC_SUBLIST(which,field) \
2135dfb07bc7Smrg	    save2FontList(xw, "cached", \
2136dfb07bc7Smrg			  &(subresourceRec.fonts), \
2137dfb07bc7Smrg			  which, \
2138dfb07bc7Smrg			  subresourceRec.default_font.field, False)
2139dfb07bc7Smrg
2140dfb07bc7Smrg	    ALLOC_SUBLIST(fNorm, f_n);
2141dfb07bc7Smrg	    ALLOC_SUBLIST(fBold, f_b);
2142dfb07bc7Smrg#if OPT_WIDE_CHARS
2143dfb07bc7Smrg	    ALLOC_SUBLIST(fWide, f_w);
2144dfb07bc7Smrg	    ALLOC_SUBLIST(fWBold, f_wb);
2145dfb07bc7Smrg#endif
2146dfb07bc7Smrg
2147d522f475Smrg	    /*
2148d522f475Smrg	     * If a particular resource value was not found, use the original.
2149d522f475Smrg	     */
2150dfb07bc7Smrg	    MERGE_SUBFONT(subresourceRec, xw->misc, default_font.f_n);
2151dfb07bc7Smrg	    INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_b);
2152dfb07bc7Smrg	    MERGE_SUBLIST(subresourceRec, xw->work, list_n);
2153dfb07bc7Smrg	    MERGE_SUBLIST(subresourceRec, xw->work, list_b);
2154d522f475Smrg#if OPT_WIDE_CHARS
2155dfb07bc7Smrg	    INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_w);
2156dfb07bc7Smrg	    INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_wb);
2157dfb07bc7Smrg	    MERGE_SUBLIST(subresourceRec, xw->work, list_w);
2158dfb07bc7Smrg	    MERGE_SUBLIST(subresourceRec, xw->work, list_wb);
2159d522f475Smrg#endif
21609a64e1c5Smrg	    for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) {
2161dfb07bc7Smrg		MERGE_SUBFONT(subresourceRec, xw->screen, MenuFontName(n));
21629a64e1c5Smrg	    }
2163d522f475Smrg
2164d522f475Smrg	    /*
2165d522f475Smrg	     * Finally, copy the subresource data to the widget.
2166d522f475Smrg	     */
21679a64e1c5Smrg	    COPY_DEFAULT_FONTS(xw->misc, subresourceRec);
2168dfb07bc7Smrg	    COPY_X11_FONTLISTS(xw->work, subresourceRec);
21699a64e1c5Smrg	    FREE_MENU_FONTS(xw->screen);
2170dfb07bc7Smrg	    COPY_MENU_FONTS(xw->screen, subresourceRec);
21719a64e1c5Smrg
21729a64e1c5Smrg	    FREE_STRING(screen->MenuFontName(fontMenu_default));
21739a64e1c5Smrg	    FREE_STRING(screen->menu_font_names[0][fBold]);
2174dfb07bc7Smrg	    screen->MenuFontName(fontMenu_default) = x_strdup(DefaultFontN(xw));
2175dfb07bc7Smrg	    screen->menu_font_names[0][fBold] = x_strdup(DefaultFontB(xw));
2176d522f475Smrg#if OPT_WIDE_CHARS
21779a64e1c5Smrg	    FREE_STRING(screen->menu_font_names[0][fWide]);
21789a64e1c5Smrg	    FREE_STRING(screen->menu_font_names[0][fWBold]);
2179dfb07bc7Smrg	    screen->menu_font_names[0][fWide] = x_strdup(DefaultFontW(xw));
2180dfb07bc7Smrg	    screen->menu_font_names[0][fWBold] = x_strdup(DefaultFontWB(xw));
2181d522f475Smrg#endif
21829a64e1c5Smrg	    /*
21839a64e1c5Smrg	     * And remove our copies of strings.
21849a64e1c5Smrg	     */
21859a64e1c5Smrg	    FREE_STRING(subresourceRec.default_font.f_n);
21869a64e1c5Smrg	    FREE_STRING(subresourceRec.default_font.f_b);
21879a64e1c5Smrg#if OPT_WIDE_CHARS
21889a64e1c5Smrg	    FREE_STRING(subresourceRec.default_font.f_w);
21899a64e1c5Smrg	    FREE_STRING(subresourceRec.default_font.f_wb);
21909a64e1c5Smrg#endif
21919a64e1c5Smrg	    for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) {
21929a64e1c5Smrg		FREE_STRING(subresourceRec.MenuFontName(n));
21939a64e1c5Smrg	    }
2194d522f475Smrg	} else {
2195d522f475Smrg	    TRACE(("...no resources found\n"));
2196d522f475Smrg	    status = False;
2197d522f475Smrg	}
2198d522f475Smrg    }
2199dfb07bc7Smrg    TRACE((".. xtermLoadVTFonts: %d\n", status));
2200d522f475Smrg    return status;
2201d522f475Smrg}
2202d522f475Smrg
2203d522f475Smrg#if OPT_WIDE_CHARS
2204d522f475Smrgstatic Bool
22059a64e1c5SmrgisWideFont(XFontStruct *fp, const char *tag, Bool nullOk)
2206d522f475Smrg{
2207d522f475Smrg    Bool result = False;
2208d522f475Smrg
2209d522f475Smrg    (void) tag;
2210d522f475Smrg    if (okFont(fp)) {
2211d522f475Smrg	unsigned count = countGlyphs(fp);
2212d522f475Smrg	TRACE(("isWideFont(%s) found %d cells\n", tag, count));
2213d522f475Smrg	result = (count > 256) ? True : False;
2214d522f475Smrg    } else {
2215d522f475Smrg	result = nullOk;
2216d522f475Smrg    }
2217d522f475Smrg    return result;
2218d522f475Smrg}
2219d522f475Smrg
2220d522f475Smrg/*
2221d522f475Smrg * If the current fonts are not wide, load the UTF8 fonts.
2222d522f475Smrg *
2223d522f475Smrg * Called during initialization (for wide-character mode), the fonts have not
2224d522f475Smrg * been setup, so we pass nullOk=True to isWideFont().
2225d522f475Smrg *
2226d522f475Smrg * Called after initialization, e.g., in response to the UTF-8 menu entry
2227d522f475Smrg * (starting from narrow character mode), it checks if the fonts are not wide.
2228d522f475Smrg */
2229d522f475SmrgBool
2230d522f475SmrgxtermLoadWideFonts(XtermWidget xw, Bool nullOk)
2231d522f475Smrg{
2232956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2233d522f475Smrg    Bool result;
2234d522f475Smrg
2235d4fba8b9Smrg    if (EmptyFont(GetNormalFont(screen, fWide)->fs)) {
2236d4fba8b9Smrg	result = (isWideFont(GetNormalFont(screen, fNorm)->fs, "normal", nullOk)
2237d4fba8b9Smrg		  && isWideFont(GetNormalFont(screen, fBold)->fs, "bold", nullOk));
2238d522f475Smrg    } else {
2239d4fba8b9Smrg	result = (isWideFont(GetNormalFont(screen, fWide)->fs, "wide", nullOk)
2240d4fba8b9Smrg		  && isWideFont(GetNormalFont(screen, fWBold)->fs,
2241dfb07bc7Smrg				"wide-bold", nullOk));
2242d522f475Smrg	if (result && !screen->utf8_latin1) {
2243d4fba8b9Smrg	    result = (isWideFont(GetNormalFont(screen, fNorm)->fs, "normal", nullOk)
2244d4fba8b9Smrg		      && isWideFont(GetNormalFont(screen, fBold)->fs,
2245dfb07bc7Smrg				    "bold", nullOk));
2246d522f475Smrg	}
2247d522f475Smrg    }
2248d522f475Smrg    if (!result) {
2249d522f475Smrg	TRACE(("current fonts are not all wide%s\n", nullOk ? " nullOk" : ""));
2250e39b573cSmrg	result = xtermLoadVTFonts(xw, XtNutf8Fonts, XtCUtf8Fonts);
2251d522f475Smrg    }
2252d522f475Smrg    TRACE(("xtermLoadWideFonts:%d\n", result));
2253d522f475Smrg    return result;
2254d522f475Smrg}
2255d522f475Smrg#endif /* OPT_WIDE_CHARS */
2256d522f475Smrg
2257d522f475Smrg/*
2258d522f475Smrg * Restore the default fonts, i.e., if we had switched to wide-fonts.
2259d522f475Smrg */
2260d522f475SmrgBool
2261956cc18dSsnjxtermLoadDefaultFonts(XtermWidget xw)
2262d522f475Smrg{
2263d522f475Smrg    Bool result;
2264956cc18dSsnj    result = xtermLoadVTFonts(xw, NULL, NULL);
2265d522f475Smrg    TRACE(("xtermLoadDefaultFonts:%d\n", result));
2266d522f475Smrg    return result;
2267d522f475Smrg}
2268d522f475Smrg#endif /* OPT_LOAD_VTFONTS || OPT_WIDE_CHARS */
2269d522f475Smrg
2270d522f475Smrg#if OPT_LOAD_VTFONTS
2271d522f475Smrgvoid
2272d522f475SmrgHandleLoadVTFonts(Widget w,
22739a64e1c5Smrg		  XEvent *event GCC_UNUSED,
2274d4fba8b9Smrg		  String *params,
2275d4fba8b9Smrg		  Cardinal *param_count)
2276d522f475Smrg{
2277956cc18dSsnj    XtermWidget xw;
2278956cc18dSsnj
2279956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
2280037a25ddSmrg	static char empty[] = "";	/* appease strict compilers */
2281037a25ddSmrg
2282956cc18dSsnj	TScreen *screen = TScreenOf(xw);
2283492d43a5Smrg	char name_buf[80];
2284492d43a5Smrg	String name = (String) ((*param_count > 0) ? params[0] : empty);
228594644356Smrg	char *myName = MyStackAlloc(strlen(name) + 1, name_buf);
2286d522f475Smrg
2287d522f475Smrg	TRACE(("HandleLoadVTFonts(%d)\n", *param_count));
228894644356Smrg	if (myName != 0) {
2289037a25ddSmrg	    char class_buf[80];
229094644356Smrg	    String convert = (String) ((*param_count > 1) ? params[1] : myName);
229194644356Smrg	    char *myClass = MyStackAlloc(strlen(convert) + 1, class_buf);
229294644356Smrg
229394644356Smrg	    strcpy(myName, name);
229494644356Smrg	    if (myClass != 0) {
229594644356Smrg		strcpy(myClass, convert);
229694644356Smrg		if (*param_count == 1)
229794644356Smrg		    myClass[0] = x_toupper(myClass[0]);
229894644356Smrg
229994644356Smrg		if (xtermLoadVTFonts(xw, myName, myClass)) {
2300037a25ddSmrg		    int n;
230194644356Smrg		    /*
230294644356Smrg		     * When switching fonts, try to preserve the font-menu
230394644356Smrg		     * selection, since it is less surprising to do that (if
230494644356Smrg		     * the font-switching can be undone) than to switch to
230594644356Smrg		     * "Default".
230694644356Smrg		     */
230794644356Smrg		    int font_number = screen->menu_font_number;
230894644356Smrg		    if (font_number > fontMenu_lastBuiltin)
230994644356Smrg			font_number = fontMenu_lastBuiltin;
231094644356Smrg		    for (n = 0; n < NMENUFONTS; ++n) {
231194644356Smrg			screen->menu_font_sizes[n] = 0;
231294644356Smrg		    }
2313dfb07bc7Smrg		    if (font_number == fontMenu_default) {
2314dfb07bc7Smrg			SetVTFont(xw, font_number, True, defaultVTFontNames(xw));
2315dfb07bc7Smrg		    } else {
2316dfb07bc7Smrg			SetVTFont(xw, font_number, True, NULL);
2317dfb07bc7Smrg		    }
231894644356Smrg		}
231994644356Smrg		MyStackFree(myClass, class_buf);
23209a64e1c5Smrg	    }
232194644356Smrg	    MyStackFree(myName, name_buf);
2322d522f475Smrg	}
2323d522f475Smrg    }
2324d522f475Smrg}
2325d522f475Smrg#endif /* OPT_LOAD_VTFONTS */
2326d522f475Smrg
2327d522f475Smrg/*
2328d522f475Smrg * Set the limits for the box that outlines the cursor.
2329d522f475Smrg */
2330d522f475Smrgvoid
2331fa3f02f3SmrgxtermSetCursorBox(TScreen *screen)
2332d522f475Smrg{
2333d522f475Smrg    static XPoint VTbox[NBOX];
2334d522f475Smrg    XPoint *vp;
23352eaa94a1Schristos    int fw = FontWidth(screen) - 1;
23362eaa94a1Schristos    int fh = FontHeight(screen) - 1;
23370bd37d32Smrg    int ww = isCursorBar(screen) ? 1 : fw;
23380bd37d32Smrg    int hh = isCursorUnderline(screen) ? 1 : fh;
2339d522f475Smrg
2340d522f475Smrg    vp = &VTbox[1];
23410bd37d32Smrg    (vp++)->x = (short) ww;
23422eaa94a1Schristos    (vp++)->y = (short) hh;
23430bd37d32Smrg    (vp++)->x = (short) -ww;
23442eaa94a1Schristos    vp->y = (short) -hh;
23452eaa94a1Schristos
2346d522f475Smrg    screen->box = VTbox;
2347d522f475Smrg}
2348d522f475Smrg
2349d4fba8b9Smrg#if OPT_RENDERFONT
2350d4fba8b9Smrg
2351d4fba8b9Smrg#define CACHE_XFT(dst,src) if (src.font != 0) {\
2352d4fba8b9Smrg	    int err = checkXftWidth(xw, &(dst[fontnum]), &src);\
2353d4fba8b9Smrg	    TRACE(("Xft metrics %s[%d] = %d (%d,%d)%s advance %d, actual %d%s%s\n",\
2354d522f475Smrg		#dst,\
2355d4fba8b9Smrg		fontnum,\
2356d4fba8b9Smrg		src.font->height,\
2357d4fba8b9Smrg		src.font->ascent,\
2358d4fba8b9Smrg		src.font->descent,\
2359d4fba8b9Smrg		((src.font->ascent + src.font->descent) > src.font->height ? "*" : ""),\
2360d4fba8b9Smrg		src.font->max_advance_width,\
2361956cc18dSsnj		dst[fontnum].map.min_width,\
2362d4fba8b9Smrg		dst[fontnum].map.mixed ? " mixed" : "",\
2363d4fba8b9Smrg		err ? " ERROR" : ""));\
2364d4fba8b9Smrg	    if (err) {\
2365d4fba8b9Smrg		xtermCloseXft(screen, &src);\
2366d4fba8b9Smrg		memset((&dst[fontnum]), 0, sizeof(dst[fontnum]));\
2367d4fba8b9Smrg		failed += err;\
2368d4fba8b9Smrg	    }\
2369d522f475Smrg	}
2370d522f475Smrg
2371dfb07bc7Smrg#if OPT_REPORT_FONTS
237220d2c4d2Smrgstatic FcChar32
23739a64e1c5SmrgxtermXftFirstChar(XftFont *xft)
237420d2c4d2Smrg{
237520d2c4d2Smrg    FcChar32 map[FC_CHARSET_MAP_SIZE];
237620d2c4d2Smrg    FcChar32 next;
237720d2c4d2Smrg    FcChar32 first;
237820d2c4d2Smrg    int i;
237920d2c4d2Smrg
238020d2c4d2Smrg    first = FcCharSetFirstPage(xft->charset, map, &next);
23819a64e1c5Smrg    for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) {
238220d2c4d2Smrg	if (map[i]) {
238320d2c4d2Smrg	    FcChar32 bits = map[i];
2384fa3f02f3Smrg	    first += (FcChar32) i *32;
238520d2c4d2Smrg	    while (!(bits & 0x1)) {
238620d2c4d2Smrg		bits >>= 1;
238720d2c4d2Smrg		first++;
238820d2c4d2Smrg	    }
238920d2c4d2Smrg	    break;
239020d2c4d2Smrg	}
23919a64e1c5Smrg    }
239220d2c4d2Smrg    return first;
239320d2c4d2Smrg}
239420d2c4d2Smrg
239520d2c4d2Smrgstatic FcChar32
23969a64e1c5SmrgxtermXftLastChar(XftFont *xft)
239720d2c4d2Smrg{
239820d2c4d2Smrg    FcChar32 this, last, next;
239920d2c4d2Smrg    FcChar32 map[FC_CHARSET_MAP_SIZE];
240020d2c4d2Smrg    int i;
240120d2c4d2Smrg    last = FcCharSetFirstPage(xft->charset, map, &next);
240220d2c4d2Smrg    while ((this = FcCharSetNextPage(xft->charset, map, &next)) != FC_CHARSET_DONE)
240320d2c4d2Smrg	last = this;
2404fa3f02f3Smrg    last &= (FcChar32) ~ 0xff;
24059a64e1c5Smrg    for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--) {
240620d2c4d2Smrg	if (map[i]) {
240720d2c4d2Smrg	    FcChar32 bits = map[i];
2408fa3f02f3Smrg	    last += (FcChar32) i *32 + 31;
240920d2c4d2Smrg	    while (!(bits & 0x80000000)) {
241020d2c4d2Smrg		last--;
241120d2c4d2Smrg		bits <<= 1;
241220d2c4d2Smrg	    }
241320d2c4d2Smrg	    break;
241420d2c4d2Smrg	}
24159a64e1c5Smrg    }
2416dfb07bc7Smrg    return (FcChar32) last;
241720d2c4d2Smrg}
2418dfb07bc7Smrg#endif /* OPT_REPORT_FONTS */
241920d2c4d2Smrg
2420d4fba8b9Smrg#if OPT_TRACE
2421d4fba8b9Smrg
2422d4fba8b9Smrg#if !OPT_WIDE_CHARS
2423d4fba8b9Smrgstatic Char *
2424d4fba8b9SmrgconvertToUTF8(Char *buffer, int c)
2425d4fba8b9Smrg{
2426d4fba8b9Smrg    buffer[0] = (Char) c;
2427d4fba8b9Smrg    buffer[1] = 0;
2428d4fba8b9Smrg    return buffer;
2429d4fba8b9Smrg}
2430d4fba8b9Smrg#endif
2431d4fba8b9Smrg
243220d2c4d2Smrgstatic void
24339a64e1c5SmrgdumpXft(XtermWidget xw, XTermXftFonts *data)
243420d2c4d2Smrg{
243520d2c4d2Smrg    XftFont *xft = data->font;
243620d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
243720d2c4d2Smrg    VTwin *win = WhichVWin(screen);
243820d2c4d2Smrg
243920d2c4d2Smrg    FcChar32 c;
244020d2c4d2Smrg    FcChar32 first = xtermXftFirstChar(xft);
244120d2c4d2Smrg    FcChar32 last = xtermXftLastChar(xft);
2442d4fba8b9Smrg    FcChar32 dump;
244320d2c4d2Smrg    unsigned count = 0;
2444d4fba8b9Smrg    unsigned too_high = 0;
2445d4fba8b9Smrg    unsigned too_wide = 0;
2446d4fba8b9Smrg    Boolean skip = False;
2447d4fba8b9Smrg
2448d4fba8b9Smrg    TRACE(("dumpXft " TRACE_L "\n"));
2449d4fba8b9Smrg    TRACE(("\tdata range U+%04X..U+%04X\n", first, last));
2450d4fba8b9Smrg    TRACE(("\tcode\tcells\tdimensions\n"));
2451d4fba8b9Smrg#if OPT_TRACE < 2
2452d4fba8b9Smrg    dump = 255;
2453d4fba8b9Smrg#else
2454d4fba8b9Smrg    dump = last;
2455d4fba8b9Smrg#endif
245620d2c4d2Smrg    for (c = first; c <= last; ++c) {
245720d2c4d2Smrg	if (FcCharSetHasChar(xft->charset, c)) {
2458c48a5815Smrg	    int width = CharWidth(screen, c);
245920d2c4d2Smrg	    XGlyphInfo extents;
2460d4fba8b9Smrg	    Boolean big_x;
2461d4fba8b9Smrg	    Boolean big_y;
246220d2c4d2Smrg
246320d2c4d2Smrg	    XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents);
2464d4fba8b9Smrg	    big_x = (extents.width > win->f_width);
2465d4fba8b9Smrg	    big_y = (extents.height > win->f_height);
2466d4fba8b9Smrg
2467d4fba8b9Smrg	    if (c <= dump) {
2468d4fba8b9Smrg		Char buffer[80];
2469d4fba8b9Smrg
2470d4fba8b9Smrg		*convertToUTF8(buffer, c) = '\0';
2471d4fba8b9Smrg		TRACE(("%s%s\tU+%04X\t%d\t%.1f x %.1f\t%s\n",
2472d4fba8b9Smrg		       (big_y ? "y" : ""),
2473d4fba8b9Smrg		       (big_x ? "x" : ""),
2474d4fba8b9Smrg		       c, width,
2475d4fba8b9Smrg		       ((double) extents.height) / win->f_height,
2476d4fba8b9Smrg		       ((double) extents.width) / win->f_width,
2477d4fba8b9Smrg		       buffer));
2478d4fba8b9Smrg	    } else if (!skip) {
2479d4fba8b9Smrg		skip = True;
2480d4fba8b9Smrg		TRACE(("\t...skipping\n"));
2481d4fba8b9Smrg	    }
2482d4fba8b9Smrg	    if (big_y)
2483d4fba8b9Smrg		++too_high;
2484d4fba8b9Smrg	    if (big_x)
2485d4fba8b9Smrg		++too_wide;
248620d2c4d2Smrg	    ++count;
248720d2c4d2Smrg	}
248820d2c4d2Smrg    }
2489d4fba8b9Smrg    TRACE((TRACE_R " %u total, %u too-high, %u too-wide\n", count, too_high, too_wide));
249020d2c4d2Smrg}
249120d2c4d2Smrg#define DUMP_XFT(xw, data) dumpXft(xw, data)
249220d2c4d2Smrg#else
249320d2c4d2Smrg#define DUMP_XFT(xw, data)	/* nothing */
249420d2c4d2Smrg#endif
249520d2c4d2Smrg
2496d4fba8b9Smrg/*
2497d4fba8b9Smrg * Check if this is a FC_COLOR font, which fontconfig misrepresents to "fix" a
2498d4fba8b9Smrg * problem with web browsers.  As of 2018/12 (4 years later), Xft does not work
2499d4fba8b9Smrg * with that.  Even with this workaround, fontconfig has at least one bug which
2500d4fba8b9Smrg * causes it to crash (Debian #917034).
2501d4fba8b9Smrg */
2502d4fba8b9Smrg#ifdef FC_COLOR
2503d4fba8b9Smrg#define GetFcBool(pattern, what) \
2504d4fba8b9Smrg    (FcPatternGetBool(pattern, what, 0, &fcbogus) == FcResultMatch)
2505d4fba8b9Smrg
2506d4fba8b9Smrgstatic Boolean
2507d4fba8b9SmrgisBogusXft(XftFont *font)
2508d4fba8b9Smrg{
2509d4fba8b9Smrg    Boolean result = False;
2510d4fba8b9Smrg    if (font != 0) {
2511d4fba8b9Smrg	FcBool fcbogus;
2512d4fba8b9Smrg	if (GetFcBool(font->pattern, FC_COLOR) && fcbogus) {
2513d4fba8b9Smrg	    TRACE(("...matched color-bitmap font\n"));
2514d4fba8b9Smrg	    result = True;
2515d4fba8b9Smrg	} else if (GetFcBool(font->pattern, FC_OUTLINE) && !fcbogus) {
2516d4fba8b9Smrg	    TRACE(("...matched non-outline font\n"));
2517d4fba8b9Smrg	    /* This is legal for regular bitmap fonts - fontconfig attempts to
2518d4fba8b9Smrg	     * find a match - but problematic for misencoded color-bitmap fonts.
2519d4fba8b9Smrg	     */
2520d4fba8b9Smrg	}
2521d4fba8b9Smrg    }
2522d4fba8b9Smrg    return result;
2523d4fba8b9Smrg}
2524d4fba8b9Smrg#endif
2525d4fba8b9Smrg
2526d4fba8b9Smrg#if OPT_BOX_CHARS
2527956cc18dSsnjstatic void
2528d4fba8b9SmrgsetBrokenBoxChars(XtermWidget xw, Bool state)
2529d4fba8b9Smrg{
2530d4fba8b9Smrg    TRACE(("setBrokenBoxChars %s\n", BtoS(state)));
2531d4fba8b9Smrg    term->work.broken_box_chars = (Boolean) state;
2532d4fba8b9Smrg    TScreenOf(xw)->broken_box_chars = (Boolean) state;
2533d4fba8b9Smrg    update_font_boxchars();
2534d4fba8b9Smrg}
2535d4fba8b9Smrg
2536d4fba8b9Smrg#else
2537d4fba8b9Smrg#define setBrokenBoxChars(xw, state)	/* nothing */
2538d4fba8b9Smrg#endif
2539d4fba8b9Smrg
2540d4fba8b9Smrgstatic Boolean
2541d4fba8b9SmrgcheckedXftWidth(Display *dpy,
2542d4fba8b9Smrg		XTermXftFonts *source,
2543d4fba8b9Smrg		unsigned limit,
2544d4fba8b9Smrg		Dimension *width,
2545d4fba8b9Smrg		FcChar32 c)
2546d4fba8b9Smrg{
2547d4fba8b9Smrg    Boolean result = False;
2548d4fba8b9Smrg
2549d4fba8b9Smrg    if (FcCharSetHasChar(source->font->charset, c)) {
2550d4fba8b9Smrg	XGlyphInfo extents;
2551d4fba8b9Smrg
2552d4fba8b9Smrg	result = True;
2553d4fba8b9Smrg	XftTextExtents32(dpy, source->font, &c, 1, &extents);
2554d4fba8b9Smrg	if (*width < extents.width && extents.width <= limit) {
2555d4fba8b9Smrg	    *width = extents.width;
2556d4fba8b9Smrg	}
2557d4fba8b9Smrg    }
2558d4fba8b9Smrg    return result;
2559d4fba8b9Smrg}
2560d4fba8b9Smrg
2561d4fba8b9Smrgstatic int
2562d4fba8b9SmrgcheckXftWidth(XtermWidget xw, XTermXftFonts *target, XTermXftFonts *source)
2563956cc18dSsnj{
2564956cc18dSsnj    FcChar32 c;
2565d4fba8b9Smrg    FcChar32 last = xtermXftLastChar(source->font);
2566d4fba8b9Smrg    Dimension limit = (Dimension) source->font->max_advance_width;
2567956cc18dSsnj    Dimension width = 0;
2568d4fba8b9Smrg    Dimension width2 = 0;
2569d4fba8b9Smrg    int failed = 0;
2570d4fba8b9Smrg#if OPT_WIDE_CHARS
2571d4fba8b9Smrg    Cardinal n;
2572d4fba8b9Smrg#endif
2573956cc18dSsnj
2574d4fba8b9Smrg    target->font = source->font;
2575d4fba8b9Smrg    target->pattern = source->pattern;
2576d4fba8b9Smrg    target->map.min_width = 0;
2577d4fba8b9Smrg    target->map.max_width = limit;
2578d4fba8b9Smrg
2579d4fba8b9Smrg#if OPT_WIDE_CHARS
2580d4fba8b9Smrg    /*
2581d4fba8b9Smrg     * Check if the line-drawing characters are all provided in the font.
2582d4fba8b9Smrg     * If so, take that into account for the cell-widths.
2583d4fba8b9Smrg     */
2584d4fba8b9Smrg    for (n = 0; n < XtNumber(unicode_boxes) - 1; ++n) {
2585d4fba8b9Smrg	if (!checkedXftWidth(XtDisplay(xw),
2586d4fba8b9Smrg			     source,
2587d4fba8b9Smrg			     limit,
2588d4fba8b9Smrg			     &width2, unicode_boxes[n].code)) {
2589d4fba8b9Smrg	    width2 = 0;
2590d4fba8b9Smrg	    TRACE(("font omits U+%04X line-drawing symbol\n",
2591d4fba8b9Smrg		   unicode_boxes[n].code));
2592d4fba8b9Smrg	    break;
2593d4fba8b9Smrg	}
2594d4fba8b9Smrg    }
2595d4fba8b9Smrg#else
2596d4fba8b9Smrg    (void) width2;
2597d4fba8b9Smrg#endif
2598d4fba8b9Smrg
2599d4fba8b9Smrg    if (width2 > 0) {
2600d4fba8b9Smrg	Dimension check = (Dimension) (limit + 1) / 2;
2601d4fba8b9Smrg	TRACE(("font provides VT100-style line-drawing\n"));
2602d4fba8b9Smrg	/*
2603d4fba8b9Smrg	 * The "VT100 line-drawing" characters happen to be all "ambiguous
2604d4fba8b9Smrg	 * width" in Unicode's scheme.  That means that they could be twice as
2605d4fba8b9Smrg	 * wide as the Latin-1 characters.
2606d4fba8b9Smrg	 */
2607d4fba8b9Smrg#define FC_ERR(n) (1.2 * (n))
2608d4fba8b9Smrg	if (width2 > FC_ERR(check)) {
2609d4fba8b9Smrg	    TRACE(("line-drawing characters appear to be double-width (ignore)\n"));
2610d4fba8b9Smrg	    setBrokenBoxChars(xw, True);
2611d4fba8b9Smrg	} else if (width2 > width) {
2612d4fba8b9Smrg	    width = width2;
2613d4fba8b9Smrg	}
2614d4fba8b9Smrg    } else {
2615d4fba8b9Smrg	TRACE(("font does NOT provide VT100-style line-drawing\n"));
2616d4fba8b9Smrg	setBrokenBoxChars(xw, True);
2617d4fba8b9Smrg    }
2618956cc18dSsnj
261920d2c4d2Smrg    /*
2620d4fba8b9Smrg     * For each printable code, ask what its width is.  Given the maximum width
2621d4fba8b9Smrg     * for those, we have a reasonable estimate of the single-column width.
262220d2c4d2Smrg     *
262320d2c4d2Smrg     * Ignore control characters - their extent information is misleading.
262420d2c4d2Smrg     */
2625956cc18dSsnj    for (c = 32; c < 256; ++c) {
2626c48a5815Smrg	if (CharWidth(TScreenOf(xw), c) <= 0)
262720d2c4d2Smrg	    continue;
2628d4fba8b9Smrg	if (FcCharSetHasChar(source->font->charset, c)) {
2629d4fba8b9Smrg	    (void) checkedXftWidth(XtDisplay(xw),
2630d4fba8b9Smrg				   source,
2631d4fba8b9Smrg				   target->map.max_width,
2632d4fba8b9Smrg				   &width, c);
2633d4fba8b9Smrg	}
2634d4fba8b9Smrg    }
2635956cc18dSsnj
2636d4fba8b9Smrg    /*
2637d4fba8b9Smrg     * Sometimes someone uses a symbol font which has no useful ASCII or
2638d4fba8b9Smrg     * Latin-1 characters.  Allow that, in case they did it intentionally.
2639d4fba8b9Smrg     */
2640d4fba8b9Smrg    if (width == 0) {
2641d4fba8b9Smrg	failed = 1;
2642d4fba8b9Smrg	if (last >= 256) {
2643d4fba8b9Smrg	    width = target->map.max_width;
2644956cc18dSsnj	}
2645956cc18dSsnj    }
2646d4fba8b9Smrg    target->map.min_width = width;
2647d4fba8b9Smrg    target->map.mixed = (target->map.max_width >= (target->map.min_width + 1));
2648d4fba8b9Smrg    return failed;
2649956cc18dSsnj}
2650956cc18dSsnj
2651dfb07bc7Smrg#if OPT_REPORT_FONTS
2652fa3f02f3Smrgstatic void
2653fa3f02f3SmrgreportXftFonts(XtermWidget xw,
26549a64e1c5Smrg	       XftFont *fp,
2655fa3f02f3Smrg	       const char *name,
2656fa3f02f3Smrg	       const char *tag,
26579a64e1c5Smrg	       XftPattern *match)
2658fa3f02f3Smrg{
2659fa3f02f3Smrg    if (resource.reportFonts) {
2660fa3f02f3Smrg	char buffer[1024];
2661fa3f02f3Smrg	FcChar32 first_char = xtermXftFirstChar(fp);
2662fa3f02f3Smrg	FcChar32 last_char = xtermXftLastChar(fp);
2663fa3f02f3Smrg	FcChar32 ch;
2664fa3f02f3Smrg	unsigned missing = 0;
2665fa3f02f3Smrg
266694644356Smrg	printf("Loaded XftFonts(%s[%s])\n", name, tag);
2667fa3f02f3Smrg
2668fa3f02f3Smrg	for (ch = first_char; ch <= last_char; ++ch) {
2669fa3f02f3Smrg	    if (xtermXftMissing(xw, fp, ch)) {
2670fa3f02f3Smrg		++missing;
2671fa3f02f3Smrg	    }
2672fa3f02f3Smrg	}
2673fa3f02f3Smrg	printf("\t\tfirst char:    %u\n", first_char);
2674fa3f02f3Smrg	printf("\t\tlast char:     %u\n", last_char);
2675fa3f02f3Smrg	printf("\t\tmissing-chars: %u\n", missing);
2676fa3f02f3Smrg	printf("\t\tpresent-chars: %u\n", (last_char - first_char) + 1 - missing);
2677fa3f02f3Smrg
2678fa3f02f3Smrg	if (XftNameUnparse(match, buffer, (int) sizeof(buffer))) {
2679fa3f02f3Smrg	    char *target;
2680fa3f02f3Smrg	    char *source = buffer;
2681fa3f02f3Smrg	    while ((target = strtok(source, ":")) != 0) {
2682fa3f02f3Smrg		printf("\t%s\n", target);
2683fa3f02f3Smrg		source = 0;
2684fa3f02f3Smrg	    }
2685fa3f02f3Smrg	}
2686d4fba8b9Smrg	fflush(stdout);
2687fa3f02f3Smrg    }
2688fa3f02f3Smrg}
2689dfb07bc7Smrg#else
2690dfb07bc7Smrg#define reportXftFonts(xw, result, name, tag, match)	/* empty */
2691dfb07bc7Smrg#endif /* OPT_REPORT_FONTS */
2692fa3f02f3Smrg
2693d4fba8b9Smrg/*
2694d4fba8b9Smrg * Xft discards the pattern-match during open-pattern if the result happens to
2695d4fba8b9Smrg * match a currently-open file, but provides no clue to the caller when it does
2696d4fba8b9Smrg * this.  That is, closing a font-file may leave the data in Xft's cache, while
2697d4fba8b9Smrg * opening a file may free the data used for the match.
2698d4fba8b9Smrg *
2699d4fba8b9Smrg * Because of this problem, we cannot reliably refer to the pattern-match data
2700d4fba8b9Smrg * if it may have been seen before.
2701d4fba8b9Smrg */
2702d4fba8b9SmrgBoolean
2703d4fba8b9SmrgmaybeXftCache(XtermWidget xw, XftFont *font)
2704d4fba8b9Smrg{
2705d4fba8b9Smrg    Boolean result = False;
2706d4fba8b9Smrg    if (font != 0) {
2707d4fba8b9Smrg	TScreen *screen = TScreenOf(xw);
2708d4fba8b9Smrg	ListXftFonts *p;
2709d4fba8b9Smrg	for (p = screen->list_xft_fonts; p != 0; p = p->next) {
2710d4fba8b9Smrg	    if (p->font == font) {
2711d4fba8b9Smrg		result = True;
2712d4fba8b9Smrg		break;
2713d4fba8b9Smrg	    }
2714d4fba8b9Smrg	}
2715d4fba8b9Smrg	if (!result) {
2716d4fba8b9Smrg	    p = TypeXtMalloc(ListXftFonts);
2717d4fba8b9Smrg	    if (p != 0) {
2718d4fba8b9Smrg		p->font = font;
2719d4fba8b9Smrg		p->next = screen->list_xft_fonts;
2720d4fba8b9Smrg		screen->list_xft_fonts = p;
2721d4fba8b9Smrg	    }
2722d4fba8b9Smrg	}
2723d4fba8b9Smrg    }
2724d4fba8b9Smrg    return result;
2725d4fba8b9Smrg}
2726d4fba8b9Smrg
2727d4fba8b9Smrg/*
2728d4fba8b9Smrg * Drop an entry from the cache, and close the font.
2729d4fba8b9Smrg */
2730d4fba8b9Smrgvoid
2731d4fba8b9SmrgcloseCachedXft(TScreen *screen, XftFont *font)
2732d4fba8b9Smrg{
2733d4fba8b9Smrg    if (font != 0) {
2734d4fba8b9Smrg	ListXftFonts *p, *q;
2735d4fba8b9Smrg
2736d4fba8b9Smrg	for (p = screen->list_xft_fonts, q = 0; p != 0; q = p, p = p->next) {
2737d4fba8b9Smrg	    if (p->font == font) {
2738d4fba8b9Smrg		XftFontClose(screen->display, font);
2739d4fba8b9Smrg		if (q != 0) {
2740d4fba8b9Smrg		    q->next = p->next;
2741d4fba8b9Smrg		} else {
2742d4fba8b9Smrg		    screen->list_xft_fonts = p->next;
2743d4fba8b9Smrg		}
2744d4fba8b9Smrg		free(p);
2745d4fba8b9Smrg		break;
2746d4fba8b9Smrg	    }
2747d4fba8b9Smrg	}
2748d4fba8b9Smrg    }
2749d4fba8b9Smrg}
2750d4fba8b9Smrg
2751d522f475Smrgstatic XftFont *
27529a64e1c5SmrgxtermOpenXft(XtermWidget xw, const char *name, XftPattern *pat, const char *tag)
2753d522f475Smrg{
2754956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2755956cc18dSsnj    Display *dpy = screen->display;
2756d522f475Smrg    XftResult status;
2757d522f475Smrg    XftFont *result = 0;
2758d522f475Smrg
2759d4fba8b9Smrg    TRACE(("xtermOpenXft(name=%s, tag=%s)\n", name, tag));
2760d522f475Smrg    if (pat != 0) {
2761d4fba8b9Smrg	XftPattern *match;
2762d4fba8b9Smrg
2763d4fba8b9Smrg	FcConfigSubstitute(NULL, pat, FcMatchPattern);
2764d4fba8b9Smrg	XftDefaultSubstitute(dpy, DefaultScreen(dpy), pat);
2765d4fba8b9Smrg
2766d4fba8b9Smrg	match = FcFontMatch(NULL, pat, &status);
2767d522f475Smrg	if (match != 0) {
2768d4fba8b9Smrg	    Boolean maybeReopened = False;
2769d522f475Smrg	    result = XftFontOpenPattern(dpy, match);
2770d4fba8b9Smrg#ifdef FC_COLOR
2771d4fba8b9Smrg	    if (result != 0) {
2772d4fba8b9Smrg		if (isBogusXft(result)) {
2773d4fba8b9Smrg		    XftFontClose(dpy, result);
2774d4fba8b9Smrg		    result = 0;
2775d4fba8b9Smrg		    maybeReopened = True;
2776d4fba8b9Smrg		}
2777d4fba8b9Smrg	    }
2778d4fba8b9Smrg#endif
2779d522f475Smrg	    if (result != 0) {
2780d522f475Smrg		TRACE(("...matched %s font\n", tag));
2781d4fba8b9Smrg		if (!maybeXftCache(xw, result)) {
2782d4fba8b9Smrg		    reportXftFonts(xw, result, name, tag, match);
2783d4fba8b9Smrg		}
2784d522f475Smrg	    } else {
2785d4fba8b9Smrg		TRACE(("...could not open %s font\n", tag));
2786d4fba8b9Smrg		if (!maybeReopened)
2787d4fba8b9Smrg		    XftPatternDestroy(match);
2788956cc18dSsnj		if (xw->misc.fontWarnings >= fwAlways) {
2789dfb07bc7Smrg		    cannotFont(xw, "open", tag, name);
2790956cc18dSsnj		}
2791d522f475Smrg	    }
2792d522f475Smrg	} else {
2793d522f475Smrg	    TRACE(("...did not match %s font\n", tag));
2794956cc18dSsnj	    if (xw->misc.fontWarnings >= fwResource) {
2795dfb07bc7Smrg		cannotFont(xw, "match", tag, name);
2796956cc18dSsnj	    }
2797d522f475Smrg	}
2798d522f475Smrg    }
2799d522f475Smrg    return result;
2800d522f475Smrg}
2801d522f475Smrg
2802d522f475Smrg#if OPT_SHIFT_FONTS
2803d522f475Smrg/*
2804d522f475Smrg * Don't make a dependency on the math library for a single function.
2805d522f475Smrg * (Newton Raphson).
2806d522f475Smrg */
2807d522f475Smrgstatic double
28080bd37d32SmrgdimSquareRoot(double value)
2809d522f475Smrg{
2810d522f475Smrg    double result = 0.0;
2811d522f475Smrg    if (value > 0.0) {
2812d522f475Smrg	int n;
2813d522f475Smrg	double older = value;
2814d522f475Smrg	for (n = 0; n < 10; ++n) {
2815d522f475Smrg	    double delta = (older * older - value) / (2.0 * older);
2816d522f475Smrg	    double newer = older - delta;
2817d522f475Smrg	    older = newer;
2818d522f475Smrg	    result = newer;
2819d522f475Smrg	    if (delta > -0.001 && delta < 0.001)
2820d522f475Smrg		break;
2821d522f475Smrg	}
2822d522f475Smrg    }
2823d522f475Smrg    return result;
2824d522f475Smrg}
2825d522f475Smrg#endif
2826d522f475Smrg
2827d4fba8b9Smrg#ifdef DEBUG_XFT
2828d4fba8b9Smrgstatic void
2829d4fba8b9Smrgtrace_xft_glyph(TScreen *screen, XftFont *font, FT_Face face, int code, const char *name)
2830d4fba8b9Smrg{
2831d4fba8b9Smrg    if (!XftGlyphExists(screen->display, font, code)) {
2832d4fba8b9Smrg	TRACE(("Xft glyph U+%04X missing :%s\n", code, name));
2833d4fba8b9Smrg    } else if (FT_Load_Char(face, code, FT_LOAD_RENDER) == 0) {
2834d4fba8b9Smrg	FT_GlyphSlot g = face->glyph;
2835d4fba8b9Smrg	TRACE(("Xft glyph U+%04X size(%3d,%3d) at(%3d,%3d) :%s\n",
2836d4fba8b9Smrg	       code,
2837d4fba8b9Smrg	       g->bitmap.rows, g->bitmap.width,
2838d4fba8b9Smrg	       g->bitmap_top, g->bitmap_left,
2839d4fba8b9Smrg	       name));
2840d4fba8b9Smrg    }
2841d4fba8b9Smrg}
2842d4fba8b9Smrg
2843d4fba8b9Smrg#if OPT_WIDE_CHARS
2844d4fba8b9Smrgstatic void
2845d4fba8b9Smrgtrace_xft_line_drawing(TScreen *screen, XftFont *font, FT_Face face)
2846d4fba8b9Smrg{
2847d4fba8b9Smrg    int n;
2848d4fba8b9Smrg    for (n = 0; unicode_boxes[n].code != 0; ++n) {
2849d4fba8b9Smrg	trace_xft_glyph(screen, font, face, unicode_boxes[n].code,
2850d4fba8b9Smrg			unicode_boxes[n].name);
2851d4fba8b9Smrg    }
2852d4fba8b9Smrg}
2853d4fba8b9Smrg#else
2854d4fba8b9Smrg#define trace_xft_line_drawing(screen, font, face)	/* nothing */
2855d4fba8b9Smrg#endif
2856d4fba8b9Smrg#endif /* DEBUG_XFT */
2857d4fba8b9Smrg
2858d4fba8b9Smrg/*
2859d4fba8b9Smrg * Check if the line-drawing characters do not fill the bounding box.  If so,
2860d4fba8b9Smrg * they're not useful.
2861d4fba8b9Smrg */
2862d4fba8b9Smrg#if OPT_BOX_CHARS
2863d4fba8b9Smrgstatic void
2864d4fba8b9Smrglinedrawing_gaps(XtermWidget xw, XftFont *font)
2865d4fba8b9Smrg{
2866d4fba8b9Smrg    Boolean broken;
2867d4fba8b9Smrg
2868d4fba8b9Smrg#if OPT_WIDE_CHARS
2869d4fba8b9Smrg    TScreen *screen = TScreenOf(xw);
2870d4fba8b9Smrg    int n;
2871d4fba8b9Smrg    FT_Face face;
2872d4fba8b9Smrg    face = XftLockFace(font);
2873d4fba8b9Smrg    broken = False;
2874d4fba8b9Smrg    for (n = 0; unicode_boxes[n].code; ++n) {
2875d4fba8b9Smrg	unsigned code = unicode_boxes[n].code;
2876d4fba8b9Smrg
2877d4fba8b9Smrg	if (!XftGlyphExists(screen->display, font, code)) {
2878d4fba8b9Smrg	    TRACE(("Xft glyph U+%04X is missing\n", code));
2879d4fba8b9Smrg	    broken = True;
2880d4fba8b9Smrg	    break;
2881d4fba8b9Smrg	}
2882d4fba8b9Smrg
2883d4fba8b9Smrg	if (FT_Load_Char(face, code, FT_LOAD_RENDER) == 0) {
2884d4fba8b9Smrg	    FT_GlyphSlot g = face->glyph;
2885d4fba8b9Smrg	    TRACE(("Xft glyph U+%04X size(%3d,%3d) at(%3d,%3d) :%s\n",
2886d4fba8b9Smrg		   code,
2887d4fba8b9Smrg		   g->bitmap.rows, g->bitmap.width,
2888d4fba8b9Smrg		   g->bitmap_top, g->bitmap_left,
2889d4fba8b9Smrg		   unicode_boxes[n].name));
2890d4fba8b9Smrg	    /*
2891d4fba8b9Smrg	     * While it is possible for badly-designed fonts to have line
2892d4fba8b9Smrg	     * drawing characters which do not meet, FreeType aggravates the
2893d4fba8b9Smrg	     * situation with its rounding.  Check for an obvious case where
2894d4fba8b9Smrg	     * the weights at the ends of a vertical line do not add up.  That
2895d4fba8b9Smrg	     * shows up as two under-weight rows at the beginning/end of the
2896d4fba8b9Smrg	     * bitmap.
2897d4fba8b9Smrg	     */
2898d4fba8b9Smrg	    if (code == 0x2502) {
2899d4fba8b9Smrg		unsigned r, c;
2900d4fba8b9Smrg		unsigned mids = 0, ends = 0;
2901d4fba8b9Smrg		unsigned char *data = g->bitmap.buffer;
2902d4fba8b9Smrg
2903d4fba8b9Smrg		switch (g->bitmap.pixel_mode) {
2904d4fba8b9Smrg		case FT_PIXEL_MODE_MONO:
2905d4fba8b9Smrg		    /* FALLTHRU */
2906d4fba8b9Smrg		case FT_PIXEL_MODE_GRAY:
2907d4fba8b9Smrg		    for (r = 0; r < (unsigned) g->bitmap.rows; ++r) {
2908d4fba8b9Smrg			unsigned k = r * (unsigned) g->bitmap.pitch;
2909d4fba8b9Smrg			unsigned sum = 0;
2910d4fba8b9Smrg			for (c = 0; c < (unsigned) g->bitmap.width; ++c) {
2911d4fba8b9Smrg			    unsigned xx = 0;
2912d4fba8b9Smrg			    switch (g->bitmap.pixel_mode) {
2913d4fba8b9Smrg			    case FT_PIXEL_MODE_MONO:
2914d4fba8b9Smrg				xx = (unsigned) ((data[k + (c / 8)]
2915d4fba8b9Smrg						  >> (c % 8)) & 1);
2916d4fba8b9Smrg				break;
2917d4fba8b9Smrg			    case FT_PIXEL_MODE_GRAY:
2918d4fba8b9Smrg				xx = data[k + c];
2919d4fba8b9Smrg				break;
2920d4fba8b9Smrg			    }
2921d4fba8b9Smrg			    sum += xx;
2922d4fba8b9Smrg			    TRACE2((" %2x", xx));
2923d4fba8b9Smrg			}
2924d4fba8b9Smrg			TRACE2((" = %u\n", sum));
2925d4fba8b9Smrg			if (r > 0 && (r + 1) < (unsigned) g->bitmap.rows) {
2926d4fba8b9Smrg			    mids = sum;
2927d4fba8b9Smrg			} else {
2928d4fba8b9Smrg			    ends += sum;
2929d4fba8b9Smrg			}
2930d4fba8b9Smrg		    }
2931d4fba8b9Smrg		    TRACE(("...compare middle %u vs ends %u\n", mids, ends));
2932d4fba8b9Smrg		    if ((mids > ends) && (g->bitmap.rows < 16))
2933d4fba8b9Smrg			broken = True;
2934d4fba8b9Smrg		    break;
2935d4fba8b9Smrg		default:
2936d4fba8b9Smrg		    TRACE(("FIXME pixel_mode %d not handled\n",
2937d4fba8b9Smrg			   g->bitmap.pixel_mode));
2938d4fba8b9Smrg		    break;
2939d4fba8b9Smrg		}
2940d4fba8b9Smrg		if (broken)
2941d4fba8b9Smrg		    break;
2942d4fba8b9Smrg	    }
2943d4fba8b9Smrg	    /*
2944d4fba8b9Smrg	     * The factor of two accounts for line-drawing that goes through
2945d4fba8b9Smrg	     * the middle of a cell, possibly leaving half of the cell unused.
2946d4fba8b9Smrg	     * A horizontal line has to extend the full width of the cell.
2947d4fba8b9Smrg	     */
2948d4fba8b9Smrg	    switch (unicode_boxes[n].high) {
2949d4fba8b9Smrg	    case 1:
2950d4fba8b9Smrg		if ((unsigned) g->bitmap.rows < (unsigned) FontHeight(screen)) {
2951d4fba8b9Smrg		    TRACE(("...bitmap is shorter than full-cell (%u vs %u)\n",
2952d4fba8b9Smrg			   (unsigned) g->bitmap.rows,
2953d4fba8b9Smrg			   (unsigned) FontHeight(screen)));
2954d4fba8b9Smrg		    broken = True;
2955d4fba8b9Smrg		}
2956d4fba8b9Smrg		break;
2957d4fba8b9Smrg	    case 2:
2958d4fba8b9Smrg		if ((unsigned) (g->bitmap.rows * 2) < (unsigned) FontHeight(screen)) {
2959d4fba8b9Smrg		    TRACE(("...bitmap is too short for half-cell (%u vs %u)\n",
2960d4fba8b9Smrg			   (unsigned) (g->bitmap.rows * 2),
2961d4fba8b9Smrg			   (unsigned) FontHeight(screen)));
2962d4fba8b9Smrg		    broken = True;
2963d4fba8b9Smrg		}
2964d4fba8b9Smrg		break;
2965d4fba8b9Smrg	    }
2966d4fba8b9Smrg	    switch (unicode_boxes[n].wide) {
2967d4fba8b9Smrg	    case 1:
2968d4fba8b9Smrg		if ((unsigned) g->bitmap.width < (unsigned) FontWidth(screen)) {
2969d4fba8b9Smrg		    TRACE(("...bitmap is narrower than full-cell (%u vs %u)\n",
2970d4fba8b9Smrg			   (unsigned) g->bitmap.width,
2971d4fba8b9Smrg			   (unsigned) FontWidth(screen)));
2972d4fba8b9Smrg		    broken = True;
2973d4fba8b9Smrg		}
2974d4fba8b9Smrg		break;
2975d4fba8b9Smrg	    case 2:
2976d4fba8b9Smrg		if ((unsigned) (g->bitmap.width * 2) < (unsigned) FontWidth(screen)) {
2977d4fba8b9Smrg		    TRACE(("...bitmap is too narrow for half-cell (%u vs %u)\n",
2978d4fba8b9Smrg			   (unsigned) (g->bitmap.width * 2),
2979d4fba8b9Smrg			   (unsigned) FontWidth(screen)));
2980d4fba8b9Smrg		    broken = True;
2981d4fba8b9Smrg		}
2982d4fba8b9Smrg		break;
2983d4fba8b9Smrg	    }
2984d4fba8b9Smrg	    if (broken)
2985d4fba8b9Smrg		break;
2986d4fba8b9Smrg	}
2987d4fba8b9Smrg    }
2988d4fba8b9Smrg    XftUnlockFace(font);
2989d4fba8b9Smrg#else
2990d4fba8b9Smrg    (void) font;
2991d4fba8b9Smrg    broken = True;
2992d4fba8b9Smrg#endif
2993d4fba8b9Smrg
2994d4fba8b9Smrg    if (broken) {
2995d4fba8b9Smrg	TRACE(("Xft line-drawing would not work\n"));
2996d4fba8b9Smrg	setBrokenBoxChars(xw, True);
2997d4fba8b9Smrg    }
2998d4fba8b9Smrg}
2999d4fba8b9Smrg#endif /* OPT_BOX_CHARS */
3000d4fba8b9Smrg
3001d522f475Smrg/*
3002d522f475Smrg * Given the Xft font metrics, determine the actual font size.  This is used
3003d522f475Smrg * for each font to ensure that normal, bold and italic fonts follow the same
3004d522f475Smrg * rule.
3005d522f475Smrg */
3006d522f475Smrgstatic void
3007d4fba8b9SmrgsetRenderFontsize(XtermWidget xw, VTwin *win, XftFont *font, const char *tag)
3008d522f475Smrg{
3009d522f475Smrg    if (font != 0) {
3010d4fba8b9Smrg	TScreen *screen = TScreenOf(xw);
3011d522f475Smrg	int width, height, ascent, descent;
3012d4fba8b9Smrg#ifdef DEBUG_XFT
3013d4fba8b9Smrg	int n;
3014d4fba8b9Smrg	FT_Face face;
3015d4fba8b9Smrg	FT_Size size;
3016d4fba8b9Smrg	FT_Size_Metrics metrics;
3017d4fba8b9Smrg	Boolean scalable;
3018d4fba8b9Smrg	Boolean is_fixed;
3019d4fba8b9Smrg	Boolean debug_xft = False;
3020d4fba8b9Smrg
3021d4fba8b9Smrg	face = XftLockFace(font);
3022d4fba8b9Smrg	size = face->size;
3023d4fba8b9Smrg	metrics = size->metrics;
3024d4fba8b9Smrg	is_fixed = FT_IS_FIXED_WIDTH(face);
3025d4fba8b9Smrg	scalable = FT_IS_SCALABLE(face);
3026d4fba8b9Smrg	trace_xft_line_drawing(screen, font, face);
3027d4fba8b9Smrg	for (n = 32; n < 127; ++n) {
3028d4fba8b9Smrg	    char name[80];
3029d4fba8b9Smrg	    sprintf(name, "letter \"%c\"", n);
3030d4fba8b9Smrg	    trace_xft_glyph(screen, font, face, n, name);
3031d4fba8b9Smrg	}
3032d4fba8b9Smrg	XftUnlockFace(font);
3033d4fba8b9Smrg
3034d4fba8b9Smrg	/* freetype's inconsistent for this sign */
3035d4fba8b9Smrg	metrics.descender = -metrics.descender;
3036d4fba8b9Smrg
3037d4fba8b9Smrg#define TR_XFT	   "Xft metrics: "
3038d4fba8b9Smrg#define D_64(name) ((double)(metrics.name)/64.0)
3039d4fba8b9Smrg#define M_64(a,b)  ((font->a * 64) != metrics.b)
3040d4fba8b9Smrg#define BOTH(a,b)  D_64(b), M_64(a,b) ? "*" : ""
3041d4fba8b9Smrg
3042d4fba8b9Smrg	debug_xft = (M_64(ascent, ascender)
3043d4fba8b9Smrg		     || M_64(descent, descender)
3044d4fba8b9Smrg		     || M_64(height, height)
3045d4fba8b9Smrg		     || M_64(max_advance_width, max_advance));
3046d4fba8b9Smrg
3047d4fba8b9Smrg	TRACE(("Xft font is %sscalable, %sfixed-width\n",
3048d4fba8b9Smrg	       is_fixed ? "" : "not ",
3049d4fba8b9Smrg	       scalable ? "" : "not "));
3050d4fba8b9Smrg
3051d4fba8b9Smrg	if (debug_xft) {
3052d4fba8b9Smrg	    TRACE(("Xft font size %d+%d vs %d by %d\n",
3053d4fba8b9Smrg		   font->ascent,
3054d4fba8b9Smrg		   font->descent,
3055d4fba8b9Smrg		   font->height,
3056d4fba8b9Smrg		   font->max_advance_width));
3057d4fba8b9Smrg	    TRACE((TR_XFT "ascender    %6.2f%s\n", BOTH(ascent, ascender)));
3058d4fba8b9Smrg	    TRACE((TR_XFT "descender   %6.2f%s\n", BOTH(descent, descender)));
3059d4fba8b9Smrg	    TRACE((TR_XFT "height      %6.2f%s\n", BOTH(height, height)));
3060d4fba8b9Smrg	    TRACE((TR_XFT "max_advance %6.2f%s\n", BOTH(max_advance_width, max_advance)));
3061d4fba8b9Smrg	} else {
3062d4fba8b9Smrg	    TRACE((TR_XFT "matches font\n"));
3063d4fba8b9Smrg	}
3064d4fba8b9Smrg#endif
3065d522f475Smrg
3066d522f475Smrg	width = font->max_advance_width;
3067d522f475Smrg	height = font->height;
3068d522f475Smrg	ascent = font->ascent;
3069d522f475Smrg	descent = font->descent;
3070d4fba8b9Smrg	if (screen->force_xft_height && height < ascent + descent) {
3071d4fba8b9Smrg	    TRACE(("...height is less than ascent + descent (%u vs %u)\n",
3072d4fba8b9Smrg		   height, ascent + descent));
3073d4fba8b9Smrg	    if ((ascent + descent) > (height + 1)) {
3074d4fba8b9Smrg		/* this happens less than 10% of the time */
3075d4fba8b9Smrg		--ascent;
3076d4fba8b9Smrg		--descent;
3077d4fba8b9Smrg		TRACE(("...decrement both ascent and descent before retry\n"));
3078d4fba8b9Smrg	    } else if (ascent > descent) {
3079d4fba8b9Smrg		/* this is the usual case */
3080d4fba8b9Smrg		--ascent;
3081d4fba8b9Smrg		TRACE(("...decrement ascent before retry\n"));
3082d4fba8b9Smrg	    } else {
3083d4fba8b9Smrg		/* this could happen, though rare... */
3084d4fba8b9Smrg		--descent;
3085d4fba8b9Smrg		TRACE(("...decrement descent before retry\n"));
3086d4fba8b9Smrg	    }
3087d522f475Smrg	    height = ascent + descent;
3088d4fba8b9Smrg	    font->ascent = ascent;
3089d4fba8b9Smrg	    font->descent = descent;
3090d4fba8b9Smrg	    TRACE(("...updated height %d vs %d (ascent %d, descent %d)\n",
3091d4fba8b9Smrg		   height, ascent + descent, ascent, descent));
3092d522f475Smrg	}
3093d522f475Smrg	if (is_double_width_font_xft(screen->display, font)) {
3094d4fba8b9Smrg	    TRACE(("...reduce width from %d to %d\n", width, width >> 1));
3095d522f475Smrg	    width >>= 1;
3096d522f475Smrg	}
3097d522f475Smrg	if (tag == 0) {
30980bd37d32Smrg	    SetFontWidth(screen, win, width);
30990bd37d32Smrg	    SetFontHeight(screen, win, height);
3100d522f475Smrg	    win->f_ascent = ascent;
3101d522f475Smrg	    win->f_descent = descent;
3102d522f475Smrg	    TRACE(("setRenderFontsize result %dx%d (%d+%d)\n",
3103d522f475Smrg		   width, height, ascent, descent));
3104d522f475Smrg	} else if (win->f_width < width ||
3105d522f475Smrg		   win->f_height < height ||
3106d522f475Smrg		   win->f_ascent < ascent ||
3107d522f475Smrg		   win->f_descent < descent) {
3108d522f475Smrg	    TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n",
3109d522f475Smrg		   tag,
3110d522f475Smrg		   win->f_width, win->f_height, win->f_ascent, win->f_descent,
3111d522f475Smrg		   width, height, ascent, descent));
3112d522f475Smrg
31130bd37d32Smrg	    SetFontWidth(screen, win, width);
31140bd37d32Smrg	    SetFontHeight(screen, win, height);
3115d522f475Smrg	    win->f_ascent = ascent;
3116d522f475Smrg	    win->f_descent = descent;
3117d522f475Smrg	} else {
3118d522f475Smrg	    TRACE(("setRenderFontsize %s unchanged\n", tag));
3119d522f475Smrg	}
3120d4fba8b9Smrg#if OPT_BOX_CHARS
3121d4fba8b9Smrg	if (!screen->broken_box_chars && (tag == 0)) {
3122d4fba8b9Smrg	    linedrawing_gaps(xw, font);
3123d4fba8b9Smrg	}
3124d4fba8b9Smrg#endif
3125d522f475Smrg    }
3126d522f475Smrg}
3127d522f475Smrg#endif
3128d522f475Smrg
312920d2c4d2Smrgstatic void
3130d4fba8b9SmrgcheckFontInfo(int value, const char *tag, int failed)
313120d2c4d2Smrg{
3132d4fba8b9Smrg    if (value == 0 || failed) {
3133d4fba8b9Smrg	if (value == 0) {
3134d4fba8b9Smrg	    xtermWarning("Selected font has no non-zero %s for ISO-8859-1 encoding\n", tag);
3135d4fba8b9Smrg	    exit(1);
3136d4fba8b9Smrg	} else {
3137d4fba8b9Smrg	    xtermWarning("Selected font has no valid %s for ISO-8859-1 encoding\n", tag);
3138d4fba8b9Smrg	}
313920d2c4d2Smrg    }
314020d2c4d2Smrg}
314120d2c4d2Smrg
314220d2c4d2Smrg#if OPT_RENDERFONT
314320d2c4d2Smrgvoid
31449a64e1c5SmrgxtermCloseXft(TScreen *screen, XTermXftFonts *pub)
314520d2c4d2Smrg{
314620d2c4d2Smrg    if (pub->font != 0) {
3147d4fba8b9Smrg	Cardinal n;
3148d4fba8b9Smrg
3149d4fba8b9Smrg	closeCachedXft(screen, pub->font);
315020d2c4d2Smrg	pub->font = 0;
3151d4fba8b9Smrg
3152d4fba8b9Smrg	if (pub->pattern) {
3153d4fba8b9Smrg	    XftPatternDestroy(pub->pattern);
3154d4fba8b9Smrg	    pub->pattern = 0;
3155d4fba8b9Smrg	}
3156d4fba8b9Smrg	if (pub->fontset) {
3157d4fba8b9Smrg	    XftFontSetDestroy(pub->fontset);
3158d4fba8b9Smrg	    pub->fontset = 0;
3159d4fba8b9Smrg	}
3160d4fba8b9Smrg
3161d4fba8b9Smrg	for (n = 0; n < pub->limit; ++n) {
3162d4fba8b9Smrg	    if (pub->cache[n].font) {
3163d4fba8b9Smrg		closeCachedXft(screen, pub->cache[n].font);
3164d4fba8b9Smrg		pub->cache[n].font = 0;
3165d4fba8b9Smrg	    }
3166d4fba8b9Smrg	}
3167d4fba8b9Smrg	free(pub->cache);
3168d4fba8b9Smrg	pub->cache = NULL;
316920d2c4d2Smrg    }
317020d2c4d2Smrg}
317120d2c4d2Smrg
317220d2c4d2Smrg/*
3173d4fba8b9Smrg * Get the faceName/faceNameDoublesize resource setting.
317420d2c4d2Smrg */
3175492d43a5SmrgString
3176d4fba8b9SmrggetFaceName(XtermWidget xw, Bool wideName)
317720d2c4d2Smrg{
317820d2c4d2Smrg#if OPT_RENDERWIDE
3179492d43a5Smrg    String result = (wideName
3180dfb07bc7Smrg		     ? FirstItemOf(xw->work.fonts.xft.list_w)
3181dfb07bc7Smrg		     : CurrentXftFont(xw));
318220d2c4d2Smrg#else
3183dfb07bc7Smrg    String result = CurrentXftFont(xw);
3184d4fba8b9Smrg    (void) wideName;
318520d2c4d2Smrg#endif
318620d2c4d2Smrg    return x_nonempty(result);
318720d2c4d2Smrg}
318820d2c4d2Smrg
318920d2c4d2Smrg/*
319020d2c4d2Smrg * If we change the faceName, we'll have to re-acquire all of the fonts that
319120d2c4d2Smrg * are derived from it.
319220d2c4d2Smrg */
319320d2c4d2Smrgvoid
319420d2c4d2SmrgsetFaceName(XtermWidget xw, const char *value)
319520d2c4d2Smrg{
319620d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
3197dfb07bc7Smrg    Boolean changed = (Boolean) ((CurrentXftFont(xw) == 0)
3198dfb07bc7Smrg				 || strcmp(CurrentXftFont(xw), value));
319920d2c4d2Smrg
32000bd37d32Smrg    if (changed) {
3201037a25ddSmrg	int n;
3202037a25ddSmrg
3203dfb07bc7Smrg	CurrentXftFont(xw) = x_strdup(value);
32040bd37d32Smrg	for (n = 0; n < NMENUFONTS; ++n) {
3205dfb07bc7Smrg	    int e;
32060bd37d32Smrg	    xw->misc.face_size[n] = -1.0;
3207dfb07bc7Smrg	    for (e = 0; e < fMAX; ++e) {
3208dfb07bc7Smrg		xtermCloseXft(screen, getMyXftFont(xw, e, n));
3209dfb07bc7Smrg	    }
32100bd37d32Smrg	}
321120d2c4d2Smrg    }
321220d2c4d2Smrg}
321320d2c4d2Smrg#endif
321420d2c4d2Smrg
3215d522f475Smrg/*
3216d522f475Smrg * Compute useful values for the font/window sizes
3217d522f475Smrg */
3218d522f475Smrgvoid
3219d522f475SmrgxtermComputeFontInfo(XtermWidget xw,
32209a64e1c5Smrg		     VTwin *win,
32219a64e1c5Smrg		     XFontStruct *font,
3222d522f475Smrg		     int sbwidth)
3223d522f475Smrg{
3224956cc18dSsnj    TScreen *screen = TScreenOf(xw);
3225d522f475Smrg
3226d522f475Smrg    int i, j, width, height;
3227492d43a5Smrg#if OPT_RENDERFONT
3228492d43a5Smrg    int fontnum = screen->menu_font_number;
3229492d43a5Smrg#endif
3230d4fba8b9Smrg    int failed = 0;
3231d522f475Smrg
3232d522f475Smrg#if OPT_RENDERFONT
3233d522f475Smrg    /*
3234d522f475Smrg     * xterm contains a lot of references to fonts, assuming they are fixed
3235d522f475Smrg     * size.  This chunk of code overrides the actual font-selection (see
3236d522f475Smrg     * drawXtermText()), if the user has selected render-font.  All of the
3237d522f475Smrg     * font-loading for fixed-fonts still goes on whether or not this chunk
3238d522f475Smrg     * overrides it.
3239d522f475Smrg     */
3240492d43a5Smrg    if (UsingRenderFont(xw) && fontnum >= 0) {
3241492d43a5Smrg	String face_name = getFaceName(xw, False);
3242d4fba8b9Smrg	XTermXftFonts norm = screen->renderFontNorm[fontnum];
3243d4fba8b9Smrg	XTermXftFonts bold = screen->renderFontBold[fontnum];
3244d4fba8b9Smrg	XTermXftFonts ital = screen->renderFontItal[fontnum];
3245d4fba8b9Smrg	XTermXftFonts btal = screen->renderFontBtal[fontnum];
3246d522f475Smrg#if OPT_RENDERWIDE
3247d4fba8b9Smrg	XTermXftFonts wnorm = screen->renderWideNorm[fontnum];
3248d4fba8b9Smrg	XTermXftFonts wbold = screen->renderWideBold[fontnum];
3249d4fba8b9Smrg	XTermXftFonts wital = screen->renderWideItal[fontnum];
3250d4fba8b9Smrg	XTermXftFonts wbtal = screen->renderWideBtal[fontnum];
3251d522f475Smrg#endif
3252d522f475Smrg
3253d4fba8b9Smrg	if (norm.font == 0 && !IsEmpty(face_name)) {
3254d522f475Smrg	    XftPattern *pat;
32550bd37d32Smrg	    double face_size;
3256d522f475Smrg
32570bd37d32Smrg	    TRACE(("xtermComputeFontInfo font %d: norm(face %s, size %.1f)\n",
3258492d43a5Smrg		   fontnum, face_name,
3259d522f475Smrg		   xw->misc.face_size[fontnum]));
3260d522f475Smrg
3261d4fba8b9Smrg	    TRACE(("Using Xft %d\n", XftVersion));
3262d4fba8b9Smrg	    TRACE(("Using FontConfig %d\n", FC_VERSION));
3263d4fba8b9Smrg
32640bd37d32Smrg	    fillInFaceSize(xw, fontnum);
3265d4fba8b9Smrg	    face_size = (double) xw->misc.face_size[fontnum];
3266d522f475Smrg
3267d522f475Smrg	    /*
3268d522f475Smrg	     * By observation (there is no documentation), XftPatternBuild is
3269d522f475Smrg	     * cumulative.  Build the bold- and italic-patterns on top of the
3270d522f475Smrg	     * normal pattern.
3271d522f475Smrg	     */
3272d4fba8b9Smrg#ifdef FC_COLOR
3273d522f475Smrg#define NormXftPattern \
3274d4fba8b9Smrg	    XFT_FAMILY,     XftTypeString, "mono", \
3275d4fba8b9Smrg	    FC_COLOR,       XftTypeBool,   FcFalse, \
3276d4fba8b9Smrg	    FC_OUTLINE,     XftTypeBool,   FcTrue, \
3277d4fba8b9Smrg	    XFT_SIZE,       XftTypeDouble, face_size
3278d4fba8b9Smrg#else
3279d4fba8b9Smrg#define NormXftPattern \
3280d4fba8b9Smrg	    XFT_FAMILY,     XftTypeString, "mono", \
3281d4fba8b9Smrg	    XFT_SIZE,       XftTypeDouble, face_size
3282d4fba8b9Smrg#endif
3283d522f475Smrg
3284d522f475Smrg#define BoldXftPattern(norm) \
3285d4fba8b9Smrg	    XFT_WEIGHT,     XftTypeInteger, XFT_WEIGHT_BOLD, \
3286d4fba8b9Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm.font->max_advance_width
3287d522f475Smrg
3288d522f475Smrg#define ItalXftPattern(norm) \
3289d4fba8b9Smrg	    XFT_SLANT,      XftTypeInteger, XFT_SLANT_ITALIC, \
3290d4fba8b9Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm.font->max_advance_width
3291d4fba8b9Smrg
3292d4fba8b9Smrg#define BtalXftPattern(norm) \
3293d4fba8b9Smrg	    XFT_WEIGHT,     XftTypeInteger, XFT_WEIGHT_BOLD, \
3294d4fba8b9Smrg	    XFT_SLANT,      XftTypeInteger, XFT_SLANT_ITALIC, \
3295d4fba8b9Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm.font->max_advance_width
3296d522f475Smrg
32979a64e1c5Smrg#if OPT_WIDE_ATTRS
32989a64e1c5Smrg#define HAVE_ITALICS 1
32999a64e1c5Smrg#define FIND_ITALICS ((pat = XftNameParse(face_name)) != 0)
33009a64e1c5Smrg#elif OPT_ISO_COLORS
33019a64e1c5Smrg#define HAVE_ITALICS 1
33029a64e1c5Smrg#define FIND_ITALICS (screen->italicULMode && (pat = XftNameParse(face_name)) != 0)
33039a64e1c5Smrg#else
33049a64e1c5Smrg#define HAVE_ITALICS 0
33059a64e1c5Smrg#endif
33069a64e1c5Smrg
3307d4fba8b9Smrg#if OPT_DEC_CHRSET
3308d4fba8b9Smrg	    freeall_DoubleFT(xw);
3309d4fba8b9Smrg#endif
331020d2c4d2Smrg	    if ((pat = XftNameParse(face_name)) != 0) {
3311d4fba8b9Smrg#define OPEN_XFT(name, tag) name.font = xtermOpenXft(xw, face_name, name.pattern, tag)
3312d4fba8b9Smrg		norm.pattern = XftPatternDuplicate(pat);
3313d4fba8b9Smrg		XftPatternBuild(norm.pattern,
3314d522f475Smrg				NormXftPattern,
3315d522f475Smrg				(void *) 0);
3316d4fba8b9Smrg		OPEN_XFT(norm, "normal");
3317d522f475Smrg
3318d4fba8b9Smrg		if (norm.font != 0) {
3319d4fba8b9Smrg		    bold.pattern = XftPatternDuplicate(pat);
3320d4fba8b9Smrg		    XftPatternBuild(bold.pattern,
3321d4fba8b9Smrg				    NormXftPattern,
3322d522f475Smrg				    BoldXftPattern(norm),
3323d522f475Smrg				    (void *) 0);
3324d4fba8b9Smrg		    OPEN_XFT(bold, "bold");
3325d522f475Smrg
33269a64e1c5Smrg#if HAVE_ITALICS
33279a64e1c5Smrg		    if (FIND_ITALICS) {
3328d4fba8b9Smrg			ital.pattern = XftPatternDuplicate(pat);
3329d4fba8b9Smrg			XftPatternBuild(ital.pattern,
3330d522f475Smrg					NormXftPattern,
3331d522f475Smrg					ItalXftPattern(norm),
3332d522f475Smrg					(void *) 0);
3333d4fba8b9Smrg			OPEN_XFT(ital, "italic");
3334d4fba8b9Smrg			btal.pattern = XftPatternDuplicate(pat);
3335d4fba8b9Smrg			XftPatternBuild(btal.pattern,
3336d4fba8b9Smrg					NormXftPattern,
3337d4fba8b9Smrg					BtalXftPattern(norm),
3338d4fba8b9Smrg					(void *) 0);
3339d4fba8b9Smrg			OPEN_XFT(btal, "bold-italic");
3340d522f475Smrg		    }
33419a64e1c5Smrg#endif
3342d522f475Smrg
3343d522f475Smrg		    /*
3344d522f475Smrg		     * FIXME:  just assume that the corresponding font has no
3345d522f475Smrg		     * graphics characters.
3346d522f475Smrg		     */
3347d522f475Smrg		    if (screen->fnt_boxes) {
3348d4fba8b9Smrg			screen->fnt_boxes = 0;
3349d522f475Smrg			TRACE(("Xft opened - will %suse internal line-drawing characters\n",
3350d522f475Smrg			       screen->fnt_boxes ? "not " : ""));
3351d522f475Smrg		    }
3352d522f475Smrg		}
3353d522f475Smrg
3354d4fba8b9Smrg		CACHE_XFT(screen->renderFontNorm, norm);
3355d4fba8b9Smrg
3356d4fba8b9Smrg		CACHE_XFT(screen->renderFontBold, bold);
3357d4fba8b9Smrg		if (norm.font != 0 && !bold.font) {
3358d4fba8b9Smrg		    noUsableXft(xw, "bold");
3359d4fba8b9Smrg		    XftPatternDestroy(bold.pattern);
3360d4fba8b9Smrg		    bold.pattern = XftPatternDuplicate(pat);
3361d4fba8b9Smrg		    XftPatternBuild(bold.pattern,
3362d4fba8b9Smrg				    NormXftPattern,
3363d4fba8b9Smrg				    (void *) 0);
3364d4fba8b9Smrg		    OPEN_XFT(bold, "bold");
3365d4fba8b9Smrg		    failed = 0;
3366d4fba8b9Smrg		    CACHE_XFT(screen->renderFontBold, bold);
3367d4fba8b9Smrg		}
3368d4fba8b9Smrg#if HAVE_ITALICS
3369d4fba8b9Smrg		CACHE_XFT(screen->renderFontItal, ital);
3370d4fba8b9Smrg		if (norm.font != 0 && !ital.font) {
3371d4fba8b9Smrg		    noUsableXft(xw, "italic");
3372d4fba8b9Smrg		    XftPatternDestroy(ital.pattern);
3373d4fba8b9Smrg		    ital.pattern = XftPatternDuplicate(pat);
3374d4fba8b9Smrg		    XftPatternBuild(ital.pattern,
3375d4fba8b9Smrg				    NormXftPattern,
3376d4fba8b9Smrg				    (void *) 0);
3377d4fba8b9Smrg		    OPEN_XFT(ital, "italics");
3378d4fba8b9Smrg		    failed = 0;
3379d4fba8b9Smrg		    CACHE_XFT(screen->renderFontItal, ital);
3380d4fba8b9Smrg		}
3381d4fba8b9Smrg		CACHE_XFT(screen->renderFontBtal, btal);
3382d4fba8b9Smrg		if (norm.font != 0 && !btal.font) {
3383d4fba8b9Smrg		    noUsableXft(xw, "bold italic");
3384d4fba8b9Smrg		    XftPatternDestroy(btal.pattern);
3385d4fba8b9Smrg		    btal.pattern = XftPatternDuplicate(pat);
3386d4fba8b9Smrg		    XftPatternBuild(btal.pattern,
3387d4fba8b9Smrg				    NormXftPattern,
3388d4fba8b9Smrg				    (void *) 0);
3389d4fba8b9Smrg		    OPEN_XFT(btal, "bold-italics");
3390d4fba8b9Smrg		    failed = 0;
3391d4fba8b9Smrg		    CACHE_XFT(screen->renderFontBtal, btal);
3392d4fba8b9Smrg		}
3393d4fba8b9Smrg#endif
3394d522f475Smrg		XftPatternDestroy(pat);
3395d4fba8b9Smrg	    } else {
3396d4fba8b9Smrg		failed = 1;
3397d522f475Smrg	    }
3398d4fba8b9Smrg#undef OPEN_XFT
3399d522f475Smrg
3400d522f475Smrg	    /*
3401d4fba8b9Smrg	     * See xtermXftDrawString().  A separate double-width font is nice
3402d4fba8b9Smrg	     * to have, but not essential.
3403d522f475Smrg	     */
3404d522f475Smrg#if OPT_RENDERWIDE
3405d4fba8b9Smrg	    if (norm.font != 0 && screen->wide_chars) {
3406d4fba8b9Smrg		int char_width = norm.font->max_advance_width * 2;
3407dfb07bc7Smrg		double aspect = ((FirstItemOf(xw->work.fonts.xft.list_w)
3408956cc18dSsnj				  || screen->renderFontNorm[fontnum].map.mixed)
3409956cc18dSsnj				 ? 1.0
3410956cc18dSsnj				 : 2.0);
3411d522f475Smrg
341220d2c4d2Smrg		face_name = getFaceName(xw, True);
3413d522f475Smrg		TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n",
341420d2c4d2Smrg		       NonNull(face_name),
3415d522f475Smrg		       char_width));
3416d522f475Smrg
3417d522f475Smrg#define WideXftPattern \
3418d4fba8b9Smrg		XFT_FAMILY,     XftTypeString,   "mono", \
3419d4fba8b9Smrg		XFT_SIZE,       XftTypeDouble,   face_size, \
3420d4fba8b9Smrg		XFT_SPACING,    XftTypeInteger,  XFT_MONO, \
3421d4fba8b9Smrg		XFT_CHAR_WIDTH, XftTypeInteger,  char_width, \
3422d4fba8b9Smrg		FC_ASPECT,      XftTypeDouble,   aspect
3423d4fba8b9Smrg
3424d4fba8b9Smrg		if (!IsEmpty(face_name) && (pat = XftNameParse(face_name))
3425d4fba8b9Smrg		    != 0) {
3426d4fba8b9Smrg#define OPEN_XFT(name, tag) name.font = xtermOpenXft(xw, face_name, name.pattern, tag)
3427d4fba8b9Smrg		    wnorm.pattern = XftPatternDuplicate(pat);
3428d4fba8b9Smrg		    XftPatternBuild(wnorm.pattern,
3429d522f475Smrg				    WideXftPattern,
3430d522f475Smrg				    (void *) 0);
3431d4fba8b9Smrg		    OPEN_XFT(wnorm, "wide");
3432d522f475Smrg
3433d4fba8b9Smrg		    if (wnorm.font != 0) {
3434d4fba8b9Smrg			wbold.pattern = XftPatternDuplicate(pat);
3435d4fba8b9Smrg			XftPatternBuild(wbold.pattern,
3436d522f475Smrg					WideXftPattern,
3437d522f475Smrg					BoldXftPattern(wnorm),
3438d522f475Smrg					(void *) 0);
3439d4fba8b9Smrg			OPEN_XFT(wbold, "wide-bold");
3440d522f475Smrg
34419a64e1c5Smrg#if HAVE_ITALICS
34429a64e1c5Smrg			if (FIND_ITALICS) {
3443d4fba8b9Smrg			    wital.pattern = XftPatternDuplicate(pat);
3444d4fba8b9Smrg			    XftPatternBuild(wital.pattern,
3445d522f475Smrg					    WideXftPattern,
3446d522f475Smrg					    ItalXftPattern(wnorm),
3447d522f475Smrg					    (void *) 0);
3448d4fba8b9Smrg			    OPEN_XFT(wital, "wide-italic");
3449d4fba8b9Smrg			}
3450d4fba8b9Smrg			CACHE_XFT(screen->renderWideBtal, wbtal);
3451d4fba8b9Smrg			if (!wbtal.font) {
3452d4fba8b9Smrg			    noUsableXft(xw, "wide bold");
3453d4fba8b9Smrg			    XftPatternDestroy(wbtal.pattern);
3454d4fba8b9Smrg			    wbtal.pattern = XftPatternDuplicate(pat);
3455d4fba8b9Smrg			    XftPatternBuild(wbtal.pattern,
3456d4fba8b9Smrg					    WideXftPattern,
3457d4fba8b9Smrg					    (void *) 0);
3458d4fba8b9Smrg			    OPEN_XFT(wbtal, "wide-bold-italics");
3459d4fba8b9Smrg			    failed = 0;
3460d4fba8b9Smrg			    CACHE_XFT(screen->renderWideBtal, wbtal);
3461d522f475Smrg			}
3462d522f475Smrg#endif
3463d522f475Smrg		    }
3464d4fba8b9Smrg
3465d4fba8b9Smrg		    CACHE_XFT(screen->renderWideNorm, wnorm);
3466d4fba8b9Smrg
3467d4fba8b9Smrg		    CACHE_XFT(screen->renderWideBold, wbold);
3468d4fba8b9Smrg		    if (wnorm.font != 0 && !wbold.font) {
3469d4fba8b9Smrg			noUsableXft(xw, "wide-bold");
3470d4fba8b9Smrg			XftPatternDestroy(wbold.pattern);
3471d4fba8b9Smrg			wbold.pattern = XftPatternDuplicate(pat);
3472d4fba8b9Smrg			XftPatternBuild(bold.pattern,
3473d4fba8b9Smrg					WideXftPattern,
3474d4fba8b9Smrg					(void *) 0);
3475d4fba8b9Smrg			OPEN_XFT(wbold, "wide-bold");
3476d4fba8b9Smrg			failed = 0;
3477d4fba8b9Smrg			CACHE_XFT(screen->renderWideBold, bold);
3478d4fba8b9Smrg		    }
3479d4fba8b9Smrg
3480d4fba8b9Smrg		    CACHE_XFT(screen->renderWideItal, wital);
3481d4fba8b9Smrg		    if (wnorm.font != 0 && !wital.font) {
3482d4fba8b9Smrg			noUsableXft(xw, "wide-italic");
3483d4fba8b9Smrg			XftPatternDestroy(wital.pattern);
3484d4fba8b9Smrg			wital.pattern = XftPatternDuplicate(pat);
3485d4fba8b9Smrg			XftPatternBuild(wital.pattern,
3486d4fba8b9Smrg					WideXftPattern,
3487d4fba8b9Smrg					(void *) 0);
3488d4fba8b9Smrg			OPEN_XFT(wital, "wide-italic");
3489d4fba8b9Smrg			failed = 0;
3490d4fba8b9Smrg			CACHE_XFT(screen->renderWideItal, wital);
3491d4fba8b9Smrg		    }
3492d4fba8b9Smrg
3493d522f475Smrg		    XftPatternDestroy(pat);
3494d522f475Smrg		}
3495d4fba8b9Smrg#undef OPEN_XFT
3496d522f475Smrg	    }
3497d522f475Smrg#endif /* OPT_RENDERWIDE */
3498d522f475Smrg	}
3499d4fba8b9Smrg	if (norm.font == 0) {
35002eaa94a1Schristos	    TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum));
35010bd37d32Smrg	    xw->work.render_font = False;
3502d522f475Smrg	    update_font_renderfont();
3503d522f475Smrg	    /* now we will fall through into the bitmap fonts */
3504d522f475Smrg	} else {
3505d4fba8b9Smrg	    setBrokenBoxChars(xw, False);
3506d4fba8b9Smrg	    setRenderFontsize(xw, win, norm.font, NULL);
3507d4fba8b9Smrg	    setRenderFontsize(xw, win, bold.font, "bold");
3508d4fba8b9Smrg	    setRenderFontsize(xw, win, ital.font, "ital");
3509d4fba8b9Smrg	    setRenderFontsize(xw, win, btal.font, "btal");
351020d2c4d2Smrg#if OPT_BOX_CHARS
351120d2c4d2Smrg	    setupPackedFonts(xw);
351220d2c4d2Smrg
351320d2c4d2Smrg	    if (screen->force_packed) {
351420d2c4d2Smrg		XTermXftFonts *use = &(screen->renderFontNorm[fontnum]);
35150bd37d32Smrg		SetFontHeight(screen, win, use->font->ascent + use->font->descent);
35160bd37d32Smrg		SetFontWidth(screen, win, use->map.min_width);
351720d2c4d2Smrg		TRACE(("...packed TrueType font %dx%d vs %d\n",
351820d2c4d2Smrg		       win->f_height,
351920d2c4d2Smrg		       win->f_width,
352020d2c4d2Smrg		       use->map.max_width));
352120d2c4d2Smrg	    }
352220d2c4d2Smrg#endif
352320d2c4d2Smrg	    DUMP_XFT(xw, &(screen->renderFontNorm[fontnum]));
3524d522f475Smrg	}
3525d522f475Smrg    }
3526d522f475Smrg    /*
3527d522f475Smrg     * Are we handling a bitmap font?
3528d522f475Smrg     */
3529492d43a5Smrg    else
3530d522f475Smrg#endif /* OPT_RENDERFONT */
3531d522f475Smrg    {
353220d2c4d2Smrg	if (is_double_width_font(font) && !(screen->fnt_prop)) {
35330bd37d32Smrg	    SetFontWidth(screen, win, font->min_bounds.width);
3534d522f475Smrg	} else {
35350bd37d32Smrg	    SetFontWidth(screen, win, font->max_bounds.width);
3536d522f475Smrg	}
35370bd37d32Smrg	SetFontHeight(screen, win, font->ascent + font->descent);
3538d522f475Smrg	win->f_ascent = font->ascent;
3539d522f475Smrg	win->f_descent = font->descent;
3540d522f475Smrg    }
3541d522f475Smrg    i = 2 * screen->border + sbwidth;
3542d522f475Smrg    j = 2 * screen->border;
3543d522f475Smrg    width = MaxCols(screen) * win->f_width + i;
3544d522f475Smrg    height = MaxRows(screen) * win->f_height + j;
3545956cc18dSsnj    win->fullwidth = (Dimension) width;
3546956cc18dSsnj    win->fullheight = (Dimension) height;
3547d522f475Smrg    win->width = width - i;
3548d522f475Smrg    win->height = height - j;
3549d522f475Smrg
3550d522f475Smrg    TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n",
3551d522f475Smrg	   win->height,
3552d522f475Smrg	   win->width,
3553d522f475Smrg	   win->fullheight,
3554d522f475Smrg	   win->fullwidth,
3555d522f475Smrg	   win->f_height,
3556d522f475Smrg	   win->f_width,
3557d522f475Smrg	   win->f_ascent,
3558d522f475Smrg	   win->f_descent));
355920d2c4d2Smrg
3560d4fba8b9Smrg    checkFontInfo(win->f_height, "height", failed);
3561d4fba8b9Smrg    checkFontInfo(win->f_width, "width", failed);
3562d522f475Smrg}
3563d522f475Smrg
3564d522f475Smrg/* save this information as a side-effect for double-sized characters */
3565d4fba8b9Smrgstatic void
35669a64e1c5SmrgxtermSaveFontInfo(TScreen *screen, XFontStruct *font)
3567d522f475Smrg{
3568956cc18dSsnj    screen->fnt_wide = (Dimension) (font->max_bounds.width);
3569956cc18dSsnj    screen->fnt_high = (Dimension) (font->ascent + font->descent);
3570d522f475Smrg    TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide));
3571d522f475Smrg}
3572d522f475Smrg
3573d522f475Smrg/*
3574d522f475Smrg * After loading a new font, update the structures that use its size.
3575d522f475Smrg */
3576d522f475Smrgvoid
3577d522f475SmrgxtermUpdateFontInfo(XtermWidget xw, Bool doresize)
3578d522f475Smrg{
3579956cc18dSsnj    TScreen *screen = TScreenOf(xw);
3580d522f475Smrg
3581d522f475Smrg    int scrollbar_width;
3582d522f475Smrg    VTwin *win = &(screen->fullVwin);
3583d522f475Smrg
3584d4fba8b9Smrg#if USE_DOUBLE_BUFFER
3585d4fba8b9Smrg    discardRenderDraw(TScreenOf(xw));
3586d4fba8b9Smrg#endif /* USE_DOUBLE_BUFFER */
3587d4fba8b9Smrg
3588d522f475Smrg    scrollbar_width = (xw->misc.scrollbar
3589d522f475Smrg		       ? (screen->scrollWidget->core.width +
3590d522f475Smrg			  BorderWidth(screen->scrollWidget))
3591d522f475Smrg		       : 0);
3592d4fba8b9Smrg    xtermComputeFontInfo(xw, win, GetNormalFont(screen, fNorm)->fs, scrollbar_width);
3593d4fba8b9Smrg    xtermSaveFontInfo(screen, GetNormalFont(screen, fNorm)->fs);
3594d522f475Smrg
3595d522f475Smrg    if (doresize) {
3596d522f475Smrg	if (VWindow(screen)) {
3597d522f475Smrg	    xtermClear(xw);
3598d522f475Smrg	}
3599d4fba8b9Smrg	TRACE(("xtermUpdateFontInfo " TRACE_L "\n"));
3600d522f475Smrg	DoResizeScreen(xw);	/* set to the new natural size */
3601d522f475Smrg	ResizeScrollBar(xw);
3602d522f475Smrg	Redraw();
3603d4fba8b9Smrg	TRACE((TRACE_R " xtermUpdateFontInfo\n"));
3604d522f475Smrg#ifdef SCROLLBAR_RIGHT
3605d522f475Smrg	updateRightScrollbar(xw);
3606d522f475Smrg#endif
3607d522f475Smrg    }
3608d522f475Smrg    xtermSetCursorBox(screen);
3609d522f475Smrg}
3610d522f475Smrg
3611fa3f02f3Smrg#if OPT_BOX_CHARS || OPT_REPORT_FONTS
3612d522f475Smrg
3613d522f475Smrg/*
3614d522f475Smrg * Returns true if the given character is missing from the specified font.
3615d522f475Smrg */
3616d522f475SmrgBool
3617956cc18dSsnjxtermMissingChar(unsigned ch, XTermFonts * font)
3618d522f475Smrg{
3619956cc18dSsnj    Bool result = False;
3620956cc18dSsnj    XFontStruct *fs = font->fs;
3621fa3f02f3Smrg    XCharStruct *pc = 0;
3622d522f475Smrg
3623d4fba8b9Smrg    if (fs == NULL) {
3624d4fba8b9Smrg	result = True;
3625d4fba8b9Smrg    } else if (fs->max_byte1 == 0) {
3626d522f475Smrg#if OPT_WIDE_CHARS
3627fa3f02f3Smrg	if (ch < 256)
3628956cc18dSsnj#endif
3629fa3f02f3Smrg	{
3630fa3f02f3Smrg	    CI_GET_CHAR_INFO_1D(fs, E2A(ch), pc);
3631fa3f02f3Smrg	}
3632956cc18dSsnj    }
3633d522f475Smrg#if OPT_WIDE_CHARS
3634956cc18dSsnj    else {
3635fa3f02f3Smrg	unsigned row = (ch >> 8);
3636fa3f02f3Smrg	unsigned col = (ch & 0xff);
3637fa3f02f3Smrg	CI_GET_CHAR_INFO_2D(fs, row, col, pc);
3638956cc18dSsnj    }
3639d522f475Smrg#endif
3640d522f475Smrg
3641fa3f02f3Smrg    if (pc == 0 || CI_NONEXISTCHAR(pc)) {
3642c48a5815Smrg	TRACE2(("xtermMissingChar %#04x (!exists)\n", ch));
3643956cc18dSsnj	result = True;
3644d522f475Smrg    }
3645fa3f02f3Smrg    if (ch < KNOWN_MISSING) {
3646956cc18dSsnj	font->known_missing[ch] = (Char) (result ? 2 : 1);
3647d522f475Smrg    }
3648956cc18dSsnj    return result;
3649d522f475Smrg}
3650fa3f02f3Smrg#endif
3651d522f475Smrg
3652fa3f02f3Smrg#if OPT_BOX_CHARS
3653d522f475Smrg/*
3654d522f475Smrg * The grid is arbitrary, enough resolution that nothing's lost in
3655d522f475Smrg * initialization.
3656d522f475Smrg */
3657d522f475Smrg#define BOX_HIGH 60
3658d522f475Smrg#define BOX_WIDE 60
3659d522f475Smrg
3660d522f475Smrg#define MID_HIGH (BOX_HIGH/2)
3661d522f475Smrg#define MID_WIDE (BOX_WIDE/2)
3662d522f475Smrg
3663d522f475Smrg#define CHR_WIDE ((9*BOX_WIDE)/10)
3664d522f475Smrg#define CHR_HIGH ((9*BOX_HIGH)/10)
3665d522f475Smrg
3666d522f475Smrg/*
3667d522f475Smrg * ...since we'll scale the values anyway.
3668d522f475Smrg */
3669d4fba8b9Smrg#define Scale_XY(n,d,f) ((int)(n) * ((int)(f))) / (d)
3670d4fba8b9Smrg#define SCALED_X(n) Scale_XY(n, BOX_WIDE, font_width)
3671d4fba8b9Smrg#define SCALED_Y(n) Scale_XY(n, BOX_HIGH, font_height)
3672e39b573cSmrg#define SCALE_X(n) n = SCALED_X(n)
3673e39b573cSmrg#define SCALE_Y(n) n = SCALED_Y(n)
3674d522f475Smrg
3675d522f475Smrg#define SEG(x0,y0,x1,y1) x0,y0, x1,y1
3676d522f475Smrg
3677d522f475Smrg/*
3678d522f475Smrg * Draw the given graphic character, if it is simple enough (i.e., a
3679d522f475Smrg * line-drawing character).
3680d522f475Smrg */
3681d522f475Smrgvoid
3682d4fba8b9SmrgxtermDrawBoxChar(XTermDraw * params,
3683d522f475Smrg		 unsigned ch,
3684d522f475Smrg		 GC gc,
3685d522f475Smrg		 int x,
3686d522f475Smrg		 int y,
3687d4fba8b9Smrg		 int cells,
3688d4fba8b9Smrg		 Bool xftords)
3689d522f475Smrg{
3690d4fba8b9Smrg    TScreen *screen = TScreenOf(params->xw);
3691d522f475Smrg    /* *INDENT-OFF* */
3692d522f475Smrg    static const short glyph_ht[] = {
3693d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,5*MID_HIGH/6),	/* H */
3694d522f475Smrg	SEG(6*BOX_WIDE/10,  0,		6*BOX_WIDE/10,5*MID_HIGH/6),
3695d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12),
3696d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
3697d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
3698d522f475Smrg	-1
3699d522f475Smrg    }, glyph_ff[] = {
3700d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		6*BOX_WIDE/10,	0),		/* F */
3701d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12),
3702d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		0*BOX_WIDE/3, 5*MID_HIGH/6),
3703d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
3704d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
3705d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
3706d522f475Smrg	-1
3707d522f475Smrg    }, glyph_lf[] = {
3708d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,9*MID_HIGH/12),	/* L */
3709d522f475Smrg	SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12),
3710d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
3711d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
3712d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
3713d522f475Smrg	-1
3714d522f475Smrg    }, glyph_nl[] = {
3715d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10,	0),		/* N */
3716d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		5*BOX_WIDE/6, 5*MID_HIGH/6),
3717d522f475Smrg	SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
3718d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),	/* L */
3719d522f475Smrg	SEG(1*BOX_WIDE/3,   CHR_HIGH,	  CHR_WIDE,	CHR_HIGH),
3720d522f475Smrg	-1
3721d522f475Smrg    }, glyph_vt[] = {
3722d522f475Smrg	SEG(1*BOX_WIDE/10,   0,		5*BOX_WIDE/12,5*MID_HIGH/6),	/* V */
3723d522f475Smrg	SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
3724d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
3725d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
3726d522f475Smrg	-1
3727d522f475Smrg    }, plus_or_minus[] =
3728d522f475Smrg    {
3729d522f475Smrg	SEG(  0,	  5*BOX_HIGH/6,	  CHR_WIDE,   5*BOX_HIGH/6),
3730d522f475Smrg	SEG(  MID_WIDE,	  2*BOX_HIGH/6,	  MID_WIDE,   4*BOX_HIGH/6),
3731d522f475Smrg	SEG(  0,	  3*BOX_HIGH/6,	  CHR_WIDE,   3*BOX_HIGH/6),
3732d522f475Smrg	-1
3733d522f475Smrg    }, lower_right_corner[] =
3734d522f475Smrg    {
3735d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
3736d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	0),
3737d522f475Smrg	-1
3738d522f475Smrg    }, upper_right_corner[] =
3739d522f475Smrg    {
3740d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
3741d522f475Smrg	SEG( MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
3742d522f475Smrg	-1
3743d522f475Smrg    }, upper_left_corner[] =
3744d522f475Smrg    {
3745d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
3746d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
3747d522f475Smrg	-1
3748d522f475Smrg    }, lower_left_corner[] =
3749d522f475Smrg    {
3750d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
3751d522f475Smrg	SEG(  MID_WIDE,	    MID_WIDE,	  BOX_WIDE,	MID_HIGH),
3752d522f475Smrg	-1
3753d522f475Smrg    }, cross[] =
3754d522f475Smrg    {
3755d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
3756d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
3757d522f475Smrg	-1
3758d522f475Smrg    }, scan_line_1[] =
3759d522f475Smrg    {
3760d522f475Smrg	SEG(  0,	    0,		  BOX_WIDE,	0),
3761d522f475Smrg	-1
3762d522f475Smrg    }, scan_line_3[] =
3763d522f475Smrg    {
3764d522f475Smrg	SEG(  0,	    BOX_HIGH/4,	  BOX_WIDE,	BOX_HIGH/4),
3765d522f475Smrg	-1
3766d522f475Smrg    }, scan_line_7[] =
3767d522f475Smrg    {
3768d522f475Smrg	SEG( 0,		    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
3769d522f475Smrg	-1
3770d522f475Smrg    }, scan_line_9[] =
3771d522f475Smrg    {
3772d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  BOX_WIDE,   3*BOX_HIGH/4),
3773d522f475Smrg	-1
3774d522f475Smrg    }, horizontal_line[] =
3775d522f475Smrg    {
3776d522f475Smrg	SEG(  0,	    BOX_HIGH,	  BOX_WIDE,	BOX_HIGH),
3777d522f475Smrg	-1
3778d522f475Smrg    }, left_tee[] =
3779d522f475Smrg    {
3780d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
3781d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
3782d522f475Smrg	-1
3783d522f475Smrg    }, right_tee[] =
3784d522f475Smrg    {
3785d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
3786d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  0,		MID_HIGH),
3787d522f475Smrg	-1
3788d522f475Smrg    }, bottom_tee[] =
3789d522f475Smrg    {
3790d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
3791d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
3792d522f475Smrg	-1
3793d522f475Smrg    }, top_tee[] =
3794d522f475Smrg    {
3795d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
3796d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
3797d522f475Smrg	-1
3798d522f475Smrg    }, vertical_line[] =
3799d522f475Smrg    {
3800d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
3801d522f475Smrg	-1
3802d522f475Smrg    }, less_than_or_equal[] =
3803d522f475Smrg    {
3804d522f475Smrg	SEG(  CHR_WIDE,	    BOX_HIGH/3,	  0,		MID_HIGH),
3805d522f475Smrg	SEG(  CHR_WIDE,	  2*BOX_HIGH/3,	  0,		MID_HIGH),
3806d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
3807d522f475Smrg	-1
3808d522f475Smrg    }, greater_than_or_equal[] =
3809d522f475Smrg    {
3810d522f475Smrg	SEG(  0,	    BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
3811d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
3812d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
3813d522f475Smrg	-1
3814d522f475Smrg    }, greek_pi[] =
3815d522f475Smrg    {
3816d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
3817d522f475Smrg	SEG(5*CHR_WIDE/6,   MID_HIGH,	5*CHR_WIDE/6,	CHR_HIGH),
3818d522f475Smrg	SEG(2*CHR_WIDE/6,   MID_HIGH,	2*CHR_WIDE/6,	CHR_HIGH),
3819d522f475Smrg	-1
3820d522f475Smrg    }, not_equal_to[] =
3821d522f475Smrg    {
3822d522f475Smrg	SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3,	CHR_HIGH),
3823d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,   2*BOX_HIGH/3),
3824d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
3825d522f475Smrg	-1
3826d522f475Smrg    };
3827d522f475Smrg
3828d4fba8b9Smrg    static const struct {
3829d4fba8b9Smrg	const int mode;			/* 1=y, 2=x, 3=both */
3830d4fba8b9Smrg	const short *data;
3831d4fba8b9Smrg    } lines[] =
3832d522f475Smrg    {
3833d4fba8b9Smrg	{ 0, 0 },			/* 00 (unused) */
3834d4fba8b9Smrg	{ 0, 0 },			/* 01 diamond */
3835d4fba8b9Smrg	{ 0, 0 },			/* 02 box */
3836d4fba8b9Smrg	{ 0, glyph_ht },		/* 03 HT */
3837d4fba8b9Smrg	{ 0, glyph_ff },		/* 04 FF */
3838d4fba8b9Smrg	{ 0, 0 },			/* 05 CR */
3839d4fba8b9Smrg	{ 0, glyph_lf },		/* 06 LF */
3840d4fba8b9Smrg	{ 0, 0 },			/* 07 degrees (small circle) */
3841d4fba8b9Smrg	{ 3, plus_or_minus },		/* 08 */
3842d4fba8b9Smrg	{ 0, glyph_nl },		/* 09 */
3843d4fba8b9Smrg	{ 0, glyph_vt },		/* 0A */
3844d4fba8b9Smrg	{ 3, lower_right_corner },	/* 0B */
3845d4fba8b9Smrg	{ 3, upper_right_corner },	/* 0C */
3846d4fba8b9Smrg	{ 3, upper_left_corner },	/* 0D */
3847d4fba8b9Smrg	{ 3, lower_left_corner },	/* 0E */
3848d4fba8b9Smrg	{ 3, cross },			/* 0F */
3849d4fba8b9Smrg	{ 2, scan_line_1 },		/* 10 */
3850d4fba8b9Smrg	{ 2, scan_line_3 },		/* 11 */
3851d4fba8b9Smrg	{ 2, scan_line_7 },		/* 12 */
3852d4fba8b9Smrg	{ 2, scan_line_9 },		/* 13 */
3853d4fba8b9Smrg	{ 2, horizontal_line },		/* 14 */
3854d4fba8b9Smrg	{ 3, left_tee },		/* 15 */
3855d4fba8b9Smrg	{ 3, right_tee },		/* 16 */
3856d4fba8b9Smrg	{ 3, bottom_tee },		/* 17 */
3857d4fba8b9Smrg	{ 3, top_tee },			/* 18 */
3858d4fba8b9Smrg	{ 1, vertical_line },		/* 19 */
3859d4fba8b9Smrg	{ 0, less_than_or_equal },	/* 1A */
3860d4fba8b9Smrg	{ 0, greater_than_or_equal },	/* 1B */
3861d4fba8b9Smrg	{ 0, greek_pi },		/* 1C */
3862d4fba8b9Smrg	{ 0, not_equal_to },		/* 1D */
3863d4fba8b9Smrg	{ 0, 0 },			/* 1E LB */
3864d4fba8b9Smrg	{ 0, 0 },			/* 1F bullet */
3865d522f475Smrg    };
3866d4fba8b9Smrg    /* *INDENT-ON* */
3867d522f475Smrg
3868d522f475Smrg    GC gc2;
3869d522f475Smrg    CgsEnum cgsId = (ch == 2) ? gcDots : gcLine;
3870d522f475Smrg    VTwin *cgsWin = WhichVWin(screen);
3871d522f475Smrg    const short *p;
3872d4fba8b9Smrg    unsigned font_width = (((params->draw_flags & DOUBLEWFONT) ? 2U : 1U)
3873d4fba8b9Smrg			   * screen->fnt_wide);
3874d4fba8b9Smrg    unsigned font_height = (((params->draw_flags & DOUBLEHFONT) ? 2U : 1U)
3875d4fba8b9Smrg			    * screen->fnt_high);
3876d522f475Smrg
3877d522f475Smrg    if (cells > 1)
3878956cc18dSsnj	font_width *= (unsigned) cells;
3879d522f475Smrg
3880d522f475Smrg#if OPT_WIDE_CHARS
3881d522f475Smrg    /*
3882d522f475Smrg     * Try to show line-drawing characters if we happen to be in UTF-8
3883d522f475Smrg     * mode, but have gotten an old-style font.
3884d522f475Smrg     */
3885d522f475Smrg    if (screen->utf8_mode
3886d522f475Smrg#if OPT_RENDERFONT
3887d4fba8b9Smrg	&& !UsingRenderFont(params->xw)
3888d522f475Smrg#endif
3889d522f475Smrg	&& (ch > 127)
3890d522f475Smrg	&& (ch != UCS_REPL)) {
3891d4fba8b9Smrg	int which = (params->attr_flags & BOLD) ? fBold : fNorm;
3892d522f475Smrg	unsigned n;
3893d522f475Smrg	for (n = 1; n < 32; n++) {
3894d4fba8b9Smrg	    if (xtermMissingChar(n, getNormalFont(screen, which)))
3895d4fba8b9Smrg		continue;
3896d4fba8b9Smrg	    if (dec2ucs(screen, n) != ch)
3897d4fba8b9Smrg		continue;
3898d4fba8b9Smrg	    TRACE(("...use xterm-style linedrawing U+%04X ->%d\n", ch, n));
3899d4fba8b9Smrg	    ch = n;
3900d4fba8b9Smrg	    break;
3901d522f475Smrg	}
3902d522f475Smrg    }
3903d522f475Smrg#endif
3904d522f475Smrg
3905d4fba8b9Smrg#if OPT_VT52_MODE
3906d4fba8b9Smrg    if (!(screen->vtXX_level)) {
3907d4fba8b9Smrg	switch (ch) {
3908d4fba8b9Smrg	case 6:
3909d4fba8b9Smrg	    ch = 7;
3910d4fba8b9Smrg	    break;
3911d4fba8b9Smrg	default:
3912d4fba8b9Smrg	    ch = 256;
3913d4fba8b9Smrg	    break;
3914d4fba8b9Smrg	}
3915d4fba8b9Smrg    }
3916d4fba8b9Smrg#endif
3917d4fba8b9Smrg
3918d4fba8b9Smrg    /*
3919d4fba8b9Smrg     * Line-drawing characters show use the full (scaled) cellsize, while
3920d4fba8b9Smrg     * other characters should be shifted to center them vertically.
3921d4fba8b9Smrg     */
3922d4fba8b9Smrg    if (!xftords) {
3923d4fba8b9Smrg	if ((ch < XtNumber(lines)) && (lines[ch].mode & 3) != 0) {
3924d4fba8b9Smrg	    font_height = (unsigned) ((float) font_height * screen->scale_height);
3925d4fba8b9Smrg	} else {
3926d4fba8b9Smrg	    y += ScaleShift(screen);
3927d4fba8b9Smrg	}
3928d4fba8b9Smrg    }
3929d4fba8b9Smrg
3930d4fba8b9Smrg    TRACE(("DRAW_BOX(%02X) cell %dx%d at %d,%d%s\n",
3931d522f475Smrg	   ch, font_height, font_width, y, x,
3932d4fba8b9Smrg	   ((ch >= XtNumber(lines))
3933d522f475Smrg	    ? "-BAD"
3934d522f475Smrg	    : "")));
3935d522f475Smrg
3936d522f475Smrg    if (cgsId == gcDots) {
3937d4fba8b9Smrg	setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc));
3938d4fba8b9Smrg	setCgsFore(params->xw, cgsWin, cgsId, getCgsFore(params->xw, cgsWin, gc));
3939d4fba8b9Smrg	setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc));
3940d522f475Smrg    } else {
3941d4fba8b9Smrg	setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc));
3942d4fba8b9Smrg	setCgsFore(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc));
3943d4fba8b9Smrg	setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc));
3944d522f475Smrg    }
3945d4fba8b9Smrg    gc2 = getCgsGC(params->xw, cgsWin, cgsId);
3946d522f475Smrg
3947d4fba8b9Smrg    if (!(params->draw_flags & NOBACKGROUND)) {
39480bd37d32Smrg	XFillRectangle(screen->display, VDrawable(screen), gc2, x, y,
3949d522f475Smrg		       font_width,
3950d522f475Smrg		       font_height);
3951d522f475Smrg    }
3952d522f475Smrg
3953d4fba8b9Smrg    setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc));
3954d4fba8b9Smrg    setCgsFore(params->xw, cgsWin, cgsId, getCgsFore(params->xw, cgsWin, gc));
3955d4fba8b9Smrg    setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc));
3956d4fba8b9Smrg    gc2 = getCgsGC(params->xw, cgsWin, cgsId);
3957d522f475Smrg
3958d522f475Smrg    XSetLineAttributes(screen->display, gc2,
3959d4fba8b9Smrg		       (params->attr_flags & BOLD)
3960d522f475Smrg		       ? ((font_height > 12)
3961d522f475Smrg			  ? font_height / 12
3962d522f475Smrg			  : 1)
3963d522f475Smrg		       : ((font_height > 16)
3964d522f475Smrg			  ? font_height / 16
3965d522f475Smrg			  : 1),
3966d522f475Smrg		       LineSolid,
3967d522f475Smrg		       CapProjecting,
3968d522f475Smrg		       JoinMiter);
3969d522f475Smrg
3970d522f475Smrg    if (ch == 1) {		/* diamond */
3971d522f475Smrg	XPoint points[5];
3972d522f475Smrg	int npoints = 5, n;
3973d522f475Smrg
3974d522f475Smrg	points[0].x = MID_WIDE;
3975d522f475Smrg	points[0].y = BOX_HIGH / 4;
3976d522f475Smrg
3977d522f475Smrg	points[1].x = 8 * BOX_WIDE / 8;
3978d522f475Smrg	points[1].y = MID_HIGH;
3979d522f475Smrg
3980d522f475Smrg	points[2].x = points[0].x;
3981d522f475Smrg	points[2].y = 3 * BOX_HIGH / 4;
3982d522f475Smrg
3983d522f475Smrg	points[3].x = 0 * BOX_WIDE / 8;
3984d522f475Smrg	points[3].y = points[1].y;
3985d522f475Smrg
3986d522f475Smrg	points[4].x = points[0].x;
3987d522f475Smrg	points[4].y = points[0].y;
3988d522f475Smrg
3989d522f475Smrg	for (n = 0; n < npoints; ++n) {
3990d4fba8b9Smrg	    points[n].x = (short) (SCALED_X(points[n].x));
3991d4fba8b9Smrg	    points[n].y = (short) (SCALED_Y(points[n].y));
3992e39b573cSmrg	    points[n].x = (short) (points[n].x + x);
3993e39b573cSmrg	    points[n].y = (short) (points[n].y + y);
3994d522f475Smrg	}
3995d522f475Smrg
3996d522f475Smrg	XFillPolygon(screen->display,
39970bd37d32Smrg		     VDrawable(screen), gc2,
3998d522f475Smrg		     points, npoints,
3999d522f475Smrg		     Convex, CoordModeOrigin);
4000d522f475Smrg    } else if (ch == 7) {	/* degrees */
4001d522f475Smrg	unsigned width = (BOX_WIDE / 3);
4002956cc18dSsnj	int x_coord = MID_WIDE - (int) (width / 2);
4003956cc18dSsnj	int y_coord = MID_HIGH - (int) width;
4004d522f475Smrg
4005d522f475Smrg	SCALE_X(x_coord);
4006d522f475Smrg	SCALE_Y(y_coord);
4007e39b573cSmrg	width = (unsigned) SCALED_X(width);
4008d522f475Smrg
4009d522f475Smrg	XDrawArc(screen->display,
40100bd37d32Smrg		 VDrawable(screen), gc2,
4011d522f475Smrg		 x + x_coord, y + y_coord, width, width,
4012d522f475Smrg		 0,
4013d522f475Smrg		 360 * 64);
4014d522f475Smrg    } else if (ch == 0x1f) {	/* bullet */
4015d522f475Smrg	unsigned width = 7 * BOX_WIDE / 10;
4016956cc18dSsnj	int x_coord = MID_WIDE - (int) (width / 3);
4017956cc18dSsnj	int y_coord = MID_HIGH - (int) (width / 3);
4018d522f475Smrg
4019d522f475Smrg	SCALE_X(x_coord);
4020d522f475Smrg	SCALE_Y(y_coord);
4021e39b573cSmrg	width = (unsigned) SCALED_X(width);
4022d522f475Smrg
4023d522f475Smrg	XDrawArc(screen->display,
40240bd37d32Smrg		 VDrawable(screen), gc2,
4025d522f475Smrg		 x + x_coord, y + y_coord, width, width,
4026d522f475Smrg		 0,
4027d522f475Smrg		 360 * 64);
4028d4fba8b9Smrg    } else if (ch < XtNumber(lines)
4029d4fba8b9Smrg	       && (p = lines[ch].data) != 0) {
4030956cc18dSsnj	int coord[4];
4031d522f475Smrg	int n = 0;
4032d522f475Smrg	while (*p >= 0) {
4033d522f475Smrg	    coord[n++] = *p++;
4034d522f475Smrg	    if (n == 4) {
4035d522f475Smrg		SCALE_X(coord[0]);
4036d522f475Smrg		SCALE_Y(coord[1]);
4037d522f475Smrg		SCALE_X(coord[2]);
4038d522f475Smrg		SCALE_Y(coord[3]);
4039d522f475Smrg		XDrawLine(screen->display,
40400bd37d32Smrg			  VDrawable(screen), gc2,
4041d522f475Smrg			  x + coord[0], y + coord[1],
4042d522f475Smrg			  x + coord[2], y + coord[3]);
4043d522f475Smrg		n = 0;
4044d522f475Smrg	    }
4045d522f475Smrg	}
4046d522f475Smrg    } else if (screen->force_all_chars) {
4047d522f475Smrg	/* bounding rectangle, for debugging */
40480bd37d32Smrg	XDrawRectangle(screen->display, VDrawable(screen), gc2, x, y,
4049d522f475Smrg		       font_width - 1,
4050d522f475Smrg		       font_height - 1);
4051d522f475Smrg    }
4052d522f475Smrg}
4053fa3f02f3Smrg#endif /* OPT_BOX_CHARS */
4054d522f475Smrg
4055d522f475Smrg#if OPT_RENDERFONT
4056d4fba8b9Smrg/*
4057d4fba8b9Smrg * Check if the glyph is defined in the given font, and (try to) filter out
4058d4fba8b9Smrg * cases where double-width glyphs are stuffed into a single-width outline.
4059d4fba8b9Smrg */
4060d4fba8b9Smrgstatic Boolean
4061d4fba8b9SmrgfoundXftGlyph(XtermWidget xw, XftFont *font, unsigned wc)
4062d4fba8b9Smrg{
4063d4fba8b9Smrg    TScreen *screen = TScreenOf(xw);
4064d4fba8b9Smrg    Boolean result = False;
4065d4fba8b9Smrg
4066d4fba8b9Smrg    if (font != 0 && XftGlyphExists(screen->display, font, wc)) {
4067d4fba8b9Smrg	int expect;
4068d4fba8b9Smrg
4069c48a5815Smrg	if ((expect = CharWidth(screen, wc)) > 0) {
4070d4fba8b9Smrg	    XGlyphInfo gi;
4071d4fba8b9Smrg	    int actual;
4072d4fba8b9Smrg
4073d4fba8b9Smrg	    XftTextExtents32(screen->display, font, &wc, 1, &gi);
4074d4fba8b9Smrg	    /*
4075d4fba8b9Smrg	     * Some (more than a few) fonts are sloppy; allow 10% outside
4076d4fba8b9Smrg	     * the bounding box to accommodate them.
4077d4fba8b9Smrg	     */
4078d4fba8b9Smrg	    actual = ((gi.xOff * 10) >= (11 * FontWidth(screen))) ? 2 : 1;
4079d4fba8b9Smrg	    if (actual <= expect) {
4080d4fba8b9Smrg		/* allow double-cell if wcwidth agrees */
4081d4fba8b9Smrg		result = True;
4082d4fba8b9Smrg	    } else {
4083d4fba8b9Smrg		TRACE(("SKIP U+%04X %d vs %d (%d vs %d)\n",
4084d4fba8b9Smrg		       wc, gi.xOff, FontWidth(screen), actual, expect));
4085d4fba8b9Smrg	    }
4086d4fba8b9Smrg	} else {
4087d4fba8b9Smrg	    result = True;
4088d4fba8b9Smrg	}
4089d4fba8b9Smrg    }
4090d4fba8b9Smrg    return result;
4091d4fba8b9Smrg}
4092d4fba8b9Smrg
4093d4fba8b9Smrgstatic void
4094d4fba8b9SmrgmarkXftOpened(XtermWidget xw, XTermXftFonts *which, Cardinal n, unsigned wc)
4095d4fba8b9Smrg{
4096d4fba8b9Smrg    if (which->cache[n].usage != xcOpened) {
4097d4fba8b9Smrg	which->opened++;
4098d4fba8b9Smrg	which->cache[n].usage = xcOpened;
4099d4fba8b9Smrg	/* XFT_DEBUG=3 will show useful context for this */
4100d4fba8b9Smrg	if (getenv("XFT_DEBUG") != 0) {
4101d4fba8b9Smrg	    printf("xterm: matched U+%04X in fontset #%d [%u:%u]\n",
4102d4fba8b9Smrg		   wc, n + 1,
4103d4fba8b9Smrg		   which->opened,
4104d4fba8b9Smrg		   xw->work.max_fontsets);
4105d4fba8b9Smrg	}
4106d4fba8b9Smrg    }
4107d4fba8b9Smrg}
4108d4fba8b9Smrg
4109d4fba8b9Smrg/*
4110d4fba8b9Smrg * Check if the given character has a glyph known to Xft.  If it is missing,
4111d4fba8b9Smrg * try first to replace the font with a fallback that provides the glyph.
4112d4fba8b9Smrg */
4113d4fba8b9SmrgXftFont *
4114d4fba8b9SmrgfindXftGlyph(XtermWidget xw, XftFont *given, unsigned wc)
4115d4fba8b9Smrg{
4116d4fba8b9Smrg    TScreen *screen = TScreenOf(xw);
4117d4fba8b9Smrg    XTermXftFonts *which = 0;
4118d4fba8b9Smrg    XftFont *result = 0;
4119d4fba8b9Smrg    /* workaround for interface changes... */
4120d4fba8b9Smrg    int fontnum = screen->menu_font_number;
4121d4fba8b9Smrg    static int table[] =
4122d4fba8b9Smrg    {
4123d4fba8b9Smrg	offsetof(TScreen, renderFontNorm),
4124d4fba8b9Smrg	offsetof(TScreen, renderFontBold),
4125d4fba8b9Smrg	offsetof(TScreen, renderFontItal),
4126d4fba8b9Smrg	offsetof(TScreen, renderFontBtal),
4127d4fba8b9Smrg#if OPT_RENDERWIDE
4128d4fba8b9Smrg	offsetof(TScreen, renderWideNorm),
4129d4fba8b9Smrg	offsetof(TScreen, renderWideBold),
4130d4fba8b9Smrg	offsetof(TScreen, renderWideItal),
4131d4fba8b9Smrg	offsetof(TScreen, renderWideBtal),
4132d4fba8b9Smrg#endif
4133d4fba8b9Smrg    };
4134d4fba8b9Smrg    Cardinal n;
4135d4fba8b9Smrg    FcResult status;
4136d4fba8b9Smrg    const char *tag = 0;
4137d4fba8b9Smrg
4138d4fba8b9Smrg    /* if fontsets are not wanted, just leave */
4139d4fba8b9Smrg    if (xw->work.max_fontsets == 0) {
4140d4fba8b9Smrg	return 0;
4141d4fba8b9Smrg    }
4142d4fba8b9Smrg
4143d4fba8b9Smrg    /* ignore codes in private use areas */
4144d4fba8b9Smrg    if ((wc >= 0xe000 && wc <= 0xf8ff)
4145d4fba8b9Smrg	|| (wc >= 0xf0000 && wc <= 0xffffd)
4146d4fba8b9Smrg	|| (wc >= 0x100000 && wc <= 0x10fffd)) {
4147d4fba8b9Smrg	return 0;
4148d4fba8b9Smrg    }
4149d4fba8b9Smrg    /* the end of the BMP is reserved for non-characters */
4150d4fba8b9Smrg    if (wc >= 0xfff0 && wc <= 0xffff) {
4151d4fba8b9Smrg	return 0;
4152d4fba8b9Smrg    }
4153d4fba8b9Smrg
4154d4fba8b9Smrg    for (n = 0; n < XtNumber(table); ++n) {
4155d4fba8b9Smrg	XTermXftFonts *check = (XTermXftFonts *) ((void *) ((char *) screen
4156d4fba8b9Smrg							    + table[n]));
4157d4fba8b9Smrg	if (check[fontnum].font == given) {
4158d4fba8b9Smrg	    which = &check[fontnum];
4159d4fba8b9Smrg	    tag = whichFontEnum((VTFontEnum) n);
4160d4fba8b9Smrg	    break;
4161d4fba8b9Smrg	}
4162d4fba8b9Smrg    }
4163d4fba8b9Smrg    if (which != 0) {
4164d4fba8b9Smrg	if (which->fontset == 0) {
4165d4fba8b9Smrg	    FcFontSet *sortedFonts;
4166d4fba8b9Smrg	    FcPattern *myPattern;
4167d4fba8b9Smrg	    int j;
4168d4fba8b9Smrg
4169d4fba8b9Smrg	    myPattern = FcPatternDuplicate(which->pattern);
4170d4fba8b9Smrg
4171d4fba8b9Smrg	    FcPatternAddBool(myPattern, FC_SCALABLE, FcTrue);
4172d4fba8b9Smrg	    FcPatternAddInteger(myPattern, FC_CHAR_WIDTH, given->max_advance_width);
4173d4fba8b9Smrg
4174d4fba8b9Smrg	    FcConfigSubstitute(FcConfigGetCurrent(),
4175d4fba8b9Smrg			       myPattern,
4176d4fba8b9Smrg			       FcMatchPattern);
4177d4fba8b9Smrg	    FcDefaultSubstitute(myPattern);
4178d4fba8b9Smrg
4179d4fba8b9Smrg	    which->fontset = FcFontSetCreate();
4180d4fba8b9Smrg
4181d4fba8b9Smrg	    sortedFonts = FcFontSort(0, myPattern, FcTrue, 0, &status);
4182d4fba8b9Smrg
4183d4fba8b9Smrg	    if (!sortedFonts || sortedFonts->nfont <= 0) {
4184d4fba8b9Smrg		xtermWarning("did not find any usable TrueType font\n");
4185d4fba8b9Smrg		return 0;
4186d4fba8b9Smrg	    }
4187d4fba8b9Smrg	    which->limit = (unsigned) sortedFonts->nfont;
4188d4fba8b9Smrg	    which->cache = TypeCallocN(XTermXftCache, (which->limit + 1));
4189d4fba8b9Smrg	    for (j = 0; j < sortedFonts->nfont; j++) {
4190d4fba8b9Smrg		FcPattern *font_pattern;
4191d4fba8b9Smrg
4192d4fba8b9Smrg		font_pattern = FcFontRenderPrepare(FcConfigGetCurrent(),
4193d4fba8b9Smrg						   myPattern,
4194d4fba8b9Smrg						   sortedFonts->fonts[j]);
4195d4fba8b9Smrg		if (font_pattern)
4196d4fba8b9Smrg		    FcFontSetAdd(which->fontset, font_pattern);
4197d4fba8b9Smrg	    }
4198d4fba8b9Smrg
4199d4fba8b9Smrg	    FcFontSetSortDestroy(sortedFonts);
4200d4fba8b9Smrg	    FcPatternDestroy(myPattern);
4201d4fba8b9Smrg	}
4202d4fba8b9Smrg	if (which->fontset != 0) {
4203d4fba8b9Smrg	    XftFont *check;
4204d4fba8b9Smrg	    Cardinal empty = which->limit;
4205d4fba8b9Smrg
4206d4fba8b9Smrg	    for (n = 0; n < which->limit; ++n) {
4207d4fba8b9Smrg		XftCache usage = which->cache[n].usage;
4208d4fba8b9Smrg		if (usage == xcEmpty) {
4209d4fba8b9Smrg		    if (empty > n)
4210d4fba8b9Smrg			empty = n;
4211d4fba8b9Smrg		} else if (usage == xcOpened
4212d4fba8b9Smrg			   || (usage == xcUnused
4213d4fba8b9Smrg			       && (which->opened < xw->work.max_fontsets))) {
4214d4fba8b9Smrg		    check = which->cache[n].font;
4215d4fba8b9Smrg		    if (foundXftGlyph(xw, check, wc)) {
4216d4fba8b9Smrg			markXftOpened(xw, which, n, wc);
4217d4fba8b9Smrg			result = check;
4218d4fba8b9Smrg			TRACE_FALLBACK(xw, "old", wc, (int) n, result);
4219d4fba8b9Smrg			break;
4220d4fba8b9Smrg		    }
4221d4fba8b9Smrg		}
4222d4fba8b9Smrg	    }
4223d4fba8b9Smrg
4224d4fba8b9Smrg	    if ((result == 0)
4225d4fba8b9Smrg		&& (empty < which->limit)
4226d4fba8b9Smrg		&& (which->opened < xw->work.max_fontsets)) {
4227d4fba8b9Smrg		FcPattern *myPattern = 0;
4228d4fba8b9Smrg		FcPattern *myReport = 0;
4229d4fba8b9Smrg
4230d4fba8b9Smrg		for (n = empty; n < which->limit; ++n) {
4231d4fba8b9Smrg		    if (which->cache[n].usage >= xcBogus)
4232d4fba8b9Smrg			continue;
4233d4fba8b9Smrg		    if (resource.reportFonts) {
4234d4fba8b9Smrg			myReport = FcPatternDuplicate(which->fontset->fonts[n]);
4235d4fba8b9Smrg		    }
4236d4fba8b9Smrg		    myPattern = FcPatternDuplicate(which->fontset->fonts[n]);
4237d4fba8b9Smrg		    check = XftFontOpenPattern(screen->display, myPattern);
4238d4fba8b9Smrg		    closeCachedXft(screen, which->cache[n].font);
4239d4fba8b9Smrg		    (void) maybeXftCache(xw, check);
4240d4fba8b9Smrg		    which->cache[n].font = check;
4241d4fba8b9Smrg		    which->cache[n].usage = xcBogus;
4242d4fba8b9Smrg		    if (check == 0)
4243d4fba8b9Smrg			continue;	/* shouldn't happen... */
4244d4fba8b9Smrg#ifdef FC_COLOR
4245d4fba8b9Smrg		    if (isBogusXft(check)) {
4246d4fba8b9Smrg			continue;
4247d4fba8b9Smrg		    }
4248d4fba8b9Smrg#endif
4249d4fba8b9Smrg		    if (foundXftGlyph(xw, check, wc)) {
4250d4fba8b9Smrg			markXftOpened(xw, which, n, wc);
4251d4fba8b9Smrg			reportXftFonts(xw, check, "fallback", tag, myReport);
4252d4fba8b9Smrg			result = check;
4253d4fba8b9Smrg			TRACE_FALLBACK(xw, "new", wc, (int) n, result);
4254d4fba8b9Smrg			break;
4255d4fba8b9Smrg		    }
4256d4fba8b9Smrg		    /*
4257d4fba8b9Smrg		     * The slot is opened, but we are not using it.
4258d4fba8b9Smrg		     */
4259d4fba8b9Smrg		    which->cache[n].usage = xcUnused;
4260d4fba8b9Smrg		}
4261d4fba8b9Smrg	    }
4262d4fba8b9Smrg	}
4263d4fba8b9Smrg    }
4264d4fba8b9Smrg    return result;
4265d4fba8b9Smrg}
4266d522f475Smrg
4267d522f475Smrg/*
4268d4fba8b9Smrg * Check if the given character has a glyph known to Xft.  If it is missing,
4269d4fba8b9Smrg * return true.
4270d522f475Smrg *
4271d522f475Smrg * see xc/lib/Xft/xftglyphs.c
4272d522f475Smrg */
4273d522f475SmrgBool
42749a64e1c5SmrgxtermXftMissing(XtermWidget xw, XftFont *font, unsigned wc)
4275d522f475Smrg{
4276d522f475Smrg    Bool result = False;
4277d522f475Smrg
4278d522f475Smrg    if (font != 0) {
4279956cc18dSsnj	TScreen *screen = TScreenOf(xw);
4280956cc18dSsnj	if (!XftGlyphExists(screen->display, font, wc)) {
4281d522f475Smrg#if OPT_WIDE_CHARS
4282dfb07bc7Smrg	    TRACE2(("xtermXftMissing %d (dec=%#x, ucs=%#x)\n",
4283d4fba8b9Smrg		    wc, ucs2dec(screen, wc), dec2ucs(screen, wc)));
4284d522f475Smrg#else
4285dfb07bc7Smrg	    TRACE2(("xtermXftMissing %d\n", wc));
4286d522f475Smrg#endif
4287d522f475Smrg	    result = True;
4288d522f475Smrg	}
4289d522f475Smrg    }
4290d522f475Smrg    return result;
4291d522f475Smrg}
4292fa3f02f3Smrg#endif /* OPT_RENDERFONT */
4293d522f475Smrg
4294d522f475Smrg#if OPT_WIDE_CHARS
4295d522f475Smrg#define MY_UCS(ucs,dec) case ucs: result = dec; break
4296d522f475Smrgunsigned
4297d4fba8b9Smrgucs2dec(TScreen *screen, unsigned ch)
4298d522f475Smrg{
4299d522f475Smrg    unsigned result = ch;
4300d4fba8b9Smrg
4301d4fba8b9Smrg    (void) screen;
4302d522f475Smrg    if ((ch > 127)
4303d522f475Smrg	&& (ch != UCS_REPL)) {
4304d4fba8b9Smrg#if OPT_VT52_MODE
4305d4fba8b9Smrg	if (screen != 0 && !(screen->vtXX_level)) {
4306d4fba8b9Smrg	    /*
4307d4fba8b9Smrg	     * Intentionally empty: it would be possible to use the built-in
4308d4fba8b9Smrg	     * line-drawing fallback in xtermDrawBoxChar(), but for testing
4309d4fba8b9Smrg	     * ncurses, this is good enough.
4310d4fba8b9Smrg	     */
4311d4fba8b9Smrg	    ;
4312d4fba8b9Smrg	} else
4313d4fba8b9Smrg#endif
4314d4fba8b9Smrg	    switch (ch) {
4315d4fba8b9Smrg		MY_UCS(0x25ae, 0);	/* black vertical rectangle           */
4316d4fba8b9Smrg		MY_UCS(0x25c6, 1);	/* black diamond                      */
4317d4fba8b9Smrg		MY_UCS(0x2592, 2);	/* medium shade                       */
4318d4fba8b9Smrg		MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation   */
4319d4fba8b9Smrg		MY_UCS(0x240c, 4);	/* symbol for form feed               */
4320d4fba8b9Smrg		MY_UCS(0x240d, 5);	/* symbol for carriage return         */
4321d4fba8b9Smrg		MY_UCS(0x240a, 6);	/* symbol for line feed               */
4322d4fba8b9Smrg		MY_UCS(0x00b0, 7);	/* degree sign                        */
4323d4fba8b9Smrg		MY_UCS(0x00b1, 8);	/* plus-minus sign                    */
4324d4fba8b9Smrg		MY_UCS(0x2424, 9);	/* symbol for newline                 */
4325d4fba8b9Smrg		MY_UCS(0x240b, 10);	/* symbol for vertical tabulation     */
4326d4fba8b9Smrg		MY_UCS(0x2518, 11);	/* box drawings light up and left     */
4327d4fba8b9Smrg		MY_UCS(0x2510, 12);	/* box drawings light down and left   */
4328d4fba8b9Smrg		MY_UCS(0x250c, 13);	/* box drawings light down and right  */
4329d4fba8b9Smrg		MY_UCS(0x2514, 14);	/* box drawings light up and right    */
4330d4fba8b9Smrg		MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
4331d4fba8b9Smrg		MY_UCS(0x23ba, 16);	/* box drawings scan 1                */
4332d4fba8b9Smrg		MY_UCS(0x23bb, 17);	/* box drawings scan 3                */
4333d4fba8b9Smrg		MY_UCS(0x2500, 18);	/* box drawings light horizontal      */
4334d4fba8b9Smrg		MY_UCS(0x23bc, 19);	/* box drawings scan 7                */
4335d4fba8b9Smrg		MY_UCS(0x23bd, 20);	/* box drawings scan 9                */
4336d4fba8b9Smrg		MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
4337d4fba8b9Smrg		MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
4338d4fba8b9Smrg		MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
4339d4fba8b9Smrg		MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
4340d4fba8b9Smrg		MY_UCS(0x2502, 25);	/* box drawings light vertical        */
4341d4fba8b9Smrg		MY_UCS(0x2264, 26);	/* less-than or equal to              */
4342d4fba8b9Smrg		MY_UCS(0x2265, 27);	/* greater-than or equal to           */
4343d4fba8b9Smrg		MY_UCS(0x03c0, 28);	/* greek small letter pi              */
4344d4fba8b9Smrg		MY_UCS(0x2260, 29);	/* not equal to                       */
4345d4fba8b9Smrg		MY_UCS(0x00a3, 30);	/* pound sign                         */
4346d4fba8b9Smrg		MY_UCS(0x00b7, 31);	/* middle dot                         */
4347d4fba8b9Smrg	    }
4348d522f475Smrg    }
4349d522f475Smrg    return result;
4350d522f475Smrg}
4351d522f475Smrg
4352d522f475Smrg#undef  MY_UCS
4353d522f475Smrg#define MY_UCS(ucs,dec) case dec: result = ucs; break
4354d522f475Smrg
4355d522f475Smrgunsigned
4356d4fba8b9Smrgdec2ucs(TScreen *screen, unsigned ch)
4357d522f475Smrg{
4358d522f475Smrg    unsigned result = ch;
4359d4fba8b9Smrg
4360d4fba8b9Smrg    (void) screen;
4361d522f475Smrg    if (xtermIsDecGraphic(ch)) {
4362d4fba8b9Smrg#if OPT_VT52_MODE
4363d4fba8b9Smrg	if (screen != 0 && !(screen->vtXX_level)) {
4364d4fba8b9Smrg	    switch (ch) {
4365d4fba8b9Smrg		MY_UCS(0x0020, 0);	/* nbsp, treat as blank           */
4366d4fba8b9Smrg		MY_UCS(0x0020, 1);	/* reserved, treat as blank       */
4367d4fba8b9Smrg		MY_UCS(0x25ae, 2);	/* black vertical rectangle       */
4368d4fba8b9Smrg		MY_UCS(0x215f, 3);	/* "1/"                           */
4369d4fba8b9Smrg		MY_UCS(0x0020, 4);	/* "3/", not in Unicode, ignore   */
4370d4fba8b9Smrg		MY_UCS(0x0020, 5);	/* "5/", not in Unicode, ignore   */
4371d4fba8b9Smrg		MY_UCS(0x0020, 6);	/* "7/", not in Unicode, ignore   */
4372d4fba8b9Smrg		MY_UCS(0x00b0, 7);	/* degree sign                    */
4373d4fba8b9Smrg		MY_UCS(0x00b1, 8);	/* plus-minus sign                */
4374d4fba8b9Smrg		MY_UCS(0x2192, 9);	/* right-arrow                    */
4375d4fba8b9Smrg		MY_UCS(0x2026, 10);	/* ellipsis                       */
4376d4fba8b9Smrg		MY_UCS(0x00f7, 11);	/* divide by                      */
4377d4fba8b9Smrg		MY_UCS(0x2193, 12);	/* down arrow                     */
4378d4fba8b9Smrg		MY_UCS(0x23ba, 13);	/* bar at scan 0                  */
4379d4fba8b9Smrg		MY_UCS(0x23ba, 14);	/* bar at scan 1                  */
4380d4fba8b9Smrg		MY_UCS(0x23bb, 15);	/* bar at scan 2                  */
4381d4fba8b9Smrg		MY_UCS(0x23bb, 16);	/* bar at scan 3                  */
4382d4fba8b9Smrg		MY_UCS(0x23bc, 17);	/* bar at scan 4                  */
4383d4fba8b9Smrg		MY_UCS(0x23bc, 18);	/* bar at scan 5                  */
4384d4fba8b9Smrg		MY_UCS(0x23bd, 19);	/* bar at scan 6                  */
4385d4fba8b9Smrg		MY_UCS(0x23bd, 20);	/* bar at scan 7                  */
4386d4fba8b9Smrg		MY_UCS(0x2080, 21);	/* subscript 0                    */
4387d4fba8b9Smrg		MY_UCS(0x2081, 22);	/* subscript 1                    */
4388d4fba8b9Smrg		MY_UCS(0x2082, 23);	/* subscript 2                    */
4389d4fba8b9Smrg		MY_UCS(0x2083, 24);	/* subscript 3                    */
4390d4fba8b9Smrg		MY_UCS(0x2084, 25);	/* subscript 4                    */
4391d4fba8b9Smrg		MY_UCS(0x2085, 26);	/* subscript 5                    */
4392d4fba8b9Smrg		MY_UCS(0x2086, 27);	/* subscript 6                    */
4393d4fba8b9Smrg		MY_UCS(0x2087, 28);	/* subscript 7                    */
4394d4fba8b9Smrg		MY_UCS(0x2088, 29);	/* subscript 8                    */
4395d4fba8b9Smrg		MY_UCS(0x2089, 30);	/* subscript 9                    */
4396d4fba8b9Smrg		MY_UCS(0x00b6, 31);	/* paragraph                      */
4397d4fba8b9Smrg	    }
4398d4fba8b9Smrg	} else
4399d4fba8b9Smrg#endif
4400d4fba8b9Smrg	    switch (ch) {
4401d4fba8b9Smrg		MY_UCS(0x25ae, 0);	/* black vertical rectangle           */
4402d4fba8b9Smrg		MY_UCS(0x25c6, 1);	/* black diamond                      */
4403d4fba8b9Smrg		MY_UCS(0x2592, 2);	/* medium shade                       */
4404d4fba8b9Smrg		MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation   */
4405d4fba8b9Smrg		MY_UCS(0x240c, 4);	/* symbol for form feed               */
4406d4fba8b9Smrg		MY_UCS(0x240d, 5);	/* symbol for carriage return         */
4407d4fba8b9Smrg		MY_UCS(0x240a, 6);	/* symbol for line feed               */
4408d4fba8b9Smrg		MY_UCS(0x00b0, 7);	/* degree sign                        */
4409d4fba8b9Smrg		MY_UCS(0x00b1, 8);	/* plus-minus sign                    */
4410d4fba8b9Smrg		MY_UCS(0x2424, 9);	/* symbol for newline                 */
4411d4fba8b9Smrg		MY_UCS(0x240b, 10);	/* symbol for vertical tabulation     */
4412d4fba8b9Smrg		MY_UCS(0x2518, 11);	/* box drawings light up and left     */
4413d4fba8b9Smrg		MY_UCS(0x2510, 12);	/* box drawings light down and left   */
4414d4fba8b9Smrg		MY_UCS(0x250c, 13);	/* box drawings light down and right  */
4415d4fba8b9Smrg		MY_UCS(0x2514, 14);	/* box drawings light up and right    */
4416d4fba8b9Smrg		MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
4417d4fba8b9Smrg		MY_UCS(0x23ba, 16);	/* box drawings scan 1                */
4418d4fba8b9Smrg		MY_UCS(0x23bb, 17);	/* box drawings scan 3                */
4419d4fba8b9Smrg		MY_UCS(0x2500, 18);	/* box drawings light horizontal      */
4420d4fba8b9Smrg		MY_UCS(0x23bc, 19);	/* box drawings scan 7                */
4421d4fba8b9Smrg		MY_UCS(0x23bd, 20);	/* box drawings scan 9                */
4422d4fba8b9Smrg		MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
4423d4fba8b9Smrg		MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
4424d4fba8b9Smrg		MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
4425d4fba8b9Smrg		MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
4426d4fba8b9Smrg		MY_UCS(0x2502, 25);	/* box drawings light vertical        */
4427d4fba8b9Smrg		MY_UCS(0x2264, 26);	/* less-than or equal to              */
4428d4fba8b9Smrg		MY_UCS(0x2265, 27);	/* greater-than or equal to           */
4429d4fba8b9Smrg		MY_UCS(0x03c0, 28);	/* greek small letter pi              */
4430d4fba8b9Smrg		MY_UCS(0x2260, 29);	/* not equal to                       */
4431d4fba8b9Smrg		MY_UCS(0x00a3, 30);	/* pound sign                         */
4432d4fba8b9Smrg		MY_UCS(0x00b7, 31);	/* middle dot                         */
4433d4fba8b9Smrg	    }
4434d522f475Smrg    }
4435d522f475Smrg    return result;
4436d522f475Smrg}
4437d522f475Smrg
4438d522f475Smrg#endif /* OPT_WIDE_CHARS */
4439d522f475Smrg
4440b6fea0ceSmrg#if OPT_RENDERFONT || OPT_SHIFT_FONTS
44410bd37d32Smrgstatic int
4442d522f475SmrglookupOneFontSize(XtermWidget xw, int fontnum)
4443d522f475Smrg{
4444d522f475Smrg    TScreen *screen = TScreenOf(xw);
4445d522f475Smrg
4446d522f475Smrg    if (screen->menu_font_sizes[fontnum] == 0) {
4447d522f475Smrg	XTermFonts fnt;
4448d522f475Smrg
4449d522f475Smrg	memset(&fnt, 0, sizeof(fnt));
4450d522f475Smrg	screen->menu_font_sizes[fontnum] = -1;
4451dfb07bc7Smrg	if (xtermOpenFont(xw, screen->MenuFontName(fontnum), &fnt, True)) {
445220d2c4d2Smrg	    if (fontnum <= fontMenu_lastBuiltin
44530bd37d32Smrg		|| strcmp(fnt.fn, DEFFONT)) {
445420d2c4d2Smrg		screen->menu_font_sizes[fontnum] = FontSize(fnt.fs);
44550bd37d32Smrg		if (screen->menu_font_sizes[fontnum] <= 0)
44560bd37d32Smrg		    screen->menu_font_sizes[fontnum] = -1;
44570bd37d32Smrg	    }
4458d522f475Smrg	    xtermCloseFont(xw, &fnt);
4459d522f475Smrg	}
4460d522f475Smrg    }
44610bd37d32Smrg    return (screen->menu_font_sizes[fontnum] > 0);
4462d522f475Smrg}
4463d522f475Smrg
4464d522f475Smrg/*
4465d522f475Smrg * Cache the font-sizes so subsequent larger/smaller font actions will go fast.
4466d522f475Smrg */
4467d522f475Smrgstatic void
4468d522f475SmrglookupFontSizes(XtermWidget xw)
4469d522f475Smrg{
4470d522f475Smrg    int n;
4471d522f475Smrg
4472d522f475Smrg    for (n = 0; n < NMENUFONTS; n++) {
44730bd37d32Smrg	(void) lookupOneFontSize(xw, n);
4474d522f475Smrg    }
4475d522f475Smrg}
4476b6fea0ceSmrg#endif /* OPT_RENDERFONT || OPT_SHIFT_FONTS */
4477d522f475Smrg
44782eaa94a1Schristos#if OPT_RENDERFONT
44799a64e1c5Smrgstatic double
44809a64e1c5SmrgdefaultFaceSize(void)
44819a64e1c5Smrg{
44829a64e1c5Smrg    double result;
44839a64e1c5Smrg    float value;
44849a64e1c5Smrg
44859a64e1c5Smrg    if (sscanf(DEFFACESIZE, "%f", &value) == 1)
4486d4fba8b9Smrg	result = (double) value;
44879a64e1c5Smrg    else
44889a64e1c5Smrg	result = 14.0;
44899a64e1c5Smrg    return result;
44909a64e1c5Smrg}
44919a64e1c5Smrg
44920bd37d32Smrgstatic void
44930bd37d32SmrgfillInFaceSize(XtermWidget xw, int fontnum)
44940bd37d32Smrg{
44950bd37d32Smrg    TScreen *screen = TScreenOf(xw);
4496d4fba8b9Smrg    double face_size = (double) xw->misc.face_size[fontnum];
44970bd37d32Smrg
44980bd37d32Smrg    if (face_size <= 0.0) {
44990bd37d32Smrg#if OPT_SHIFT_FONTS
45000bd37d32Smrg	/*
45010bd37d32Smrg	 * If the user is switching font-sizes, make it follow by
45020bd37d32Smrg	 * default the same ratios to the default as the fixed fonts
45030bd37d32Smrg	 * would, for easy comparison.  There will be some differences
45040bd37d32Smrg	 * since the fixed fonts have a variety of height/width ratios,
45050bd37d32Smrg	 * but this is simpler than adding another resource value - and
45060bd37d32Smrg	 * as noted above, the data for the fixed fonts are available.
45070bd37d32Smrg	 */
45080bd37d32Smrg	(void) lookupOneFontSize(xw, 0);
45090bd37d32Smrg	if (fontnum == fontMenu_default) {
45109a64e1c5Smrg	    face_size = defaultFaceSize();
45110bd37d32Smrg	} else if (lookupOneFontSize(xw, fontnum)
45120bd37d32Smrg		   && (screen->menu_font_sizes[0]
45130bd37d32Smrg		       != screen->menu_font_sizes[fontnum])) {
45140bd37d32Smrg	    double ratio;
45150bd37d32Smrg	    long num = screen->menu_font_sizes[fontnum];
45160bd37d32Smrg	    long den = screen->menu_font_sizes[0];
45170bd37d32Smrg
45180bd37d32Smrg	    if (den <= 0)
45190bd37d32Smrg		den = 1;
45200bd37d32Smrg	    ratio = dimSquareRoot((double) num / (double) den);
45210bd37d32Smrg
4522d4fba8b9Smrg	    face_size = (ratio * (double) xw->misc.face_size[0]);
45230bd37d32Smrg	    TRACE(("scaled[%d] using %3ld/%ld = %.2f -> %f\n",
45240bd37d32Smrg		   fontnum, num, den, ratio, face_size));
45250bd37d32Smrg	} else
45260bd37d32Smrg#endif
45270bd37d32Smrg	{
4528d4fba8b9Smrg#define LikeBitmap(s) (((s) / 78.0) * (double) xw->misc.face_size[fontMenu_default])
45290bd37d32Smrg	    switch (fontnum) {
45300bd37d32Smrg	    case fontMenu_font1:
45310bd37d32Smrg		face_size = LikeBitmap(2.0);
45320bd37d32Smrg		break;
45330bd37d32Smrg	    case fontMenu_font2:
45340bd37d32Smrg		face_size = LikeBitmap(35.0);
45350bd37d32Smrg		break;
45360bd37d32Smrg	    case fontMenu_font3:
45370bd37d32Smrg		face_size = LikeBitmap(60.0);
45380bd37d32Smrg		break;
45390bd37d32Smrg	    default:
45409a64e1c5Smrg		face_size = defaultFaceSize();
45410bd37d32Smrg		break;
45420bd37d32Smrg	    case fontMenu_font4:
45430bd37d32Smrg		face_size = LikeBitmap(90.0);
45440bd37d32Smrg		break;
45450bd37d32Smrg	    case fontMenu_font5:
45460bd37d32Smrg		face_size = LikeBitmap(135.0);
45470bd37d32Smrg		break;
45480bd37d32Smrg	    case fontMenu_font6:
45490bd37d32Smrg		face_size = LikeBitmap(200.0);
45500bd37d32Smrg		break;
4551d4fba8b9Smrg	    case fontMenu_font7:
4552d4fba8b9Smrg		face_size = LikeBitmap(240.0);
4553d4fba8b9Smrg		break;
45540bd37d32Smrg	    }
45550bd37d32Smrg	    TRACE(("builtin[%d] -> %f\n", fontnum, face_size));
45560bd37d32Smrg	}
45570bd37d32Smrg	xw->misc.face_size[fontnum] = (float) face_size;
45580bd37d32Smrg    }
45590bd37d32Smrg}
45600bd37d32Smrg
45610bd37d32Smrg/* no selection or escape */
45620bd37d32Smrg#define NMENU_RENDERFONTS (fontMenu_lastBuiltin + 1)
45630bd37d32Smrg
45640bd37d32Smrg/*
45650bd37d32Smrg * Workaround for breakage in font-packages - check if all of the bitmap font
45660bd37d32Smrg * sizes are the same, and if we're using TrueType fonts.
45670bd37d32Smrg */
45682eaa94a1Schristosstatic Boolean
45692eaa94a1SchristosuseFaceSizes(XtermWidget xw)
45702eaa94a1Schristos{
45712eaa94a1Schristos    Boolean result = False;
45722eaa94a1Schristos
4573d4fba8b9Smrg    TRACE(("useFaceSizes " TRACE_L "\n"));
45742eaa94a1Schristos    if (UsingRenderFont(xw)) {
45750bd37d32Smrg	Boolean nonzero = True;
4576037a25ddSmrg	int n;
45770bd37d32Smrg
45782eaa94a1Schristos	for (n = 0; n < NMENU_RENDERFONTS; ++n) {
4579d4fba8b9Smrg	    if (xw->misc.face_size[n] <= 0.0f) {
45800bd37d32Smrg		nonzero = False;
45812eaa94a1Schristos		break;
45822eaa94a1Schristos	    }
45832eaa94a1Schristos	}
45840bd37d32Smrg	if (!nonzero) {
4585956cc18dSsnj	    Boolean broken_fonts = True;
4586956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
45870bd37d32Smrg	    long first;
4588956cc18dSsnj
4589956cc18dSsnj	    lookupFontSizes(xw);
45900bd37d32Smrg	    first = screen->menu_font_sizes[0];
4591956cc18dSsnj	    for (n = 0; n < NMENUFONTS; n++) {
4592956cc18dSsnj		if (screen->menu_font_sizes[n] > 0
4593956cc18dSsnj		    && screen->menu_font_sizes[n] != first) {
4594956cc18dSsnj		    broken_fonts = False;
4595956cc18dSsnj		    break;
4596956cc18dSsnj		}
4597956cc18dSsnj	    }
4598956cc18dSsnj
4599956cc18dSsnj	    if (broken_fonts) {
4600956cc18dSsnj
4601956cc18dSsnj		TRACE(("bitmap fonts are broken - set faceSize resources\n"));
4602956cc18dSsnj		for (n = 0; n < NMENUFONTS; n++) {
46030bd37d32Smrg		    fillInFaceSize(xw, n);
4604956cc18dSsnj		}
4605956cc18dSsnj
4606956cc18dSsnj	    }
4607956cc18dSsnj	}
46080bd37d32Smrg	result = True;
46092eaa94a1Schristos    }
4610d4fba8b9Smrg    TRACE((TRACE_R " useFaceSizes %d\n", result));
46112eaa94a1Schristos    return result;
46122eaa94a1Schristos}
46130bd37d32Smrg#endif /* OPT_RENDERFONT */
46142eaa94a1Schristos
4615b6fea0ceSmrg#if OPT_SHIFT_FONTS
4616d522f475Smrg/*
4617d522f475Smrg * Find the index of a larger/smaller font (according to the sign of 'relative'
4618d522f475Smrg * and its magnitude), starting from the 'old' index.
4619d522f475Smrg */
4620d522f475Smrgint
4621d522f475SmrglookupRelativeFontSize(XtermWidget xw, int old, int relative)
4622d522f475Smrg{
4623d522f475Smrg    TScreen *screen = TScreenOf(xw);
4624037a25ddSmrg    int m = -1;
4625d522f475Smrg
46262eaa94a1Schristos    TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative));
4627d522f475Smrg    if (!IsIcon(screen)) {
46282eaa94a1Schristos#if OPT_RENDERFONT
46292eaa94a1Schristos	if (useFaceSizes(xw)) {
46302eaa94a1Schristos	    TRACE(("...using FaceSize\n"));
46312eaa94a1Schristos	    if (relative != 0) {
4632037a25ddSmrg		int n;
46332eaa94a1Schristos		for (n = 0; n < NMENU_RENDERFONTS; ++n) {
46340bd37d32Smrg		    fillInFaceSize(xw, n);
46352eaa94a1Schristos		    if (xw->misc.face_size[n] > 0 &&
46362eaa94a1Schristos			xw->misc.face_size[n] != xw->misc.face_size[old]) {
46372eaa94a1Schristos			int cmp_0 = ((xw->misc.face_size[n] >
46382eaa94a1Schristos				      xw->misc.face_size[old])
46392eaa94a1Schristos				     ? relative
46402eaa94a1Schristos				     : -relative);
46412eaa94a1Schristos			int cmp_m = ((m < 0)
46422eaa94a1Schristos				     ? 1
46432eaa94a1Schristos				     : ((xw->misc.face_size[n] <
46442eaa94a1Schristos					 xw->misc.face_size[m])
46452eaa94a1Schristos					? relative
46462eaa94a1Schristos					: -relative));
46472eaa94a1Schristos			if (cmp_0 > 0 && cmp_m > 0) {
46482eaa94a1Schristos			    m = n;
46492eaa94a1Schristos			}
4650d522f475Smrg		    }
4651d522f475Smrg		}
4652d522f475Smrg	    }
46532eaa94a1Schristos	} else
46542eaa94a1Schristos#endif
46552eaa94a1Schristos	{
46562eaa94a1Schristos	    TRACE(("...using bitmap areas\n"));
46572eaa94a1Schristos	    lookupFontSizes(xw);
46582eaa94a1Schristos	    if (relative != 0) {
4659037a25ddSmrg		int n;
46602eaa94a1Schristos		for (n = 0; n < NMENUFONTS; ++n) {
46612eaa94a1Schristos		    if (screen->menu_font_sizes[n] > 0 &&
46622eaa94a1Schristos			screen->menu_font_sizes[n] !=
46632eaa94a1Schristos			screen->menu_font_sizes[old]) {
46642eaa94a1Schristos			int cmp_0 = ((screen->menu_font_sizes[n] >
46652eaa94a1Schristos				      screen->menu_font_sizes[old])
46662eaa94a1Schristos				     ? relative
46672eaa94a1Schristos				     : -relative);
46682eaa94a1Schristos			int cmp_m = ((m < 0)
46692eaa94a1Schristos				     ? 1
46702eaa94a1Schristos				     : ((screen->menu_font_sizes[n] <
46712eaa94a1Schristos					 screen->menu_font_sizes[m])
46722eaa94a1Schristos					? relative
46732eaa94a1Schristos					: -relative));
46742eaa94a1Schristos			if (cmp_0 > 0 && cmp_m > 0) {
46752eaa94a1Schristos			    m = n;
46762eaa94a1Schristos			}
46772eaa94a1Schristos		    }
46782eaa94a1Schristos		}
4679d522f475Smrg	    }
4680d522f475Smrg	}
46812eaa94a1Schristos	TRACE(("...new index %d\n", m));
46822eaa94a1Schristos	if (m >= 0) {
46832eaa94a1Schristos	    if (relative > 1)
46842eaa94a1Schristos		m = lookupRelativeFontSize(xw, m, relative - 1);
46852eaa94a1Schristos	    else if (relative < -1)
46862eaa94a1Schristos		m = lookupRelativeFontSize(xw, m, relative + 1);
46872eaa94a1Schristos	}
4688d522f475Smrg    }
4689d522f475Smrg    return m;
4690d522f475Smrg}
4691d522f475Smrg
4692d522f475Smrg/* ARGSUSED */
4693d522f475Smrgvoid
4694d4fba8b9SmrgHandleLargerFont(Widget w,
46959a64e1c5Smrg		 XEvent *event GCC_UNUSED,
4696fa3f02f3Smrg		 String *params GCC_UNUSED,
4697d522f475Smrg		 Cardinal *param_count GCC_UNUSED)
4698d522f475Smrg{
4699956cc18dSsnj    XtermWidget xw;
4700d522f475Smrg
470120d2c4d2Smrg    TRACE(("Handle larger-vt-font for %p\n", (void *) w));
4702956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
4703d522f475Smrg	if (xw->misc.shift_fonts) {
4704956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
4705d522f475Smrg	    int m;
4706d522f475Smrg
4707d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, 1);
4708d522f475Smrg	    if (m >= 0) {
4709d522f475Smrg		SetVTFont(xw, m, True, NULL);
4710d522f475Smrg	    } else {
471120d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
4712d522f475Smrg	    }
4713d522f475Smrg	}
4714d522f475Smrg    }
4715d522f475Smrg}
4716d522f475Smrg
4717d522f475Smrg/* ARGSUSED */
4718d522f475Smrgvoid
4719d4fba8b9SmrgHandleSmallerFont(Widget w,
47209a64e1c5Smrg		  XEvent *event GCC_UNUSED,
4721fa3f02f3Smrg		  String *params GCC_UNUSED,
4722d522f475Smrg		  Cardinal *param_count GCC_UNUSED)
4723d522f475Smrg{
4724956cc18dSsnj    XtermWidget xw;
4725d522f475Smrg
472620d2c4d2Smrg    TRACE(("Handle smaller-vt-font for %p\n", (void *) w));
4727956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
4728d522f475Smrg	if (xw->misc.shift_fonts) {
4729956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
4730d522f475Smrg	    int m;
4731d522f475Smrg
4732d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, -1);
4733d522f475Smrg	    if (m >= 0) {
4734d522f475Smrg		SetVTFont(xw, m, True, NULL);
4735d522f475Smrg	    } else {
473620d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
4737d522f475Smrg	    }
4738d522f475Smrg	}
4739d522f475Smrg    }
4740d522f475Smrg}
4741b6fea0ceSmrg#endif /* OPT_SHIFT_FONTS */
4742d522f475Smrg
4743d522f475Smrgint
4744d522f475SmrgxtermGetFont(const char *param)
4745d522f475Smrg{
4746d522f475Smrg    int fontnum;
4747d522f475Smrg
4748d522f475Smrg    switch (param[0]) {
4749d522f475Smrg    case 'd':
4750d522f475Smrg    case 'D':
4751d522f475Smrg    case '0':
4752d522f475Smrg	fontnum = fontMenu_default;
4753d522f475Smrg	break;
4754d522f475Smrg    case '1':
4755d522f475Smrg	fontnum = fontMenu_font1;
4756d522f475Smrg	break;
4757d522f475Smrg    case '2':
4758d522f475Smrg	fontnum = fontMenu_font2;
4759d522f475Smrg	break;
4760d522f475Smrg    case '3':
4761d522f475Smrg	fontnum = fontMenu_font3;
4762d522f475Smrg	break;
4763d522f475Smrg    case '4':
4764d522f475Smrg	fontnum = fontMenu_font4;
4765d522f475Smrg	break;
4766d522f475Smrg    case '5':
4767d522f475Smrg	fontnum = fontMenu_font5;
4768d522f475Smrg	break;
4769d522f475Smrg    case '6':
4770d522f475Smrg	fontnum = fontMenu_font6;
4771d522f475Smrg	break;
4772d4fba8b9Smrg    case '7':
4773d4fba8b9Smrg	fontnum = fontMenu_font7;
4774d4fba8b9Smrg	break;
4775d522f475Smrg    case 'e':
4776d522f475Smrg    case 'E':
4777d522f475Smrg	fontnum = fontMenu_fontescape;
4778d522f475Smrg	break;
4779d522f475Smrg    case 's':
4780d522f475Smrg    case 'S':
4781d522f475Smrg	fontnum = fontMenu_fontsel;
4782d522f475Smrg	break;
4783d522f475Smrg    default:
4784d522f475Smrg	fontnum = -1;
4785d522f475Smrg	break;
4786d522f475Smrg    }
4787d4fba8b9Smrg    TRACE(("xtermGetFont(%s) ->%d\n", NonNull(param), fontnum));
4788d522f475Smrg    return fontnum;
4789d522f475Smrg}
4790d522f475Smrg
4791d522f475Smrg/* ARGSUSED */
4792d522f475Smrgvoid
4793d4fba8b9SmrgHandleSetFont(Widget w,
47949a64e1c5Smrg	      XEvent *event GCC_UNUSED,
4795fa3f02f3Smrg	      String *params,
4796d522f475Smrg	      Cardinal *param_count)
4797d522f475Smrg{
4798956cc18dSsnj    XtermWidget xw;
4799956cc18dSsnj
4800956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
4801d522f475Smrg	int fontnum;
4802d522f475Smrg	VTFontNames fonts;
4803d522f475Smrg
4804d522f475Smrg	memset(&fonts, 0, sizeof(fonts));
4805d522f475Smrg
4806d522f475Smrg	if (*param_count == 0) {
4807d522f475Smrg	    fontnum = fontMenu_default;
4808d522f475Smrg	} else {
4809d522f475Smrg	    Cardinal maxparams = 1;	/* total number of params allowed */
4810d522f475Smrg	    int result = xtermGetFont(params[0]);
4811d522f475Smrg
4812d522f475Smrg	    switch (result) {
4813d522f475Smrg	    case fontMenu_default:	/* FALLTHRU */
4814d522f475Smrg	    case fontMenu_font1:	/* FALLTHRU */
4815d522f475Smrg	    case fontMenu_font2:	/* FALLTHRU */
4816d522f475Smrg	    case fontMenu_font3:	/* FALLTHRU */
4817d522f475Smrg	    case fontMenu_font4:	/* FALLTHRU */
4818d522f475Smrg	    case fontMenu_font5:	/* FALLTHRU */
4819d522f475Smrg	    case fontMenu_font6:	/* FALLTHRU */
4820d4fba8b9Smrg	    case fontMenu_font7:	/* FALLTHRU */
4821d522f475Smrg		break;
4822d522f475Smrg	    case fontMenu_fontescape:
4823d522f475Smrg#if OPT_WIDE_CHARS
4824d522f475Smrg		maxparams = 5;
4825d522f475Smrg#else
4826d522f475Smrg		maxparams = 3;
4827d522f475Smrg#endif
4828d522f475Smrg		break;
4829d522f475Smrg	    case fontMenu_fontsel:
4830d522f475Smrg		maxparams = 2;
4831d522f475Smrg		break;
4832d522f475Smrg	    default:
483320d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
4834d522f475Smrg		return;
4835d522f475Smrg	    }
4836d522f475Smrg	    fontnum = result;
4837d522f475Smrg
4838d522f475Smrg	    if (*param_count > maxparams) {	/* see if extra args given */
483920d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
4840d522f475Smrg		return;
4841d522f475Smrg	    }
4842d522f475Smrg	    switch (*param_count) {	/* assign 'em */
4843d522f475Smrg#if OPT_WIDE_CHARS
4844d522f475Smrg	    case 5:
4845dfb07bc7Smrg		fonts.f_wb = x_strdup(params[4]);
4846d522f475Smrg		/* FALLTHRU */
4847d522f475Smrg	    case 4:
4848dfb07bc7Smrg		fonts.f_w = x_strdup(params[3]);
4849d522f475Smrg#endif
4850dfb07bc7Smrg		/* FALLTHRU */
4851d522f475Smrg	    case 3:
4852dfb07bc7Smrg		fonts.f_b = x_strdup(params[2]);
4853d522f475Smrg		/* FALLTHRU */
4854d522f475Smrg	    case 2:
4855dfb07bc7Smrg		fonts.f_n = x_strdup(params[1]);
4856d522f475Smrg		break;
4857d522f475Smrg	    }
4858d522f475Smrg	}
4859d522f475Smrg
4860956cc18dSsnj	SetVTFont(xw, fontnum, True, &fonts);
4861d522f475Smrg    }
4862d522f475Smrg}
4863d522f475Smrg
4864d522f475Smrgvoid
4865d522f475SmrgSetVTFont(XtermWidget xw,
4866d522f475Smrg	  int which,
4867d522f475Smrg	  Bool doresize,
4868d522f475Smrg	  const VTFontNames * fonts)
4869d522f475Smrg{
4870956cc18dSsnj    TScreen *screen = TScreenOf(xw);
4871d522f475Smrg
4872d522f475Smrg    TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which,
4873d522f475Smrg	   (fonts && fonts->f_n) ? fonts->f_n : "<null>",
4874d522f475Smrg	   (fonts && fonts->f_b) ? fonts->f_b : "<null>"));
4875d522f475Smrg
4876d522f475Smrg    if (IsIcon(screen)) {
487720d2c4d2Smrg	Bell(xw, XkbBI_MinorError, 0);
4878d522f475Smrg    } else if (which >= 0 && which < NMENUFONTS) {
4879d522f475Smrg	VTFontNames myfonts;
4880d522f475Smrg
4881d522f475Smrg	memset(&myfonts, 0, sizeof(myfonts));
4882d522f475Smrg	if (fonts != 0)
4883d522f475Smrg	    myfonts = *fonts;
4884d522f475Smrg
4885d522f475Smrg	if (which == fontMenu_fontsel) {	/* go get the selection */
4886d522f475Smrg	    FindFontSelection(xw, myfonts.f_n, False);
4887d522f475Smrg	} else {
4888d522f475Smrg	    int oldFont = screen->menu_font_number;
4889d522f475Smrg
4890d522f475Smrg#define USE_CACHED(field, name) \
4891d522f475Smrg	    if (myfonts.field == 0) { \
4892492d43a5Smrg		myfonts.field = x_strdup(screen->menu_font_names[which][name]); \
4893d522f475Smrg		TRACE(("set myfonts." #field " from menu_font_names[%d][" #name "] %s\n", \
4894d522f475Smrg		       which, NonNull(myfonts.field))); \
4895d522f475Smrg	    } else { \
4896d522f475Smrg		TRACE(("set myfonts." #field " reused\n")); \
4897d522f475Smrg	    }
489820d2c4d2Smrg#define SAVE_FNAME(field, name) \
489920d2c4d2Smrg	    if (myfonts.field != 0) { \
490020d2c4d2Smrg		if (screen->menu_font_names[which][name] == 0 \
490120d2c4d2Smrg		 || strcmp(screen->menu_font_names[which][name], myfonts.field)) { \
4902d4fba8b9Smrg		    TRACE(("updating menu_font_names[%d][" #name "] to \"%s\"\n", \
490320d2c4d2Smrg			   which, myfonts.field)); \
49049a64e1c5Smrg		    FREE_STRING(screen->menu_font_names[which][name]); \
490520d2c4d2Smrg		    screen->menu_font_names[which][name] = x_strdup(myfonts.field); \
490620d2c4d2Smrg		} \
490720d2c4d2Smrg	    }
490820d2c4d2Smrg
4909d522f475Smrg	    USE_CACHED(f_n, fNorm);
4910d522f475Smrg	    USE_CACHED(f_b, fBold);
4911d522f475Smrg#if OPT_WIDE_CHARS
4912d522f475Smrg	    USE_CACHED(f_w, fWide);
4913d522f475Smrg	    USE_CACHED(f_wb, fWBold);
4914d522f475Smrg#endif
4915d522f475Smrg	    if (xtermLoadFont(xw,
4916d522f475Smrg			      &myfonts,
4917d522f475Smrg			      doresize, which)) {
491820d2c4d2Smrg		/*
491920d2c4d2Smrg		 * If successful, save the data so that a subsequent query via
492020d2c4d2Smrg		 * OSC-50 will return the expected values.
492120d2c4d2Smrg		 */
492220d2c4d2Smrg		SAVE_FNAME(f_n, fNorm);
492320d2c4d2Smrg		SAVE_FNAME(f_b, fBold);
492420d2c4d2Smrg#if OPT_WIDE_CHARS
492520d2c4d2Smrg		SAVE_FNAME(f_w, fWide);
492620d2c4d2Smrg		SAVE_FNAME(f_wb, fWBold);
492720d2c4d2Smrg#endif
4928d522f475Smrg	    } else {
492994644356Smrg		(void) xtermLoadFont(xw,
493094644356Smrg				     xtermFontName(screen->MenuFontName(oldFont)),
493194644356Smrg				     doresize, oldFont);
493220d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
4933d522f475Smrg	    }
49349a64e1c5Smrg	    FREE_FNAME(f_n);
49359a64e1c5Smrg	    FREE_FNAME(f_b);
49369a64e1c5Smrg#if OPT_WIDE_CHARS
49379a64e1c5Smrg	    FREE_FNAME(f_w);
49389a64e1c5Smrg	    FREE_FNAME(f_wb);
49399a64e1c5Smrg#endif
4940d522f475Smrg	}
494120d2c4d2Smrg    } else {
494220d2c4d2Smrg	Bell(xw, XkbBI_MinorError, 0);
4943d522f475Smrg    }
4944d522f475Smrg    return;
4945d522f475Smrg}
4946dfb07bc7Smrg
4947dfb07bc7Smrg#if OPT_RENDERFONT
4948dfb07bc7Smrgstatic void
4949dfb07bc7SmrgtrimSizeFromFace(char *face_name, float *face_size)
4950dfb07bc7Smrg{
4951dfb07bc7Smrg    char *first = strstr(face_name, ":size=");
4952dfb07bc7Smrg    if (first == 0) {
4953dfb07bc7Smrg	first = face_name;
4954dfb07bc7Smrg    } else {
4955dfb07bc7Smrg	first++;
4956dfb07bc7Smrg    }
4957dfb07bc7Smrg    if (!strncmp(first, "size=", (size_t) 5)) {
4958dfb07bc7Smrg	char *last = strchr(first, ':');
4959dfb07bc7Smrg	char mark;
4960dfb07bc7Smrg	float value;
4961dfb07bc7Smrg	char extra;
4962dfb07bc7Smrg	TRACE(("...before trimming, font = \"%s\"\n", face_name));
4963dfb07bc7Smrg	if (last == 0)
4964dfb07bc7Smrg	    last = first + strlen(first);
4965dfb07bc7Smrg	mark = *last;
4966dfb07bc7Smrg	*last = '\0';
4967dfb07bc7Smrg	if (sscanf(first, "size=%g%c", &value, &extra) == 1) {
4968dfb07bc7Smrg	    TRACE(("...trimmed size from font: %g\n", value));
4969dfb07bc7Smrg	    if (face_size != 0)
4970dfb07bc7Smrg		*face_size = value;
4971dfb07bc7Smrg	}
4972dfb07bc7Smrg	if (mark) {
4973dfb07bc7Smrg	    while ((*first++ = *++last) != '\0') {
4974dfb07bc7Smrg		;
4975dfb07bc7Smrg	    }
4976dfb07bc7Smrg	} else {
4977dfb07bc7Smrg	    if (first != face_name)
4978dfb07bc7Smrg		--first;
4979dfb07bc7Smrg	    *first = '\0';
4980dfb07bc7Smrg	}
4981dfb07bc7Smrg	TRACE(("...after trimming, font = \"%s\"\n", face_name));
4982dfb07bc7Smrg    }
4983dfb07bc7Smrg}
4984dfb07bc7Smrg#endif
4985dfb07bc7Smrg
4986dfb07bc7Smrg/*
4987dfb07bc7Smrg * Save a font specification to the proper list.
4988dfb07bc7Smrg */
4989dfb07bc7Smrgstatic void
4990dfb07bc7Smrgsave2FontList(XtermWidget xw,
4991dfb07bc7Smrg	      const char *name,
4992dfb07bc7Smrg	      XtermFontNames * fontnames,
4993dfb07bc7Smrg	      VTFontEnum which,
4994dfb07bc7Smrg	      const char *source,
4995dfb07bc7Smrg	      Bool ttf)
4996dfb07bc7Smrg{
4997dfb07bc7Smrg    char *value;
4998dfb07bc7Smrg    size_t plen;
4999dfb07bc7Smrg    Bool marked = False;
5000dfb07bc7Smrg    Bool use_ttf = ttf;
5001dfb07bc7Smrg
5002dfb07bc7Smrg    (void) xw;
5003dfb07bc7Smrg
5004dfb07bc7Smrg    if (source == 0)
5005dfb07bc7Smrg	source = "";
5006dfb07bc7Smrg    while (isspace(CharOf(*source)))
5007dfb07bc7Smrg	++source;
5008dfb07bc7Smrg
5009dfb07bc7Smrg    /* fontconfig patterns can contain ':' separators, but we'll treat
5010dfb07bc7Smrg     * a leading prefix specially to denote whether the pattern might be
5011dfb07bc7Smrg     * XLFD ("x" or "xlfd") versus Xft ("xft").
5012dfb07bc7Smrg     */
5013dfb07bc7Smrg    for (plen = 0; source[plen] != '\0'; ++plen) {
5014dfb07bc7Smrg	if (source[plen] == ':') {
5015dfb07bc7Smrg	    marked = True;
5016dfb07bc7Smrg	    switch (plen) {
5017dfb07bc7Smrg	    case 0:
5018dfb07bc7Smrg		++plen;		/* trim leading ':' */
5019dfb07bc7Smrg		break;
5020dfb07bc7Smrg	    case 1:
5021dfb07bc7Smrg		if (!strncmp(source, "x", plen)) {
5022dfb07bc7Smrg		    ++plen;
5023dfb07bc7Smrg		    use_ttf = False;
5024dfb07bc7Smrg		} else {
5025dfb07bc7Smrg		    marked = False;
5026dfb07bc7Smrg		}
5027dfb07bc7Smrg		break;
5028dfb07bc7Smrg	    case 3:
5029dfb07bc7Smrg		if (!strncmp(source, "xft", plen)) {
5030dfb07bc7Smrg		    ++plen;
5031dfb07bc7Smrg		    use_ttf = True;
5032dfb07bc7Smrg		} else {
5033dfb07bc7Smrg		    marked = False;
5034dfb07bc7Smrg		}
5035dfb07bc7Smrg		break;
5036dfb07bc7Smrg	    case 4:
5037dfb07bc7Smrg		if (!strncmp(source, "xlfd", plen)) {
5038dfb07bc7Smrg		    ++plen;
5039dfb07bc7Smrg		    use_ttf = False;
5040dfb07bc7Smrg		} else {
5041dfb07bc7Smrg		    marked = False;
5042dfb07bc7Smrg		}
5043dfb07bc7Smrg		break;
5044dfb07bc7Smrg	    default:
5045dfb07bc7Smrg		marked = False;
5046dfb07bc7Smrg		plen = 0;
5047dfb07bc7Smrg		break;
5048dfb07bc7Smrg	    }
5049dfb07bc7Smrg	    break;
5050dfb07bc7Smrg	}
5051dfb07bc7Smrg    }
5052dfb07bc7Smrg    if (!marked)
5053dfb07bc7Smrg	plen = 0;
5054dfb07bc7Smrg    value = x_strtrim(source + plen);
5055dfb07bc7Smrg    if (value != 0) {
5056dfb07bc7Smrg	Bool success = False;
5057dfb07bc7Smrg#if OPT_RENDERFONT
5058dfb07bc7Smrg	VTFontList *target = (use_ttf
5059dfb07bc7Smrg			      ? &(fontnames->xft)
5060dfb07bc7Smrg			      : &(fontnames->x11));
5061dfb07bc7Smrg#else
5062dfb07bc7Smrg	VTFontList *target = &(fontnames->x11);
5063dfb07bc7Smrg#endif
5064dfb07bc7Smrg	char ***list = 0;
5065dfb07bc7Smrg	char **next = 0;
5066dfb07bc7Smrg	size_t count = 0;
5067dfb07bc7Smrg
5068dfb07bc7Smrg	(void) use_ttf;
5069dfb07bc7Smrg	switch (which) {
5070dfb07bc7Smrg	case fNorm:
5071dfb07bc7Smrg	    list = &(target->list_n);
5072dfb07bc7Smrg	    break;
5073dfb07bc7Smrg	case fBold:
5074dfb07bc7Smrg	    list = &(target->list_b);
5075dfb07bc7Smrg	    break;
5076dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
5077dfb07bc7Smrg	case fItal:
5078dfb07bc7Smrg	    list = &(target->list_i);
5079dfb07bc7Smrg	    break;
5080d4fba8b9Smrg	case fBtal:
5081d4fba8b9Smrg	    list = &(target->list_bi);
5082d4fba8b9Smrg	    break;
5083dfb07bc7Smrg#endif
5084dfb07bc7Smrg#if OPT_WIDE_CHARS
5085dfb07bc7Smrg	case fWide:
5086dfb07bc7Smrg	    list = &(target->list_w);
5087dfb07bc7Smrg	    break;
5088dfb07bc7Smrg	case fWBold:
5089dfb07bc7Smrg	    list = &(target->list_wb);
5090dfb07bc7Smrg	    break;
5091dfb07bc7Smrg	case fWItal:
5092dfb07bc7Smrg	    list = &(target->list_wi);
5093dfb07bc7Smrg	    break;
5094d4fba8b9Smrg	case fWBtal:
5095d4fba8b9Smrg	    list = &(target->list_wbi);
5096d4fba8b9Smrg	    break;
5097dfb07bc7Smrg#endif
5098dfb07bc7Smrg	case fMAX:
5099dfb07bc7Smrg	    list = 0;
5100dfb07bc7Smrg	    break;
5101dfb07bc7Smrg	}
5102dfb07bc7Smrg
5103dfb07bc7Smrg	if (list != 0) {
5104dfb07bc7Smrg	    success = True;
5105dfb07bc7Smrg	    if (*list != 0) {
5106dfb07bc7Smrg		while ((*list)[count] != 0) {
5107dfb07bc7Smrg		    if (IsEmpty((*list)[count])) {
5108dfb07bc7Smrg			TRACE(("... initial %s\n", value));
5109dfb07bc7Smrg			free((*list)[count]);
5110dfb07bc7Smrg			break;
5111dfb07bc7Smrg		    } else if (!strcmp(value, (*list)[count])) {
5112dfb07bc7Smrg			TRACE(("... duplicate %s\n", value));
5113dfb07bc7Smrg			success = False;
5114dfb07bc7Smrg			break;
5115dfb07bc7Smrg		    }
5116dfb07bc7Smrg		    ++count;
5117dfb07bc7Smrg		}
5118dfb07bc7Smrg	    }
5119dfb07bc7Smrg	    if (success) {
5120dfb07bc7Smrg		next = realloc(*list, sizeof(char *) * (count + 2));
5121dfb07bc7Smrg		if (next != 0) {
5122dfb07bc7Smrg#if OPT_RENDERFONT
5123dfb07bc7Smrg		    if (use_ttf) {
5124dfb07bc7Smrg			trimSizeFromFace(value,
5125dfb07bc7Smrg					 (count == 0 && which == fNorm)
5126dfb07bc7Smrg					 ? &(xw->misc.face_size[0])
5127dfb07bc7Smrg					 : (float *) 0);
5128dfb07bc7Smrg		    }
5129dfb07bc7Smrg#endif
5130dfb07bc7Smrg		    next[count++] = value;
5131dfb07bc7Smrg		    next[count] = 0;
5132dfb07bc7Smrg		    *list = next;
51338f44fb3bSmrg		    TRACE(("... saved \"%s\" \"%s\" %lu:\"%s\"\n",
5134dfb07bc7Smrg			   whichFontList(xw, target),
5135dfb07bc7Smrg			   whichFontList2(xw, *list),
5136dfb07bc7Smrg			   (unsigned long) count,
5137dfb07bc7Smrg			   value));
5138dfb07bc7Smrg		} else {
5139dfb07bc7Smrg		    fprintf(stderr,
5140dfb07bc7Smrg			    "realloc failure in save2FontList(%s)\n",
5141dfb07bc7Smrg			    name);
5142dfb07bc7Smrg		    freeFontList(list);
5143dfb07bc7Smrg		    success = False;
5144dfb07bc7Smrg		}
5145dfb07bc7Smrg	    }
5146dfb07bc7Smrg	}
5147dfb07bc7Smrg	if (success) {
5148d4fba8b9Smrg#if (MAX_XFT_FONTS == MAX_XLFD_FONTS)
5149d4fba8b9Smrg	    size_t limit = MAX_XFT_FONTS;
5150d4fba8b9Smrg#else
5151dfb07bc7Smrg	    size_t limit = use_ttf ? MAX_XFT_FONTS : MAX_XLFD_FONTS;
5152d4fba8b9Smrg#endif
5153d4fba8b9Smrg	    if (count > limit && *x_skip_blanks(value)) {
5154dfb07bc7Smrg		fprintf(stderr, "%s: too many fonts for %s, ignoring %s\n",
5155dfb07bc7Smrg			ProgramName,
5156dfb07bc7Smrg			whichFontEnum(which),
5157dfb07bc7Smrg			value);
5158dfb07bc7Smrg		if (list && *list) {
5159dfb07bc7Smrg		    free((*list)[limit]);
5160dfb07bc7Smrg		    (*list)[limit] = 0;
5161dfb07bc7Smrg		}
5162dfb07bc7Smrg	    }
5163dfb07bc7Smrg	} else {
5164dfb07bc7Smrg	    free(value);
5165dfb07bc7Smrg	}
5166dfb07bc7Smrg    }
5167dfb07bc7Smrg}
5168dfb07bc7Smrg
5169dfb07bc7Smrg/*
5170dfb07bc7Smrg * In principle, any of the font-name resources could be extended to be a list
5171dfb07bc7Smrg * of font-names.  That would be bad for performance, but as a basis for an
5172dfb07bc7Smrg * extension, parse the font-name as a comma-separated list, creating/updating
5173dfb07bc7Smrg * an array of font-names.
5174dfb07bc7Smrg */
5175dfb07bc7Smrgvoid
5176dfb07bc7SmrgallocFontList(XtermWidget xw,
5177dfb07bc7Smrg	      const char *name,
5178dfb07bc7Smrg	      XtermFontNames * target,
5179dfb07bc7Smrg	      VTFontEnum which,
5180dfb07bc7Smrg	      const char *source,
5181dfb07bc7Smrg	      Bool ttf)
5182dfb07bc7Smrg{
5183dfb07bc7Smrg    char *blob;
5184dfb07bc7Smrg
5185dfb07bc7Smrg    blob = x_strdup(source);
5186d4fba8b9Smrg    if (blob != 0) {
5187dfb07bc7Smrg	int n;
5188dfb07bc7Smrg	int pass;
5189dfb07bc7Smrg	char **list = 0;
5190dfb07bc7Smrg
51918f44fb3bSmrg	TRACE(("allocFontList %s name=\"%s\" source=\"%s\"\n",
51928f44fb3bSmrg	       whichFontEnum(which), name, blob));
5193dfb07bc7Smrg
5194dfb07bc7Smrg	for (pass = 0; pass < 2; ++pass) {
5195dfb07bc7Smrg	    unsigned count = 0;
5196dfb07bc7Smrg	    if (pass)
5197dfb07bc7Smrg		list[0] = blob;
5198dfb07bc7Smrg	    for (n = 0; blob[n] != '\0'; ++n) {
5199dfb07bc7Smrg		if (blob[n] == ',') {
5200dfb07bc7Smrg		    ++count;
5201dfb07bc7Smrg		    if (pass != 0) {
5202dfb07bc7Smrg			blob[n] = '\0';
5203dfb07bc7Smrg			list[count] = blob + n + 1;
5204dfb07bc7Smrg		    }
5205dfb07bc7Smrg		}
5206dfb07bc7Smrg	    }
5207dfb07bc7Smrg	    if (!pass) {
5208dfb07bc7Smrg		if (count == 0 && *blob == '\0')
5209dfb07bc7Smrg		    break;
5210dfb07bc7Smrg		list = TypeCallocN(char *, count + 2);
5211dfb07bc7Smrg		if (list == 0)
5212dfb07bc7Smrg		    break;
5213dfb07bc7Smrg	    }
5214dfb07bc7Smrg	}
5215dfb07bc7Smrg	if (list) {
5216dfb07bc7Smrg	    for (n = 0; list[n] != 0; ++n) {
5217dfb07bc7Smrg		if (*list[n]) {
5218dfb07bc7Smrg		    save2FontList(xw, name, target, which, list[n], ttf);
5219dfb07bc7Smrg		}
5220dfb07bc7Smrg	    }
5221dfb07bc7Smrg	    free(list);
5222dfb07bc7Smrg	}
5223dfb07bc7Smrg    }
5224dfb07bc7Smrg    free(blob);
5225dfb07bc7Smrg}
5226dfb07bc7Smrg
5227dfb07bc7Smrgstatic void
5228dfb07bc7SmrginitFontList(XtermWidget xw,
5229dfb07bc7Smrg	     const char *name,
5230dfb07bc7Smrg	     XtermFontNames * target,
5231dfb07bc7Smrg	     Bool ttf)
5232dfb07bc7Smrg{
5233dfb07bc7Smrg    int which;
5234dfb07bc7Smrg
5235dfb07bc7Smrg    TRACE(("initFontList(%s)\n", name));
5236dfb07bc7Smrg    for (which = 0; which < fMAX; ++which) {
5237dfb07bc7Smrg	save2FontList(xw, name, target, (VTFontEnum) which, "", ttf);
5238dfb07bc7Smrg    }
5239dfb07bc7Smrg}
5240dfb07bc7Smrg
5241dfb07bc7Smrgvoid
5242dfb07bc7SmrginitFontLists(XtermWidget xw)
5243dfb07bc7Smrg{
5244dfb07bc7Smrg    TRACE(("initFontLists\n"));
5245dfb07bc7Smrg    initFontList(xw, "x11 font", &(xw->work.fonts), False);
5246dfb07bc7Smrg#if OPT_RENDERFONT
5247dfb07bc7Smrg    initFontList(xw, "xft font", &(xw->work.fonts), True);
5248dfb07bc7Smrg#endif
5249dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
5250dfb07bc7Smrg    initFontList(xw, "cached font",
5251dfb07bc7Smrg		 &(xw->screen.cacheVTFonts.fonts), False);
5252dfb07bc7Smrg#endif
5253dfb07bc7Smrg}
5254dfb07bc7Smrg
5255dfb07bc7Smrgvoid
5256dfb07bc7SmrgcopyFontList(char ***targetp, char **source)
5257dfb07bc7Smrg{
5258dfb07bc7Smrg    freeFontList(targetp);
5259dfb07bc7Smrg
5260dfb07bc7Smrg    if (source != 0) {
5261dfb07bc7Smrg	int pass;
5262dfb07bc7Smrg	size_t count;
5263dfb07bc7Smrg
5264dfb07bc7Smrg	for (pass = 0; pass < 2; ++pass) {
5265dfb07bc7Smrg	    for (count = 0; source[count] != 0; ++count) {
5266dfb07bc7Smrg		if (pass)
5267dfb07bc7Smrg		    (*targetp)[count] = x_strdup(source[count]);
5268dfb07bc7Smrg	    }
5269dfb07bc7Smrg	    if (!pass) {
5270dfb07bc7Smrg		++count;
5271dfb07bc7Smrg		*targetp = TypeCallocN(char *, count);
5272dfb07bc7Smrg	    }
5273dfb07bc7Smrg	}
5274dfb07bc7Smrg    } else {
5275dfb07bc7Smrg	*targetp = TypeCallocN(char *, 2);
5276dfb07bc7Smrg	(*targetp)[0] = x_strdup("");
5277dfb07bc7Smrg    }
5278dfb07bc7Smrg}
5279dfb07bc7Smrg
5280dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
5281dfb07bc7Smrgstatic Boolean
5282dfb07bc7Smrgmerge_sublist(char ***targetp, char **source)
5283dfb07bc7Smrg{
5284dfb07bc7Smrg    Boolean result = False;
5285dfb07bc7Smrg    if ((*targetp == 0 || IsEmpty(**targetp)) && !IsEmpty(*source)) {
5286dfb07bc7Smrg	copyFontList(targetp, source);
5287dfb07bc7Smrg	result = True;
5288dfb07bc7Smrg    }
5289dfb07bc7Smrg    return result;
5290dfb07bc7Smrg}
5291dfb07bc7Smrg#endif
5292dfb07bc7Smrg
5293dfb07bc7Smrgvoid
5294dfb07bc7SmrgfreeFontList(char ***targetp)
5295dfb07bc7Smrg{
5296dfb07bc7Smrg    if (targetp != 0) {
5297dfb07bc7Smrg	char **target = *targetp;
5298dfb07bc7Smrg	if (target != 0) {
5299dfb07bc7Smrg	    int n;
5300dfb07bc7Smrg	    for (n = 0; target[n] != 0; ++n) {
5301dfb07bc7Smrg		free(target[n]);
5302dfb07bc7Smrg	    }
5303dfb07bc7Smrg	    free(target);
5304dfb07bc7Smrg	    *targetp = 0;
5305dfb07bc7Smrg	}
5306dfb07bc7Smrg    }
5307dfb07bc7Smrg}
5308dfb07bc7Smrg
5309dfb07bc7Smrgvoid
5310dfb07bc7SmrgfreeFontLists(VTFontList * lists)
5311dfb07bc7Smrg{
5312dfb07bc7Smrg    int which;
5313dfb07bc7Smrg
5314dfb07bc7Smrg    TRACE(("freeFontLists\n"));
5315dfb07bc7Smrg    for (which = 0; which < fMAX; ++which) {
5316dfb07bc7Smrg	char ***target = 0;
5317dfb07bc7Smrg	switch (which) {
5318dfb07bc7Smrg	case fNorm:
5319dfb07bc7Smrg	    target = &(lists->list_n);
5320dfb07bc7Smrg	    break;
5321dfb07bc7Smrg	case fBold:
5322dfb07bc7Smrg	    target = &(lists->list_b);
5323dfb07bc7Smrg	    break;
5324dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
5325dfb07bc7Smrg	case fItal:
5326dfb07bc7Smrg	    target = &(lists->list_i);
5327dfb07bc7Smrg	    break;
5328d4fba8b9Smrg	case fBtal:
5329d4fba8b9Smrg	    target = &(lists->list_bi);
5330d4fba8b9Smrg	    break;
5331dfb07bc7Smrg#endif
5332dfb07bc7Smrg#if OPT_WIDE_CHARS
5333dfb07bc7Smrg	case fWide:
5334dfb07bc7Smrg	    target = &(lists->list_w);
5335dfb07bc7Smrg	    break;
5336dfb07bc7Smrg	case fWBold:
5337dfb07bc7Smrg	    target = &(lists->list_wb);
5338dfb07bc7Smrg	    break;
5339dfb07bc7Smrg	case fWItal:
5340dfb07bc7Smrg	    target = &(lists->list_wi);
5341dfb07bc7Smrg	    break;
5342d4fba8b9Smrg	case fWBtal:
5343d4fba8b9Smrg	    target = &(lists->list_wbi);
5344d4fba8b9Smrg	    break;
5345dfb07bc7Smrg#endif
5346dfb07bc7Smrg	default:
5347dfb07bc7Smrg	    target = 0;
5348dfb07bc7Smrg	    break;
5349dfb07bc7Smrg	}
5350dfb07bc7Smrg	freeFontList(target);
5351dfb07bc7Smrg    }
5352dfb07bc7Smrg}
5353dfb07bc7Smrg
5354dfb07bc7Smrg/*
5355dfb07bc7Smrg * Return a pointer to the XLFD font information for a given font class.
5356dfb07bc7Smrg * XXX make this allocate the font on demand.
5357dfb07bc7Smrg */
5358dfb07bc7SmrgXTermFonts *
5359dfb07bc7SmrggetNormalFont(TScreen *screen, int which)
5360dfb07bc7Smrg{
5361dfb07bc7Smrg    XTermFonts *result = 0;
5362dfb07bc7Smrg    if (which >= 0 && which < fMAX)
5363d4fba8b9Smrg	result = GetNormalFont(screen, which);
5364dfb07bc7Smrg    return result;
5365dfb07bc7Smrg}
5366dfb07bc7Smrg
5367dfb07bc7Smrg#if OPT_DEC_CHRSET
5368dfb07bc7SmrgXTermFonts *
5369dfb07bc7SmrggetDoubleFont(TScreen *screen, int which)
5370dfb07bc7Smrg{
5371dfb07bc7Smrg    XTermFonts *result = 0;
5372dfb07bc7Smrg    if ((int) which >= 0 && which < NUM_CHRSET)
5373d4fba8b9Smrg	result = GetDoubleFont(screen, which);
5374d4fba8b9Smrg    return result;
5375d4fba8b9Smrg}
5376d4fba8b9Smrg
5377d4fba8b9Smrg#if OPT_RENDERFONT
5378d4fba8b9SmrgXftFont *
5379d4fba8b9SmrggetDoubleXftFont(XTermDraw * params, unsigned chrset, unsigned attr_flags)
5380d4fba8b9Smrg{
5381d4fba8b9Smrg    XftFont *result = 0;
5382d4fba8b9Smrg
5383d4fba8b9Smrg    XtermWidget xw = params->xw;
5384d4fba8b9Smrg    TScreen *screen = TScreenOf(xw);
5385d4fba8b9Smrg    XftPattern *top_pattern;
5386d4fba8b9Smrg    int fontnum = screen->menu_font_number;
5387d4fba8b9Smrg    const char *face_name = getFaceName(xw, False);
5388d4fba8b9Smrg
5389d4fba8b9Smrg    if (chrset != CSET_SWL
5390d4fba8b9Smrg	&& (top_pattern = XftNameParse(face_name)) != 0) {
5391d4fba8b9Smrg	double face_size = (double) xw->misc.face_size[fontnum];
5392d4fba8b9Smrg	XftPattern *sub_pattern = XftPatternDuplicate(top_pattern);
5393d4fba8b9Smrg
5394d4fba8b9Smrg	switch (chrset) {
5395d4fba8b9Smrg	case CSET_DHL_TOP:
5396d4fba8b9Smrg	    /* FALLTHRU */
5397d4fba8b9Smrg	case CSET_DHL_BOT:
5398d4fba8b9Smrg	    face_size *= 2;
5399d4fba8b9Smrg	    XftPatternBuild(sub_pattern,
5400d4fba8b9Smrg			    NormXftPattern,
5401d4fba8b9Smrg			    (void *) 0);
5402d4fba8b9Smrg	    break;
5403d4fba8b9Smrg	case CSET_DWL:
5404d4fba8b9Smrg	    XftPatternBuild(sub_pattern,
5405d4fba8b9Smrg			    NormXftPattern,
5406d4fba8b9Smrg			    FC_ASPECT, XftTypeDouble, 2.0,
5407d4fba8b9Smrg			    (void *) 0);
5408d4fba8b9Smrg	    break;
5409d4fba8b9Smrg	}
5410d4fba8b9Smrg	if (attr_flags & BOLD) {
5411d4fba8b9Smrg	    XftPatternBuild(sub_pattern,
5412d4fba8b9Smrg			    XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD,
5413d4fba8b9Smrg			    (void *) 0);
5414d4fba8b9Smrg	}
5415d4fba8b9Smrg	result = xtermOpenXft(xw, face_name, sub_pattern, "doublesize");
5416d4fba8b9Smrg    }
5417dfb07bc7Smrg    return result;
5418dfb07bc7Smrg}
5419dfb07bc7Smrg#endif
5420d4fba8b9Smrg#endif /* OPT_DEC_CHRSET */
5421dfb07bc7Smrg
5422dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
5423dfb07bc7SmrgXTermFonts *
5424dfb07bc7SmrggetItalicFont(TScreen *screen, int which)
5425dfb07bc7Smrg{
5426dfb07bc7Smrg    XTermFonts *result = 0;
5427dfb07bc7Smrg#if OPT_WIDE_ATTRS
5428dfb07bc7Smrg    if (which >= 0 && which < fMAX)
5429d4fba8b9Smrg	result = GetItalicFont(screen, which);
5430dfb07bc7Smrg#else
5431dfb07bc7Smrg    (void) screen;
5432dfb07bc7Smrg    (void) which;
5433dfb07bc7Smrg#endif
5434dfb07bc7Smrg    return result;
5435dfb07bc7Smrg}
5436dfb07bc7Smrg#endif
5437dfb07bc7Smrg
5438dfb07bc7Smrg#if OPT_RENDERFONT
5439dfb07bc7Smrg/*
5440dfb07bc7Smrg * This returns a pointer to everything known about a given Xft font.
5441dfb07bc7Smrg * XXX make this allocate the font on demand.
5442dfb07bc7Smrg */
5443dfb07bc7SmrgXTermXftFonts *
5444dfb07bc7SmrggetMyXftFont(XtermWidget xw, int which, int fontnum)
5445dfb07bc7Smrg{
5446dfb07bc7Smrg    TScreen *screen = TScreenOf(xw);
5447dfb07bc7Smrg    XTermXftFonts *result = 0;
5448dfb07bc7Smrg    if (fontnum >= 0 && fontnum < NMENUFONTS) {
5449dfb07bc7Smrg	switch ((VTFontEnum) which) {
5450dfb07bc7Smrg	case fNorm:
5451dfb07bc7Smrg	    result = &(screen->renderFontNorm[fontnum]);
5452dfb07bc7Smrg	    break;
5453dfb07bc7Smrg	case fBold:
5454dfb07bc7Smrg	    result = &(screen->renderFontBold[fontnum]);
5455dfb07bc7Smrg	    break;
5456dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
5457dfb07bc7Smrg	case fItal:
5458dfb07bc7Smrg	    result = &(screen->renderFontItal[fontnum]);
5459dfb07bc7Smrg	    break;
5460d4fba8b9Smrg	case fBtal:
5461d4fba8b9Smrg	    result = &(screen->renderFontBtal[fontnum]);
5462d4fba8b9Smrg	    break;
5463dfb07bc7Smrg#endif
5464dfb07bc7Smrg#if OPT_WIDE_CHARS
5465dfb07bc7Smrg	case fWide:
5466dfb07bc7Smrg	    result = &(screen->renderWideNorm[fontnum]);
5467dfb07bc7Smrg	    break;
5468dfb07bc7Smrg	case fWBold:
5469dfb07bc7Smrg	    result = &(screen->renderWideBold[fontnum]);
5470dfb07bc7Smrg	    break;
5471dfb07bc7Smrg	case fWItal:
5472dfb07bc7Smrg	    result = &(screen->renderWideItal[fontnum]);
5473dfb07bc7Smrg	    break;
5474d4fba8b9Smrg	case fWBtal:
5475d4fba8b9Smrg	    result = &(screen->renderWideBtal[fontnum]);
5476d4fba8b9Smrg	    break;
5477dfb07bc7Smrg#endif
5478dfb07bc7Smrg	case fMAX:
5479dfb07bc7Smrg	    break;
5480dfb07bc7Smrg	}
5481dfb07bc7Smrg    }
5482dfb07bc7Smrg    return result;
5483dfb07bc7Smrg}
5484dfb07bc7Smrg
5485dfb07bc7SmrgXftFont *
5486dfb07bc7SmrggetXftFont(XtermWidget xw, VTFontEnum which, int fontnum)
5487dfb07bc7Smrg{
5488d4fba8b9Smrg    XTermXftFonts *data = getMyXftFont(xw, (int) which, fontnum);
5489dfb07bc7Smrg    XftFont *result = 0;
5490dfb07bc7Smrg    if (data != 0)
5491dfb07bc7Smrg	result = data->font;
5492dfb07bc7Smrg    return result;
5493dfb07bc7Smrg}
5494dfb07bc7Smrg#endif
5495dfb07bc7Smrg
5496dfb07bc7Smrgconst char *
5497dfb07bc7SmrgwhichFontEnum(VTFontEnum value)
5498dfb07bc7Smrg{
5499dfb07bc7Smrg    const char *result = "?";
5500dfb07bc7Smrg#define DATA(name) case name: result = #name; break
5501dfb07bc7Smrg    switch (value) {
5502dfb07bc7Smrg	DATA(fNorm);
5503dfb07bc7Smrg	DATA(fBold);
5504dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
5505dfb07bc7Smrg	DATA(fItal);
5506d4fba8b9Smrg	DATA(fBtal);
5507dfb07bc7Smrg#endif
5508dfb07bc7Smrg#if OPT_WIDE_CHARS
5509dfb07bc7Smrg	DATA(fWide);
5510dfb07bc7Smrg	DATA(fWBold);
5511dfb07bc7Smrg	DATA(fWItal);
5512d4fba8b9Smrg	DATA(fWBtal);
5513dfb07bc7Smrg#endif
5514dfb07bc7Smrg	DATA(fMAX);
5515dfb07bc7Smrg    }
5516dfb07bc7Smrg#undef DATA
5517dfb07bc7Smrg    return result;
5518dfb07bc7Smrg}
5519dfb07bc7Smrg
5520dfb07bc7Smrgconst char *
5521dfb07bc7SmrgwhichFontList(XtermWidget xw, VTFontList * value)
5522dfb07bc7Smrg{
5523dfb07bc7Smrg    const char *result = "?";
5524dfb07bc7Smrg    if (value == &(xw->work.fonts.x11))
5525dfb07bc7Smrg	result = "x11_fontnames";
5526dfb07bc7Smrg#if OPT_RENDERFONT
5527dfb07bc7Smrg    else if (value == &(xw->work.fonts.xft))
5528dfb07bc7Smrg	result = "xft_fontnames";
5529dfb07bc7Smrg#endif
5530dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
5531dfb07bc7Smrg    else if (value == &(xw->screen.cacheVTFonts.fonts.x11))
5532dfb07bc7Smrg	result = "cached_fontnames";
5533dfb07bc7Smrg#endif
5534dfb07bc7Smrg    return result;
5535dfb07bc7Smrg}
5536dfb07bc7Smrg
5537dfb07bc7Smrgstatic const char *
5538dfb07bc7SmrgwhichFontList2s(VTFontList * list, char **value)
5539dfb07bc7Smrg{
5540dfb07bc7Smrg    const char *result = 0;
5541dfb07bc7Smrg#define DATA(name) if (value == (list->name)) result = #name
5542dfb07bc7Smrg    DATA(list_n);
5543dfb07bc7Smrg    DATA(list_b);
5544dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE
5545dfb07bc7Smrg    DATA(list_i);
5546d4fba8b9Smrg    DATA(list_bi);
5547dfb07bc7Smrg#endif
5548dfb07bc7Smrg#if OPT_WIDE_CHARS
5549dfb07bc7Smrg    DATA(list_w);
5550dfb07bc7Smrg    DATA(list_wb);
5551dfb07bc7Smrg    DATA(list_wi);
5552d4fba8b9Smrg    DATA(list_wbi);
5553dfb07bc7Smrg#endif
5554dfb07bc7Smrg#undef DATA
5555dfb07bc7Smrg    return result;
5556dfb07bc7Smrg}
5557dfb07bc7Smrg
5558dfb07bc7Smrgconst char *
5559dfb07bc7SmrgwhichFontList2(XtermWidget xw, char **value)
5560dfb07bc7Smrg{
5561dfb07bc7Smrg    const char *result = 0;
5562dfb07bc7Smrg#define DATA(name) (result = whichFontList2s(&(xw->name), value))
5563dfb07bc7Smrg    if (DATA(work.fonts.x11) == 0) {
5564dfb07bc7Smrg#if OPT_RENDERFONT
5565dfb07bc7Smrg	if (DATA(work.fonts.xft) == 0)
5566dfb07bc7Smrg#endif
5567dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
5568dfb07bc7Smrg	    if (DATA(screen.cacheVTFonts.fonts.x11) == 0)
5569dfb07bc7Smrg#endif
5570dfb07bc7Smrg		result = "?";
5571dfb07bc7Smrg    }
5572dfb07bc7Smrg#undef DATA
5573dfb07bc7Smrg    return result;
5574dfb07bc7Smrg}
5575