fontutils.c revision 20d2c4d2
120d2c4d2Smrg/* $XTermId: fontutils.c,v 1.344 2010/06/15 08:18:58 tom Exp $ */
2d522f475Smrg
3d522f475Smrg/************************************************************
4d522f475Smrg
520d2c4d2SmrgCopyright 1998-2009,2010 by Thomas E. Dickey
6d522f475Smrg
7d522f475Smrg                        All Rights Reserved
8d522f475Smrg
9d522f475SmrgPermission is hereby granted, free of charge, to any person obtaining a
10d522f475Smrgcopy of this software and associated documentation files (the
11d522f475Smrg"Software"), to deal in the Software without restriction, including
12d522f475Smrgwithout limitation the rights to use, copy, modify, merge, publish,
13d522f475Smrgdistribute, sublicense, and/or sell copies of the Software, and to
14d522f475Smrgpermit persons to whom the Software is furnished to do so, subject to
15d522f475Smrgthe following conditions:
16d522f475Smrg
17d522f475SmrgThe above copyright notice and this permission notice shall be included
18d522f475Smrgin all copies or substantial portions of the Software.
19d522f475Smrg
20d522f475SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21d522f475SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22d522f475SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23d522f475SmrgIN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
24d522f475SmrgCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25d522f475SmrgTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26d522f475SmrgSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27d522f475Smrg
28d522f475SmrgExcept as contained in this notice, the name(s) of the above copyright
29d522f475Smrgholders shall not be used in advertising or otherwise to promote the
30d522f475Smrgsale, use or other dealings in this Software without prior written
31d522f475Smrgauthorization.
32d522f475Smrg
33d522f475Smrg********************************************************/
34d522f475Smrg
35d522f475Smrg/*
36d522f475Smrg * A portion of this module (for FontNameProperties) was adapted from EMU 1.3;
37d522f475Smrg * it constructs font names with specific properties changed, e.g., for bold
38d522f475Smrg * and double-size characters.
39d522f475Smrg */
40d522f475Smrg
41d522f475Smrg#define RES_OFFSET(field)	XtOffsetOf(SubResourceRec, field)
42d522f475Smrg
43d522f475Smrg#include <fontutils.h>
44d522f475Smrg#include <X11/Xmu/Drawing.h>
4520d2c4d2Smrg#include <X11/Xmu/CharSet.h>
46d522f475Smrg
47d522f475Smrg#include <main.h>
48d522f475Smrg#include <data.h>
49d522f475Smrg#include <menu.h>
50d522f475Smrg#include <xstrings.h>
51d522f475Smrg#include <xterm.h>
52d522f475Smrg
53d522f475Smrg#include <stdio.h>
54d522f475Smrg#include <ctype.h>
55d522f475Smrg
56d522f475Smrg/* from X11/Xlibint.h - not all vendors install this file */
57d522f475Smrg#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
58d522f475Smrg			     (((cs)->rbearing|(cs)->lbearing| \
59d522f475Smrg			       (cs)->ascent|(cs)->descent) == 0))
60d522f475Smrg
61d522f475Smrg#define CI_GET_CHAR_INFO_1D(fs,col,def,cs) \
62d522f475Smrg{ \
63d522f475Smrg    cs = def; \
64d522f475Smrg    if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
65d522f475Smrg	if (fs->per_char == NULL) { \
66d522f475Smrg	    cs = &fs->min_bounds; \
67d522f475Smrg	} else { \
68d522f475Smrg	    cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
69d522f475Smrg	    if (CI_NONEXISTCHAR(cs)) cs = def; \
70d522f475Smrg	} \
71d522f475Smrg    } \
72d522f475Smrg}
73d522f475Smrg
74d522f475Smrg#define CI_GET_CHAR_INFO_2D(fs,row,col,def,cs) \
75d522f475Smrg{ \
76d522f475Smrg    cs = def; \
77d522f475Smrg    if (row >= fs->min_byte1 && row <= fs->max_byte1 && \
78d522f475Smrg	col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
79d522f475Smrg	if (fs->per_char == NULL) { \
80d522f475Smrg	    cs = &fs->min_bounds; \
81d522f475Smrg	} else { \
82d522f475Smrg	    cs = &fs->per_char[((row - fs->min_byte1) * \
83d522f475Smrg				(fs->max_char_or_byte2 - \
84d522f475Smrg				 fs->min_char_or_byte2 + 1)) + \
85d522f475Smrg			       (col - fs->min_char_or_byte2)]; \
86d522f475Smrg	    if (CI_NONEXISTCHAR(cs)) cs = def; \
87d522f475Smrg	} \
88d522f475Smrg    } \
89d522f475Smrg}
90d522f475Smrg
91d522f475Smrg#define MAX_FONTNAME 200
92d522f475Smrg
93d522f475Smrg/*
94d522f475Smrg * A structure to hold the relevant properties from a font
95d522f475Smrg * we need to make a well formed font name for it.
96d522f475Smrg */
97d522f475Smrgtypedef struct {
98d522f475Smrg    /* registry, foundry, family */
99d522f475Smrg    char *beginning;
100d522f475Smrg    /* weight */
101d522f475Smrg    char *weight;
102d522f475Smrg    /* slant */
103d522f475Smrg    char *slant;
104d522f475Smrg    /* wideness */
105d522f475Smrg    char *wideness;
106d522f475Smrg    /* add style */
107d522f475Smrg    char *add_style;
108d522f475Smrg    int pixel_size;
109d522f475Smrg    char *point_size;
110d522f475Smrg    int res_x;
111d522f475Smrg    int res_y;
112d522f475Smrg    char *spacing;
113d522f475Smrg    int average_width;
114d522f475Smrg    /* charset registry, charset encoding */
115d522f475Smrg    char *end;
116d522f475Smrg} FontNameProperties;
117d522f475Smrg
118d522f475Smrg#if OPT_SHIFT_FONTS
119d522f475Smrgstatic void lookupOneFontSize(XtermWidget, int);
120d522f475Smrg#endif
121d522f475Smrg
122d522f475Smrg#if OPT_WIDE_CHARS
1232eaa94a1Schristosstatic unsigned
124d522f475SmrgcountGlyphs(XFontStruct * fp)
125d522f475Smrg{
126d522f475Smrg    unsigned count = 0;
127d522f475Smrg
128d522f475Smrg    if (fp != 0) {
129d522f475Smrg	if (fp->min_byte1 == 0 && fp->max_byte1 == 0) {
130d522f475Smrg	    count = fp->max_char_or_byte2 - fp->min_char_or_byte2;
131d522f475Smrg	} else if (fp->min_char_or_byte2 < 256
132d522f475Smrg		   && fp->max_char_or_byte2 < 256) {
133d522f475Smrg	    unsigned first = (fp->min_byte1 << 8) + fp->min_char_or_byte2;
134d522f475Smrg	    unsigned last = (fp->max_byte1 << 8) + fp->max_char_or_byte2;
135d522f475Smrg	    count = last + 1 - first;
136d522f475Smrg	}
137d522f475Smrg    }
138d522f475Smrg    return count;
139d522f475Smrg}
140d522f475Smrg
141d522f475Smrg/*
142d522f475Smrg * Verify that the wide-bold font is at least a bold font with roughly as many
143d522f475Smrg * glyphs as the wide font.  The counts should be the same, but settle for
144d522f475Smrg * filtering out the worst of the font mismatches.
145d522f475Smrg */
146d522f475Smrgstatic Bool
147d522f475SmrgcompatibleWideCounts(XFontStruct * wfs, XFontStruct * wbfs)
148d522f475Smrg{
149d522f475Smrg    unsigned count_w = countGlyphs(wfs);
150d522f475Smrg    unsigned count_wb = countGlyphs(wbfs);
151d522f475Smrg    if (count_w <= 256 ||
152d522f475Smrg	count_wb <= 256 ||
153d522f475Smrg	((count_w / 4) * 3) > count_wb) {
154d522f475Smrg	TRACE(("...font server lied (count wide %u vs wide-bold %u)\n",
155d522f475Smrg	       count_w, count_wb));
156d522f475Smrg	return False;
157d522f475Smrg    }
158d522f475Smrg    return True;
159d522f475Smrg}
160d522f475Smrg#endif /* OPT_WIDE_CHARS */
161d522f475Smrg
16220d2c4d2Smrg#if OPT_BOX_CHARS
16320d2c4d2Smrgstatic void
16420d2c4d2SmrgsetupPackedFonts(XtermWidget xw)
16520d2c4d2Smrg{
16620d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
16720d2c4d2Smrg    Bool value = False;
16820d2c4d2Smrg
16920d2c4d2Smrg#if OPT_RENDERFONT
17020d2c4d2Smrg#define MIXED(name) screen->name[fontnum].map.mixed
17120d2c4d2Smrg    if (xw->misc.render_font == True) {
17220d2c4d2Smrg	int fontnum = screen->menu_font_number;
17320d2c4d2Smrg
17420d2c4d2Smrg	screen->allow_packing = (Boolean) (MIXED(renderFontNorm)
17520d2c4d2Smrg					   || MIXED(renderFontBold)
17620d2c4d2Smrg					   || MIXED(renderFontItal)
17720d2c4d2Smrg#if OPT_RENDERWIDE
17820d2c4d2Smrg					   || MIXED(renderWideNorm)
17920d2c4d2Smrg					   || MIXED(renderWideBold)
18020d2c4d2Smrg					   || MIXED(renderWideItal)
18120d2c4d2Smrg#endif
18220d2c4d2Smrg	    );
18320d2c4d2Smrg#undef MIXED
18420d2c4d2Smrg    }
18520d2c4d2Smrg#endif /* OPT_RENDERFONT */
18620d2c4d2Smrg
18720d2c4d2Smrg    value = screen->allow_packing;
18820d2c4d2Smrg
18920d2c4d2Smrg    SetItemSensitivity(fontMenuEntries[fontMenu_font_packedfont].widget, value);
19020d2c4d2Smrg}
19120d2c4d2Smrg#endif
19220d2c4d2Smrg
193d522f475Smrg/*
194d522f475Smrg * Returns the fields from start to stop in a dash- separated string.  This
195d522f475Smrg * function will modify the source, putting '\0's in the appropiate place and
196d522f475Smrg * moving the beginning forward to after the '\0'
197d522f475Smrg *
198d522f475Smrg * This will NOT work for the last field (but we won't need it).
199d522f475Smrg */
200d522f475Smrgstatic char *
201d522f475Smrgn_fields(char **source, int start, int stop)
202d522f475Smrg{
203d522f475Smrg    int i;
204d522f475Smrg    char *str, *str1;
205d522f475Smrg
206d522f475Smrg    /*
207d522f475Smrg     * find the start-1th dash
208d522f475Smrg     */
209d522f475Smrg    for (i = start - 1, str = *source; i; i--, str++)
210d522f475Smrg	if ((str = strchr(str, '-')) == 0)
211d522f475Smrg	    return 0;
212d522f475Smrg
213d522f475Smrg    /*
214d522f475Smrg     * find the stopth dash
215d522f475Smrg     */
216d522f475Smrg    for (i = stop - start + 1, str1 = str; i; i--, str1++)
217d522f475Smrg	if ((str1 = strchr(str1, '-')) == 0)
218d522f475Smrg	    return 0;
219d522f475Smrg
220d522f475Smrg    /*
221d522f475Smrg     * put a \0 at the end of the fields
222d522f475Smrg     */
223d522f475Smrg    *(str1 - 1) = '\0';
224d522f475Smrg
225d522f475Smrg    /*
226d522f475Smrg     * move source forward
227d522f475Smrg     */
228d522f475Smrg    *source = str1;
229d522f475Smrg
230d522f475Smrg    return str;
231d522f475Smrg}
232d522f475Smrg
233956cc18dSsnjstatic Boolean
234956cc18dSsnjcheck_fontname(const char *name)
235956cc18dSsnj{
236956cc18dSsnj    Boolean result = True;
237956cc18dSsnj
238956cc18dSsnj    if (name == 0) {
239956cc18dSsnj	TRACE(("fontname missing\n"));
240956cc18dSsnj	result = False;
241956cc18dSsnj    } else if (strlen(name) >= MAX_FONTNAME - 1) {
242956cc18dSsnj	TRACE(("fontname too large: %s\n", name));
243956cc18dSsnj	result = False;
244956cc18dSsnj    }
245956cc18dSsnj    return result;
246956cc18dSsnj}
247956cc18dSsnj
248d522f475Smrg/*
249d522f475Smrg * Gets the font properties from a given font structure.  We use the FONT name
250d522f475Smrg * to find them out, since that seems easier.
251d522f475Smrg *
252d522f475Smrg * Returns a pointer to a static FontNameProperties structure
253d522f475Smrg * or NULL on error.
254d522f475Smrg */
255d522f475Smrgstatic FontNameProperties *
256d522f475Smrgget_font_name_props(Display * dpy, XFontStruct * fs, char *result)
257d522f475Smrg{
258d522f475Smrg    static FontNameProperties props;
259d522f475Smrg    static char *last_name;
260d522f475Smrg
261d522f475Smrg    XFontProp *fp;
262d522f475Smrg    int i;
263d522f475Smrg    Atom fontatom = XInternAtom(dpy, "FONT", False);
26420d2c4d2Smrg    char *name = 0;
265d522f475Smrg    char *str;
266d522f475Smrg
267d522f475Smrg    /*
268d522f475Smrg     * first get the full font name
269d522f475Smrg     */
27020d2c4d2Smrg    if (fontatom != 0) {
27120d2c4d2Smrg	for (i = 0, fp = fs->properties; i < fs->n_properties; i++, fp++) {
27220d2c4d2Smrg	    if (fp->name == fontatom) {
27320d2c4d2Smrg		name = XGetAtomName(dpy, fp->card32);
27420d2c4d2Smrg		break;
27520d2c4d2Smrg	    }
27620d2c4d2Smrg	}
27720d2c4d2Smrg    }
278d522f475Smrg
279d522f475Smrg    if (name == 0)
280d522f475Smrg	return 0;
281d522f475Smrg
282d522f475Smrg    /*
283d522f475Smrg     * XGetAtomName allocates memory - don't leak
284d522f475Smrg     */
285d522f475Smrg    if (last_name != 0)
286d522f475Smrg	XFree(last_name);
287d522f475Smrg    last_name = name;
288d522f475Smrg
289d522f475Smrg    if (result != 0) {
290956cc18dSsnj	if (!check_fontname(name))
291d522f475Smrg	    return 0;
292956cc18dSsnj	strcpy(result, name);
293d522f475Smrg    }
294d522f475Smrg
295d522f475Smrg    /*
296d522f475Smrg     * Now split it up into parts and put them in
297d522f475Smrg     * their places. Since we are using parts of
298d522f475Smrg     * the original string, we must not free the Atom Name
299d522f475Smrg     */
300d522f475Smrg
301d522f475Smrg    /* registry, foundry, family */
302d522f475Smrg    if ((props.beginning = n_fields(&name, 1, 3)) == 0)
303d522f475Smrg	return 0;
304d522f475Smrg
305d522f475Smrg    /* weight is the next */
306d522f475Smrg    if ((props.weight = n_fields(&name, 1, 1)) == 0)
307d522f475Smrg	return 0;
308d522f475Smrg
309d522f475Smrg    /* slant */
310d522f475Smrg    if ((props.slant = n_fields(&name, 1, 1)) == 0)
311d522f475Smrg	return 0;
312d522f475Smrg
313d522f475Smrg    /* width */
314d522f475Smrg    if ((props.wideness = n_fields(&name, 1, 1)) == 0)
315d522f475Smrg	return 0;
316d522f475Smrg
317d522f475Smrg    /* add style */
318d522f475Smrg    if ((props.add_style = n_fields(&name, 1, 1)) == 0)
319d522f475Smrg	return 0;
320d522f475Smrg
321d522f475Smrg    /* pixel size */
322d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
323d522f475Smrg	return 0;
324d522f475Smrg    if ((props.pixel_size = atoi(str)) == 0)
325d522f475Smrg	return 0;
326d522f475Smrg
327d522f475Smrg    /* point size */
328d522f475Smrg    if ((props.point_size = n_fields(&name, 1, 1)) == 0)
329d522f475Smrg	return 0;
330d522f475Smrg
331d522f475Smrg    /* res_x */
332d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
333d522f475Smrg	return 0;
334d522f475Smrg    if ((props.res_x = atoi(str)) == 0)
335d522f475Smrg	return 0;
336d522f475Smrg
337d522f475Smrg    /* res_y */
338d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
339d522f475Smrg	return 0;
340d522f475Smrg    if ((props.res_y = atoi(str)) == 0)
341d522f475Smrg	return 0;
342d522f475Smrg
343d522f475Smrg    /* spacing */
344d522f475Smrg    if ((props.spacing = n_fields(&name, 1, 1)) == 0)
345d522f475Smrg	return 0;
346d522f475Smrg
347d522f475Smrg    /* average width */
348d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
349d522f475Smrg	return 0;
350d522f475Smrg    if ((props.average_width = atoi(str)) == 0)
351d522f475Smrg	return 0;
352d522f475Smrg
353d522f475Smrg    /* the rest: charset registry and charset encoding */
354d522f475Smrg    props.end = name;
355d522f475Smrg
356d522f475Smrg    return &props;
357d522f475Smrg}
358d522f475Smrg
359d522f475Smrg#define ALLOCHUNK(n) ((n | 127) + 1)
360d522f475Smrg
361d522f475Smrgstatic void
362956cc18dSsnjalloca_fontname(char **result, size_t next)
363d522f475Smrg{
364956cc18dSsnj    size_t last = (*result != 0) ? strlen(*result) : 0;
365956cc18dSsnj    size_t have = (*result != 0) ? ALLOCHUNK(last) : 0;
366956cc18dSsnj    size_t want = last + next + 2;
367d522f475Smrg
368d522f475Smrg    if (want >= have) {
369d522f475Smrg	want = ALLOCHUNK(want);
370d522f475Smrg	if (last != 0) {
371d522f475Smrg	    *result = TypeRealloc(char, want, *result);
372d522f475Smrg	} else {
373d522f475Smrg	    if ((*result = TypeMallocN(char, want)) != 0)
374d522f475Smrg		**result = '\0';
375d522f475Smrg	}
376d522f475Smrg    }
377d522f475Smrg}
378d522f475Smrg
379d522f475Smrgstatic void
38020d2c4d2Smrgappend_fontname_str(char **result, const char *value)
381d522f475Smrg{
382d522f475Smrg    if (value == 0)
383d522f475Smrg	value = "*";
384d522f475Smrg    alloca_fontname(result, strlen(value));
385d522f475Smrg    if (*result != 0) {
386d522f475Smrg	if (**result != '\0')
387d522f475Smrg	    strcat(*result, "-");
388d522f475Smrg	strcat(*result, value);
389d522f475Smrg    }
390d522f475Smrg}
391d522f475Smrg
392d522f475Smrgstatic void
393d522f475Smrgappend_fontname_num(char **result, int value)
394d522f475Smrg{
395d522f475Smrg    if (value < 0) {
396d522f475Smrg	append_fontname_str(result, "*");
397d522f475Smrg    } else {
398d522f475Smrg	char temp[100];
399d522f475Smrg	sprintf(temp, "%d", value);
400d522f475Smrg	append_fontname_str(result, temp);
401d522f475Smrg    }
402d522f475Smrg}
403d522f475Smrg
404d522f475Smrg/*
405d522f475Smrg * Take the given font props and try to make a well formed font name specifying
406d522f475Smrg * the same base font and size and everything, but with different weight/width
407d522f475Smrg * according to the parameters.  The return value is allocated, should be freed
408d522f475Smrg * by the caller.
409d522f475Smrg */
410d522f475Smrgstatic char *
411d522f475Smrgderive_font_name(FontNameProperties * props,
41220d2c4d2Smrg		 const char *use_weight,
413d522f475Smrg		 int use_average_width,
41420d2c4d2Smrg		 const char *use_encoding)
415d522f475Smrg{
416d522f475Smrg    char *result = 0;
417d522f475Smrg
418d522f475Smrg    append_fontname_str(&result, props->beginning);
419d522f475Smrg    append_fontname_str(&result, use_weight);
420d522f475Smrg    append_fontname_str(&result, props->slant);
421d522f475Smrg    append_fontname_str(&result, 0);
422d522f475Smrg    append_fontname_str(&result, 0);
423d522f475Smrg    append_fontname_num(&result, props->pixel_size);
424d522f475Smrg    append_fontname_str(&result, props->point_size);
425d522f475Smrg    append_fontname_num(&result, props->res_x);
426d522f475Smrg    append_fontname_num(&result, props->res_y);
427d522f475Smrg    append_fontname_str(&result, props->spacing);
428d522f475Smrg    append_fontname_num(&result, use_average_width);
429d522f475Smrg    append_fontname_str(&result, use_encoding);
430d522f475Smrg
431d522f475Smrg    return result;
432d522f475Smrg}
433d522f475Smrg
434d522f475Smrgstatic char *
435d522f475Smrgbold_font_name(FontNameProperties * props, int use_average_width)
436d522f475Smrg{
437d522f475Smrg    return derive_font_name(props, "bold", use_average_width, props->end);
438d522f475Smrg}
439d522f475Smrg
440d522f475Smrg#if OPT_WIDE_CHARS
441d522f475Smrg#define derive_wide_font(props, weight) \
442d522f475Smrg	derive_font_name(props, weight, props->average_width * 2, "ISO10646-1")
443d522f475Smrg
444d522f475Smrgstatic char *
445d522f475Smrgwide_font_name(FontNameProperties * props)
446d522f475Smrg{
447d522f475Smrg    return derive_wide_font(props, "medium");
448d522f475Smrg}
449d522f475Smrg
450d522f475Smrgstatic char *
451d522f475Smrgwidebold_font_name(FontNameProperties * props)
452d522f475Smrg{
453d522f475Smrg    return derive_wide_font(props, "bold");
454d522f475Smrg}
455d522f475Smrg#endif /* OPT_WIDE_CHARS */
456d522f475Smrg
457d522f475Smrg#if OPT_DEC_CHRSET
458d522f475Smrg/*
459d522f475Smrg * Take the given font props and try to make a well formed font name specifying
460d522f475Smrg * the same base font but changed depending on the given attributes and chrset.
461d522f475Smrg *
462d522f475Smrg * For double width fonts, we just double the X-resolution, for double height
463d522f475Smrg * fonts we double the pixel-size and Y-resolution
464d522f475Smrg */
465d522f475Smrgchar *
466d522f475SmrgxtermSpecialFont(TScreen * screen, unsigned atts, unsigned chrset)
467d522f475Smrg{
468d522f475Smrg#if OPT_TRACE
469d522f475Smrg    static char old_spacing[80];
470d522f475Smrg    static FontNameProperties old_props;
471d522f475Smrg#endif
472d522f475Smrg    FontNameProperties *props;
473d522f475Smrg    char *result = 0;
47420d2c4d2Smrg    const char *weight;
475d522f475Smrg    int pixel_size;
476d522f475Smrg    int res_x;
477d522f475Smrg    int res_y;
478d522f475Smrg
479d522f475Smrg    props = get_font_name_props(screen->display, screen->fnts[fNorm].fs, 0);
480d522f475Smrg    if (props == 0)
481d522f475Smrg	return result;
482d522f475Smrg
483d522f475Smrg    pixel_size = props->pixel_size;
484d522f475Smrg    res_x = props->res_x;
485d522f475Smrg    res_y = props->res_y;
486d522f475Smrg    if (atts & BOLD)
487d522f475Smrg	weight = "bold";
488d522f475Smrg    else
489d522f475Smrg	weight = props->weight;
490d522f475Smrg
491d522f475Smrg    if (CSET_DOUBLE(chrset))
492d522f475Smrg	res_x *= 2;
493d522f475Smrg
494d522f475Smrg    if (chrset == CSET_DHL_TOP
495d522f475Smrg	|| chrset == CSET_DHL_BOT) {
496d522f475Smrg	res_y *= 2;
497d522f475Smrg	pixel_size *= 2;
498d522f475Smrg    }
499d522f475Smrg#if OPT_TRACE
500d522f475Smrg    if (old_props.res_x != res_x
501d522f475Smrg	|| old_props.res_x != res_y
502d522f475Smrg	|| old_props.pixel_size != pixel_size
503d522f475Smrg	|| strcmp(old_props.spacing, props->spacing)) {
504d522f475Smrg	TRACE(("xtermSpecialFont(atts = %#x, chrset = %#x)\n", atts, chrset));
505d522f475Smrg	TRACE(("res_x      = %d\n", res_x));
506d522f475Smrg	TRACE(("res_y      = %d\n", res_y));
507d522f475Smrg	TRACE(("point_size = %s\n", props->point_size));
508d522f475Smrg	TRACE(("pixel_size = %d\n", pixel_size));
509d522f475Smrg	TRACE(("spacing    = %s\n", props->spacing));
510d522f475Smrg	old_props.res_x = res_x;
511d522f475Smrg	old_props.res_x = res_y;
512d522f475Smrg	old_props.pixel_size = pixel_size;
513d522f475Smrg	old_props.spacing = strcpy(old_spacing, props->spacing);
514d522f475Smrg    }
515d522f475Smrg#endif
516d522f475Smrg
517d522f475Smrg    append_fontname_str(&result, props->beginning);
518d522f475Smrg    append_fontname_str(&result, weight);
519d522f475Smrg    append_fontname_str(&result, props->slant);
520d522f475Smrg    append_fontname_str(&result, props->wideness);
521d522f475Smrg    append_fontname_str(&result, props->add_style);
522d522f475Smrg    append_fontname_num(&result, pixel_size);
523d522f475Smrg    append_fontname_str(&result, props->point_size);
524d522f475Smrg    append_fontname_num(&result, (atts & NORESOLUTION) ? -1 : res_x);
525d522f475Smrg    append_fontname_num(&result, (atts & NORESOLUTION) ? -1 : res_y);
526d522f475Smrg    append_fontname_str(&result, props->spacing);
527d522f475Smrg    append_fontname_str(&result, 0);
528d522f475Smrg    append_fontname_str(&result, props->end);
529d522f475Smrg
530d522f475Smrg    return result;
531d522f475Smrg}
532d522f475Smrg#endif /* OPT_DEC_CHRSET */
533d522f475Smrg
534d522f475Smrg/*
535d522f475Smrg * Case-independent comparison for font-names, including wildcards.
536d522f475Smrg * XLFD allows '?' as a wildcard, but we do not handle that (no one seems
537d522f475Smrg * to use it).
538d522f475Smrg */
539d522f475Smrgstatic Bool
540d522f475Smrgsame_font_name(char *pattern, char *match)
541d522f475Smrg{
542956cc18dSsnj    Bool result = False;
543956cc18dSsnj
544956cc18dSsnj    if (pattern && match) {
545956cc18dSsnj	while (*pattern && *match) {
546956cc18dSsnj	    if (*pattern == *match) {
547956cc18dSsnj		pattern++;
548956cc18dSsnj		match++;
549956cc18dSsnj	    } else if (*pattern == '*' || *match == '*') {
550956cc18dSsnj		if (same_font_name(pattern + 1, match)) {
551956cc18dSsnj		    return True;
552956cc18dSsnj		} else if (same_font_name(pattern, match + 1)) {
553956cc18dSsnj		    return True;
554956cc18dSsnj		} else {
555956cc18dSsnj		    return False;
556956cc18dSsnj		}
557d522f475Smrg	    } else {
558956cc18dSsnj		int p = x_toupper(*pattern++);
559956cc18dSsnj		int m = x_toupper(*match++);
560956cc18dSsnj		if (p != m)
561956cc18dSsnj		    return False;
562d522f475Smrg	    }
563d522f475Smrg	}
564956cc18dSsnj	result = (*pattern == *match);	/* both should be NUL */
565d522f475Smrg    }
566956cc18dSsnj    return result;
567d522f475Smrg}
568d522f475Smrg
569d522f475Smrg/*
570d522f475Smrg * Double-check the fontname that we asked for versus what the font server
571d522f475Smrg * actually gave us.  The larger fixed fonts do not always have a matching bold
572d522f475Smrg * font, and the font server may try to scale another font or otherwise
573d522f475Smrg * substitute a mismatched font.
574d522f475Smrg *
575d522f475Smrg * If we cannot get what we requested, we will fallback to the original
576d522f475Smrg * behavior, which simulates bold by overstriking each character at one pixel
577d522f475Smrg * offset.
578d522f475Smrg */
579d522f475Smrgstatic int
580d522f475Smrggot_bold_font(Display * dpy, XFontStruct * fs, char *requested)
581d522f475Smrg{
582d522f475Smrg    char actual[MAX_FONTNAME];
583d522f475Smrg    int got;
584d522f475Smrg
585d522f475Smrg    if (get_font_name_props(dpy, fs, actual) == 0)
586d522f475Smrg	got = 0;
587d522f475Smrg    else
588d522f475Smrg	got = same_font_name(requested, actual);
589d522f475Smrg    return got;
590d522f475Smrg}
591d522f475Smrg
592d522f475Smrg/*
593d522f475Smrg * If the font server tries to adjust another font, it may not adjust it
594d522f475Smrg * properly.  Check that the bounding boxes are compatible.  Otherwise we'll
595d522f475Smrg * leave trash on the display when we mix normal and bold fonts.
596d522f475Smrg */
597d522f475Smrgstatic int
598d522f475Smrgsame_font_size(XtermWidget xw, XFontStruct * nfs, XFontStruct * bfs)
599d522f475Smrg{
600956cc18dSsnj    TScreen *screen = TScreenOf(xw);
601d522f475Smrg    TRACE(("same_font_size height %d/%d, min %d/%d max %d/%d\n",
602d522f475Smrg	   nfs->ascent + nfs->descent,
603d522f475Smrg	   bfs->ascent + bfs->descent,
604d522f475Smrg	   nfs->min_bounds.width, bfs->min_bounds.width,
605d522f475Smrg	   nfs->max_bounds.width, bfs->max_bounds.width));
606956cc18dSsnj    return screen->free_bold_box
607d522f475Smrg	|| ((nfs->ascent + nfs->descent) == (bfs->ascent + bfs->descent)
608d522f475Smrg	    && (nfs->min_bounds.width == bfs->min_bounds.width
609d522f475Smrg		|| nfs->min_bounds.width == bfs->min_bounds.width + 1)
610d522f475Smrg	    && (nfs->max_bounds.width == bfs->max_bounds.width
611d522f475Smrg		|| nfs->max_bounds.width == bfs->max_bounds.width + 1));
612d522f475Smrg}
613d522f475Smrg
614d522f475Smrg/*
615d522f475Smrg * Check if the font looks like it has fixed width
616d522f475Smrg */
617d522f475Smrgstatic int
618d522f475Smrgis_fixed_font(XFontStruct * fs)
619d522f475Smrg{
620d522f475Smrg    if (fs)
621d522f475Smrg	return (fs->min_bounds.width == fs->max_bounds.width);
622d522f475Smrg    return 1;
623d522f475Smrg}
624d522f475Smrg
625d522f475Smrg/*
626d522f475Smrg * Check if the font looks like a double width font (i.e. contains
627d522f475Smrg * characters of width X and 2X
628d522f475Smrg */
629d522f475Smrg#if OPT_WIDE_CHARS
630d522f475Smrgstatic int
631d522f475Smrgis_double_width_font(XFontStruct * fs)
632d522f475Smrg{
633d522f475Smrg    return ((2 * fs->min_bounds.width) == fs->max_bounds.width);
634d522f475Smrg}
635d522f475Smrg#else
636d522f475Smrg#define is_double_width_font(fs) 0
637d522f475Smrg#endif
638d522f475Smrg
639d522f475Smrg#if OPT_WIDE_CHARS && OPT_RENDERFONT && defined(HAVE_TYPE_FCCHAR32)
640d522f475Smrg#define HALF_WIDTH_TEST_STRING "1234567890"
641d522f475Smrg
642d522f475Smrg/* '1234567890' in Chinese characters in UTF-8 */
643d522f475Smrg#define FULL_WIDTH_TEST_STRING "\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89" \
644d522f475Smrg                               "\xe5\x9b\x9b\xe4\xba\x94" \
645d522f475Smrg			       "\xef\xa7\x91\xe4\xb8\x83\xe5\x85\xab" \
646d522f475Smrg			       "\xe4\xb9\x9d\xef\xa6\xb2"
647d522f475Smrg
648d522f475Smrg/* '1234567890' in Korean script in UTF-8 */
649d522f475Smrg#define FULL_WIDTH_TEST_STRING2 "\xec\x9d\xbc\xec\x9d\xb4\xec\x82\xbc" \
650d522f475Smrg                                "\xec\x82\xac\xec\x98\xa4" \
651d522f475Smrg			        "\xec\x9c\xa1\xec\xb9\xa0\xed\x8c\x94" \
652d522f475Smrg			        "\xea\xb5\xac\xec\x98\x81"
653d522f475Smrg
654d522f475Smrg#define HALF_WIDTH_CHAR1  0x0031	/* '1' */
655d522f475Smrg#define HALF_WIDTH_CHAR2  0x0057	/* 'W' */
656d522f475Smrg#define FULL_WIDTH_CHAR1  0x4E00	/* CJK Ideograph 'number one' */
657d522f475Smrg#define FULL_WIDTH_CHAR2  0xAC00	/* Korean script syllable 'Ka' */
658d522f475Smrg
659d522f475Smrgstatic Bool
660d522f475Smrgis_double_width_font_xft(Display * dpy, XftFont * font)
661d522f475Smrg{
662d522f475Smrg    XGlyphInfo gi1, gi2;
663d522f475Smrg    FcChar32 c1 = HALF_WIDTH_CHAR1, c2 = HALF_WIDTH_CHAR2;
664d522f475Smrg    char *fwstr = FULL_WIDTH_TEST_STRING;
665d522f475Smrg    char *hwstr = HALF_WIDTH_TEST_STRING;
666d522f475Smrg
667d522f475Smrg    /* Some Korean fonts don't have Chinese characters at all. */
668d522f475Smrg    if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR1)) {
669d522f475Smrg	if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR2))
670d522f475Smrg	    return False;	/* Not a CJK font */
671d522f475Smrg	else			/* a Korean font without CJK Ideographs */
672d522f475Smrg	    fwstr = FULL_WIDTH_TEST_STRING2;
673d522f475Smrg    }
674d522f475Smrg
675d522f475Smrg    XftTextExtents32(dpy, font, &c1, 1, &gi1);
676d522f475Smrg    XftTextExtents32(dpy, font, &c2, 1, &gi2);
677d522f475Smrg    if (gi1.xOff != gi2.xOff)	/* Not a fixed-width font */
678d522f475Smrg	return False;
679d522f475Smrg
680d522f475Smrg    XftTextExtentsUtf8(dpy, font, (FcChar8 *) hwstr, (int) strlen(hwstr), &gi1);
681d522f475Smrg    XftTextExtentsUtf8(dpy, font, (FcChar8 *) fwstr, (int) strlen(fwstr), &gi2);
682d522f475Smrg
683d522f475Smrg    /*
684d522f475Smrg     * fontconfig and Xft prior to 2.2(?) set the width of half-width
685d522f475Smrg     * characters identical to that of full-width character in CJK double-width
686d522f475Smrg     * (bi-width / monospace) font even though the former is half as wide as
687d522f475Smrg     * the latter.  This was fixed sometime before the release of fontconfig
688d522f475Smrg     * 2.2 in early 2003.  See
689d522f475Smrg     *  http://bugzilla.mozilla.org/show_bug.cgi?id=196312
690d522f475Smrg     * In the meantime, we have to check both possibilities.
691d522f475Smrg     */
692d522f475Smrg    return ((2 * gi1.xOff == gi2.xOff) || (gi1.xOff == gi2.xOff));
693d522f475Smrg}
694d522f475Smrg#else
695d522f475Smrg#define is_double_width_font_xft(dpy, xftfont) 0
696d522f475Smrg#endif
697d522f475Smrg
698d522f475Smrg#define EmptyFont(fs) (fs != 0 \
699d522f475Smrg		   && ((fs)->ascent + (fs)->descent == 0 \
700d522f475Smrg		    || (fs)->max_bounds.width == 0))
701d522f475Smrg
702d522f475Smrg#define FontSize(fs) (((fs)->ascent + (fs)->descent) \
703d522f475Smrg		    *  (fs)->max_bounds.width)
704d522f475Smrg
705d522f475Smrgconst VTFontNames *
70620d2c4d2SmrgxtermFontName(const char *normal)
707d522f475Smrg{
708d522f475Smrg    static VTFontNames data;
70920d2c4d2Smrg    if (data.f_n)
71020d2c4d2Smrg	free(data.f_n);
711d522f475Smrg    memset(&data, 0, sizeof(data));
71220d2c4d2Smrg    data.f_n = x_strdup(normal);
713d522f475Smrg    return &data;
714d522f475Smrg}
715d522f475Smrg
716d522f475Smrgstatic void
717d522f475Smrgcache_menu_font_name(TScreen * screen, int fontnum, int which, const char *name)
718d522f475Smrg{
719d522f475Smrg    if (name != 0) {
720d522f475Smrg	char *last = screen->menu_font_names[fontnum][which];
721d522f475Smrg	if (last != 0) {
722d522f475Smrg	    if (strcmp(last, name)) {
723d522f475Smrg		free(last);
724d522f475Smrg		TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name));
725d522f475Smrg		screen->menu_font_names[fontnum][which] = x_strdup(name);
726d522f475Smrg	    }
727d522f475Smrg	} else {
728d522f475Smrg	    TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name));
729d522f475Smrg	    screen->menu_font_names[fontnum][which] = x_strdup(name);
730d522f475Smrg	}
731d522f475Smrg    }
732d522f475Smrg}
733d522f475Smrg
734d522f475Smrg/*
735d522f475Smrg * Open the given font and verify that it is non-empty.  Return a null on
736d522f475Smrg * failure.
737d522f475Smrg */
738d522f475SmrgBool
739956cc18dSsnjxtermOpenFont(XtermWidget xw,
740956cc18dSsnj	      const char *name,
741956cc18dSsnj	      XTermFonts * result,
742956cc18dSsnj	      fontWarningTypes warn,
743956cc18dSsnj	      Bool force)
744d522f475Smrg{
745d522f475Smrg    Bool code = False;
746d522f475Smrg    TScreen *screen = TScreenOf(xw);
747d522f475Smrg
748956cc18dSsnj    if (name != 0) {
749956cc18dSsnj	if ((result->fs = XLoadQueryFont(screen->display, name)) != 0) {
750956cc18dSsnj	    code = True;
751956cc18dSsnj	    if (EmptyFont(result->fs)) {
75220d2c4d2Smrg		(void) xtermCloseFont(xw, result);
753956cc18dSsnj		code = False;
754956cc18dSsnj	    } else {
755956cc18dSsnj		result->fn = x_strdup(name);
756956cc18dSsnj	    }
75720d2c4d2Smrg	} else if (XmuCompareISOLatin1(name, DEFFONT) != 0) {
758956cc18dSsnj	    if (warn <= xw->misc.fontWarnings
759956cc18dSsnj#if OPT_RENDERFONT
760956cc18dSsnj		&& !UsingRenderFont(xw)
761956cc18dSsnj#endif
762956cc18dSsnj		) {
763956cc18dSsnj		TRACE(("OOPS: cannot load font %s\n", name));
764956cc18dSsnj		fprintf(stderr, "%s: cannot load font %s\n", ProgramName, name);
76520d2c4d2Smrg#if OPT_RENDERFONT
76620d2c4d2Smrg		/*
76720d2c4d2Smrg		 * Do a sanity check in case someone's mixed up xterm with
76820d2c4d2Smrg		 * one of those programs that read their resource data from
76920d2c4d2Smrg		 * xterm's namespace.
77020d2c4d2Smrg		 */
77120d2c4d2Smrg		if (strchr(name, ':') != 0 || strchr(name, '=') != 0) {
77220d2c4d2Smrg		    fprintf(stderr,
77320d2c4d2Smrg			    "Use the \"-fa\" option for the Xft fonts\n");
77420d2c4d2Smrg		}
77520d2c4d2Smrg#endif
776956cc18dSsnj	    } else {
777956cc18dSsnj		TRACE(("xtermOpenFont: cannot load font %s\n", name));
778956cc18dSsnj	    }
779956cc18dSsnj	    if (force) {
780956cc18dSsnj		code = xtermOpenFont(xw, DEFFONT, result, fwAlways, True);
781956cc18dSsnj	    }
782d522f475Smrg	}
783d522f475Smrg    }
784d522f475Smrg    return code;
785d522f475Smrg}
786d522f475Smrg
787d522f475Smrg/*
788956cc18dSsnj * Close the font and free the font info.
789d522f475Smrg */
790d522f475SmrgXTermFonts *
791d522f475SmrgxtermCloseFont(XtermWidget xw, XTermFonts * fnt)
792d522f475Smrg{
793d522f475Smrg    if (fnt != 0 && fnt->fs != 0) {
794d522f475Smrg	TScreen *screen = TScreenOf(xw);
795d522f475Smrg
796d522f475Smrg	clrCgsFonts(xw, WhichVWin(screen), fnt);
797d522f475Smrg	XFreeFont(screen->display, fnt->fs);
798d522f475Smrg	xtermFreeFontInfo(fnt);
799d522f475Smrg    }
800d522f475Smrg    return 0;
801d522f475Smrg}
802d522f475Smrg
803d522f475Smrg/*
804d522f475Smrg * Close the listed fonts, noting that some may use copies of the pointer.
805d522f475Smrg */
806d522f475Smrgvoid
807d522f475SmrgxtermCloseFonts(XtermWidget xw, XTermFonts * fnts)
808d522f475Smrg{
809d522f475Smrg    int j, k;
810d522f475Smrg
811d522f475Smrg    for (j = 0; j < fMAX; ++j) {
812d522f475Smrg	/*
813d522f475Smrg	 * Need to save the pointer since xtermCloseFont zeroes it
814d522f475Smrg	 */
815d522f475Smrg	XFontStruct *thisFont = fnts[j].fs;
816d522f475Smrg	if (thisFont != 0) {
817d522f475Smrg	    xtermCloseFont(xw, &fnts[j]);
818d522f475Smrg	    for (k = j + 1; k < fMAX; ++k) {
819d522f475Smrg		if (thisFont == fnts[k].fs)
820d522f475Smrg		    xtermFreeFontInfo(&fnts[k]);
821d522f475Smrg	    }
822d522f475Smrg	}
823d522f475Smrg    }
824d522f475Smrg}
825d522f475Smrg
826d522f475Smrg/*
827d522f475Smrg * Make a copy of the source, assuming the XFontStruct's to be unique, but
828d522f475Smrg * ensuring that the names are reallocated to simplify freeing.
829d522f475Smrg */
830d522f475Smrgvoid
831d522f475SmrgxtermCopyFontInfo(XTermFonts * target, XTermFonts * source)
832d522f475Smrg{
833d522f475Smrg    xtermFreeFontInfo(target);
834d522f475Smrg    target->chrset = source->chrset;
835d522f475Smrg    target->flags = source->flags;
836d522f475Smrg    target->fn = x_strdup(source->fn);
837d522f475Smrg    target->fs = source->fs;
838d522f475Smrg}
839d522f475Smrg
840d522f475Smrgvoid
841d522f475SmrgxtermFreeFontInfo(XTermFonts * target)
842d522f475Smrg{
843d522f475Smrg    target->chrset = 0;
844d522f475Smrg    target->flags = 0;
845d522f475Smrg    if (target->fn != 0) {
846d522f475Smrg	free(target->fn);
847d522f475Smrg	target->fn = 0;
848d522f475Smrg    }
849d522f475Smrg    target->fs = 0;
850d522f475Smrg}
851d522f475Smrg
852d522f475Smrgint
853d522f475SmrgxtermLoadFont(XtermWidget xw,
854d522f475Smrg	      const VTFontNames * fonts,
855d522f475Smrg	      Bool doresize,
856d522f475Smrg	      int fontnum)
857d522f475Smrg{
858956cc18dSsnj    TScreen *screen = TScreenOf(xw);
859d522f475Smrg    VTwin *win = WhichVWin(screen);
860d522f475Smrg
861d522f475Smrg    VTFontNames myfonts;
862d522f475Smrg    FontNameProperties *fp;
863d522f475Smrg    XTermFonts fnts[fMAX];
864d522f475Smrg    Pixel new_normal;
865d522f475Smrg    Pixel new_revers;
866d522f475Smrg    char *tmpname = NULL;
867d522f475Smrg    char normal[MAX_FONTNAME];
868956cc18dSsnj    Boolean proportional = False;
869956cc18dSsnj    fontWarningTypes warn[fMAX];
870956cc18dSsnj    int j;
871d522f475Smrg
872d522f475Smrg    memset(&myfonts, 0, sizeof(myfonts));
873d522f475Smrg    memset(fnts, 0, sizeof(fnts));
874d522f475Smrg
875d522f475Smrg    if (fonts != 0)
876d522f475Smrg	myfonts = *fonts;
877956cc18dSsnj    if (!check_fontname(myfonts.f_n))
878d522f475Smrg	return 0;
879d522f475Smrg
880956cc18dSsnj    /*
881956cc18dSsnj     * Check the font names against the resource values, to see which were
882956cc18dSsnj     * derived in a previous call.  If so, we'll only warn about those if
883956cc18dSsnj     * the warning level is set to "always".
884956cc18dSsnj     */
885956cc18dSsnj    for (j = 0; j < fMAX; ++j) {
886956cc18dSsnj	warn[j] = fwAlways;
887956cc18dSsnj    }
888956cc18dSsnj#define CmpResource(field, index) \
889956cc18dSsnj    if (same_font_name(screen->menu_font_names[fontnum][index], myfonts.field)) \
890956cc18dSsnj	warn[index] = fwResource
891956cc18dSsnj
892956cc18dSsnj    CmpResource(f_n, fNorm);
893956cc18dSsnj    if (fontnum == fontMenu_default) {
894956cc18dSsnj	CmpResource(f_b, fBold);
895956cc18dSsnj#if OPT_WIDE_CHARS
896956cc18dSsnj	CmpResource(f_b, fWide);
897956cc18dSsnj	CmpResource(f_b, fWBold);
898956cc18dSsnj#endif
899956cc18dSsnj    }
900956cc18dSsnj
901d522f475Smrg    if (fontnum == fontMenu_fontescape
902d522f475Smrg	&& myfonts.f_n != screen->MenuFontName(fontnum)) {
903d522f475Smrg	if ((tmpname = x_strdup(myfonts.f_n)) == 0)
904d522f475Smrg	    return 0;
905d522f475Smrg    }
906d522f475Smrg
907d522f475Smrg    TRACE(("Begin Cgs - xtermLoadFont(%s)\n", myfonts.f_n));
908d522f475Smrg    releaseWindowGCs(xw, win);
909d522f475Smrg
910956cc18dSsnj#define DbgResource(name, field, index) \
911956cc18dSsnj    TRACE(("xtermLoadFont #%d "name" %s%s\n", \
912956cc18dSsnj    	   fontnum, \
913956cc18dSsnj	   (warn[index] == fwResource) ? "*" : " ", \
914956cc18dSsnj	   NonNull(myfonts.field)));
915956cc18dSsnj    DbgResource("normal", f_n, fNorm);
916956cc18dSsnj    DbgResource("bold  ", f_b, fBold);
917d522f475Smrg#if OPT_WIDE_CHARS
918956cc18dSsnj    DbgResource("wide  ", f_w, fWide);
919956cc18dSsnj    DbgResource("w/bold", f_wb, fWBold);
920d522f475Smrg#endif
921d522f475Smrg
922956cc18dSsnj    if (!xtermOpenFont(xw, myfonts.f_n, &fnts[fNorm], warn[fNorm], True))
923d522f475Smrg	goto bad;
924d522f475Smrg
925d522f475Smrg    strcpy(normal, myfonts.f_n);
926956cc18dSsnj    if (!check_fontname(myfonts.f_b)) {
927956cc18dSsnj	warn[fBold] = fwAlways;
928d522f475Smrg	fp = get_font_name_props(screen->display, fnts[fNorm].fs, normal);
929d522f475Smrg	if (fp != 0) {
930d522f475Smrg	    myfonts.f_b = bold_font_name(fp, fp->average_width);
931956cc18dSsnj	    if (!xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], fwAlways, False)) {
932d522f475Smrg		myfonts.f_b = bold_font_name(fp, -1);
933956cc18dSsnj		xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], fwAlways, False);
934d522f475Smrg	    }
935d522f475Smrg	    TRACE(("...derived bold %s\n", NonNull(myfonts.f_b)));
936d522f475Smrg	}
937d522f475Smrg	if (fp == 0 || fnts[fBold].fs == 0) {
938d522f475Smrg	    xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]);
939d522f475Smrg	    TRACE(("...cannot load a matching bold font\n"));
940d522f475Smrg	} else if (same_font_size(xw, fnts[fNorm].fs, fnts[fBold].fs)
941d522f475Smrg		   && got_bold_font(screen->display, fnts[fBold].fs, myfonts.f_b)) {
942d522f475Smrg	    TRACE(("...got a matching bold font\n"));
943d522f475Smrg	    cache_menu_font_name(screen, fontnum, fBold, myfonts.f_b);
944d522f475Smrg	} else {
945d522f475Smrg	    xtermCloseFont(xw, &fnts[fBold]);
946d522f475Smrg	    fnts[fBold] = fnts[fNorm];
947d522f475Smrg	    TRACE(("...did not get a matching bold font\n"));
948d522f475Smrg	}
949956cc18dSsnj    } else if (!xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], warn[fBold], False)) {
950d522f475Smrg	xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]);
951956cc18dSsnj	warn[fBold] = fwAlways;
952d522f475Smrg	TRACE(("...cannot load bold font %s\n", NonNull(myfonts.f_b)));
953d522f475Smrg    } else {
954d522f475Smrg	cache_menu_font_name(screen, fontnum, fBold, myfonts.f_b);
955d522f475Smrg    }
956d522f475Smrg
957d522f475Smrg    /*
958d522f475Smrg     * If there is no widefont specified, fake it by doubling AVERAGE_WIDTH
959d522f475Smrg     * of normal fonts XLFD, and asking for it.  This plucks out 18x18ja
960d522f475Smrg     * and 12x13ja as the corresponding fonts for 9x18 and 6x13.
961d522f475Smrg     */
962d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
963d522f475Smrg	Bool derived;
964d522f475Smrg	char bold[MAX_FONTNAME];
965d522f475Smrg
966956cc18dSsnj	if (check_fontname(myfonts.f_w)) {
967d522f475Smrg	    cache_menu_font_name(screen, fontnum, fWide, myfonts.f_w);
968d522f475Smrg	} else if (!is_double_width_font(fnts[fNorm].fs)) {
969d522f475Smrg	    fp = get_font_name_props(screen->display, fnts[fNorm].fs, normal);
970d522f475Smrg	    if (fp != 0) {
971d522f475Smrg		myfonts.f_w = wide_font_name(fp);
972956cc18dSsnj		warn[fWide] = fwAlways;
973d522f475Smrg		TRACE(("...derived wide %s\n", NonNull(myfonts.f_w)));
974d522f475Smrg		cache_menu_font_name(screen, fontnum, fWide, myfonts.f_w);
975d522f475Smrg	    }
976d522f475Smrg	}
977d522f475Smrg
978956cc18dSsnj	if (check_fontname(myfonts.f_w)) {
979956cc18dSsnj	    (void) xtermOpenFont(xw, myfonts.f_w, &fnts[fWide], warn[fWide], False);
980d522f475Smrg	} else {
981d522f475Smrg	    xtermCopyFontInfo(&fnts[fWide], &fnts[fNorm]);
982956cc18dSsnj	    warn[fWide] = fwAlways;
983d522f475Smrg	}
984d522f475Smrg
985d522f475Smrg	derived = False;
986956cc18dSsnj	if (!check_fontname(myfonts.f_wb)) {
987d522f475Smrg	    fp = get_font_name_props(screen->display, fnts[fBold].fs, bold);
988d522f475Smrg	    if (fp != 0) {
989d522f475Smrg		myfonts.f_wb = widebold_font_name(fp);
990956cc18dSsnj		warn[fWBold] = fwAlways;
991d522f475Smrg		derived = True;
992d522f475Smrg	    }
993d522f475Smrg	}
994d522f475Smrg
995956cc18dSsnj	if (check_fontname(myfonts.f_wb)) {
996d522f475Smrg
997956cc18dSsnj	    xtermOpenFont(xw, myfonts.f_wb, &fnts[fWBold], warn[fWBold], False);
998d522f475Smrg
999d522f475Smrg	    if (derived
1000d522f475Smrg		&& !compatibleWideCounts(fnts[fWide].fs, fnts[fWBold].fs)) {
1001d522f475Smrg		xtermCloseFont(xw, &fnts[fWBold]);
1002d522f475Smrg	    }
1003d522f475Smrg	    if (fnts[fWBold].fs == 0) {
1004d522f475Smrg		myfonts.f_wb = myfonts.f_w;
1005956cc18dSsnj		warn[fWBold] = fwAlways;
1006d522f475Smrg		xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
1007d522f475Smrg		TRACE(("...cannot load wide-bold, use wide %s\n", NonNull(myfonts.f_w)));
1008d522f475Smrg	    } else {
1009d522f475Smrg		TRACE(("...%s wide/bold %s\n",
1010d522f475Smrg		       derived ? "derived" : "given",
1011d522f475Smrg		       NonNull(myfonts.f_wb)));
1012d522f475Smrg		cache_menu_font_name(screen, fontnum, fWBold, myfonts.f_wb);
1013d522f475Smrg	    }
1014d522f475Smrg	} else if (is_double_width_font(fnts[fBold].fs)) {
1015d522f475Smrg	    xtermCopyFontInfo(&fnts[fWBold], &fnts[fBold]);
1016956cc18dSsnj	    warn[fWBold] = fwAlways;
1017d522f475Smrg	    TRACE(("...bold font is double-width, use it %s\n", NonNull(myfonts.f_b)));
1018d522f475Smrg	} else {
1019d522f475Smrg	    xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
1020956cc18dSsnj	    warn[fWBold] = fwAlways;
1021d522f475Smrg	    TRACE(("...cannot load wide bold font, use wide %s\n", NonNull(myfonts.f_w)));
1022d522f475Smrg	}
1023d522f475Smrg
1024d522f475Smrg	if (EmptyFont(fnts[fWBold].fs))
1025d522f475Smrg	    goto bad;		/* can't use a 0-sized font */
1026d522f475Smrg    });
1027d522f475Smrg
1028d522f475Smrg    /*
1029d522f475Smrg     * Most of the time this call to load the font will succeed, even if
1030d522f475Smrg     * there is no wide font :  the X server doubles the width of the
1031d522f475Smrg     * normal font, or similar.
1032d522f475Smrg     *
1033d522f475Smrg     * But if it did fail for some reason, then nevermind.
1034d522f475Smrg     */
1035d522f475Smrg    if (EmptyFont(fnts[fBold].fs))
1036d522f475Smrg	goto bad;		/* can't use a 0-sized font */
1037d522f475Smrg
1038d522f475Smrg    if (!same_font_size(xw, fnts[fNorm].fs, fnts[fBold].fs)
1039d522f475Smrg	&& (is_fixed_font(fnts[fNorm].fs) && is_fixed_font(fnts[fBold].fs))) {
1040d522f475Smrg	TRACE(("...ignoring mismatched normal/bold fonts\n"));
1041d522f475Smrg	xtermCloseFont(xw, &fnts[fBold]);
1042d522f475Smrg	xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]);
1043d522f475Smrg    }
1044d522f475Smrg
1045d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
1046d522f475Smrg	if (fnts[fWide].fs != 0
1047d522f475Smrg	    && fnts[fWBold].fs != 0
1048d522f475Smrg	    && !same_font_size(xw, fnts[fWide].fs, fnts[fWBold].fs)
1049d522f475Smrg	    && (is_fixed_font(fnts[fWide].fs) && is_fixed_font(fnts[fWBold].fs))) {
1050d522f475Smrg	    TRACE(("...ignoring mismatched normal/bold wide fonts\n"));
1051d522f475Smrg	    xtermCloseFont(xw, &fnts[fWBold]);
1052d522f475Smrg	    xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
1053d522f475Smrg	}
1054d522f475Smrg    });
1055d522f475Smrg
1056d522f475Smrg    /*
1057d522f475Smrg     * Normal/bold fonts should be the same width.  Also, the min/max
1058d522f475Smrg     * values should be the same.
1059d522f475Smrg     */
1060d522f475Smrg    if (!is_fixed_font(fnts[fNorm].fs)
1061d522f475Smrg	|| !is_fixed_font(fnts[fBold].fs)
1062d522f475Smrg	|| fnts[fNorm].fs->max_bounds.width != fnts[fBold].fs->max_bounds.width) {
1063d522f475Smrg	TRACE(("Proportional font! normal %d/%d, bold %d/%d\n",
1064d522f475Smrg	       fnts[fNorm].fs->min_bounds.width,
1065d522f475Smrg	       fnts[fNorm].fs->max_bounds.width,
1066d522f475Smrg	       fnts[fBold].fs->min_bounds.width,
1067d522f475Smrg	       fnts[fBold].fs->max_bounds.width));
1068d522f475Smrg	proportional = True;
1069d522f475Smrg    }
1070d522f475Smrg
1071d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
1072d522f475Smrg	if (fnts[fWide].fs != 0
1073d522f475Smrg	    && fnts[fWBold].fs != 0
1074d522f475Smrg	    && (!is_fixed_font(fnts[fWide].fs)
1075d522f475Smrg		|| !is_fixed_font(fnts[fWBold].fs)
1076d522f475Smrg		|| fnts[fWide].fs->max_bounds.width != fnts[fWBold].fs->max_bounds.width)) {
1077d522f475Smrg	    TRACE(("Proportional font! wide %d/%d, wide bold %d/%d\n",
1078d522f475Smrg		   fnts[fWide].fs->min_bounds.width,
1079d522f475Smrg		   fnts[fWide].fs->max_bounds.width,
1080d522f475Smrg		   fnts[fWBold].fs->min_bounds.width,
1081d522f475Smrg		   fnts[fWBold].fs->max_bounds.width));
1082d522f475Smrg	    proportional = True;
1083d522f475Smrg	}
1084d522f475Smrg    });
1085d522f475Smrg
1086d522f475Smrg    /* TODO : enforce that the width of the wide font is 2* the width
1087d522f475Smrg       of the narrow font */
1088d522f475Smrg
1089d522f475Smrg    /*
1090d522f475Smrg     * If we're switching fonts, free the old ones.  Otherwise we'll leak
1091d522f475Smrg     * the memory that is associated with the old fonts.  The
1092d522f475Smrg     * XLoadQueryFont call allocates a new XFontStruct.
1093d522f475Smrg     */
1094d522f475Smrg    xtermCloseFonts(xw, screen->fnts);
1095d522f475Smrg
1096d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fNorm]), &fnts[fNorm]);
1097d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fBold]), &fnts[fBold]);
1098d522f475Smrg#if OPT_WIDE_CHARS
1099d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fWide]), &fnts[fWide]);
1100d522f475Smrg    if (fnts[fWBold].fs == NULL)
1101d522f475Smrg	xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
1102d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fWBold]), &fnts[fWBold]);
1103d522f475Smrg#endif
1104d522f475Smrg
1105d522f475Smrg    new_normal = getXtermForeground(xw, xw->flags, xw->cur_foreground);
1106d522f475Smrg    new_revers = getXtermBackground(xw, xw->flags, xw->cur_background);
1107d522f475Smrg
1108d522f475Smrg    setCgsFore(xw, win, gcNorm, new_normal);
1109d522f475Smrg    setCgsBack(xw, win, gcNorm, new_revers);
1110d522f475Smrg    setCgsFont(xw, win, gcNorm, &(screen->fnts[fNorm]));
1111d522f475Smrg
1112d522f475Smrg    copyCgs(xw, win, gcBold, gcNorm);
1113d522f475Smrg    setCgsFont(xw, win, gcBold, &(screen->fnts[fBold]));
1114d522f475Smrg
1115d522f475Smrg    setCgsFore(xw, win, gcNormReverse, new_revers);
1116d522f475Smrg    setCgsBack(xw, win, gcNormReverse, new_normal);
1117d522f475Smrg    setCgsFont(xw, win, gcNormReverse, &(screen->fnts[fNorm]));
1118d522f475Smrg
1119d522f475Smrg    copyCgs(xw, win, gcBoldReverse, gcNormReverse);
1120d522f475Smrg    setCgsFont(xw, win, gcBoldReverse, &(screen->fnts[fBold]));
1121d522f475Smrg
1122d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
1123d522f475Smrg	if (screen->fnts[fWide].fs != 0
1124d522f475Smrg	    && screen->fnts[fWBold].fs != 0) {
1125d522f475Smrg	    setCgsFore(xw, win, gcWide, new_normal);
1126d522f475Smrg	    setCgsBack(xw, win, gcWide, new_revers);
1127d522f475Smrg	    setCgsFont(xw, win, gcWide, &(screen->fnts[fWide]));
1128d522f475Smrg
1129d522f475Smrg	    copyCgs(xw, win, gcWBold, gcWide);
1130d522f475Smrg	    setCgsFont(xw, win, gcWBold, &(screen->fnts[fWBold]));
1131d522f475Smrg
1132d522f475Smrg	    setCgsFore(xw, win, gcWideReverse, new_revers);
1133d522f475Smrg	    setCgsBack(xw, win, gcWideReverse, new_normal);
1134d522f475Smrg	    setCgsFont(xw, win, gcWideReverse, &(screen->fnts[fWide]));
1135d522f475Smrg
1136d522f475Smrg	    copyCgs(xw, win, gcWBoldReverse, gcWideReverse);
1137d522f475Smrg	    setCgsFont(xw, win, gcWBoldReverse, &(screen->fnts[fWBold]));
1138d522f475Smrg	}
1139d522f475Smrg    });
1140d522f475Smrg
114120d2c4d2Smrg#if OPT_BOX_CHARS
114220d2c4d2Smrg    screen->allow_packing = proportional;
114320d2c4d2Smrg    setupPackedFonts(xw);
114420d2c4d2Smrg#endif
114520d2c4d2Smrg    screen->fnt_prop = (Boolean) (proportional && !(screen->force_packed));
1146d522f475Smrg    screen->fnt_boxes = True;
1147d522f475Smrg
1148d522f475Smrg#if OPT_BOX_CHARS
1149d522f475Smrg    /*
1150d522f475Smrg     * Xterm uses character positions 1-31 of a font for the line-drawing
1151d522f475Smrg     * characters.  Check that they are all present.  The null character
1152d522f475Smrg     * (0) is special, and is not used.
1153d522f475Smrg     */
1154d522f475Smrg#if OPT_RENDERFONT
1155d522f475Smrg    if (UsingRenderFont(xw)) {
1156d522f475Smrg	/*
1157d522f475Smrg	 * FIXME: we shouldn't even be here if we're using Xft.
1158d522f475Smrg	 */
1159d522f475Smrg	screen->fnt_boxes = False;
1160d522f475Smrg	TRACE(("assume Xft missing line-drawing chars\n"));
1161d522f475Smrg    } else
1162d522f475Smrg#endif
1163d522f475Smrg    {
1164d522f475Smrg	unsigned ch;
1165d522f475Smrg
1166d522f475Smrg	for (ch = 1; ch < 32; ch++) {
1167d522f475Smrg	    unsigned n = ch;
1168d522f475Smrg#if OPT_WIDE_CHARS
1169d522f475Smrg	    if (screen->utf8_mode || screen->unicode_font) {
1170d522f475Smrg		n = dec2ucs(ch);
1171d522f475Smrg		if (n == UCS_REPL)
1172d522f475Smrg		    continue;
1173d522f475Smrg	    }
1174d522f475Smrg#endif
1175956cc18dSsnj	    if (IsXtermMissingChar(screen, n, &fnts[fNorm])) {
1176d522f475Smrg		TRACE(("missing normal char #%d\n", n));
1177d522f475Smrg		screen->fnt_boxes = False;
1178d522f475Smrg		break;
1179d522f475Smrg	    }
1180956cc18dSsnj	    if (IsXtermMissingChar(screen, n, &fnts[fBold])) {
1181d522f475Smrg		TRACE(("missing bold char #%d\n", n));
1182d522f475Smrg		screen->fnt_boxes = False;
1183d522f475Smrg		break;
1184d522f475Smrg	    }
1185d522f475Smrg	}
1186d522f475Smrg    }
1187d522f475Smrg    TRACE(("Will %suse internal line-drawing characters\n",
1188d522f475Smrg	   screen->fnt_boxes ? "not " : ""));
1189d522f475Smrg#endif
1190d522f475Smrg
1191d522f475Smrg    if (screen->always_bold_mode) {
1192d522f475Smrg	screen->enbolden = screen->bold_mode;
1193d522f475Smrg    } else {
1194d522f475Smrg	screen->enbolden = screen->bold_mode
1195d522f475Smrg	    && ((fnts[fNorm].fs == fnts[fBold].fs)
1196d522f475Smrg		|| same_font_name(normal, myfonts.f_b));
1197d522f475Smrg    }
1198d522f475Smrg    TRACE(("Will %suse 1-pixel offset/overstrike to simulate bold\n",
1199d522f475Smrg	   screen->enbolden ? "" : "not "));
1200d522f475Smrg
1201d522f475Smrg    set_menu_font(False);
1202d522f475Smrg    screen->menu_font_number = fontnum;
1203d522f475Smrg    set_menu_font(True);
1204d522f475Smrg    if (tmpname) {		/* if setting escape or sel */
1205d522f475Smrg	if (screen->MenuFontName(fontnum))
120620d2c4d2Smrg	    free((void *) screen->MenuFontName(fontnum));
1207d522f475Smrg	screen->MenuFontName(fontnum) = tmpname;
1208d522f475Smrg	if (fontnum == fontMenu_fontescape) {
1209d522f475Smrg	    SetItemSensitivity(fontMenuEntries[fontMenu_fontescape].widget,
1210d522f475Smrg			       True);
1211d522f475Smrg	}
1212d522f475Smrg#if OPT_SHIFT_FONTS
1213d522f475Smrg	screen->menu_font_sizes[fontnum] = FontSize(fnts[fNorm].fs);
1214d522f475Smrg#endif
1215d522f475Smrg    }
1216d522f475Smrg    set_cursor_gcs(xw);
1217d522f475Smrg    xtermUpdateFontInfo(xw, doresize);
1218d522f475Smrg    TRACE(("Success Cgs - xtermLoadFont\n"));
1219d522f475Smrg    return 1;
1220d522f475Smrg
1221d522f475Smrg  bad:
1222d522f475Smrg    if (tmpname)
1223d522f475Smrg	free(tmpname);
1224d522f475Smrg    releaseWindowGCs(xw, win);
1225d522f475Smrg
1226d522f475Smrg    xtermCloseFonts(xw, fnts);
1227d522f475Smrg    TRACE(("Fail Cgs - xtermLoadFont\n"));
1228d522f475Smrg    return 0;
1229d522f475Smrg}
1230d522f475Smrg
1231d522f475Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
1232d522f475Smrg/*
1233d522f475Smrg * Collect font-names that we can modify with the load-vt-fonts() action.
1234d522f475Smrg */
1235d522f475Smrgtypedef struct {
1236d522f475Smrg    VTFontNames default_font;
1237d522f475Smrg    char *menu_font_names[fontMenu_lastBuiltin + 1][fMAX];
1238d522f475Smrg} SubResourceRec;
1239d522f475Smrg
1240d522f475Smrg#define MERGE_SUBFONT(src,dst,name) \
1241d522f475Smrg	if (dst.name == 0) { \
1242d522f475Smrg	    TRACE(("MERGE_SUBFONT " #dst "." #name " merge %s\n", NonNull(src.name))); \
1243d522f475Smrg	    dst.name = src.name; \
1244d522f475Smrg	} else { \
1245d522f475Smrg	    TRACE(("MERGE_SUBFONT " #dst "." #name " found %s\n", NonNull(dst.name))); \
1246d522f475Smrg	}
1247d522f475Smrg
1248d522f475Smrg#define COPY_MENU_FONTS(src,dst) \
1249d522f475Smrg	TRACE(("COPY_MENU_FONTS " #src " to " #dst "\n")); \
1250d522f475Smrg	for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \
1251d522f475Smrg	    for (m = 0; m < fMAX; ++m) { \
1252d522f475Smrg		dst.menu_font_names[n][m] = src.menu_font_names[n][m]; \
1253d522f475Smrg	    } \
1254d522f475Smrg	}
1255d522f475Smrg
1256d522f475Smrg/*
1257d522f475Smrg * Load the "VT" font names from the given subresource name/class.  These
1258d522f475Smrg * correspond to the VT100 resources.
1259d522f475Smrg */
1260d522f475Smrgstatic Bool
126120d2c4d2SmrgxtermLoadVTFonts(XtermWidget xw, String myName, String myClass)
1262d522f475Smrg{
1263d522f475Smrg    static Bool initialized = False;
1264d522f475Smrg    static SubResourceRec original, referenceRec, subresourceRec;
1265d522f475Smrg
1266d522f475Smrg    /*
1267d522f475Smrg     * These are duplicates of the VT100 font resources, but with a special
1268d522f475Smrg     * application/classname passed in to distinguish them.
1269d522f475Smrg     */
1270d522f475Smrg    static XtResource font_resources[] =
1271d522f475Smrg    {
1272d522f475Smrg	Sres(XtNfont, XtCFont, default_font.f_n, DEFFONT),
1273d522f475Smrg	Sres(XtNboldFont, XtCBoldFont, default_font.f_b, DEFBOLDFONT),
1274d522f475Smrg#if OPT_WIDE_CHARS
1275d522f475Smrg	Sres(XtNwideFont, XtCWideFont, default_font.f_w, DEFWIDEFONT),
1276d522f475Smrg	Sres(XtNwideBoldFont, XtCWideBoldFont, default_font.f_wb, DEFWIDEBOLDFONT),
1277d522f475Smrg#endif
1278d522f475Smrg	Sres(XtNfont1, XtCFont1, MenuFontName(fontMenu_font1), NULL),
1279d522f475Smrg	Sres(XtNfont2, XtCFont2, MenuFontName(fontMenu_font2), NULL),
1280d522f475Smrg	Sres(XtNfont3, XtCFont3, MenuFontName(fontMenu_font3), NULL),
1281d522f475Smrg	Sres(XtNfont4, XtCFont4, MenuFontName(fontMenu_font4), NULL),
1282d522f475Smrg	Sres(XtNfont5, XtCFont5, MenuFontName(fontMenu_font5), NULL),
1283d522f475Smrg	Sres(XtNfont6, XtCFont6, MenuFontName(fontMenu_font6), NULL),
1284d522f475Smrg    };
1285d522f475Smrg    Cardinal n, m;
1286d522f475Smrg    Bool status = True;
1287956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1288d522f475Smrg
1289d522f475Smrg    if (!initialized) {
1290d522f475Smrg
1291d522f475Smrg	initialized = True;
1292d522f475Smrg	TRACE(("xtermLoadVTFonts saving original\n"));
1293956cc18dSsnj	original.default_font = xw->misc.default_font;
1294956cc18dSsnj	COPY_MENU_FONTS(xw->screen, original);
1295d522f475Smrg    }
1296d522f475Smrg
1297d522f475Smrg    if (myName == 0 || *myName == 0) {
1298d522f475Smrg	TRACE(("xtermLoadVTFonts restoring original\n"));
1299956cc18dSsnj	xw->misc.default_font = original.default_font;
1300956cc18dSsnj	COPY_MENU_FONTS(original, xw->screen);
1301d522f475Smrg	for (n = 0; n < XtNumber(original.menu_font_names); ++n)
1302956cc18dSsnj	    screen->MenuFontName(n) = original.MenuFontName(n);
1303d522f475Smrg    } else {
1304d522f475Smrg	TRACE(("xtermLoadVTFonts(%s, %s)\n", myName, myClass));
1305d522f475Smrg
1306d522f475Smrg	memset(&subresourceRec, 0, sizeof(subresourceRec));
1307956cc18dSsnj	XtGetSubresources((Widget) xw, (XtPointer) &subresourceRec,
1308d522f475Smrg			  myName, myClass,
1309d522f475Smrg			  font_resources,
1310d522f475Smrg			  (Cardinal) XtNumber(font_resources),
1311d522f475Smrg			  NULL, (Cardinal) 0);
1312d522f475Smrg
1313d522f475Smrg	if (memcmp(&referenceRec, &subresourceRec, sizeof(referenceRec))) {
1314d522f475Smrg
1315d522f475Smrg	    /*
1316d522f475Smrg	     * If a particular resource value was not found, use the original.
1317d522f475Smrg	     */
1318956cc18dSsnj	    MERGE_SUBFONT(xw->misc, subresourceRec, default_font.f_n);
1319956cc18dSsnj	    MERGE_SUBFONT(xw->misc, subresourceRec, default_font.f_b);
1320d522f475Smrg#if OPT_WIDE_CHARS
1321956cc18dSsnj	    MERGE_SUBFONT(xw->misc, subresourceRec, default_font.f_w);
1322956cc18dSsnj	    MERGE_SUBFONT(xw->misc, subresourceRec, default_font.f_wb);
1323d522f475Smrg#endif
1324d522f475Smrg	    for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n)
1325956cc18dSsnj		MERGE_SUBFONT(xw->screen, subresourceRec, MenuFontName(n));
1326d522f475Smrg
1327d522f475Smrg	    /*
1328d522f475Smrg	     * Finally, copy the subresource data to the widget.
1329d522f475Smrg	     */
1330956cc18dSsnj	    xw->misc.default_font = subresourceRec.default_font;
1331956cc18dSsnj	    COPY_MENU_FONTS(subresourceRec, xw->screen);
1332956cc18dSsnj	    screen->MenuFontName(fontMenu_default) = xw->misc.default_font.f_n;
1333956cc18dSsnj	    screen->menu_font_names[0][fBold] = xw->misc.default_font.f_b;
1334d522f475Smrg#if OPT_WIDE_CHARS
1335956cc18dSsnj	    screen->menu_font_names[0][fWide] = xw->misc.default_font.f_w;
1336956cc18dSsnj	    screen->menu_font_names[0][fWBold] = xw->misc.default_font.f_wb;
1337d522f475Smrg#endif
1338d522f475Smrg	} else {
1339d522f475Smrg	    TRACE(("...no resources found\n"));
1340d522f475Smrg	    status = False;
1341d522f475Smrg	}
1342d522f475Smrg    }
1343d522f475Smrg    return status;
1344d522f475Smrg}
1345d522f475Smrg
1346d522f475Smrg#if OPT_WIDE_CHARS
1347d522f475Smrgstatic Bool
134820d2c4d2SmrgisWideFont(XFontStruct * fp, const char *tag, Bool nullOk)
1349d522f475Smrg{
1350d522f475Smrg    Bool result = False;
1351d522f475Smrg
1352d522f475Smrg    (void) tag;
1353d522f475Smrg    if (okFont(fp)) {
1354d522f475Smrg	unsigned count = countGlyphs(fp);
1355d522f475Smrg	TRACE(("isWideFont(%s) found %d cells\n", tag, count));
1356d522f475Smrg	result = (count > 256) ? True : False;
1357d522f475Smrg    } else {
1358d522f475Smrg	result = nullOk;
1359d522f475Smrg    }
1360d522f475Smrg    return result;
1361d522f475Smrg}
1362d522f475Smrg
1363d522f475Smrg/*
1364d522f475Smrg * If the current fonts are not wide, load the UTF8 fonts.
1365d522f475Smrg *
1366d522f475Smrg * Called during initialization (for wide-character mode), the fonts have not
1367d522f475Smrg * been setup, so we pass nullOk=True to isWideFont().
1368d522f475Smrg *
1369d522f475Smrg * Called after initialization, e.g., in response to the UTF-8 menu entry
1370d522f475Smrg * (starting from narrow character mode), it checks if the fonts are not wide.
1371d522f475Smrg */
1372d522f475SmrgBool
1373d522f475SmrgxtermLoadWideFonts(XtermWidget xw, Bool nullOk)
1374d522f475Smrg{
1375956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1376d522f475Smrg    Bool result;
1377d522f475Smrg
1378d522f475Smrg    if (EmptyFont(screen->fnts[fWide].fs)) {
1379d522f475Smrg	result = (isWideFont(screen->fnts[fNorm].fs, "normal", nullOk)
1380d522f475Smrg		  && isWideFont(screen->fnts[fBold].fs, "bold", nullOk));
1381d522f475Smrg    } else {
1382d522f475Smrg	result = (isWideFont(screen->fnts[fWide].fs, "wide", nullOk)
1383d522f475Smrg		  && isWideFont(screen->fnts[fWBold].fs, "wide-bold", nullOk));
1384d522f475Smrg	if (result && !screen->utf8_latin1) {
1385d522f475Smrg	    result = (isWideFont(screen->fnts[fNorm].fs, "normal", nullOk)
1386d522f475Smrg		      && isWideFont(screen->fnts[fBold].fs, "bold", nullOk));
1387d522f475Smrg	}
1388d522f475Smrg    }
1389d522f475Smrg    if (!result) {
1390d522f475Smrg	TRACE(("current fonts are not all wide%s\n", nullOk ? " nullOk" : ""));
1391d522f475Smrg	result = xtermLoadVTFonts(xw, "utf8Fonts", "Utf8Fonts");
1392d522f475Smrg    }
1393d522f475Smrg    TRACE(("xtermLoadWideFonts:%d\n", result));
1394d522f475Smrg    return result;
1395d522f475Smrg}
1396d522f475Smrg#endif /* OPT_WIDE_CHARS */
1397d522f475Smrg
1398d522f475Smrg/*
1399d522f475Smrg * Restore the default fonts, i.e., if we had switched to wide-fonts.
1400d522f475Smrg */
1401d522f475SmrgBool
1402956cc18dSsnjxtermLoadDefaultFonts(XtermWidget xw)
1403d522f475Smrg{
1404d522f475Smrg    Bool result;
1405956cc18dSsnj    result = xtermLoadVTFonts(xw, NULL, NULL);
1406d522f475Smrg    TRACE(("xtermLoadDefaultFonts:%d\n", result));
1407d522f475Smrg    return result;
1408d522f475Smrg}
1409d522f475Smrg#endif /* OPT_LOAD_VTFONTS || OPT_WIDE_CHARS */
1410d522f475Smrg
1411d522f475Smrg#if OPT_LOAD_VTFONTS
1412d522f475Smrgvoid
1413d522f475SmrgHandleLoadVTFonts(Widget w,
1414d522f475Smrg		  XEvent * event GCC_UNUSED,
1415d522f475Smrg		  String * params GCC_UNUSED,
1416d522f475Smrg		  Cardinal *param_count GCC_UNUSED)
1417d522f475Smrg{
1418d522f475Smrg    static char empty[] = "";	/* appease strict compilers */
1419d522f475Smrg
1420956cc18dSsnj    XtermWidget xw;
1421956cc18dSsnj
1422956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
1423956cc18dSsnj	TScreen *screen = TScreenOf(xw);
1424d522f475Smrg	char buf[80];
142520d2c4d2Smrg	char *myName = (char *) ((*param_count > 0) ? params[0] : empty);
142620d2c4d2Smrg	char *convert = (char *) ((*param_count > 1) ? params[1] : myName);
1427d522f475Smrg	char *myClass = (char *) MyStackAlloc(strlen(convert), buf);
1428d522f475Smrg	int n;
1429d522f475Smrg
1430d522f475Smrg	TRACE(("HandleLoadVTFonts(%d)\n", *param_count));
1431d522f475Smrg	strcpy(myClass, convert);
14322eaa94a1Schristos	if (*param_count == 1)
14332eaa94a1Schristos	    myClass[0] = x_toupper(myClass[0]);
1434d522f475Smrg
1435d522f475Smrg	if (xtermLoadVTFonts(xw, myName, myClass)) {
1436d522f475Smrg	    /*
1437d522f475Smrg	     * When switching fonts, try to preserve the font-menu selection, since
1438d522f475Smrg	     * it is less surprising to do that (if the font-switching can be
1439d522f475Smrg	     * undone) than to switch to "Default".
1440d522f475Smrg	     */
1441956cc18dSsnj	    int font_number = screen->menu_font_number;
1442d522f475Smrg	    if (font_number > fontMenu_lastBuiltin)
1443d522f475Smrg		font_number = fontMenu_lastBuiltin;
1444d522f475Smrg	    for (n = 0; n < NMENUFONTS; ++n)
1445956cc18dSsnj		screen->menu_font_sizes[n] = 0;
1446d522f475Smrg	    SetVTFont(xw, font_number, True,
1447d522f475Smrg		      ((font_number == fontMenu_default)
1448d522f475Smrg		       ? &(xw->misc.default_font)
1449d522f475Smrg		       : NULL));
1450d522f475Smrg	}
1451d522f475Smrg
1452d522f475Smrg	MyStackFree(myClass, buf);
1453d522f475Smrg    }
1454d522f475Smrg}
1455d522f475Smrg#endif /* OPT_LOAD_VTFONTS */
1456d522f475Smrg
1457d522f475Smrg/*
1458d522f475Smrg * Set the limits for the box that outlines the cursor.
1459d522f475Smrg */
1460d522f475Smrgvoid
1461d522f475SmrgxtermSetCursorBox(TScreen * screen)
1462d522f475Smrg{
1463d522f475Smrg    static XPoint VTbox[NBOX];
1464d522f475Smrg    XPoint *vp;
14652eaa94a1Schristos    int fw = FontWidth(screen) - 1;
14662eaa94a1Schristos    int fh = FontHeight(screen) - 1;
14672eaa94a1Schristos    int hh = screen->cursor_underline ? 1 : fh;
1468d522f475Smrg
1469d522f475Smrg    vp = &VTbox[1];
14702eaa94a1Schristos    (vp++)->x = (short) fw;
14712eaa94a1Schristos    (vp++)->y = (short) hh;
14722eaa94a1Schristos    (vp++)->x = (short) -fw;
14732eaa94a1Schristos    vp->y = (short) -hh;
14742eaa94a1Schristos
1475d522f475Smrg    screen->box = VTbox;
1476d522f475Smrg}
1477d522f475Smrg
1478d522f475Smrg#define CACHE_XFT(dst,src) if (src != 0) {\
1479956cc18dSsnj	    checkXft(xw, &(dst[fontnum]), src);\
1480956cc18dSsnj	    TRACE(("Xft metrics %s[%d] = %d (%d,%d) advance %d, actual %d%s\n",\
1481d522f475Smrg		#dst,\
1482d522f475Smrg	    	fontnum,\
1483d522f475Smrg		src->height,\
1484d522f475Smrg		src->ascent,\
1485d522f475Smrg		src->descent,\
1486956cc18dSsnj		src->max_advance_width,\
1487956cc18dSsnj		dst[fontnum].map.min_width,\
1488956cc18dSsnj		dst[fontnum].map.mixed ? " mixed" : ""));\
1489d522f475Smrg	}
1490d522f475Smrg
1491d522f475Smrg#if OPT_RENDERFONT
1492956cc18dSsnj
149320d2c4d2Smrg#if OPT_TRACE > 1
149420d2c4d2Smrgstatic FcChar32
149520d2c4d2SmrgxtermXftFirstChar(XftFont * xft)
149620d2c4d2Smrg{
149720d2c4d2Smrg    FcChar32 map[FC_CHARSET_MAP_SIZE];
149820d2c4d2Smrg    FcChar32 next;
149920d2c4d2Smrg    FcChar32 first;
150020d2c4d2Smrg    int i;
150120d2c4d2Smrg
150220d2c4d2Smrg    first = FcCharSetFirstPage(xft->charset, map, &next);
150320d2c4d2Smrg    for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
150420d2c4d2Smrg	if (map[i]) {
150520d2c4d2Smrg	    FcChar32 bits = map[i];
150620d2c4d2Smrg	    first += i * 32;
150720d2c4d2Smrg	    while (!(bits & 0x1)) {
150820d2c4d2Smrg		bits >>= 1;
150920d2c4d2Smrg		first++;
151020d2c4d2Smrg	    }
151120d2c4d2Smrg	    break;
151220d2c4d2Smrg	}
151320d2c4d2Smrg    return first;
151420d2c4d2Smrg}
151520d2c4d2Smrg
151620d2c4d2Smrgstatic FcChar32
151720d2c4d2SmrgxtermXftLastChar(XftFont * xft)
151820d2c4d2Smrg{
151920d2c4d2Smrg    FcChar32 this, last, next;
152020d2c4d2Smrg    FcChar32 map[FC_CHARSET_MAP_SIZE];
152120d2c4d2Smrg    int i;
152220d2c4d2Smrg    last = FcCharSetFirstPage(xft->charset, map, &next);
152320d2c4d2Smrg    while ((this = FcCharSetNextPage(xft->charset, map, &next)) != FC_CHARSET_DONE)
152420d2c4d2Smrg	last = this;
152520d2c4d2Smrg    last &= ~0xff;
152620d2c4d2Smrg    for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--)
152720d2c4d2Smrg	if (map[i]) {
152820d2c4d2Smrg	    FcChar32 bits = map[i];
152920d2c4d2Smrg	    last += i * 32 + 31;
153020d2c4d2Smrg	    while (!(bits & 0x80000000)) {
153120d2c4d2Smrg		last--;
153220d2c4d2Smrg		bits <<= 1;
153320d2c4d2Smrg	    }
153420d2c4d2Smrg	    break;
153520d2c4d2Smrg	}
153620d2c4d2Smrg    return (long) last;
153720d2c4d2Smrg}
153820d2c4d2Smrg
153920d2c4d2Smrgstatic void
154020d2c4d2SmrgdumpXft(XtermWidget xw, XTermXftFonts * data)
154120d2c4d2Smrg{
154220d2c4d2Smrg    XftFont *xft = data->font;
154320d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
154420d2c4d2Smrg    VTwin *win = WhichVWin(screen);
154520d2c4d2Smrg
154620d2c4d2Smrg    FcChar32 c;
154720d2c4d2Smrg    FcChar32 first = xtermXftFirstChar(xft);
154820d2c4d2Smrg    FcChar32 last = xtermXftLastChar(xft);
154920d2c4d2Smrg    unsigned count = 0;
155020d2c4d2Smrg    unsigned outside = 0;
155120d2c4d2Smrg
155220d2c4d2Smrg    TRACE(("dumpXft {{\n"));
155320d2c4d2Smrg    TRACE(("   data range %#6x..%#6x\n", first, last));
155420d2c4d2Smrg    for (c = first; c <= last; ++c) {
155520d2c4d2Smrg	if (FcCharSetHasChar(xft->charset, c)) {
155620d2c4d2Smrg	    int width = my_wcwidth((int) c);
155720d2c4d2Smrg	    XGlyphInfo extents;
155820d2c4d2Smrg
155920d2c4d2Smrg	    XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents);
156020d2c4d2Smrg	    TRACE(("%#6x  %2d  %.1f\n", c, width,
156120d2c4d2Smrg		   ((double) extents.width) / win->f_width));
156220d2c4d2Smrg	    if (extents.width > win->f_width)
156320d2c4d2Smrg		++outside;
156420d2c4d2Smrg	    ++count;
156520d2c4d2Smrg	}
156620d2c4d2Smrg    }
156720d2c4d2Smrg    TRACE(("}} %u total, %u outside\n", count, outside));
156820d2c4d2Smrg}
156920d2c4d2Smrg#define DUMP_XFT(xw, data) dumpXft(xw, data)
157020d2c4d2Smrg#else
157120d2c4d2Smrg#define DUMP_XFT(xw, data)	/* nothing */
157220d2c4d2Smrg#endif
157320d2c4d2Smrg
1574956cc18dSsnjstatic void
1575956cc18dSsnjcheckXft(XtermWidget xw, XTermXftFonts * data, XftFont * xft)
1576956cc18dSsnj{
1577956cc18dSsnj    FcChar32 c;
1578956cc18dSsnj    Dimension width = 0;
1579956cc18dSsnj
1580956cc18dSsnj    data->font = xft;
1581956cc18dSsnj    data->map.min_width = 0;
1582956cc18dSsnj    data->map.max_width = (Dimension) xft->max_advance_width;
1583956cc18dSsnj
158420d2c4d2Smrg    /*
158520d2c4d2Smrg     * For each ASCII or ISO-8859-1 printable code, ask what its width is.
158620d2c4d2Smrg     * Given the maximum width for those, we have a reasonable estimate of
158720d2c4d2Smrg     * the single-column width.
158820d2c4d2Smrg     *
158920d2c4d2Smrg     * Ignore control characters - their extent information is misleading.
159020d2c4d2Smrg     */
1591956cc18dSsnj    for (c = 32; c < 256; ++c) {
159220d2c4d2Smrg	if (c >= 127 && c <= 159)
159320d2c4d2Smrg	    continue;
1594956cc18dSsnj	if (FcCharSetHasChar(xft->charset, c)) {
1595956cc18dSsnj	    XGlyphInfo extents;
1596956cc18dSsnj
1597956cc18dSsnj	    XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents);
159820d2c4d2Smrg	    if (width < extents.width && extents.width <= data->map.max_width) {
1599956cc18dSsnj		width = extents.width;
160020d2c4d2Smrg	    }
1601956cc18dSsnj	}
1602956cc18dSsnj    }
1603956cc18dSsnj    data->map.min_width = width;
1604956cc18dSsnj    data->map.mixed = (data->map.max_width >= (data->map.min_width + 1));
1605956cc18dSsnj}
1606956cc18dSsnj
1607d522f475Smrgstatic XftFont *
1608956cc18dSsnjxtermOpenXft(XtermWidget xw, const char *name, XftPattern * pat, const char *tag)
1609d522f475Smrg{
1610956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1611956cc18dSsnj    Display *dpy = screen->display;
1612d522f475Smrg    XftPattern *match;
1613d522f475Smrg    XftResult status;
1614d522f475Smrg    XftFont *result = 0;
1615d522f475Smrg
1616d522f475Smrg    if (pat != 0) {
1617d522f475Smrg	match = XftFontMatch(dpy, DefaultScreen(dpy), pat, &status);
1618d522f475Smrg	if (match != 0) {
1619d522f475Smrg	    result = XftFontOpenPattern(dpy, match);
1620d522f475Smrg	    if (result != 0) {
1621d522f475Smrg		TRACE(("...matched %s font\n", tag));
1622d522f475Smrg	    } else {
1623d522f475Smrg		TRACE(("...could did not open %s font\n", tag));
1624d522f475Smrg		XftPatternDestroy(match);
1625956cc18dSsnj		if (xw->misc.fontWarnings >= fwAlways) {
1626956cc18dSsnj		    TRACE(("OOPS cannot open %s font \"%s\"\n", tag, name));
1627956cc18dSsnj		    fprintf(stderr, "%s: cannot open %s font \"%s\"\n",
1628956cc18dSsnj			    ProgramName, tag, name);
1629956cc18dSsnj		}
1630d522f475Smrg	    }
1631d522f475Smrg	} else {
1632d522f475Smrg	    TRACE(("...did not match %s font\n", tag));
1633956cc18dSsnj	    if (xw->misc.fontWarnings >= fwResource) {
1634956cc18dSsnj		TRACE(("OOPS: cannot match %s font \"%s\"\n", tag, name));
1635956cc18dSsnj		fprintf(stderr, "%s: cannot match %s font \"%s\"\n",
1636956cc18dSsnj			ProgramName, tag, name);
1637956cc18dSsnj	    }
1638d522f475Smrg	}
1639d522f475Smrg    }
1640d522f475Smrg    return result;
1641d522f475Smrg}
1642d522f475Smrg#endif
1643d522f475Smrg
1644d522f475Smrg#if OPT_RENDERFONT
1645d522f475Smrg#if OPT_SHIFT_FONTS
1646d522f475Smrg/*
1647d522f475Smrg * Don't make a dependency on the math library for a single function.
1648d522f475Smrg * (Newton Raphson).
1649d522f475Smrg */
1650d522f475Smrgstatic double
1651d522f475SmrgmySquareRoot(double value)
1652d522f475Smrg{
1653d522f475Smrg    double result = 0.0;
1654d522f475Smrg    if (value > 0.0) {
1655d522f475Smrg	int n;
1656d522f475Smrg	double older = value;
1657d522f475Smrg	for (n = 0; n < 10; ++n) {
1658d522f475Smrg	    double delta = (older * older - value) / (2.0 * older);
1659d522f475Smrg	    double newer = older - delta;
1660d522f475Smrg	    older = newer;
1661d522f475Smrg	    result = newer;
1662d522f475Smrg	    if (delta > -0.001 && delta < 0.001)
1663d522f475Smrg		break;
1664d522f475Smrg	}
1665d522f475Smrg    }
1666d522f475Smrg    return result;
1667d522f475Smrg}
1668d522f475Smrg#endif
1669d522f475Smrg
1670d522f475Smrg/*
1671d522f475Smrg * Given the Xft font metrics, determine the actual font size.  This is used
1672d522f475Smrg * for each font to ensure that normal, bold and italic fonts follow the same
1673d522f475Smrg * rule.
1674d522f475Smrg */
1675d522f475Smrgstatic void
1676d522f475SmrgsetRenderFontsize(TScreen * screen, VTwin * win, XftFont * font, const char *tag)
1677d522f475Smrg{
1678d522f475Smrg    if (font != 0) {
1679d522f475Smrg	int width, height, ascent, descent;
1680d522f475Smrg
1681d522f475Smrg	(void) screen;
1682d522f475Smrg
1683d522f475Smrg	width = font->max_advance_width;
1684d522f475Smrg	height = font->height;
1685d522f475Smrg	ascent = font->ascent;
1686d522f475Smrg	descent = font->descent;
1687d522f475Smrg	if (height < ascent + descent) {
1688d522f475Smrg	    TRACE(("...increase height from %d\n", height));
1689d522f475Smrg	    height = ascent + descent;
1690d522f475Smrg	}
1691d522f475Smrg	if (is_double_width_font_xft(screen->display, font)) {
1692d522f475Smrg	    TRACE(("...reduced width from %d\n", width));
1693d522f475Smrg	    width >>= 1;
1694d522f475Smrg	}
1695d522f475Smrg	if (tag == 0) {
1696d522f475Smrg	    win->f_width = width;
1697d522f475Smrg	    win->f_height = height;
1698d522f475Smrg	    win->f_ascent = ascent;
1699d522f475Smrg	    win->f_descent = descent;
1700d522f475Smrg	    TRACE(("setRenderFontsize result %dx%d (%d+%d)\n",
1701d522f475Smrg		   width, height, ascent, descent));
1702d522f475Smrg	} else if (win->f_width < width ||
1703d522f475Smrg		   win->f_height < height ||
1704d522f475Smrg		   win->f_ascent < ascent ||
1705d522f475Smrg		   win->f_descent < descent) {
1706d522f475Smrg	    TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n",
1707d522f475Smrg		   tag,
1708d522f475Smrg		   win->f_width, win->f_height, win->f_ascent, win->f_descent,
1709d522f475Smrg		   width, height, ascent, descent));
1710d522f475Smrg
1711d522f475Smrg	    win->f_width = width;
1712d522f475Smrg	    win->f_height = height;
1713d522f475Smrg	    win->f_ascent = ascent;
1714d522f475Smrg	    win->f_descent = descent;
1715d522f475Smrg	} else {
1716d522f475Smrg	    TRACE(("setRenderFontsize %s unchanged\n", tag));
1717d522f475Smrg	}
1718d522f475Smrg    }
1719d522f475Smrg}
1720d522f475Smrg#endif
1721d522f475Smrg
172220d2c4d2Smrgstatic void
172320d2c4d2SmrgcheckFontInfo(int value, const char *tag)
172420d2c4d2Smrg{
172520d2c4d2Smrg    if (value == 0) {
172620d2c4d2Smrg	fprintf(stderr,
172720d2c4d2Smrg		"Selected font has no non-zero %s for ISO-8859-1 encoding\n", tag);
172820d2c4d2Smrg	exit(1);
172920d2c4d2Smrg    }
173020d2c4d2Smrg}
173120d2c4d2Smrg
173220d2c4d2Smrg#if OPT_RENDERFONT
173320d2c4d2Smrgvoid
173420d2c4d2SmrgxtermCloseXft(TScreen * screen, XTermXftFonts * pub)
173520d2c4d2Smrg{
173620d2c4d2Smrg    if (pub->font != 0) {
173720d2c4d2Smrg	XftFontClose(screen->display, pub->font);
173820d2c4d2Smrg	pub->font = 0;
173920d2c4d2Smrg    }
174020d2c4d2Smrg}
174120d2c4d2Smrg
174220d2c4d2Smrg/*
174320d2c4d2Smrg * Get the faceName/faceDoublesize resource setting.  Strip off "xft:", which
174420d2c4d2Smrg * is not recognized by XftParseName().
174520d2c4d2Smrg */
174620d2c4d2Smrgchar *
174720d2c4d2SmrggetFaceName(XtermWidget xw, Bool wideName GCC_UNUSED)
174820d2c4d2Smrg{
174920d2c4d2Smrg#if OPT_RENDERWIDE
175020d2c4d2Smrg    char *result = (wideName
175120d2c4d2Smrg		    ? xw->misc.face_wide_name
175220d2c4d2Smrg		    : xw->misc.face_name);
175320d2c4d2Smrg#else
175420d2c4d2Smrg    char *result = xw->misc.face_name;
175520d2c4d2Smrg#endif
175620d2c4d2Smrg    if (!IsEmpty(result) && !strncmp(result, "xft:", (size_t) 4))
175720d2c4d2Smrg	result += 4;
175820d2c4d2Smrg    return x_nonempty(result);
175920d2c4d2Smrg}
176020d2c4d2Smrg
176120d2c4d2Smrg/*
176220d2c4d2Smrg * If we change the faceName, we'll have to re-acquire all of the fonts that
176320d2c4d2Smrg * are derived from it.
176420d2c4d2Smrg */
176520d2c4d2Smrgvoid
176620d2c4d2SmrgsetFaceName(XtermWidget xw, const char *value)
176720d2c4d2Smrg{
176820d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
176920d2c4d2Smrg    int n;
177020d2c4d2Smrg
177120d2c4d2Smrg    xw->misc.face_name = x_strdup(value);
177220d2c4d2Smrg    for (n = 0; n < NMENUFONTS; ++n) {
177320d2c4d2Smrg	xw->misc.face_size[n] = -1.0;
177420d2c4d2Smrg	xtermCloseXft(screen, &(screen->renderFontNorm[n]));
177520d2c4d2Smrg	xtermCloseXft(screen, &(screen->renderFontBold[n]));
177620d2c4d2Smrg	xtermCloseXft(screen, &(screen->renderFontBold[n]));
177720d2c4d2Smrg#if OPT_RENDERWIDE
177820d2c4d2Smrg	xtermCloseXft(screen, &(screen->renderWideNorm[n]));
177920d2c4d2Smrg	xtermCloseXft(screen, &(screen->renderWideBold[n]));
178020d2c4d2Smrg	xtermCloseXft(screen, &(screen->renderWideItal[n]));
178120d2c4d2Smrg#endif
178220d2c4d2Smrg    }
178320d2c4d2Smrg}
178420d2c4d2Smrg#endif
178520d2c4d2Smrg
1786d522f475Smrg/*
1787d522f475Smrg * Compute useful values for the font/window sizes
1788d522f475Smrg */
1789d522f475Smrgvoid
1790d522f475SmrgxtermComputeFontInfo(XtermWidget xw,
1791d522f475Smrg		     VTwin * win,
1792d522f475Smrg		     XFontStruct * font,
1793d522f475Smrg		     int sbwidth)
1794d522f475Smrg{
1795956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1796d522f475Smrg
1797d522f475Smrg    int i, j, width, height;
1798d522f475Smrg
1799d522f475Smrg#if OPT_RENDERFONT
1800d522f475Smrg    /*
1801d522f475Smrg     * xterm contains a lot of references to fonts, assuming they are fixed
1802d522f475Smrg     * size.  This chunk of code overrides the actual font-selection (see
1803d522f475Smrg     * drawXtermText()), if the user has selected render-font.  All of the
1804d522f475Smrg     * font-loading for fixed-fonts still goes on whether or not this chunk
1805d522f475Smrg     * overrides it.
1806d522f475Smrg     */
180720d2c4d2Smrg    if (UsingRenderFont(xw)) {
180820d2c4d2Smrg	char *face_name = getFaceName(xw, False);
1809d522f475Smrg	int fontnum = screen->menu_font_number;
1810956cc18dSsnj	XftFont *norm = screen->renderFontNorm[fontnum].font;
1811956cc18dSsnj	XftFont *bold = screen->renderFontBold[fontnum].font;
1812956cc18dSsnj	XftFont *ital = screen->renderFontItal[fontnum].font;
1813d522f475Smrg#if OPT_RENDERWIDE
1814956cc18dSsnj	XftFont *wnorm = screen->renderWideNorm[fontnum].font;
1815956cc18dSsnj	XftFont *wbold = screen->renderWideBold[fontnum].font;
1816956cc18dSsnj	XftFont *wital = screen->renderWideItal[fontnum].font;
1817d522f475Smrg#endif
1818d522f475Smrg
181920d2c4d2Smrg	if (norm == 0 && face_name) {
1820d522f475Smrg	    XftPattern *pat;
1821d522f475Smrg	    double face_size = xw->misc.face_size[fontnum];
1822d522f475Smrg
1823d522f475Smrg	    TRACE(("xtermComputeFontInfo norm(face %s, size %f)\n",
182420d2c4d2Smrg		   face_name,
1825d522f475Smrg		   xw->misc.face_size[fontnum]));
1826d522f475Smrg
1827d522f475Smrg	    if (face_size <= 0.0) {
1828d522f475Smrg#if OPT_SHIFT_FONTS
1829d522f475Smrg		/*
1830d522f475Smrg		 * If the user is switching font-sizes, make it follow by
1831d522f475Smrg		 * default the same ratios to the default as the fixed fonts
1832d522f475Smrg		 * would, for easy comparison.  There will be some differences
1833d522f475Smrg		 * since the fixed fonts have a variety of height/width ratios,
1834d522f475Smrg		 * but this is simpler than adding another resource value - and
1835d522f475Smrg		 * as noted above, the data for the fixed fonts are available.
1836d522f475Smrg		 */
1837d522f475Smrg		lookupOneFontSize(xw, 0);
1838d522f475Smrg		lookupOneFontSize(xw, fontnum);
1839d522f475Smrg		if (fontnum == fontMenu_default) {
1840d522f475Smrg		    face_size = 14.0;
1841d522f475Smrg		} else {
1842d522f475Smrg		    double ratio;
184320d2c4d2Smrg		    long num = screen->menu_font_sizes[fontnum];
184420d2c4d2Smrg		    long den = screen->menu_font_sizes[0];
1845d522f475Smrg
1846d522f475Smrg		    if (den <= 0)
1847d522f475Smrg			den = 1;
184820d2c4d2Smrg		    ratio = mySquareRoot((double) num / (double) den);
1849d522f475Smrg
1850d522f475Smrg		    face_size = (ratio * xw->misc.face_size[0]);
185120d2c4d2Smrg		    TRACE(("scaled using %3ld/%ld = %.2f -> %f\n",
1852d522f475Smrg			   num, den, ratio, face_size));
1853d522f475Smrg		}
1854d522f475Smrg#else
1855d522f475Smrg		switch (fontnum) {
1856d522f475Smrg		case fontMenu_font1:
1857d522f475Smrg		    face_size = 8.0;
1858d522f475Smrg		    break;
1859d522f475Smrg		case fontMenu_font2:
1860d522f475Smrg		    face_size = 10.0;
1861d522f475Smrg		    break;
1862d522f475Smrg		case fontMenu_font3:
1863d522f475Smrg		    face_size = 12.0;
1864d522f475Smrg		    break;
1865d522f475Smrg		default:
1866d522f475Smrg		    face_size = 14.0;
1867d522f475Smrg		    break;
1868d522f475Smrg		case fontMenu_font4:
1869d522f475Smrg		    face_size = 16.0;
1870d522f475Smrg		    break;
1871d522f475Smrg		case fontMenu_font5:
1872d522f475Smrg		    face_size = 18.0;
1873d522f475Smrg		    break;
1874d522f475Smrg		case fontMenu_font6:
1875d522f475Smrg		    face_size = 20.0;
1876d522f475Smrg		    break;
1877d522f475Smrg		}
1878d522f475Smrg#endif
1879956cc18dSsnj		xw->misc.face_size[fontnum] = (float) face_size;
1880d522f475Smrg	    }
1881d522f475Smrg
1882d522f475Smrg	    /*
1883d522f475Smrg	     * By observation (there is no documentation), XftPatternBuild is
1884d522f475Smrg	     * cumulative.  Build the bold- and italic-patterns on top of the
1885d522f475Smrg	     * normal pattern.
1886d522f475Smrg	     */
1887d522f475Smrg#define NormXftPattern \
1888d522f475Smrg	    XFT_FAMILY, XftTypeString, "mono", \
1889d522f475Smrg	    XFT_SIZE, XftTypeDouble, face_size, \
1890d522f475Smrg	    XFT_SPACING, XftTypeInteger, XFT_MONO
1891d522f475Smrg
1892d522f475Smrg#define BoldXftPattern(norm) \
1893d522f475Smrg	    XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \
1894d522f475Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width
1895d522f475Smrg
1896d522f475Smrg#define ItalXftPattern(norm) \
1897d522f475Smrg	    XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \
1898d522f475Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width
1899d522f475Smrg
190020d2c4d2Smrg	    if ((pat = XftNameParse(face_name)) != 0) {
190120d2c4d2Smrg#define OPEN_XFT(tag) xtermOpenXft(xw, face_name, pat, tag)
1902d522f475Smrg		XftPatternBuild(pat,
1903d522f475Smrg				NormXftPattern,
1904d522f475Smrg				(void *) 0);
1905956cc18dSsnj		norm = OPEN_XFT("normal");
1906d522f475Smrg
1907d522f475Smrg		if (norm != 0) {
1908d522f475Smrg		    XftPatternBuild(pat,
1909d522f475Smrg				    BoldXftPattern(norm),
1910d522f475Smrg				    (void *) 0);
1911956cc18dSsnj		    bold = OPEN_XFT("bold");
1912d522f475Smrg
1913d522f475Smrg#if OPT_ISO_COLORS
1914d522f475Smrg		    if (screen->italicULMode
191520d2c4d2Smrg			&& (pat = XftNameParse(face_name)) != 0) {
1916d522f475Smrg			XftPatternBuild(pat,
1917d522f475Smrg					NormXftPattern,
1918d522f475Smrg					ItalXftPattern(norm),
1919d522f475Smrg					(void *) 0);
1920956cc18dSsnj			ital = OPEN_XFT("italic");
1921d522f475Smrg		    }
1922d522f475Smrg#endif /* OPT_ISO_COLORS */
1923956cc18dSsnj#undef OPEN_XFT
1924d522f475Smrg
1925d522f475Smrg		    /*
1926d522f475Smrg		     * FIXME:  just assume that the corresponding font has no
1927d522f475Smrg		     * graphics characters.
1928d522f475Smrg		     */
1929d522f475Smrg		    if (screen->fnt_boxes) {
1930d522f475Smrg			screen->fnt_boxes = False;
1931d522f475Smrg			TRACE(("Xft opened - will %suse internal line-drawing characters\n",
1932d522f475Smrg			       screen->fnt_boxes ? "not " : ""));
1933d522f475Smrg		    }
1934d522f475Smrg		}
1935d522f475Smrg
1936d522f475Smrg		XftPatternDestroy(pat);
1937d522f475Smrg	    }
1938d522f475Smrg
1939d522f475Smrg	    CACHE_XFT(screen->renderFontNorm, norm);
1940d522f475Smrg	    CACHE_XFT(screen->renderFontBold, bold);
1941d522f475Smrg	    CACHE_XFT(screen->renderFontItal, ital);
1942d522f475Smrg
1943d522f475Smrg	    /*
1944d522f475Smrg	     * See xtermXftDrawString().
1945d522f475Smrg	     */
1946d522f475Smrg#if OPT_RENDERWIDE
1947d522f475Smrg	    if (norm != 0 && screen->wide_chars) {
1948d522f475Smrg		int char_width = norm->max_advance_width * 2;
1949956cc18dSsnj#ifdef FC_ASPECT
1950956cc18dSsnj		double aspect = ((xw->misc.face_wide_name
1951956cc18dSsnj				  || screen->renderFontNorm[fontnum].map.mixed)
1952956cc18dSsnj				 ? 1.0
1953956cc18dSsnj				 : 2.0);
1954956cc18dSsnj#endif
1955d522f475Smrg
195620d2c4d2Smrg		face_name = getFaceName(xw, True);
1957d522f475Smrg		TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n",
195820d2c4d2Smrg		       NonNull(face_name),
1959d522f475Smrg		       char_width));
1960d522f475Smrg
1961d522f475Smrg#define WideXftPattern \
1962d522f475Smrg		XFT_FAMILY, XftTypeString, "mono", \
1963d522f475Smrg		XFT_SIZE, XftTypeDouble, face_size, \
1964d522f475Smrg		XFT_SPACING, XftTypeInteger, XFT_MONO
1965d522f475Smrg
196620d2c4d2Smrg		if (face_name && (pat = XftNameParse(face_name)) != 0) {
1967956cc18dSsnj#define OPEN_XFT(tag) xtermOpenXft(xw, face_name, pat, tag)
1968d522f475Smrg		    XftPatternBuild(pat,
1969d522f475Smrg				    WideXftPattern,
1970d522f475Smrg				    XFT_CHAR_WIDTH, XftTypeInteger, char_width,
1971956cc18dSsnj#ifdef FC_ASPECT
1972956cc18dSsnj				    FC_ASPECT, XftTypeDouble, aspect,
1973956cc18dSsnj#endif
1974d522f475Smrg				    (void *) 0);
1975956cc18dSsnj		    wnorm = OPEN_XFT("wide");
1976d522f475Smrg
1977d522f475Smrg		    if (wnorm != 0) {
1978d522f475Smrg			XftPatternBuild(pat,
1979d522f475Smrg					WideXftPattern,
1980d522f475Smrg					BoldXftPattern(wnorm),
1981d522f475Smrg					(void *) 0);
1982956cc18dSsnj			wbold = OPEN_XFT("wide-bold");
1983d522f475Smrg
1984d522f475Smrg#if OPT_ISO_COLORS
1985d522f475Smrg			if (screen->italicULMode
1986d522f475Smrg			    && (pat = XftNameParse(face_name)) != 0) {
1987d522f475Smrg			    XftPatternBuild(pat,
1988d522f475Smrg					    WideXftPattern,
1989d522f475Smrg					    ItalXftPattern(wnorm),
1990d522f475Smrg					    (void *) 0);
1991956cc18dSsnj			    wital = OPEN_XFT("wide-italic");
1992d522f475Smrg			}
1993d522f475Smrg#endif
1994956cc18dSsnj#undef OPEN_XFT
1995d522f475Smrg		    }
1996d522f475Smrg		    XftPatternDestroy(pat);
1997d522f475Smrg		}
1998d522f475Smrg
1999d522f475Smrg		CACHE_XFT(screen->renderWideNorm, wnorm);
2000d522f475Smrg		CACHE_XFT(screen->renderWideBold, wbold);
2001d522f475Smrg		CACHE_XFT(screen->renderWideItal, wital);
2002d522f475Smrg	    }
2003d522f475Smrg#endif /* OPT_RENDERWIDE */
2004d522f475Smrg	}
2005d522f475Smrg	if (norm == 0) {
20062eaa94a1Schristos	    TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum));
2007d522f475Smrg	    xw->misc.render_font = False;
2008d522f475Smrg	    update_font_renderfont();
2009d522f475Smrg	    /* now we will fall through into the bitmap fonts */
2010d522f475Smrg	} else {
2011d522f475Smrg	    setRenderFontsize(screen, win, norm, NULL);
2012d522f475Smrg	    setRenderFontsize(screen, win, bold, "bold");
2013d522f475Smrg	    setRenderFontsize(screen, win, ital, "ital");
201420d2c4d2Smrg#if OPT_BOX_CHARS
201520d2c4d2Smrg	    setupPackedFonts(xw);
201620d2c4d2Smrg
201720d2c4d2Smrg	    if (screen->force_packed) {
201820d2c4d2Smrg		XTermXftFonts *use = &(screen->renderFontNorm[fontnum]);
201920d2c4d2Smrg		win->f_height = use->font->ascent + use->font->descent;
202020d2c4d2Smrg		win->f_width = use->map.min_width;
202120d2c4d2Smrg		TRACE(("...packed TrueType font %dx%d vs %d\n",
202220d2c4d2Smrg		       win->f_height,
202320d2c4d2Smrg		       win->f_width,
202420d2c4d2Smrg		       use->map.max_width));
202520d2c4d2Smrg	    }
202620d2c4d2Smrg#endif
202720d2c4d2Smrg	    DUMP_XFT(xw, &(screen->renderFontNorm[fontnum]));
2028d522f475Smrg	}
2029d522f475Smrg    }
2030d522f475Smrg    /*
2031d522f475Smrg     * Are we handling a bitmap font?
2032d522f475Smrg     */
203320d2c4d2Smrg    if (!UsingRenderFont(xw))
2034d522f475Smrg#endif /* OPT_RENDERFONT */
2035d522f475Smrg    {
203620d2c4d2Smrg	if (is_double_width_font(font) && !(screen->fnt_prop)) {
2037d522f475Smrg	    win->f_width = (font->min_bounds.width);
2038d522f475Smrg	} else {
2039d522f475Smrg	    win->f_width = (font->max_bounds.width);
2040d522f475Smrg	}
2041d522f475Smrg	win->f_height = (font->ascent + font->descent);
2042d522f475Smrg	win->f_ascent = font->ascent;
2043d522f475Smrg	win->f_descent = font->descent;
2044d522f475Smrg    }
2045d522f475Smrg    i = 2 * screen->border + sbwidth;
2046d522f475Smrg    j = 2 * screen->border;
2047d522f475Smrg    width = MaxCols(screen) * win->f_width + i;
2048d522f475Smrg    height = MaxRows(screen) * win->f_height + j;
2049956cc18dSsnj    win->fullwidth = (Dimension) width;
2050956cc18dSsnj    win->fullheight = (Dimension) height;
2051d522f475Smrg    win->width = width - i;
2052d522f475Smrg    win->height = height - j;
2053d522f475Smrg
2054d522f475Smrg    TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n",
2055d522f475Smrg	   win->height,
2056d522f475Smrg	   win->width,
2057d522f475Smrg	   win->fullheight,
2058d522f475Smrg	   win->fullwidth,
2059d522f475Smrg	   win->f_height,
2060d522f475Smrg	   win->f_width,
2061d522f475Smrg	   win->f_ascent,
2062d522f475Smrg	   win->f_descent));
206320d2c4d2Smrg
206420d2c4d2Smrg    checkFontInfo(win->f_height, "height");
206520d2c4d2Smrg    checkFontInfo(win->f_width, "width");
2066d522f475Smrg}
2067d522f475Smrg
2068d522f475Smrg/* save this information as a side-effect for double-sized characters */
2069d522f475Smrgvoid
2070d522f475SmrgxtermSaveFontInfo(TScreen * screen, XFontStruct * font)
2071d522f475Smrg{
2072956cc18dSsnj    screen->fnt_wide = (Dimension) (font->max_bounds.width);
2073956cc18dSsnj    screen->fnt_high = (Dimension) (font->ascent + font->descent);
2074d522f475Smrg    TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide));
2075d522f475Smrg}
2076d522f475Smrg
2077d522f475Smrg/*
2078d522f475Smrg * After loading a new font, update the structures that use its size.
2079d522f475Smrg */
2080d522f475Smrgvoid
2081d522f475SmrgxtermUpdateFontInfo(XtermWidget xw, Bool doresize)
2082d522f475Smrg{
2083956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2084d522f475Smrg
2085d522f475Smrg    int scrollbar_width;
2086d522f475Smrg    VTwin *win = &(screen->fullVwin);
2087d522f475Smrg
2088d522f475Smrg    scrollbar_width = (xw->misc.scrollbar
2089d522f475Smrg		       ? (screen->scrollWidget->core.width +
2090d522f475Smrg			  BorderWidth(screen->scrollWidget))
2091d522f475Smrg		       : 0);
2092d522f475Smrg    xtermComputeFontInfo(xw, win, screen->fnts[fNorm].fs, scrollbar_width);
2093d522f475Smrg    xtermSaveFontInfo(screen, screen->fnts[fNorm].fs);
2094d522f475Smrg
2095d522f475Smrg    if (doresize) {
2096d522f475Smrg	if (VWindow(screen)) {
2097d522f475Smrg	    xtermClear(xw);
2098d522f475Smrg	}
2099d522f475Smrg	TRACE(("xtermUpdateFontInfo {{\n"));
2100d522f475Smrg	DoResizeScreen(xw);	/* set to the new natural size */
2101d522f475Smrg	ResizeScrollBar(xw);
2102d522f475Smrg	Redraw();
2103d522f475Smrg	TRACE(("... }} xtermUpdateFontInfo\n"));
2104d522f475Smrg#ifdef SCROLLBAR_RIGHT
2105d522f475Smrg	updateRightScrollbar(xw);
2106d522f475Smrg#endif
2107d522f475Smrg    }
2108d522f475Smrg    xtermSetCursorBox(screen);
2109d522f475Smrg}
2110d522f475Smrg
2111d522f475Smrg#if OPT_BOX_CHARS
2112d522f475Smrg
2113d522f475Smrg/*
2114d522f475Smrg * Returns true if the given character is missing from the specified font.
2115d522f475Smrg */
2116d522f475SmrgBool
2117956cc18dSsnjxtermMissingChar(unsigned ch, XTermFonts * font)
2118d522f475Smrg{
2119956cc18dSsnj    Bool result = False;
2120956cc18dSsnj    XFontStruct *fs = font->fs;
2121956cc18dSsnj    static XCharStruct dft, *tmp = &dft, *pc = 0;
2122d522f475Smrg
2123956cc18dSsnj    if (fs->max_byte1 == 0) {
2124d522f475Smrg#if OPT_WIDE_CHARS
2125956cc18dSsnj	if (ch > 255) {
2126956cc18dSsnj	    TRACE(("xtermMissingChar %#04x (row)\n", ch));
2127956cc18dSsnj	    return True;
2128d522f475Smrg	}
2129956cc18dSsnj#endif
2130956cc18dSsnj	CI_GET_CHAR_INFO_1D(fs, E2A(ch), tmp, pc);
2131956cc18dSsnj    }
2132d522f475Smrg#if OPT_WIDE_CHARS
2133956cc18dSsnj    else {
2134956cc18dSsnj	CI_GET_CHAR_INFO_2D(fs, HI_BYTE(ch), LO_BYTE(ch), tmp, pc);
2135956cc18dSsnj    }
2136d522f475Smrg#else
2137d522f475Smrg
2138956cc18dSsnj    if (!pc)
2139956cc18dSsnj	return False;		/* Urgh! */
2140d522f475Smrg#endif
2141d522f475Smrg
2142956cc18dSsnj    if (CI_NONEXISTCHAR(pc)) {
2143956cc18dSsnj	TRACE(("xtermMissingChar %#04x (!exists)\n", ch));
2144956cc18dSsnj	result = True;
2145d522f475Smrg    }
2146956cc18dSsnj    if (ch < 256) {
2147956cc18dSsnj	font->known_missing[ch] = (Char) (result ? 2 : 1);
2148d522f475Smrg    }
2149956cc18dSsnj    return result;
2150d522f475Smrg}
2151d522f475Smrg
2152d522f475Smrg/*
2153d522f475Smrg * The grid is arbitrary, enough resolution that nothing's lost in
2154d522f475Smrg * initialization.
2155d522f475Smrg */
2156d522f475Smrg#define BOX_HIGH 60
2157d522f475Smrg#define BOX_WIDE 60
2158d522f475Smrg
2159d522f475Smrg#define MID_HIGH (BOX_HIGH/2)
2160d522f475Smrg#define MID_WIDE (BOX_WIDE/2)
2161d522f475Smrg
2162d522f475Smrg#define CHR_WIDE ((9*BOX_WIDE)/10)
2163d522f475Smrg#define CHR_HIGH ((9*BOX_HIGH)/10)
2164d522f475Smrg
2165d522f475Smrg/*
2166d522f475Smrg * ...since we'll scale the values anyway.
2167d522f475Smrg */
2168956cc18dSsnj#define SCALE_X(n) n = (n * (((int) font_width) - 1)) / (BOX_WIDE-1)
2169956cc18dSsnj#define SCALE_Y(n) n = (n * (((int) font_height) - 1)) / (BOX_HIGH-1)
2170d522f475Smrg
2171d522f475Smrg#define SEG(x0,y0,x1,y1) x0,y0, x1,y1
2172d522f475Smrg
2173d522f475Smrg/*
2174d522f475Smrg * Draw the given graphic character, if it is simple enough (i.e., a
2175d522f475Smrg * line-drawing character).
2176d522f475Smrg */
2177d522f475Smrgvoid
2178d522f475SmrgxtermDrawBoxChar(XtermWidget xw,
2179d522f475Smrg		 unsigned ch,
2180d522f475Smrg		 unsigned flags,
2181d522f475Smrg		 GC gc,
2182d522f475Smrg		 int x,
2183d522f475Smrg		 int y,
2184d522f475Smrg		 int cells)
2185d522f475Smrg{
2186956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2187d522f475Smrg    /* *INDENT-OFF* */
2188d522f475Smrg    static const short glyph_ht[] = {
2189d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,5*MID_HIGH/6),	/* H */
2190d522f475Smrg	SEG(6*BOX_WIDE/10,  0,		6*BOX_WIDE/10,5*MID_HIGH/6),
2191d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12),
2192d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
2193d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
2194d522f475Smrg	-1
2195d522f475Smrg    }, glyph_ff[] = {
2196d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		6*BOX_WIDE/10,	0),		/* F */
2197d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12),
2198d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		0*BOX_WIDE/3, 5*MID_HIGH/6),
2199d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
2200d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
2201d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
2202d522f475Smrg	-1
2203d522f475Smrg    }, glyph_lf[] = {
2204d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,9*MID_HIGH/12),	/* L */
2205d522f475Smrg	SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12),
2206d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
2207d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
2208d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
2209d522f475Smrg	-1
2210d522f475Smrg    }, glyph_nl[] = {
2211d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10,	0),		/* N */
2212d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		5*BOX_WIDE/6, 5*MID_HIGH/6),
2213d522f475Smrg	SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
2214d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),	/* L */
2215d522f475Smrg	SEG(1*BOX_WIDE/3,   CHR_HIGH,	  CHR_WIDE,	CHR_HIGH),
2216d522f475Smrg	-1
2217d522f475Smrg    }, glyph_vt[] = {
2218d522f475Smrg	SEG(1*BOX_WIDE/10,   0,		5*BOX_WIDE/12,5*MID_HIGH/6),	/* V */
2219d522f475Smrg	SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
2220d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
2221d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
2222d522f475Smrg	-1
2223d522f475Smrg    }, plus_or_minus[] =
2224d522f475Smrg    {
2225d522f475Smrg	SEG(  0,	  5*BOX_HIGH/6,	  CHR_WIDE,   5*BOX_HIGH/6),
2226d522f475Smrg	SEG(  MID_WIDE,	  2*BOX_HIGH/6,	  MID_WIDE,   4*BOX_HIGH/6),
2227d522f475Smrg	SEG(  0,	  3*BOX_HIGH/6,	  CHR_WIDE,   3*BOX_HIGH/6),
2228d522f475Smrg	-1
2229d522f475Smrg    }, lower_right_corner[] =
2230d522f475Smrg    {
2231d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
2232d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	0),
2233d522f475Smrg	-1
2234d522f475Smrg    }, upper_right_corner[] =
2235d522f475Smrg    {
2236d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
2237d522f475Smrg	SEG( MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
2238d522f475Smrg	-1
2239d522f475Smrg    }, upper_left_corner[] =
2240d522f475Smrg    {
2241d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2242d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
2243d522f475Smrg	-1
2244d522f475Smrg    }, lower_left_corner[] =
2245d522f475Smrg    {
2246d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
2247d522f475Smrg	SEG(  MID_WIDE,	    MID_WIDE,	  BOX_WIDE,	MID_HIGH),
2248d522f475Smrg	-1
2249d522f475Smrg    }, cross[] =
2250d522f475Smrg    {
2251d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2252d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2253d522f475Smrg	-1
2254d522f475Smrg    }, scan_line_1[] =
2255d522f475Smrg    {
2256d522f475Smrg	SEG(  0,	    0,		  BOX_WIDE,	0),
2257d522f475Smrg	-1
2258d522f475Smrg    }, scan_line_3[] =
2259d522f475Smrg    {
2260d522f475Smrg	SEG(  0,	    BOX_HIGH/4,	  BOX_WIDE,	BOX_HIGH/4),
2261d522f475Smrg	-1
2262d522f475Smrg    }, scan_line_7[] =
2263d522f475Smrg    {
2264d522f475Smrg	SEG( 0,		    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2265d522f475Smrg	-1
2266d522f475Smrg    }, scan_line_9[] =
2267d522f475Smrg    {
2268d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  BOX_WIDE,   3*BOX_HIGH/4),
2269d522f475Smrg	-1
2270d522f475Smrg    }, horizontal_line[] =
2271d522f475Smrg    {
2272d522f475Smrg	SEG(  0,	    BOX_HIGH,	  BOX_WIDE,	BOX_HIGH),
2273d522f475Smrg	-1
2274d522f475Smrg    }, left_tee[] =
2275d522f475Smrg    {
2276d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2277d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2278d522f475Smrg	-1
2279d522f475Smrg    }, right_tee[] =
2280d522f475Smrg    {
2281d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2282d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  0,		MID_HIGH),
2283d522f475Smrg	-1
2284d522f475Smrg    }, bottom_tee[] =
2285d522f475Smrg    {
2286d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2287d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
2288d522f475Smrg	-1
2289d522f475Smrg    }, top_tee[] =
2290d522f475Smrg    {
2291d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2292d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
2293d522f475Smrg	-1
2294d522f475Smrg    }, vertical_line[] =
2295d522f475Smrg    {
2296d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2297d522f475Smrg	-1
2298d522f475Smrg    }, less_than_or_equal[] =
2299d522f475Smrg    {
2300d522f475Smrg	SEG(  CHR_WIDE,	    BOX_HIGH/3,	  0,		MID_HIGH),
2301d522f475Smrg	SEG(  CHR_WIDE,	  2*BOX_HIGH/3,	  0,		MID_HIGH),
2302d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
2303d522f475Smrg	-1
2304d522f475Smrg    }, greater_than_or_equal[] =
2305d522f475Smrg    {
2306d522f475Smrg	SEG(  0,	    BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
2307d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
2308d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
2309d522f475Smrg	-1
2310d522f475Smrg    }, greek_pi[] =
2311d522f475Smrg    {
2312d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
2313d522f475Smrg	SEG(5*CHR_WIDE/6,   MID_HIGH,	5*CHR_WIDE/6,	CHR_HIGH),
2314d522f475Smrg	SEG(2*CHR_WIDE/6,   MID_HIGH,	2*CHR_WIDE/6,	CHR_HIGH),
2315d522f475Smrg	-1
2316d522f475Smrg    }, not_equal_to[] =
2317d522f475Smrg    {
2318d522f475Smrg	SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3,	CHR_HIGH),
2319d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,   2*BOX_HIGH/3),
2320d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
2321d522f475Smrg	-1
2322d522f475Smrg    };
2323d522f475Smrg    /* *INDENT-ON* */
2324d522f475Smrg
2325d522f475Smrg    static const short *lines[] =
2326d522f475Smrg    {
2327d522f475Smrg	0,			/* 00 (unused) */
2328d522f475Smrg	0,			/* 01 diamond */
2329d522f475Smrg	0,			/* 02 box */
2330d522f475Smrg	glyph_ht,		/* 03 HT */
2331d522f475Smrg	glyph_ff,		/* 04 FF */
2332d522f475Smrg	0,			/* 05 CR */
2333d522f475Smrg	glyph_lf,		/* 06 LF */
2334d522f475Smrg	0,			/* 07 degrees (small circle) */
2335d522f475Smrg	plus_or_minus,		/* 08 */
2336d522f475Smrg	glyph_nl,		/* 09 */
2337d522f475Smrg	glyph_vt,		/* 0A */
2338d522f475Smrg	lower_right_corner,	/* 0B */
2339d522f475Smrg	upper_right_corner,	/* 0C */
2340d522f475Smrg	upper_left_corner,	/* 0D */
2341d522f475Smrg	lower_left_corner,	/* 0E */
2342d522f475Smrg	cross,			/* 0F */
2343d522f475Smrg	scan_line_1,		/* 10 */
2344d522f475Smrg	scan_line_3,		/* 11 */
2345d522f475Smrg	scan_line_7,		/* 12 */
2346d522f475Smrg	scan_line_9,		/* 13 */
2347d522f475Smrg	horizontal_line,	/* 14 */
2348d522f475Smrg	left_tee,		/* 15 */
2349d522f475Smrg	right_tee,		/* 16 */
2350d522f475Smrg	bottom_tee,		/* 17 */
2351d522f475Smrg	top_tee,		/* 18 */
2352d522f475Smrg	vertical_line,		/* 19 */
2353d522f475Smrg	less_than_or_equal,	/* 1A */
2354d522f475Smrg	greater_than_or_equal,	/* 1B */
2355d522f475Smrg	greek_pi,		/* 1C */
2356d522f475Smrg	not_equal_to,		/* 1D */
2357d522f475Smrg	0,			/* 1E LB */
2358d522f475Smrg	0,			/* 1F bullet */
2359d522f475Smrg    };
2360d522f475Smrg
2361d522f475Smrg    GC gc2;
2362d522f475Smrg    CgsEnum cgsId = (ch == 2) ? gcDots : gcLine;
2363d522f475Smrg    VTwin *cgsWin = WhichVWin(screen);
2364d522f475Smrg    const short *p;
2365956cc18dSsnj    unsigned font_width = (unsigned) (((flags & DOUBLEWFONT) ? 2 : 1) * screen->fnt_wide);
2366956cc18dSsnj    unsigned font_height = (unsigned) (((flags & DOUBLEHFONT) ? 2 : 1) * screen->fnt_high);
2367d522f475Smrg
2368d522f475Smrg    if (cells > 1)
2369956cc18dSsnj	font_width *= (unsigned) cells;
2370d522f475Smrg
2371d522f475Smrg#if OPT_WIDE_CHARS
2372d522f475Smrg    /*
2373d522f475Smrg     * Try to show line-drawing characters if we happen to be in UTF-8
2374d522f475Smrg     * mode, but have gotten an old-style font.
2375d522f475Smrg     */
2376d522f475Smrg    if (screen->utf8_mode
2377d522f475Smrg#if OPT_RENDERFONT
2378d522f475Smrg	&& !UsingRenderFont(xw)
2379d522f475Smrg#endif
2380d522f475Smrg	&& (ch > 127)
2381d522f475Smrg	&& (ch != UCS_REPL)) {
2382d522f475Smrg	unsigned n;
2383d522f475Smrg	for (n = 1; n < 32; n++) {
2384d522f475Smrg	    if (dec2ucs(n) == ch
238520d2c4d2Smrg		&& !((flags & BOLD)
238620d2c4d2Smrg		     ? IsXtermMissingChar(screen, n, &screen->fnts[fBold])
238720d2c4d2Smrg		     : IsXtermMissingChar(screen, n, &screen->fnts[fNorm]))) {
2388d522f475Smrg		TRACE(("...use xterm-style linedrawing\n"));
2389d522f475Smrg		ch = n;
2390d522f475Smrg		break;
2391d522f475Smrg	    }
2392d522f475Smrg	}
2393d522f475Smrg    }
2394d522f475Smrg#endif
2395d522f475Smrg
2396d522f475Smrg    TRACE(("DRAW_BOX(%d) cell %dx%d at %d,%d%s\n",
2397d522f475Smrg	   ch, font_height, font_width, y, x,
2398d522f475Smrg	   (ch >= (sizeof(lines) / sizeof(lines[0]))
2399d522f475Smrg	    ? "-BAD"
2400d522f475Smrg	    : "")));
2401d522f475Smrg
2402d522f475Smrg    if (cgsId == gcDots) {
2403d522f475Smrg	setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2404d522f475Smrg	setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc));
2405d522f475Smrg	setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2406d522f475Smrg    } else {
2407d522f475Smrg	setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2408d522f475Smrg	setCgsFore(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2409d522f475Smrg	setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2410d522f475Smrg    }
2411d522f475Smrg    gc2 = getCgsGC(xw, cgsWin, cgsId);
2412d522f475Smrg
2413d522f475Smrg    if (!(flags & NOBACKGROUND)) {
2414d522f475Smrg	XFillRectangle(screen->display, VWindow(screen), gc2, x, y,
2415d522f475Smrg		       font_width,
2416d522f475Smrg		       font_height);
2417d522f475Smrg    }
2418d522f475Smrg
2419d522f475Smrg    setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2420d522f475Smrg    setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc));
2421d522f475Smrg    setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2422d522f475Smrg    gc2 = getCgsGC(xw, cgsWin, cgsId);
2423d522f475Smrg
2424d522f475Smrg    XSetLineAttributes(screen->display, gc2,
2425d522f475Smrg		       (flags & BOLD)
2426d522f475Smrg		       ? ((font_height > 12)
2427d522f475Smrg			  ? font_height / 12
2428d522f475Smrg			  : 1)
2429d522f475Smrg		       : ((font_height > 16)
2430d522f475Smrg			  ? font_height / 16
2431d522f475Smrg			  : 1),
2432d522f475Smrg		       LineSolid,
2433d522f475Smrg		       CapProjecting,
2434d522f475Smrg		       JoinMiter);
2435d522f475Smrg
2436d522f475Smrg    if (ch == 1) {		/* diamond */
2437d522f475Smrg	XPoint points[5];
2438d522f475Smrg	int npoints = 5, n;
2439d522f475Smrg
2440d522f475Smrg	points[0].x = MID_WIDE;
2441d522f475Smrg	points[0].y = BOX_HIGH / 4;
2442d522f475Smrg
2443d522f475Smrg	points[1].x = 8 * BOX_WIDE / 8;
2444d522f475Smrg	points[1].y = MID_HIGH;
2445d522f475Smrg
2446d522f475Smrg	points[2].x = points[0].x;
2447d522f475Smrg	points[2].y = 3 * BOX_HIGH / 4;
2448d522f475Smrg
2449d522f475Smrg	points[3].x = 0 * BOX_WIDE / 8;
2450d522f475Smrg	points[3].y = points[1].y;
2451d522f475Smrg
2452d522f475Smrg	points[4].x = points[0].x;
2453d522f475Smrg	points[4].y = points[0].y;
2454d522f475Smrg
2455d522f475Smrg	for (n = 0; n < npoints; ++n) {
2456d522f475Smrg	    SCALE_X(points[n].x);
2457d522f475Smrg	    SCALE_Y(points[n].y);
2458d522f475Smrg	    points[n].x += x;
2459d522f475Smrg	    points[n].y += y;
2460d522f475Smrg	}
2461d522f475Smrg
2462d522f475Smrg	XFillPolygon(screen->display,
2463d522f475Smrg		     VWindow(screen), gc2,
2464d522f475Smrg		     points, npoints,
2465d522f475Smrg		     Convex, CoordModeOrigin);
2466d522f475Smrg    } else if (ch == 7) {	/* degrees */
2467d522f475Smrg	unsigned width = (BOX_WIDE / 3);
2468956cc18dSsnj	int x_coord = MID_WIDE - (int) (width / 2);
2469956cc18dSsnj	int y_coord = MID_HIGH - (int) width;
2470d522f475Smrg
2471d522f475Smrg	SCALE_X(x_coord);
2472d522f475Smrg	SCALE_Y(y_coord);
2473d522f475Smrg	SCALE_X(width);
2474d522f475Smrg
2475d522f475Smrg	XDrawArc(screen->display,
2476d522f475Smrg		 VWindow(screen), gc2,
2477d522f475Smrg		 x + x_coord, y + y_coord, width, width,
2478d522f475Smrg		 0,
2479d522f475Smrg		 360 * 64);
2480d522f475Smrg    } else if (ch == 0x1f) {	/* bullet */
2481d522f475Smrg	unsigned width = 7 * BOX_WIDE / 10;
2482956cc18dSsnj	int x_coord = MID_WIDE - (int) (width / 3);
2483956cc18dSsnj	int y_coord = MID_HIGH - (int) (width / 3);
2484d522f475Smrg
2485d522f475Smrg	SCALE_X(x_coord);
2486d522f475Smrg	SCALE_Y(y_coord);
2487d522f475Smrg	SCALE_X(width);
2488d522f475Smrg
2489d522f475Smrg	XDrawArc(screen->display,
2490d522f475Smrg		 VWindow(screen), gc2,
2491d522f475Smrg		 x + x_coord, y + y_coord, width, width,
2492d522f475Smrg		 0,
2493d522f475Smrg		 360 * 64);
2494d522f475Smrg    } else if (ch < (sizeof(lines) / sizeof(lines[0]))
2495d522f475Smrg	       && (p = lines[ch]) != 0) {
2496956cc18dSsnj	int coord[4];
2497d522f475Smrg	int n = 0;
2498d522f475Smrg	while (*p >= 0) {
2499d522f475Smrg	    coord[n++] = *p++;
2500d522f475Smrg	    if (n == 4) {
2501d522f475Smrg		SCALE_X(coord[0]);
2502d522f475Smrg		SCALE_Y(coord[1]);
2503d522f475Smrg		SCALE_X(coord[2]);
2504d522f475Smrg		SCALE_Y(coord[3]);
2505d522f475Smrg		XDrawLine(screen->display,
2506d522f475Smrg			  VWindow(screen), gc2,
2507d522f475Smrg			  x + coord[0], y + coord[1],
2508d522f475Smrg			  x + coord[2], y + coord[3]);
2509d522f475Smrg		n = 0;
2510d522f475Smrg	    }
2511d522f475Smrg	}
2512d522f475Smrg    } else if (screen->force_all_chars) {
2513d522f475Smrg	/* bounding rectangle, for debugging */
2514d522f475Smrg	XDrawRectangle(screen->display, VWindow(screen), gc2, x, y,
2515d522f475Smrg		       font_width - 1,
2516d522f475Smrg		       font_height - 1);
2517d522f475Smrg    }
2518d522f475Smrg}
2519d522f475Smrg
2520d522f475Smrg#if OPT_RENDERFONT
2521d522f475Smrg
2522d522f475Smrg/*
2523d522f475Smrg * Check if the given character has a glyph known to Xft.
2524d522f475Smrg *
2525d522f475Smrg * see xc/lib/Xft/xftglyphs.c
2526d522f475Smrg */
2527d522f475SmrgBool
2528d522f475SmrgxtermXftMissing(XtermWidget xw, XftFont * font, unsigned wc)
2529d522f475Smrg{
2530d522f475Smrg    Bool result = False;
2531d522f475Smrg
2532d522f475Smrg    if (font != 0) {
2533956cc18dSsnj	TScreen *screen = TScreenOf(xw);
2534956cc18dSsnj	if (!XftGlyphExists(screen->display, font, wc)) {
2535d522f475Smrg#if OPT_WIDE_CHARS
2536d522f475Smrg	    TRACE(("xtermXftMissing %d (dec=%#x, ucs=%#x)\n",
2537d522f475Smrg		   wc, ucs2dec(wc), dec2ucs(wc)));
2538d522f475Smrg#else
2539d522f475Smrg	    TRACE(("xtermXftMissing %d\n", wc));
2540d522f475Smrg#endif
2541d522f475Smrg	    result = True;
2542d522f475Smrg	}
2543d522f475Smrg    }
2544d522f475Smrg    return result;
2545d522f475Smrg}
2546d522f475Smrg#endif /* OPT_RENDERFONT && OPT_WIDE_CHARS */
2547d522f475Smrg
2548d522f475Smrg#endif /* OPT_BOX_CHARS */
2549d522f475Smrg
2550d522f475Smrg#if OPT_WIDE_CHARS
2551d522f475Smrg#define MY_UCS(ucs,dec) case ucs: result = dec; break
2552d522f475Smrgunsigned
2553d522f475Smrgucs2dec(unsigned ch)
2554d522f475Smrg{
2555d522f475Smrg    unsigned result = ch;
2556d522f475Smrg    if ((ch > 127)
2557d522f475Smrg	&& (ch != UCS_REPL)) {
2558d522f475Smrg	switch (ch) {
2559d522f475Smrg	    MY_UCS(0x25ae, 0);	/* black vertical rectangle                   */
2560d522f475Smrg	    MY_UCS(0x25c6, 1);	/* black diamond                              */
2561d522f475Smrg	    MY_UCS(0x2592, 2);	/* medium shade                               */
2562d522f475Smrg	    MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation           */
2563d522f475Smrg	    MY_UCS(0x240c, 4);	/* symbol for form feed                       */
2564d522f475Smrg	    MY_UCS(0x240d, 5);	/* symbol for carriage return                 */
2565d522f475Smrg	    MY_UCS(0x240a, 6);	/* symbol for line feed                       */
2566d522f475Smrg	    MY_UCS(0x00b0, 7);	/* degree sign                                */
2567d522f475Smrg	    MY_UCS(0x00b1, 8);	/* plus-minus sign                            */
2568d522f475Smrg	    MY_UCS(0x2424, 9);	/* symbol for newline                         */
2569d522f475Smrg	    MY_UCS(0x240b, 10);	/* symbol for vertical tabulation             */
2570d522f475Smrg	    MY_UCS(0x2518, 11);	/* box drawings light up and left             */
2571d522f475Smrg	    MY_UCS(0x2510, 12);	/* box drawings light down and left           */
2572d522f475Smrg	    MY_UCS(0x250c, 13);	/* box drawings light down and right          */
2573d522f475Smrg	    MY_UCS(0x2514, 14);	/* box drawings light up and right            */
2574d522f475Smrg	    MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
2575d522f475Smrg	    MY_UCS(0x23ba, 16);	/* box drawings scan 1                        */
2576d522f475Smrg	    MY_UCS(0x23bb, 17);	/* box drawings scan 3                        */
2577d522f475Smrg	    MY_UCS(0x2500, 18);	/* box drawings light horizontal              */
2578d522f475Smrg	    MY_UCS(0x23bc, 19);	/* box drawings scan 7                        */
2579d522f475Smrg	    MY_UCS(0x23bd, 20);	/* box drawings scan 9                        */
2580d522f475Smrg	    MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
2581d522f475Smrg	    MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
2582d522f475Smrg	    MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
2583d522f475Smrg	    MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
2584d522f475Smrg	    MY_UCS(0x2502, 25);	/* box drawings light vertical                */
2585d522f475Smrg	    MY_UCS(0x2264, 26);	/* less-than or equal to                      */
2586d522f475Smrg	    MY_UCS(0x2265, 27);	/* greater-than or equal to                   */
2587d522f475Smrg	    MY_UCS(0x03c0, 28);	/* greek small letter pi                      */
2588d522f475Smrg	    MY_UCS(0x2260, 29);	/* not equal to                               */
2589d522f475Smrg	    MY_UCS(0x00a3, 30);	/* pound sign                                 */
2590d522f475Smrg	    MY_UCS(0x00b7, 31);	/* middle dot                                 */
2591d522f475Smrg	}
2592d522f475Smrg    }
2593d522f475Smrg    return result;
2594d522f475Smrg}
2595d522f475Smrg
2596d522f475Smrg#undef  MY_UCS
2597d522f475Smrg#define MY_UCS(ucs,dec) case dec: result = ucs; break
2598d522f475Smrg
2599d522f475Smrgunsigned
2600d522f475Smrgdec2ucs(unsigned ch)
2601d522f475Smrg{
2602d522f475Smrg    unsigned result = ch;
2603d522f475Smrg    if (xtermIsDecGraphic(ch)) {
2604d522f475Smrg	switch (ch) {
2605d522f475Smrg	    MY_UCS(0x25ae, 0);	/* black vertical rectangle                   */
2606d522f475Smrg	    MY_UCS(0x25c6, 1);	/* black diamond                              */
2607d522f475Smrg	    MY_UCS(0x2592, 2);	/* medium shade                               */
2608d522f475Smrg	    MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation           */
2609d522f475Smrg	    MY_UCS(0x240c, 4);	/* symbol for form feed                       */
2610d522f475Smrg	    MY_UCS(0x240d, 5);	/* symbol for carriage return                 */
2611d522f475Smrg	    MY_UCS(0x240a, 6);	/* symbol for line feed                       */
2612d522f475Smrg	    MY_UCS(0x00b0, 7);	/* degree sign                                */
2613d522f475Smrg	    MY_UCS(0x00b1, 8);	/* plus-minus sign                            */
2614d522f475Smrg	    MY_UCS(0x2424, 9);	/* symbol for newline                         */
2615d522f475Smrg	    MY_UCS(0x240b, 10);	/* symbol for vertical tabulation             */
2616d522f475Smrg	    MY_UCS(0x2518, 11);	/* box drawings light up and left             */
2617d522f475Smrg	    MY_UCS(0x2510, 12);	/* box drawings light down and left           */
2618d522f475Smrg	    MY_UCS(0x250c, 13);	/* box drawings light down and right          */
2619d522f475Smrg	    MY_UCS(0x2514, 14);	/* box drawings light up and right            */
2620d522f475Smrg	    MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
2621d522f475Smrg	    MY_UCS(0x23ba, 16);	/* box drawings scan 1                        */
2622d522f475Smrg	    MY_UCS(0x23bb, 17);	/* box drawings scan 3                        */
2623d522f475Smrg	    MY_UCS(0x2500, 18);	/* box drawings light horizontal              */
2624d522f475Smrg	    MY_UCS(0x23bc, 19);	/* box drawings scan 7                        */
2625d522f475Smrg	    MY_UCS(0x23bd, 20);	/* box drawings scan 9                        */
2626d522f475Smrg	    MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
2627d522f475Smrg	    MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
2628d522f475Smrg	    MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
2629d522f475Smrg	    MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
2630d522f475Smrg	    MY_UCS(0x2502, 25);	/* box drawings light vertical                */
2631d522f475Smrg	    MY_UCS(0x2264, 26);	/* less-than or equal to                      */
2632d522f475Smrg	    MY_UCS(0x2265, 27);	/* greater-than or equal to                   */
2633d522f475Smrg	    MY_UCS(0x03c0, 28);	/* greek small letter pi                      */
2634d522f475Smrg	    MY_UCS(0x2260, 29);	/* not equal to                               */
2635d522f475Smrg	    MY_UCS(0x00a3, 30);	/* pound sign                                 */
2636d522f475Smrg	    MY_UCS(0x00b7, 31);	/* middle dot                                 */
2637d522f475Smrg	}
2638d522f475Smrg    }
2639d522f475Smrg    return result;
2640d522f475Smrg}
2641d522f475Smrg
2642d522f475Smrg#endif /* OPT_WIDE_CHARS */
2643d522f475Smrg
2644d522f475Smrg#if OPT_SHIFT_FONTS
2645d522f475Smrgstatic void
2646d522f475SmrglookupOneFontSize(XtermWidget xw, int fontnum)
2647d522f475Smrg{
2648d522f475Smrg    TScreen *screen = TScreenOf(xw);
2649d522f475Smrg
2650d522f475Smrg    if (screen->menu_font_sizes[fontnum] == 0) {
2651d522f475Smrg	XTermFonts fnt;
2652d522f475Smrg
2653d522f475Smrg	memset(&fnt, 0, sizeof(fnt));
2654d522f475Smrg	screen->menu_font_sizes[fontnum] = -1;
2655956cc18dSsnj	if (xtermOpenFont(xw, screen->MenuFontName(fontnum), &fnt, fwAlways, True)) {
265620d2c4d2Smrg	    if (fontnum <= fontMenu_lastBuiltin
265720d2c4d2Smrg		|| strcmp(fnt.fn, DEFFONT))
265820d2c4d2Smrg		screen->menu_font_sizes[fontnum] = FontSize(fnt.fs);
2659d522f475Smrg	    xtermCloseFont(xw, &fnt);
2660d522f475Smrg	}
2661d522f475Smrg    }
2662d522f475Smrg}
2663d522f475Smrg
2664d522f475Smrg/*
2665d522f475Smrg * Cache the font-sizes so subsequent larger/smaller font actions will go fast.
2666d522f475Smrg */
2667d522f475Smrgstatic void
2668d522f475SmrglookupFontSizes(XtermWidget xw)
2669d522f475Smrg{
2670d522f475Smrg    int n;
2671d522f475Smrg
2672d522f475Smrg    for (n = 0; n < NMENUFONTS; n++) {
2673d522f475Smrg	lookupOneFontSize(xw, n);
2674d522f475Smrg    }
2675d522f475Smrg}
2676d522f475Smrg
26772eaa94a1Schristos#if OPT_RENDERFONT
26782eaa94a1Schristos#define NMENU_RENDERFONTS (NMENUFONTS - 2)	/* no selection or escape */
26792eaa94a1Schristosstatic Boolean
26802eaa94a1SchristosuseFaceSizes(XtermWidget xw)
26812eaa94a1Schristos{
26822eaa94a1Schristos    Boolean result = False;
26832eaa94a1Schristos    int n;
26842eaa94a1Schristos
26852eaa94a1Schristos    if (UsingRenderFont(xw)) {
26862eaa94a1Schristos	result = True;
26872eaa94a1Schristos	for (n = 0; n < NMENU_RENDERFONTS; ++n) {
26882eaa94a1Schristos	    if (xw->misc.face_size[n] <= 0.0) {
26892eaa94a1Schristos		result = False;
26902eaa94a1Schristos		break;
26912eaa94a1Schristos	    }
26922eaa94a1Schristos	}
2693956cc18dSsnj	if (!result) {
2694956cc18dSsnj	    Boolean broken_fonts = True;
2695956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
269620d2c4d2Smrg	    long first = screen->menu_font_sizes[0];
2697956cc18dSsnj
2698956cc18dSsnj	    lookupFontSizes(xw);
2699956cc18dSsnj	    for (n = 0; n < NMENUFONTS; n++) {
2700956cc18dSsnj		if (screen->menu_font_sizes[n] > 0
2701956cc18dSsnj		    && screen->menu_font_sizes[n] != first) {
2702956cc18dSsnj		    broken_fonts = False;
2703956cc18dSsnj		    break;
2704956cc18dSsnj		}
2705956cc18dSsnj	    }
2706956cc18dSsnj
2707956cc18dSsnj	    /*
2708956cc18dSsnj	     * Workaround for breakage in font-packages - check if all of the
2709956cc18dSsnj	     * bitmap font sizes are the same, and if we're using TrueType
2710956cc18dSsnj	     * fonts.
2711956cc18dSsnj	     */
2712956cc18dSsnj	    if (broken_fonts) {
2713956cc18dSsnj		float lo_value = (float) 9.0e9;
2714956cc18dSsnj		float hi_value = (float) 0.0;
2715956cc18dSsnj		float value;
2716956cc18dSsnj
2717956cc18dSsnj		TRACE(("bitmap fonts are broken - set faceSize resources\n"));
2718956cc18dSsnj		for (n = 0; n < NMENUFONTS; n++) {
2719956cc18dSsnj		    value = xw->misc.face_size[n];
2720956cc18dSsnj		    if (value > 0.0) {
2721956cc18dSsnj			if (lo_value > value)
2722956cc18dSsnj			    lo_value = value;
2723956cc18dSsnj			if (hi_value < value)
2724956cc18dSsnj			    hi_value = value;
2725956cc18dSsnj		    }
2726956cc18dSsnj		}
2727956cc18dSsnj
2728956cc18dSsnj		if (hi_value <= 0.0)
2729956cc18dSsnj		    sscanf(DEFFACESIZE, "%f", &value);
2730956cc18dSsnj		else
2731956cc18dSsnj		    value = (float) ((hi_value + lo_value) / 2.0);
2732956cc18dSsnj		if (value <= 0)
2733956cc18dSsnj		    value = (float) 14.0;
2734956cc18dSsnj
2735956cc18dSsnj		for (n = 0; n < NMENUFONTS; n++) {
2736956cc18dSsnj		    TRACE(("setting faceSize%d %.1f\n", n, value));
2737956cc18dSsnj		    xw->misc.face_size[n] = value;
2738956cc18dSsnj		    value = (float) (value * 1.1);
2739956cc18dSsnj		}
2740956cc18dSsnj		result = True;
2741956cc18dSsnj	    }
2742956cc18dSsnj	}
27432eaa94a1Schristos    }
27442eaa94a1Schristos    return result;
27452eaa94a1Schristos}
27462eaa94a1Schristos#endif
27472eaa94a1Schristos
2748d522f475Smrg/*
2749d522f475Smrg * Find the index of a larger/smaller font (according to the sign of 'relative'
2750d522f475Smrg * and its magnitude), starting from the 'old' index.
2751d522f475Smrg */
2752d522f475Smrgint
2753d522f475SmrglookupRelativeFontSize(XtermWidget xw, int old, int relative)
2754d522f475Smrg{
2755d522f475Smrg    TScreen *screen = TScreenOf(xw);
2756d522f475Smrg    int n, m = -1;
2757d522f475Smrg
27582eaa94a1Schristos    TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative));
2759d522f475Smrg    if (!IsIcon(screen)) {
27602eaa94a1Schristos#if OPT_RENDERFONT
27612eaa94a1Schristos	if (useFaceSizes(xw)) {
27622eaa94a1Schristos	    TRACE(("...using FaceSize\n"));
27632eaa94a1Schristos	    if (relative != 0) {
27642eaa94a1Schristos		for (n = 0; n < NMENU_RENDERFONTS; ++n) {
27652eaa94a1Schristos		    if (xw->misc.face_size[n] > 0 &&
27662eaa94a1Schristos			xw->misc.face_size[n] != xw->misc.face_size[old]) {
27672eaa94a1Schristos			int cmp_0 = ((xw->misc.face_size[n] >
27682eaa94a1Schristos				      xw->misc.face_size[old])
27692eaa94a1Schristos				     ? relative
27702eaa94a1Schristos				     : -relative);
27712eaa94a1Schristos			int cmp_m = ((m < 0)
27722eaa94a1Schristos				     ? 1
27732eaa94a1Schristos				     : ((xw->misc.face_size[n] <
27742eaa94a1Schristos					 xw->misc.face_size[m])
27752eaa94a1Schristos					? relative
27762eaa94a1Schristos					: -relative));
27772eaa94a1Schristos			if (cmp_0 > 0 && cmp_m > 0) {
27782eaa94a1Schristos			    m = n;
27792eaa94a1Schristos			}
2780d522f475Smrg		    }
2781d522f475Smrg		}
2782d522f475Smrg	    }
27832eaa94a1Schristos	} else
27842eaa94a1Schristos#endif
27852eaa94a1Schristos	{
27862eaa94a1Schristos	    TRACE(("...using bitmap areas\n"));
27872eaa94a1Schristos	    lookupFontSizes(xw);
27882eaa94a1Schristos	    if (relative != 0) {
27892eaa94a1Schristos		for (n = 0; n < NMENUFONTS; ++n) {
27902eaa94a1Schristos		    if (screen->menu_font_sizes[n] > 0 &&
27912eaa94a1Schristos			screen->menu_font_sizes[n] !=
27922eaa94a1Schristos			screen->menu_font_sizes[old]) {
27932eaa94a1Schristos			int cmp_0 = ((screen->menu_font_sizes[n] >
27942eaa94a1Schristos				      screen->menu_font_sizes[old])
27952eaa94a1Schristos				     ? relative
27962eaa94a1Schristos				     : -relative);
27972eaa94a1Schristos			int cmp_m = ((m < 0)
27982eaa94a1Schristos				     ? 1
27992eaa94a1Schristos				     : ((screen->menu_font_sizes[n] <
28002eaa94a1Schristos					 screen->menu_font_sizes[m])
28012eaa94a1Schristos					? relative
28022eaa94a1Schristos					: -relative));
28032eaa94a1Schristos			if (cmp_0 > 0 && cmp_m > 0) {
28042eaa94a1Schristos			    m = n;
28052eaa94a1Schristos			}
28062eaa94a1Schristos		    }
28072eaa94a1Schristos		}
2808d522f475Smrg	    }
2809d522f475Smrg	}
28102eaa94a1Schristos	TRACE(("...new index %d\n", m));
28112eaa94a1Schristos	if (m >= 0) {
28122eaa94a1Schristos	    if (relative > 1)
28132eaa94a1Schristos		m = lookupRelativeFontSize(xw, m, relative - 1);
28142eaa94a1Schristos	    else if (relative < -1)
28152eaa94a1Schristos		m = lookupRelativeFontSize(xw, m, relative + 1);
28162eaa94a1Schristos	}
2817d522f475Smrg    }
2818d522f475Smrg    return m;
2819d522f475Smrg}
2820d522f475Smrg
2821d522f475Smrg/* ARGSUSED */
2822d522f475Smrgvoid
2823d522f475SmrgHandleLargerFont(Widget w GCC_UNUSED,
2824d522f475Smrg		 XEvent * event GCC_UNUSED,
2825d522f475Smrg		 String * params GCC_UNUSED,
2826d522f475Smrg		 Cardinal *param_count GCC_UNUSED)
2827d522f475Smrg{
2828956cc18dSsnj    XtermWidget xw;
2829d522f475Smrg
283020d2c4d2Smrg    TRACE(("Handle larger-vt-font for %p\n", (void *) w));
2831956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
2832d522f475Smrg	if (xw->misc.shift_fonts) {
2833956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
2834d522f475Smrg	    int m;
2835d522f475Smrg
2836d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, 1);
2837d522f475Smrg	    if (m >= 0) {
2838d522f475Smrg		SetVTFont(xw, m, True, NULL);
2839d522f475Smrg	    } else {
284020d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
2841d522f475Smrg	    }
2842d522f475Smrg	}
2843d522f475Smrg    }
2844d522f475Smrg}
2845d522f475Smrg
2846d522f475Smrg/* ARGSUSED */
2847d522f475Smrgvoid
2848d522f475SmrgHandleSmallerFont(Widget w GCC_UNUSED,
2849d522f475Smrg		  XEvent * event GCC_UNUSED,
2850d522f475Smrg		  String * params GCC_UNUSED,
2851d522f475Smrg		  Cardinal *param_count GCC_UNUSED)
2852d522f475Smrg{
2853956cc18dSsnj    XtermWidget xw;
2854d522f475Smrg
285520d2c4d2Smrg    TRACE(("Handle smaller-vt-font for %p\n", (void *) w));
2856956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
2857d522f475Smrg	if (xw->misc.shift_fonts) {
2858956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
2859d522f475Smrg	    int m;
2860d522f475Smrg
2861d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, -1);
2862d522f475Smrg	    if (m >= 0) {
2863d522f475Smrg		SetVTFont(xw, m, True, NULL);
2864d522f475Smrg	    } else {
286520d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
2866d522f475Smrg	    }
2867d522f475Smrg	}
2868d522f475Smrg    }
2869d522f475Smrg}
2870d522f475Smrg#endif
2871d522f475Smrg
2872d522f475Smrgint
2873d522f475SmrgxtermGetFont(const char *param)
2874d522f475Smrg{
2875d522f475Smrg    int fontnum;
2876d522f475Smrg
2877d522f475Smrg    switch (param[0]) {
2878d522f475Smrg    case 'd':
2879d522f475Smrg    case 'D':
2880d522f475Smrg    case '0':
2881d522f475Smrg	fontnum = fontMenu_default;
2882d522f475Smrg	break;
2883d522f475Smrg    case '1':
2884d522f475Smrg	fontnum = fontMenu_font1;
2885d522f475Smrg	break;
2886d522f475Smrg    case '2':
2887d522f475Smrg	fontnum = fontMenu_font2;
2888d522f475Smrg	break;
2889d522f475Smrg    case '3':
2890d522f475Smrg	fontnum = fontMenu_font3;
2891d522f475Smrg	break;
2892d522f475Smrg    case '4':
2893d522f475Smrg	fontnum = fontMenu_font4;
2894d522f475Smrg	break;
2895d522f475Smrg    case '5':
2896d522f475Smrg	fontnum = fontMenu_font5;
2897d522f475Smrg	break;
2898d522f475Smrg    case '6':
2899d522f475Smrg	fontnum = fontMenu_font6;
2900d522f475Smrg	break;
2901d522f475Smrg    case 'e':
2902d522f475Smrg    case 'E':
2903d522f475Smrg	fontnum = fontMenu_fontescape;
2904d522f475Smrg	break;
2905d522f475Smrg    case 's':
2906d522f475Smrg    case 'S':
2907d522f475Smrg	fontnum = fontMenu_fontsel;
2908d522f475Smrg	break;
2909d522f475Smrg    default:
2910d522f475Smrg	fontnum = -1;
2911d522f475Smrg	break;
2912d522f475Smrg    }
2913d522f475Smrg    return fontnum;
2914d522f475Smrg}
2915d522f475Smrg
2916d522f475Smrg/* ARGSUSED */
2917d522f475Smrgvoid
2918d522f475SmrgHandleSetFont(Widget w GCC_UNUSED,
2919d522f475Smrg	      XEvent * event GCC_UNUSED,
2920d522f475Smrg	      String * params,
2921d522f475Smrg	      Cardinal *param_count)
2922d522f475Smrg{
2923956cc18dSsnj    XtermWidget xw;
2924956cc18dSsnj
2925956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
2926d522f475Smrg	int fontnum;
2927d522f475Smrg	VTFontNames fonts;
2928d522f475Smrg
2929d522f475Smrg	memset(&fonts, 0, sizeof(fonts));
2930d522f475Smrg
2931d522f475Smrg	if (*param_count == 0) {
2932d522f475Smrg	    fontnum = fontMenu_default;
2933d522f475Smrg	} else {
2934d522f475Smrg	    Cardinal maxparams = 1;	/* total number of params allowed */
2935d522f475Smrg	    int result = xtermGetFont(params[0]);
2936d522f475Smrg
2937d522f475Smrg	    switch (result) {
2938d522f475Smrg	    case fontMenu_default:	/* FALLTHRU */
2939d522f475Smrg	    case fontMenu_font1:	/* FALLTHRU */
2940d522f475Smrg	    case fontMenu_font2:	/* FALLTHRU */
2941d522f475Smrg	    case fontMenu_font3:	/* FALLTHRU */
2942d522f475Smrg	    case fontMenu_font4:	/* FALLTHRU */
2943d522f475Smrg	    case fontMenu_font5:	/* FALLTHRU */
2944d522f475Smrg	    case fontMenu_font6:	/* FALLTHRU */
2945d522f475Smrg		break;
2946d522f475Smrg	    case fontMenu_fontescape:
2947d522f475Smrg#if OPT_WIDE_CHARS
2948d522f475Smrg		maxparams = 5;
2949d522f475Smrg#else
2950d522f475Smrg		maxparams = 3;
2951d522f475Smrg#endif
2952d522f475Smrg		break;
2953d522f475Smrg	    case fontMenu_fontsel:
2954d522f475Smrg		maxparams = 2;
2955d522f475Smrg		break;
2956d522f475Smrg	    default:
295720d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
2958d522f475Smrg		return;
2959d522f475Smrg	    }
2960d522f475Smrg	    fontnum = result;
2961d522f475Smrg
2962d522f475Smrg	    if (*param_count > maxparams) {	/* see if extra args given */
296320d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
2964d522f475Smrg		return;
2965d522f475Smrg	    }
2966d522f475Smrg	    switch (*param_count) {	/* assign 'em */
2967d522f475Smrg#if OPT_WIDE_CHARS
2968d522f475Smrg	    case 5:
2969d522f475Smrg		fonts.f_wb = params[4];
2970d522f475Smrg		/* FALLTHRU */
2971d522f475Smrg	    case 4:
2972d522f475Smrg		fonts.f_w = params[3];
2973d522f475Smrg		/* FALLTHRU */
2974d522f475Smrg#endif
2975d522f475Smrg	    case 3:
2976d522f475Smrg		fonts.f_b = params[2];
2977d522f475Smrg		/* FALLTHRU */
2978d522f475Smrg	    case 2:
2979d522f475Smrg		fonts.f_n = params[1];
2980d522f475Smrg		break;
2981d522f475Smrg	    }
2982d522f475Smrg	}
2983d522f475Smrg
2984956cc18dSsnj	SetVTFont(xw, fontnum, True, &fonts);
2985d522f475Smrg    }
2986d522f475Smrg}
2987d522f475Smrg
2988d522f475Smrgvoid
2989d522f475SmrgSetVTFont(XtermWidget xw,
2990d522f475Smrg	  int which,
2991d522f475Smrg	  Bool doresize,
2992d522f475Smrg	  const VTFontNames * fonts)
2993d522f475Smrg{
2994956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2995d522f475Smrg
2996d522f475Smrg    TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which,
2997d522f475Smrg	   (fonts && fonts->f_n) ? fonts->f_n : "<null>",
2998d522f475Smrg	   (fonts && fonts->f_b) ? fonts->f_b : "<null>"));
2999d522f475Smrg
3000d522f475Smrg    if (IsIcon(screen)) {
300120d2c4d2Smrg	Bell(xw, XkbBI_MinorError, 0);
3002d522f475Smrg    } else if (which >= 0 && which < NMENUFONTS) {
3003d522f475Smrg	VTFontNames myfonts;
3004d522f475Smrg
3005d522f475Smrg	memset(&myfonts, 0, sizeof(myfonts));
3006d522f475Smrg	if (fonts != 0)
3007d522f475Smrg	    myfonts = *fonts;
3008d522f475Smrg
3009d522f475Smrg	if (which == fontMenu_fontsel) {	/* go get the selection */
3010d522f475Smrg	    FindFontSelection(xw, myfonts.f_n, False);
3011d522f475Smrg	} else {
3012d522f475Smrg	    int oldFont = screen->menu_font_number;
3013d522f475Smrg
3014d522f475Smrg#define USE_CACHED(field, name) \
3015d522f475Smrg	    if (myfonts.field == 0) { \
3016d522f475Smrg		myfonts.field = screen->menu_font_names[which][name]; \
3017d522f475Smrg		TRACE(("set myfonts." #field " from menu_font_names[%d][" #name "] %s\n", \
3018d522f475Smrg		       which, NonNull(myfonts.field))); \
3019d522f475Smrg	    } else { \
3020d522f475Smrg		TRACE(("set myfonts." #field " reused\n")); \
3021d522f475Smrg	    }
302220d2c4d2Smrg#define SAVE_FNAME(field, name) \
302320d2c4d2Smrg	    if (myfonts.field != 0) { \
302420d2c4d2Smrg		if (screen->menu_font_names[which][name] == 0 \
302520d2c4d2Smrg		 || strcmp(screen->menu_font_names[which][name], myfonts.field)) { \
302620d2c4d2Smrg		    TRACE(("updating menu_font_names[%d][" #name "] to %s\n", \
302720d2c4d2Smrg			   which, myfonts.field)); \
302820d2c4d2Smrg		    screen->menu_font_names[which][name] = x_strdup(myfonts.field); \
302920d2c4d2Smrg		} \
303020d2c4d2Smrg	    }
303120d2c4d2Smrg
3032d522f475Smrg	    USE_CACHED(f_n, fNorm);
3033d522f475Smrg	    USE_CACHED(f_b, fBold);
3034d522f475Smrg#if OPT_WIDE_CHARS
3035d522f475Smrg	    USE_CACHED(f_w, fWide);
3036d522f475Smrg	    USE_CACHED(f_wb, fWBold);
3037d522f475Smrg#endif
3038d522f475Smrg	    if (xtermLoadFont(xw,
3039d522f475Smrg			      &myfonts,
3040d522f475Smrg			      doresize, which)) {
304120d2c4d2Smrg		/*
304220d2c4d2Smrg		 * If successful, save the data so that a subsequent query via
304320d2c4d2Smrg		 * OSC-50 will return the expected values.
304420d2c4d2Smrg		 */
304520d2c4d2Smrg		SAVE_FNAME(f_n, fNorm);
304620d2c4d2Smrg		SAVE_FNAME(f_b, fBold);
304720d2c4d2Smrg#if OPT_WIDE_CHARS
304820d2c4d2Smrg		SAVE_FNAME(f_w, fWide);
304920d2c4d2Smrg		SAVE_FNAME(f_wb, fWBold);
305020d2c4d2Smrg#endif
3051d522f475Smrg	    } else {
3052d522f475Smrg		xtermLoadFont(xw,
3053d522f475Smrg			      xtermFontName(screen->MenuFontName(oldFont)),
3054d522f475Smrg			      doresize, oldFont);
305520d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
3056d522f475Smrg	    }
3057d522f475Smrg	}
305820d2c4d2Smrg    } else {
305920d2c4d2Smrg	Bell(xw, XkbBI_MinorError, 0);
3060d522f475Smrg    }
3061d522f475Smrg    return;
3062d522f475Smrg}
3063