fontutils.c revision 492d43a5
1492d43a5Smrg/* $XTermId: fontutils.c,v 1.353 2010/10/23 00:27:22 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
238492d43a5Smrg    if (IsEmpty(name)) {
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
540492d43a5Smrgsame_font_name(const char *pattern, const 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
580492d43a5Smrggot_bold_font(Display * dpy, XFontStruct * fs, String 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)
710492d43a5Smrg	free((void *) 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) {
720492d43a5Smrg	char *last = (char *) 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
748492d43a5Smrg    if (!IsEmpty(name)) {
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));
764492d43a5Smrg		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 {
777492d43a5Smrg		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) ? "*" : " ", \
914492d43a5Smrg	   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	    }
935492d43a5Smrg	    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;
952492d43a5Smrg	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;
1237492d43a5Smrg    String menu_font_names[fontMenu_lastBuiltin + 1][fMAX];
1238d522f475Smrg} SubResourceRec;
1239d522f475Smrg
1240d522f475Smrg#define MERGE_SUBFONT(src,dst,name) \
1241492d43a5Smrg	if (IsEmpty(dst.name)) { \
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) { \
1252492d43a5Smrg		dst.menu_font_names[n][m] = x_strdup(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
1297492d43a5Smrg    if (IsEmpty(myName)) {
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);
1332492d43a5Smrg	    screen->MenuFontName(fontMenu_default) = x_strdup(xw->misc.default_font.f_n);
1333492d43a5Smrg	    screen->menu_font_names[0][fBold] = x_strdup(xw->misc.default_font.f_b);
1334d522f475Smrg#if OPT_WIDE_CHARS
1335492d43a5Smrg	    screen->menu_font_names[0][fWide] = x_strdup(xw->misc.default_font.f_w);
1336492d43a5Smrg	    screen->menu_font_names[0][fWBold] = x_strdup(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);
1424492d43a5Smrg	char name_buf[80];
1425492d43a5Smrg	char class_buf[80];
1426492d43a5Smrg	String name = (String) ((*param_count > 0) ? params[0] : empty);
1427492d43a5Smrg	char *myName = (char *) MyStackAlloc(strlen(name), name_buf);
1428492d43a5Smrg	String convert = (String) ((*param_count > 1) ? params[1] : myName);
1429492d43a5Smrg	char *myClass = (char *) MyStackAlloc(strlen(convert), class_buf);
1430d522f475Smrg	int n;
1431d522f475Smrg
1432d522f475Smrg	TRACE(("HandleLoadVTFonts(%d)\n", *param_count));
1433492d43a5Smrg	strcpy(myName, name);
1434d522f475Smrg	strcpy(myClass, convert);
14352eaa94a1Schristos	if (*param_count == 1)
14362eaa94a1Schristos	    myClass[0] = x_toupper(myClass[0]);
1437d522f475Smrg
1438d522f475Smrg	if (xtermLoadVTFonts(xw, myName, myClass)) {
1439d522f475Smrg	    /*
1440d522f475Smrg	     * When switching fonts, try to preserve the font-menu selection, since
1441d522f475Smrg	     * it is less surprising to do that (if the font-switching can be
1442d522f475Smrg	     * undone) than to switch to "Default".
1443d522f475Smrg	     */
1444956cc18dSsnj	    int font_number = screen->menu_font_number;
1445d522f475Smrg	    if (font_number > fontMenu_lastBuiltin)
1446d522f475Smrg		font_number = fontMenu_lastBuiltin;
1447d522f475Smrg	    for (n = 0; n < NMENUFONTS; ++n)
1448956cc18dSsnj		screen->menu_font_sizes[n] = 0;
1449d522f475Smrg	    SetVTFont(xw, font_number, True,
1450d522f475Smrg		      ((font_number == fontMenu_default)
1451d522f475Smrg		       ? &(xw->misc.default_font)
1452d522f475Smrg		       : NULL));
1453d522f475Smrg	}
1454d522f475Smrg
1455492d43a5Smrg	MyStackFree(myName, name_buf);
1456492d43a5Smrg	MyStackFree(myClass, class_buf);
1457d522f475Smrg    }
1458d522f475Smrg}
1459d522f475Smrg#endif /* OPT_LOAD_VTFONTS */
1460d522f475Smrg
1461d522f475Smrg/*
1462d522f475Smrg * Set the limits for the box that outlines the cursor.
1463d522f475Smrg */
1464d522f475Smrgvoid
1465d522f475SmrgxtermSetCursorBox(TScreen * screen)
1466d522f475Smrg{
1467d522f475Smrg    static XPoint VTbox[NBOX];
1468d522f475Smrg    XPoint *vp;
14692eaa94a1Schristos    int fw = FontWidth(screen) - 1;
14702eaa94a1Schristos    int fh = FontHeight(screen) - 1;
14712eaa94a1Schristos    int hh = screen->cursor_underline ? 1 : fh;
1472d522f475Smrg
1473d522f475Smrg    vp = &VTbox[1];
14742eaa94a1Schristos    (vp++)->x = (short) fw;
14752eaa94a1Schristos    (vp++)->y = (short) hh;
14762eaa94a1Schristos    (vp++)->x = (short) -fw;
14772eaa94a1Schristos    vp->y = (short) -hh;
14782eaa94a1Schristos
1479d522f475Smrg    screen->box = VTbox;
1480d522f475Smrg}
1481d522f475Smrg
1482d522f475Smrg#define CACHE_XFT(dst,src) if (src != 0) {\
1483956cc18dSsnj	    checkXft(xw, &(dst[fontnum]), src);\
1484956cc18dSsnj	    TRACE(("Xft metrics %s[%d] = %d (%d,%d) advance %d, actual %d%s\n",\
1485d522f475Smrg		#dst,\
1486d522f475Smrg	    	fontnum,\
1487d522f475Smrg		src->height,\
1488d522f475Smrg		src->ascent,\
1489d522f475Smrg		src->descent,\
1490956cc18dSsnj		src->max_advance_width,\
1491956cc18dSsnj		dst[fontnum].map.min_width,\
1492956cc18dSsnj		dst[fontnum].map.mixed ? " mixed" : ""));\
1493d522f475Smrg	}
1494d522f475Smrg
1495d522f475Smrg#if OPT_RENDERFONT
1496956cc18dSsnj
149720d2c4d2Smrg#if OPT_TRACE > 1
149820d2c4d2Smrgstatic FcChar32
149920d2c4d2SmrgxtermXftFirstChar(XftFont * xft)
150020d2c4d2Smrg{
150120d2c4d2Smrg    FcChar32 map[FC_CHARSET_MAP_SIZE];
150220d2c4d2Smrg    FcChar32 next;
150320d2c4d2Smrg    FcChar32 first;
150420d2c4d2Smrg    int i;
150520d2c4d2Smrg
150620d2c4d2Smrg    first = FcCharSetFirstPage(xft->charset, map, &next);
150720d2c4d2Smrg    for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
150820d2c4d2Smrg	if (map[i]) {
150920d2c4d2Smrg	    FcChar32 bits = map[i];
151020d2c4d2Smrg	    first += i * 32;
151120d2c4d2Smrg	    while (!(bits & 0x1)) {
151220d2c4d2Smrg		bits >>= 1;
151320d2c4d2Smrg		first++;
151420d2c4d2Smrg	    }
151520d2c4d2Smrg	    break;
151620d2c4d2Smrg	}
151720d2c4d2Smrg    return first;
151820d2c4d2Smrg}
151920d2c4d2Smrg
152020d2c4d2Smrgstatic FcChar32
152120d2c4d2SmrgxtermXftLastChar(XftFont * xft)
152220d2c4d2Smrg{
152320d2c4d2Smrg    FcChar32 this, last, next;
152420d2c4d2Smrg    FcChar32 map[FC_CHARSET_MAP_SIZE];
152520d2c4d2Smrg    int i;
152620d2c4d2Smrg    last = FcCharSetFirstPage(xft->charset, map, &next);
152720d2c4d2Smrg    while ((this = FcCharSetNextPage(xft->charset, map, &next)) != FC_CHARSET_DONE)
152820d2c4d2Smrg	last = this;
152920d2c4d2Smrg    last &= ~0xff;
153020d2c4d2Smrg    for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--)
153120d2c4d2Smrg	if (map[i]) {
153220d2c4d2Smrg	    FcChar32 bits = map[i];
153320d2c4d2Smrg	    last += i * 32 + 31;
153420d2c4d2Smrg	    while (!(bits & 0x80000000)) {
153520d2c4d2Smrg		last--;
153620d2c4d2Smrg		bits <<= 1;
153720d2c4d2Smrg	    }
153820d2c4d2Smrg	    break;
153920d2c4d2Smrg	}
154020d2c4d2Smrg    return (long) last;
154120d2c4d2Smrg}
154220d2c4d2Smrg
154320d2c4d2Smrgstatic void
154420d2c4d2SmrgdumpXft(XtermWidget xw, XTermXftFonts * data)
154520d2c4d2Smrg{
154620d2c4d2Smrg    XftFont *xft = data->font;
154720d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
154820d2c4d2Smrg    VTwin *win = WhichVWin(screen);
154920d2c4d2Smrg
155020d2c4d2Smrg    FcChar32 c;
155120d2c4d2Smrg    FcChar32 first = xtermXftFirstChar(xft);
155220d2c4d2Smrg    FcChar32 last = xtermXftLastChar(xft);
155320d2c4d2Smrg    unsigned count = 0;
155420d2c4d2Smrg    unsigned outside = 0;
155520d2c4d2Smrg
155620d2c4d2Smrg    TRACE(("dumpXft {{\n"));
155720d2c4d2Smrg    TRACE(("   data range %#6x..%#6x\n", first, last));
155820d2c4d2Smrg    for (c = first; c <= last; ++c) {
155920d2c4d2Smrg	if (FcCharSetHasChar(xft->charset, c)) {
156020d2c4d2Smrg	    int width = my_wcwidth((int) c);
156120d2c4d2Smrg	    XGlyphInfo extents;
156220d2c4d2Smrg
156320d2c4d2Smrg	    XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents);
156420d2c4d2Smrg	    TRACE(("%#6x  %2d  %.1f\n", c, width,
156520d2c4d2Smrg		   ((double) extents.width) / win->f_width));
156620d2c4d2Smrg	    if (extents.width > win->f_width)
156720d2c4d2Smrg		++outside;
156820d2c4d2Smrg	    ++count;
156920d2c4d2Smrg	}
157020d2c4d2Smrg    }
157120d2c4d2Smrg    TRACE(("}} %u total, %u outside\n", count, outside));
157220d2c4d2Smrg}
157320d2c4d2Smrg#define DUMP_XFT(xw, data) dumpXft(xw, data)
157420d2c4d2Smrg#else
157520d2c4d2Smrg#define DUMP_XFT(xw, data)	/* nothing */
157620d2c4d2Smrg#endif
157720d2c4d2Smrg
1578956cc18dSsnjstatic void
1579956cc18dSsnjcheckXft(XtermWidget xw, XTermXftFonts * data, XftFont * xft)
1580956cc18dSsnj{
1581956cc18dSsnj    FcChar32 c;
1582956cc18dSsnj    Dimension width = 0;
1583956cc18dSsnj
1584956cc18dSsnj    data->font = xft;
1585956cc18dSsnj    data->map.min_width = 0;
1586956cc18dSsnj    data->map.max_width = (Dimension) xft->max_advance_width;
1587956cc18dSsnj
158820d2c4d2Smrg    /*
158920d2c4d2Smrg     * For each ASCII or ISO-8859-1 printable code, ask what its width is.
159020d2c4d2Smrg     * Given the maximum width for those, we have a reasonable estimate of
159120d2c4d2Smrg     * the single-column width.
159220d2c4d2Smrg     *
159320d2c4d2Smrg     * Ignore control characters - their extent information is misleading.
159420d2c4d2Smrg     */
1595956cc18dSsnj    for (c = 32; c < 256; ++c) {
159620d2c4d2Smrg	if (c >= 127 && c <= 159)
159720d2c4d2Smrg	    continue;
1598956cc18dSsnj	if (FcCharSetHasChar(xft->charset, c)) {
1599956cc18dSsnj	    XGlyphInfo extents;
1600956cc18dSsnj
1601956cc18dSsnj	    XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents);
160220d2c4d2Smrg	    if (width < extents.width && extents.width <= data->map.max_width) {
1603956cc18dSsnj		width = extents.width;
160420d2c4d2Smrg	    }
1605956cc18dSsnj	}
1606956cc18dSsnj    }
1607956cc18dSsnj    data->map.min_width = width;
1608956cc18dSsnj    data->map.mixed = (data->map.max_width >= (data->map.min_width + 1));
1609956cc18dSsnj}
1610956cc18dSsnj
1611d522f475Smrgstatic XftFont *
1612956cc18dSsnjxtermOpenXft(XtermWidget xw, const char *name, XftPattern * pat, const char *tag)
1613d522f475Smrg{
1614956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1615956cc18dSsnj    Display *dpy = screen->display;
1616d522f475Smrg    XftPattern *match;
1617d522f475Smrg    XftResult status;
1618d522f475Smrg    XftFont *result = 0;
1619d522f475Smrg
1620d522f475Smrg    if (pat != 0) {
1621d522f475Smrg	match = XftFontMatch(dpy, DefaultScreen(dpy), pat, &status);
1622d522f475Smrg	if (match != 0) {
1623d522f475Smrg	    result = XftFontOpenPattern(dpy, match);
1624d522f475Smrg	    if (result != 0) {
1625d522f475Smrg		TRACE(("...matched %s font\n", tag));
1626d522f475Smrg	    } else {
1627d522f475Smrg		TRACE(("...could did not open %s font\n", tag));
1628d522f475Smrg		XftPatternDestroy(match);
1629956cc18dSsnj		if (xw->misc.fontWarnings >= fwAlways) {
1630956cc18dSsnj		    TRACE(("OOPS cannot open %s font \"%s\"\n", tag, name));
1631956cc18dSsnj		    fprintf(stderr, "%s: cannot open %s font \"%s\"\n",
1632956cc18dSsnj			    ProgramName, tag, name);
1633956cc18dSsnj		}
1634d522f475Smrg	    }
1635d522f475Smrg	} else {
1636d522f475Smrg	    TRACE(("...did not match %s font\n", tag));
1637956cc18dSsnj	    if (xw->misc.fontWarnings >= fwResource) {
1638956cc18dSsnj		TRACE(("OOPS: cannot match %s font \"%s\"\n", tag, name));
1639956cc18dSsnj		fprintf(stderr, "%s: cannot match %s font \"%s\"\n",
1640956cc18dSsnj			ProgramName, tag, name);
1641956cc18dSsnj	    }
1642d522f475Smrg	}
1643d522f475Smrg    }
1644d522f475Smrg    return result;
1645d522f475Smrg}
1646d522f475Smrg#endif
1647d522f475Smrg
1648d522f475Smrg#if OPT_RENDERFONT
1649d522f475Smrg#if OPT_SHIFT_FONTS
1650d522f475Smrg/*
1651d522f475Smrg * Don't make a dependency on the math library for a single function.
1652d522f475Smrg * (Newton Raphson).
1653d522f475Smrg */
1654d522f475Smrgstatic double
1655d522f475SmrgmySquareRoot(double value)
1656d522f475Smrg{
1657d522f475Smrg    double result = 0.0;
1658d522f475Smrg    if (value > 0.0) {
1659d522f475Smrg	int n;
1660d522f475Smrg	double older = value;
1661d522f475Smrg	for (n = 0; n < 10; ++n) {
1662d522f475Smrg	    double delta = (older * older - value) / (2.0 * older);
1663d522f475Smrg	    double newer = older - delta;
1664d522f475Smrg	    older = newer;
1665d522f475Smrg	    result = newer;
1666d522f475Smrg	    if (delta > -0.001 && delta < 0.001)
1667d522f475Smrg		break;
1668d522f475Smrg	}
1669d522f475Smrg    }
1670d522f475Smrg    return result;
1671d522f475Smrg}
1672d522f475Smrg#endif
1673d522f475Smrg
1674d522f475Smrg/*
1675d522f475Smrg * Given the Xft font metrics, determine the actual font size.  This is used
1676d522f475Smrg * for each font to ensure that normal, bold and italic fonts follow the same
1677d522f475Smrg * rule.
1678d522f475Smrg */
1679d522f475Smrgstatic void
1680d522f475SmrgsetRenderFontsize(TScreen * screen, VTwin * win, XftFont * font, const char *tag)
1681d522f475Smrg{
1682d522f475Smrg    if (font != 0) {
1683d522f475Smrg	int width, height, ascent, descent;
1684d522f475Smrg
1685d522f475Smrg	(void) screen;
1686d522f475Smrg
1687d522f475Smrg	width = font->max_advance_width;
1688d522f475Smrg	height = font->height;
1689d522f475Smrg	ascent = font->ascent;
1690d522f475Smrg	descent = font->descent;
1691d522f475Smrg	if (height < ascent + descent) {
1692d522f475Smrg	    TRACE(("...increase height from %d\n", height));
1693d522f475Smrg	    height = ascent + descent;
1694d522f475Smrg	}
1695d522f475Smrg	if (is_double_width_font_xft(screen->display, font)) {
1696d522f475Smrg	    TRACE(("...reduced width from %d\n", width));
1697d522f475Smrg	    width >>= 1;
1698d522f475Smrg	}
1699d522f475Smrg	if (tag == 0) {
1700d522f475Smrg	    win->f_width = width;
1701d522f475Smrg	    win->f_height = height;
1702d522f475Smrg	    win->f_ascent = ascent;
1703d522f475Smrg	    win->f_descent = descent;
1704d522f475Smrg	    TRACE(("setRenderFontsize result %dx%d (%d+%d)\n",
1705d522f475Smrg		   width, height, ascent, descent));
1706d522f475Smrg	} else if (win->f_width < width ||
1707d522f475Smrg		   win->f_height < height ||
1708d522f475Smrg		   win->f_ascent < ascent ||
1709d522f475Smrg		   win->f_descent < descent) {
1710d522f475Smrg	    TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n",
1711d522f475Smrg		   tag,
1712d522f475Smrg		   win->f_width, win->f_height, win->f_ascent, win->f_descent,
1713d522f475Smrg		   width, height, ascent, descent));
1714d522f475Smrg
1715d522f475Smrg	    win->f_width = width;
1716d522f475Smrg	    win->f_height = height;
1717d522f475Smrg	    win->f_ascent = ascent;
1718d522f475Smrg	    win->f_descent = descent;
1719d522f475Smrg	} else {
1720d522f475Smrg	    TRACE(("setRenderFontsize %s unchanged\n", tag));
1721d522f475Smrg	}
1722d522f475Smrg    }
1723d522f475Smrg}
1724d522f475Smrg#endif
1725d522f475Smrg
172620d2c4d2Smrgstatic void
172720d2c4d2SmrgcheckFontInfo(int value, const char *tag)
172820d2c4d2Smrg{
172920d2c4d2Smrg    if (value == 0) {
173020d2c4d2Smrg	fprintf(stderr,
173120d2c4d2Smrg		"Selected font has no non-zero %s for ISO-8859-1 encoding\n", tag);
173220d2c4d2Smrg	exit(1);
173320d2c4d2Smrg    }
173420d2c4d2Smrg}
173520d2c4d2Smrg
173620d2c4d2Smrg#if OPT_RENDERFONT
173720d2c4d2Smrgvoid
173820d2c4d2SmrgxtermCloseXft(TScreen * screen, XTermXftFonts * pub)
173920d2c4d2Smrg{
174020d2c4d2Smrg    if (pub->font != 0) {
174120d2c4d2Smrg	XftFontClose(screen->display, pub->font);
174220d2c4d2Smrg	pub->font = 0;
174320d2c4d2Smrg    }
174420d2c4d2Smrg}
174520d2c4d2Smrg
174620d2c4d2Smrg/*
174720d2c4d2Smrg * Get the faceName/faceDoublesize resource setting.  Strip off "xft:", which
174820d2c4d2Smrg * is not recognized by XftParseName().
174920d2c4d2Smrg */
1750492d43a5SmrgString
175120d2c4d2SmrggetFaceName(XtermWidget xw, Bool wideName GCC_UNUSED)
175220d2c4d2Smrg{
175320d2c4d2Smrg#if OPT_RENDERWIDE
1754492d43a5Smrg    String result = (wideName
1755492d43a5Smrg		     ? xw->misc.face_wide_name
1756492d43a5Smrg		     : xw->misc.face_name);
175720d2c4d2Smrg#else
1758492d43a5Smrg    String result = xw->misc.face_name;
175920d2c4d2Smrg#endif
176020d2c4d2Smrg    if (!IsEmpty(result) && !strncmp(result, "xft:", (size_t) 4))
176120d2c4d2Smrg	result += 4;
176220d2c4d2Smrg    return x_nonempty(result);
176320d2c4d2Smrg}
176420d2c4d2Smrg
176520d2c4d2Smrg/*
176620d2c4d2Smrg * If we change the faceName, we'll have to re-acquire all of the fonts that
176720d2c4d2Smrg * are derived from it.
176820d2c4d2Smrg */
176920d2c4d2Smrgvoid
177020d2c4d2SmrgsetFaceName(XtermWidget xw, const char *value)
177120d2c4d2Smrg{
177220d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
177320d2c4d2Smrg    int n;
177420d2c4d2Smrg
177520d2c4d2Smrg    xw->misc.face_name = x_strdup(value);
177620d2c4d2Smrg    for (n = 0; n < NMENUFONTS; ++n) {
177720d2c4d2Smrg	xw->misc.face_size[n] = -1.0;
177820d2c4d2Smrg	xtermCloseXft(screen, &(screen->renderFontNorm[n]));
177920d2c4d2Smrg	xtermCloseXft(screen, &(screen->renderFontBold[n]));
178020d2c4d2Smrg	xtermCloseXft(screen, &(screen->renderFontBold[n]));
178120d2c4d2Smrg#if OPT_RENDERWIDE
178220d2c4d2Smrg	xtermCloseXft(screen, &(screen->renderWideNorm[n]));
178320d2c4d2Smrg	xtermCloseXft(screen, &(screen->renderWideBold[n]));
178420d2c4d2Smrg	xtermCloseXft(screen, &(screen->renderWideItal[n]));
178520d2c4d2Smrg#endif
178620d2c4d2Smrg    }
178720d2c4d2Smrg}
178820d2c4d2Smrg#endif
178920d2c4d2Smrg
1790d522f475Smrg/*
1791d522f475Smrg * Compute useful values for the font/window sizes
1792d522f475Smrg */
1793d522f475Smrgvoid
1794d522f475SmrgxtermComputeFontInfo(XtermWidget xw,
1795d522f475Smrg		     VTwin * win,
1796d522f475Smrg		     XFontStruct * font,
1797d522f475Smrg		     int sbwidth)
1798d522f475Smrg{
1799956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1800d522f475Smrg
1801d522f475Smrg    int i, j, width, height;
1802492d43a5Smrg#if OPT_RENDERFONT
1803492d43a5Smrg    int fontnum = screen->menu_font_number;
1804492d43a5Smrg#endif
1805d522f475Smrg
1806d522f475Smrg#if OPT_RENDERFONT
1807d522f475Smrg    /*
1808d522f475Smrg     * xterm contains a lot of references to fonts, assuming they are fixed
1809d522f475Smrg     * size.  This chunk of code overrides the actual font-selection (see
1810d522f475Smrg     * drawXtermText()), if the user has selected render-font.  All of the
1811d522f475Smrg     * font-loading for fixed-fonts still goes on whether or not this chunk
1812d522f475Smrg     * overrides it.
1813d522f475Smrg     */
1814492d43a5Smrg    if (UsingRenderFont(xw) && fontnum >= 0) {
1815492d43a5Smrg	String face_name = getFaceName(xw, False);
1816956cc18dSsnj	XftFont *norm = screen->renderFontNorm[fontnum].font;
1817956cc18dSsnj	XftFont *bold = screen->renderFontBold[fontnum].font;
1818956cc18dSsnj	XftFont *ital = screen->renderFontItal[fontnum].font;
1819d522f475Smrg#if OPT_RENDERWIDE
1820956cc18dSsnj	XftFont *wnorm = screen->renderWideNorm[fontnum].font;
1821956cc18dSsnj	XftFont *wbold = screen->renderWideBold[fontnum].font;
1822956cc18dSsnj	XftFont *wital = screen->renderWideItal[fontnum].font;
1823d522f475Smrg#endif
1824d522f475Smrg
182520d2c4d2Smrg	if (norm == 0 && face_name) {
1826d522f475Smrg	    XftPattern *pat;
1827d522f475Smrg	    double face_size = xw->misc.face_size[fontnum];
1828d522f475Smrg
1829492d43a5Smrg	    TRACE(("xtermComputeFontInfo font %d: norm(face %s, size %f)\n",
1830492d43a5Smrg		   fontnum, face_name,
1831d522f475Smrg		   xw->misc.face_size[fontnum]));
1832d522f475Smrg
1833d522f475Smrg	    if (face_size <= 0.0) {
1834d522f475Smrg#if OPT_SHIFT_FONTS
1835d522f475Smrg		/*
1836d522f475Smrg		 * If the user is switching font-sizes, make it follow by
1837d522f475Smrg		 * default the same ratios to the default as the fixed fonts
1838d522f475Smrg		 * would, for easy comparison.  There will be some differences
1839d522f475Smrg		 * since the fixed fonts have a variety of height/width ratios,
1840d522f475Smrg		 * but this is simpler than adding another resource value - and
1841d522f475Smrg		 * as noted above, the data for the fixed fonts are available.
1842d522f475Smrg		 */
1843d522f475Smrg		lookupOneFontSize(xw, 0);
1844d522f475Smrg		lookupOneFontSize(xw, fontnum);
1845d522f475Smrg		if (fontnum == fontMenu_default) {
1846d522f475Smrg		    face_size = 14.0;
1847d522f475Smrg		} else {
1848d522f475Smrg		    double ratio;
184920d2c4d2Smrg		    long num = screen->menu_font_sizes[fontnum];
185020d2c4d2Smrg		    long den = screen->menu_font_sizes[0];
1851d522f475Smrg
1852d522f475Smrg		    if (den <= 0)
1853d522f475Smrg			den = 1;
185420d2c4d2Smrg		    ratio = mySquareRoot((double) num / (double) den);
1855d522f475Smrg
1856d522f475Smrg		    face_size = (ratio * xw->misc.face_size[0]);
185720d2c4d2Smrg		    TRACE(("scaled using %3ld/%ld = %.2f -> %f\n",
1858d522f475Smrg			   num, den, ratio, face_size));
1859d522f475Smrg		}
1860d522f475Smrg#else
1861d522f475Smrg		switch (fontnum) {
1862d522f475Smrg		case fontMenu_font1:
1863d522f475Smrg		    face_size = 8.0;
1864d522f475Smrg		    break;
1865d522f475Smrg		case fontMenu_font2:
1866d522f475Smrg		    face_size = 10.0;
1867d522f475Smrg		    break;
1868d522f475Smrg		case fontMenu_font3:
1869d522f475Smrg		    face_size = 12.0;
1870d522f475Smrg		    break;
1871d522f475Smrg		default:
1872d522f475Smrg		    face_size = 14.0;
1873d522f475Smrg		    break;
1874d522f475Smrg		case fontMenu_font4:
1875d522f475Smrg		    face_size = 16.0;
1876d522f475Smrg		    break;
1877d522f475Smrg		case fontMenu_font5:
1878d522f475Smrg		    face_size = 18.0;
1879d522f475Smrg		    break;
1880d522f475Smrg		case fontMenu_font6:
1881d522f475Smrg		    face_size = 20.0;
1882d522f475Smrg		    break;
1883d522f475Smrg		}
1884d522f475Smrg#endif
1885956cc18dSsnj		xw->misc.face_size[fontnum] = (float) face_size;
1886d522f475Smrg	    }
1887d522f475Smrg
1888d522f475Smrg	    /*
1889d522f475Smrg	     * By observation (there is no documentation), XftPatternBuild is
1890d522f475Smrg	     * cumulative.  Build the bold- and italic-patterns on top of the
1891d522f475Smrg	     * normal pattern.
1892d522f475Smrg	     */
1893d522f475Smrg#define NormXftPattern \
1894d522f475Smrg	    XFT_FAMILY, XftTypeString, "mono", \
1895d522f475Smrg	    XFT_SIZE, XftTypeDouble, face_size, \
1896d522f475Smrg	    XFT_SPACING, XftTypeInteger, XFT_MONO
1897d522f475Smrg
1898d522f475Smrg#define BoldXftPattern(norm) \
1899d522f475Smrg	    XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \
1900d522f475Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width
1901d522f475Smrg
1902d522f475Smrg#define ItalXftPattern(norm) \
1903d522f475Smrg	    XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \
1904d522f475Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width
1905d522f475Smrg
190620d2c4d2Smrg	    if ((pat = XftNameParse(face_name)) != 0) {
190720d2c4d2Smrg#define OPEN_XFT(tag) xtermOpenXft(xw, face_name, pat, tag)
1908d522f475Smrg		XftPatternBuild(pat,
1909d522f475Smrg				NormXftPattern,
1910d522f475Smrg				(void *) 0);
1911956cc18dSsnj		norm = OPEN_XFT("normal");
1912d522f475Smrg
1913d522f475Smrg		if (norm != 0) {
1914d522f475Smrg		    XftPatternBuild(pat,
1915d522f475Smrg				    BoldXftPattern(norm),
1916d522f475Smrg				    (void *) 0);
1917956cc18dSsnj		    bold = OPEN_XFT("bold");
1918d522f475Smrg
1919d522f475Smrg#if OPT_ISO_COLORS
1920d522f475Smrg		    if (screen->italicULMode
192120d2c4d2Smrg			&& (pat = XftNameParse(face_name)) != 0) {
1922d522f475Smrg			XftPatternBuild(pat,
1923d522f475Smrg					NormXftPattern,
1924d522f475Smrg					ItalXftPattern(norm),
1925d522f475Smrg					(void *) 0);
1926956cc18dSsnj			ital = OPEN_XFT("italic");
1927d522f475Smrg		    }
1928d522f475Smrg#endif /* OPT_ISO_COLORS */
1929956cc18dSsnj#undef OPEN_XFT
1930d522f475Smrg
1931d522f475Smrg		    /*
1932d522f475Smrg		     * FIXME:  just assume that the corresponding font has no
1933d522f475Smrg		     * graphics characters.
1934d522f475Smrg		     */
1935d522f475Smrg		    if (screen->fnt_boxes) {
1936d522f475Smrg			screen->fnt_boxes = False;
1937d522f475Smrg			TRACE(("Xft opened - will %suse internal line-drawing characters\n",
1938d522f475Smrg			       screen->fnt_boxes ? "not " : ""));
1939d522f475Smrg		    }
1940d522f475Smrg		}
1941d522f475Smrg
1942d522f475Smrg		XftPatternDestroy(pat);
1943d522f475Smrg	    }
1944d522f475Smrg
1945d522f475Smrg	    CACHE_XFT(screen->renderFontNorm, norm);
1946d522f475Smrg	    CACHE_XFT(screen->renderFontBold, bold);
1947d522f475Smrg	    CACHE_XFT(screen->renderFontItal, ital);
1948d522f475Smrg
1949d522f475Smrg	    /*
1950d522f475Smrg	     * See xtermXftDrawString().
1951d522f475Smrg	     */
1952d522f475Smrg#if OPT_RENDERWIDE
1953d522f475Smrg	    if (norm != 0 && screen->wide_chars) {
1954d522f475Smrg		int char_width = norm->max_advance_width * 2;
1955956cc18dSsnj#ifdef FC_ASPECT
1956956cc18dSsnj		double aspect = ((xw->misc.face_wide_name
1957956cc18dSsnj				  || screen->renderFontNorm[fontnum].map.mixed)
1958956cc18dSsnj				 ? 1.0
1959956cc18dSsnj				 : 2.0);
1960956cc18dSsnj#endif
1961d522f475Smrg
196220d2c4d2Smrg		face_name = getFaceName(xw, True);
1963d522f475Smrg		TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n",
196420d2c4d2Smrg		       NonNull(face_name),
1965d522f475Smrg		       char_width));
1966d522f475Smrg
1967d522f475Smrg#define WideXftPattern \
1968d522f475Smrg		XFT_FAMILY, XftTypeString, "mono", \
1969d522f475Smrg		XFT_SIZE, XftTypeDouble, face_size, \
1970d522f475Smrg		XFT_SPACING, XftTypeInteger, XFT_MONO
1971d522f475Smrg
197220d2c4d2Smrg		if (face_name && (pat = XftNameParse(face_name)) != 0) {
1973956cc18dSsnj#define OPEN_XFT(tag) xtermOpenXft(xw, face_name, pat, tag)
1974d522f475Smrg		    XftPatternBuild(pat,
1975d522f475Smrg				    WideXftPattern,
1976d522f475Smrg				    XFT_CHAR_WIDTH, XftTypeInteger, char_width,
1977956cc18dSsnj#ifdef FC_ASPECT
1978956cc18dSsnj				    FC_ASPECT, XftTypeDouble, aspect,
1979956cc18dSsnj#endif
1980d522f475Smrg				    (void *) 0);
1981956cc18dSsnj		    wnorm = OPEN_XFT("wide");
1982d522f475Smrg
1983d522f475Smrg		    if (wnorm != 0) {
1984d522f475Smrg			XftPatternBuild(pat,
1985d522f475Smrg					WideXftPattern,
1986d522f475Smrg					BoldXftPattern(wnorm),
1987d522f475Smrg					(void *) 0);
1988956cc18dSsnj			wbold = OPEN_XFT("wide-bold");
1989d522f475Smrg
1990d522f475Smrg#if OPT_ISO_COLORS
1991d522f475Smrg			if (screen->italicULMode
1992d522f475Smrg			    && (pat = XftNameParse(face_name)) != 0) {
1993d522f475Smrg			    XftPatternBuild(pat,
1994d522f475Smrg					    WideXftPattern,
1995d522f475Smrg					    ItalXftPattern(wnorm),
1996d522f475Smrg					    (void *) 0);
1997956cc18dSsnj			    wital = OPEN_XFT("wide-italic");
1998d522f475Smrg			}
1999d522f475Smrg#endif
2000956cc18dSsnj#undef OPEN_XFT
2001d522f475Smrg		    }
2002d522f475Smrg		    XftPatternDestroy(pat);
2003d522f475Smrg		}
2004d522f475Smrg
2005d522f475Smrg		CACHE_XFT(screen->renderWideNorm, wnorm);
2006d522f475Smrg		CACHE_XFT(screen->renderWideBold, wbold);
2007d522f475Smrg		CACHE_XFT(screen->renderWideItal, wital);
2008d522f475Smrg	    }
2009d522f475Smrg#endif /* OPT_RENDERWIDE */
2010d522f475Smrg	}
2011d522f475Smrg	if (norm == 0) {
20122eaa94a1Schristos	    TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum));
2013d522f475Smrg	    xw->misc.render_font = False;
2014d522f475Smrg	    update_font_renderfont();
2015d522f475Smrg	    /* now we will fall through into the bitmap fonts */
2016d522f475Smrg	} else {
2017d522f475Smrg	    setRenderFontsize(screen, win, norm, NULL);
2018d522f475Smrg	    setRenderFontsize(screen, win, bold, "bold");
2019d522f475Smrg	    setRenderFontsize(screen, win, ital, "ital");
202020d2c4d2Smrg#if OPT_BOX_CHARS
202120d2c4d2Smrg	    setupPackedFonts(xw);
202220d2c4d2Smrg
202320d2c4d2Smrg	    if (screen->force_packed) {
202420d2c4d2Smrg		XTermXftFonts *use = &(screen->renderFontNorm[fontnum]);
202520d2c4d2Smrg		win->f_height = use->font->ascent + use->font->descent;
202620d2c4d2Smrg		win->f_width = use->map.min_width;
202720d2c4d2Smrg		TRACE(("...packed TrueType font %dx%d vs %d\n",
202820d2c4d2Smrg		       win->f_height,
202920d2c4d2Smrg		       win->f_width,
203020d2c4d2Smrg		       use->map.max_width));
203120d2c4d2Smrg	    }
203220d2c4d2Smrg#endif
203320d2c4d2Smrg	    DUMP_XFT(xw, &(screen->renderFontNorm[fontnum]));
2034d522f475Smrg	}
2035d522f475Smrg    }
2036d522f475Smrg    /*
2037d522f475Smrg     * Are we handling a bitmap font?
2038d522f475Smrg     */
2039492d43a5Smrg    else
2040d522f475Smrg#endif /* OPT_RENDERFONT */
2041d522f475Smrg    {
204220d2c4d2Smrg	if (is_double_width_font(font) && !(screen->fnt_prop)) {
2043d522f475Smrg	    win->f_width = (font->min_bounds.width);
2044d522f475Smrg	} else {
2045d522f475Smrg	    win->f_width = (font->max_bounds.width);
2046d522f475Smrg	}
2047d522f475Smrg	win->f_height = (font->ascent + font->descent);
2048d522f475Smrg	win->f_ascent = font->ascent;
2049d522f475Smrg	win->f_descent = font->descent;
2050d522f475Smrg    }
2051d522f475Smrg    i = 2 * screen->border + sbwidth;
2052d522f475Smrg    j = 2 * screen->border;
2053d522f475Smrg    width = MaxCols(screen) * win->f_width + i;
2054d522f475Smrg    height = MaxRows(screen) * win->f_height + j;
2055956cc18dSsnj    win->fullwidth = (Dimension) width;
2056956cc18dSsnj    win->fullheight = (Dimension) height;
2057d522f475Smrg    win->width = width - i;
2058d522f475Smrg    win->height = height - j;
2059d522f475Smrg
2060d522f475Smrg    TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n",
2061d522f475Smrg	   win->height,
2062d522f475Smrg	   win->width,
2063d522f475Smrg	   win->fullheight,
2064d522f475Smrg	   win->fullwidth,
2065d522f475Smrg	   win->f_height,
2066d522f475Smrg	   win->f_width,
2067d522f475Smrg	   win->f_ascent,
2068d522f475Smrg	   win->f_descent));
206920d2c4d2Smrg
207020d2c4d2Smrg    checkFontInfo(win->f_height, "height");
207120d2c4d2Smrg    checkFontInfo(win->f_width, "width");
2072d522f475Smrg}
2073d522f475Smrg
2074d522f475Smrg/* save this information as a side-effect for double-sized characters */
2075d522f475Smrgvoid
2076d522f475SmrgxtermSaveFontInfo(TScreen * screen, XFontStruct * font)
2077d522f475Smrg{
2078956cc18dSsnj    screen->fnt_wide = (Dimension) (font->max_bounds.width);
2079956cc18dSsnj    screen->fnt_high = (Dimension) (font->ascent + font->descent);
2080d522f475Smrg    TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide));
2081d522f475Smrg}
2082d522f475Smrg
2083d522f475Smrg/*
2084d522f475Smrg * After loading a new font, update the structures that use its size.
2085d522f475Smrg */
2086d522f475Smrgvoid
2087d522f475SmrgxtermUpdateFontInfo(XtermWidget xw, Bool doresize)
2088d522f475Smrg{
2089956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2090d522f475Smrg
2091d522f475Smrg    int scrollbar_width;
2092d522f475Smrg    VTwin *win = &(screen->fullVwin);
2093d522f475Smrg
2094d522f475Smrg    scrollbar_width = (xw->misc.scrollbar
2095d522f475Smrg		       ? (screen->scrollWidget->core.width +
2096d522f475Smrg			  BorderWidth(screen->scrollWidget))
2097d522f475Smrg		       : 0);
2098d522f475Smrg    xtermComputeFontInfo(xw, win, screen->fnts[fNorm].fs, scrollbar_width);
2099d522f475Smrg    xtermSaveFontInfo(screen, screen->fnts[fNorm].fs);
2100d522f475Smrg
2101d522f475Smrg    if (doresize) {
2102d522f475Smrg	if (VWindow(screen)) {
2103d522f475Smrg	    xtermClear(xw);
2104d522f475Smrg	}
2105d522f475Smrg	TRACE(("xtermUpdateFontInfo {{\n"));
2106d522f475Smrg	DoResizeScreen(xw);	/* set to the new natural size */
2107d522f475Smrg	ResizeScrollBar(xw);
2108d522f475Smrg	Redraw();
2109d522f475Smrg	TRACE(("... }} xtermUpdateFontInfo\n"));
2110d522f475Smrg#ifdef SCROLLBAR_RIGHT
2111d522f475Smrg	updateRightScrollbar(xw);
2112d522f475Smrg#endif
2113d522f475Smrg    }
2114d522f475Smrg    xtermSetCursorBox(screen);
2115d522f475Smrg}
2116d522f475Smrg
2117d522f475Smrg#if OPT_BOX_CHARS
2118d522f475Smrg
2119d522f475Smrg/*
2120d522f475Smrg * Returns true if the given character is missing from the specified font.
2121d522f475Smrg */
2122d522f475SmrgBool
2123956cc18dSsnjxtermMissingChar(unsigned ch, XTermFonts * font)
2124d522f475Smrg{
2125956cc18dSsnj    Bool result = False;
2126956cc18dSsnj    XFontStruct *fs = font->fs;
2127956cc18dSsnj    static XCharStruct dft, *tmp = &dft, *pc = 0;
2128d522f475Smrg
2129956cc18dSsnj    if (fs->max_byte1 == 0) {
2130d522f475Smrg#if OPT_WIDE_CHARS
2131956cc18dSsnj	if (ch > 255) {
2132956cc18dSsnj	    TRACE(("xtermMissingChar %#04x (row)\n", ch));
2133956cc18dSsnj	    return True;
2134d522f475Smrg	}
2135956cc18dSsnj#endif
2136956cc18dSsnj	CI_GET_CHAR_INFO_1D(fs, E2A(ch), tmp, pc);
2137956cc18dSsnj    }
2138d522f475Smrg#if OPT_WIDE_CHARS
2139956cc18dSsnj    else {
2140956cc18dSsnj	CI_GET_CHAR_INFO_2D(fs, HI_BYTE(ch), LO_BYTE(ch), tmp, pc);
2141956cc18dSsnj    }
2142d522f475Smrg#else
2143d522f475Smrg
2144956cc18dSsnj    if (!pc)
2145956cc18dSsnj	return False;		/* Urgh! */
2146d522f475Smrg#endif
2147d522f475Smrg
2148956cc18dSsnj    if (CI_NONEXISTCHAR(pc)) {
2149956cc18dSsnj	TRACE(("xtermMissingChar %#04x (!exists)\n", ch));
2150956cc18dSsnj	result = True;
2151d522f475Smrg    }
2152956cc18dSsnj    if (ch < 256) {
2153956cc18dSsnj	font->known_missing[ch] = (Char) (result ? 2 : 1);
2154d522f475Smrg    }
2155956cc18dSsnj    return result;
2156d522f475Smrg}
2157d522f475Smrg
2158d522f475Smrg/*
2159d522f475Smrg * The grid is arbitrary, enough resolution that nothing's lost in
2160d522f475Smrg * initialization.
2161d522f475Smrg */
2162d522f475Smrg#define BOX_HIGH 60
2163d522f475Smrg#define BOX_WIDE 60
2164d522f475Smrg
2165d522f475Smrg#define MID_HIGH (BOX_HIGH/2)
2166d522f475Smrg#define MID_WIDE (BOX_WIDE/2)
2167d522f475Smrg
2168d522f475Smrg#define CHR_WIDE ((9*BOX_WIDE)/10)
2169d522f475Smrg#define CHR_HIGH ((9*BOX_HIGH)/10)
2170d522f475Smrg
2171d522f475Smrg/*
2172d522f475Smrg * ...since we'll scale the values anyway.
2173d522f475Smrg */
2174956cc18dSsnj#define SCALE_X(n) n = (n * (((int) font_width) - 1)) / (BOX_WIDE-1)
2175956cc18dSsnj#define SCALE_Y(n) n = (n * (((int) font_height) - 1)) / (BOX_HIGH-1)
2176d522f475Smrg
2177d522f475Smrg#define SEG(x0,y0,x1,y1) x0,y0, x1,y1
2178d522f475Smrg
2179d522f475Smrg/*
2180d522f475Smrg * Draw the given graphic character, if it is simple enough (i.e., a
2181d522f475Smrg * line-drawing character).
2182d522f475Smrg */
2183d522f475Smrgvoid
2184d522f475SmrgxtermDrawBoxChar(XtermWidget xw,
2185d522f475Smrg		 unsigned ch,
2186d522f475Smrg		 unsigned flags,
2187d522f475Smrg		 GC gc,
2188d522f475Smrg		 int x,
2189d522f475Smrg		 int y,
2190d522f475Smrg		 int cells)
2191d522f475Smrg{
2192956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2193d522f475Smrg    /* *INDENT-OFF* */
2194d522f475Smrg    static const short glyph_ht[] = {
2195d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,5*MID_HIGH/6),	/* H */
2196d522f475Smrg	SEG(6*BOX_WIDE/10,  0,		6*BOX_WIDE/10,5*MID_HIGH/6),
2197d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12),
2198d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
2199d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
2200d522f475Smrg	-1
2201d522f475Smrg    }, glyph_ff[] = {
2202d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		6*BOX_WIDE/10,	0),		/* F */
2203d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12),
2204d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		0*BOX_WIDE/3, 5*MID_HIGH/6),
2205d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
2206d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
2207d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
2208d522f475Smrg	-1
2209d522f475Smrg    }, glyph_lf[] = {
2210d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,9*MID_HIGH/12),	/* L */
2211d522f475Smrg	SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12),
2212d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
2213d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
2214d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
2215d522f475Smrg	-1
2216d522f475Smrg    }, glyph_nl[] = {
2217d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10,	0),		/* N */
2218d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		5*BOX_WIDE/6, 5*MID_HIGH/6),
2219d522f475Smrg	SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
2220d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),	/* L */
2221d522f475Smrg	SEG(1*BOX_WIDE/3,   CHR_HIGH,	  CHR_WIDE,	CHR_HIGH),
2222d522f475Smrg	-1
2223d522f475Smrg    }, glyph_vt[] = {
2224d522f475Smrg	SEG(1*BOX_WIDE/10,   0,		5*BOX_WIDE/12,5*MID_HIGH/6),	/* V */
2225d522f475Smrg	SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
2226d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
2227d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
2228d522f475Smrg	-1
2229d522f475Smrg    }, plus_or_minus[] =
2230d522f475Smrg    {
2231d522f475Smrg	SEG(  0,	  5*BOX_HIGH/6,	  CHR_WIDE,   5*BOX_HIGH/6),
2232d522f475Smrg	SEG(  MID_WIDE,	  2*BOX_HIGH/6,	  MID_WIDE,   4*BOX_HIGH/6),
2233d522f475Smrg	SEG(  0,	  3*BOX_HIGH/6,	  CHR_WIDE,   3*BOX_HIGH/6),
2234d522f475Smrg	-1
2235d522f475Smrg    }, lower_right_corner[] =
2236d522f475Smrg    {
2237d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
2238d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	0),
2239d522f475Smrg	-1
2240d522f475Smrg    }, upper_right_corner[] =
2241d522f475Smrg    {
2242d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
2243d522f475Smrg	SEG( MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
2244d522f475Smrg	-1
2245d522f475Smrg    }, upper_left_corner[] =
2246d522f475Smrg    {
2247d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2248d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
2249d522f475Smrg	-1
2250d522f475Smrg    }, lower_left_corner[] =
2251d522f475Smrg    {
2252d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
2253d522f475Smrg	SEG(  MID_WIDE,	    MID_WIDE,	  BOX_WIDE,	MID_HIGH),
2254d522f475Smrg	-1
2255d522f475Smrg    }, cross[] =
2256d522f475Smrg    {
2257d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2258d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2259d522f475Smrg	-1
2260d522f475Smrg    }, scan_line_1[] =
2261d522f475Smrg    {
2262d522f475Smrg	SEG(  0,	    0,		  BOX_WIDE,	0),
2263d522f475Smrg	-1
2264d522f475Smrg    }, scan_line_3[] =
2265d522f475Smrg    {
2266d522f475Smrg	SEG(  0,	    BOX_HIGH/4,	  BOX_WIDE,	BOX_HIGH/4),
2267d522f475Smrg	-1
2268d522f475Smrg    }, scan_line_7[] =
2269d522f475Smrg    {
2270d522f475Smrg	SEG( 0,		    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2271d522f475Smrg	-1
2272d522f475Smrg    }, scan_line_9[] =
2273d522f475Smrg    {
2274d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  BOX_WIDE,   3*BOX_HIGH/4),
2275d522f475Smrg	-1
2276d522f475Smrg    }, horizontal_line[] =
2277d522f475Smrg    {
2278d522f475Smrg	SEG(  0,	    BOX_HIGH,	  BOX_WIDE,	BOX_HIGH),
2279d522f475Smrg	-1
2280d522f475Smrg    }, left_tee[] =
2281d522f475Smrg    {
2282d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2283d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2284d522f475Smrg	-1
2285d522f475Smrg    }, right_tee[] =
2286d522f475Smrg    {
2287d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2288d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  0,		MID_HIGH),
2289d522f475Smrg	-1
2290d522f475Smrg    }, bottom_tee[] =
2291d522f475Smrg    {
2292d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2293d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
2294d522f475Smrg	-1
2295d522f475Smrg    }, top_tee[] =
2296d522f475Smrg    {
2297d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2298d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
2299d522f475Smrg	-1
2300d522f475Smrg    }, vertical_line[] =
2301d522f475Smrg    {
2302d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2303d522f475Smrg	-1
2304d522f475Smrg    }, less_than_or_equal[] =
2305d522f475Smrg    {
2306d522f475Smrg	SEG(  CHR_WIDE,	    BOX_HIGH/3,	  0,		MID_HIGH),
2307d522f475Smrg	SEG(  CHR_WIDE,	  2*BOX_HIGH/3,	  0,		MID_HIGH),
2308d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
2309d522f475Smrg	-1
2310d522f475Smrg    }, greater_than_or_equal[] =
2311d522f475Smrg    {
2312d522f475Smrg	SEG(  0,	    BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
2313d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
2314d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
2315d522f475Smrg	-1
2316d522f475Smrg    }, greek_pi[] =
2317d522f475Smrg    {
2318d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
2319d522f475Smrg	SEG(5*CHR_WIDE/6,   MID_HIGH,	5*CHR_WIDE/6,	CHR_HIGH),
2320d522f475Smrg	SEG(2*CHR_WIDE/6,   MID_HIGH,	2*CHR_WIDE/6,	CHR_HIGH),
2321d522f475Smrg	-1
2322d522f475Smrg    }, not_equal_to[] =
2323d522f475Smrg    {
2324d522f475Smrg	SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3,	CHR_HIGH),
2325d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,   2*BOX_HIGH/3),
2326d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
2327d522f475Smrg	-1
2328d522f475Smrg    };
2329d522f475Smrg    /* *INDENT-ON* */
2330d522f475Smrg
2331d522f475Smrg    static const short *lines[] =
2332d522f475Smrg    {
2333d522f475Smrg	0,			/* 00 (unused) */
2334d522f475Smrg	0,			/* 01 diamond */
2335d522f475Smrg	0,			/* 02 box */
2336d522f475Smrg	glyph_ht,		/* 03 HT */
2337d522f475Smrg	glyph_ff,		/* 04 FF */
2338d522f475Smrg	0,			/* 05 CR */
2339d522f475Smrg	glyph_lf,		/* 06 LF */
2340d522f475Smrg	0,			/* 07 degrees (small circle) */
2341d522f475Smrg	plus_or_minus,		/* 08 */
2342d522f475Smrg	glyph_nl,		/* 09 */
2343d522f475Smrg	glyph_vt,		/* 0A */
2344d522f475Smrg	lower_right_corner,	/* 0B */
2345d522f475Smrg	upper_right_corner,	/* 0C */
2346d522f475Smrg	upper_left_corner,	/* 0D */
2347d522f475Smrg	lower_left_corner,	/* 0E */
2348d522f475Smrg	cross,			/* 0F */
2349d522f475Smrg	scan_line_1,		/* 10 */
2350d522f475Smrg	scan_line_3,		/* 11 */
2351d522f475Smrg	scan_line_7,		/* 12 */
2352d522f475Smrg	scan_line_9,		/* 13 */
2353d522f475Smrg	horizontal_line,	/* 14 */
2354d522f475Smrg	left_tee,		/* 15 */
2355d522f475Smrg	right_tee,		/* 16 */
2356d522f475Smrg	bottom_tee,		/* 17 */
2357d522f475Smrg	top_tee,		/* 18 */
2358d522f475Smrg	vertical_line,		/* 19 */
2359d522f475Smrg	less_than_or_equal,	/* 1A */
2360d522f475Smrg	greater_than_or_equal,	/* 1B */
2361d522f475Smrg	greek_pi,		/* 1C */
2362d522f475Smrg	not_equal_to,		/* 1D */
2363d522f475Smrg	0,			/* 1E LB */
2364d522f475Smrg	0,			/* 1F bullet */
2365d522f475Smrg    };
2366d522f475Smrg
2367d522f475Smrg    GC gc2;
2368d522f475Smrg    CgsEnum cgsId = (ch == 2) ? gcDots : gcLine;
2369d522f475Smrg    VTwin *cgsWin = WhichVWin(screen);
2370d522f475Smrg    const short *p;
2371956cc18dSsnj    unsigned font_width = (unsigned) (((flags & DOUBLEWFONT) ? 2 : 1) * screen->fnt_wide);
2372956cc18dSsnj    unsigned font_height = (unsigned) (((flags & DOUBLEHFONT) ? 2 : 1) * screen->fnt_high);
2373d522f475Smrg
2374d522f475Smrg    if (cells > 1)
2375956cc18dSsnj	font_width *= (unsigned) cells;
2376d522f475Smrg
2377d522f475Smrg#if OPT_WIDE_CHARS
2378d522f475Smrg    /*
2379d522f475Smrg     * Try to show line-drawing characters if we happen to be in UTF-8
2380d522f475Smrg     * mode, but have gotten an old-style font.
2381d522f475Smrg     */
2382d522f475Smrg    if (screen->utf8_mode
2383d522f475Smrg#if OPT_RENDERFONT
2384d522f475Smrg	&& !UsingRenderFont(xw)
2385d522f475Smrg#endif
2386d522f475Smrg	&& (ch > 127)
2387d522f475Smrg	&& (ch != UCS_REPL)) {
2388d522f475Smrg	unsigned n;
2389d522f475Smrg	for (n = 1; n < 32; n++) {
2390d522f475Smrg	    if (dec2ucs(n) == ch
239120d2c4d2Smrg		&& !((flags & BOLD)
239220d2c4d2Smrg		     ? IsXtermMissingChar(screen, n, &screen->fnts[fBold])
239320d2c4d2Smrg		     : IsXtermMissingChar(screen, n, &screen->fnts[fNorm]))) {
2394d522f475Smrg		TRACE(("...use xterm-style linedrawing\n"));
2395d522f475Smrg		ch = n;
2396d522f475Smrg		break;
2397d522f475Smrg	    }
2398d522f475Smrg	}
2399d522f475Smrg    }
2400d522f475Smrg#endif
2401d522f475Smrg
2402d522f475Smrg    TRACE(("DRAW_BOX(%d) cell %dx%d at %d,%d%s\n",
2403d522f475Smrg	   ch, font_height, font_width, y, x,
2404d522f475Smrg	   (ch >= (sizeof(lines) / sizeof(lines[0]))
2405d522f475Smrg	    ? "-BAD"
2406d522f475Smrg	    : "")));
2407d522f475Smrg
2408d522f475Smrg    if (cgsId == gcDots) {
2409d522f475Smrg	setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2410d522f475Smrg	setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc));
2411d522f475Smrg	setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2412d522f475Smrg    } else {
2413d522f475Smrg	setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2414d522f475Smrg	setCgsFore(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2415d522f475Smrg	setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2416d522f475Smrg    }
2417d522f475Smrg    gc2 = getCgsGC(xw, cgsWin, cgsId);
2418d522f475Smrg
2419d522f475Smrg    if (!(flags & NOBACKGROUND)) {
2420d522f475Smrg	XFillRectangle(screen->display, VWindow(screen), gc2, x, y,
2421d522f475Smrg		       font_width,
2422d522f475Smrg		       font_height);
2423d522f475Smrg    }
2424d522f475Smrg
2425d522f475Smrg    setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2426d522f475Smrg    setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc));
2427d522f475Smrg    setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2428d522f475Smrg    gc2 = getCgsGC(xw, cgsWin, cgsId);
2429d522f475Smrg
2430d522f475Smrg    XSetLineAttributes(screen->display, gc2,
2431d522f475Smrg		       (flags & BOLD)
2432d522f475Smrg		       ? ((font_height > 12)
2433d522f475Smrg			  ? font_height / 12
2434d522f475Smrg			  : 1)
2435d522f475Smrg		       : ((font_height > 16)
2436d522f475Smrg			  ? font_height / 16
2437d522f475Smrg			  : 1),
2438d522f475Smrg		       LineSolid,
2439d522f475Smrg		       CapProjecting,
2440d522f475Smrg		       JoinMiter);
2441d522f475Smrg
2442d522f475Smrg    if (ch == 1) {		/* diamond */
2443d522f475Smrg	XPoint points[5];
2444d522f475Smrg	int npoints = 5, n;
2445d522f475Smrg
2446d522f475Smrg	points[0].x = MID_WIDE;
2447d522f475Smrg	points[0].y = BOX_HIGH / 4;
2448d522f475Smrg
2449d522f475Smrg	points[1].x = 8 * BOX_WIDE / 8;
2450d522f475Smrg	points[1].y = MID_HIGH;
2451d522f475Smrg
2452d522f475Smrg	points[2].x = points[0].x;
2453d522f475Smrg	points[2].y = 3 * BOX_HIGH / 4;
2454d522f475Smrg
2455d522f475Smrg	points[3].x = 0 * BOX_WIDE / 8;
2456d522f475Smrg	points[3].y = points[1].y;
2457d522f475Smrg
2458d522f475Smrg	points[4].x = points[0].x;
2459d522f475Smrg	points[4].y = points[0].y;
2460d522f475Smrg
2461d522f475Smrg	for (n = 0; n < npoints; ++n) {
2462d522f475Smrg	    SCALE_X(points[n].x);
2463d522f475Smrg	    SCALE_Y(points[n].y);
2464d522f475Smrg	    points[n].x += x;
2465d522f475Smrg	    points[n].y += y;
2466d522f475Smrg	}
2467d522f475Smrg
2468d522f475Smrg	XFillPolygon(screen->display,
2469d522f475Smrg		     VWindow(screen), gc2,
2470d522f475Smrg		     points, npoints,
2471d522f475Smrg		     Convex, CoordModeOrigin);
2472d522f475Smrg    } else if (ch == 7) {	/* degrees */
2473d522f475Smrg	unsigned width = (BOX_WIDE / 3);
2474956cc18dSsnj	int x_coord = MID_WIDE - (int) (width / 2);
2475956cc18dSsnj	int y_coord = MID_HIGH - (int) width;
2476d522f475Smrg
2477d522f475Smrg	SCALE_X(x_coord);
2478d522f475Smrg	SCALE_Y(y_coord);
2479d522f475Smrg	SCALE_X(width);
2480d522f475Smrg
2481d522f475Smrg	XDrawArc(screen->display,
2482d522f475Smrg		 VWindow(screen), gc2,
2483d522f475Smrg		 x + x_coord, y + y_coord, width, width,
2484d522f475Smrg		 0,
2485d522f475Smrg		 360 * 64);
2486d522f475Smrg    } else if (ch == 0x1f) {	/* bullet */
2487d522f475Smrg	unsigned width = 7 * BOX_WIDE / 10;
2488956cc18dSsnj	int x_coord = MID_WIDE - (int) (width / 3);
2489956cc18dSsnj	int y_coord = MID_HIGH - (int) (width / 3);
2490d522f475Smrg
2491d522f475Smrg	SCALE_X(x_coord);
2492d522f475Smrg	SCALE_Y(y_coord);
2493d522f475Smrg	SCALE_X(width);
2494d522f475Smrg
2495d522f475Smrg	XDrawArc(screen->display,
2496d522f475Smrg		 VWindow(screen), gc2,
2497d522f475Smrg		 x + x_coord, y + y_coord, width, width,
2498d522f475Smrg		 0,
2499d522f475Smrg		 360 * 64);
2500d522f475Smrg    } else if (ch < (sizeof(lines) / sizeof(lines[0]))
2501d522f475Smrg	       && (p = lines[ch]) != 0) {
2502956cc18dSsnj	int coord[4];
2503d522f475Smrg	int n = 0;
2504d522f475Smrg	while (*p >= 0) {
2505d522f475Smrg	    coord[n++] = *p++;
2506d522f475Smrg	    if (n == 4) {
2507d522f475Smrg		SCALE_X(coord[0]);
2508d522f475Smrg		SCALE_Y(coord[1]);
2509d522f475Smrg		SCALE_X(coord[2]);
2510d522f475Smrg		SCALE_Y(coord[3]);
2511d522f475Smrg		XDrawLine(screen->display,
2512d522f475Smrg			  VWindow(screen), gc2,
2513d522f475Smrg			  x + coord[0], y + coord[1],
2514d522f475Smrg			  x + coord[2], y + coord[3]);
2515d522f475Smrg		n = 0;
2516d522f475Smrg	    }
2517d522f475Smrg	}
2518d522f475Smrg    } else if (screen->force_all_chars) {
2519d522f475Smrg	/* bounding rectangle, for debugging */
2520d522f475Smrg	XDrawRectangle(screen->display, VWindow(screen), gc2, x, y,
2521d522f475Smrg		       font_width - 1,
2522d522f475Smrg		       font_height - 1);
2523d522f475Smrg    }
2524d522f475Smrg}
2525d522f475Smrg
2526d522f475Smrg#if OPT_RENDERFONT
2527d522f475Smrg
2528d522f475Smrg/*
2529d522f475Smrg * Check if the given character has a glyph known to Xft.
2530d522f475Smrg *
2531d522f475Smrg * see xc/lib/Xft/xftglyphs.c
2532d522f475Smrg */
2533d522f475SmrgBool
2534d522f475SmrgxtermXftMissing(XtermWidget xw, XftFont * font, unsigned wc)
2535d522f475Smrg{
2536d522f475Smrg    Bool result = False;
2537d522f475Smrg
2538d522f475Smrg    if (font != 0) {
2539956cc18dSsnj	TScreen *screen = TScreenOf(xw);
2540956cc18dSsnj	if (!XftGlyphExists(screen->display, font, wc)) {
2541d522f475Smrg#if OPT_WIDE_CHARS
2542d522f475Smrg	    TRACE(("xtermXftMissing %d (dec=%#x, ucs=%#x)\n",
2543d522f475Smrg		   wc, ucs2dec(wc), dec2ucs(wc)));
2544d522f475Smrg#else
2545d522f475Smrg	    TRACE(("xtermXftMissing %d\n", wc));
2546d522f475Smrg#endif
2547d522f475Smrg	    result = True;
2548d522f475Smrg	}
2549d522f475Smrg    }
2550d522f475Smrg    return result;
2551d522f475Smrg}
2552d522f475Smrg#endif /* OPT_RENDERFONT && OPT_WIDE_CHARS */
2553d522f475Smrg
2554d522f475Smrg#endif /* OPT_BOX_CHARS */
2555d522f475Smrg
2556d522f475Smrg#if OPT_WIDE_CHARS
2557d522f475Smrg#define MY_UCS(ucs,dec) case ucs: result = dec; break
2558d522f475Smrgunsigned
2559d522f475Smrgucs2dec(unsigned ch)
2560d522f475Smrg{
2561d522f475Smrg    unsigned result = ch;
2562d522f475Smrg    if ((ch > 127)
2563d522f475Smrg	&& (ch != UCS_REPL)) {
2564d522f475Smrg	switch (ch) {
2565d522f475Smrg	    MY_UCS(0x25ae, 0);	/* black vertical rectangle                   */
2566d522f475Smrg	    MY_UCS(0x25c6, 1);	/* black diamond                              */
2567d522f475Smrg	    MY_UCS(0x2592, 2);	/* medium shade                               */
2568d522f475Smrg	    MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation           */
2569d522f475Smrg	    MY_UCS(0x240c, 4);	/* symbol for form feed                       */
2570d522f475Smrg	    MY_UCS(0x240d, 5);	/* symbol for carriage return                 */
2571d522f475Smrg	    MY_UCS(0x240a, 6);	/* symbol for line feed                       */
2572d522f475Smrg	    MY_UCS(0x00b0, 7);	/* degree sign                                */
2573d522f475Smrg	    MY_UCS(0x00b1, 8);	/* plus-minus sign                            */
2574d522f475Smrg	    MY_UCS(0x2424, 9);	/* symbol for newline                         */
2575d522f475Smrg	    MY_UCS(0x240b, 10);	/* symbol for vertical tabulation             */
2576d522f475Smrg	    MY_UCS(0x2518, 11);	/* box drawings light up and left             */
2577d522f475Smrg	    MY_UCS(0x2510, 12);	/* box drawings light down and left           */
2578d522f475Smrg	    MY_UCS(0x250c, 13);	/* box drawings light down and right          */
2579d522f475Smrg	    MY_UCS(0x2514, 14);	/* box drawings light up and right            */
2580d522f475Smrg	    MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
2581d522f475Smrg	    MY_UCS(0x23ba, 16);	/* box drawings scan 1                        */
2582d522f475Smrg	    MY_UCS(0x23bb, 17);	/* box drawings scan 3                        */
2583d522f475Smrg	    MY_UCS(0x2500, 18);	/* box drawings light horizontal              */
2584d522f475Smrg	    MY_UCS(0x23bc, 19);	/* box drawings scan 7                        */
2585d522f475Smrg	    MY_UCS(0x23bd, 20);	/* box drawings scan 9                        */
2586d522f475Smrg	    MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
2587d522f475Smrg	    MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
2588d522f475Smrg	    MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
2589d522f475Smrg	    MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
2590d522f475Smrg	    MY_UCS(0x2502, 25);	/* box drawings light vertical                */
2591d522f475Smrg	    MY_UCS(0x2264, 26);	/* less-than or equal to                      */
2592d522f475Smrg	    MY_UCS(0x2265, 27);	/* greater-than or equal to                   */
2593d522f475Smrg	    MY_UCS(0x03c0, 28);	/* greek small letter pi                      */
2594d522f475Smrg	    MY_UCS(0x2260, 29);	/* not equal to                               */
2595d522f475Smrg	    MY_UCS(0x00a3, 30);	/* pound sign                                 */
2596d522f475Smrg	    MY_UCS(0x00b7, 31);	/* middle dot                                 */
2597d522f475Smrg	}
2598d522f475Smrg    }
2599d522f475Smrg    return result;
2600d522f475Smrg}
2601d522f475Smrg
2602d522f475Smrg#undef  MY_UCS
2603d522f475Smrg#define MY_UCS(ucs,dec) case dec: result = ucs; break
2604d522f475Smrg
2605d522f475Smrgunsigned
2606d522f475Smrgdec2ucs(unsigned ch)
2607d522f475Smrg{
2608d522f475Smrg    unsigned result = ch;
2609d522f475Smrg    if (xtermIsDecGraphic(ch)) {
2610d522f475Smrg	switch (ch) {
2611d522f475Smrg	    MY_UCS(0x25ae, 0);	/* black vertical rectangle                   */
2612d522f475Smrg	    MY_UCS(0x25c6, 1);	/* black diamond                              */
2613d522f475Smrg	    MY_UCS(0x2592, 2);	/* medium shade                               */
2614d522f475Smrg	    MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation           */
2615d522f475Smrg	    MY_UCS(0x240c, 4);	/* symbol for form feed                       */
2616d522f475Smrg	    MY_UCS(0x240d, 5);	/* symbol for carriage return                 */
2617d522f475Smrg	    MY_UCS(0x240a, 6);	/* symbol for line feed                       */
2618d522f475Smrg	    MY_UCS(0x00b0, 7);	/* degree sign                                */
2619d522f475Smrg	    MY_UCS(0x00b1, 8);	/* plus-minus sign                            */
2620d522f475Smrg	    MY_UCS(0x2424, 9);	/* symbol for newline                         */
2621d522f475Smrg	    MY_UCS(0x240b, 10);	/* symbol for vertical tabulation             */
2622d522f475Smrg	    MY_UCS(0x2518, 11);	/* box drawings light up and left             */
2623d522f475Smrg	    MY_UCS(0x2510, 12);	/* box drawings light down and left           */
2624d522f475Smrg	    MY_UCS(0x250c, 13);	/* box drawings light down and right          */
2625d522f475Smrg	    MY_UCS(0x2514, 14);	/* box drawings light up and right            */
2626d522f475Smrg	    MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
2627d522f475Smrg	    MY_UCS(0x23ba, 16);	/* box drawings scan 1                        */
2628d522f475Smrg	    MY_UCS(0x23bb, 17);	/* box drawings scan 3                        */
2629d522f475Smrg	    MY_UCS(0x2500, 18);	/* box drawings light horizontal              */
2630d522f475Smrg	    MY_UCS(0x23bc, 19);	/* box drawings scan 7                        */
2631d522f475Smrg	    MY_UCS(0x23bd, 20);	/* box drawings scan 9                        */
2632d522f475Smrg	    MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
2633d522f475Smrg	    MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
2634d522f475Smrg	    MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
2635d522f475Smrg	    MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
2636d522f475Smrg	    MY_UCS(0x2502, 25);	/* box drawings light vertical                */
2637d522f475Smrg	    MY_UCS(0x2264, 26);	/* less-than or equal to                      */
2638d522f475Smrg	    MY_UCS(0x2265, 27);	/* greater-than or equal to                   */
2639d522f475Smrg	    MY_UCS(0x03c0, 28);	/* greek small letter pi                      */
2640d522f475Smrg	    MY_UCS(0x2260, 29);	/* not equal to                               */
2641d522f475Smrg	    MY_UCS(0x00a3, 30);	/* pound sign                                 */
2642d522f475Smrg	    MY_UCS(0x00b7, 31);	/* middle dot                                 */
2643d522f475Smrg	}
2644d522f475Smrg    }
2645d522f475Smrg    return result;
2646d522f475Smrg}
2647d522f475Smrg
2648d522f475Smrg#endif /* OPT_WIDE_CHARS */
2649d522f475Smrg
2650d522f475Smrg#if OPT_SHIFT_FONTS
2651d522f475Smrgstatic void
2652d522f475SmrglookupOneFontSize(XtermWidget xw, int fontnum)
2653d522f475Smrg{
2654d522f475Smrg    TScreen *screen = TScreenOf(xw);
2655d522f475Smrg
2656d522f475Smrg    if (screen->menu_font_sizes[fontnum] == 0) {
2657d522f475Smrg	XTermFonts fnt;
2658d522f475Smrg
2659d522f475Smrg	memset(&fnt, 0, sizeof(fnt));
2660d522f475Smrg	screen->menu_font_sizes[fontnum] = -1;
2661956cc18dSsnj	if (xtermOpenFont(xw, screen->MenuFontName(fontnum), &fnt, fwAlways, True)) {
266220d2c4d2Smrg	    if (fontnum <= fontMenu_lastBuiltin
266320d2c4d2Smrg		|| strcmp(fnt.fn, DEFFONT))
266420d2c4d2Smrg		screen->menu_font_sizes[fontnum] = FontSize(fnt.fs);
2665d522f475Smrg	    xtermCloseFont(xw, &fnt);
2666d522f475Smrg	}
2667d522f475Smrg    }
2668d522f475Smrg}
2669d522f475Smrg
2670d522f475Smrg/*
2671d522f475Smrg * Cache the font-sizes so subsequent larger/smaller font actions will go fast.
2672d522f475Smrg */
2673d522f475Smrgstatic void
2674d522f475SmrglookupFontSizes(XtermWidget xw)
2675d522f475Smrg{
2676d522f475Smrg    int n;
2677d522f475Smrg
2678d522f475Smrg    for (n = 0; n < NMENUFONTS; n++) {
2679d522f475Smrg	lookupOneFontSize(xw, n);
2680d522f475Smrg    }
2681d522f475Smrg}
2682d522f475Smrg
26832eaa94a1Schristos#if OPT_RENDERFONT
26842eaa94a1Schristos#define NMENU_RENDERFONTS (NMENUFONTS - 2)	/* no selection or escape */
26852eaa94a1Schristosstatic Boolean
26862eaa94a1SchristosuseFaceSizes(XtermWidget xw)
26872eaa94a1Schristos{
26882eaa94a1Schristos    Boolean result = False;
26892eaa94a1Schristos    int n;
26902eaa94a1Schristos
26912eaa94a1Schristos    if (UsingRenderFont(xw)) {
26922eaa94a1Schristos	result = True;
26932eaa94a1Schristos	for (n = 0; n < NMENU_RENDERFONTS; ++n) {
26942eaa94a1Schristos	    if (xw->misc.face_size[n] <= 0.0) {
26952eaa94a1Schristos		result = False;
26962eaa94a1Schristos		break;
26972eaa94a1Schristos	    }
26982eaa94a1Schristos	}
2699956cc18dSsnj	if (!result) {
2700956cc18dSsnj	    Boolean broken_fonts = True;
2701956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
270220d2c4d2Smrg	    long first = screen->menu_font_sizes[0];
2703956cc18dSsnj
2704956cc18dSsnj	    lookupFontSizes(xw);
2705956cc18dSsnj	    for (n = 0; n < NMENUFONTS; n++) {
2706956cc18dSsnj		if (screen->menu_font_sizes[n] > 0
2707956cc18dSsnj		    && screen->menu_font_sizes[n] != first) {
2708956cc18dSsnj		    broken_fonts = False;
2709956cc18dSsnj		    break;
2710956cc18dSsnj		}
2711956cc18dSsnj	    }
2712956cc18dSsnj
2713956cc18dSsnj	    /*
2714956cc18dSsnj	     * Workaround for breakage in font-packages - check if all of the
2715956cc18dSsnj	     * bitmap font sizes are the same, and if we're using TrueType
2716956cc18dSsnj	     * fonts.
2717956cc18dSsnj	     */
2718956cc18dSsnj	    if (broken_fonts) {
2719956cc18dSsnj		float lo_value = (float) 9.0e9;
2720956cc18dSsnj		float hi_value = (float) 0.0;
2721956cc18dSsnj		float value;
2722956cc18dSsnj
2723956cc18dSsnj		TRACE(("bitmap fonts are broken - set faceSize resources\n"));
2724956cc18dSsnj		for (n = 0; n < NMENUFONTS; n++) {
2725956cc18dSsnj		    value = xw->misc.face_size[n];
2726956cc18dSsnj		    if (value > 0.0) {
2727956cc18dSsnj			if (lo_value > value)
2728956cc18dSsnj			    lo_value = value;
2729956cc18dSsnj			if (hi_value < value)
2730956cc18dSsnj			    hi_value = value;
2731956cc18dSsnj		    }
2732956cc18dSsnj		}
2733956cc18dSsnj
2734956cc18dSsnj		if (hi_value <= 0.0)
2735956cc18dSsnj		    sscanf(DEFFACESIZE, "%f", &value);
2736956cc18dSsnj		else
2737956cc18dSsnj		    value = (float) ((hi_value + lo_value) / 2.0);
2738956cc18dSsnj		if (value <= 0)
2739956cc18dSsnj		    value = (float) 14.0;
2740956cc18dSsnj
2741956cc18dSsnj		for (n = 0; n < NMENUFONTS; n++) {
2742956cc18dSsnj		    TRACE(("setting faceSize%d %.1f\n", n, value));
2743956cc18dSsnj		    xw->misc.face_size[n] = value;
2744956cc18dSsnj		    value = (float) (value * 1.1);
2745956cc18dSsnj		}
2746956cc18dSsnj		result = True;
2747956cc18dSsnj	    }
2748956cc18dSsnj	}
27492eaa94a1Schristos    }
27502eaa94a1Schristos    return result;
27512eaa94a1Schristos}
27522eaa94a1Schristos#endif
27532eaa94a1Schristos
2754d522f475Smrg/*
2755d522f475Smrg * Find the index of a larger/smaller font (according to the sign of 'relative'
2756d522f475Smrg * and its magnitude), starting from the 'old' index.
2757d522f475Smrg */
2758d522f475Smrgint
2759d522f475SmrglookupRelativeFontSize(XtermWidget xw, int old, int relative)
2760d522f475Smrg{
2761d522f475Smrg    TScreen *screen = TScreenOf(xw);
2762d522f475Smrg    int n, m = -1;
2763d522f475Smrg
27642eaa94a1Schristos    TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative));
2765d522f475Smrg    if (!IsIcon(screen)) {
27662eaa94a1Schristos#if OPT_RENDERFONT
27672eaa94a1Schristos	if (useFaceSizes(xw)) {
27682eaa94a1Schristos	    TRACE(("...using FaceSize\n"));
27692eaa94a1Schristos	    if (relative != 0) {
27702eaa94a1Schristos		for (n = 0; n < NMENU_RENDERFONTS; ++n) {
27712eaa94a1Schristos		    if (xw->misc.face_size[n] > 0 &&
27722eaa94a1Schristos			xw->misc.face_size[n] != xw->misc.face_size[old]) {
27732eaa94a1Schristos			int cmp_0 = ((xw->misc.face_size[n] >
27742eaa94a1Schristos				      xw->misc.face_size[old])
27752eaa94a1Schristos				     ? relative
27762eaa94a1Schristos				     : -relative);
27772eaa94a1Schristos			int cmp_m = ((m < 0)
27782eaa94a1Schristos				     ? 1
27792eaa94a1Schristos				     : ((xw->misc.face_size[n] <
27802eaa94a1Schristos					 xw->misc.face_size[m])
27812eaa94a1Schristos					? relative
27822eaa94a1Schristos					: -relative));
27832eaa94a1Schristos			if (cmp_0 > 0 && cmp_m > 0) {
27842eaa94a1Schristos			    m = n;
27852eaa94a1Schristos			}
2786d522f475Smrg		    }
2787d522f475Smrg		}
2788d522f475Smrg	    }
27892eaa94a1Schristos	} else
27902eaa94a1Schristos#endif
27912eaa94a1Schristos	{
27922eaa94a1Schristos	    TRACE(("...using bitmap areas\n"));
27932eaa94a1Schristos	    lookupFontSizes(xw);
27942eaa94a1Schristos	    if (relative != 0) {
27952eaa94a1Schristos		for (n = 0; n < NMENUFONTS; ++n) {
27962eaa94a1Schristos		    if (screen->menu_font_sizes[n] > 0 &&
27972eaa94a1Schristos			screen->menu_font_sizes[n] !=
27982eaa94a1Schristos			screen->menu_font_sizes[old]) {
27992eaa94a1Schristos			int cmp_0 = ((screen->menu_font_sizes[n] >
28002eaa94a1Schristos				      screen->menu_font_sizes[old])
28012eaa94a1Schristos				     ? relative
28022eaa94a1Schristos				     : -relative);
28032eaa94a1Schristos			int cmp_m = ((m < 0)
28042eaa94a1Schristos				     ? 1
28052eaa94a1Schristos				     : ((screen->menu_font_sizes[n] <
28062eaa94a1Schristos					 screen->menu_font_sizes[m])
28072eaa94a1Schristos					? relative
28082eaa94a1Schristos					: -relative));
28092eaa94a1Schristos			if (cmp_0 > 0 && cmp_m > 0) {
28102eaa94a1Schristos			    m = n;
28112eaa94a1Schristos			}
28122eaa94a1Schristos		    }
28132eaa94a1Schristos		}
2814d522f475Smrg	    }
2815d522f475Smrg	}
28162eaa94a1Schristos	TRACE(("...new index %d\n", m));
28172eaa94a1Schristos	if (m >= 0) {
28182eaa94a1Schristos	    if (relative > 1)
28192eaa94a1Schristos		m = lookupRelativeFontSize(xw, m, relative - 1);
28202eaa94a1Schristos	    else if (relative < -1)
28212eaa94a1Schristos		m = lookupRelativeFontSize(xw, m, relative + 1);
28222eaa94a1Schristos	}
2823d522f475Smrg    }
2824d522f475Smrg    return m;
2825d522f475Smrg}
2826d522f475Smrg
2827d522f475Smrg/* ARGSUSED */
2828d522f475Smrgvoid
2829d522f475SmrgHandleLargerFont(Widget w GCC_UNUSED,
2830d522f475Smrg		 XEvent * event GCC_UNUSED,
2831d522f475Smrg		 String * params GCC_UNUSED,
2832d522f475Smrg		 Cardinal *param_count GCC_UNUSED)
2833d522f475Smrg{
2834956cc18dSsnj    XtermWidget xw;
2835d522f475Smrg
283620d2c4d2Smrg    TRACE(("Handle larger-vt-font for %p\n", (void *) w));
2837956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
2838d522f475Smrg	if (xw->misc.shift_fonts) {
2839956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
2840d522f475Smrg	    int m;
2841d522f475Smrg
2842d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, 1);
2843d522f475Smrg	    if (m >= 0) {
2844d522f475Smrg		SetVTFont(xw, m, True, NULL);
2845d522f475Smrg	    } else {
284620d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
2847d522f475Smrg	    }
2848d522f475Smrg	}
2849d522f475Smrg    }
2850d522f475Smrg}
2851d522f475Smrg
2852d522f475Smrg/* ARGSUSED */
2853d522f475Smrgvoid
2854d522f475SmrgHandleSmallerFont(Widget w GCC_UNUSED,
2855d522f475Smrg		  XEvent * event GCC_UNUSED,
2856d522f475Smrg		  String * params GCC_UNUSED,
2857d522f475Smrg		  Cardinal *param_count GCC_UNUSED)
2858d522f475Smrg{
2859956cc18dSsnj    XtermWidget xw;
2860d522f475Smrg
286120d2c4d2Smrg    TRACE(("Handle smaller-vt-font for %p\n", (void *) w));
2862956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
2863d522f475Smrg	if (xw->misc.shift_fonts) {
2864956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
2865d522f475Smrg	    int m;
2866d522f475Smrg
2867d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, -1);
2868d522f475Smrg	    if (m >= 0) {
2869d522f475Smrg		SetVTFont(xw, m, True, NULL);
2870d522f475Smrg	    } else {
287120d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
2872d522f475Smrg	    }
2873d522f475Smrg	}
2874d522f475Smrg    }
2875d522f475Smrg}
2876d522f475Smrg#endif
2877d522f475Smrg
2878d522f475Smrgint
2879d522f475SmrgxtermGetFont(const char *param)
2880d522f475Smrg{
2881d522f475Smrg    int fontnum;
2882d522f475Smrg
2883d522f475Smrg    switch (param[0]) {
2884d522f475Smrg    case 'd':
2885d522f475Smrg    case 'D':
2886d522f475Smrg    case '0':
2887d522f475Smrg	fontnum = fontMenu_default;
2888d522f475Smrg	break;
2889d522f475Smrg    case '1':
2890d522f475Smrg	fontnum = fontMenu_font1;
2891d522f475Smrg	break;
2892d522f475Smrg    case '2':
2893d522f475Smrg	fontnum = fontMenu_font2;
2894d522f475Smrg	break;
2895d522f475Smrg    case '3':
2896d522f475Smrg	fontnum = fontMenu_font3;
2897d522f475Smrg	break;
2898d522f475Smrg    case '4':
2899d522f475Smrg	fontnum = fontMenu_font4;
2900d522f475Smrg	break;
2901d522f475Smrg    case '5':
2902d522f475Smrg	fontnum = fontMenu_font5;
2903d522f475Smrg	break;
2904d522f475Smrg    case '6':
2905d522f475Smrg	fontnum = fontMenu_font6;
2906d522f475Smrg	break;
2907d522f475Smrg    case 'e':
2908d522f475Smrg    case 'E':
2909d522f475Smrg	fontnum = fontMenu_fontescape;
2910d522f475Smrg	break;
2911d522f475Smrg    case 's':
2912d522f475Smrg    case 'S':
2913d522f475Smrg	fontnum = fontMenu_fontsel;
2914d522f475Smrg	break;
2915d522f475Smrg    default:
2916d522f475Smrg	fontnum = -1;
2917d522f475Smrg	break;
2918d522f475Smrg    }
2919d522f475Smrg    return fontnum;
2920d522f475Smrg}
2921d522f475Smrg
2922d522f475Smrg/* ARGSUSED */
2923d522f475Smrgvoid
2924d522f475SmrgHandleSetFont(Widget w GCC_UNUSED,
2925d522f475Smrg	      XEvent * event GCC_UNUSED,
2926d522f475Smrg	      String * params,
2927d522f475Smrg	      Cardinal *param_count)
2928d522f475Smrg{
2929956cc18dSsnj    XtermWidget xw;
2930956cc18dSsnj
2931956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
2932d522f475Smrg	int fontnum;
2933d522f475Smrg	VTFontNames fonts;
2934d522f475Smrg
2935d522f475Smrg	memset(&fonts, 0, sizeof(fonts));
2936d522f475Smrg
2937d522f475Smrg	if (*param_count == 0) {
2938d522f475Smrg	    fontnum = fontMenu_default;
2939d522f475Smrg	} else {
2940d522f475Smrg	    Cardinal maxparams = 1;	/* total number of params allowed */
2941d522f475Smrg	    int result = xtermGetFont(params[0]);
2942d522f475Smrg
2943d522f475Smrg	    switch (result) {
2944d522f475Smrg	    case fontMenu_default:	/* FALLTHRU */
2945d522f475Smrg	    case fontMenu_font1:	/* FALLTHRU */
2946d522f475Smrg	    case fontMenu_font2:	/* FALLTHRU */
2947d522f475Smrg	    case fontMenu_font3:	/* FALLTHRU */
2948d522f475Smrg	    case fontMenu_font4:	/* FALLTHRU */
2949d522f475Smrg	    case fontMenu_font5:	/* FALLTHRU */
2950d522f475Smrg	    case fontMenu_font6:	/* FALLTHRU */
2951d522f475Smrg		break;
2952d522f475Smrg	    case fontMenu_fontescape:
2953d522f475Smrg#if OPT_WIDE_CHARS
2954d522f475Smrg		maxparams = 5;
2955d522f475Smrg#else
2956d522f475Smrg		maxparams = 3;
2957d522f475Smrg#endif
2958d522f475Smrg		break;
2959d522f475Smrg	    case fontMenu_fontsel:
2960d522f475Smrg		maxparams = 2;
2961d522f475Smrg		break;
2962d522f475Smrg	    default:
296320d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
2964d522f475Smrg		return;
2965d522f475Smrg	    }
2966d522f475Smrg	    fontnum = result;
2967d522f475Smrg
2968d522f475Smrg	    if (*param_count > maxparams) {	/* see if extra args given */
296920d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
2970d522f475Smrg		return;
2971d522f475Smrg	    }
2972d522f475Smrg	    switch (*param_count) {	/* assign 'em */
2973d522f475Smrg#if OPT_WIDE_CHARS
2974d522f475Smrg	    case 5:
2975d522f475Smrg		fonts.f_wb = params[4];
2976d522f475Smrg		/* FALLTHRU */
2977d522f475Smrg	    case 4:
2978d522f475Smrg		fonts.f_w = params[3];
2979d522f475Smrg		/* FALLTHRU */
2980d522f475Smrg#endif
2981d522f475Smrg	    case 3:
2982d522f475Smrg		fonts.f_b = params[2];
2983d522f475Smrg		/* FALLTHRU */
2984d522f475Smrg	    case 2:
2985d522f475Smrg		fonts.f_n = params[1];
2986d522f475Smrg		break;
2987d522f475Smrg	    }
2988d522f475Smrg	}
2989d522f475Smrg
2990956cc18dSsnj	SetVTFont(xw, fontnum, True, &fonts);
2991d522f475Smrg    }
2992d522f475Smrg}
2993d522f475Smrg
2994d522f475Smrgvoid
2995d522f475SmrgSetVTFont(XtermWidget xw,
2996d522f475Smrg	  int which,
2997d522f475Smrg	  Bool doresize,
2998d522f475Smrg	  const VTFontNames * fonts)
2999d522f475Smrg{
3000956cc18dSsnj    TScreen *screen = TScreenOf(xw);
3001d522f475Smrg
3002d522f475Smrg    TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which,
3003d522f475Smrg	   (fonts && fonts->f_n) ? fonts->f_n : "<null>",
3004d522f475Smrg	   (fonts && fonts->f_b) ? fonts->f_b : "<null>"));
3005d522f475Smrg
3006d522f475Smrg    if (IsIcon(screen)) {
300720d2c4d2Smrg	Bell(xw, XkbBI_MinorError, 0);
3008d522f475Smrg    } else if (which >= 0 && which < NMENUFONTS) {
3009d522f475Smrg	VTFontNames myfonts;
3010d522f475Smrg
3011d522f475Smrg	memset(&myfonts, 0, sizeof(myfonts));
3012d522f475Smrg	if (fonts != 0)
3013d522f475Smrg	    myfonts = *fonts;
3014d522f475Smrg
3015d522f475Smrg	if (which == fontMenu_fontsel) {	/* go get the selection */
3016d522f475Smrg	    FindFontSelection(xw, myfonts.f_n, False);
3017d522f475Smrg	} else {
3018d522f475Smrg	    int oldFont = screen->menu_font_number;
3019d522f475Smrg
3020d522f475Smrg#define USE_CACHED(field, name) \
3021d522f475Smrg	    if (myfonts.field == 0) { \
3022492d43a5Smrg		myfonts.field = x_strdup(screen->menu_font_names[which][name]); \
3023d522f475Smrg		TRACE(("set myfonts." #field " from menu_font_names[%d][" #name "] %s\n", \
3024d522f475Smrg		       which, NonNull(myfonts.field))); \
3025d522f475Smrg	    } else { \
3026d522f475Smrg		TRACE(("set myfonts." #field " reused\n")); \
3027d522f475Smrg	    }
302820d2c4d2Smrg#define SAVE_FNAME(field, name) \
302920d2c4d2Smrg	    if (myfonts.field != 0) { \
303020d2c4d2Smrg		if (screen->menu_font_names[which][name] == 0 \
303120d2c4d2Smrg		 || strcmp(screen->menu_font_names[which][name], myfonts.field)) { \
303220d2c4d2Smrg		    TRACE(("updating menu_font_names[%d][" #name "] to %s\n", \
303320d2c4d2Smrg			   which, myfonts.field)); \
303420d2c4d2Smrg		    screen->menu_font_names[which][name] = x_strdup(myfonts.field); \
303520d2c4d2Smrg		} \
303620d2c4d2Smrg	    }
303720d2c4d2Smrg
3038d522f475Smrg	    USE_CACHED(f_n, fNorm);
3039d522f475Smrg	    USE_CACHED(f_b, fBold);
3040d522f475Smrg#if OPT_WIDE_CHARS
3041d522f475Smrg	    USE_CACHED(f_w, fWide);
3042d522f475Smrg	    USE_CACHED(f_wb, fWBold);
3043d522f475Smrg#endif
3044d522f475Smrg	    if (xtermLoadFont(xw,
3045d522f475Smrg			      &myfonts,
3046d522f475Smrg			      doresize, which)) {
304720d2c4d2Smrg		/*
304820d2c4d2Smrg		 * If successful, save the data so that a subsequent query via
304920d2c4d2Smrg		 * OSC-50 will return the expected values.
305020d2c4d2Smrg		 */
305120d2c4d2Smrg		SAVE_FNAME(f_n, fNorm);
305220d2c4d2Smrg		SAVE_FNAME(f_b, fBold);
305320d2c4d2Smrg#if OPT_WIDE_CHARS
305420d2c4d2Smrg		SAVE_FNAME(f_w, fWide);
305520d2c4d2Smrg		SAVE_FNAME(f_wb, fWBold);
305620d2c4d2Smrg#endif
3057d522f475Smrg	    } else {
3058d522f475Smrg		xtermLoadFont(xw,
3059d522f475Smrg			      xtermFontName(screen->MenuFontName(oldFont)),
3060d522f475Smrg			      doresize, oldFont);
306120d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
3062d522f475Smrg	    }
3063d522f475Smrg	}
306420d2c4d2Smrg    } else {
306520d2c4d2Smrg	Bell(xw, XkbBI_MinorError, 0);
3066d522f475Smrg    }
3067d522f475Smrg    return;
3068d522f475Smrg}
3069