fontutils.c revision e39b573c
1e39b573cSmrg/* $XTermId: fontutils.c,v 1.360 2011/07/13 09:54:49 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
922e39b573cSmrg    /*
923e39b573cSmrg     * If we are opening the default font, and it happens to be missing, force
924e39b573cSmrg     * that to the compiled-in default font, e.g., "fixed".  If we cannot open
925e39b573cSmrg     * the font, disable it from the menu.
926e39b573cSmrg     */
927e39b573cSmrg    if (!xtermOpenFont(xw,
928e39b573cSmrg		       myfonts.f_n,
929e39b573cSmrg		       &fnts[fNorm],
930e39b573cSmrg		       warn[fNorm],
931e39b573cSmrg		       (fontnum == fontMenu_default))) {
932e39b573cSmrg	SetItemSensitivity(fontMenuEntries[fontnum].widget, False);
933d522f475Smrg	goto bad;
934e39b573cSmrg    }
935d522f475Smrg
936d522f475Smrg    strcpy(normal, myfonts.f_n);
937956cc18dSsnj    if (!check_fontname(myfonts.f_b)) {
938956cc18dSsnj	warn[fBold] = fwAlways;
939d522f475Smrg	fp = get_font_name_props(screen->display, fnts[fNorm].fs, normal);
940d522f475Smrg	if (fp != 0) {
941d522f475Smrg	    myfonts.f_b = bold_font_name(fp, fp->average_width);
942956cc18dSsnj	    if (!xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], fwAlways, False)) {
943d522f475Smrg		myfonts.f_b = bold_font_name(fp, -1);
944956cc18dSsnj		xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], fwAlways, False);
945d522f475Smrg	    }
946492d43a5Smrg	    TRACE(("...derived bold '%s'\n", NonNull(myfonts.f_b)));
947d522f475Smrg	}
948d522f475Smrg	if (fp == 0 || fnts[fBold].fs == 0) {
949d522f475Smrg	    xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]);
950d522f475Smrg	    TRACE(("...cannot load a matching bold font\n"));
951d522f475Smrg	} else if (same_font_size(xw, fnts[fNorm].fs, fnts[fBold].fs)
952d522f475Smrg		   && got_bold_font(screen->display, fnts[fBold].fs, myfonts.f_b)) {
953d522f475Smrg	    TRACE(("...got a matching bold font\n"));
954d522f475Smrg	    cache_menu_font_name(screen, fontnum, fBold, myfonts.f_b);
955d522f475Smrg	} else {
956d522f475Smrg	    xtermCloseFont(xw, &fnts[fBold]);
957d522f475Smrg	    fnts[fBold] = fnts[fNorm];
958d522f475Smrg	    TRACE(("...did not get a matching bold font\n"));
959d522f475Smrg	}
960956cc18dSsnj    } else if (!xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], warn[fBold], False)) {
961d522f475Smrg	xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]);
962956cc18dSsnj	warn[fBold] = fwAlways;
963492d43a5Smrg	TRACE(("...cannot load bold font '%s'\n", NonNull(myfonts.f_b)));
964d522f475Smrg    } else {
965d522f475Smrg	cache_menu_font_name(screen, fontnum, fBold, myfonts.f_b);
966d522f475Smrg    }
967d522f475Smrg
968d522f475Smrg    /*
969d522f475Smrg     * If there is no widefont specified, fake it by doubling AVERAGE_WIDTH
970d522f475Smrg     * of normal fonts XLFD, and asking for it.  This plucks out 18x18ja
971d522f475Smrg     * and 12x13ja as the corresponding fonts for 9x18 and 6x13.
972d522f475Smrg     */
973d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
974d522f475Smrg	Bool derived;
975d522f475Smrg	char bold[MAX_FONTNAME];
976d522f475Smrg
977956cc18dSsnj	if (check_fontname(myfonts.f_w)) {
978d522f475Smrg	    cache_menu_font_name(screen, fontnum, fWide, myfonts.f_w);
979e39b573cSmrg	} else if (screen->utf8_fonts && !is_double_width_font(fnts[fNorm].fs)) {
980d522f475Smrg	    fp = get_font_name_props(screen->display, fnts[fNorm].fs, normal);
981d522f475Smrg	    if (fp != 0) {
982d522f475Smrg		myfonts.f_w = wide_font_name(fp);
983956cc18dSsnj		warn[fWide] = fwAlways;
984d522f475Smrg		TRACE(("...derived wide %s\n", NonNull(myfonts.f_w)));
985d522f475Smrg		cache_menu_font_name(screen, fontnum, fWide, myfonts.f_w);
986d522f475Smrg	    }
987d522f475Smrg	}
988d522f475Smrg
989956cc18dSsnj	if (check_fontname(myfonts.f_w)) {
990956cc18dSsnj	    (void) xtermOpenFont(xw, myfonts.f_w, &fnts[fWide], warn[fWide], False);
991d522f475Smrg	} else {
992d522f475Smrg	    xtermCopyFontInfo(&fnts[fWide], &fnts[fNorm]);
993956cc18dSsnj	    warn[fWide] = fwAlways;
994d522f475Smrg	}
995d522f475Smrg
996d522f475Smrg	derived = False;
997956cc18dSsnj	if (!check_fontname(myfonts.f_wb)) {
998d522f475Smrg	    fp = get_font_name_props(screen->display, fnts[fBold].fs, bold);
999d522f475Smrg	    if (fp != 0) {
1000d522f475Smrg		myfonts.f_wb = widebold_font_name(fp);
1001956cc18dSsnj		warn[fWBold] = fwAlways;
1002d522f475Smrg		derived = True;
1003d522f475Smrg	    }
1004d522f475Smrg	}
1005d522f475Smrg
1006956cc18dSsnj	if (check_fontname(myfonts.f_wb)) {
1007d522f475Smrg
1008e39b573cSmrg	    xtermOpenFont(xw,
1009e39b573cSmrg			  myfonts.f_wb,
1010e39b573cSmrg			  &fnts[fWBold],
1011e39b573cSmrg			  (screen->utf8_fonts
1012e39b573cSmrg			   ? warn[fWBold]
1013e39b573cSmrg			   : (xw->misc.fontWarnings + 1)),
1014e39b573cSmrg			  False);
1015d522f475Smrg
1016d522f475Smrg	    if (derived
1017d522f475Smrg		&& !compatibleWideCounts(fnts[fWide].fs, fnts[fWBold].fs)) {
1018d522f475Smrg		xtermCloseFont(xw, &fnts[fWBold]);
1019d522f475Smrg	    }
1020d522f475Smrg	    if (fnts[fWBold].fs == 0) {
1021e39b573cSmrg		if (IsEmpty(myfonts.f_w)) {
1022e39b573cSmrg		    myfonts.f_wb = myfonts.f_b;
1023e39b573cSmrg		    warn[fWBold] = fwAlways;
1024e39b573cSmrg		    xtermCopyFontInfo(&fnts[fWBold], &fnts[fBold]);
1025e39b573cSmrg		    TRACE(("...cannot load wide-bold, use bold %s\n",
1026e39b573cSmrg			   NonNull(myfonts.f_b)));
1027e39b573cSmrg		} else {
1028e39b573cSmrg		    myfonts.f_wb = myfonts.f_w;
1029e39b573cSmrg		    warn[fWBold] = fwAlways;
1030e39b573cSmrg		    xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
1031e39b573cSmrg		    TRACE(("...cannot load wide-bold, use wide %s\n",
1032e39b573cSmrg			   NonNull(myfonts.f_w)));
1033e39b573cSmrg		}
1034d522f475Smrg	    } else {
1035d522f475Smrg		TRACE(("...%s wide/bold %s\n",
1036d522f475Smrg		       derived ? "derived" : "given",
1037d522f475Smrg		       NonNull(myfonts.f_wb)));
1038d522f475Smrg		cache_menu_font_name(screen, fontnum, fWBold, myfonts.f_wb);
1039d522f475Smrg	    }
1040d522f475Smrg	} else if (is_double_width_font(fnts[fBold].fs)) {
1041d522f475Smrg	    xtermCopyFontInfo(&fnts[fWBold], &fnts[fBold]);
1042956cc18dSsnj	    warn[fWBold] = fwAlways;
1043d522f475Smrg	    TRACE(("...bold font is double-width, use it %s\n", NonNull(myfonts.f_b)));
1044d522f475Smrg	} else {
1045d522f475Smrg	    xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
1046956cc18dSsnj	    warn[fWBold] = fwAlways;
1047d522f475Smrg	    TRACE(("...cannot load wide bold font, use wide %s\n", NonNull(myfonts.f_w)));
1048d522f475Smrg	}
1049d522f475Smrg
1050d522f475Smrg	if (EmptyFont(fnts[fWBold].fs))
1051d522f475Smrg	    goto bad;		/* can't use a 0-sized font */
1052d522f475Smrg    });
1053d522f475Smrg
1054d522f475Smrg    /*
1055d522f475Smrg     * Most of the time this call to load the font will succeed, even if
1056d522f475Smrg     * there is no wide font :  the X server doubles the width of the
1057d522f475Smrg     * normal font, or similar.
1058d522f475Smrg     *
1059d522f475Smrg     * But if it did fail for some reason, then nevermind.
1060d522f475Smrg     */
1061d522f475Smrg    if (EmptyFont(fnts[fBold].fs))
1062d522f475Smrg	goto bad;		/* can't use a 0-sized font */
1063d522f475Smrg
1064d522f475Smrg    if (!same_font_size(xw, fnts[fNorm].fs, fnts[fBold].fs)
1065d522f475Smrg	&& (is_fixed_font(fnts[fNorm].fs) && is_fixed_font(fnts[fBold].fs))) {
1066d522f475Smrg	TRACE(("...ignoring mismatched normal/bold fonts\n"));
1067d522f475Smrg	xtermCloseFont(xw, &fnts[fBold]);
1068d522f475Smrg	xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]);
1069d522f475Smrg    }
1070d522f475Smrg
1071d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
1072d522f475Smrg	if (fnts[fWide].fs != 0
1073d522f475Smrg	    && fnts[fWBold].fs != 0
1074d522f475Smrg	    && !same_font_size(xw, fnts[fWide].fs, fnts[fWBold].fs)
1075d522f475Smrg	    && (is_fixed_font(fnts[fWide].fs) && is_fixed_font(fnts[fWBold].fs))) {
1076d522f475Smrg	    TRACE(("...ignoring mismatched normal/bold wide fonts\n"));
1077d522f475Smrg	    xtermCloseFont(xw, &fnts[fWBold]);
1078d522f475Smrg	    xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
1079d522f475Smrg	}
1080d522f475Smrg    });
1081d522f475Smrg
1082d522f475Smrg    /*
1083d522f475Smrg     * Normal/bold fonts should be the same width.  Also, the min/max
1084d522f475Smrg     * values should be the same.
1085d522f475Smrg     */
1086d522f475Smrg    if (!is_fixed_font(fnts[fNorm].fs)
1087d522f475Smrg	|| !is_fixed_font(fnts[fBold].fs)
1088d522f475Smrg	|| fnts[fNorm].fs->max_bounds.width != fnts[fBold].fs->max_bounds.width) {
1089d522f475Smrg	TRACE(("Proportional font! normal %d/%d, bold %d/%d\n",
1090d522f475Smrg	       fnts[fNorm].fs->min_bounds.width,
1091d522f475Smrg	       fnts[fNorm].fs->max_bounds.width,
1092d522f475Smrg	       fnts[fBold].fs->min_bounds.width,
1093d522f475Smrg	       fnts[fBold].fs->max_bounds.width));
1094d522f475Smrg	proportional = True;
1095d522f475Smrg    }
1096d522f475Smrg
1097d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
1098d522f475Smrg	if (fnts[fWide].fs != 0
1099d522f475Smrg	    && fnts[fWBold].fs != 0
1100d522f475Smrg	    && (!is_fixed_font(fnts[fWide].fs)
1101d522f475Smrg		|| !is_fixed_font(fnts[fWBold].fs)
1102d522f475Smrg		|| fnts[fWide].fs->max_bounds.width != fnts[fWBold].fs->max_bounds.width)) {
1103d522f475Smrg	    TRACE(("Proportional font! wide %d/%d, wide bold %d/%d\n",
1104d522f475Smrg		   fnts[fWide].fs->min_bounds.width,
1105d522f475Smrg		   fnts[fWide].fs->max_bounds.width,
1106d522f475Smrg		   fnts[fWBold].fs->min_bounds.width,
1107d522f475Smrg		   fnts[fWBold].fs->max_bounds.width));
1108d522f475Smrg	    proportional = True;
1109d522f475Smrg	}
1110d522f475Smrg    });
1111d522f475Smrg
1112d522f475Smrg    /* TODO : enforce that the width of the wide font is 2* the width
1113d522f475Smrg       of the narrow font */
1114d522f475Smrg
1115d522f475Smrg    /*
1116d522f475Smrg     * If we're switching fonts, free the old ones.  Otherwise we'll leak
1117d522f475Smrg     * the memory that is associated with the old fonts.  The
1118d522f475Smrg     * XLoadQueryFont call allocates a new XFontStruct.
1119d522f475Smrg     */
1120d522f475Smrg    xtermCloseFonts(xw, screen->fnts);
1121d522f475Smrg
1122d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fNorm]), &fnts[fNorm]);
1123d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fBold]), &fnts[fBold]);
1124d522f475Smrg#if OPT_WIDE_CHARS
1125d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fWide]), &fnts[fWide]);
1126d522f475Smrg    if (fnts[fWBold].fs == NULL)
1127d522f475Smrg	xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
1128d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fWBold]), &fnts[fWBold]);
1129d522f475Smrg#endif
1130d522f475Smrg
1131d522f475Smrg    new_normal = getXtermForeground(xw, xw->flags, xw->cur_foreground);
1132d522f475Smrg    new_revers = getXtermBackground(xw, xw->flags, xw->cur_background);
1133d522f475Smrg
1134d522f475Smrg    setCgsFore(xw, win, gcNorm, new_normal);
1135d522f475Smrg    setCgsBack(xw, win, gcNorm, new_revers);
1136d522f475Smrg    setCgsFont(xw, win, gcNorm, &(screen->fnts[fNorm]));
1137d522f475Smrg
1138d522f475Smrg    copyCgs(xw, win, gcBold, gcNorm);
1139d522f475Smrg    setCgsFont(xw, win, gcBold, &(screen->fnts[fBold]));
1140d522f475Smrg
1141d522f475Smrg    setCgsFore(xw, win, gcNormReverse, new_revers);
1142d522f475Smrg    setCgsBack(xw, win, gcNormReverse, new_normal);
1143d522f475Smrg    setCgsFont(xw, win, gcNormReverse, &(screen->fnts[fNorm]));
1144d522f475Smrg
1145d522f475Smrg    copyCgs(xw, win, gcBoldReverse, gcNormReverse);
1146d522f475Smrg    setCgsFont(xw, win, gcBoldReverse, &(screen->fnts[fBold]));
1147d522f475Smrg
1148d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
1149d522f475Smrg	if (screen->fnts[fWide].fs != 0
1150d522f475Smrg	    && screen->fnts[fWBold].fs != 0) {
1151d522f475Smrg	    setCgsFore(xw, win, gcWide, new_normal);
1152d522f475Smrg	    setCgsBack(xw, win, gcWide, new_revers);
1153d522f475Smrg	    setCgsFont(xw, win, gcWide, &(screen->fnts[fWide]));
1154d522f475Smrg
1155d522f475Smrg	    copyCgs(xw, win, gcWBold, gcWide);
1156d522f475Smrg	    setCgsFont(xw, win, gcWBold, &(screen->fnts[fWBold]));
1157d522f475Smrg
1158d522f475Smrg	    setCgsFore(xw, win, gcWideReverse, new_revers);
1159d522f475Smrg	    setCgsBack(xw, win, gcWideReverse, new_normal);
1160d522f475Smrg	    setCgsFont(xw, win, gcWideReverse, &(screen->fnts[fWide]));
1161d522f475Smrg
1162d522f475Smrg	    copyCgs(xw, win, gcWBoldReverse, gcWideReverse);
1163d522f475Smrg	    setCgsFont(xw, win, gcWBoldReverse, &(screen->fnts[fWBold]));
1164d522f475Smrg	}
1165d522f475Smrg    });
1166d522f475Smrg
116720d2c4d2Smrg#if OPT_BOX_CHARS
116820d2c4d2Smrg    screen->allow_packing = proportional;
116920d2c4d2Smrg    setupPackedFonts(xw);
117020d2c4d2Smrg#endif
117120d2c4d2Smrg    screen->fnt_prop = (Boolean) (proportional && !(screen->force_packed));
1172d522f475Smrg    screen->fnt_boxes = True;
1173d522f475Smrg
1174d522f475Smrg#if OPT_BOX_CHARS
1175d522f475Smrg    /*
1176d522f475Smrg     * Xterm uses character positions 1-31 of a font for the line-drawing
1177d522f475Smrg     * characters.  Check that they are all present.  The null character
1178d522f475Smrg     * (0) is special, and is not used.
1179d522f475Smrg     */
1180d522f475Smrg#if OPT_RENDERFONT
1181d522f475Smrg    if (UsingRenderFont(xw)) {
1182d522f475Smrg	/*
1183d522f475Smrg	 * FIXME: we shouldn't even be here if we're using Xft.
1184d522f475Smrg	 */
1185d522f475Smrg	screen->fnt_boxes = False;
1186d522f475Smrg	TRACE(("assume Xft missing line-drawing chars\n"));
1187d522f475Smrg    } else
1188d522f475Smrg#endif
1189d522f475Smrg    {
1190d522f475Smrg	unsigned ch;
1191d522f475Smrg
1192d522f475Smrg	for (ch = 1; ch < 32; ch++) {
1193d522f475Smrg	    unsigned n = ch;
1194d522f475Smrg#if OPT_WIDE_CHARS
1195d522f475Smrg	    if (screen->utf8_mode || screen->unicode_font) {
1196d522f475Smrg		n = dec2ucs(ch);
1197d522f475Smrg		if (n == UCS_REPL)
1198d522f475Smrg		    continue;
1199d522f475Smrg	    }
1200d522f475Smrg#endif
1201956cc18dSsnj	    if (IsXtermMissingChar(screen, n, &fnts[fNorm])) {
1202d522f475Smrg		TRACE(("missing normal char #%d\n", n));
1203d522f475Smrg		screen->fnt_boxes = False;
1204d522f475Smrg		break;
1205d522f475Smrg	    }
1206956cc18dSsnj	    if (IsXtermMissingChar(screen, n, &fnts[fBold])) {
1207d522f475Smrg		TRACE(("missing bold char #%d\n", n));
1208d522f475Smrg		screen->fnt_boxes = False;
1209d522f475Smrg		break;
1210d522f475Smrg	    }
1211d522f475Smrg	}
1212d522f475Smrg    }
1213d522f475Smrg    TRACE(("Will %suse internal line-drawing characters\n",
1214d522f475Smrg	   screen->fnt_boxes ? "not " : ""));
1215d522f475Smrg#endif
1216d522f475Smrg
1217d522f475Smrg    if (screen->always_bold_mode) {
1218d522f475Smrg	screen->enbolden = screen->bold_mode;
1219d522f475Smrg    } else {
1220d522f475Smrg	screen->enbolden = screen->bold_mode
1221d522f475Smrg	    && ((fnts[fNorm].fs == fnts[fBold].fs)
1222d522f475Smrg		|| same_font_name(normal, myfonts.f_b));
1223d522f475Smrg    }
1224d522f475Smrg    TRACE(("Will %suse 1-pixel offset/overstrike to simulate bold\n",
1225d522f475Smrg	   screen->enbolden ? "" : "not "));
1226d522f475Smrg
1227d522f475Smrg    set_menu_font(False);
1228d522f475Smrg    screen->menu_font_number = fontnum;
1229d522f475Smrg    set_menu_font(True);
1230d522f475Smrg    if (tmpname) {		/* if setting escape or sel */
1231d522f475Smrg	if (screen->MenuFontName(fontnum))
123220d2c4d2Smrg	    free((void *) screen->MenuFontName(fontnum));
1233d522f475Smrg	screen->MenuFontName(fontnum) = tmpname;
1234d522f475Smrg	if (fontnum == fontMenu_fontescape) {
1235d522f475Smrg	    SetItemSensitivity(fontMenuEntries[fontMenu_fontescape].widget,
1236d522f475Smrg			       True);
1237d522f475Smrg	}
1238d522f475Smrg#if OPT_SHIFT_FONTS
1239d522f475Smrg	screen->menu_font_sizes[fontnum] = FontSize(fnts[fNorm].fs);
1240d522f475Smrg#endif
1241d522f475Smrg    }
1242d522f475Smrg    set_cursor_gcs(xw);
1243d522f475Smrg    xtermUpdateFontInfo(xw, doresize);
1244d522f475Smrg    TRACE(("Success Cgs - xtermLoadFont\n"));
1245d522f475Smrg    return 1;
1246d522f475Smrg
1247d522f475Smrg  bad:
1248d522f475Smrg    if (tmpname)
1249d522f475Smrg	free(tmpname);
1250d522f475Smrg    releaseWindowGCs(xw, win);
1251d522f475Smrg
1252d522f475Smrg    xtermCloseFonts(xw, fnts);
1253d522f475Smrg    TRACE(("Fail Cgs - xtermLoadFont\n"));
1254d522f475Smrg    return 0;
1255d522f475Smrg}
1256d522f475Smrg
1257d522f475Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
1258d522f475Smrg/*
1259d522f475Smrg * Collect font-names that we can modify with the load-vt-fonts() action.
1260d522f475Smrg */
1261d522f475Smrg#define MERGE_SUBFONT(src,dst,name) \
1262492d43a5Smrg	if (IsEmpty(dst.name)) { \
1263d522f475Smrg	    TRACE(("MERGE_SUBFONT " #dst "." #name " merge %s\n", NonNull(src.name))); \
1264d522f475Smrg	    dst.name = src.name; \
1265d522f475Smrg	} else { \
1266d522f475Smrg	    TRACE(("MERGE_SUBFONT " #dst "." #name " found %s\n", NonNull(dst.name))); \
1267d522f475Smrg	}
1268d522f475Smrg
1269e39b573cSmrg#define INFER_SUBFONT(src,dst,name) \
1270e39b573cSmrg	if (IsEmpty(dst.name)) { \
1271e39b573cSmrg	    TRACE(("INFER_SUBFONT " #dst "." #name " will infer\n")); \
1272e39b573cSmrg	    dst.name = x_strdup(""); \
1273e39b573cSmrg	} else { \
1274e39b573cSmrg	    TRACE(("INFER_SUBFONT " #dst "." #name " found %s\n", NonNull(dst.name))); \
1275e39b573cSmrg	}
1276e39b573cSmrg
1277d522f475Smrg#define COPY_MENU_FONTS(src,dst) \
1278d522f475Smrg	TRACE(("COPY_MENU_FONTS " #src " to " #dst "\n")); \
1279d522f475Smrg	for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \
1280d522f475Smrg	    for (m = 0; m < fMAX; ++m) { \
1281492d43a5Smrg		dst.menu_font_names[n][m] = x_strdup(src.menu_font_names[n][m]); \
1282d522f475Smrg	    } \
1283e39b573cSmrg	    TRACE((".. " #dst ".menu_fonts_names[%d] = %s\n", n, dst.menu_font_names[n][fNorm])); \
1284e39b573cSmrg	}
1285e39b573cSmrg
1286e39b573cSmrgvoid
1287e39b573cSmrgxtermSaveVTFonts(XtermWidget xw)
1288e39b573cSmrg{
1289e39b573cSmrg    TScreen *screen = TScreenOf(xw);
1290e39b573cSmrg    Cardinal n, m;
1291e39b573cSmrg
1292e39b573cSmrg    if (!screen->savedVTFonts) {
1293e39b573cSmrg
1294e39b573cSmrg	screen->savedVTFonts = True;
1295e39b573cSmrg	TRACE(("xtermSaveVTFonts saving original\n"));
1296e39b573cSmrg	screen->cacheVTFonts.default_font = xw->misc.default_font;
1297e39b573cSmrg	COPY_MENU_FONTS(xw->screen, screen->cacheVTFonts);
1298e39b573cSmrg    }
1299e39b573cSmrg}
1300e39b573cSmrg
1301e39b573cSmrg#define SAME_STRING(x,y) ((x) == (y) || ((x) && (y) && !strcmp(x, y)))
1302e39b573cSmrg#define SAME_MEMBER(n)   SAME_STRING(a->n, b->n)
1303e39b573cSmrg
1304e39b573cSmrgstatic Boolean
1305e39b573cSmrgsameSubResources(SubResourceRec * a, SubResourceRec * b)
1306e39b573cSmrg{
1307e39b573cSmrg    Boolean result = True;
1308e39b573cSmrg    int n;
1309e39b573cSmrg
1310e39b573cSmrg    if (!SAME_MEMBER(default_font.f_n)
1311e39b573cSmrg	|| !SAME_MEMBER(default_font.f_b)
1312e39b573cSmrg	|| !SAME_MEMBER(default_font.f_w)
1313e39b573cSmrg	|| !SAME_MEMBER(default_font.f_wb)) {
1314e39b573cSmrg	TRACE(("sameSubResources: default_font differs\n"));
1315e39b573cSmrg	result = False;
1316e39b573cSmrg    } else {
1317e39b573cSmrg	for (n = 0; n < NMENUFONTS; ++n) {
1318e39b573cSmrg	    if (!SAME_MEMBER(menu_font_names[n][fNorm])) {
1319e39b573cSmrg		TRACE(("sameSubResources: menu_font_names[%d] differs\n", n));
1320e39b573cSmrg		result = False;
1321e39b573cSmrg		break;
1322e39b573cSmrg	    }
1323d522f475Smrg	}
1324e39b573cSmrg    }
1325e39b573cSmrg
1326e39b573cSmrg    return result;
1327e39b573cSmrg}
1328d522f475Smrg
1329d522f475Smrg/*
1330d522f475Smrg * Load the "VT" font names from the given subresource name/class.  These
1331d522f475Smrg * correspond to the VT100 resources.
1332d522f475Smrg */
1333d522f475Smrgstatic Bool
133420d2c4d2SmrgxtermLoadVTFonts(XtermWidget xw, String myName, String myClass)
1335d522f475Smrg{
1336e39b573cSmrg    SubResourceRec subresourceRec;
1337e39b573cSmrg    SubResourceRec referenceRec;
1338d522f475Smrg
1339d522f475Smrg    /*
1340d522f475Smrg     * These are duplicates of the VT100 font resources, but with a special
1341d522f475Smrg     * application/classname passed in to distinguish them.
1342d522f475Smrg     */
1343d522f475Smrg    static XtResource font_resources[] =
1344d522f475Smrg    {
1345d522f475Smrg	Sres(XtNfont, XtCFont, default_font.f_n, DEFFONT),
1346d522f475Smrg	Sres(XtNboldFont, XtCBoldFont, default_font.f_b, DEFBOLDFONT),
1347d522f475Smrg#if OPT_WIDE_CHARS
1348d522f475Smrg	Sres(XtNwideFont, XtCWideFont, default_font.f_w, DEFWIDEFONT),
1349d522f475Smrg	Sres(XtNwideBoldFont, XtCWideBoldFont, default_font.f_wb, DEFWIDEBOLDFONT),
1350d522f475Smrg#endif
1351d522f475Smrg	Sres(XtNfont1, XtCFont1, MenuFontName(fontMenu_font1), NULL),
1352d522f475Smrg	Sres(XtNfont2, XtCFont2, MenuFontName(fontMenu_font2), NULL),
1353d522f475Smrg	Sres(XtNfont3, XtCFont3, MenuFontName(fontMenu_font3), NULL),
1354d522f475Smrg	Sres(XtNfont4, XtCFont4, MenuFontName(fontMenu_font4), NULL),
1355d522f475Smrg	Sres(XtNfont5, XtCFont5, MenuFontName(fontMenu_font5), NULL),
1356d522f475Smrg	Sres(XtNfont6, XtCFont6, MenuFontName(fontMenu_font6), NULL),
1357d522f475Smrg    };
1358d522f475Smrg    Cardinal n, m;
1359d522f475Smrg    Bool status = True;
1360956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1361d522f475Smrg
1362e39b573cSmrg    TRACE(("called xtermLoadVTFonts(name=%s, class=%s)\n",
1363e39b573cSmrg	   NonNull(myName), NonNull(myClass)));
1364d522f475Smrg
1365e39b573cSmrg    xtermSaveVTFonts(xw);
1366d522f475Smrg
1367492d43a5Smrg    if (IsEmpty(myName)) {
1368d522f475Smrg	TRACE(("xtermLoadVTFonts restoring original\n"));
1369e39b573cSmrg	xw->misc.default_font = screen->cacheVTFonts.default_font;
1370e39b573cSmrg	COPY_MENU_FONTS(screen->cacheVTFonts, xw->screen);
1371e39b573cSmrg	for (n = 0; n < XtNumber(screen->cacheVTFonts.menu_font_names); ++n) {
1372e39b573cSmrg	    screen->MenuFontName(n) = screen->cacheVTFonts.MenuFontName(n);
1373e39b573cSmrg	}
1374d522f475Smrg    } else {
1375d522f475Smrg	TRACE(("xtermLoadVTFonts(%s, %s)\n", myName, myClass));
1376d522f475Smrg
1377e39b573cSmrg	memset(&referenceRec, 0, sizeof(referenceRec));
1378d522f475Smrg	memset(&subresourceRec, 0, sizeof(subresourceRec));
1379956cc18dSsnj	XtGetSubresources((Widget) xw, (XtPointer) &subresourceRec,
1380d522f475Smrg			  myName, myClass,
1381d522f475Smrg			  font_resources,
1382d522f475Smrg			  (Cardinal) XtNumber(font_resources),
1383d522f475Smrg			  NULL, (Cardinal) 0);
1384d522f475Smrg
1385e39b573cSmrg	/*
1386e39b573cSmrg	 * XtGetSubresources returns no status, so we compare the returned
1387e39b573cSmrg	 * data against a zero'd struct to see if any data is returned.
1388e39b573cSmrg	 */
1389e39b573cSmrg	if (memcmp(&referenceRec, &subresourceRec, sizeof(referenceRec))
1390e39b573cSmrg	    && !sameSubResources(&(screen->cacheVTFonts), &subresourceRec)) {
1391e39b573cSmrg
1392e39b573cSmrg	    screen->mergedVTFonts = True;
1393d522f475Smrg
1394d522f475Smrg	    /*
1395d522f475Smrg	     * If a particular resource value was not found, use the original.
1396d522f475Smrg	     */
1397956cc18dSsnj	    MERGE_SUBFONT(xw->misc, subresourceRec, default_font.f_n);
1398e39b573cSmrg	    INFER_SUBFONT(xw->misc, subresourceRec, default_font.f_b);
1399d522f475Smrg#if OPT_WIDE_CHARS
1400e39b573cSmrg	    INFER_SUBFONT(xw->misc, subresourceRec, default_font.f_w);
1401e39b573cSmrg	    INFER_SUBFONT(xw->misc, subresourceRec, default_font.f_wb);
1402d522f475Smrg#endif
1403d522f475Smrg	    for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n)
1404956cc18dSsnj		MERGE_SUBFONT(xw->screen, subresourceRec, MenuFontName(n));
1405d522f475Smrg
1406d522f475Smrg	    /*
1407d522f475Smrg	     * Finally, copy the subresource data to the widget.
1408d522f475Smrg	     */
1409956cc18dSsnj	    xw->misc.default_font = subresourceRec.default_font;
1410956cc18dSsnj	    COPY_MENU_FONTS(subresourceRec, xw->screen);
1411492d43a5Smrg	    screen->MenuFontName(fontMenu_default) = x_strdup(xw->misc.default_font.f_n);
1412492d43a5Smrg	    screen->menu_font_names[0][fBold] = x_strdup(xw->misc.default_font.f_b);
1413d522f475Smrg#if OPT_WIDE_CHARS
1414492d43a5Smrg	    screen->menu_font_names[0][fWide] = x_strdup(xw->misc.default_font.f_w);
1415492d43a5Smrg	    screen->menu_font_names[0][fWBold] = x_strdup(xw->misc.default_font.f_wb);
1416d522f475Smrg#endif
1417d522f475Smrg	} else {
1418d522f475Smrg	    TRACE(("...no resources found\n"));
1419d522f475Smrg	    status = False;
1420d522f475Smrg	}
1421d522f475Smrg    }
1422d522f475Smrg    return status;
1423d522f475Smrg}
1424d522f475Smrg
1425d522f475Smrg#if OPT_WIDE_CHARS
1426d522f475Smrgstatic Bool
142720d2c4d2SmrgisWideFont(XFontStruct * fp, const char *tag, Bool nullOk)
1428d522f475Smrg{
1429d522f475Smrg    Bool result = False;
1430d522f475Smrg
1431d522f475Smrg    (void) tag;
1432d522f475Smrg    if (okFont(fp)) {
1433d522f475Smrg	unsigned count = countGlyphs(fp);
1434d522f475Smrg	TRACE(("isWideFont(%s) found %d cells\n", tag, count));
1435d522f475Smrg	result = (count > 256) ? True : False;
1436d522f475Smrg    } else {
1437d522f475Smrg	result = nullOk;
1438d522f475Smrg    }
1439d522f475Smrg    return result;
1440d522f475Smrg}
1441d522f475Smrg
1442d522f475Smrg/*
1443d522f475Smrg * If the current fonts are not wide, load the UTF8 fonts.
1444d522f475Smrg *
1445d522f475Smrg * Called during initialization (for wide-character mode), the fonts have not
1446d522f475Smrg * been setup, so we pass nullOk=True to isWideFont().
1447d522f475Smrg *
1448d522f475Smrg * Called after initialization, e.g., in response to the UTF-8 menu entry
1449d522f475Smrg * (starting from narrow character mode), it checks if the fonts are not wide.
1450d522f475Smrg */
1451d522f475SmrgBool
1452d522f475SmrgxtermLoadWideFonts(XtermWidget xw, Bool nullOk)
1453d522f475Smrg{
1454956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1455d522f475Smrg    Bool result;
1456d522f475Smrg
1457d522f475Smrg    if (EmptyFont(screen->fnts[fWide].fs)) {
1458d522f475Smrg	result = (isWideFont(screen->fnts[fNorm].fs, "normal", nullOk)
1459d522f475Smrg		  && isWideFont(screen->fnts[fBold].fs, "bold", nullOk));
1460d522f475Smrg    } else {
1461d522f475Smrg	result = (isWideFont(screen->fnts[fWide].fs, "wide", nullOk)
1462d522f475Smrg		  && isWideFont(screen->fnts[fWBold].fs, "wide-bold", nullOk));
1463d522f475Smrg	if (result && !screen->utf8_latin1) {
1464d522f475Smrg	    result = (isWideFont(screen->fnts[fNorm].fs, "normal", nullOk)
1465d522f475Smrg		      && isWideFont(screen->fnts[fBold].fs, "bold", nullOk));
1466d522f475Smrg	}
1467d522f475Smrg    }
1468d522f475Smrg    if (!result) {
1469d522f475Smrg	TRACE(("current fonts are not all wide%s\n", nullOk ? " nullOk" : ""));
1470e39b573cSmrg	result = xtermLoadVTFonts(xw, XtNutf8Fonts, XtCUtf8Fonts);
1471d522f475Smrg    }
1472d522f475Smrg    TRACE(("xtermLoadWideFonts:%d\n", result));
1473d522f475Smrg    return result;
1474d522f475Smrg}
1475d522f475Smrg#endif /* OPT_WIDE_CHARS */
1476d522f475Smrg
1477d522f475Smrg/*
1478d522f475Smrg * Restore the default fonts, i.e., if we had switched to wide-fonts.
1479d522f475Smrg */
1480d522f475SmrgBool
1481956cc18dSsnjxtermLoadDefaultFonts(XtermWidget xw)
1482d522f475Smrg{
1483d522f475Smrg    Bool result;
1484956cc18dSsnj    result = xtermLoadVTFonts(xw, NULL, NULL);
1485d522f475Smrg    TRACE(("xtermLoadDefaultFonts:%d\n", result));
1486d522f475Smrg    return result;
1487d522f475Smrg}
1488d522f475Smrg#endif /* OPT_LOAD_VTFONTS || OPT_WIDE_CHARS */
1489d522f475Smrg
1490d522f475Smrg#if OPT_LOAD_VTFONTS
1491d522f475Smrgvoid
1492d522f475SmrgHandleLoadVTFonts(Widget w,
1493d522f475Smrg		  XEvent * event GCC_UNUSED,
1494d522f475Smrg		  String * params GCC_UNUSED,
1495d522f475Smrg		  Cardinal *param_count GCC_UNUSED)
1496d522f475Smrg{
1497d522f475Smrg    static char empty[] = "";	/* appease strict compilers */
1498d522f475Smrg
1499956cc18dSsnj    XtermWidget xw;
1500956cc18dSsnj
1501956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
1502956cc18dSsnj	TScreen *screen = TScreenOf(xw);
1503492d43a5Smrg	char name_buf[80];
1504492d43a5Smrg	char class_buf[80];
1505492d43a5Smrg	String name = (String) ((*param_count > 0) ? params[0] : empty);
1506492d43a5Smrg	char *myName = (char *) MyStackAlloc(strlen(name), name_buf);
1507492d43a5Smrg	String convert = (String) ((*param_count > 1) ? params[1] : myName);
1508492d43a5Smrg	char *myClass = (char *) MyStackAlloc(strlen(convert), class_buf);
1509d522f475Smrg	int n;
1510d522f475Smrg
1511d522f475Smrg	TRACE(("HandleLoadVTFonts(%d)\n", *param_count));
1512492d43a5Smrg	strcpy(myName, name);
1513d522f475Smrg	strcpy(myClass, convert);
15142eaa94a1Schristos	if (*param_count == 1)
15152eaa94a1Schristos	    myClass[0] = x_toupper(myClass[0]);
1516d522f475Smrg
1517d522f475Smrg	if (xtermLoadVTFonts(xw, myName, myClass)) {
1518d522f475Smrg	    /*
1519d522f475Smrg	     * When switching fonts, try to preserve the font-menu selection, since
1520d522f475Smrg	     * it is less surprising to do that (if the font-switching can be
1521d522f475Smrg	     * undone) than to switch to "Default".
1522d522f475Smrg	     */
1523956cc18dSsnj	    int font_number = screen->menu_font_number;
1524d522f475Smrg	    if (font_number > fontMenu_lastBuiltin)
1525d522f475Smrg		font_number = fontMenu_lastBuiltin;
1526d522f475Smrg	    for (n = 0; n < NMENUFONTS; ++n)
1527956cc18dSsnj		screen->menu_font_sizes[n] = 0;
1528d522f475Smrg	    SetVTFont(xw, font_number, True,
1529d522f475Smrg		      ((font_number == fontMenu_default)
1530d522f475Smrg		       ? &(xw->misc.default_font)
1531d522f475Smrg		       : NULL));
1532d522f475Smrg	}
1533d522f475Smrg
1534492d43a5Smrg	MyStackFree(myName, name_buf);
1535492d43a5Smrg	MyStackFree(myClass, class_buf);
1536d522f475Smrg    }
1537d522f475Smrg}
1538d522f475Smrg#endif /* OPT_LOAD_VTFONTS */
1539d522f475Smrg
1540d522f475Smrg/*
1541d522f475Smrg * Set the limits for the box that outlines the cursor.
1542d522f475Smrg */
1543d522f475Smrgvoid
1544d522f475SmrgxtermSetCursorBox(TScreen * screen)
1545d522f475Smrg{
1546d522f475Smrg    static XPoint VTbox[NBOX];
1547d522f475Smrg    XPoint *vp;
15482eaa94a1Schristos    int fw = FontWidth(screen) - 1;
15492eaa94a1Schristos    int fh = FontHeight(screen) - 1;
15502eaa94a1Schristos    int hh = screen->cursor_underline ? 1 : fh;
1551d522f475Smrg
1552d522f475Smrg    vp = &VTbox[1];
15532eaa94a1Schristos    (vp++)->x = (short) fw;
15542eaa94a1Schristos    (vp++)->y = (short) hh;
15552eaa94a1Schristos    (vp++)->x = (short) -fw;
15562eaa94a1Schristos    vp->y = (short) -hh;
15572eaa94a1Schristos
1558d522f475Smrg    screen->box = VTbox;
1559d522f475Smrg}
1560d522f475Smrg
1561d522f475Smrg#define CACHE_XFT(dst,src) if (src != 0) {\
1562956cc18dSsnj	    checkXft(xw, &(dst[fontnum]), src);\
1563956cc18dSsnj	    TRACE(("Xft metrics %s[%d] = %d (%d,%d) advance %d, actual %d%s\n",\
1564d522f475Smrg		#dst,\
1565d522f475Smrg	    	fontnum,\
1566d522f475Smrg		src->height,\
1567d522f475Smrg		src->ascent,\
1568d522f475Smrg		src->descent,\
1569956cc18dSsnj		src->max_advance_width,\
1570956cc18dSsnj		dst[fontnum].map.min_width,\
1571956cc18dSsnj		dst[fontnum].map.mixed ? " mixed" : ""));\
1572d522f475Smrg	}
1573d522f475Smrg
1574d522f475Smrg#if OPT_RENDERFONT
1575956cc18dSsnj
157620d2c4d2Smrg#if OPT_TRACE > 1
157720d2c4d2Smrgstatic FcChar32
157820d2c4d2SmrgxtermXftFirstChar(XftFont * xft)
157920d2c4d2Smrg{
158020d2c4d2Smrg    FcChar32 map[FC_CHARSET_MAP_SIZE];
158120d2c4d2Smrg    FcChar32 next;
158220d2c4d2Smrg    FcChar32 first;
158320d2c4d2Smrg    int i;
158420d2c4d2Smrg
158520d2c4d2Smrg    first = FcCharSetFirstPage(xft->charset, map, &next);
158620d2c4d2Smrg    for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
158720d2c4d2Smrg	if (map[i]) {
158820d2c4d2Smrg	    FcChar32 bits = map[i];
158920d2c4d2Smrg	    first += i * 32;
159020d2c4d2Smrg	    while (!(bits & 0x1)) {
159120d2c4d2Smrg		bits >>= 1;
159220d2c4d2Smrg		first++;
159320d2c4d2Smrg	    }
159420d2c4d2Smrg	    break;
159520d2c4d2Smrg	}
159620d2c4d2Smrg    return first;
159720d2c4d2Smrg}
159820d2c4d2Smrg
159920d2c4d2Smrgstatic FcChar32
160020d2c4d2SmrgxtermXftLastChar(XftFont * xft)
160120d2c4d2Smrg{
160220d2c4d2Smrg    FcChar32 this, last, next;
160320d2c4d2Smrg    FcChar32 map[FC_CHARSET_MAP_SIZE];
160420d2c4d2Smrg    int i;
160520d2c4d2Smrg    last = FcCharSetFirstPage(xft->charset, map, &next);
160620d2c4d2Smrg    while ((this = FcCharSetNextPage(xft->charset, map, &next)) != FC_CHARSET_DONE)
160720d2c4d2Smrg	last = this;
160820d2c4d2Smrg    last &= ~0xff;
160920d2c4d2Smrg    for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--)
161020d2c4d2Smrg	if (map[i]) {
161120d2c4d2Smrg	    FcChar32 bits = map[i];
161220d2c4d2Smrg	    last += i * 32 + 31;
161320d2c4d2Smrg	    while (!(bits & 0x80000000)) {
161420d2c4d2Smrg		last--;
161520d2c4d2Smrg		bits <<= 1;
161620d2c4d2Smrg	    }
161720d2c4d2Smrg	    break;
161820d2c4d2Smrg	}
161920d2c4d2Smrg    return (long) last;
162020d2c4d2Smrg}
162120d2c4d2Smrg
162220d2c4d2Smrgstatic void
162320d2c4d2SmrgdumpXft(XtermWidget xw, XTermXftFonts * data)
162420d2c4d2Smrg{
162520d2c4d2Smrg    XftFont *xft = data->font;
162620d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
162720d2c4d2Smrg    VTwin *win = WhichVWin(screen);
162820d2c4d2Smrg
162920d2c4d2Smrg    FcChar32 c;
163020d2c4d2Smrg    FcChar32 first = xtermXftFirstChar(xft);
163120d2c4d2Smrg    FcChar32 last = xtermXftLastChar(xft);
163220d2c4d2Smrg    unsigned count = 0;
163320d2c4d2Smrg    unsigned outside = 0;
163420d2c4d2Smrg
163520d2c4d2Smrg    TRACE(("dumpXft {{\n"));
163620d2c4d2Smrg    TRACE(("   data range %#6x..%#6x\n", first, last));
163720d2c4d2Smrg    for (c = first; c <= last; ++c) {
163820d2c4d2Smrg	if (FcCharSetHasChar(xft->charset, c)) {
163920d2c4d2Smrg	    int width = my_wcwidth((int) c);
164020d2c4d2Smrg	    XGlyphInfo extents;
164120d2c4d2Smrg
164220d2c4d2Smrg	    XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents);
164320d2c4d2Smrg	    TRACE(("%#6x  %2d  %.1f\n", c, width,
164420d2c4d2Smrg		   ((double) extents.width) / win->f_width));
164520d2c4d2Smrg	    if (extents.width > win->f_width)
164620d2c4d2Smrg		++outside;
164720d2c4d2Smrg	    ++count;
164820d2c4d2Smrg	}
164920d2c4d2Smrg    }
165020d2c4d2Smrg    TRACE(("}} %u total, %u outside\n", count, outside));
165120d2c4d2Smrg}
165220d2c4d2Smrg#define DUMP_XFT(xw, data) dumpXft(xw, data)
165320d2c4d2Smrg#else
165420d2c4d2Smrg#define DUMP_XFT(xw, data)	/* nothing */
165520d2c4d2Smrg#endif
165620d2c4d2Smrg
1657956cc18dSsnjstatic void
1658956cc18dSsnjcheckXft(XtermWidget xw, XTermXftFonts * data, XftFont * xft)
1659956cc18dSsnj{
1660956cc18dSsnj    FcChar32 c;
1661956cc18dSsnj    Dimension width = 0;
1662956cc18dSsnj
1663956cc18dSsnj    data->font = xft;
1664956cc18dSsnj    data->map.min_width = 0;
1665956cc18dSsnj    data->map.max_width = (Dimension) xft->max_advance_width;
1666956cc18dSsnj
166720d2c4d2Smrg    /*
166820d2c4d2Smrg     * For each ASCII or ISO-8859-1 printable code, ask what its width is.
166920d2c4d2Smrg     * Given the maximum width for those, we have a reasonable estimate of
167020d2c4d2Smrg     * the single-column width.
167120d2c4d2Smrg     *
167220d2c4d2Smrg     * Ignore control characters - their extent information is misleading.
167320d2c4d2Smrg     */
1674956cc18dSsnj    for (c = 32; c < 256; ++c) {
167520d2c4d2Smrg	if (c >= 127 && c <= 159)
167620d2c4d2Smrg	    continue;
1677956cc18dSsnj	if (FcCharSetHasChar(xft->charset, c)) {
1678956cc18dSsnj	    XGlyphInfo extents;
1679956cc18dSsnj
1680956cc18dSsnj	    XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents);
168120d2c4d2Smrg	    if (width < extents.width && extents.width <= data->map.max_width) {
1682956cc18dSsnj		width = extents.width;
168320d2c4d2Smrg	    }
1684956cc18dSsnj	}
1685956cc18dSsnj    }
1686956cc18dSsnj    data->map.min_width = width;
1687956cc18dSsnj    data->map.mixed = (data->map.max_width >= (data->map.min_width + 1));
1688956cc18dSsnj}
1689956cc18dSsnj
1690d522f475Smrgstatic XftFont *
1691956cc18dSsnjxtermOpenXft(XtermWidget xw, const char *name, XftPattern * pat, const char *tag)
1692d522f475Smrg{
1693956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1694956cc18dSsnj    Display *dpy = screen->display;
1695d522f475Smrg    XftPattern *match;
1696d522f475Smrg    XftResult status;
1697d522f475Smrg    XftFont *result = 0;
1698d522f475Smrg
1699d522f475Smrg    if (pat != 0) {
1700d522f475Smrg	match = XftFontMatch(dpy, DefaultScreen(dpy), pat, &status);
1701d522f475Smrg	if (match != 0) {
1702d522f475Smrg	    result = XftFontOpenPattern(dpy, match);
1703d522f475Smrg	    if (result != 0) {
1704d522f475Smrg		TRACE(("...matched %s font\n", tag));
1705d522f475Smrg	    } else {
1706d522f475Smrg		TRACE(("...could did not open %s font\n", tag));
1707d522f475Smrg		XftPatternDestroy(match);
1708956cc18dSsnj		if (xw->misc.fontWarnings >= fwAlways) {
1709956cc18dSsnj		    TRACE(("OOPS cannot open %s font \"%s\"\n", tag, name));
1710956cc18dSsnj		    fprintf(stderr, "%s: cannot open %s font \"%s\"\n",
1711956cc18dSsnj			    ProgramName, tag, name);
1712956cc18dSsnj		}
1713d522f475Smrg	    }
1714d522f475Smrg	} else {
1715d522f475Smrg	    TRACE(("...did not match %s font\n", tag));
1716956cc18dSsnj	    if (xw->misc.fontWarnings >= fwResource) {
1717956cc18dSsnj		TRACE(("OOPS: cannot match %s font \"%s\"\n", tag, name));
1718956cc18dSsnj		fprintf(stderr, "%s: cannot match %s font \"%s\"\n",
1719956cc18dSsnj			ProgramName, tag, name);
1720956cc18dSsnj	    }
1721d522f475Smrg	}
1722d522f475Smrg    }
1723d522f475Smrg    return result;
1724d522f475Smrg}
1725d522f475Smrg#endif
1726d522f475Smrg
1727d522f475Smrg#if OPT_RENDERFONT
1728d522f475Smrg#if OPT_SHIFT_FONTS
1729d522f475Smrg/*
1730d522f475Smrg * Don't make a dependency on the math library for a single function.
1731d522f475Smrg * (Newton Raphson).
1732d522f475Smrg */
1733d522f475Smrgstatic double
1734d522f475SmrgmySquareRoot(double value)
1735d522f475Smrg{
1736d522f475Smrg    double result = 0.0;
1737d522f475Smrg    if (value > 0.0) {
1738d522f475Smrg	int n;
1739d522f475Smrg	double older = value;
1740d522f475Smrg	for (n = 0; n < 10; ++n) {
1741d522f475Smrg	    double delta = (older * older - value) / (2.0 * older);
1742d522f475Smrg	    double newer = older - delta;
1743d522f475Smrg	    older = newer;
1744d522f475Smrg	    result = newer;
1745d522f475Smrg	    if (delta > -0.001 && delta < 0.001)
1746d522f475Smrg		break;
1747d522f475Smrg	}
1748d522f475Smrg    }
1749d522f475Smrg    return result;
1750d522f475Smrg}
1751d522f475Smrg#endif
1752d522f475Smrg
1753d522f475Smrg/*
1754d522f475Smrg * Given the Xft font metrics, determine the actual font size.  This is used
1755d522f475Smrg * for each font to ensure that normal, bold and italic fonts follow the same
1756d522f475Smrg * rule.
1757d522f475Smrg */
1758d522f475Smrgstatic void
1759d522f475SmrgsetRenderFontsize(TScreen * screen, VTwin * win, XftFont * font, const char *tag)
1760d522f475Smrg{
1761d522f475Smrg    if (font != 0) {
1762d522f475Smrg	int width, height, ascent, descent;
1763d522f475Smrg
1764d522f475Smrg	(void) screen;
1765d522f475Smrg
1766d522f475Smrg	width = font->max_advance_width;
1767d522f475Smrg	height = font->height;
1768d522f475Smrg	ascent = font->ascent;
1769d522f475Smrg	descent = font->descent;
1770d522f475Smrg	if (height < ascent + descent) {
1771d522f475Smrg	    TRACE(("...increase height from %d\n", height));
1772d522f475Smrg	    height = ascent + descent;
1773d522f475Smrg	}
1774d522f475Smrg	if (is_double_width_font_xft(screen->display, font)) {
1775d522f475Smrg	    TRACE(("...reduced width from %d\n", width));
1776d522f475Smrg	    width >>= 1;
1777d522f475Smrg	}
1778d522f475Smrg	if (tag == 0) {
1779d522f475Smrg	    win->f_width = width;
1780d522f475Smrg	    win->f_height = height;
1781d522f475Smrg	    win->f_ascent = ascent;
1782d522f475Smrg	    win->f_descent = descent;
1783d522f475Smrg	    TRACE(("setRenderFontsize result %dx%d (%d+%d)\n",
1784d522f475Smrg		   width, height, ascent, descent));
1785d522f475Smrg	} else if (win->f_width < width ||
1786d522f475Smrg		   win->f_height < height ||
1787d522f475Smrg		   win->f_ascent < ascent ||
1788d522f475Smrg		   win->f_descent < descent) {
1789d522f475Smrg	    TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n",
1790d522f475Smrg		   tag,
1791d522f475Smrg		   win->f_width, win->f_height, win->f_ascent, win->f_descent,
1792d522f475Smrg		   width, height, ascent, descent));
1793d522f475Smrg
1794d522f475Smrg	    win->f_width = width;
1795d522f475Smrg	    win->f_height = height;
1796d522f475Smrg	    win->f_ascent = ascent;
1797d522f475Smrg	    win->f_descent = descent;
1798d522f475Smrg	} else {
1799d522f475Smrg	    TRACE(("setRenderFontsize %s unchanged\n", tag));
1800d522f475Smrg	}
1801d522f475Smrg    }
1802d522f475Smrg}
1803d522f475Smrg#endif
1804d522f475Smrg
180520d2c4d2Smrgstatic void
180620d2c4d2SmrgcheckFontInfo(int value, const char *tag)
180720d2c4d2Smrg{
180820d2c4d2Smrg    if (value == 0) {
180920d2c4d2Smrg	fprintf(stderr,
181020d2c4d2Smrg		"Selected font has no non-zero %s for ISO-8859-1 encoding\n", tag);
181120d2c4d2Smrg	exit(1);
181220d2c4d2Smrg    }
181320d2c4d2Smrg}
181420d2c4d2Smrg
181520d2c4d2Smrg#if OPT_RENDERFONT
181620d2c4d2Smrgvoid
181720d2c4d2SmrgxtermCloseXft(TScreen * screen, XTermXftFonts * pub)
181820d2c4d2Smrg{
181920d2c4d2Smrg    if (pub->font != 0) {
182020d2c4d2Smrg	XftFontClose(screen->display, pub->font);
182120d2c4d2Smrg	pub->font = 0;
182220d2c4d2Smrg    }
182320d2c4d2Smrg}
182420d2c4d2Smrg
182520d2c4d2Smrg/*
182620d2c4d2Smrg * Get the faceName/faceDoublesize resource setting.  Strip off "xft:", which
182720d2c4d2Smrg * is not recognized by XftParseName().
182820d2c4d2Smrg */
1829492d43a5SmrgString
183020d2c4d2SmrggetFaceName(XtermWidget xw, Bool wideName GCC_UNUSED)
183120d2c4d2Smrg{
183220d2c4d2Smrg#if OPT_RENDERWIDE
1833492d43a5Smrg    String result = (wideName
1834492d43a5Smrg		     ? xw->misc.face_wide_name
1835492d43a5Smrg		     : xw->misc.face_name);
183620d2c4d2Smrg#else
1837492d43a5Smrg    String result = xw->misc.face_name;
183820d2c4d2Smrg#endif
183920d2c4d2Smrg    if (!IsEmpty(result) && !strncmp(result, "xft:", (size_t) 4))
184020d2c4d2Smrg	result += 4;
184120d2c4d2Smrg    return x_nonempty(result);
184220d2c4d2Smrg}
184320d2c4d2Smrg
184420d2c4d2Smrg/*
184520d2c4d2Smrg * If we change the faceName, we'll have to re-acquire all of the fonts that
184620d2c4d2Smrg * are derived from it.
184720d2c4d2Smrg */
184820d2c4d2Smrgvoid
184920d2c4d2SmrgsetFaceName(XtermWidget xw, const char *value)
185020d2c4d2Smrg{
185120d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
185220d2c4d2Smrg    int n;
185320d2c4d2Smrg
185420d2c4d2Smrg    xw->misc.face_name = x_strdup(value);
185520d2c4d2Smrg    for (n = 0; n < NMENUFONTS; ++n) {
185620d2c4d2Smrg	xw->misc.face_size[n] = -1.0;
185720d2c4d2Smrg	xtermCloseXft(screen, &(screen->renderFontNorm[n]));
185820d2c4d2Smrg	xtermCloseXft(screen, &(screen->renderFontBold[n]));
185920d2c4d2Smrg	xtermCloseXft(screen, &(screen->renderFontBold[n]));
186020d2c4d2Smrg#if OPT_RENDERWIDE
186120d2c4d2Smrg	xtermCloseXft(screen, &(screen->renderWideNorm[n]));
186220d2c4d2Smrg	xtermCloseXft(screen, &(screen->renderWideBold[n]));
186320d2c4d2Smrg	xtermCloseXft(screen, &(screen->renderWideItal[n]));
186420d2c4d2Smrg#endif
186520d2c4d2Smrg    }
186620d2c4d2Smrg}
186720d2c4d2Smrg#endif
186820d2c4d2Smrg
1869d522f475Smrg/*
1870d522f475Smrg * Compute useful values for the font/window sizes
1871d522f475Smrg */
1872d522f475Smrgvoid
1873d522f475SmrgxtermComputeFontInfo(XtermWidget xw,
1874d522f475Smrg		     VTwin * win,
1875d522f475Smrg		     XFontStruct * font,
1876d522f475Smrg		     int sbwidth)
1877d522f475Smrg{
1878956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1879d522f475Smrg
1880d522f475Smrg    int i, j, width, height;
1881492d43a5Smrg#if OPT_RENDERFONT
1882492d43a5Smrg    int fontnum = screen->menu_font_number;
1883492d43a5Smrg#endif
1884d522f475Smrg
1885d522f475Smrg#if OPT_RENDERFONT
1886d522f475Smrg    /*
1887d522f475Smrg     * xterm contains a lot of references to fonts, assuming they are fixed
1888d522f475Smrg     * size.  This chunk of code overrides the actual font-selection (see
1889d522f475Smrg     * drawXtermText()), if the user has selected render-font.  All of the
1890d522f475Smrg     * font-loading for fixed-fonts still goes on whether or not this chunk
1891d522f475Smrg     * overrides it.
1892d522f475Smrg     */
1893492d43a5Smrg    if (UsingRenderFont(xw) && fontnum >= 0) {
1894492d43a5Smrg	String face_name = getFaceName(xw, False);
1895956cc18dSsnj	XftFont *norm = screen->renderFontNorm[fontnum].font;
1896956cc18dSsnj	XftFont *bold = screen->renderFontBold[fontnum].font;
1897956cc18dSsnj	XftFont *ital = screen->renderFontItal[fontnum].font;
1898d522f475Smrg#if OPT_RENDERWIDE
1899956cc18dSsnj	XftFont *wnorm = screen->renderWideNorm[fontnum].font;
1900956cc18dSsnj	XftFont *wbold = screen->renderWideBold[fontnum].font;
1901956cc18dSsnj	XftFont *wital = screen->renderWideItal[fontnum].font;
1902d522f475Smrg#endif
1903d522f475Smrg
190420d2c4d2Smrg	if (norm == 0 && face_name) {
1905d522f475Smrg	    XftPattern *pat;
1906d522f475Smrg	    double face_size = xw->misc.face_size[fontnum];
1907d522f475Smrg
1908492d43a5Smrg	    TRACE(("xtermComputeFontInfo font %d: norm(face %s, size %f)\n",
1909492d43a5Smrg		   fontnum, face_name,
1910d522f475Smrg		   xw->misc.face_size[fontnum]));
1911d522f475Smrg
1912d522f475Smrg	    if (face_size <= 0.0) {
1913d522f475Smrg#if OPT_SHIFT_FONTS
1914d522f475Smrg		/*
1915d522f475Smrg		 * If the user is switching font-sizes, make it follow by
1916d522f475Smrg		 * default the same ratios to the default as the fixed fonts
1917d522f475Smrg		 * would, for easy comparison.  There will be some differences
1918d522f475Smrg		 * since the fixed fonts have a variety of height/width ratios,
1919d522f475Smrg		 * but this is simpler than adding another resource value - and
1920d522f475Smrg		 * as noted above, the data for the fixed fonts are available.
1921d522f475Smrg		 */
1922d522f475Smrg		lookupOneFontSize(xw, 0);
1923d522f475Smrg		lookupOneFontSize(xw, fontnum);
1924d522f475Smrg		if (fontnum == fontMenu_default) {
1925d522f475Smrg		    face_size = 14.0;
1926d522f475Smrg		} else {
1927d522f475Smrg		    double ratio;
192820d2c4d2Smrg		    long num = screen->menu_font_sizes[fontnum];
192920d2c4d2Smrg		    long den = screen->menu_font_sizes[0];
1930d522f475Smrg
1931d522f475Smrg		    if (den <= 0)
1932d522f475Smrg			den = 1;
193320d2c4d2Smrg		    ratio = mySquareRoot((double) num / (double) den);
1934d522f475Smrg
1935d522f475Smrg		    face_size = (ratio * xw->misc.face_size[0]);
193620d2c4d2Smrg		    TRACE(("scaled using %3ld/%ld = %.2f -> %f\n",
1937d522f475Smrg			   num, den, ratio, face_size));
1938d522f475Smrg		}
1939d522f475Smrg#else
1940d522f475Smrg		switch (fontnum) {
1941d522f475Smrg		case fontMenu_font1:
1942d522f475Smrg		    face_size = 8.0;
1943d522f475Smrg		    break;
1944d522f475Smrg		case fontMenu_font2:
1945d522f475Smrg		    face_size = 10.0;
1946d522f475Smrg		    break;
1947d522f475Smrg		case fontMenu_font3:
1948d522f475Smrg		    face_size = 12.0;
1949d522f475Smrg		    break;
1950d522f475Smrg		default:
1951d522f475Smrg		    face_size = 14.0;
1952d522f475Smrg		    break;
1953d522f475Smrg		case fontMenu_font4:
1954d522f475Smrg		    face_size = 16.0;
1955d522f475Smrg		    break;
1956d522f475Smrg		case fontMenu_font5:
1957d522f475Smrg		    face_size = 18.0;
1958d522f475Smrg		    break;
1959d522f475Smrg		case fontMenu_font6:
1960d522f475Smrg		    face_size = 20.0;
1961d522f475Smrg		    break;
1962d522f475Smrg		}
1963d522f475Smrg#endif
1964956cc18dSsnj		xw->misc.face_size[fontnum] = (float) face_size;
1965d522f475Smrg	    }
1966d522f475Smrg
1967d522f475Smrg	    /*
1968d522f475Smrg	     * By observation (there is no documentation), XftPatternBuild is
1969d522f475Smrg	     * cumulative.  Build the bold- and italic-patterns on top of the
1970d522f475Smrg	     * normal pattern.
1971d522f475Smrg	     */
1972d522f475Smrg#define NormXftPattern \
1973d522f475Smrg	    XFT_FAMILY, XftTypeString, "mono", \
1974d522f475Smrg	    XFT_SIZE, XftTypeDouble, face_size, \
1975d522f475Smrg	    XFT_SPACING, XftTypeInteger, XFT_MONO
1976d522f475Smrg
1977d522f475Smrg#define BoldXftPattern(norm) \
1978d522f475Smrg	    XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \
1979d522f475Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width
1980d522f475Smrg
1981d522f475Smrg#define ItalXftPattern(norm) \
1982d522f475Smrg	    XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \
1983d522f475Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width
1984d522f475Smrg
198520d2c4d2Smrg	    if ((pat = XftNameParse(face_name)) != 0) {
198620d2c4d2Smrg#define OPEN_XFT(tag) xtermOpenXft(xw, face_name, pat, tag)
1987d522f475Smrg		XftPatternBuild(pat,
1988d522f475Smrg				NormXftPattern,
1989d522f475Smrg				(void *) 0);
1990956cc18dSsnj		norm = OPEN_XFT("normal");
1991d522f475Smrg
1992d522f475Smrg		if (norm != 0) {
1993d522f475Smrg		    XftPatternBuild(pat,
1994d522f475Smrg				    BoldXftPattern(norm),
1995d522f475Smrg				    (void *) 0);
1996956cc18dSsnj		    bold = OPEN_XFT("bold");
1997d522f475Smrg
1998d522f475Smrg#if OPT_ISO_COLORS
1999d522f475Smrg		    if (screen->italicULMode
200020d2c4d2Smrg			&& (pat = XftNameParse(face_name)) != 0) {
2001d522f475Smrg			XftPatternBuild(pat,
2002d522f475Smrg					NormXftPattern,
2003d522f475Smrg					ItalXftPattern(norm),
2004d522f475Smrg					(void *) 0);
2005956cc18dSsnj			ital = OPEN_XFT("italic");
2006d522f475Smrg		    }
2007d522f475Smrg#endif /* OPT_ISO_COLORS */
2008956cc18dSsnj#undef OPEN_XFT
2009d522f475Smrg
2010d522f475Smrg		    /*
2011d522f475Smrg		     * FIXME:  just assume that the corresponding font has no
2012d522f475Smrg		     * graphics characters.
2013d522f475Smrg		     */
2014d522f475Smrg		    if (screen->fnt_boxes) {
2015d522f475Smrg			screen->fnt_boxes = False;
2016d522f475Smrg			TRACE(("Xft opened - will %suse internal line-drawing characters\n",
2017d522f475Smrg			       screen->fnt_boxes ? "not " : ""));
2018d522f475Smrg		    }
2019d522f475Smrg		}
2020d522f475Smrg
2021d522f475Smrg		XftPatternDestroy(pat);
2022d522f475Smrg	    }
2023d522f475Smrg
2024d522f475Smrg	    CACHE_XFT(screen->renderFontNorm, norm);
2025d522f475Smrg	    CACHE_XFT(screen->renderFontBold, bold);
2026d522f475Smrg	    CACHE_XFT(screen->renderFontItal, ital);
2027d522f475Smrg
2028d522f475Smrg	    /*
2029d522f475Smrg	     * See xtermXftDrawString().
2030d522f475Smrg	     */
2031d522f475Smrg#if OPT_RENDERWIDE
2032d522f475Smrg	    if (norm != 0 && screen->wide_chars) {
2033d522f475Smrg		int char_width = norm->max_advance_width * 2;
2034956cc18dSsnj#ifdef FC_ASPECT
2035956cc18dSsnj		double aspect = ((xw->misc.face_wide_name
2036956cc18dSsnj				  || screen->renderFontNorm[fontnum].map.mixed)
2037956cc18dSsnj				 ? 1.0
2038956cc18dSsnj				 : 2.0);
2039956cc18dSsnj#endif
2040d522f475Smrg
204120d2c4d2Smrg		face_name = getFaceName(xw, True);
2042d522f475Smrg		TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n",
204320d2c4d2Smrg		       NonNull(face_name),
2044d522f475Smrg		       char_width));
2045d522f475Smrg
2046d522f475Smrg#define WideXftPattern \
2047d522f475Smrg		XFT_FAMILY, XftTypeString, "mono", \
2048d522f475Smrg		XFT_SIZE, XftTypeDouble, face_size, \
2049d522f475Smrg		XFT_SPACING, XftTypeInteger, XFT_MONO
2050d522f475Smrg
205120d2c4d2Smrg		if (face_name && (pat = XftNameParse(face_name)) != 0) {
2052956cc18dSsnj#define OPEN_XFT(tag) xtermOpenXft(xw, face_name, pat, tag)
2053d522f475Smrg		    XftPatternBuild(pat,
2054d522f475Smrg				    WideXftPattern,
2055d522f475Smrg				    XFT_CHAR_WIDTH, XftTypeInteger, char_width,
2056956cc18dSsnj#ifdef FC_ASPECT
2057956cc18dSsnj				    FC_ASPECT, XftTypeDouble, aspect,
2058956cc18dSsnj#endif
2059d522f475Smrg				    (void *) 0);
2060956cc18dSsnj		    wnorm = OPEN_XFT("wide");
2061d522f475Smrg
2062d522f475Smrg		    if (wnorm != 0) {
2063d522f475Smrg			XftPatternBuild(pat,
2064d522f475Smrg					WideXftPattern,
2065d522f475Smrg					BoldXftPattern(wnorm),
2066d522f475Smrg					(void *) 0);
2067956cc18dSsnj			wbold = OPEN_XFT("wide-bold");
2068d522f475Smrg
2069d522f475Smrg#if OPT_ISO_COLORS
2070d522f475Smrg			if (screen->italicULMode
2071d522f475Smrg			    && (pat = XftNameParse(face_name)) != 0) {
2072d522f475Smrg			    XftPatternBuild(pat,
2073d522f475Smrg					    WideXftPattern,
2074d522f475Smrg					    ItalXftPattern(wnorm),
2075d522f475Smrg					    (void *) 0);
2076956cc18dSsnj			    wital = OPEN_XFT("wide-italic");
2077d522f475Smrg			}
2078d522f475Smrg#endif
2079956cc18dSsnj#undef OPEN_XFT
2080d522f475Smrg		    }
2081d522f475Smrg		    XftPatternDestroy(pat);
2082d522f475Smrg		}
2083d522f475Smrg
2084d522f475Smrg		CACHE_XFT(screen->renderWideNorm, wnorm);
2085d522f475Smrg		CACHE_XFT(screen->renderWideBold, wbold);
2086d522f475Smrg		CACHE_XFT(screen->renderWideItal, wital);
2087d522f475Smrg	    }
2088d522f475Smrg#endif /* OPT_RENDERWIDE */
2089d522f475Smrg	}
2090d522f475Smrg	if (norm == 0) {
20912eaa94a1Schristos	    TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum));
2092d522f475Smrg	    xw->misc.render_font = False;
2093d522f475Smrg	    update_font_renderfont();
2094d522f475Smrg	    /* now we will fall through into the bitmap fonts */
2095d522f475Smrg	} else {
2096d522f475Smrg	    setRenderFontsize(screen, win, norm, NULL);
2097d522f475Smrg	    setRenderFontsize(screen, win, bold, "bold");
2098d522f475Smrg	    setRenderFontsize(screen, win, ital, "ital");
209920d2c4d2Smrg#if OPT_BOX_CHARS
210020d2c4d2Smrg	    setupPackedFonts(xw);
210120d2c4d2Smrg
210220d2c4d2Smrg	    if (screen->force_packed) {
210320d2c4d2Smrg		XTermXftFonts *use = &(screen->renderFontNorm[fontnum]);
210420d2c4d2Smrg		win->f_height = use->font->ascent + use->font->descent;
210520d2c4d2Smrg		win->f_width = use->map.min_width;
210620d2c4d2Smrg		TRACE(("...packed TrueType font %dx%d vs %d\n",
210720d2c4d2Smrg		       win->f_height,
210820d2c4d2Smrg		       win->f_width,
210920d2c4d2Smrg		       use->map.max_width));
211020d2c4d2Smrg	    }
211120d2c4d2Smrg#endif
211220d2c4d2Smrg	    DUMP_XFT(xw, &(screen->renderFontNorm[fontnum]));
2113d522f475Smrg	}
2114d522f475Smrg    }
2115d522f475Smrg    /*
2116d522f475Smrg     * Are we handling a bitmap font?
2117d522f475Smrg     */
2118492d43a5Smrg    else
2119d522f475Smrg#endif /* OPT_RENDERFONT */
2120d522f475Smrg    {
212120d2c4d2Smrg	if (is_double_width_font(font) && !(screen->fnt_prop)) {
2122d522f475Smrg	    win->f_width = (font->min_bounds.width);
2123d522f475Smrg	} else {
2124d522f475Smrg	    win->f_width = (font->max_bounds.width);
2125d522f475Smrg	}
2126d522f475Smrg	win->f_height = (font->ascent + font->descent);
2127d522f475Smrg	win->f_ascent = font->ascent;
2128d522f475Smrg	win->f_descent = font->descent;
2129d522f475Smrg    }
2130d522f475Smrg    i = 2 * screen->border + sbwidth;
2131d522f475Smrg    j = 2 * screen->border;
2132d522f475Smrg    width = MaxCols(screen) * win->f_width + i;
2133d522f475Smrg    height = MaxRows(screen) * win->f_height + j;
2134956cc18dSsnj    win->fullwidth = (Dimension) width;
2135956cc18dSsnj    win->fullheight = (Dimension) height;
2136d522f475Smrg    win->width = width - i;
2137d522f475Smrg    win->height = height - j;
2138d522f475Smrg
2139d522f475Smrg    TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n",
2140d522f475Smrg	   win->height,
2141d522f475Smrg	   win->width,
2142d522f475Smrg	   win->fullheight,
2143d522f475Smrg	   win->fullwidth,
2144d522f475Smrg	   win->f_height,
2145d522f475Smrg	   win->f_width,
2146d522f475Smrg	   win->f_ascent,
2147d522f475Smrg	   win->f_descent));
214820d2c4d2Smrg
214920d2c4d2Smrg    checkFontInfo(win->f_height, "height");
215020d2c4d2Smrg    checkFontInfo(win->f_width, "width");
2151d522f475Smrg}
2152d522f475Smrg
2153d522f475Smrg/* save this information as a side-effect for double-sized characters */
2154d522f475Smrgvoid
2155d522f475SmrgxtermSaveFontInfo(TScreen * screen, XFontStruct * font)
2156d522f475Smrg{
2157956cc18dSsnj    screen->fnt_wide = (Dimension) (font->max_bounds.width);
2158956cc18dSsnj    screen->fnt_high = (Dimension) (font->ascent + font->descent);
2159d522f475Smrg    TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide));
2160d522f475Smrg}
2161d522f475Smrg
2162d522f475Smrg/*
2163d522f475Smrg * After loading a new font, update the structures that use its size.
2164d522f475Smrg */
2165d522f475Smrgvoid
2166d522f475SmrgxtermUpdateFontInfo(XtermWidget xw, Bool doresize)
2167d522f475Smrg{
2168956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2169d522f475Smrg
2170d522f475Smrg    int scrollbar_width;
2171d522f475Smrg    VTwin *win = &(screen->fullVwin);
2172d522f475Smrg
2173d522f475Smrg    scrollbar_width = (xw->misc.scrollbar
2174d522f475Smrg		       ? (screen->scrollWidget->core.width +
2175d522f475Smrg			  BorderWidth(screen->scrollWidget))
2176d522f475Smrg		       : 0);
2177d522f475Smrg    xtermComputeFontInfo(xw, win, screen->fnts[fNorm].fs, scrollbar_width);
2178d522f475Smrg    xtermSaveFontInfo(screen, screen->fnts[fNorm].fs);
2179d522f475Smrg
2180d522f475Smrg    if (doresize) {
2181d522f475Smrg	if (VWindow(screen)) {
2182d522f475Smrg	    xtermClear(xw);
2183d522f475Smrg	}
2184d522f475Smrg	TRACE(("xtermUpdateFontInfo {{\n"));
2185d522f475Smrg	DoResizeScreen(xw);	/* set to the new natural size */
2186d522f475Smrg	ResizeScrollBar(xw);
2187d522f475Smrg	Redraw();
2188d522f475Smrg	TRACE(("... }} xtermUpdateFontInfo\n"));
2189d522f475Smrg#ifdef SCROLLBAR_RIGHT
2190d522f475Smrg	updateRightScrollbar(xw);
2191d522f475Smrg#endif
2192d522f475Smrg    }
2193d522f475Smrg    xtermSetCursorBox(screen);
2194d522f475Smrg}
2195d522f475Smrg
2196d522f475Smrg#if OPT_BOX_CHARS
2197d522f475Smrg
2198d522f475Smrg/*
2199d522f475Smrg * Returns true if the given character is missing from the specified font.
2200d522f475Smrg */
2201d522f475SmrgBool
2202956cc18dSsnjxtermMissingChar(unsigned ch, XTermFonts * font)
2203d522f475Smrg{
2204956cc18dSsnj    Bool result = False;
2205956cc18dSsnj    XFontStruct *fs = font->fs;
2206956cc18dSsnj    static XCharStruct dft, *tmp = &dft, *pc = 0;
2207d522f475Smrg
2208956cc18dSsnj    if (fs->max_byte1 == 0) {
2209d522f475Smrg#if OPT_WIDE_CHARS
2210956cc18dSsnj	if (ch > 255) {
2211956cc18dSsnj	    TRACE(("xtermMissingChar %#04x (row)\n", ch));
2212956cc18dSsnj	    return True;
2213d522f475Smrg	}
2214956cc18dSsnj#endif
2215956cc18dSsnj	CI_GET_CHAR_INFO_1D(fs, E2A(ch), tmp, pc);
2216956cc18dSsnj    }
2217d522f475Smrg#if OPT_WIDE_CHARS
2218956cc18dSsnj    else {
2219956cc18dSsnj	CI_GET_CHAR_INFO_2D(fs, HI_BYTE(ch), LO_BYTE(ch), tmp, pc);
2220956cc18dSsnj    }
2221d522f475Smrg#else
2222d522f475Smrg
2223956cc18dSsnj    if (!pc)
2224956cc18dSsnj	return False;		/* Urgh! */
2225d522f475Smrg#endif
2226d522f475Smrg
2227956cc18dSsnj    if (CI_NONEXISTCHAR(pc)) {
2228956cc18dSsnj	TRACE(("xtermMissingChar %#04x (!exists)\n", ch));
2229956cc18dSsnj	result = True;
2230d522f475Smrg    }
2231956cc18dSsnj    if (ch < 256) {
2232956cc18dSsnj	font->known_missing[ch] = (Char) (result ? 2 : 1);
2233d522f475Smrg    }
2234956cc18dSsnj    return result;
2235d522f475Smrg}
2236d522f475Smrg
2237d522f475Smrg/*
2238d522f475Smrg * The grid is arbitrary, enough resolution that nothing's lost in
2239d522f475Smrg * initialization.
2240d522f475Smrg */
2241d522f475Smrg#define BOX_HIGH 60
2242d522f475Smrg#define BOX_WIDE 60
2243d522f475Smrg
2244d522f475Smrg#define MID_HIGH (BOX_HIGH/2)
2245d522f475Smrg#define MID_WIDE (BOX_WIDE/2)
2246d522f475Smrg
2247d522f475Smrg#define CHR_WIDE ((9*BOX_WIDE)/10)
2248d522f475Smrg#define CHR_HIGH ((9*BOX_HIGH)/10)
2249d522f475Smrg
2250d522f475Smrg/*
2251d522f475Smrg * ...since we'll scale the values anyway.
2252d522f475Smrg */
2253e39b573cSmrg#define SCALED_X(n) ((int)(n) * (((int) font_width) - 1)) / (BOX_WIDE-1)
2254e39b573cSmrg#define SCALED_Y(n) ((int)(n) * (((int) font_height) - 1)) / (BOX_HIGH-1)
2255e39b573cSmrg#define SCALE_X(n) n = SCALED_X(n)
2256e39b573cSmrg#define SCALE_Y(n) n = SCALED_Y(n)
2257d522f475Smrg
2258d522f475Smrg#define SEG(x0,y0,x1,y1) x0,y0, x1,y1
2259d522f475Smrg
2260d522f475Smrg/*
2261d522f475Smrg * Draw the given graphic character, if it is simple enough (i.e., a
2262d522f475Smrg * line-drawing character).
2263d522f475Smrg */
2264d522f475Smrgvoid
2265d522f475SmrgxtermDrawBoxChar(XtermWidget xw,
2266d522f475Smrg		 unsigned ch,
2267d522f475Smrg		 unsigned flags,
2268d522f475Smrg		 GC gc,
2269d522f475Smrg		 int x,
2270d522f475Smrg		 int y,
2271d522f475Smrg		 int cells)
2272d522f475Smrg{
2273956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2274d522f475Smrg    /* *INDENT-OFF* */
2275d522f475Smrg    static const short glyph_ht[] = {
2276d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,5*MID_HIGH/6),	/* H */
2277d522f475Smrg	SEG(6*BOX_WIDE/10,  0,		6*BOX_WIDE/10,5*MID_HIGH/6),
2278d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12),
2279d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
2280d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
2281d522f475Smrg	-1
2282d522f475Smrg    }, glyph_ff[] = {
2283d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		6*BOX_WIDE/10,	0),		/* F */
2284d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12),
2285d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		0*BOX_WIDE/3, 5*MID_HIGH/6),
2286d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
2287d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
2288d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
2289d522f475Smrg	-1
2290d522f475Smrg    }, glyph_lf[] = {
2291d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,9*MID_HIGH/12),	/* L */
2292d522f475Smrg	SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12),
2293d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
2294d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
2295d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
2296d522f475Smrg	-1
2297d522f475Smrg    }, glyph_nl[] = {
2298d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10,	0),		/* N */
2299d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		5*BOX_WIDE/6, 5*MID_HIGH/6),
2300d522f475Smrg	SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
2301d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),	/* L */
2302d522f475Smrg	SEG(1*BOX_WIDE/3,   CHR_HIGH,	  CHR_WIDE,	CHR_HIGH),
2303d522f475Smrg	-1
2304d522f475Smrg    }, glyph_vt[] = {
2305d522f475Smrg	SEG(1*BOX_WIDE/10,   0,		5*BOX_WIDE/12,5*MID_HIGH/6),	/* V */
2306d522f475Smrg	SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
2307d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
2308d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
2309d522f475Smrg	-1
2310d522f475Smrg    }, plus_or_minus[] =
2311d522f475Smrg    {
2312d522f475Smrg	SEG(  0,	  5*BOX_HIGH/6,	  CHR_WIDE,   5*BOX_HIGH/6),
2313d522f475Smrg	SEG(  MID_WIDE,	  2*BOX_HIGH/6,	  MID_WIDE,   4*BOX_HIGH/6),
2314d522f475Smrg	SEG(  0,	  3*BOX_HIGH/6,	  CHR_WIDE,   3*BOX_HIGH/6),
2315d522f475Smrg	-1
2316d522f475Smrg    }, lower_right_corner[] =
2317d522f475Smrg    {
2318d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
2319d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	0),
2320d522f475Smrg	-1
2321d522f475Smrg    }, upper_right_corner[] =
2322d522f475Smrg    {
2323d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
2324d522f475Smrg	SEG( MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
2325d522f475Smrg	-1
2326d522f475Smrg    }, upper_left_corner[] =
2327d522f475Smrg    {
2328d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2329d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
2330d522f475Smrg	-1
2331d522f475Smrg    }, lower_left_corner[] =
2332d522f475Smrg    {
2333d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
2334d522f475Smrg	SEG(  MID_WIDE,	    MID_WIDE,	  BOX_WIDE,	MID_HIGH),
2335d522f475Smrg	-1
2336d522f475Smrg    }, cross[] =
2337d522f475Smrg    {
2338d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2339d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2340d522f475Smrg	-1
2341d522f475Smrg    }, scan_line_1[] =
2342d522f475Smrg    {
2343d522f475Smrg	SEG(  0,	    0,		  BOX_WIDE,	0),
2344d522f475Smrg	-1
2345d522f475Smrg    }, scan_line_3[] =
2346d522f475Smrg    {
2347d522f475Smrg	SEG(  0,	    BOX_HIGH/4,	  BOX_WIDE,	BOX_HIGH/4),
2348d522f475Smrg	-1
2349d522f475Smrg    }, scan_line_7[] =
2350d522f475Smrg    {
2351d522f475Smrg	SEG( 0,		    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2352d522f475Smrg	-1
2353d522f475Smrg    }, scan_line_9[] =
2354d522f475Smrg    {
2355d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  BOX_WIDE,   3*BOX_HIGH/4),
2356d522f475Smrg	-1
2357d522f475Smrg    }, horizontal_line[] =
2358d522f475Smrg    {
2359d522f475Smrg	SEG(  0,	    BOX_HIGH,	  BOX_WIDE,	BOX_HIGH),
2360d522f475Smrg	-1
2361d522f475Smrg    }, left_tee[] =
2362d522f475Smrg    {
2363d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2364d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2365d522f475Smrg	-1
2366d522f475Smrg    }, right_tee[] =
2367d522f475Smrg    {
2368d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2369d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  0,		MID_HIGH),
2370d522f475Smrg	-1
2371d522f475Smrg    }, bottom_tee[] =
2372d522f475Smrg    {
2373d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2374d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
2375d522f475Smrg	-1
2376d522f475Smrg    }, top_tee[] =
2377d522f475Smrg    {
2378d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2379d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
2380d522f475Smrg	-1
2381d522f475Smrg    }, vertical_line[] =
2382d522f475Smrg    {
2383d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2384d522f475Smrg	-1
2385d522f475Smrg    }, less_than_or_equal[] =
2386d522f475Smrg    {
2387d522f475Smrg	SEG(  CHR_WIDE,	    BOX_HIGH/3,	  0,		MID_HIGH),
2388d522f475Smrg	SEG(  CHR_WIDE,	  2*BOX_HIGH/3,	  0,		MID_HIGH),
2389d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
2390d522f475Smrg	-1
2391d522f475Smrg    }, greater_than_or_equal[] =
2392d522f475Smrg    {
2393d522f475Smrg	SEG(  0,	    BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
2394d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
2395d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
2396d522f475Smrg	-1
2397d522f475Smrg    }, greek_pi[] =
2398d522f475Smrg    {
2399d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
2400d522f475Smrg	SEG(5*CHR_WIDE/6,   MID_HIGH,	5*CHR_WIDE/6,	CHR_HIGH),
2401d522f475Smrg	SEG(2*CHR_WIDE/6,   MID_HIGH,	2*CHR_WIDE/6,	CHR_HIGH),
2402d522f475Smrg	-1
2403d522f475Smrg    }, not_equal_to[] =
2404d522f475Smrg    {
2405d522f475Smrg	SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3,	CHR_HIGH),
2406d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,   2*BOX_HIGH/3),
2407d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
2408d522f475Smrg	-1
2409d522f475Smrg    };
2410d522f475Smrg    /* *INDENT-ON* */
2411d522f475Smrg
2412d522f475Smrg    static const short *lines[] =
2413d522f475Smrg    {
2414d522f475Smrg	0,			/* 00 (unused) */
2415d522f475Smrg	0,			/* 01 diamond */
2416d522f475Smrg	0,			/* 02 box */
2417d522f475Smrg	glyph_ht,		/* 03 HT */
2418d522f475Smrg	glyph_ff,		/* 04 FF */
2419d522f475Smrg	0,			/* 05 CR */
2420d522f475Smrg	glyph_lf,		/* 06 LF */
2421d522f475Smrg	0,			/* 07 degrees (small circle) */
2422d522f475Smrg	plus_or_minus,		/* 08 */
2423d522f475Smrg	glyph_nl,		/* 09 */
2424d522f475Smrg	glyph_vt,		/* 0A */
2425d522f475Smrg	lower_right_corner,	/* 0B */
2426d522f475Smrg	upper_right_corner,	/* 0C */
2427d522f475Smrg	upper_left_corner,	/* 0D */
2428d522f475Smrg	lower_left_corner,	/* 0E */
2429d522f475Smrg	cross,			/* 0F */
2430d522f475Smrg	scan_line_1,		/* 10 */
2431d522f475Smrg	scan_line_3,		/* 11 */
2432d522f475Smrg	scan_line_7,		/* 12 */
2433d522f475Smrg	scan_line_9,		/* 13 */
2434d522f475Smrg	horizontal_line,	/* 14 */
2435d522f475Smrg	left_tee,		/* 15 */
2436d522f475Smrg	right_tee,		/* 16 */
2437d522f475Smrg	bottom_tee,		/* 17 */
2438d522f475Smrg	top_tee,		/* 18 */
2439d522f475Smrg	vertical_line,		/* 19 */
2440d522f475Smrg	less_than_or_equal,	/* 1A */
2441d522f475Smrg	greater_than_or_equal,	/* 1B */
2442d522f475Smrg	greek_pi,		/* 1C */
2443d522f475Smrg	not_equal_to,		/* 1D */
2444d522f475Smrg	0,			/* 1E LB */
2445d522f475Smrg	0,			/* 1F bullet */
2446d522f475Smrg    };
2447d522f475Smrg
2448d522f475Smrg    GC gc2;
2449d522f475Smrg    CgsEnum cgsId = (ch == 2) ? gcDots : gcLine;
2450d522f475Smrg    VTwin *cgsWin = WhichVWin(screen);
2451d522f475Smrg    const short *p;
2452956cc18dSsnj    unsigned font_width = (unsigned) (((flags & DOUBLEWFONT) ? 2 : 1) * screen->fnt_wide);
2453956cc18dSsnj    unsigned font_height = (unsigned) (((flags & DOUBLEHFONT) ? 2 : 1) * screen->fnt_high);
2454d522f475Smrg
2455d522f475Smrg    if (cells > 1)
2456956cc18dSsnj	font_width *= (unsigned) cells;
2457d522f475Smrg
2458d522f475Smrg#if OPT_WIDE_CHARS
2459d522f475Smrg    /*
2460d522f475Smrg     * Try to show line-drawing characters if we happen to be in UTF-8
2461d522f475Smrg     * mode, but have gotten an old-style font.
2462d522f475Smrg     */
2463d522f475Smrg    if (screen->utf8_mode
2464d522f475Smrg#if OPT_RENDERFONT
2465d522f475Smrg	&& !UsingRenderFont(xw)
2466d522f475Smrg#endif
2467d522f475Smrg	&& (ch > 127)
2468d522f475Smrg	&& (ch != UCS_REPL)) {
2469d522f475Smrg	unsigned n;
2470d522f475Smrg	for (n = 1; n < 32; n++) {
2471d522f475Smrg	    if (dec2ucs(n) == ch
247220d2c4d2Smrg		&& !((flags & BOLD)
247320d2c4d2Smrg		     ? IsXtermMissingChar(screen, n, &screen->fnts[fBold])
247420d2c4d2Smrg		     : IsXtermMissingChar(screen, n, &screen->fnts[fNorm]))) {
2475d522f475Smrg		TRACE(("...use xterm-style linedrawing\n"));
2476d522f475Smrg		ch = n;
2477d522f475Smrg		break;
2478d522f475Smrg	    }
2479d522f475Smrg	}
2480d522f475Smrg    }
2481d522f475Smrg#endif
2482d522f475Smrg
2483d522f475Smrg    TRACE(("DRAW_BOX(%d) cell %dx%d at %d,%d%s\n",
2484d522f475Smrg	   ch, font_height, font_width, y, x,
2485d522f475Smrg	   (ch >= (sizeof(lines) / sizeof(lines[0]))
2486d522f475Smrg	    ? "-BAD"
2487d522f475Smrg	    : "")));
2488d522f475Smrg
2489d522f475Smrg    if (cgsId == gcDots) {
2490d522f475Smrg	setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2491d522f475Smrg	setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc));
2492d522f475Smrg	setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2493d522f475Smrg    } else {
2494d522f475Smrg	setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2495d522f475Smrg	setCgsFore(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2496d522f475Smrg	setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2497d522f475Smrg    }
2498d522f475Smrg    gc2 = getCgsGC(xw, cgsWin, cgsId);
2499d522f475Smrg
2500d522f475Smrg    if (!(flags & NOBACKGROUND)) {
2501d522f475Smrg	XFillRectangle(screen->display, VWindow(screen), gc2, x, y,
2502d522f475Smrg		       font_width,
2503d522f475Smrg		       font_height);
2504d522f475Smrg    }
2505d522f475Smrg
2506d522f475Smrg    setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2507d522f475Smrg    setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc));
2508d522f475Smrg    setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2509d522f475Smrg    gc2 = getCgsGC(xw, cgsWin, cgsId);
2510d522f475Smrg
2511d522f475Smrg    XSetLineAttributes(screen->display, gc2,
2512d522f475Smrg		       (flags & BOLD)
2513d522f475Smrg		       ? ((font_height > 12)
2514d522f475Smrg			  ? font_height / 12
2515d522f475Smrg			  : 1)
2516d522f475Smrg		       : ((font_height > 16)
2517d522f475Smrg			  ? font_height / 16
2518d522f475Smrg			  : 1),
2519d522f475Smrg		       LineSolid,
2520d522f475Smrg		       CapProjecting,
2521d522f475Smrg		       JoinMiter);
2522d522f475Smrg
2523d522f475Smrg    if (ch == 1) {		/* diamond */
2524d522f475Smrg	XPoint points[5];
2525d522f475Smrg	int npoints = 5, n;
2526d522f475Smrg
2527d522f475Smrg	points[0].x = MID_WIDE;
2528d522f475Smrg	points[0].y = BOX_HIGH / 4;
2529d522f475Smrg
2530d522f475Smrg	points[1].x = 8 * BOX_WIDE / 8;
2531d522f475Smrg	points[1].y = MID_HIGH;
2532d522f475Smrg
2533d522f475Smrg	points[2].x = points[0].x;
2534d522f475Smrg	points[2].y = 3 * BOX_HIGH / 4;
2535d522f475Smrg
2536d522f475Smrg	points[3].x = 0 * BOX_WIDE / 8;
2537d522f475Smrg	points[3].y = points[1].y;
2538d522f475Smrg
2539d522f475Smrg	points[4].x = points[0].x;
2540d522f475Smrg	points[4].y = points[0].y;
2541d522f475Smrg
2542d522f475Smrg	for (n = 0; n < npoints; ++n) {
2543e39b573cSmrg	    points[n].x = (short) SCALED_X(points[n].x);
2544e39b573cSmrg	    points[n].y = (short) SCALED_Y(points[n].y);
2545e39b573cSmrg	    points[n].x = (short) (points[n].x + x);
2546e39b573cSmrg	    points[n].y = (short) (points[n].y + y);
2547d522f475Smrg	}
2548d522f475Smrg
2549d522f475Smrg	XFillPolygon(screen->display,
2550d522f475Smrg		     VWindow(screen), gc2,
2551d522f475Smrg		     points, npoints,
2552d522f475Smrg		     Convex, CoordModeOrigin);
2553d522f475Smrg    } else if (ch == 7) {	/* degrees */
2554d522f475Smrg	unsigned width = (BOX_WIDE / 3);
2555956cc18dSsnj	int x_coord = MID_WIDE - (int) (width / 2);
2556956cc18dSsnj	int y_coord = MID_HIGH - (int) width;
2557d522f475Smrg
2558d522f475Smrg	SCALE_X(x_coord);
2559d522f475Smrg	SCALE_Y(y_coord);
2560e39b573cSmrg	width = (unsigned) SCALED_X(width);
2561d522f475Smrg
2562d522f475Smrg	XDrawArc(screen->display,
2563d522f475Smrg		 VWindow(screen), gc2,
2564d522f475Smrg		 x + x_coord, y + y_coord, width, width,
2565d522f475Smrg		 0,
2566d522f475Smrg		 360 * 64);
2567d522f475Smrg    } else if (ch == 0x1f) {	/* bullet */
2568d522f475Smrg	unsigned width = 7 * BOX_WIDE / 10;
2569956cc18dSsnj	int x_coord = MID_WIDE - (int) (width / 3);
2570956cc18dSsnj	int y_coord = MID_HIGH - (int) (width / 3);
2571d522f475Smrg
2572d522f475Smrg	SCALE_X(x_coord);
2573d522f475Smrg	SCALE_Y(y_coord);
2574e39b573cSmrg	width = (unsigned) SCALED_X(width);
2575d522f475Smrg
2576d522f475Smrg	XDrawArc(screen->display,
2577d522f475Smrg		 VWindow(screen), gc2,
2578d522f475Smrg		 x + x_coord, y + y_coord, width, width,
2579d522f475Smrg		 0,
2580d522f475Smrg		 360 * 64);
2581d522f475Smrg    } else if (ch < (sizeof(lines) / sizeof(lines[0]))
2582d522f475Smrg	       && (p = lines[ch]) != 0) {
2583956cc18dSsnj	int coord[4];
2584d522f475Smrg	int n = 0;
2585d522f475Smrg	while (*p >= 0) {
2586d522f475Smrg	    coord[n++] = *p++;
2587d522f475Smrg	    if (n == 4) {
2588d522f475Smrg		SCALE_X(coord[0]);
2589d522f475Smrg		SCALE_Y(coord[1]);
2590d522f475Smrg		SCALE_X(coord[2]);
2591d522f475Smrg		SCALE_Y(coord[3]);
2592d522f475Smrg		XDrawLine(screen->display,
2593d522f475Smrg			  VWindow(screen), gc2,
2594d522f475Smrg			  x + coord[0], y + coord[1],
2595d522f475Smrg			  x + coord[2], y + coord[3]);
2596d522f475Smrg		n = 0;
2597d522f475Smrg	    }
2598d522f475Smrg	}
2599d522f475Smrg    } else if (screen->force_all_chars) {
2600d522f475Smrg	/* bounding rectangle, for debugging */
2601d522f475Smrg	XDrawRectangle(screen->display, VWindow(screen), gc2, x, y,
2602d522f475Smrg		       font_width - 1,
2603d522f475Smrg		       font_height - 1);
2604d522f475Smrg    }
2605d522f475Smrg}
2606d522f475Smrg
2607d522f475Smrg#if OPT_RENDERFONT
2608d522f475Smrg
2609d522f475Smrg/*
2610d522f475Smrg * Check if the given character has a glyph known to Xft.
2611d522f475Smrg *
2612d522f475Smrg * see xc/lib/Xft/xftglyphs.c
2613d522f475Smrg */
2614d522f475SmrgBool
2615d522f475SmrgxtermXftMissing(XtermWidget xw, XftFont * font, unsigned wc)
2616d522f475Smrg{
2617d522f475Smrg    Bool result = False;
2618d522f475Smrg
2619d522f475Smrg    if (font != 0) {
2620956cc18dSsnj	TScreen *screen = TScreenOf(xw);
2621956cc18dSsnj	if (!XftGlyphExists(screen->display, font, wc)) {
2622d522f475Smrg#if OPT_WIDE_CHARS
2623d522f475Smrg	    TRACE(("xtermXftMissing %d (dec=%#x, ucs=%#x)\n",
2624d522f475Smrg		   wc, ucs2dec(wc), dec2ucs(wc)));
2625d522f475Smrg#else
2626d522f475Smrg	    TRACE(("xtermXftMissing %d\n", wc));
2627d522f475Smrg#endif
2628d522f475Smrg	    result = True;
2629d522f475Smrg	}
2630d522f475Smrg    }
2631d522f475Smrg    return result;
2632d522f475Smrg}
2633d522f475Smrg#endif /* OPT_RENDERFONT && OPT_WIDE_CHARS */
2634d522f475Smrg
2635d522f475Smrg#endif /* OPT_BOX_CHARS */
2636d522f475Smrg
2637d522f475Smrg#if OPT_WIDE_CHARS
2638d522f475Smrg#define MY_UCS(ucs,dec) case ucs: result = dec; break
2639d522f475Smrgunsigned
2640d522f475Smrgucs2dec(unsigned ch)
2641d522f475Smrg{
2642d522f475Smrg    unsigned result = ch;
2643d522f475Smrg    if ((ch > 127)
2644d522f475Smrg	&& (ch != UCS_REPL)) {
2645d522f475Smrg	switch (ch) {
2646d522f475Smrg	    MY_UCS(0x25ae, 0);	/* black vertical rectangle                   */
2647d522f475Smrg	    MY_UCS(0x25c6, 1);	/* black diamond                              */
2648d522f475Smrg	    MY_UCS(0x2592, 2);	/* medium shade                               */
2649d522f475Smrg	    MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation           */
2650d522f475Smrg	    MY_UCS(0x240c, 4);	/* symbol for form feed                       */
2651d522f475Smrg	    MY_UCS(0x240d, 5);	/* symbol for carriage return                 */
2652d522f475Smrg	    MY_UCS(0x240a, 6);	/* symbol for line feed                       */
2653d522f475Smrg	    MY_UCS(0x00b0, 7);	/* degree sign                                */
2654d522f475Smrg	    MY_UCS(0x00b1, 8);	/* plus-minus sign                            */
2655d522f475Smrg	    MY_UCS(0x2424, 9);	/* symbol for newline                         */
2656d522f475Smrg	    MY_UCS(0x240b, 10);	/* symbol for vertical tabulation             */
2657d522f475Smrg	    MY_UCS(0x2518, 11);	/* box drawings light up and left             */
2658d522f475Smrg	    MY_UCS(0x2510, 12);	/* box drawings light down and left           */
2659d522f475Smrg	    MY_UCS(0x250c, 13);	/* box drawings light down and right          */
2660d522f475Smrg	    MY_UCS(0x2514, 14);	/* box drawings light up and right            */
2661d522f475Smrg	    MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
2662d522f475Smrg	    MY_UCS(0x23ba, 16);	/* box drawings scan 1                        */
2663d522f475Smrg	    MY_UCS(0x23bb, 17);	/* box drawings scan 3                        */
2664d522f475Smrg	    MY_UCS(0x2500, 18);	/* box drawings light horizontal              */
2665d522f475Smrg	    MY_UCS(0x23bc, 19);	/* box drawings scan 7                        */
2666d522f475Smrg	    MY_UCS(0x23bd, 20);	/* box drawings scan 9                        */
2667d522f475Smrg	    MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
2668d522f475Smrg	    MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
2669d522f475Smrg	    MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
2670d522f475Smrg	    MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
2671d522f475Smrg	    MY_UCS(0x2502, 25);	/* box drawings light vertical                */
2672d522f475Smrg	    MY_UCS(0x2264, 26);	/* less-than or equal to                      */
2673d522f475Smrg	    MY_UCS(0x2265, 27);	/* greater-than or equal to                   */
2674d522f475Smrg	    MY_UCS(0x03c0, 28);	/* greek small letter pi                      */
2675d522f475Smrg	    MY_UCS(0x2260, 29);	/* not equal to                               */
2676d522f475Smrg	    MY_UCS(0x00a3, 30);	/* pound sign                                 */
2677d522f475Smrg	    MY_UCS(0x00b7, 31);	/* middle dot                                 */
2678d522f475Smrg	}
2679d522f475Smrg    }
2680d522f475Smrg    return result;
2681d522f475Smrg}
2682d522f475Smrg
2683d522f475Smrg#undef  MY_UCS
2684d522f475Smrg#define MY_UCS(ucs,dec) case dec: result = ucs; break
2685d522f475Smrg
2686d522f475Smrgunsigned
2687d522f475Smrgdec2ucs(unsigned ch)
2688d522f475Smrg{
2689d522f475Smrg    unsigned result = ch;
2690d522f475Smrg    if (xtermIsDecGraphic(ch)) {
2691d522f475Smrg	switch (ch) {
2692d522f475Smrg	    MY_UCS(0x25ae, 0);	/* black vertical rectangle                   */
2693d522f475Smrg	    MY_UCS(0x25c6, 1);	/* black diamond                              */
2694d522f475Smrg	    MY_UCS(0x2592, 2);	/* medium shade                               */
2695d522f475Smrg	    MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation           */
2696d522f475Smrg	    MY_UCS(0x240c, 4);	/* symbol for form feed                       */
2697d522f475Smrg	    MY_UCS(0x240d, 5);	/* symbol for carriage return                 */
2698d522f475Smrg	    MY_UCS(0x240a, 6);	/* symbol for line feed                       */
2699d522f475Smrg	    MY_UCS(0x00b0, 7);	/* degree sign                                */
2700d522f475Smrg	    MY_UCS(0x00b1, 8);	/* plus-minus sign                            */
2701d522f475Smrg	    MY_UCS(0x2424, 9);	/* symbol for newline                         */
2702d522f475Smrg	    MY_UCS(0x240b, 10);	/* symbol for vertical tabulation             */
2703d522f475Smrg	    MY_UCS(0x2518, 11);	/* box drawings light up and left             */
2704d522f475Smrg	    MY_UCS(0x2510, 12);	/* box drawings light down and left           */
2705d522f475Smrg	    MY_UCS(0x250c, 13);	/* box drawings light down and right          */
2706d522f475Smrg	    MY_UCS(0x2514, 14);	/* box drawings light up and right            */
2707d522f475Smrg	    MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
2708d522f475Smrg	    MY_UCS(0x23ba, 16);	/* box drawings scan 1                        */
2709d522f475Smrg	    MY_UCS(0x23bb, 17);	/* box drawings scan 3                        */
2710d522f475Smrg	    MY_UCS(0x2500, 18);	/* box drawings light horizontal              */
2711d522f475Smrg	    MY_UCS(0x23bc, 19);	/* box drawings scan 7                        */
2712d522f475Smrg	    MY_UCS(0x23bd, 20);	/* box drawings scan 9                        */
2713d522f475Smrg	    MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
2714d522f475Smrg	    MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
2715d522f475Smrg	    MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
2716d522f475Smrg	    MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
2717d522f475Smrg	    MY_UCS(0x2502, 25);	/* box drawings light vertical                */
2718d522f475Smrg	    MY_UCS(0x2264, 26);	/* less-than or equal to                      */
2719d522f475Smrg	    MY_UCS(0x2265, 27);	/* greater-than or equal to                   */
2720d522f475Smrg	    MY_UCS(0x03c0, 28);	/* greek small letter pi                      */
2721d522f475Smrg	    MY_UCS(0x2260, 29);	/* not equal to                               */
2722d522f475Smrg	    MY_UCS(0x00a3, 30);	/* pound sign                                 */
2723d522f475Smrg	    MY_UCS(0x00b7, 31);	/* middle dot                                 */
2724d522f475Smrg	}
2725d522f475Smrg    }
2726d522f475Smrg    return result;
2727d522f475Smrg}
2728d522f475Smrg
2729d522f475Smrg#endif /* OPT_WIDE_CHARS */
2730d522f475Smrg
2731d522f475Smrg#if OPT_SHIFT_FONTS
2732d522f475Smrgstatic void
2733d522f475SmrglookupOneFontSize(XtermWidget xw, int fontnum)
2734d522f475Smrg{
2735d522f475Smrg    TScreen *screen = TScreenOf(xw);
2736d522f475Smrg
2737d522f475Smrg    if (screen->menu_font_sizes[fontnum] == 0) {
2738d522f475Smrg	XTermFonts fnt;
2739d522f475Smrg
2740d522f475Smrg	memset(&fnt, 0, sizeof(fnt));
2741d522f475Smrg	screen->menu_font_sizes[fontnum] = -1;
2742956cc18dSsnj	if (xtermOpenFont(xw, screen->MenuFontName(fontnum), &fnt, fwAlways, True)) {
274320d2c4d2Smrg	    if (fontnum <= fontMenu_lastBuiltin
274420d2c4d2Smrg		|| strcmp(fnt.fn, DEFFONT))
274520d2c4d2Smrg		screen->menu_font_sizes[fontnum] = FontSize(fnt.fs);
2746d522f475Smrg	    xtermCloseFont(xw, &fnt);
2747d522f475Smrg	}
2748d522f475Smrg    }
2749d522f475Smrg}
2750d522f475Smrg
2751d522f475Smrg/*
2752d522f475Smrg * Cache the font-sizes so subsequent larger/smaller font actions will go fast.
2753d522f475Smrg */
2754d522f475Smrgstatic void
2755d522f475SmrglookupFontSizes(XtermWidget xw)
2756d522f475Smrg{
2757d522f475Smrg    int n;
2758d522f475Smrg
2759d522f475Smrg    for (n = 0; n < NMENUFONTS; n++) {
2760d522f475Smrg	lookupOneFontSize(xw, n);
2761d522f475Smrg    }
2762d522f475Smrg}
2763d522f475Smrg
27642eaa94a1Schristos#if OPT_RENDERFONT
27652eaa94a1Schristos#define NMENU_RENDERFONTS (NMENUFONTS - 2)	/* no selection or escape */
27662eaa94a1Schristosstatic Boolean
27672eaa94a1SchristosuseFaceSizes(XtermWidget xw)
27682eaa94a1Schristos{
27692eaa94a1Schristos    Boolean result = False;
27702eaa94a1Schristos    int n;
27712eaa94a1Schristos
27722eaa94a1Schristos    if (UsingRenderFont(xw)) {
27732eaa94a1Schristos	result = True;
27742eaa94a1Schristos	for (n = 0; n < NMENU_RENDERFONTS; ++n) {
27752eaa94a1Schristos	    if (xw->misc.face_size[n] <= 0.0) {
27762eaa94a1Schristos		result = False;
27772eaa94a1Schristos		break;
27782eaa94a1Schristos	    }
27792eaa94a1Schristos	}
2780956cc18dSsnj	if (!result) {
2781956cc18dSsnj	    Boolean broken_fonts = True;
2782956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
278320d2c4d2Smrg	    long first = screen->menu_font_sizes[0];
2784956cc18dSsnj
2785956cc18dSsnj	    lookupFontSizes(xw);
2786956cc18dSsnj	    for (n = 0; n < NMENUFONTS; n++) {
2787956cc18dSsnj		if (screen->menu_font_sizes[n] > 0
2788956cc18dSsnj		    && screen->menu_font_sizes[n] != first) {
2789956cc18dSsnj		    broken_fonts = False;
2790956cc18dSsnj		    break;
2791956cc18dSsnj		}
2792956cc18dSsnj	    }
2793956cc18dSsnj
2794956cc18dSsnj	    /*
2795956cc18dSsnj	     * Workaround for breakage in font-packages - check if all of the
2796956cc18dSsnj	     * bitmap font sizes are the same, and if we're using TrueType
2797956cc18dSsnj	     * fonts.
2798956cc18dSsnj	     */
2799956cc18dSsnj	    if (broken_fonts) {
2800956cc18dSsnj		float lo_value = (float) 9.0e9;
2801956cc18dSsnj		float hi_value = (float) 0.0;
2802956cc18dSsnj		float value;
2803956cc18dSsnj
2804956cc18dSsnj		TRACE(("bitmap fonts are broken - set faceSize resources\n"));
2805956cc18dSsnj		for (n = 0; n < NMENUFONTS; n++) {
2806956cc18dSsnj		    value = xw->misc.face_size[n];
2807956cc18dSsnj		    if (value > 0.0) {
2808956cc18dSsnj			if (lo_value > value)
2809956cc18dSsnj			    lo_value = value;
2810956cc18dSsnj			if (hi_value < value)
2811956cc18dSsnj			    hi_value = value;
2812956cc18dSsnj		    }
2813956cc18dSsnj		}
2814956cc18dSsnj
2815956cc18dSsnj		if (hi_value <= 0.0)
2816956cc18dSsnj		    sscanf(DEFFACESIZE, "%f", &value);
2817956cc18dSsnj		else
2818956cc18dSsnj		    value = (float) ((hi_value + lo_value) / 2.0);
2819956cc18dSsnj		if (value <= 0)
2820956cc18dSsnj		    value = (float) 14.0;
2821956cc18dSsnj
2822956cc18dSsnj		for (n = 0; n < NMENUFONTS; n++) {
2823956cc18dSsnj		    TRACE(("setting faceSize%d %.1f\n", n, value));
2824956cc18dSsnj		    xw->misc.face_size[n] = value;
2825956cc18dSsnj		    value = (float) (value * 1.1);
2826956cc18dSsnj		}
2827956cc18dSsnj		result = True;
2828956cc18dSsnj	    }
2829956cc18dSsnj	}
28302eaa94a1Schristos    }
28312eaa94a1Schristos    return result;
28322eaa94a1Schristos}
28332eaa94a1Schristos#endif
28342eaa94a1Schristos
2835d522f475Smrg/*
2836d522f475Smrg * Find the index of a larger/smaller font (according to the sign of 'relative'
2837d522f475Smrg * and its magnitude), starting from the 'old' index.
2838d522f475Smrg */
2839d522f475Smrgint
2840d522f475SmrglookupRelativeFontSize(XtermWidget xw, int old, int relative)
2841d522f475Smrg{
2842d522f475Smrg    TScreen *screen = TScreenOf(xw);
2843d522f475Smrg    int n, m = -1;
2844d522f475Smrg
28452eaa94a1Schristos    TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative));
2846d522f475Smrg    if (!IsIcon(screen)) {
28472eaa94a1Schristos#if OPT_RENDERFONT
28482eaa94a1Schristos	if (useFaceSizes(xw)) {
28492eaa94a1Schristos	    TRACE(("...using FaceSize\n"));
28502eaa94a1Schristos	    if (relative != 0) {
28512eaa94a1Schristos		for (n = 0; n < NMENU_RENDERFONTS; ++n) {
28522eaa94a1Schristos		    if (xw->misc.face_size[n] > 0 &&
28532eaa94a1Schristos			xw->misc.face_size[n] != xw->misc.face_size[old]) {
28542eaa94a1Schristos			int cmp_0 = ((xw->misc.face_size[n] >
28552eaa94a1Schristos				      xw->misc.face_size[old])
28562eaa94a1Schristos				     ? relative
28572eaa94a1Schristos				     : -relative);
28582eaa94a1Schristos			int cmp_m = ((m < 0)
28592eaa94a1Schristos				     ? 1
28602eaa94a1Schristos				     : ((xw->misc.face_size[n] <
28612eaa94a1Schristos					 xw->misc.face_size[m])
28622eaa94a1Schristos					? relative
28632eaa94a1Schristos					: -relative));
28642eaa94a1Schristos			if (cmp_0 > 0 && cmp_m > 0) {
28652eaa94a1Schristos			    m = n;
28662eaa94a1Schristos			}
2867d522f475Smrg		    }
2868d522f475Smrg		}
2869d522f475Smrg	    }
28702eaa94a1Schristos	} else
28712eaa94a1Schristos#endif
28722eaa94a1Schristos	{
28732eaa94a1Schristos	    TRACE(("...using bitmap areas\n"));
28742eaa94a1Schristos	    lookupFontSizes(xw);
28752eaa94a1Schristos	    if (relative != 0) {
28762eaa94a1Schristos		for (n = 0; n < NMENUFONTS; ++n) {
28772eaa94a1Schristos		    if (screen->menu_font_sizes[n] > 0 &&
28782eaa94a1Schristos			screen->menu_font_sizes[n] !=
28792eaa94a1Schristos			screen->menu_font_sizes[old]) {
28802eaa94a1Schristos			int cmp_0 = ((screen->menu_font_sizes[n] >
28812eaa94a1Schristos				      screen->menu_font_sizes[old])
28822eaa94a1Schristos				     ? relative
28832eaa94a1Schristos				     : -relative);
28842eaa94a1Schristos			int cmp_m = ((m < 0)
28852eaa94a1Schristos				     ? 1
28862eaa94a1Schristos				     : ((screen->menu_font_sizes[n] <
28872eaa94a1Schristos					 screen->menu_font_sizes[m])
28882eaa94a1Schristos					? relative
28892eaa94a1Schristos					: -relative));
28902eaa94a1Schristos			if (cmp_0 > 0 && cmp_m > 0) {
28912eaa94a1Schristos			    m = n;
28922eaa94a1Schristos			}
28932eaa94a1Schristos		    }
28942eaa94a1Schristos		}
2895d522f475Smrg	    }
2896d522f475Smrg	}
28972eaa94a1Schristos	TRACE(("...new index %d\n", m));
28982eaa94a1Schristos	if (m >= 0) {
28992eaa94a1Schristos	    if (relative > 1)
29002eaa94a1Schristos		m = lookupRelativeFontSize(xw, m, relative - 1);
29012eaa94a1Schristos	    else if (relative < -1)
29022eaa94a1Schristos		m = lookupRelativeFontSize(xw, m, relative + 1);
29032eaa94a1Schristos	}
2904d522f475Smrg    }
2905d522f475Smrg    return m;
2906d522f475Smrg}
2907d522f475Smrg
2908d522f475Smrg/* ARGSUSED */
2909d522f475Smrgvoid
2910d522f475SmrgHandleLargerFont(Widget w GCC_UNUSED,
2911d522f475Smrg		 XEvent * event GCC_UNUSED,
2912d522f475Smrg		 String * params GCC_UNUSED,
2913d522f475Smrg		 Cardinal *param_count GCC_UNUSED)
2914d522f475Smrg{
2915956cc18dSsnj    XtermWidget xw;
2916d522f475Smrg
291720d2c4d2Smrg    TRACE(("Handle larger-vt-font for %p\n", (void *) w));
2918956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
2919d522f475Smrg	if (xw->misc.shift_fonts) {
2920956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
2921d522f475Smrg	    int m;
2922d522f475Smrg
2923d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, 1);
2924d522f475Smrg	    if (m >= 0) {
2925d522f475Smrg		SetVTFont(xw, m, True, NULL);
2926d522f475Smrg	    } else {
292720d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
2928d522f475Smrg	    }
2929d522f475Smrg	}
2930d522f475Smrg    }
2931d522f475Smrg}
2932d522f475Smrg
2933d522f475Smrg/* ARGSUSED */
2934d522f475Smrgvoid
2935d522f475SmrgHandleSmallerFont(Widget w GCC_UNUSED,
2936d522f475Smrg		  XEvent * event GCC_UNUSED,
2937d522f475Smrg		  String * params GCC_UNUSED,
2938d522f475Smrg		  Cardinal *param_count GCC_UNUSED)
2939d522f475Smrg{
2940956cc18dSsnj    XtermWidget xw;
2941d522f475Smrg
294220d2c4d2Smrg    TRACE(("Handle smaller-vt-font for %p\n", (void *) w));
2943956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
2944d522f475Smrg	if (xw->misc.shift_fonts) {
2945956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
2946d522f475Smrg	    int m;
2947d522f475Smrg
2948d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, -1);
2949d522f475Smrg	    if (m >= 0) {
2950d522f475Smrg		SetVTFont(xw, m, True, NULL);
2951d522f475Smrg	    } else {
295220d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
2953d522f475Smrg	    }
2954d522f475Smrg	}
2955d522f475Smrg    }
2956d522f475Smrg}
2957d522f475Smrg#endif
2958d522f475Smrg
2959d522f475Smrgint
2960d522f475SmrgxtermGetFont(const char *param)
2961d522f475Smrg{
2962d522f475Smrg    int fontnum;
2963d522f475Smrg
2964d522f475Smrg    switch (param[0]) {
2965d522f475Smrg    case 'd':
2966d522f475Smrg    case 'D':
2967d522f475Smrg    case '0':
2968d522f475Smrg	fontnum = fontMenu_default;
2969d522f475Smrg	break;
2970d522f475Smrg    case '1':
2971d522f475Smrg	fontnum = fontMenu_font1;
2972d522f475Smrg	break;
2973d522f475Smrg    case '2':
2974d522f475Smrg	fontnum = fontMenu_font2;
2975d522f475Smrg	break;
2976d522f475Smrg    case '3':
2977d522f475Smrg	fontnum = fontMenu_font3;
2978d522f475Smrg	break;
2979d522f475Smrg    case '4':
2980d522f475Smrg	fontnum = fontMenu_font4;
2981d522f475Smrg	break;
2982d522f475Smrg    case '5':
2983d522f475Smrg	fontnum = fontMenu_font5;
2984d522f475Smrg	break;
2985d522f475Smrg    case '6':
2986d522f475Smrg	fontnum = fontMenu_font6;
2987d522f475Smrg	break;
2988d522f475Smrg    case 'e':
2989d522f475Smrg    case 'E':
2990d522f475Smrg	fontnum = fontMenu_fontescape;
2991d522f475Smrg	break;
2992d522f475Smrg    case 's':
2993d522f475Smrg    case 'S':
2994d522f475Smrg	fontnum = fontMenu_fontsel;
2995d522f475Smrg	break;
2996d522f475Smrg    default:
2997d522f475Smrg	fontnum = -1;
2998d522f475Smrg	break;
2999d522f475Smrg    }
3000d522f475Smrg    return fontnum;
3001d522f475Smrg}
3002d522f475Smrg
3003d522f475Smrg/* ARGSUSED */
3004d522f475Smrgvoid
3005d522f475SmrgHandleSetFont(Widget w GCC_UNUSED,
3006d522f475Smrg	      XEvent * event GCC_UNUSED,
3007d522f475Smrg	      String * params,
3008d522f475Smrg	      Cardinal *param_count)
3009d522f475Smrg{
3010956cc18dSsnj    XtermWidget xw;
3011956cc18dSsnj
3012956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
3013d522f475Smrg	int fontnum;
3014d522f475Smrg	VTFontNames fonts;
3015d522f475Smrg
3016d522f475Smrg	memset(&fonts, 0, sizeof(fonts));
3017d522f475Smrg
3018d522f475Smrg	if (*param_count == 0) {
3019d522f475Smrg	    fontnum = fontMenu_default;
3020d522f475Smrg	} else {
3021d522f475Smrg	    Cardinal maxparams = 1;	/* total number of params allowed */
3022d522f475Smrg	    int result = xtermGetFont(params[0]);
3023d522f475Smrg
3024d522f475Smrg	    switch (result) {
3025d522f475Smrg	    case fontMenu_default:	/* FALLTHRU */
3026d522f475Smrg	    case fontMenu_font1:	/* FALLTHRU */
3027d522f475Smrg	    case fontMenu_font2:	/* FALLTHRU */
3028d522f475Smrg	    case fontMenu_font3:	/* FALLTHRU */
3029d522f475Smrg	    case fontMenu_font4:	/* FALLTHRU */
3030d522f475Smrg	    case fontMenu_font5:	/* FALLTHRU */
3031d522f475Smrg	    case fontMenu_font6:	/* FALLTHRU */
3032d522f475Smrg		break;
3033d522f475Smrg	    case fontMenu_fontescape:
3034d522f475Smrg#if OPT_WIDE_CHARS
3035d522f475Smrg		maxparams = 5;
3036d522f475Smrg#else
3037d522f475Smrg		maxparams = 3;
3038d522f475Smrg#endif
3039d522f475Smrg		break;
3040d522f475Smrg	    case fontMenu_fontsel:
3041d522f475Smrg		maxparams = 2;
3042d522f475Smrg		break;
3043d522f475Smrg	    default:
304420d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
3045d522f475Smrg		return;
3046d522f475Smrg	    }
3047d522f475Smrg	    fontnum = result;
3048d522f475Smrg
3049d522f475Smrg	    if (*param_count > maxparams) {	/* see if extra args given */
305020d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
3051d522f475Smrg		return;
3052d522f475Smrg	    }
3053d522f475Smrg	    switch (*param_count) {	/* assign 'em */
3054d522f475Smrg#if OPT_WIDE_CHARS
3055d522f475Smrg	    case 5:
3056d522f475Smrg		fonts.f_wb = params[4];
3057d522f475Smrg		/* FALLTHRU */
3058d522f475Smrg	    case 4:
3059d522f475Smrg		fonts.f_w = params[3];
3060d522f475Smrg		/* FALLTHRU */
3061d522f475Smrg#endif
3062d522f475Smrg	    case 3:
3063d522f475Smrg		fonts.f_b = params[2];
3064d522f475Smrg		/* FALLTHRU */
3065d522f475Smrg	    case 2:
3066d522f475Smrg		fonts.f_n = params[1];
3067d522f475Smrg		break;
3068d522f475Smrg	    }
3069d522f475Smrg	}
3070d522f475Smrg
3071956cc18dSsnj	SetVTFont(xw, fontnum, True, &fonts);
3072d522f475Smrg    }
3073d522f475Smrg}
3074d522f475Smrg
3075d522f475Smrgvoid
3076d522f475SmrgSetVTFont(XtermWidget xw,
3077d522f475Smrg	  int which,
3078d522f475Smrg	  Bool doresize,
3079d522f475Smrg	  const VTFontNames * fonts)
3080d522f475Smrg{
3081956cc18dSsnj    TScreen *screen = TScreenOf(xw);
3082d522f475Smrg
3083d522f475Smrg    TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which,
3084d522f475Smrg	   (fonts && fonts->f_n) ? fonts->f_n : "<null>",
3085d522f475Smrg	   (fonts && fonts->f_b) ? fonts->f_b : "<null>"));
3086d522f475Smrg
3087d522f475Smrg    if (IsIcon(screen)) {
308820d2c4d2Smrg	Bell(xw, XkbBI_MinorError, 0);
3089d522f475Smrg    } else if (which >= 0 && which < NMENUFONTS) {
3090d522f475Smrg	VTFontNames myfonts;
3091d522f475Smrg
3092d522f475Smrg	memset(&myfonts, 0, sizeof(myfonts));
3093d522f475Smrg	if (fonts != 0)
3094d522f475Smrg	    myfonts = *fonts;
3095d522f475Smrg
3096d522f475Smrg	if (which == fontMenu_fontsel) {	/* go get the selection */
3097d522f475Smrg	    FindFontSelection(xw, myfonts.f_n, False);
3098d522f475Smrg	} else {
3099d522f475Smrg	    int oldFont = screen->menu_font_number;
3100d522f475Smrg
3101d522f475Smrg#define USE_CACHED(field, name) \
3102d522f475Smrg	    if (myfonts.field == 0) { \
3103492d43a5Smrg		myfonts.field = x_strdup(screen->menu_font_names[which][name]); \
3104d522f475Smrg		TRACE(("set myfonts." #field " from menu_font_names[%d][" #name "] %s\n", \
3105d522f475Smrg		       which, NonNull(myfonts.field))); \
3106d522f475Smrg	    } else { \
3107d522f475Smrg		TRACE(("set myfonts." #field " reused\n")); \
3108d522f475Smrg	    }
310920d2c4d2Smrg#define SAVE_FNAME(field, name) \
311020d2c4d2Smrg	    if (myfonts.field != 0) { \
311120d2c4d2Smrg		if (screen->menu_font_names[which][name] == 0 \
311220d2c4d2Smrg		 || strcmp(screen->menu_font_names[which][name], myfonts.field)) { \
311320d2c4d2Smrg		    TRACE(("updating menu_font_names[%d][" #name "] to %s\n", \
311420d2c4d2Smrg			   which, myfonts.field)); \
311520d2c4d2Smrg		    screen->menu_font_names[which][name] = x_strdup(myfonts.field); \
311620d2c4d2Smrg		} \
311720d2c4d2Smrg	    }
311820d2c4d2Smrg
3119d522f475Smrg	    USE_CACHED(f_n, fNorm);
3120d522f475Smrg	    USE_CACHED(f_b, fBold);
3121d522f475Smrg#if OPT_WIDE_CHARS
3122d522f475Smrg	    USE_CACHED(f_w, fWide);
3123d522f475Smrg	    USE_CACHED(f_wb, fWBold);
3124d522f475Smrg#endif
3125d522f475Smrg	    if (xtermLoadFont(xw,
3126d522f475Smrg			      &myfonts,
3127d522f475Smrg			      doresize, which)) {
312820d2c4d2Smrg		/*
312920d2c4d2Smrg		 * If successful, save the data so that a subsequent query via
313020d2c4d2Smrg		 * OSC-50 will return the expected values.
313120d2c4d2Smrg		 */
313220d2c4d2Smrg		SAVE_FNAME(f_n, fNorm);
313320d2c4d2Smrg		SAVE_FNAME(f_b, fBold);
313420d2c4d2Smrg#if OPT_WIDE_CHARS
313520d2c4d2Smrg		SAVE_FNAME(f_w, fWide);
313620d2c4d2Smrg		SAVE_FNAME(f_wb, fWBold);
313720d2c4d2Smrg#endif
3138d522f475Smrg	    } else {
3139d522f475Smrg		xtermLoadFont(xw,
3140d522f475Smrg			      xtermFontName(screen->MenuFontName(oldFont)),
3141d522f475Smrg			      doresize, oldFont);
314220d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
3143d522f475Smrg	    }
3144d522f475Smrg	}
314520d2c4d2Smrg    } else {
314620d2c4d2Smrg	Bell(xw, XkbBI_MinorError, 0);
3147d522f475Smrg    }
3148d522f475Smrg    return;
3149d522f475Smrg}
3150