fontutils.c revision 956cc18d
1956cc18dSsnj/* $XTermId: fontutils.c,v 1.307 2009/08/07 23:22:32 tom Exp $ */
2d522f475Smrg
3d522f475Smrg/************************************************************
4d522f475Smrg
5956cc18dSsnjCopyright 1998-2008,2009 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>
45d522f475Smrg
46d522f475Smrg#include <main.h>
47d522f475Smrg#include <data.h>
48d522f475Smrg#include <menu.h>
49d522f475Smrg#include <xstrings.h>
50d522f475Smrg#include <xterm.h>
51d522f475Smrg
52d522f475Smrg#include <stdio.h>
53d522f475Smrg#include <ctype.h>
54d522f475Smrg
55d522f475Smrg/* from X11/Xlibint.h - not all vendors install this file */
56d522f475Smrg#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
57d522f475Smrg			     (((cs)->rbearing|(cs)->lbearing| \
58d522f475Smrg			       (cs)->ascent|(cs)->descent) == 0))
59d522f475Smrg
60d522f475Smrg#define CI_GET_CHAR_INFO_1D(fs,col,def,cs) \
61d522f475Smrg{ \
62d522f475Smrg    cs = def; \
63d522f475Smrg    if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
64d522f475Smrg	if (fs->per_char == NULL) { \
65d522f475Smrg	    cs = &fs->min_bounds; \
66d522f475Smrg	} else { \
67d522f475Smrg	    cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
68d522f475Smrg	    if (CI_NONEXISTCHAR(cs)) cs = def; \
69d522f475Smrg	} \
70d522f475Smrg    } \
71d522f475Smrg}
72d522f475Smrg
73d522f475Smrg#define CI_GET_CHAR_INFO_2D(fs,row,col,def,cs) \
74d522f475Smrg{ \
75d522f475Smrg    cs = def; \
76d522f475Smrg    if (row >= fs->min_byte1 && row <= fs->max_byte1 && \
77d522f475Smrg	col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
78d522f475Smrg	if (fs->per_char == NULL) { \
79d522f475Smrg	    cs = &fs->min_bounds; \
80d522f475Smrg	} else { \
81d522f475Smrg	    cs = &fs->per_char[((row - fs->min_byte1) * \
82d522f475Smrg				(fs->max_char_or_byte2 - \
83d522f475Smrg				 fs->min_char_or_byte2 + 1)) + \
84d522f475Smrg			       (col - fs->min_char_or_byte2)]; \
85d522f475Smrg	    if (CI_NONEXISTCHAR(cs)) cs = def; \
86d522f475Smrg	} \
87d522f475Smrg    } \
88d522f475Smrg}
89d522f475Smrg
90d522f475Smrg#define MAX_FONTNAME 200
91d522f475Smrg
92d522f475Smrg/*
93d522f475Smrg * A structure to hold the relevant properties from a font
94d522f475Smrg * we need to make a well formed font name for it.
95d522f475Smrg */
96d522f475Smrgtypedef struct {
97d522f475Smrg    /* registry, foundry, family */
98d522f475Smrg    char *beginning;
99d522f475Smrg    /* weight */
100d522f475Smrg    char *weight;
101d522f475Smrg    /* slant */
102d522f475Smrg    char *slant;
103d522f475Smrg    /* wideness */
104d522f475Smrg    char *wideness;
105d522f475Smrg    /* add style */
106d522f475Smrg    char *add_style;
107d522f475Smrg    int pixel_size;
108d522f475Smrg    char *point_size;
109d522f475Smrg    int res_x;
110d522f475Smrg    int res_y;
111d522f475Smrg    char *spacing;
112d522f475Smrg    int average_width;
113d522f475Smrg    /* charset registry, charset encoding */
114d522f475Smrg    char *end;
115d522f475Smrg} FontNameProperties;
116d522f475Smrg
117d522f475Smrg#if OPT_SHIFT_FONTS
118d522f475Smrgstatic void lookupOneFontSize(XtermWidget, int);
119d522f475Smrg#endif
120d522f475Smrg
121d522f475Smrg#if OPT_WIDE_CHARS
1222eaa94a1Schristosstatic unsigned
123d522f475SmrgcountGlyphs(XFontStruct * fp)
124d522f475Smrg{
125d522f475Smrg    unsigned count = 0;
126d522f475Smrg
127d522f475Smrg    if (fp != 0) {
128d522f475Smrg	if (fp->min_byte1 == 0 && fp->max_byte1 == 0) {
129d522f475Smrg	    count = fp->max_char_or_byte2 - fp->min_char_or_byte2;
130d522f475Smrg	} else if (fp->min_char_or_byte2 < 256
131d522f475Smrg		   && fp->max_char_or_byte2 < 256) {
132d522f475Smrg	    unsigned first = (fp->min_byte1 << 8) + fp->min_char_or_byte2;
133d522f475Smrg	    unsigned last = (fp->max_byte1 << 8) + fp->max_char_or_byte2;
134d522f475Smrg	    count = last + 1 - first;
135d522f475Smrg	}
136d522f475Smrg    }
137d522f475Smrg    return count;
138d522f475Smrg}
139d522f475Smrg
140d522f475Smrg/*
141d522f475Smrg * Verify that the wide-bold font is at least a bold font with roughly as many
142d522f475Smrg * glyphs as the wide font.  The counts should be the same, but settle for
143d522f475Smrg * filtering out the worst of the font mismatches.
144d522f475Smrg */
145d522f475Smrgstatic Bool
146d522f475SmrgcompatibleWideCounts(XFontStruct * wfs, XFontStruct * wbfs)
147d522f475Smrg{
148d522f475Smrg    unsigned count_w = countGlyphs(wfs);
149d522f475Smrg    unsigned count_wb = countGlyphs(wbfs);
150d522f475Smrg    if (count_w <= 256 ||
151d522f475Smrg	count_wb <= 256 ||
152d522f475Smrg	((count_w / 4) * 3) > count_wb) {
153d522f475Smrg	TRACE(("...font server lied (count wide %u vs wide-bold %u)\n",
154d522f475Smrg	       count_w, count_wb));
155d522f475Smrg	return False;
156d522f475Smrg    }
157d522f475Smrg    return True;
158d522f475Smrg}
159d522f475Smrg#endif /* OPT_WIDE_CHARS */
160d522f475Smrg
161d522f475Smrg/*
162d522f475Smrg * Returns the fields from start to stop in a dash- separated string.  This
163d522f475Smrg * function will modify the source, putting '\0's in the appropiate place and
164d522f475Smrg * moving the beginning forward to after the '\0'
165d522f475Smrg *
166d522f475Smrg * This will NOT work for the last field (but we won't need it).
167d522f475Smrg */
168d522f475Smrgstatic char *
169d522f475Smrgn_fields(char **source, int start, int stop)
170d522f475Smrg{
171d522f475Smrg    int i;
172d522f475Smrg    char *str, *str1;
173d522f475Smrg
174d522f475Smrg    /*
175d522f475Smrg     * find the start-1th dash
176d522f475Smrg     */
177d522f475Smrg    for (i = start - 1, str = *source; i; i--, str++)
178d522f475Smrg	if ((str = strchr(str, '-')) == 0)
179d522f475Smrg	    return 0;
180d522f475Smrg
181d522f475Smrg    /*
182d522f475Smrg     * find the stopth dash
183d522f475Smrg     */
184d522f475Smrg    for (i = stop - start + 1, str1 = str; i; i--, str1++)
185d522f475Smrg	if ((str1 = strchr(str1, '-')) == 0)
186d522f475Smrg	    return 0;
187d522f475Smrg
188d522f475Smrg    /*
189d522f475Smrg     * put a \0 at the end of the fields
190d522f475Smrg     */
191d522f475Smrg    *(str1 - 1) = '\0';
192d522f475Smrg
193d522f475Smrg    /*
194d522f475Smrg     * move source forward
195d522f475Smrg     */
196d522f475Smrg    *source = str1;
197d522f475Smrg
198d522f475Smrg    return str;
199d522f475Smrg}
200d522f475Smrg
201956cc18dSsnjstatic Boolean
202956cc18dSsnjcheck_fontname(const char *name)
203956cc18dSsnj{
204956cc18dSsnj    Boolean result = True;
205956cc18dSsnj
206956cc18dSsnj    if (name == 0) {
207956cc18dSsnj	TRACE(("fontname missing\n"));
208956cc18dSsnj	result = False;
209956cc18dSsnj    } else if (strlen(name) >= MAX_FONTNAME - 1) {
210956cc18dSsnj	TRACE(("fontname too large: %s\n", name));
211956cc18dSsnj	result = False;
212956cc18dSsnj    }
213956cc18dSsnj    return result;
214956cc18dSsnj}
215956cc18dSsnj
216d522f475Smrg/*
217d522f475Smrg * Gets the font properties from a given font structure.  We use the FONT name
218d522f475Smrg * to find them out, since that seems easier.
219d522f475Smrg *
220d522f475Smrg * Returns a pointer to a static FontNameProperties structure
221d522f475Smrg * or NULL on error.
222d522f475Smrg */
223d522f475Smrgstatic FontNameProperties *
224d522f475Smrgget_font_name_props(Display * dpy, XFontStruct * fs, char *result)
225d522f475Smrg{
226d522f475Smrg    static FontNameProperties props;
227d522f475Smrg    static char *last_name;
228d522f475Smrg
229d522f475Smrg    XFontProp *fp;
230d522f475Smrg    int i;
231d522f475Smrg    Atom fontatom = XInternAtom(dpy, "FONT", False);
232d522f475Smrg    char *name;
233d522f475Smrg    char *str;
234d522f475Smrg
235d522f475Smrg    /*
236d522f475Smrg     * first get the full font name
237d522f475Smrg     */
238d522f475Smrg    for (name = 0, i = 0, fp = fs->properties;
239d522f475Smrg	 i < fs->n_properties;
240d522f475Smrg	 i++, fp++)
241d522f475Smrg	if (fp->name == fontatom)
242d522f475Smrg	    name = XGetAtomName(dpy, fp->card32);
243d522f475Smrg
244d522f475Smrg    if (name == 0)
245d522f475Smrg	return 0;
246d522f475Smrg
247d522f475Smrg    /*
248d522f475Smrg     * XGetAtomName allocates memory - don't leak
249d522f475Smrg     */
250d522f475Smrg    if (last_name != 0)
251d522f475Smrg	XFree(last_name);
252d522f475Smrg    last_name = name;
253d522f475Smrg
254d522f475Smrg    if (result != 0) {
255956cc18dSsnj	if (!check_fontname(name))
256d522f475Smrg	    return 0;
257956cc18dSsnj	strcpy(result, name);
258d522f475Smrg    }
259d522f475Smrg
260d522f475Smrg    /*
261d522f475Smrg     * Now split it up into parts and put them in
262d522f475Smrg     * their places. Since we are using parts of
263d522f475Smrg     * the original string, we must not free the Atom Name
264d522f475Smrg     */
265d522f475Smrg
266d522f475Smrg    /* registry, foundry, family */
267d522f475Smrg    if ((props.beginning = n_fields(&name, 1, 3)) == 0)
268d522f475Smrg	return 0;
269d522f475Smrg
270d522f475Smrg    /* weight is the next */
271d522f475Smrg    if ((props.weight = n_fields(&name, 1, 1)) == 0)
272d522f475Smrg	return 0;
273d522f475Smrg
274d522f475Smrg    /* slant */
275d522f475Smrg    if ((props.slant = n_fields(&name, 1, 1)) == 0)
276d522f475Smrg	return 0;
277d522f475Smrg
278d522f475Smrg    /* width */
279d522f475Smrg    if ((props.wideness = n_fields(&name, 1, 1)) == 0)
280d522f475Smrg	return 0;
281d522f475Smrg
282d522f475Smrg    /* add style */
283d522f475Smrg    if ((props.add_style = n_fields(&name, 1, 1)) == 0)
284d522f475Smrg	return 0;
285d522f475Smrg
286d522f475Smrg    /* pixel size */
287d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
288d522f475Smrg	return 0;
289d522f475Smrg    if ((props.pixel_size = atoi(str)) == 0)
290d522f475Smrg	return 0;
291d522f475Smrg
292d522f475Smrg    /* point size */
293d522f475Smrg    if ((props.point_size = n_fields(&name, 1, 1)) == 0)
294d522f475Smrg	return 0;
295d522f475Smrg
296d522f475Smrg    /* res_x */
297d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
298d522f475Smrg	return 0;
299d522f475Smrg    if ((props.res_x = atoi(str)) == 0)
300d522f475Smrg	return 0;
301d522f475Smrg
302d522f475Smrg    /* res_y */
303d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
304d522f475Smrg	return 0;
305d522f475Smrg    if ((props.res_y = atoi(str)) == 0)
306d522f475Smrg	return 0;
307d522f475Smrg
308d522f475Smrg    /* spacing */
309d522f475Smrg    if ((props.spacing = n_fields(&name, 1, 1)) == 0)
310d522f475Smrg	return 0;
311d522f475Smrg
312d522f475Smrg    /* average width */
313d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
314d522f475Smrg	return 0;
315d522f475Smrg    if ((props.average_width = atoi(str)) == 0)
316d522f475Smrg	return 0;
317d522f475Smrg
318d522f475Smrg    /* the rest: charset registry and charset encoding */
319d522f475Smrg    props.end = name;
320d522f475Smrg
321d522f475Smrg    return &props;
322d522f475Smrg}
323d522f475Smrg
324d522f475Smrg#define ALLOCHUNK(n) ((n | 127) + 1)
325d522f475Smrg
326d522f475Smrgstatic void
327956cc18dSsnjalloca_fontname(char **result, size_t next)
328d522f475Smrg{
329956cc18dSsnj    size_t last = (*result != 0) ? strlen(*result) : 0;
330956cc18dSsnj    size_t have = (*result != 0) ? ALLOCHUNK(last) : 0;
331956cc18dSsnj    size_t want = last + next + 2;
332d522f475Smrg
333d522f475Smrg    if (want >= have) {
334d522f475Smrg	want = ALLOCHUNK(want);
335d522f475Smrg	if (last != 0) {
336d522f475Smrg	    *result = TypeRealloc(char, want, *result);
337d522f475Smrg	} else {
338d522f475Smrg	    if ((*result = TypeMallocN(char, want)) != 0)
339d522f475Smrg		**result = '\0';
340d522f475Smrg	}
341d522f475Smrg    }
342d522f475Smrg}
343d522f475Smrg
344d522f475Smrgstatic void
345d522f475Smrgappend_fontname_str(char **result, char *value)
346d522f475Smrg{
347d522f475Smrg    if (value == 0)
348d522f475Smrg	value = "*";
349d522f475Smrg    alloca_fontname(result, strlen(value));
350d522f475Smrg    if (*result != 0) {
351d522f475Smrg	if (**result != '\0')
352d522f475Smrg	    strcat(*result, "-");
353d522f475Smrg	strcat(*result, value);
354d522f475Smrg    }
355d522f475Smrg}
356d522f475Smrg
357d522f475Smrgstatic void
358d522f475Smrgappend_fontname_num(char **result, int value)
359d522f475Smrg{
360d522f475Smrg    if (value < 0) {
361d522f475Smrg	append_fontname_str(result, "*");
362d522f475Smrg    } else {
363d522f475Smrg	char temp[100];
364d522f475Smrg	sprintf(temp, "%d", value);
365d522f475Smrg	append_fontname_str(result, temp);
366d522f475Smrg    }
367d522f475Smrg}
368d522f475Smrg
369d522f475Smrg/*
370d522f475Smrg * Take the given font props and try to make a well formed font name specifying
371d522f475Smrg * the same base font and size and everything, but with different weight/width
372d522f475Smrg * according to the parameters.  The return value is allocated, should be freed
373d522f475Smrg * by the caller.
374d522f475Smrg */
375d522f475Smrgstatic char *
376d522f475Smrgderive_font_name(FontNameProperties * props,
377d522f475Smrg		 char *use_weight,
378d522f475Smrg		 int use_average_width,
379d522f475Smrg		 char *use_encoding)
380d522f475Smrg{
381d522f475Smrg    char *result = 0;
382d522f475Smrg
383d522f475Smrg    append_fontname_str(&result, props->beginning);
384d522f475Smrg    append_fontname_str(&result, use_weight);
385d522f475Smrg    append_fontname_str(&result, props->slant);
386d522f475Smrg    append_fontname_str(&result, 0);
387d522f475Smrg    append_fontname_str(&result, 0);
388d522f475Smrg    append_fontname_num(&result, props->pixel_size);
389d522f475Smrg    append_fontname_str(&result, props->point_size);
390d522f475Smrg    append_fontname_num(&result, props->res_x);
391d522f475Smrg    append_fontname_num(&result, props->res_y);
392d522f475Smrg    append_fontname_str(&result, props->spacing);
393d522f475Smrg    append_fontname_num(&result, use_average_width);
394d522f475Smrg    append_fontname_str(&result, use_encoding);
395d522f475Smrg
396d522f475Smrg    return result;
397d522f475Smrg}
398d522f475Smrg
399d522f475Smrgstatic char *
400d522f475Smrgbold_font_name(FontNameProperties * props, int use_average_width)
401d522f475Smrg{
402d522f475Smrg    return derive_font_name(props, "bold", use_average_width, props->end);
403d522f475Smrg}
404d522f475Smrg
405d522f475Smrg#if OPT_WIDE_CHARS
406d522f475Smrg#define derive_wide_font(props, weight) \
407d522f475Smrg	derive_font_name(props, weight, props->average_width * 2, "ISO10646-1")
408d522f475Smrg
409d522f475Smrgstatic char *
410d522f475Smrgwide_font_name(FontNameProperties * props)
411d522f475Smrg{
412d522f475Smrg    return derive_wide_font(props, "medium");
413d522f475Smrg}
414d522f475Smrg
415d522f475Smrgstatic char *
416d522f475Smrgwidebold_font_name(FontNameProperties * props)
417d522f475Smrg{
418d522f475Smrg    return derive_wide_font(props, "bold");
419d522f475Smrg}
420d522f475Smrg#endif /* OPT_WIDE_CHARS */
421d522f475Smrg
422d522f475Smrg#if OPT_DEC_CHRSET
423d522f475Smrg/*
424d522f475Smrg * Take the given font props and try to make a well formed font name specifying
425d522f475Smrg * the same base font but changed depending on the given attributes and chrset.
426d522f475Smrg *
427d522f475Smrg * For double width fonts, we just double the X-resolution, for double height
428d522f475Smrg * fonts we double the pixel-size and Y-resolution
429d522f475Smrg */
430d522f475Smrgchar *
431d522f475SmrgxtermSpecialFont(TScreen * screen, unsigned atts, unsigned chrset)
432d522f475Smrg{
433d522f475Smrg#if OPT_TRACE
434d522f475Smrg    static char old_spacing[80];
435d522f475Smrg    static FontNameProperties old_props;
436d522f475Smrg#endif
437d522f475Smrg    FontNameProperties *props;
438d522f475Smrg    char *result = 0;
439d522f475Smrg    char *weight;
440d522f475Smrg    int pixel_size;
441d522f475Smrg    int res_x;
442d522f475Smrg    int res_y;
443d522f475Smrg
444d522f475Smrg    props = get_font_name_props(screen->display, screen->fnts[fNorm].fs, 0);
445d522f475Smrg    if (props == 0)
446d522f475Smrg	return result;
447d522f475Smrg
448d522f475Smrg    pixel_size = props->pixel_size;
449d522f475Smrg    res_x = props->res_x;
450d522f475Smrg    res_y = props->res_y;
451d522f475Smrg    if (atts & BOLD)
452d522f475Smrg	weight = "bold";
453d522f475Smrg    else
454d522f475Smrg	weight = props->weight;
455d522f475Smrg
456d522f475Smrg    if (CSET_DOUBLE(chrset))
457d522f475Smrg	res_x *= 2;
458d522f475Smrg
459d522f475Smrg    if (chrset == CSET_DHL_TOP
460d522f475Smrg	|| chrset == CSET_DHL_BOT) {
461d522f475Smrg	res_y *= 2;
462d522f475Smrg	pixel_size *= 2;
463d522f475Smrg    }
464d522f475Smrg#if OPT_TRACE
465d522f475Smrg    if (old_props.res_x != res_x
466d522f475Smrg	|| old_props.res_x != res_y
467d522f475Smrg	|| old_props.pixel_size != pixel_size
468d522f475Smrg	|| strcmp(old_props.spacing, props->spacing)) {
469d522f475Smrg	TRACE(("xtermSpecialFont(atts = %#x, chrset = %#x)\n", atts, chrset));
470d522f475Smrg	TRACE(("res_x      = %d\n", res_x));
471d522f475Smrg	TRACE(("res_y      = %d\n", res_y));
472d522f475Smrg	TRACE(("point_size = %s\n", props->point_size));
473d522f475Smrg	TRACE(("pixel_size = %d\n", pixel_size));
474d522f475Smrg	TRACE(("spacing    = %s\n", props->spacing));
475d522f475Smrg	old_props.res_x = res_x;
476d522f475Smrg	old_props.res_x = res_y;
477d522f475Smrg	old_props.pixel_size = pixel_size;
478d522f475Smrg	old_props.spacing = strcpy(old_spacing, props->spacing);
479d522f475Smrg    }
480d522f475Smrg#endif
481d522f475Smrg
482d522f475Smrg    append_fontname_str(&result, props->beginning);
483d522f475Smrg    append_fontname_str(&result, weight);
484d522f475Smrg    append_fontname_str(&result, props->slant);
485d522f475Smrg    append_fontname_str(&result, props->wideness);
486d522f475Smrg    append_fontname_str(&result, props->add_style);
487d522f475Smrg    append_fontname_num(&result, pixel_size);
488d522f475Smrg    append_fontname_str(&result, props->point_size);
489d522f475Smrg    append_fontname_num(&result, (atts & NORESOLUTION) ? -1 : res_x);
490d522f475Smrg    append_fontname_num(&result, (atts & NORESOLUTION) ? -1 : res_y);
491d522f475Smrg    append_fontname_str(&result, props->spacing);
492d522f475Smrg    append_fontname_str(&result, 0);
493d522f475Smrg    append_fontname_str(&result, props->end);
494d522f475Smrg
495d522f475Smrg    return result;
496d522f475Smrg}
497d522f475Smrg#endif /* OPT_DEC_CHRSET */
498d522f475Smrg
499d522f475Smrg/*
500d522f475Smrg * Case-independent comparison for font-names, including wildcards.
501d522f475Smrg * XLFD allows '?' as a wildcard, but we do not handle that (no one seems
502d522f475Smrg * to use it).
503d522f475Smrg */
504d522f475Smrgstatic Bool
505d522f475Smrgsame_font_name(char *pattern, char *match)
506d522f475Smrg{
507956cc18dSsnj    Bool result = False;
508956cc18dSsnj
509956cc18dSsnj    if (pattern && match) {
510956cc18dSsnj	while (*pattern && *match) {
511956cc18dSsnj	    if (*pattern == *match) {
512956cc18dSsnj		pattern++;
513956cc18dSsnj		match++;
514956cc18dSsnj	    } else if (*pattern == '*' || *match == '*') {
515956cc18dSsnj		if (same_font_name(pattern + 1, match)) {
516956cc18dSsnj		    return True;
517956cc18dSsnj		} else if (same_font_name(pattern, match + 1)) {
518956cc18dSsnj		    return True;
519956cc18dSsnj		} else {
520956cc18dSsnj		    return False;
521956cc18dSsnj		}
522d522f475Smrg	    } else {
523956cc18dSsnj		int p = x_toupper(*pattern++);
524956cc18dSsnj		int m = x_toupper(*match++);
525956cc18dSsnj		if (p != m)
526956cc18dSsnj		    return False;
527d522f475Smrg	    }
528d522f475Smrg	}
529956cc18dSsnj	result = (*pattern == *match);	/* both should be NUL */
530d522f475Smrg    }
531956cc18dSsnj    return result;
532d522f475Smrg}
533d522f475Smrg
534d522f475Smrg/*
535d522f475Smrg * Double-check the fontname that we asked for versus what the font server
536d522f475Smrg * actually gave us.  The larger fixed fonts do not always have a matching bold
537d522f475Smrg * font, and the font server may try to scale another font or otherwise
538d522f475Smrg * substitute a mismatched font.
539d522f475Smrg *
540d522f475Smrg * If we cannot get what we requested, we will fallback to the original
541d522f475Smrg * behavior, which simulates bold by overstriking each character at one pixel
542d522f475Smrg * offset.
543d522f475Smrg */
544d522f475Smrgstatic int
545d522f475Smrggot_bold_font(Display * dpy, XFontStruct * fs, char *requested)
546d522f475Smrg{
547d522f475Smrg    char actual[MAX_FONTNAME];
548d522f475Smrg    int got;
549d522f475Smrg
550d522f475Smrg    if (get_font_name_props(dpy, fs, actual) == 0)
551d522f475Smrg	got = 0;
552d522f475Smrg    else
553d522f475Smrg	got = same_font_name(requested, actual);
554d522f475Smrg    return got;
555d522f475Smrg}
556d522f475Smrg
557d522f475Smrg/*
558d522f475Smrg * If the font server tries to adjust another font, it may not adjust it
559d522f475Smrg * properly.  Check that the bounding boxes are compatible.  Otherwise we'll
560d522f475Smrg * leave trash on the display when we mix normal and bold fonts.
561d522f475Smrg */
562d522f475Smrgstatic int
563d522f475Smrgsame_font_size(XtermWidget xw, XFontStruct * nfs, XFontStruct * bfs)
564d522f475Smrg{
565956cc18dSsnj    TScreen *screen = TScreenOf(xw);
566d522f475Smrg    TRACE(("same_font_size height %d/%d, min %d/%d max %d/%d\n",
567d522f475Smrg	   nfs->ascent + nfs->descent,
568d522f475Smrg	   bfs->ascent + bfs->descent,
569d522f475Smrg	   nfs->min_bounds.width, bfs->min_bounds.width,
570d522f475Smrg	   nfs->max_bounds.width, bfs->max_bounds.width));
571956cc18dSsnj    return screen->free_bold_box
572d522f475Smrg	|| ((nfs->ascent + nfs->descent) == (bfs->ascent + bfs->descent)
573d522f475Smrg	    && (nfs->min_bounds.width == bfs->min_bounds.width
574d522f475Smrg		|| nfs->min_bounds.width == bfs->min_bounds.width + 1)
575d522f475Smrg	    && (nfs->max_bounds.width == bfs->max_bounds.width
576d522f475Smrg		|| nfs->max_bounds.width == bfs->max_bounds.width + 1));
577d522f475Smrg}
578d522f475Smrg
579d522f475Smrg/*
580d522f475Smrg * Check if the font looks like it has fixed width
581d522f475Smrg */
582d522f475Smrgstatic int
583d522f475Smrgis_fixed_font(XFontStruct * fs)
584d522f475Smrg{
585d522f475Smrg    if (fs)
586d522f475Smrg	return (fs->min_bounds.width == fs->max_bounds.width);
587d522f475Smrg    return 1;
588d522f475Smrg}
589d522f475Smrg
590d522f475Smrg/*
591d522f475Smrg * Check if the font looks like a double width font (i.e. contains
592d522f475Smrg * characters of width X and 2X
593d522f475Smrg */
594d522f475Smrg#if OPT_WIDE_CHARS
595d522f475Smrgstatic int
596d522f475Smrgis_double_width_font(XFontStruct * fs)
597d522f475Smrg{
598d522f475Smrg    return ((2 * fs->min_bounds.width) == fs->max_bounds.width);
599d522f475Smrg}
600d522f475Smrg#else
601d522f475Smrg#define is_double_width_font(fs) 0
602d522f475Smrg#endif
603d522f475Smrg
604d522f475Smrg#if OPT_WIDE_CHARS && OPT_RENDERFONT && defined(HAVE_TYPE_FCCHAR32)
605d522f475Smrg#define HALF_WIDTH_TEST_STRING "1234567890"
606d522f475Smrg
607d522f475Smrg/* '1234567890' in Chinese characters in UTF-8 */
608d522f475Smrg#define FULL_WIDTH_TEST_STRING "\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89" \
609d522f475Smrg                               "\xe5\x9b\x9b\xe4\xba\x94" \
610d522f475Smrg			       "\xef\xa7\x91\xe4\xb8\x83\xe5\x85\xab" \
611d522f475Smrg			       "\xe4\xb9\x9d\xef\xa6\xb2"
612d522f475Smrg
613d522f475Smrg/* '1234567890' in Korean script in UTF-8 */
614d522f475Smrg#define FULL_WIDTH_TEST_STRING2 "\xec\x9d\xbc\xec\x9d\xb4\xec\x82\xbc" \
615d522f475Smrg                                "\xec\x82\xac\xec\x98\xa4" \
616d522f475Smrg			        "\xec\x9c\xa1\xec\xb9\xa0\xed\x8c\x94" \
617d522f475Smrg			        "\xea\xb5\xac\xec\x98\x81"
618d522f475Smrg
619d522f475Smrg#define HALF_WIDTH_CHAR1  0x0031	/* '1' */
620d522f475Smrg#define HALF_WIDTH_CHAR2  0x0057	/* 'W' */
621d522f475Smrg#define FULL_WIDTH_CHAR1  0x4E00	/* CJK Ideograph 'number one' */
622d522f475Smrg#define FULL_WIDTH_CHAR2  0xAC00	/* Korean script syllable 'Ka' */
623d522f475Smrg
624d522f475Smrgstatic Bool
625d522f475Smrgis_double_width_font_xft(Display * dpy, XftFont * font)
626d522f475Smrg{
627d522f475Smrg    XGlyphInfo gi1, gi2;
628d522f475Smrg    FcChar32 c1 = HALF_WIDTH_CHAR1, c2 = HALF_WIDTH_CHAR2;
629d522f475Smrg    char *fwstr = FULL_WIDTH_TEST_STRING;
630d522f475Smrg    char *hwstr = HALF_WIDTH_TEST_STRING;
631d522f475Smrg
632d522f475Smrg    /* Some Korean fonts don't have Chinese characters at all. */
633d522f475Smrg    if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR1)) {
634d522f475Smrg	if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR2))
635d522f475Smrg	    return False;	/* Not a CJK font */
636d522f475Smrg	else			/* a Korean font without CJK Ideographs */
637d522f475Smrg	    fwstr = FULL_WIDTH_TEST_STRING2;
638d522f475Smrg    }
639d522f475Smrg
640d522f475Smrg    XftTextExtents32(dpy, font, &c1, 1, &gi1);
641d522f475Smrg    XftTextExtents32(dpy, font, &c2, 1, &gi2);
642d522f475Smrg    if (gi1.xOff != gi2.xOff)	/* Not a fixed-width font */
643d522f475Smrg	return False;
644d522f475Smrg
645d522f475Smrg    XftTextExtentsUtf8(dpy, font, (FcChar8 *) hwstr, (int) strlen(hwstr), &gi1);
646d522f475Smrg    XftTextExtentsUtf8(dpy, font, (FcChar8 *) fwstr, (int) strlen(fwstr), &gi2);
647d522f475Smrg
648d522f475Smrg    /*
649d522f475Smrg     * fontconfig and Xft prior to 2.2(?) set the width of half-width
650d522f475Smrg     * characters identical to that of full-width character in CJK double-width
651d522f475Smrg     * (bi-width / monospace) font even though the former is half as wide as
652d522f475Smrg     * the latter.  This was fixed sometime before the release of fontconfig
653d522f475Smrg     * 2.2 in early 2003.  See
654d522f475Smrg     *  http://bugzilla.mozilla.org/show_bug.cgi?id=196312
655d522f475Smrg     * In the meantime, we have to check both possibilities.
656d522f475Smrg     */
657d522f475Smrg    return ((2 * gi1.xOff == gi2.xOff) || (gi1.xOff == gi2.xOff));
658d522f475Smrg}
659d522f475Smrg#else
660d522f475Smrg#define is_double_width_font_xft(dpy, xftfont) 0
661d522f475Smrg#endif
662d522f475Smrg
663d522f475Smrg#define EmptyFont(fs) (fs != 0 \
664d522f475Smrg		   && ((fs)->ascent + (fs)->descent == 0 \
665d522f475Smrg		    || (fs)->max_bounds.width == 0))
666d522f475Smrg
667d522f475Smrg#define FontSize(fs) (((fs)->ascent + (fs)->descent) \
668d522f475Smrg		    *  (fs)->max_bounds.width)
669d522f475Smrg
670d522f475Smrgconst VTFontNames *
671d522f475SmrgxtermFontName(char *normal)
672d522f475Smrg{
673d522f475Smrg    static VTFontNames data;
674d522f475Smrg    memset(&data, 0, sizeof(data));
675d522f475Smrg    data.f_n = normal;
676d522f475Smrg    return &data;
677d522f475Smrg}
678d522f475Smrg
679d522f475Smrgstatic void
680d522f475Smrgcache_menu_font_name(TScreen * screen, int fontnum, int which, const char *name)
681d522f475Smrg{
682d522f475Smrg    if (name != 0) {
683d522f475Smrg	char *last = screen->menu_font_names[fontnum][which];
684d522f475Smrg	if (last != 0) {
685d522f475Smrg	    if (strcmp(last, name)) {
686d522f475Smrg		free(last);
687d522f475Smrg		TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name));
688d522f475Smrg		screen->menu_font_names[fontnum][which] = x_strdup(name);
689d522f475Smrg	    }
690d522f475Smrg	} else {
691d522f475Smrg	    TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name));
692d522f475Smrg	    screen->menu_font_names[fontnum][which] = x_strdup(name);
693d522f475Smrg	}
694d522f475Smrg    }
695d522f475Smrg}
696d522f475Smrg
697d522f475Smrg/*
698d522f475Smrg * Open the given font and verify that it is non-empty.  Return a null on
699d522f475Smrg * failure.
700d522f475Smrg */
701d522f475SmrgBool
702956cc18dSsnjxtermOpenFont(XtermWidget xw,
703956cc18dSsnj	      const char *name,
704956cc18dSsnj	      XTermFonts * result,
705956cc18dSsnj	      fontWarningTypes warn,
706956cc18dSsnj	      Bool force)
707d522f475Smrg{
708d522f475Smrg    Bool code = False;
709d522f475Smrg    TScreen *screen = TScreenOf(xw);
710d522f475Smrg
711956cc18dSsnj    if (name != 0) {
712956cc18dSsnj	if ((result->fs = XLoadQueryFont(screen->display, name)) != 0) {
713956cc18dSsnj	    code = True;
714956cc18dSsnj	    if (EmptyFont(result->fs)) {
715956cc18dSsnj		result = xtermCloseFont(xw, result);
716956cc18dSsnj		code = False;
717956cc18dSsnj	    } else {
718956cc18dSsnj		result->fn = x_strdup(name);
719956cc18dSsnj	    }
720956cc18dSsnj	} else if (strcmp(name, DEFFONT)) {
721956cc18dSsnj	    if (warn <= xw->misc.fontWarnings
722956cc18dSsnj#if OPT_RENDERFONT
723956cc18dSsnj		&& !UsingRenderFont(xw)
724956cc18dSsnj#endif
725956cc18dSsnj		) {
726956cc18dSsnj		TRACE(("OOPS: cannot load font %s\n", name));
727956cc18dSsnj		fprintf(stderr, "%s: cannot load font %s\n", ProgramName, name);
728956cc18dSsnj	    } else {
729956cc18dSsnj		TRACE(("xtermOpenFont: cannot load font %s\n", name));
730956cc18dSsnj	    }
731956cc18dSsnj	    if (force) {
732956cc18dSsnj		code = xtermOpenFont(xw, DEFFONT, result, fwAlways, True);
733956cc18dSsnj	    }
734d522f475Smrg	}
735d522f475Smrg    }
736d522f475Smrg    return code;
737d522f475Smrg}
738d522f475Smrg
739d522f475Smrg/*
740956cc18dSsnj * Close the font and free the font info.
741d522f475Smrg */
742d522f475SmrgXTermFonts *
743d522f475SmrgxtermCloseFont(XtermWidget xw, XTermFonts * fnt)
744d522f475Smrg{
745d522f475Smrg    if (fnt != 0 && fnt->fs != 0) {
746d522f475Smrg	TScreen *screen = TScreenOf(xw);
747d522f475Smrg
748d522f475Smrg	clrCgsFonts(xw, WhichVWin(screen), fnt);
749d522f475Smrg	XFreeFont(screen->display, fnt->fs);
750d522f475Smrg	xtermFreeFontInfo(fnt);
751d522f475Smrg    }
752d522f475Smrg    return 0;
753d522f475Smrg}
754d522f475Smrg
755d522f475Smrg/*
756d522f475Smrg * Close the listed fonts, noting that some may use copies of the pointer.
757d522f475Smrg */
758d522f475Smrgvoid
759d522f475SmrgxtermCloseFonts(XtermWidget xw, XTermFonts * fnts)
760d522f475Smrg{
761d522f475Smrg    int j, k;
762d522f475Smrg
763d522f475Smrg    for (j = 0; j < fMAX; ++j) {
764d522f475Smrg	/*
765d522f475Smrg	 * Need to save the pointer since xtermCloseFont zeroes it
766d522f475Smrg	 */
767d522f475Smrg	XFontStruct *thisFont = fnts[j].fs;
768d522f475Smrg	if (thisFont != 0) {
769d522f475Smrg	    xtermCloseFont(xw, &fnts[j]);
770d522f475Smrg	    for (k = j + 1; k < fMAX; ++k) {
771d522f475Smrg		if (thisFont == fnts[k].fs)
772d522f475Smrg		    xtermFreeFontInfo(&fnts[k]);
773d522f475Smrg	    }
774d522f475Smrg	}
775d522f475Smrg    }
776d522f475Smrg}
777d522f475Smrg
778d522f475Smrg/*
779d522f475Smrg * Make a copy of the source, assuming the XFontStruct's to be unique, but
780d522f475Smrg * ensuring that the names are reallocated to simplify freeing.
781d522f475Smrg */
782d522f475Smrgvoid
783d522f475SmrgxtermCopyFontInfo(XTermFonts * target, XTermFonts * source)
784d522f475Smrg{
785d522f475Smrg    xtermFreeFontInfo(target);
786d522f475Smrg    target->chrset = source->chrset;
787d522f475Smrg    target->flags = source->flags;
788d522f475Smrg    target->fn = x_strdup(source->fn);
789d522f475Smrg    target->fs = source->fs;
790d522f475Smrg}
791d522f475Smrg
792d522f475Smrgvoid
793d522f475SmrgxtermFreeFontInfo(XTermFonts * target)
794d522f475Smrg{
795d522f475Smrg    target->chrset = 0;
796d522f475Smrg    target->flags = 0;
797d522f475Smrg    if (target->fn != 0) {
798d522f475Smrg	free(target->fn);
799d522f475Smrg	target->fn = 0;
800d522f475Smrg    }
801d522f475Smrg    target->fs = 0;
802d522f475Smrg}
803d522f475Smrg
804d522f475Smrgint
805d522f475SmrgxtermLoadFont(XtermWidget xw,
806d522f475Smrg	      const VTFontNames * fonts,
807d522f475Smrg	      Bool doresize,
808d522f475Smrg	      int fontnum)
809d522f475Smrg{
810956cc18dSsnj    TScreen *screen = TScreenOf(xw);
811d522f475Smrg    VTwin *win = WhichVWin(screen);
812d522f475Smrg
813d522f475Smrg    VTFontNames myfonts;
814d522f475Smrg    FontNameProperties *fp;
815d522f475Smrg    XTermFonts fnts[fMAX];
816d522f475Smrg    Pixel new_normal;
817d522f475Smrg    Pixel new_revers;
818d522f475Smrg    char *tmpname = NULL;
819d522f475Smrg    char normal[MAX_FONTNAME];
820956cc18dSsnj    Boolean proportional = False;
821956cc18dSsnj    fontWarningTypes warn[fMAX];
822956cc18dSsnj    int j;
823d522f475Smrg
824d522f475Smrg    memset(&myfonts, 0, sizeof(myfonts));
825d522f475Smrg    memset(fnts, 0, sizeof(fnts));
826d522f475Smrg
827d522f475Smrg    if (fonts != 0)
828d522f475Smrg	myfonts = *fonts;
829956cc18dSsnj    if (!check_fontname(myfonts.f_n))
830d522f475Smrg	return 0;
831d522f475Smrg
832956cc18dSsnj    /*
833956cc18dSsnj     * Check the font names against the resource values, to see which were
834956cc18dSsnj     * derived in a previous call.  If so, we'll only warn about those if
835956cc18dSsnj     * the warning level is set to "always".
836956cc18dSsnj     */
837956cc18dSsnj    for (j = 0; j < fMAX; ++j) {
838956cc18dSsnj	warn[j] = fwAlways;
839956cc18dSsnj    }
840956cc18dSsnj#define CmpResource(field, index) \
841956cc18dSsnj    if (same_font_name(screen->menu_font_names[fontnum][index], myfonts.field)) \
842956cc18dSsnj	warn[index] = fwResource
843956cc18dSsnj
844956cc18dSsnj    CmpResource(f_n, fNorm);
845956cc18dSsnj    if (fontnum == fontMenu_default) {
846956cc18dSsnj	CmpResource(f_b, fBold);
847956cc18dSsnj#if OPT_WIDE_CHARS
848956cc18dSsnj	CmpResource(f_b, fWide);
849956cc18dSsnj	CmpResource(f_b, fWBold);
850956cc18dSsnj#endif
851956cc18dSsnj    }
852956cc18dSsnj
853d522f475Smrg    if (fontnum == fontMenu_fontescape
854d522f475Smrg	&& myfonts.f_n != screen->MenuFontName(fontnum)) {
855d522f475Smrg	if ((tmpname = x_strdup(myfonts.f_n)) == 0)
856d522f475Smrg	    return 0;
857d522f475Smrg    }
858d522f475Smrg
859d522f475Smrg    TRACE(("Begin Cgs - xtermLoadFont(%s)\n", myfonts.f_n));
860d522f475Smrg    releaseWindowGCs(xw, win);
861d522f475Smrg
862956cc18dSsnj#define DbgResource(name, field, index) \
863956cc18dSsnj    TRACE(("xtermLoadFont #%d "name" %s%s\n", \
864956cc18dSsnj    	   fontnum, \
865956cc18dSsnj	   (warn[index] == fwResource) ? "*" : " ", \
866956cc18dSsnj	   NonNull(myfonts.field)));
867956cc18dSsnj    DbgResource("normal", f_n, fNorm);
868956cc18dSsnj    DbgResource("bold  ", f_b, fBold);
869d522f475Smrg#if OPT_WIDE_CHARS
870956cc18dSsnj    DbgResource("wide  ", f_w, fWide);
871956cc18dSsnj    DbgResource("w/bold", f_wb, fWBold);
872d522f475Smrg#endif
873d522f475Smrg
874956cc18dSsnj    if (!xtermOpenFont(xw, myfonts.f_n, &fnts[fNorm], warn[fNorm], True))
875d522f475Smrg	goto bad;
876d522f475Smrg
877d522f475Smrg    strcpy(normal, myfonts.f_n);
878956cc18dSsnj    if (!check_fontname(myfonts.f_b)) {
879956cc18dSsnj	warn[fBold] = fwAlways;
880d522f475Smrg	fp = get_font_name_props(screen->display, fnts[fNorm].fs, normal);
881d522f475Smrg	if (fp != 0) {
882d522f475Smrg	    myfonts.f_b = bold_font_name(fp, fp->average_width);
883956cc18dSsnj	    if (!xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], fwAlways, False)) {
884d522f475Smrg		myfonts.f_b = bold_font_name(fp, -1);
885956cc18dSsnj		xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], fwAlways, False);
886d522f475Smrg	    }
887d522f475Smrg	    TRACE(("...derived bold %s\n", NonNull(myfonts.f_b)));
888d522f475Smrg	}
889d522f475Smrg	if (fp == 0 || fnts[fBold].fs == 0) {
890d522f475Smrg	    xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]);
891d522f475Smrg	    TRACE(("...cannot load a matching bold font\n"));
892d522f475Smrg	} else if (same_font_size(xw, fnts[fNorm].fs, fnts[fBold].fs)
893d522f475Smrg		   && got_bold_font(screen->display, fnts[fBold].fs, myfonts.f_b)) {
894d522f475Smrg	    TRACE(("...got a matching bold font\n"));
895d522f475Smrg	    cache_menu_font_name(screen, fontnum, fBold, myfonts.f_b);
896d522f475Smrg	} else {
897d522f475Smrg	    xtermCloseFont(xw, &fnts[fBold]);
898d522f475Smrg	    fnts[fBold] = fnts[fNorm];
899d522f475Smrg	    TRACE(("...did not get a matching bold font\n"));
900d522f475Smrg	}
901956cc18dSsnj    } else if (!xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], warn[fBold], False)) {
902d522f475Smrg	xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]);
903956cc18dSsnj	warn[fBold] = fwAlways;
904d522f475Smrg	TRACE(("...cannot load bold font %s\n", NonNull(myfonts.f_b)));
905d522f475Smrg    } else {
906d522f475Smrg	cache_menu_font_name(screen, fontnum, fBold, myfonts.f_b);
907d522f475Smrg    }
908d522f475Smrg
909d522f475Smrg    /*
910d522f475Smrg     * If there is no widefont specified, fake it by doubling AVERAGE_WIDTH
911d522f475Smrg     * of normal fonts XLFD, and asking for it.  This plucks out 18x18ja
912d522f475Smrg     * and 12x13ja as the corresponding fonts for 9x18 and 6x13.
913d522f475Smrg     */
914d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
915d522f475Smrg	Bool derived;
916d522f475Smrg	char bold[MAX_FONTNAME];
917d522f475Smrg
918956cc18dSsnj	if (check_fontname(myfonts.f_w)) {
919d522f475Smrg	    cache_menu_font_name(screen, fontnum, fWide, myfonts.f_w);
920d522f475Smrg	} else if (!is_double_width_font(fnts[fNorm].fs)) {
921d522f475Smrg	    fp = get_font_name_props(screen->display, fnts[fNorm].fs, normal);
922d522f475Smrg	    if (fp != 0) {
923d522f475Smrg		myfonts.f_w = wide_font_name(fp);
924956cc18dSsnj		warn[fWide] = fwAlways;
925d522f475Smrg		TRACE(("...derived wide %s\n", NonNull(myfonts.f_w)));
926d522f475Smrg		cache_menu_font_name(screen, fontnum, fWide, myfonts.f_w);
927d522f475Smrg	    }
928d522f475Smrg	}
929d522f475Smrg
930956cc18dSsnj	if (check_fontname(myfonts.f_w)) {
931956cc18dSsnj	    (void) xtermOpenFont(xw, myfonts.f_w, &fnts[fWide], warn[fWide], False);
932d522f475Smrg	} else {
933d522f475Smrg	    xtermCopyFontInfo(&fnts[fWide], &fnts[fNorm]);
934956cc18dSsnj	    warn[fWide] = fwAlways;
935d522f475Smrg	}
936d522f475Smrg
937d522f475Smrg	derived = False;
938956cc18dSsnj	if (!check_fontname(myfonts.f_wb)) {
939d522f475Smrg	    fp = get_font_name_props(screen->display, fnts[fBold].fs, bold);
940d522f475Smrg	    if (fp != 0) {
941d522f475Smrg		myfonts.f_wb = widebold_font_name(fp);
942956cc18dSsnj		warn[fWBold] = fwAlways;
943d522f475Smrg		derived = True;
944d522f475Smrg	    }
945d522f475Smrg	}
946d522f475Smrg
947956cc18dSsnj	if (check_fontname(myfonts.f_wb)) {
948d522f475Smrg
949956cc18dSsnj	    xtermOpenFont(xw, myfonts.f_wb, &fnts[fWBold], warn[fWBold], False);
950d522f475Smrg
951d522f475Smrg	    if (derived
952d522f475Smrg		&& !compatibleWideCounts(fnts[fWide].fs, fnts[fWBold].fs)) {
953d522f475Smrg		xtermCloseFont(xw, &fnts[fWBold]);
954d522f475Smrg	    }
955d522f475Smrg	    if (fnts[fWBold].fs == 0) {
956d522f475Smrg		myfonts.f_wb = myfonts.f_w;
957956cc18dSsnj		warn[fWBold] = fwAlways;
958d522f475Smrg		xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
959d522f475Smrg		TRACE(("...cannot load wide-bold, use wide %s\n", NonNull(myfonts.f_w)));
960d522f475Smrg	    } else {
961d522f475Smrg		TRACE(("...%s wide/bold %s\n",
962d522f475Smrg		       derived ? "derived" : "given",
963d522f475Smrg		       NonNull(myfonts.f_wb)));
964d522f475Smrg		cache_menu_font_name(screen, fontnum, fWBold, myfonts.f_wb);
965d522f475Smrg	    }
966d522f475Smrg	} else if (is_double_width_font(fnts[fBold].fs)) {
967d522f475Smrg	    xtermCopyFontInfo(&fnts[fWBold], &fnts[fBold]);
968956cc18dSsnj	    warn[fWBold] = fwAlways;
969d522f475Smrg	    TRACE(("...bold font is double-width, use it %s\n", NonNull(myfonts.f_b)));
970d522f475Smrg	} else {
971d522f475Smrg	    xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
972956cc18dSsnj	    warn[fWBold] = fwAlways;
973d522f475Smrg	    TRACE(("...cannot load wide bold font, use wide %s\n", NonNull(myfonts.f_w)));
974d522f475Smrg	}
975d522f475Smrg
976d522f475Smrg	if (EmptyFont(fnts[fWBold].fs))
977d522f475Smrg	    goto bad;		/* can't use a 0-sized font */
978d522f475Smrg    });
979d522f475Smrg
980d522f475Smrg    /*
981d522f475Smrg     * Most of the time this call to load the font will succeed, even if
982d522f475Smrg     * there is no wide font :  the X server doubles the width of the
983d522f475Smrg     * normal font, or similar.
984d522f475Smrg     *
985d522f475Smrg     * But if it did fail for some reason, then nevermind.
986d522f475Smrg     */
987d522f475Smrg    if (EmptyFont(fnts[fBold].fs))
988d522f475Smrg	goto bad;		/* can't use a 0-sized font */
989d522f475Smrg
990d522f475Smrg    if (!same_font_size(xw, fnts[fNorm].fs, fnts[fBold].fs)
991d522f475Smrg	&& (is_fixed_font(fnts[fNorm].fs) && is_fixed_font(fnts[fBold].fs))) {
992d522f475Smrg	TRACE(("...ignoring mismatched normal/bold fonts\n"));
993d522f475Smrg	xtermCloseFont(xw, &fnts[fBold]);
994d522f475Smrg	xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]);
995d522f475Smrg    }
996d522f475Smrg
997d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
998d522f475Smrg	if (fnts[fWide].fs != 0
999d522f475Smrg	    && fnts[fWBold].fs != 0
1000d522f475Smrg	    && !same_font_size(xw, fnts[fWide].fs, fnts[fWBold].fs)
1001d522f475Smrg	    && (is_fixed_font(fnts[fWide].fs) && is_fixed_font(fnts[fWBold].fs))) {
1002d522f475Smrg	    TRACE(("...ignoring mismatched normal/bold wide fonts\n"));
1003d522f475Smrg	    xtermCloseFont(xw, &fnts[fWBold]);
1004d522f475Smrg	    xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
1005d522f475Smrg	}
1006d522f475Smrg    });
1007d522f475Smrg
1008d522f475Smrg    /*
1009d522f475Smrg     * Normal/bold fonts should be the same width.  Also, the min/max
1010d522f475Smrg     * values should be the same.
1011d522f475Smrg     */
1012d522f475Smrg    if (!is_fixed_font(fnts[fNorm].fs)
1013d522f475Smrg	|| !is_fixed_font(fnts[fBold].fs)
1014d522f475Smrg	|| fnts[fNorm].fs->max_bounds.width != fnts[fBold].fs->max_bounds.width) {
1015d522f475Smrg	TRACE(("Proportional font! normal %d/%d, bold %d/%d\n",
1016d522f475Smrg	       fnts[fNorm].fs->min_bounds.width,
1017d522f475Smrg	       fnts[fNorm].fs->max_bounds.width,
1018d522f475Smrg	       fnts[fBold].fs->min_bounds.width,
1019d522f475Smrg	       fnts[fBold].fs->max_bounds.width));
1020d522f475Smrg	proportional = True;
1021d522f475Smrg    }
1022d522f475Smrg
1023d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
1024d522f475Smrg	if (fnts[fWide].fs != 0
1025d522f475Smrg	    && fnts[fWBold].fs != 0
1026d522f475Smrg	    && (!is_fixed_font(fnts[fWide].fs)
1027d522f475Smrg		|| !is_fixed_font(fnts[fWBold].fs)
1028d522f475Smrg		|| fnts[fWide].fs->max_bounds.width != fnts[fWBold].fs->max_bounds.width)) {
1029d522f475Smrg	    TRACE(("Proportional font! wide %d/%d, wide bold %d/%d\n",
1030d522f475Smrg		   fnts[fWide].fs->min_bounds.width,
1031d522f475Smrg		   fnts[fWide].fs->max_bounds.width,
1032d522f475Smrg		   fnts[fWBold].fs->min_bounds.width,
1033d522f475Smrg		   fnts[fWBold].fs->max_bounds.width));
1034d522f475Smrg	    proportional = True;
1035d522f475Smrg	}
1036d522f475Smrg    });
1037d522f475Smrg
1038d522f475Smrg    /* TODO : enforce that the width of the wide font is 2* the width
1039d522f475Smrg       of the narrow font */
1040d522f475Smrg
1041d522f475Smrg    /*
1042d522f475Smrg     * If we're switching fonts, free the old ones.  Otherwise we'll leak
1043d522f475Smrg     * the memory that is associated with the old fonts.  The
1044d522f475Smrg     * XLoadQueryFont call allocates a new XFontStruct.
1045d522f475Smrg     */
1046d522f475Smrg    xtermCloseFonts(xw, screen->fnts);
1047d522f475Smrg
1048d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fNorm]), &fnts[fNorm]);
1049d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fBold]), &fnts[fBold]);
1050d522f475Smrg#if OPT_WIDE_CHARS
1051d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fWide]), &fnts[fWide]);
1052d522f475Smrg    if (fnts[fWBold].fs == NULL)
1053d522f475Smrg	xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
1054d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fWBold]), &fnts[fWBold]);
1055d522f475Smrg#endif
1056d522f475Smrg
1057d522f475Smrg    new_normal = getXtermForeground(xw, xw->flags, xw->cur_foreground);
1058d522f475Smrg    new_revers = getXtermBackground(xw, xw->flags, xw->cur_background);
1059d522f475Smrg
1060d522f475Smrg    setCgsFore(xw, win, gcNorm, new_normal);
1061d522f475Smrg    setCgsBack(xw, win, gcNorm, new_revers);
1062d522f475Smrg    setCgsFont(xw, win, gcNorm, &(screen->fnts[fNorm]));
1063d522f475Smrg
1064d522f475Smrg    copyCgs(xw, win, gcBold, gcNorm);
1065d522f475Smrg    setCgsFont(xw, win, gcBold, &(screen->fnts[fBold]));
1066d522f475Smrg
1067d522f475Smrg    setCgsFore(xw, win, gcNormReverse, new_revers);
1068d522f475Smrg    setCgsBack(xw, win, gcNormReverse, new_normal);
1069d522f475Smrg    setCgsFont(xw, win, gcNormReverse, &(screen->fnts[fNorm]));
1070d522f475Smrg
1071d522f475Smrg    copyCgs(xw, win, gcBoldReverse, gcNormReverse);
1072d522f475Smrg    setCgsFont(xw, win, gcBoldReverse, &(screen->fnts[fBold]));
1073d522f475Smrg
1074d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
1075d522f475Smrg	if (screen->fnts[fWide].fs != 0
1076d522f475Smrg	    && screen->fnts[fWBold].fs != 0) {
1077d522f475Smrg	    setCgsFore(xw, win, gcWide, new_normal);
1078d522f475Smrg	    setCgsBack(xw, win, gcWide, new_revers);
1079d522f475Smrg	    setCgsFont(xw, win, gcWide, &(screen->fnts[fWide]));
1080d522f475Smrg
1081d522f475Smrg	    copyCgs(xw, win, gcWBold, gcWide);
1082d522f475Smrg	    setCgsFont(xw, win, gcWBold, &(screen->fnts[fWBold]));
1083d522f475Smrg
1084d522f475Smrg	    setCgsFore(xw, win, gcWideReverse, new_revers);
1085d522f475Smrg	    setCgsBack(xw, win, gcWideReverse, new_normal);
1086d522f475Smrg	    setCgsFont(xw, win, gcWideReverse, &(screen->fnts[fWide]));
1087d522f475Smrg
1088d522f475Smrg	    copyCgs(xw, win, gcWBoldReverse, gcWideReverse);
1089d522f475Smrg	    setCgsFont(xw, win, gcWBoldReverse, &(screen->fnts[fWBold]));
1090d522f475Smrg	}
1091d522f475Smrg    });
1092d522f475Smrg
1093d522f475Smrg    screen->fnt_prop = proportional;
1094d522f475Smrg    screen->fnt_boxes = True;
1095d522f475Smrg
1096d522f475Smrg#if OPT_BOX_CHARS
1097d522f475Smrg    /*
1098d522f475Smrg     * Xterm uses character positions 1-31 of a font for the line-drawing
1099d522f475Smrg     * characters.  Check that they are all present.  The null character
1100d522f475Smrg     * (0) is special, and is not used.
1101d522f475Smrg     */
1102d522f475Smrg#if OPT_RENDERFONT
1103d522f475Smrg    if (UsingRenderFont(xw)) {
1104d522f475Smrg	/*
1105d522f475Smrg	 * FIXME: we shouldn't even be here if we're using Xft.
1106d522f475Smrg	 */
1107d522f475Smrg	screen->fnt_boxes = False;
1108d522f475Smrg	TRACE(("assume Xft missing line-drawing chars\n"));
1109d522f475Smrg    } else
1110d522f475Smrg#endif
1111d522f475Smrg    {
1112d522f475Smrg	unsigned ch;
1113d522f475Smrg
1114d522f475Smrg	for (ch = 1; ch < 32; ch++) {
1115d522f475Smrg	    unsigned n = ch;
1116d522f475Smrg#if OPT_WIDE_CHARS
1117d522f475Smrg	    if (screen->utf8_mode || screen->unicode_font) {
1118d522f475Smrg		n = dec2ucs(ch);
1119d522f475Smrg		if (n == UCS_REPL)
1120d522f475Smrg		    continue;
1121d522f475Smrg	    }
1122d522f475Smrg#endif
1123956cc18dSsnj	    if (IsXtermMissingChar(screen, n, &fnts[fNorm])) {
1124d522f475Smrg		TRACE(("missing normal char #%d\n", n));
1125d522f475Smrg		screen->fnt_boxes = False;
1126d522f475Smrg		break;
1127d522f475Smrg	    }
1128956cc18dSsnj	    if (IsXtermMissingChar(screen, n, &fnts[fBold])) {
1129d522f475Smrg		TRACE(("missing bold char #%d\n", n));
1130d522f475Smrg		screen->fnt_boxes = False;
1131d522f475Smrg		break;
1132d522f475Smrg	    }
1133d522f475Smrg	}
1134d522f475Smrg    }
1135d522f475Smrg    TRACE(("Will %suse internal line-drawing characters\n",
1136d522f475Smrg	   screen->fnt_boxes ? "not " : ""));
1137d522f475Smrg#endif
1138d522f475Smrg
1139d522f475Smrg    if (screen->always_bold_mode) {
1140d522f475Smrg	screen->enbolden = screen->bold_mode;
1141d522f475Smrg    } else {
1142d522f475Smrg	screen->enbolden = screen->bold_mode
1143d522f475Smrg	    && ((fnts[fNorm].fs == fnts[fBold].fs)
1144d522f475Smrg		|| same_font_name(normal, myfonts.f_b));
1145d522f475Smrg    }
1146d522f475Smrg    TRACE(("Will %suse 1-pixel offset/overstrike to simulate bold\n",
1147d522f475Smrg	   screen->enbolden ? "" : "not "));
1148d522f475Smrg
1149d522f475Smrg    set_menu_font(False);
1150d522f475Smrg    screen->menu_font_number = fontnum;
1151d522f475Smrg    set_menu_font(True);
1152d522f475Smrg    if (tmpname) {		/* if setting escape or sel */
1153d522f475Smrg	if (screen->MenuFontName(fontnum))
1154d522f475Smrg	    free(screen->MenuFontName(fontnum));
1155d522f475Smrg	screen->MenuFontName(fontnum) = tmpname;
1156d522f475Smrg	if (fontnum == fontMenu_fontescape) {
1157d522f475Smrg	    SetItemSensitivity(fontMenuEntries[fontMenu_fontescape].widget,
1158d522f475Smrg			       True);
1159d522f475Smrg	}
1160d522f475Smrg#if OPT_SHIFT_FONTS
1161d522f475Smrg	screen->menu_font_sizes[fontnum] = FontSize(fnts[fNorm].fs);
1162d522f475Smrg#endif
1163d522f475Smrg    }
1164d522f475Smrg    set_cursor_gcs(xw);
1165d522f475Smrg    xtermUpdateFontInfo(xw, doresize);
1166d522f475Smrg    TRACE(("Success Cgs - xtermLoadFont\n"));
1167d522f475Smrg    return 1;
1168d522f475Smrg
1169d522f475Smrg  bad:
1170d522f475Smrg    if (tmpname)
1171d522f475Smrg	free(tmpname);
1172d522f475Smrg    releaseWindowGCs(xw, win);
1173d522f475Smrg
1174d522f475Smrg    xtermCloseFonts(xw, fnts);
1175d522f475Smrg    TRACE(("Fail Cgs - xtermLoadFont\n"));
1176d522f475Smrg    return 0;
1177d522f475Smrg}
1178d522f475Smrg
1179d522f475Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
1180d522f475Smrg/*
1181d522f475Smrg * Collect font-names that we can modify with the load-vt-fonts() action.
1182d522f475Smrg */
1183d522f475Smrgtypedef struct {
1184d522f475Smrg    VTFontNames default_font;
1185d522f475Smrg    char *menu_font_names[fontMenu_lastBuiltin + 1][fMAX];
1186d522f475Smrg} SubResourceRec;
1187d522f475Smrg
1188d522f475Smrg#define MERGE_SUBFONT(src,dst,name) \
1189d522f475Smrg	if (dst.name == 0) { \
1190d522f475Smrg	    TRACE(("MERGE_SUBFONT " #dst "." #name " merge %s\n", NonNull(src.name))); \
1191d522f475Smrg	    dst.name = src.name; \
1192d522f475Smrg	} else { \
1193d522f475Smrg	    TRACE(("MERGE_SUBFONT " #dst "." #name " found %s\n", NonNull(dst.name))); \
1194d522f475Smrg	}
1195d522f475Smrg
1196d522f475Smrg#define COPY_MENU_FONTS(src,dst) \
1197d522f475Smrg	TRACE(("COPY_MENU_FONTS " #src " to " #dst "\n")); \
1198d522f475Smrg	for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \
1199d522f475Smrg	    for (m = 0; m < fMAX; ++m) { \
1200d522f475Smrg		dst.menu_font_names[n][m] = src.menu_font_names[n][m]; \
1201d522f475Smrg	    } \
1202d522f475Smrg	}
1203d522f475Smrg
1204d522f475Smrg/*
1205d522f475Smrg * Load the "VT" font names from the given subresource name/class.  These
1206d522f475Smrg * correspond to the VT100 resources.
1207d522f475Smrg */
1208d522f475Smrgstatic Bool
1209956cc18dSsnjxtermLoadVTFonts(XtermWidget xw, char *myName, char *myClass)
1210d522f475Smrg{
1211d522f475Smrg    static Bool initialized = False;
1212d522f475Smrg    static SubResourceRec original, referenceRec, subresourceRec;
1213d522f475Smrg
1214d522f475Smrg    /*
1215d522f475Smrg     * These are duplicates of the VT100 font resources, but with a special
1216d522f475Smrg     * application/classname passed in to distinguish them.
1217d522f475Smrg     */
1218d522f475Smrg    static XtResource font_resources[] =
1219d522f475Smrg    {
1220d522f475Smrg	Sres(XtNfont, XtCFont, default_font.f_n, DEFFONT),
1221d522f475Smrg	Sres(XtNboldFont, XtCBoldFont, default_font.f_b, DEFBOLDFONT),
1222d522f475Smrg#if OPT_WIDE_CHARS
1223d522f475Smrg	Sres(XtNwideFont, XtCWideFont, default_font.f_w, DEFWIDEFONT),
1224d522f475Smrg	Sres(XtNwideBoldFont, XtCWideBoldFont, default_font.f_wb, DEFWIDEBOLDFONT),
1225d522f475Smrg#endif
1226d522f475Smrg	Sres(XtNfont1, XtCFont1, MenuFontName(fontMenu_font1), NULL),
1227d522f475Smrg	Sres(XtNfont2, XtCFont2, MenuFontName(fontMenu_font2), NULL),
1228d522f475Smrg	Sres(XtNfont3, XtCFont3, MenuFontName(fontMenu_font3), NULL),
1229d522f475Smrg	Sres(XtNfont4, XtCFont4, MenuFontName(fontMenu_font4), NULL),
1230d522f475Smrg	Sres(XtNfont5, XtCFont5, MenuFontName(fontMenu_font5), NULL),
1231d522f475Smrg	Sres(XtNfont6, XtCFont6, MenuFontName(fontMenu_font6), NULL),
1232d522f475Smrg    };
1233d522f475Smrg    Cardinal n, m;
1234d522f475Smrg    Bool status = True;
1235956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1236d522f475Smrg
1237d522f475Smrg    if (!initialized) {
1238d522f475Smrg
1239d522f475Smrg	initialized = True;
1240d522f475Smrg	TRACE(("xtermLoadVTFonts saving original\n"));
1241956cc18dSsnj	original.default_font = xw->misc.default_font;
1242956cc18dSsnj	COPY_MENU_FONTS(xw->screen, original);
1243d522f475Smrg    }
1244d522f475Smrg
1245d522f475Smrg    if (myName == 0 || *myName == 0) {
1246d522f475Smrg	TRACE(("xtermLoadVTFonts restoring original\n"));
1247956cc18dSsnj	xw->misc.default_font = original.default_font;
1248956cc18dSsnj	COPY_MENU_FONTS(original, xw->screen);
1249d522f475Smrg	for (n = 0; n < XtNumber(original.menu_font_names); ++n)
1250956cc18dSsnj	    screen->MenuFontName(n) = original.MenuFontName(n);
1251d522f475Smrg    } else {
1252d522f475Smrg	TRACE(("xtermLoadVTFonts(%s, %s)\n", myName, myClass));
1253d522f475Smrg
1254d522f475Smrg	memset(&subresourceRec, 0, sizeof(subresourceRec));
1255956cc18dSsnj	XtGetSubresources((Widget) xw, (XtPointer) &subresourceRec,
1256d522f475Smrg			  myName, myClass,
1257d522f475Smrg			  font_resources,
1258d522f475Smrg			  (Cardinal) XtNumber(font_resources),
1259d522f475Smrg			  NULL, (Cardinal) 0);
1260d522f475Smrg
1261d522f475Smrg	if (memcmp(&referenceRec, &subresourceRec, sizeof(referenceRec))) {
1262d522f475Smrg
1263d522f475Smrg	    /*
1264d522f475Smrg	     * If a particular resource value was not found, use the original.
1265d522f475Smrg	     */
1266956cc18dSsnj	    MERGE_SUBFONT(xw->misc, subresourceRec, default_font.f_n);
1267956cc18dSsnj	    MERGE_SUBFONT(xw->misc, subresourceRec, default_font.f_b);
1268d522f475Smrg#if OPT_WIDE_CHARS
1269956cc18dSsnj	    MERGE_SUBFONT(xw->misc, subresourceRec, default_font.f_w);
1270956cc18dSsnj	    MERGE_SUBFONT(xw->misc, subresourceRec, default_font.f_wb);
1271d522f475Smrg#endif
1272d522f475Smrg	    for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n)
1273956cc18dSsnj		MERGE_SUBFONT(xw->screen, subresourceRec, MenuFontName(n));
1274d522f475Smrg
1275d522f475Smrg	    /*
1276d522f475Smrg	     * Finally, copy the subresource data to the widget.
1277d522f475Smrg	     */
1278956cc18dSsnj	    xw->misc.default_font = subresourceRec.default_font;
1279956cc18dSsnj	    COPY_MENU_FONTS(subresourceRec, xw->screen);
1280956cc18dSsnj	    screen->MenuFontName(fontMenu_default) = xw->misc.default_font.f_n;
1281956cc18dSsnj	    screen->menu_font_names[0][fBold] = xw->misc.default_font.f_b;
1282d522f475Smrg#if OPT_WIDE_CHARS
1283956cc18dSsnj	    screen->menu_font_names[0][fWide] = xw->misc.default_font.f_w;
1284956cc18dSsnj	    screen->menu_font_names[0][fWBold] = xw->misc.default_font.f_wb;
1285d522f475Smrg#endif
1286d522f475Smrg	} else {
1287d522f475Smrg	    TRACE(("...no resources found\n"));
1288d522f475Smrg	    status = False;
1289d522f475Smrg	}
1290d522f475Smrg    }
1291d522f475Smrg    return status;
1292d522f475Smrg}
1293d522f475Smrg
1294d522f475Smrg#if OPT_WIDE_CHARS
1295d522f475Smrgstatic Bool
1296d522f475SmrgisWideFont(XFontStruct * fp, char *tag, Bool nullOk)
1297d522f475Smrg{
1298d522f475Smrg    Bool result = False;
1299d522f475Smrg
1300d522f475Smrg    (void) tag;
1301d522f475Smrg    if (okFont(fp)) {
1302d522f475Smrg	unsigned count = countGlyphs(fp);
1303d522f475Smrg	TRACE(("isWideFont(%s) found %d cells\n", tag, count));
1304d522f475Smrg	result = (count > 256) ? True : False;
1305d522f475Smrg    } else {
1306d522f475Smrg	result = nullOk;
1307d522f475Smrg    }
1308d522f475Smrg    return result;
1309d522f475Smrg}
1310d522f475Smrg
1311d522f475Smrg/*
1312d522f475Smrg * If the current fonts are not wide, load the UTF8 fonts.
1313d522f475Smrg *
1314d522f475Smrg * Called during initialization (for wide-character mode), the fonts have not
1315d522f475Smrg * been setup, so we pass nullOk=True to isWideFont().
1316d522f475Smrg *
1317d522f475Smrg * Called after initialization, e.g., in response to the UTF-8 menu entry
1318d522f475Smrg * (starting from narrow character mode), it checks if the fonts are not wide.
1319d522f475Smrg */
1320d522f475SmrgBool
1321d522f475SmrgxtermLoadWideFonts(XtermWidget xw, Bool nullOk)
1322d522f475Smrg{
1323956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1324d522f475Smrg    Bool result;
1325d522f475Smrg
1326d522f475Smrg    if (EmptyFont(screen->fnts[fWide].fs)) {
1327d522f475Smrg	result = (isWideFont(screen->fnts[fNorm].fs, "normal", nullOk)
1328d522f475Smrg		  && isWideFont(screen->fnts[fBold].fs, "bold", nullOk));
1329d522f475Smrg    } else {
1330d522f475Smrg	result = (isWideFont(screen->fnts[fWide].fs, "wide", nullOk)
1331d522f475Smrg		  && isWideFont(screen->fnts[fWBold].fs, "wide-bold", nullOk));
1332d522f475Smrg	if (result && !screen->utf8_latin1) {
1333d522f475Smrg	    result = (isWideFont(screen->fnts[fNorm].fs, "normal", nullOk)
1334d522f475Smrg		      && isWideFont(screen->fnts[fBold].fs, "bold", nullOk));
1335d522f475Smrg	}
1336d522f475Smrg    }
1337d522f475Smrg    if (!result) {
1338d522f475Smrg	TRACE(("current fonts are not all wide%s\n", nullOk ? " nullOk" : ""));
1339d522f475Smrg	result = xtermLoadVTFonts(xw, "utf8Fonts", "Utf8Fonts");
1340d522f475Smrg    }
1341d522f475Smrg    TRACE(("xtermLoadWideFonts:%d\n", result));
1342d522f475Smrg    return result;
1343d522f475Smrg}
1344d522f475Smrg#endif /* OPT_WIDE_CHARS */
1345d522f475Smrg
1346d522f475Smrg/*
1347d522f475Smrg * Restore the default fonts, i.e., if we had switched to wide-fonts.
1348d522f475Smrg */
1349d522f475SmrgBool
1350956cc18dSsnjxtermLoadDefaultFonts(XtermWidget xw)
1351d522f475Smrg{
1352d522f475Smrg    Bool result;
1353956cc18dSsnj    result = xtermLoadVTFonts(xw, NULL, NULL);
1354d522f475Smrg    TRACE(("xtermLoadDefaultFonts:%d\n", result));
1355d522f475Smrg    return result;
1356d522f475Smrg}
1357d522f475Smrg#endif /* OPT_LOAD_VTFONTS || OPT_WIDE_CHARS */
1358d522f475Smrg
1359d522f475Smrg#if OPT_LOAD_VTFONTS
1360d522f475Smrgvoid
1361d522f475SmrgHandleLoadVTFonts(Widget w,
1362d522f475Smrg		  XEvent * event GCC_UNUSED,
1363d522f475Smrg		  String * params GCC_UNUSED,
1364d522f475Smrg		  Cardinal *param_count GCC_UNUSED)
1365d522f475Smrg{
1366d522f475Smrg    static char empty[] = "";	/* appease strict compilers */
1367d522f475Smrg
1368956cc18dSsnj    XtermWidget xw;
1369956cc18dSsnj
1370956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
1371956cc18dSsnj	TScreen *screen = TScreenOf(xw);
1372d522f475Smrg	char buf[80];
1373d522f475Smrg	char *myName = (*param_count > 0) ? params[0] : empty;
1374d522f475Smrg	char *convert = (*param_count > 1) ? params[1] : myName;
1375d522f475Smrg	char *myClass = (char *) MyStackAlloc(strlen(convert), buf);
1376d522f475Smrg	int n;
1377d522f475Smrg
1378d522f475Smrg	TRACE(("HandleLoadVTFonts(%d)\n", *param_count));
1379d522f475Smrg	strcpy(myClass, convert);
13802eaa94a1Schristos	if (*param_count == 1)
13812eaa94a1Schristos	    myClass[0] = x_toupper(myClass[0]);
1382d522f475Smrg
1383d522f475Smrg	if (xtermLoadVTFonts(xw, myName, myClass)) {
1384d522f475Smrg	    /*
1385d522f475Smrg	     * When switching fonts, try to preserve the font-menu selection, since
1386d522f475Smrg	     * it is less surprising to do that (if the font-switching can be
1387d522f475Smrg	     * undone) than to switch to "Default".
1388d522f475Smrg	     */
1389956cc18dSsnj	    int font_number = screen->menu_font_number;
1390d522f475Smrg	    if (font_number > fontMenu_lastBuiltin)
1391d522f475Smrg		font_number = fontMenu_lastBuiltin;
1392d522f475Smrg	    for (n = 0; n < NMENUFONTS; ++n)
1393956cc18dSsnj		screen->menu_font_sizes[n] = 0;
1394d522f475Smrg	    SetVTFont(xw, font_number, True,
1395d522f475Smrg		      ((font_number == fontMenu_default)
1396d522f475Smrg		       ? &(xw->misc.default_font)
1397d522f475Smrg		       : NULL));
1398d522f475Smrg	}
1399d522f475Smrg
1400d522f475Smrg	MyStackFree(myClass, buf);
1401d522f475Smrg    }
1402d522f475Smrg}
1403d522f475Smrg#endif /* OPT_LOAD_VTFONTS */
1404d522f475Smrg
1405d522f475Smrg/*
1406d522f475Smrg * Set the limits for the box that outlines the cursor.
1407d522f475Smrg */
1408d522f475Smrgvoid
1409d522f475SmrgxtermSetCursorBox(TScreen * screen)
1410d522f475Smrg{
1411d522f475Smrg    static XPoint VTbox[NBOX];
1412d522f475Smrg    XPoint *vp;
14132eaa94a1Schristos    int fw = FontWidth(screen) - 1;
14142eaa94a1Schristos    int fh = FontHeight(screen) - 1;
14152eaa94a1Schristos    int hh = screen->cursor_underline ? 1 : fh;
1416d522f475Smrg
1417d522f475Smrg    vp = &VTbox[1];
14182eaa94a1Schristos    (vp++)->x = (short) fw;
14192eaa94a1Schristos    (vp++)->y = (short) hh;
14202eaa94a1Schristos    (vp++)->x = (short) -fw;
14212eaa94a1Schristos    vp->y = (short) -hh;
14222eaa94a1Schristos
1423d522f475Smrg    screen->box = VTbox;
1424d522f475Smrg}
1425d522f475Smrg
1426d522f475Smrg#define CACHE_XFT(dst,src) if (src != 0) {\
1427956cc18dSsnj	    checkXft(xw, &(dst[fontnum]), src);\
1428956cc18dSsnj	    TRACE(("Xft metrics %s[%d] = %d (%d,%d) advance %d, actual %d%s\n",\
1429d522f475Smrg		#dst,\
1430d522f475Smrg	    	fontnum,\
1431d522f475Smrg		src->height,\
1432d522f475Smrg		src->ascent,\
1433d522f475Smrg		src->descent,\
1434956cc18dSsnj		src->max_advance_width,\
1435956cc18dSsnj		dst[fontnum].map.min_width,\
1436956cc18dSsnj		dst[fontnum].map.mixed ? " mixed" : ""));\
1437d522f475Smrg	}
1438d522f475Smrg
1439d522f475Smrg#if OPT_RENDERFONT
1440956cc18dSsnj
1441956cc18dSsnjstatic void
1442956cc18dSsnjcheckXft(XtermWidget xw, XTermXftFonts * data, XftFont * xft)
1443956cc18dSsnj{
1444956cc18dSsnj    FcChar32 c;
1445956cc18dSsnj    Dimension width = 0;
1446956cc18dSsnj
1447956cc18dSsnj    data->font = xft;
1448956cc18dSsnj    data->map.min_width = 0;
1449956cc18dSsnj    data->map.max_width = (Dimension) xft->max_advance_width;
1450956cc18dSsnj
1451956cc18dSsnj    for (c = 32; c < 256; ++c) {
1452956cc18dSsnj	if (FcCharSetHasChar(xft->charset, c)) {
1453956cc18dSsnj	    XGlyphInfo extents;
1454956cc18dSsnj
1455956cc18dSsnj	    XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents);
1456956cc18dSsnj	    if (width < extents.width)
1457956cc18dSsnj		width = extents.width;
1458956cc18dSsnj	}
1459956cc18dSsnj    }
1460956cc18dSsnj    data->map.min_width = width;
1461956cc18dSsnj    data->map.mixed = (data->map.max_width >= (data->map.min_width + 1));
1462956cc18dSsnj}
1463956cc18dSsnj
1464d522f475Smrgstatic XftFont *
1465956cc18dSsnjxtermOpenXft(XtermWidget xw, const char *name, XftPattern * pat, const char *tag)
1466d522f475Smrg{
1467956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1468956cc18dSsnj    Display *dpy = screen->display;
1469d522f475Smrg    XftPattern *match;
1470d522f475Smrg    XftResult status;
1471d522f475Smrg    XftFont *result = 0;
1472d522f475Smrg
1473d522f475Smrg    if (pat != 0) {
1474d522f475Smrg	match = XftFontMatch(dpy, DefaultScreen(dpy), pat, &status);
1475d522f475Smrg	if (match != 0) {
1476d522f475Smrg	    result = XftFontOpenPattern(dpy, match);
1477d522f475Smrg	    if (result != 0) {
1478d522f475Smrg		TRACE(("...matched %s font\n", tag));
1479d522f475Smrg	    } else {
1480d522f475Smrg		TRACE(("...could did not open %s font\n", tag));
1481d522f475Smrg		XftPatternDestroy(match);
1482956cc18dSsnj		if (xw->misc.fontWarnings >= fwAlways) {
1483956cc18dSsnj		    TRACE(("OOPS cannot open %s font \"%s\"\n", tag, name));
1484956cc18dSsnj		    fprintf(stderr, "%s: cannot open %s font \"%s\"\n",
1485956cc18dSsnj			    ProgramName, tag, name);
1486956cc18dSsnj		}
1487d522f475Smrg	    }
1488d522f475Smrg	} else {
1489d522f475Smrg	    TRACE(("...did not match %s font\n", tag));
1490956cc18dSsnj	    if (xw->misc.fontWarnings >= fwResource) {
1491956cc18dSsnj		TRACE(("OOPS: cannot match %s font \"%s\"\n", tag, name));
1492956cc18dSsnj		fprintf(stderr, "%s: cannot match %s font \"%s\"\n",
1493956cc18dSsnj			ProgramName, tag, name);
1494956cc18dSsnj	    }
1495d522f475Smrg	}
1496d522f475Smrg    }
1497d522f475Smrg    return result;
1498d522f475Smrg}
1499d522f475Smrg#endif
1500d522f475Smrg
1501d522f475Smrg#if OPT_RENDERFONT
1502d522f475Smrg#if OPT_SHIFT_FONTS
1503d522f475Smrg/*
1504d522f475Smrg * Don't make a dependency on the math library for a single function.
1505d522f475Smrg * (Newton Raphson).
1506d522f475Smrg */
1507d522f475Smrgstatic double
1508d522f475SmrgmySquareRoot(double value)
1509d522f475Smrg{
1510d522f475Smrg    double result = 0.0;
1511d522f475Smrg    if (value > 0.0) {
1512d522f475Smrg	int n;
1513d522f475Smrg	double older = value;
1514d522f475Smrg	for (n = 0; n < 10; ++n) {
1515d522f475Smrg	    double delta = (older * older - value) / (2.0 * older);
1516d522f475Smrg	    double newer = older - delta;
1517d522f475Smrg	    older = newer;
1518d522f475Smrg	    result = newer;
1519d522f475Smrg	    if (delta > -0.001 && delta < 0.001)
1520d522f475Smrg		break;
1521d522f475Smrg	}
1522d522f475Smrg    }
1523d522f475Smrg    return result;
1524d522f475Smrg}
1525d522f475Smrg#endif
1526d522f475Smrg
1527d522f475Smrg/*
1528d522f475Smrg * Given the Xft font metrics, determine the actual font size.  This is used
1529d522f475Smrg * for each font to ensure that normal, bold and italic fonts follow the same
1530d522f475Smrg * rule.
1531d522f475Smrg */
1532d522f475Smrgstatic void
1533d522f475SmrgsetRenderFontsize(TScreen * screen, VTwin * win, XftFont * font, const char *tag)
1534d522f475Smrg{
1535d522f475Smrg    if (font != 0) {
1536d522f475Smrg	int width, height, ascent, descent;
1537d522f475Smrg
1538d522f475Smrg	(void) screen;
1539d522f475Smrg
1540d522f475Smrg	width = font->max_advance_width;
1541d522f475Smrg	height = font->height;
1542d522f475Smrg	ascent = font->ascent;
1543d522f475Smrg	descent = font->descent;
1544d522f475Smrg	if (height < ascent + descent) {
1545d522f475Smrg	    TRACE(("...increase height from %d\n", height));
1546d522f475Smrg	    height = ascent + descent;
1547d522f475Smrg	}
1548d522f475Smrg	if (is_double_width_font_xft(screen->display, font)) {
1549d522f475Smrg	    TRACE(("...reduced width from %d\n", width));
1550d522f475Smrg	    width >>= 1;
1551d522f475Smrg	}
1552d522f475Smrg	if (tag == 0) {
1553d522f475Smrg	    win->f_width = width;
1554d522f475Smrg	    win->f_height = height;
1555d522f475Smrg	    win->f_ascent = ascent;
1556d522f475Smrg	    win->f_descent = descent;
1557d522f475Smrg	    TRACE(("setRenderFontsize result %dx%d (%d+%d)\n",
1558d522f475Smrg		   width, height, ascent, descent));
1559d522f475Smrg	} else if (win->f_width < width ||
1560d522f475Smrg		   win->f_height < height ||
1561d522f475Smrg		   win->f_ascent < ascent ||
1562d522f475Smrg		   win->f_descent < descent) {
1563d522f475Smrg	    TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n",
1564d522f475Smrg		   tag,
1565d522f475Smrg		   win->f_width, win->f_height, win->f_ascent, win->f_descent,
1566d522f475Smrg		   width, height, ascent, descent));
1567d522f475Smrg
1568d522f475Smrg	    win->f_width = width;
1569d522f475Smrg	    win->f_height = height;
1570d522f475Smrg	    win->f_ascent = ascent;
1571d522f475Smrg	    win->f_descent = descent;
1572d522f475Smrg	} else {
1573d522f475Smrg	    TRACE(("setRenderFontsize %s unchanged\n", tag));
1574d522f475Smrg	}
1575d522f475Smrg    }
1576d522f475Smrg}
1577d522f475Smrg#endif
1578d522f475Smrg
1579d522f475Smrg/*
1580d522f475Smrg * Compute useful values for the font/window sizes
1581d522f475Smrg */
1582d522f475Smrgvoid
1583d522f475SmrgxtermComputeFontInfo(XtermWidget xw,
1584d522f475Smrg		     VTwin * win,
1585d522f475Smrg		     XFontStruct * font,
1586d522f475Smrg		     int sbwidth)
1587d522f475Smrg{
1588956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1589d522f475Smrg
1590d522f475Smrg    int i, j, width, height;
1591d522f475Smrg
1592d522f475Smrg#if OPT_RENDERFONT
1593d522f475Smrg    /*
1594d522f475Smrg     * xterm contains a lot of references to fonts, assuming they are fixed
1595d522f475Smrg     * size.  This chunk of code overrides the actual font-selection (see
1596d522f475Smrg     * drawXtermText()), if the user has selected render-font.  All of the
1597d522f475Smrg     * font-loading for fixed-fonts still goes on whether or not this chunk
1598d522f475Smrg     * overrides it.
1599d522f475Smrg     */
1600d522f475Smrg    if (xw->misc.render_font && !IsIconWin(screen, win)) {
1601d522f475Smrg	int fontnum = screen->menu_font_number;
1602956cc18dSsnj	XftFont *norm = screen->renderFontNorm[fontnum].font;
1603956cc18dSsnj	XftFont *bold = screen->renderFontBold[fontnum].font;
1604956cc18dSsnj	XftFont *ital = screen->renderFontItal[fontnum].font;
1605d522f475Smrg#if OPT_RENDERWIDE
1606956cc18dSsnj	XftFont *wnorm = screen->renderWideNorm[fontnum].font;
1607956cc18dSsnj	XftFont *wbold = screen->renderWideBold[fontnum].font;
1608956cc18dSsnj	XftFont *wital = screen->renderWideItal[fontnum].font;
1609d522f475Smrg#endif
1610d522f475Smrg
1611d522f475Smrg	if (norm == 0 && xw->misc.face_name) {
1612d522f475Smrg	    XftPattern *pat;
1613d522f475Smrg	    double face_size = xw->misc.face_size[fontnum];
1614d522f475Smrg
1615d522f475Smrg	    TRACE(("xtermComputeFontInfo norm(face %s, size %f)\n",
1616d522f475Smrg		   xw->misc.face_name,
1617d522f475Smrg		   xw->misc.face_size[fontnum]));
1618d522f475Smrg
1619d522f475Smrg	    if (face_size <= 0.0) {
1620d522f475Smrg#if OPT_SHIFT_FONTS
1621d522f475Smrg		/*
1622d522f475Smrg		 * If the user is switching font-sizes, make it follow by
1623d522f475Smrg		 * default the same ratios to the default as the fixed fonts
1624d522f475Smrg		 * would, for easy comparison.  There will be some differences
1625d522f475Smrg		 * since the fixed fonts have a variety of height/width ratios,
1626d522f475Smrg		 * but this is simpler than adding another resource value - and
1627d522f475Smrg		 * as noted above, the data for the fixed fonts are available.
1628d522f475Smrg		 */
1629d522f475Smrg		lookupOneFontSize(xw, 0);
1630d522f475Smrg		lookupOneFontSize(xw, fontnum);
1631d522f475Smrg		if (fontnum == fontMenu_default) {
1632d522f475Smrg		    face_size = 14.0;
1633d522f475Smrg		} else {
1634d522f475Smrg		    double ratio;
1635d522f475Smrg		    int num = screen->menu_font_sizes[fontnum];
1636d522f475Smrg		    int den = screen->menu_font_sizes[0];
1637d522f475Smrg
1638d522f475Smrg		    if (den <= 0)
1639d522f475Smrg			den = 1;
1640d522f475Smrg		    ratio = mySquareRoot((1.0 * num) / den);
1641d522f475Smrg
1642d522f475Smrg		    face_size = (ratio * xw->misc.face_size[0]);
1643d522f475Smrg		    TRACE(("scaled using %3d/%d = %.2f -> %f\n",
1644d522f475Smrg			   num, den, ratio, face_size));
1645d522f475Smrg		}
1646d522f475Smrg#else
1647d522f475Smrg		switch (fontnum) {
1648d522f475Smrg		case fontMenu_font1:
1649d522f475Smrg		    face_size = 8.0;
1650d522f475Smrg		    break;
1651d522f475Smrg		case fontMenu_font2:
1652d522f475Smrg		    face_size = 10.0;
1653d522f475Smrg		    break;
1654d522f475Smrg		case fontMenu_font3:
1655d522f475Smrg		    face_size = 12.0;
1656d522f475Smrg		    break;
1657d522f475Smrg		default:
1658d522f475Smrg		    face_size = 14.0;
1659d522f475Smrg		    break;
1660d522f475Smrg		case fontMenu_font4:
1661d522f475Smrg		    face_size = 16.0;
1662d522f475Smrg		    break;
1663d522f475Smrg		case fontMenu_font5:
1664d522f475Smrg		    face_size = 18.0;
1665d522f475Smrg		    break;
1666d522f475Smrg		case fontMenu_font6:
1667d522f475Smrg		    face_size = 20.0;
1668d522f475Smrg		    break;
1669d522f475Smrg		}
1670d522f475Smrg#endif
1671956cc18dSsnj		xw->misc.face_size[fontnum] = (float) face_size;
1672d522f475Smrg	    }
1673d522f475Smrg
1674d522f475Smrg	    /*
1675d522f475Smrg	     * By observation (there is no documentation), XftPatternBuild is
1676d522f475Smrg	     * cumulative.  Build the bold- and italic-patterns on top of the
1677d522f475Smrg	     * normal pattern.
1678d522f475Smrg	     */
1679d522f475Smrg#define NormXftPattern \
1680d522f475Smrg	    XFT_FAMILY, XftTypeString, "mono", \
1681d522f475Smrg	    XFT_SIZE, XftTypeDouble, face_size, \
1682d522f475Smrg	    XFT_SPACING, XftTypeInteger, XFT_MONO
1683d522f475Smrg
1684d522f475Smrg#define BoldXftPattern(norm) \
1685d522f475Smrg	    XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \
1686d522f475Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width
1687d522f475Smrg
1688d522f475Smrg#define ItalXftPattern(norm) \
1689d522f475Smrg	    XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \
1690d522f475Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width
1691d522f475Smrg
1692d522f475Smrg	    if ((pat = XftNameParse(xw->misc.face_name)) != 0) {
1693956cc18dSsnj#define OPEN_XFT(tag) xtermOpenXft(xw, xw->misc.face_name, pat, tag)
1694d522f475Smrg		XftPatternBuild(pat,
1695d522f475Smrg				NormXftPattern,
1696d522f475Smrg				(void *) 0);
1697956cc18dSsnj		norm = OPEN_XFT("normal");
1698d522f475Smrg
1699d522f475Smrg		if (norm != 0) {
1700d522f475Smrg		    XftPatternBuild(pat,
1701d522f475Smrg				    BoldXftPattern(norm),
1702d522f475Smrg				    (void *) 0);
1703956cc18dSsnj		    bold = OPEN_XFT("bold");
1704d522f475Smrg
1705d522f475Smrg#if OPT_ISO_COLORS
1706d522f475Smrg		    if (screen->italicULMode
1707d522f475Smrg			&& (pat = XftNameParse(xw->misc.face_name)) != 0) {
1708d522f475Smrg			XftPatternBuild(pat,
1709d522f475Smrg					NormXftPattern,
1710d522f475Smrg					ItalXftPattern(norm),
1711d522f475Smrg					(void *) 0);
1712956cc18dSsnj			ital = OPEN_XFT("italic");
1713d522f475Smrg		    }
1714d522f475Smrg#endif /* OPT_ISO_COLORS */
1715956cc18dSsnj#undef OPEN_XFT
1716d522f475Smrg
1717d522f475Smrg		    /*
1718d522f475Smrg		     * FIXME:  just assume that the corresponding font has no
1719d522f475Smrg		     * graphics characters.
1720d522f475Smrg		     */
1721d522f475Smrg		    if (screen->fnt_boxes) {
1722d522f475Smrg			screen->fnt_boxes = False;
1723d522f475Smrg			TRACE(("Xft opened - will %suse internal line-drawing characters\n",
1724d522f475Smrg			       screen->fnt_boxes ? "not " : ""));
1725d522f475Smrg		    }
1726d522f475Smrg		}
1727d522f475Smrg
1728d522f475Smrg		XftPatternDestroy(pat);
1729d522f475Smrg	    }
1730d522f475Smrg
1731d522f475Smrg	    CACHE_XFT(screen->renderFontNorm, norm);
1732d522f475Smrg	    CACHE_XFT(screen->renderFontBold, bold);
1733d522f475Smrg	    CACHE_XFT(screen->renderFontItal, ital);
1734d522f475Smrg
1735d522f475Smrg	    /*
1736d522f475Smrg	     * See xtermXftDrawString().
1737d522f475Smrg	     */
1738d522f475Smrg#if OPT_RENDERWIDE
1739d522f475Smrg	    if (norm != 0 && screen->wide_chars) {
1740d522f475Smrg		char *face_name = (xw->misc.face_wide_name
1741d522f475Smrg				   ? xw->misc.face_wide_name
1742d522f475Smrg				   : xw->misc.face_name);
1743d522f475Smrg		int char_width = norm->max_advance_width * 2;
1744956cc18dSsnj#ifdef FC_ASPECT
1745956cc18dSsnj		double aspect = ((xw->misc.face_wide_name
1746956cc18dSsnj				  || screen->renderFontNorm[fontnum].map.mixed)
1747956cc18dSsnj				 ? 1.0
1748956cc18dSsnj				 : 2.0);
1749956cc18dSsnj#endif
1750d522f475Smrg
1751d522f475Smrg		TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n",
1752d522f475Smrg		       face_name,
1753d522f475Smrg		       char_width));
1754d522f475Smrg
1755d522f475Smrg#define WideXftPattern \
1756d522f475Smrg		XFT_FAMILY, XftTypeString, "mono", \
1757d522f475Smrg		XFT_SIZE, XftTypeDouble, face_size, \
1758d522f475Smrg		XFT_SPACING, XftTypeInteger, XFT_MONO
1759d522f475Smrg
1760d522f475Smrg		if ((pat = XftNameParse(face_name)) != 0) {
1761956cc18dSsnj#define OPEN_XFT(tag) xtermOpenXft(xw, face_name, pat, tag)
1762d522f475Smrg		    XftPatternBuild(pat,
1763d522f475Smrg				    WideXftPattern,
1764d522f475Smrg				    XFT_CHAR_WIDTH, XftTypeInteger, char_width,
1765956cc18dSsnj#ifdef FC_ASPECT
1766956cc18dSsnj				    FC_ASPECT, XftTypeDouble, aspect,
1767956cc18dSsnj#endif
1768d522f475Smrg				    (void *) 0);
1769956cc18dSsnj		    wnorm = OPEN_XFT("wide");
1770d522f475Smrg
1771d522f475Smrg		    if (wnorm != 0) {
1772d522f475Smrg			XftPatternBuild(pat,
1773d522f475Smrg					WideXftPattern,
1774d522f475Smrg					BoldXftPattern(wnorm),
1775d522f475Smrg					(void *) 0);
1776956cc18dSsnj			wbold = OPEN_XFT("wide-bold");
1777d522f475Smrg
1778d522f475Smrg#if OPT_ISO_COLORS
1779d522f475Smrg			if (screen->italicULMode
1780d522f475Smrg			    && (pat = XftNameParse(face_name)) != 0) {
1781d522f475Smrg			    XftPatternBuild(pat,
1782d522f475Smrg					    WideXftPattern,
1783d522f475Smrg					    ItalXftPattern(wnorm),
1784d522f475Smrg					    (void *) 0);
1785956cc18dSsnj			    wital = OPEN_XFT("wide-italic");
1786d522f475Smrg			}
1787d522f475Smrg#endif
1788956cc18dSsnj#undef OPEN_XFT
1789d522f475Smrg		    }
1790d522f475Smrg		    XftPatternDestroy(pat);
1791d522f475Smrg		}
1792d522f475Smrg
1793d522f475Smrg		CACHE_XFT(screen->renderWideNorm, wnorm);
1794d522f475Smrg		CACHE_XFT(screen->renderWideBold, wbold);
1795d522f475Smrg		CACHE_XFT(screen->renderWideItal, wital);
1796d522f475Smrg	    }
1797d522f475Smrg#endif /* OPT_RENDERWIDE */
1798d522f475Smrg	}
1799d522f475Smrg	if (norm == 0) {
18002eaa94a1Schristos	    TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum));
1801d522f475Smrg	    xw->misc.render_font = False;
1802d522f475Smrg	    update_font_renderfont();
1803d522f475Smrg	    /* now we will fall through into the bitmap fonts */
1804d522f475Smrg	} else {
1805d522f475Smrg	    setRenderFontsize(screen, win, norm, NULL);
1806d522f475Smrg	    setRenderFontsize(screen, win, bold, "bold");
1807d522f475Smrg	    setRenderFontsize(screen, win, ital, "ital");
1808d522f475Smrg	}
1809d522f475Smrg    }
1810d522f475Smrg    /*
1811d522f475Smrg     * Are we handling a bitmap font?
1812d522f475Smrg     */
1813d522f475Smrg    if (!xw->misc.render_font || IsIconWin(screen, win))
1814d522f475Smrg#endif /* OPT_RENDERFONT */
1815d522f475Smrg    {
1816d522f475Smrg	if (is_double_width_font(font)) {
1817d522f475Smrg	    win->f_width = (font->min_bounds.width);
1818d522f475Smrg	} else {
1819d522f475Smrg	    win->f_width = (font->max_bounds.width);
1820d522f475Smrg	}
1821d522f475Smrg	win->f_height = (font->ascent + font->descent);
1822d522f475Smrg	win->f_ascent = font->ascent;
1823d522f475Smrg	win->f_descent = font->descent;
1824d522f475Smrg    }
1825d522f475Smrg    i = 2 * screen->border + sbwidth;
1826d522f475Smrg    j = 2 * screen->border;
1827d522f475Smrg    width = MaxCols(screen) * win->f_width + i;
1828d522f475Smrg    height = MaxRows(screen) * win->f_height + j;
1829956cc18dSsnj    win->fullwidth = (Dimension) width;
1830956cc18dSsnj    win->fullheight = (Dimension) height;
1831d522f475Smrg    win->width = width - i;
1832d522f475Smrg    win->height = height - j;
1833d522f475Smrg
1834d522f475Smrg    TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n",
1835d522f475Smrg	   win->height,
1836d522f475Smrg	   win->width,
1837d522f475Smrg	   win->fullheight,
1838d522f475Smrg	   win->fullwidth,
1839d522f475Smrg	   win->f_height,
1840d522f475Smrg	   win->f_width,
1841d522f475Smrg	   win->f_ascent,
1842d522f475Smrg	   win->f_descent));
1843d522f475Smrg}
1844d522f475Smrg
1845d522f475Smrg/* save this information as a side-effect for double-sized characters */
1846d522f475Smrgvoid
1847d522f475SmrgxtermSaveFontInfo(TScreen * screen, XFontStruct * font)
1848d522f475Smrg{
1849956cc18dSsnj    screen->fnt_wide = (Dimension) (font->max_bounds.width);
1850956cc18dSsnj    screen->fnt_high = (Dimension) (font->ascent + font->descent);
1851d522f475Smrg    TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide));
1852d522f475Smrg}
1853d522f475Smrg
1854d522f475Smrg/*
1855d522f475Smrg * After loading a new font, update the structures that use its size.
1856d522f475Smrg */
1857d522f475Smrgvoid
1858d522f475SmrgxtermUpdateFontInfo(XtermWidget xw, Bool doresize)
1859d522f475Smrg{
1860956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1861d522f475Smrg
1862d522f475Smrg    int scrollbar_width;
1863d522f475Smrg    VTwin *win = &(screen->fullVwin);
1864d522f475Smrg
1865d522f475Smrg    scrollbar_width = (xw->misc.scrollbar
1866d522f475Smrg		       ? (screen->scrollWidget->core.width +
1867d522f475Smrg			  BorderWidth(screen->scrollWidget))
1868d522f475Smrg		       : 0);
1869d522f475Smrg    xtermComputeFontInfo(xw, win, screen->fnts[fNorm].fs, scrollbar_width);
1870d522f475Smrg    xtermSaveFontInfo(screen, screen->fnts[fNorm].fs);
1871d522f475Smrg
1872d522f475Smrg    if (doresize) {
1873d522f475Smrg	if (VWindow(screen)) {
1874d522f475Smrg	    xtermClear(xw);
1875d522f475Smrg	}
1876d522f475Smrg	TRACE(("xtermUpdateFontInfo {{\n"));
1877d522f475Smrg	DoResizeScreen(xw);	/* set to the new natural size */
1878d522f475Smrg	ResizeScrollBar(xw);
1879d522f475Smrg	Redraw();
1880d522f475Smrg	TRACE(("... }} xtermUpdateFontInfo\n"));
1881d522f475Smrg#ifdef SCROLLBAR_RIGHT
1882d522f475Smrg	updateRightScrollbar(xw);
1883d522f475Smrg#endif
1884d522f475Smrg    }
1885d522f475Smrg    xtermSetCursorBox(screen);
1886d522f475Smrg}
1887d522f475Smrg
1888d522f475Smrg#if OPT_BOX_CHARS
1889d522f475Smrg
1890d522f475Smrg/*
1891d522f475Smrg * Returns true if the given character is missing from the specified font.
1892d522f475Smrg */
1893d522f475SmrgBool
1894956cc18dSsnjxtermMissingChar(unsigned ch, XTermFonts * font)
1895d522f475Smrg{
1896956cc18dSsnj    Bool result = False;
1897956cc18dSsnj    XFontStruct *fs = font->fs;
1898956cc18dSsnj    static XCharStruct dft, *tmp = &dft, *pc = 0;
1899d522f475Smrg
1900956cc18dSsnj    if (fs->max_byte1 == 0) {
1901d522f475Smrg#if OPT_WIDE_CHARS
1902956cc18dSsnj	if (ch > 255) {
1903956cc18dSsnj	    TRACE(("xtermMissingChar %#04x (row)\n", ch));
1904956cc18dSsnj	    return True;
1905d522f475Smrg	}
1906956cc18dSsnj#endif
1907956cc18dSsnj	CI_GET_CHAR_INFO_1D(fs, E2A(ch), tmp, pc);
1908956cc18dSsnj    }
1909d522f475Smrg#if OPT_WIDE_CHARS
1910956cc18dSsnj    else {
1911956cc18dSsnj	CI_GET_CHAR_INFO_2D(fs, HI_BYTE(ch), LO_BYTE(ch), tmp, pc);
1912956cc18dSsnj    }
1913d522f475Smrg#else
1914d522f475Smrg
1915956cc18dSsnj    if (!pc)
1916956cc18dSsnj	return False;		/* Urgh! */
1917d522f475Smrg#endif
1918d522f475Smrg
1919956cc18dSsnj    if (CI_NONEXISTCHAR(pc)) {
1920956cc18dSsnj	TRACE(("xtermMissingChar %#04x (!exists)\n", ch));
1921956cc18dSsnj	result = True;
1922d522f475Smrg    }
1923956cc18dSsnj    if (ch < 256) {
1924956cc18dSsnj	font->known_missing[ch] = (Char) (result ? 2 : 1);
1925d522f475Smrg    }
1926956cc18dSsnj    return result;
1927d522f475Smrg}
1928d522f475Smrg
1929d522f475Smrg/*
1930d522f475Smrg * The grid is arbitrary, enough resolution that nothing's lost in
1931d522f475Smrg * initialization.
1932d522f475Smrg */
1933d522f475Smrg#define BOX_HIGH 60
1934d522f475Smrg#define BOX_WIDE 60
1935d522f475Smrg
1936d522f475Smrg#define MID_HIGH (BOX_HIGH/2)
1937d522f475Smrg#define MID_WIDE (BOX_WIDE/2)
1938d522f475Smrg
1939d522f475Smrg#define CHR_WIDE ((9*BOX_WIDE)/10)
1940d522f475Smrg#define CHR_HIGH ((9*BOX_HIGH)/10)
1941d522f475Smrg
1942d522f475Smrg/*
1943d522f475Smrg * ...since we'll scale the values anyway.
1944d522f475Smrg */
1945956cc18dSsnj#define SCALE_X(n) n = (n * (((int) font_width) - 1)) / (BOX_WIDE-1)
1946956cc18dSsnj#define SCALE_Y(n) n = (n * (((int) font_height) - 1)) / (BOX_HIGH-1)
1947d522f475Smrg
1948d522f475Smrg#define SEG(x0,y0,x1,y1) x0,y0, x1,y1
1949d522f475Smrg
1950d522f475Smrg/*
1951d522f475Smrg * Draw the given graphic character, if it is simple enough (i.e., a
1952d522f475Smrg * line-drawing character).
1953d522f475Smrg */
1954d522f475Smrgvoid
1955d522f475SmrgxtermDrawBoxChar(XtermWidget xw,
1956d522f475Smrg		 unsigned ch,
1957d522f475Smrg		 unsigned flags,
1958d522f475Smrg		 GC gc,
1959d522f475Smrg		 int x,
1960d522f475Smrg		 int y,
1961d522f475Smrg		 int cells)
1962d522f475Smrg{
1963956cc18dSsnj    TScreen *screen = TScreenOf(xw);
1964d522f475Smrg    /* *INDENT-OFF* */
1965d522f475Smrg    static const short glyph_ht[] = {
1966d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,5*MID_HIGH/6),	/* H */
1967d522f475Smrg	SEG(6*BOX_WIDE/10,  0,		6*BOX_WIDE/10,5*MID_HIGH/6),
1968d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12),
1969d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
1970d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
1971d522f475Smrg	-1
1972d522f475Smrg    }, glyph_ff[] = {
1973d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		6*BOX_WIDE/10,	0),		/* F */
1974d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12),
1975d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		0*BOX_WIDE/3, 5*MID_HIGH/6),
1976d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
1977d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
1978d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
1979d522f475Smrg	-1
1980d522f475Smrg    }, glyph_lf[] = {
1981d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,9*MID_HIGH/12),	/* L */
1982d522f475Smrg	SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12),
1983d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
1984d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
1985d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
1986d522f475Smrg	-1
1987d522f475Smrg    }, glyph_nl[] = {
1988d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10,	0),		/* N */
1989d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		5*BOX_WIDE/6, 5*MID_HIGH/6),
1990d522f475Smrg	SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
1991d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),	/* L */
1992d522f475Smrg	SEG(1*BOX_WIDE/3,   CHR_HIGH,	  CHR_WIDE,	CHR_HIGH),
1993d522f475Smrg	-1
1994d522f475Smrg    }, glyph_vt[] = {
1995d522f475Smrg	SEG(1*BOX_WIDE/10,   0,		5*BOX_WIDE/12,5*MID_HIGH/6),	/* V */
1996d522f475Smrg	SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
1997d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
1998d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
1999d522f475Smrg	-1
2000d522f475Smrg    }, plus_or_minus[] =
2001d522f475Smrg    {
2002d522f475Smrg	SEG(  0,	  5*BOX_HIGH/6,	  CHR_WIDE,   5*BOX_HIGH/6),
2003d522f475Smrg	SEG(  MID_WIDE,	  2*BOX_HIGH/6,	  MID_WIDE,   4*BOX_HIGH/6),
2004d522f475Smrg	SEG(  0,	  3*BOX_HIGH/6,	  CHR_WIDE,   3*BOX_HIGH/6),
2005d522f475Smrg	-1
2006d522f475Smrg    }, lower_right_corner[] =
2007d522f475Smrg    {
2008d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
2009d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	0),
2010d522f475Smrg	-1
2011d522f475Smrg    }, upper_right_corner[] =
2012d522f475Smrg    {
2013d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
2014d522f475Smrg	SEG( MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
2015d522f475Smrg	-1
2016d522f475Smrg    }, upper_left_corner[] =
2017d522f475Smrg    {
2018d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2019d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
2020d522f475Smrg	-1
2021d522f475Smrg    }, lower_left_corner[] =
2022d522f475Smrg    {
2023d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
2024d522f475Smrg	SEG(  MID_WIDE,	    MID_WIDE,	  BOX_WIDE,	MID_HIGH),
2025d522f475Smrg	-1
2026d522f475Smrg    }, cross[] =
2027d522f475Smrg    {
2028d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2029d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2030d522f475Smrg	-1
2031d522f475Smrg    }, scan_line_1[] =
2032d522f475Smrg    {
2033d522f475Smrg	SEG(  0,	    0,		  BOX_WIDE,	0),
2034d522f475Smrg	-1
2035d522f475Smrg    }, scan_line_3[] =
2036d522f475Smrg    {
2037d522f475Smrg	SEG(  0,	    BOX_HIGH/4,	  BOX_WIDE,	BOX_HIGH/4),
2038d522f475Smrg	-1
2039d522f475Smrg    }, scan_line_7[] =
2040d522f475Smrg    {
2041d522f475Smrg	SEG( 0,		    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2042d522f475Smrg	-1
2043d522f475Smrg    }, scan_line_9[] =
2044d522f475Smrg    {
2045d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  BOX_WIDE,   3*BOX_HIGH/4),
2046d522f475Smrg	-1
2047d522f475Smrg    }, horizontal_line[] =
2048d522f475Smrg    {
2049d522f475Smrg	SEG(  0,	    BOX_HIGH,	  BOX_WIDE,	BOX_HIGH),
2050d522f475Smrg	-1
2051d522f475Smrg    }, left_tee[] =
2052d522f475Smrg    {
2053d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2054d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2055d522f475Smrg	-1
2056d522f475Smrg    }, right_tee[] =
2057d522f475Smrg    {
2058d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2059d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  0,		MID_HIGH),
2060d522f475Smrg	-1
2061d522f475Smrg    }, bottom_tee[] =
2062d522f475Smrg    {
2063d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2064d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
2065d522f475Smrg	-1
2066d522f475Smrg    }, top_tee[] =
2067d522f475Smrg    {
2068d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
2069d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
2070d522f475Smrg	-1
2071d522f475Smrg    }, vertical_line[] =
2072d522f475Smrg    {
2073d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
2074d522f475Smrg	-1
2075d522f475Smrg    }, less_than_or_equal[] =
2076d522f475Smrg    {
2077d522f475Smrg	SEG(  CHR_WIDE,	    BOX_HIGH/3,	  0,		MID_HIGH),
2078d522f475Smrg	SEG(  CHR_WIDE,	  2*BOX_HIGH/3,	  0,		MID_HIGH),
2079d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
2080d522f475Smrg	-1
2081d522f475Smrg    }, greater_than_or_equal[] =
2082d522f475Smrg    {
2083d522f475Smrg	SEG(  0,	    BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
2084d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
2085d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
2086d522f475Smrg	-1
2087d522f475Smrg    }, greek_pi[] =
2088d522f475Smrg    {
2089d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
2090d522f475Smrg	SEG(5*CHR_WIDE/6,   MID_HIGH,	5*CHR_WIDE/6,	CHR_HIGH),
2091d522f475Smrg	SEG(2*CHR_WIDE/6,   MID_HIGH,	2*CHR_WIDE/6,	CHR_HIGH),
2092d522f475Smrg	-1
2093d522f475Smrg    }, not_equal_to[] =
2094d522f475Smrg    {
2095d522f475Smrg	SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3,	CHR_HIGH),
2096d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,   2*BOX_HIGH/3),
2097d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
2098d522f475Smrg	-1
2099d522f475Smrg    };
2100d522f475Smrg    /* *INDENT-ON* */
2101d522f475Smrg
2102d522f475Smrg    static const short *lines[] =
2103d522f475Smrg    {
2104d522f475Smrg	0,			/* 00 (unused) */
2105d522f475Smrg	0,			/* 01 diamond */
2106d522f475Smrg	0,			/* 02 box */
2107d522f475Smrg	glyph_ht,		/* 03 HT */
2108d522f475Smrg	glyph_ff,		/* 04 FF */
2109d522f475Smrg	0,			/* 05 CR */
2110d522f475Smrg	glyph_lf,		/* 06 LF */
2111d522f475Smrg	0,			/* 07 degrees (small circle) */
2112d522f475Smrg	plus_or_minus,		/* 08 */
2113d522f475Smrg	glyph_nl,		/* 09 */
2114d522f475Smrg	glyph_vt,		/* 0A */
2115d522f475Smrg	lower_right_corner,	/* 0B */
2116d522f475Smrg	upper_right_corner,	/* 0C */
2117d522f475Smrg	upper_left_corner,	/* 0D */
2118d522f475Smrg	lower_left_corner,	/* 0E */
2119d522f475Smrg	cross,			/* 0F */
2120d522f475Smrg	scan_line_1,		/* 10 */
2121d522f475Smrg	scan_line_3,		/* 11 */
2122d522f475Smrg	scan_line_7,		/* 12 */
2123d522f475Smrg	scan_line_9,		/* 13 */
2124d522f475Smrg	horizontal_line,	/* 14 */
2125d522f475Smrg	left_tee,		/* 15 */
2126d522f475Smrg	right_tee,		/* 16 */
2127d522f475Smrg	bottom_tee,		/* 17 */
2128d522f475Smrg	top_tee,		/* 18 */
2129d522f475Smrg	vertical_line,		/* 19 */
2130d522f475Smrg	less_than_or_equal,	/* 1A */
2131d522f475Smrg	greater_than_or_equal,	/* 1B */
2132d522f475Smrg	greek_pi,		/* 1C */
2133d522f475Smrg	not_equal_to,		/* 1D */
2134d522f475Smrg	0,			/* 1E LB */
2135d522f475Smrg	0,			/* 1F bullet */
2136d522f475Smrg    };
2137d522f475Smrg
2138d522f475Smrg    GC gc2;
2139d522f475Smrg    CgsEnum cgsId = (ch == 2) ? gcDots : gcLine;
2140d522f475Smrg    VTwin *cgsWin = WhichVWin(screen);
2141d522f475Smrg    const short *p;
2142956cc18dSsnj    unsigned font_width = (unsigned) (((flags & DOUBLEWFONT) ? 2 : 1) * screen->fnt_wide);
2143956cc18dSsnj    unsigned font_height = (unsigned) (((flags & DOUBLEHFONT) ? 2 : 1) * screen->fnt_high);
2144d522f475Smrg
2145d522f475Smrg    if (cells > 1)
2146956cc18dSsnj	font_width *= (unsigned) cells;
2147d522f475Smrg
2148d522f475Smrg#if OPT_WIDE_CHARS
2149d522f475Smrg    /*
2150d522f475Smrg     * Try to show line-drawing characters if we happen to be in UTF-8
2151d522f475Smrg     * mode, but have gotten an old-style font.
2152d522f475Smrg     */
2153d522f475Smrg    if (screen->utf8_mode
2154d522f475Smrg#if OPT_RENDERFONT
2155d522f475Smrg	&& !UsingRenderFont(xw)
2156d522f475Smrg#endif
2157d522f475Smrg	&& (ch > 127)
2158d522f475Smrg	&& (ch != UCS_REPL)) {
2159d522f475Smrg	unsigned n;
2160d522f475Smrg	for (n = 1; n < 32; n++) {
2161d522f475Smrg	    if (dec2ucs(n) == ch
2162956cc18dSsnj		&& !IsXtermMissingChar(screen, n,
2163956cc18dSsnj				       ((flags & BOLD)
2164956cc18dSsnj					? &screen->fnts[fBold]
2165956cc18dSsnj					: &screen->fnts[fNorm]))) {
2166d522f475Smrg		TRACE(("...use xterm-style linedrawing\n"));
2167d522f475Smrg		ch = n;
2168d522f475Smrg		break;
2169d522f475Smrg	    }
2170d522f475Smrg	}
2171d522f475Smrg    }
2172d522f475Smrg#endif
2173d522f475Smrg
2174d522f475Smrg    TRACE(("DRAW_BOX(%d) cell %dx%d at %d,%d%s\n",
2175d522f475Smrg	   ch, font_height, font_width, y, x,
2176d522f475Smrg	   (ch >= (sizeof(lines) / sizeof(lines[0]))
2177d522f475Smrg	    ? "-BAD"
2178d522f475Smrg	    : "")));
2179d522f475Smrg
2180d522f475Smrg    if (cgsId == gcDots) {
2181d522f475Smrg	setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2182d522f475Smrg	setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc));
2183d522f475Smrg	setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2184d522f475Smrg    } else {
2185d522f475Smrg	setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2186d522f475Smrg	setCgsFore(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2187d522f475Smrg	setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2188d522f475Smrg    }
2189d522f475Smrg    gc2 = getCgsGC(xw, cgsWin, cgsId);
2190d522f475Smrg
2191d522f475Smrg    if (!(flags & NOBACKGROUND)) {
2192d522f475Smrg	XFillRectangle(screen->display, VWindow(screen), gc2, x, y,
2193d522f475Smrg		       font_width,
2194d522f475Smrg		       font_height);
2195d522f475Smrg    }
2196d522f475Smrg
2197d522f475Smrg    setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2198d522f475Smrg    setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc));
2199d522f475Smrg    setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2200d522f475Smrg    gc2 = getCgsGC(xw, cgsWin, cgsId);
2201d522f475Smrg
2202d522f475Smrg    XSetLineAttributes(screen->display, gc2,
2203d522f475Smrg		       (flags & BOLD)
2204d522f475Smrg		       ? ((font_height > 12)
2205d522f475Smrg			  ? font_height / 12
2206d522f475Smrg			  : 1)
2207d522f475Smrg		       : ((font_height > 16)
2208d522f475Smrg			  ? font_height / 16
2209d522f475Smrg			  : 1),
2210d522f475Smrg		       LineSolid,
2211d522f475Smrg		       CapProjecting,
2212d522f475Smrg		       JoinMiter);
2213d522f475Smrg
2214d522f475Smrg    if (ch == 1) {		/* diamond */
2215d522f475Smrg	XPoint points[5];
2216d522f475Smrg	int npoints = 5, n;
2217d522f475Smrg
2218d522f475Smrg	points[0].x = MID_WIDE;
2219d522f475Smrg	points[0].y = BOX_HIGH / 4;
2220d522f475Smrg
2221d522f475Smrg	points[1].x = 8 * BOX_WIDE / 8;
2222d522f475Smrg	points[1].y = MID_HIGH;
2223d522f475Smrg
2224d522f475Smrg	points[2].x = points[0].x;
2225d522f475Smrg	points[2].y = 3 * BOX_HIGH / 4;
2226d522f475Smrg
2227d522f475Smrg	points[3].x = 0 * BOX_WIDE / 8;
2228d522f475Smrg	points[3].y = points[1].y;
2229d522f475Smrg
2230d522f475Smrg	points[4].x = points[0].x;
2231d522f475Smrg	points[4].y = points[0].y;
2232d522f475Smrg
2233d522f475Smrg	for (n = 0; n < npoints; ++n) {
2234d522f475Smrg	    SCALE_X(points[n].x);
2235d522f475Smrg	    SCALE_Y(points[n].y);
2236d522f475Smrg	    points[n].x += x;
2237d522f475Smrg	    points[n].y += y;
2238d522f475Smrg	}
2239d522f475Smrg
2240d522f475Smrg	XFillPolygon(screen->display,
2241d522f475Smrg		     VWindow(screen), gc2,
2242d522f475Smrg		     points, npoints,
2243d522f475Smrg		     Convex, CoordModeOrigin);
2244d522f475Smrg    } else if (ch == 7) {	/* degrees */
2245d522f475Smrg	unsigned width = (BOX_WIDE / 3);
2246956cc18dSsnj	int x_coord = MID_WIDE - (int) (width / 2);
2247956cc18dSsnj	int y_coord = MID_HIGH - (int) width;
2248d522f475Smrg
2249d522f475Smrg	SCALE_X(x_coord);
2250d522f475Smrg	SCALE_Y(y_coord);
2251d522f475Smrg	SCALE_X(width);
2252d522f475Smrg
2253d522f475Smrg	XDrawArc(screen->display,
2254d522f475Smrg		 VWindow(screen), gc2,
2255d522f475Smrg		 x + x_coord, y + y_coord, width, width,
2256d522f475Smrg		 0,
2257d522f475Smrg		 360 * 64);
2258d522f475Smrg    } else if (ch == 0x1f) {	/* bullet */
2259d522f475Smrg	unsigned width = 7 * BOX_WIDE / 10;
2260956cc18dSsnj	int x_coord = MID_WIDE - (int) (width / 3);
2261956cc18dSsnj	int y_coord = MID_HIGH - (int) (width / 3);
2262d522f475Smrg
2263d522f475Smrg	SCALE_X(x_coord);
2264d522f475Smrg	SCALE_Y(y_coord);
2265d522f475Smrg	SCALE_X(width);
2266d522f475Smrg
2267d522f475Smrg	XDrawArc(screen->display,
2268d522f475Smrg		 VWindow(screen), gc2,
2269d522f475Smrg		 x + x_coord, y + y_coord, width, width,
2270d522f475Smrg		 0,
2271d522f475Smrg		 360 * 64);
2272d522f475Smrg    } else if (ch < (sizeof(lines) / sizeof(lines[0]))
2273d522f475Smrg	       && (p = lines[ch]) != 0) {
2274956cc18dSsnj	int coord[4];
2275d522f475Smrg	int n = 0;
2276d522f475Smrg	while (*p >= 0) {
2277d522f475Smrg	    coord[n++] = *p++;
2278d522f475Smrg	    if (n == 4) {
2279d522f475Smrg		SCALE_X(coord[0]);
2280d522f475Smrg		SCALE_Y(coord[1]);
2281d522f475Smrg		SCALE_X(coord[2]);
2282d522f475Smrg		SCALE_Y(coord[3]);
2283d522f475Smrg		XDrawLine(screen->display,
2284d522f475Smrg			  VWindow(screen), gc2,
2285d522f475Smrg			  x + coord[0], y + coord[1],
2286d522f475Smrg			  x + coord[2], y + coord[3]);
2287d522f475Smrg		n = 0;
2288d522f475Smrg	    }
2289d522f475Smrg	}
2290d522f475Smrg    } else if (screen->force_all_chars) {
2291d522f475Smrg	/* bounding rectangle, for debugging */
2292d522f475Smrg	XDrawRectangle(screen->display, VWindow(screen), gc2, x, y,
2293d522f475Smrg		       font_width - 1,
2294d522f475Smrg		       font_height - 1);
2295d522f475Smrg    }
2296d522f475Smrg}
2297d522f475Smrg
2298d522f475Smrg#if OPT_RENDERFONT
2299d522f475Smrg
2300d522f475Smrg/*
2301d522f475Smrg * Check if the given character has a glyph known to Xft.
2302d522f475Smrg *
2303d522f475Smrg * see xc/lib/Xft/xftglyphs.c
2304d522f475Smrg */
2305d522f475SmrgBool
2306d522f475SmrgxtermXftMissing(XtermWidget xw, XftFont * font, unsigned wc)
2307d522f475Smrg{
2308d522f475Smrg    Bool result = False;
2309d522f475Smrg
2310d522f475Smrg    if (font != 0) {
2311956cc18dSsnj	TScreen *screen = TScreenOf(xw);
2312956cc18dSsnj	if (!XftGlyphExists(screen->display, font, wc)) {
2313d522f475Smrg#if OPT_WIDE_CHARS
2314d522f475Smrg	    TRACE(("xtermXftMissing %d (dec=%#x, ucs=%#x)\n",
2315d522f475Smrg		   wc, ucs2dec(wc), dec2ucs(wc)));
2316d522f475Smrg#else
2317d522f475Smrg	    TRACE(("xtermXftMissing %d\n", wc));
2318d522f475Smrg#endif
2319d522f475Smrg	    result = True;
2320d522f475Smrg	}
2321d522f475Smrg    }
2322d522f475Smrg    return result;
2323d522f475Smrg}
2324d522f475Smrg#endif /* OPT_RENDERFONT && OPT_WIDE_CHARS */
2325d522f475Smrg
2326d522f475Smrg#endif /* OPT_BOX_CHARS */
2327d522f475Smrg
2328d522f475Smrg#if OPT_WIDE_CHARS
2329d522f475Smrg#define MY_UCS(ucs,dec) case ucs: result = dec; break
2330d522f475Smrgunsigned
2331d522f475Smrgucs2dec(unsigned ch)
2332d522f475Smrg{
2333d522f475Smrg    unsigned result = ch;
2334d522f475Smrg    if ((ch > 127)
2335d522f475Smrg	&& (ch != UCS_REPL)) {
2336d522f475Smrg	switch (ch) {
2337d522f475Smrg	    MY_UCS(0x25ae, 0);	/* black vertical rectangle                   */
2338d522f475Smrg	    MY_UCS(0x25c6, 1);	/* black diamond                              */
2339d522f475Smrg	    MY_UCS(0x2592, 2);	/* medium shade                               */
2340d522f475Smrg	    MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation           */
2341d522f475Smrg	    MY_UCS(0x240c, 4);	/* symbol for form feed                       */
2342d522f475Smrg	    MY_UCS(0x240d, 5);	/* symbol for carriage return                 */
2343d522f475Smrg	    MY_UCS(0x240a, 6);	/* symbol for line feed                       */
2344d522f475Smrg	    MY_UCS(0x00b0, 7);	/* degree sign                                */
2345d522f475Smrg	    MY_UCS(0x00b1, 8);	/* plus-minus sign                            */
2346d522f475Smrg	    MY_UCS(0x2424, 9);	/* symbol for newline                         */
2347d522f475Smrg	    MY_UCS(0x240b, 10);	/* symbol for vertical tabulation             */
2348d522f475Smrg	    MY_UCS(0x2518, 11);	/* box drawings light up and left             */
2349d522f475Smrg	    MY_UCS(0x2510, 12);	/* box drawings light down and left           */
2350d522f475Smrg	    MY_UCS(0x250c, 13);	/* box drawings light down and right          */
2351d522f475Smrg	    MY_UCS(0x2514, 14);	/* box drawings light up and right            */
2352d522f475Smrg	    MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
2353d522f475Smrg	    MY_UCS(0x23ba, 16);	/* box drawings scan 1                        */
2354d522f475Smrg	    MY_UCS(0x23bb, 17);	/* box drawings scan 3                        */
2355d522f475Smrg	    MY_UCS(0x2500, 18);	/* box drawings light horizontal              */
2356d522f475Smrg	    MY_UCS(0x23bc, 19);	/* box drawings scan 7                        */
2357d522f475Smrg	    MY_UCS(0x23bd, 20);	/* box drawings scan 9                        */
2358d522f475Smrg	    MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
2359d522f475Smrg	    MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
2360d522f475Smrg	    MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
2361d522f475Smrg	    MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
2362d522f475Smrg	    MY_UCS(0x2502, 25);	/* box drawings light vertical                */
2363d522f475Smrg	    MY_UCS(0x2264, 26);	/* less-than or equal to                      */
2364d522f475Smrg	    MY_UCS(0x2265, 27);	/* greater-than or equal to                   */
2365d522f475Smrg	    MY_UCS(0x03c0, 28);	/* greek small letter pi                      */
2366d522f475Smrg	    MY_UCS(0x2260, 29);	/* not equal to                               */
2367d522f475Smrg	    MY_UCS(0x00a3, 30);	/* pound sign                                 */
2368d522f475Smrg	    MY_UCS(0x00b7, 31);	/* middle dot                                 */
2369d522f475Smrg	}
2370d522f475Smrg    }
2371d522f475Smrg    return result;
2372d522f475Smrg}
2373d522f475Smrg
2374d522f475Smrg#undef  MY_UCS
2375d522f475Smrg#define MY_UCS(ucs,dec) case dec: result = ucs; break
2376d522f475Smrg
2377d522f475Smrgunsigned
2378d522f475Smrgdec2ucs(unsigned ch)
2379d522f475Smrg{
2380d522f475Smrg    unsigned result = ch;
2381d522f475Smrg    if (xtermIsDecGraphic(ch)) {
2382d522f475Smrg	switch (ch) {
2383d522f475Smrg	    MY_UCS(0x25ae, 0);	/* black vertical rectangle                   */
2384d522f475Smrg	    MY_UCS(0x25c6, 1);	/* black diamond                              */
2385d522f475Smrg	    MY_UCS(0x2592, 2);	/* medium shade                               */
2386d522f475Smrg	    MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation           */
2387d522f475Smrg	    MY_UCS(0x240c, 4);	/* symbol for form feed                       */
2388d522f475Smrg	    MY_UCS(0x240d, 5);	/* symbol for carriage return                 */
2389d522f475Smrg	    MY_UCS(0x240a, 6);	/* symbol for line feed                       */
2390d522f475Smrg	    MY_UCS(0x00b0, 7);	/* degree sign                                */
2391d522f475Smrg	    MY_UCS(0x00b1, 8);	/* plus-minus sign                            */
2392d522f475Smrg	    MY_UCS(0x2424, 9);	/* symbol for newline                         */
2393d522f475Smrg	    MY_UCS(0x240b, 10);	/* symbol for vertical tabulation             */
2394d522f475Smrg	    MY_UCS(0x2518, 11);	/* box drawings light up and left             */
2395d522f475Smrg	    MY_UCS(0x2510, 12);	/* box drawings light down and left           */
2396d522f475Smrg	    MY_UCS(0x250c, 13);	/* box drawings light down and right          */
2397d522f475Smrg	    MY_UCS(0x2514, 14);	/* box drawings light up and right            */
2398d522f475Smrg	    MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
2399d522f475Smrg	    MY_UCS(0x23ba, 16);	/* box drawings scan 1                        */
2400d522f475Smrg	    MY_UCS(0x23bb, 17);	/* box drawings scan 3                        */
2401d522f475Smrg	    MY_UCS(0x2500, 18);	/* box drawings light horizontal              */
2402d522f475Smrg	    MY_UCS(0x23bc, 19);	/* box drawings scan 7                        */
2403d522f475Smrg	    MY_UCS(0x23bd, 20);	/* box drawings scan 9                        */
2404d522f475Smrg	    MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
2405d522f475Smrg	    MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
2406d522f475Smrg	    MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
2407d522f475Smrg	    MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
2408d522f475Smrg	    MY_UCS(0x2502, 25);	/* box drawings light vertical                */
2409d522f475Smrg	    MY_UCS(0x2264, 26);	/* less-than or equal to                      */
2410d522f475Smrg	    MY_UCS(0x2265, 27);	/* greater-than or equal to                   */
2411d522f475Smrg	    MY_UCS(0x03c0, 28);	/* greek small letter pi                      */
2412d522f475Smrg	    MY_UCS(0x2260, 29);	/* not equal to                               */
2413d522f475Smrg	    MY_UCS(0x00a3, 30);	/* pound sign                                 */
2414d522f475Smrg	    MY_UCS(0x00b7, 31);	/* middle dot                                 */
2415d522f475Smrg	}
2416d522f475Smrg    }
2417d522f475Smrg    return result;
2418d522f475Smrg}
2419d522f475Smrg
2420d522f475Smrg#endif /* OPT_WIDE_CHARS */
2421d522f475Smrg
2422d522f475Smrg#if OPT_SHIFT_FONTS
2423d522f475Smrgstatic void
2424d522f475SmrglookupOneFontSize(XtermWidget xw, int fontnum)
2425d522f475Smrg{
2426d522f475Smrg    TScreen *screen = TScreenOf(xw);
2427d522f475Smrg
2428d522f475Smrg    if (screen->menu_font_sizes[fontnum] == 0) {
2429d522f475Smrg	XTermFonts fnt;
2430d522f475Smrg
2431d522f475Smrg	memset(&fnt, 0, sizeof(fnt));
2432d522f475Smrg	screen->menu_font_sizes[fontnum] = -1;
2433956cc18dSsnj	if (xtermOpenFont(xw, screen->MenuFontName(fontnum), &fnt, fwAlways, True)) {
2434d522f475Smrg	    screen->menu_font_sizes[fontnum] = FontSize(fnt.fs);
2435d522f475Smrg	    TRACE(("menu_font_sizes[%d] = %ld\n", fontnum,
2436d522f475Smrg		   screen->menu_font_sizes[fontnum]));
2437d522f475Smrg	    xtermCloseFont(xw, &fnt);
2438d522f475Smrg	}
2439d522f475Smrg    }
2440d522f475Smrg}
2441d522f475Smrg
2442d522f475Smrg/*
2443d522f475Smrg * Cache the font-sizes so subsequent larger/smaller font actions will go fast.
2444d522f475Smrg */
2445d522f475Smrgstatic void
2446d522f475SmrglookupFontSizes(XtermWidget xw)
2447d522f475Smrg{
2448d522f475Smrg    int n;
2449d522f475Smrg
2450d522f475Smrg    for (n = 0; n < NMENUFONTS; n++) {
2451d522f475Smrg	lookupOneFontSize(xw, n);
2452d522f475Smrg    }
2453d522f475Smrg}
2454d522f475Smrg
24552eaa94a1Schristos#if OPT_RENDERFONT
24562eaa94a1Schristos#define NMENU_RENDERFONTS (NMENUFONTS - 2)	/* no selection or escape */
24572eaa94a1Schristosstatic Boolean
24582eaa94a1SchristosuseFaceSizes(XtermWidget xw)
24592eaa94a1Schristos{
24602eaa94a1Schristos    Boolean result = False;
24612eaa94a1Schristos    int n;
24622eaa94a1Schristos
24632eaa94a1Schristos    if (UsingRenderFont(xw)) {
24642eaa94a1Schristos	result = True;
24652eaa94a1Schristos	for (n = 0; n < NMENU_RENDERFONTS; ++n) {
24662eaa94a1Schristos	    if (xw->misc.face_size[n] <= 0.0) {
24672eaa94a1Schristos		result = False;
24682eaa94a1Schristos		break;
24692eaa94a1Schristos	    }
24702eaa94a1Schristos	}
2471956cc18dSsnj	if (!result) {
2472956cc18dSsnj	    Boolean broken_fonts = True;
2473956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
2474956cc18dSsnj	    int first = screen->menu_font_sizes[0];
2475956cc18dSsnj
2476956cc18dSsnj	    lookupFontSizes(xw);
2477956cc18dSsnj	    for (n = 0; n < NMENUFONTS; n++) {
2478956cc18dSsnj		if (screen->menu_font_sizes[n] > 0
2479956cc18dSsnj		    && screen->menu_font_sizes[n] != first) {
2480956cc18dSsnj		    broken_fonts = False;
2481956cc18dSsnj		    break;
2482956cc18dSsnj		}
2483956cc18dSsnj	    }
2484956cc18dSsnj
2485956cc18dSsnj	    /*
2486956cc18dSsnj	     * Workaround for breakage in font-packages - check if all of the
2487956cc18dSsnj	     * bitmap font sizes are the same, and if we're using TrueType
2488956cc18dSsnj	     * fonts.
2489956cc18dSsnj	     */
2490956cc18dSsnj	    if (broken_fonts) {
2491956cc18dSsnj		float lo_value = (float) 9.0e9;
2492956cc18dSsnj		float hi_value = (float) 0.0;
2493956cc18dSsnj		float value;
2494956cc18dSsnj
2495956cc18dSsnj		TRACE(("bitmap fonts are broken - set faceSize resources\n"));
2496956cc18dSsnj		for (n = 0; n < NMENUFONTS; n++) {
2497956cc18dSsnj		    value = xw->misc.face_size[n];
2498956cc18dSsnj		    if (value > 0.0) {
2499956cc18dSsnj			if (lo_value > value)
2500956cc18dSsnj			    lo_value = value;
2501956cc18dSsnj			if (hi_value < value)
2502956cc18dSsnj			    hi_value = value;
2503956cc18dSsnj		    }
2504956cc18dSsnj		}
2505956cc18dSsnj
2506956cc18dSsnj		if (hi_value <= 0.0)
2507956cc18dSsnj		    sscanf(DEFFACESIZE, "%f", &value);
2508956cc18dSsnj		else
2509956cc18dSsnj		    value = (float) ((hi_value + lo_value) / 2.0);
2510956cc18dSsnj		if (value <= 0)
2511956cc18dSsnj		    value = (float) 14.0;
2512956cc18dSsnj
2513956cc18dSsnj		for (n = 0; n < NMENUFONTS; n++) {
2514956cc18dSsnj		    TRACE(("setting faceSize%d %.1f\n", n, value));
2515956cc18dSsnj		    xw->misc.face_size[n] = value;
2516956cc18dSsnj		    value = (float) (value * 1.1);
2517956cc18dSsnj		}
2518956cc18dSsnj		result = True;
2519956cc18dSsnj	    }
2520956cc18dSsnj	}
25212eaa94a1Schristos    }
25222eaa94a1Schristos    return result;
25232eaa94a1Schristos}
25242eaa94a1Schristos#endif
25252eaa94a1Schristos
2526d522f475Smrg/*
2527d522f475Smrg * Find the index of a larger/smaller font (according to the sign of 'relative'
2528d522f475Smrg * and its magnitude), starting from the 'old' index.
2529d522f475Smrg */
2530d522f475Smrgint
2531d522f475SmrglookupRelativeFontSize(XtermWidget xw, int old, int relative)
2532d522f475Smrg{
2533d522f475Smrg    TScreen *screen = TScreenOf(xw);
2534d522f475Smrg    int n, m = -1;
2535d522f475Smrg
25362eaa94a1Schristos    TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative));
2537d522f475Smrg    if (!IsIcon(screen)) {
25382eaa94a1Schristos#if OPT_RENDERFONT
25392eaa94a1Schristos	if (useFaceSizes(xw)) {
25402eaa94a1Schristos	    TRACE(("...using FaceSize\n"));
25412eaa94a1Schristos	    if (relative != 0) {
25422eaa94a1Schristos		for (n = 0; n < NMENU_RENDERFONTS; ++n) {
25432eaa94a1Schristos		    if (xw->misc.face_size[n] > 0 &&
25442eaa94a1Schristos			xw->misc.face_size[n] != xw->misc.face_size[old]) {
25452eaa94a1Schristos			int cmp_0 = ((xw->misc.face_size[n] >
25462eaa94a1Schristos				      xw->misc.face_size[old])
25472eaa94a1Schristos				     ? relative
25482eaa94a1Schristos				     : -relative);
25492eaa94a1Schristos			int cmp_m = ((m < 0)
25502eaa94a1Schristos				     ? 1
25512eaa94a1Schristos				     : ((xw->misc.face_size[n] <
25522eaa94a1Schristos					 xw->misc.face_size[m])
25532eaa94a1Schristos					? relative
25542eaa94a1Schristos					: -relative));
25552eaa94a1Schristos			if (cmp_0 > 0 && cmp_m > 0) {
25562eaa94a1Schristos			    m = n;
25572eaa94a1Schristos			}
2558d522f475Smrg		    }
2559d522f475Smrg		}
2560d522f475Smrg	    }
25612eaa94a1Schristos	} else
25622eaa94a1Schristos#endif
25632eaa94a1Schristos	{
25642eaa94a1Schristos	    TRACE(("...using bitmap areas\n"));
25652eaa94a1Schristos	    lookupFontSizes(xw);
25662eaa94a1Schristos	    if (relative != 0) {
25672eaa94a1Schristos		for (n = 0; n < NMENUFONTS; ++n) {
25682eaa94a1Schristos		    if (screen->menu_font_sizes[n] > 0 &&
25692eaa94a1Schristos			screen->menu_font_sizes[n] !=
25702eaa94a1Schristos			screen->menu_font_sizes[old]) {
25712eaa94a1Schristos			int cmp_0 = ((screen->menu_font_sizes[n] >
25722eaa94a1Schristos				      screen->menu_font_sizes[old])
25732eaa94a1Schristos				     ? relative
25742eaa94a1Schristos				     : -relative);
25752eaa94a1Schristos			int cmp_m = ((m < 0)
25762eaa94a1Schristos				     ? 1
25772eaa94a1Schristos				     : ((screen->menu_font_sizes[n] <
25782eaa94a1Schristos					 screen->menu_font_sizes[m])
25792eaa94a1Schristos					? relative
25802eaa94a1Schristos					: -relative));
25812eaa94a1Schristos			if (cmp_0 > 0 && cmp_m > 0) {
25822eaa94a1Schristos			    m = n;
25832eaa94a1Schristos			}
25842eaa94a1Schristos		    }
25852eaa94a1Schristos		}
2586d522f475Smrg	    }
2587d522f475Smrg	}
25882eaa94a1Schristos	TRACE(("...new index %d\n", m));
25892eaa94a1Schristos	if (m >= 0) {
25902eaa94a1Schristos	    if (relative > 1)
25912eaa94a1Schristos		m = lookupRelativeFontSize(xw, m, relative - 1);
25922eaa94a1Schristos	    else if (relative < -1)
25932eaa94a1Schristos		m = lookupRelativeFontSize(xw, m, relative + 1);
25942eaa94a1Schristos	}
2595d522f475Smrg    }
2596d522f475Smrg    return m;
2597d522f475Smrg}
2598d522f475Smrg
2599d522f475Smrg/* ARGSUSED */
2600d522f475Smrgvoid
2601d522f475SmrgHandleLargerFont(Widget w GCC_UNUSED,
2602d522f475Smrg		 XEvent * event GCC_UNUSED,
2603d522f475Smrg		 String * params GCC_UNUSED,
2604d522f475Smrg		 Cardinal *param_count GCC_UNUSED)
2605d522f475Smrg{
2606956cc18dSsnj    XtermWidget xw;
2607d522f475Smrg
2608956cc18dSsnj    TRACE(("Handle larger-vt-font for %p\n", w));
2609956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
2610d522f475Smrg	if (xw->misc.shift_fonts) {
2611956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
2612d522f475Smrg	    int m;
2613d522f475Smrg
2614d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, 1);
2615d522f475Smrg	    if (m >= 0) {
2616d522f475Smrg		SetVTFont(xw, m, True, NULL);
2617d522f475Smrg	    } else {
2618d522f475Smrg		Bell(XkbBI_MinorError, 0);
2619d522f475Smrg	    }
2620d522f475Smrg	}
2621d522f475Smrg    }
2622d522f475Smrg}
2623d522f475Smrg
2624d522f475Smrg/* ARGSUSED */
2625d522f475Smrgvoid
2626d522f475SmrgHandleSmallerFont(Widget w GCC_UNUSED,
2627d522f475Smrg		  XEvent * event GCC_UNUSED,
2628d522f475Smrg		  String * params GCC_UNUSED,
2629d522f475Smrg		  Cardinal *param_count GCC_UNUSED)
2630d522f475Smrg{
2631956cc18dSsnj    XtermWidget xw;
2632d522f475Smrg
2633956cc18dSsnj    TRACE(("Handle smaller-vt-font for %p\n", w));
2634956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
2635d522f475Smrg	if (xw->misc.shift_fonts) {
2636956cc18dSsnj	    TScreen *screen = TScreenOf(xw);
2637d522f475Smrg	    int m;
2638d522f475Smrg
2639d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, -1);
2640d522f475Smrg	    if (m >= 0) {
2641d522f475Smrg		SetVTFont(xw, m, True, NULL);
2642d522f475Smrg	    } else {
2643d522f475Smrg		Bell(XkbBI_MinorError, 0);
2644d522f475Smrg	    }
2645d522f475Smrg	}
2646d522f475Smrg    }
2647d522f475Smrg}
2648d522f475Smrg#endif
2649d522f475Smrg
2650d522f475Smrgint
2651d522f475SmrgxtermGetFont(const char *param)
2652d522f475Smrg{
2653d522f475Smrg    int fontnum;
2654d522f475Smrg
2655d522f475Smrg    switch (param[0]) {
2656d522f475Smrg    case 'd':
2657d522f475Smrg    case 'D':
2658d522f475Smrg    case '0':
2659d522f475Smrg	fontnum = fontMenu_default;
2660d522f475Smrg	break;
2661d522f475Smrg    case '1':
2662d522f475Smrg	fontnum = fontMenu_font1;
2663d522f475Smrg	break;
2664d522f475Smrg    case '2':
2665d522f475Smrg	fontnum = fontMenu_font2;
2666d522f475Smrg	break;
2667d522f475Smrg    case '3':
2668d522f475Smrg	fontnum = fontMenu_font3;
2669d522f475Smrg	break;
2670d522f475Smrg    case '4':
2671d522f475Smrg	fontnum = fontMenu_font4;
2672d522f475Smrg	break;
2673d522f475Smrg    case '5':
2674d522f475Smrg	fontnum = fontMenu_font5;
2675d522f475Smrg	break;
2676d522f475Smrg    case '6':
2677d522f475Smrg	fontnum = fontMenu_font6;
2678d522f475Smrg	break;
2679d522f475Smrg    case 'e':
2680d522f475Smrg    case 'E':
2681d522f475Smrg	fontnum = fontMenu_fontescape;
2682d522f475Smrg	break;
2683d522f475Smrg    case 's':
2684d522f475Smrg    case 'S':
2685d522f475Smrg	fontnum = fontMenu_fontsel;
2686d522f475Smrg	break;
2687d522f475Smrg    default:
2688d522f475Smrg	fontnum = -1;
2689d522f475Smrg	break;
2690d522f475Smrg    }
2691d522f475Smrg    return fontnum;
2692d522f475Smrg}
2693d522f475Smrg
2694d522f475Smrg/* ARGSUSED */
2695d522f475Smrgvoid
2696d522f475SmrgHandleSetFont(Widget w GCC_UNUSED,
2697d522f475Smrg	      XEvent * event GCC_UNUSED,
2698d522f475Smrg	      String * params,
2699d522f475Smrg	      Cardinal *param_count)
2700d522f475Smrg{
2701956cc18dSsnj    XtermWidget xw;
2702956cc18dSsnj
2703956cc18dSsnj    if ((xw = getXtermWidget(w)) != 0) {
2704d522f475Smrg	int fontnum;
2705d522f475Smrg	VTFontNames fonts;
2706d522f475Smrg
2707d522f475Smrg	memset(&fonts, 0, sizeof(fonts));
2708d522f475Smrg
2709d522f475Smrg	if (*param_count == 0) {
2710d522f475Smrg	    fontnum = fontMenu_default;
2711d522f475Smrg	} else {
2712d522f475Smrg	    Cardinal maxparams = 1;	/* total number of params allowed */
2713d522f475Smrg	    int result = xtermGetFont(params[0]);
2714d522f475Smrg
2715d522f475Smrg	    switch (result) {
2716d522f475Smrg	    case fontMenu_default:	/* FALLTHRU */
2717d522f475Smrg	    case fontMenu_font1:	/* FALLTHRU */
2718d522f475Smrg	    case fontMenu_font2:	/* FALLTHRU */
2719d522f475Smrg	    case fontMenu_font3:	/* FALLTHRU */
2720d522f475Smrg	    case fontMenu_font4:	/* FALLTHRU */
2721d522f475Smrg	    case fontMenu_font5:	/* FALLTHRU */
2722d522f475Smrg	    case fontMenu_font6:	/* FALLTHRU */
2723d522f475Smrg		break;
2724d522f475Smrg	    case fontMenu_fontescape:
2725d522f475Smrg#if OPT_WIDE_CHARS
2726d522f475Smrg		maxparams = 5;
2727d522f475Smrg#else
2728d522f475Smrg		maxparams = 3;
2729d522f475Smrg#endif
2730d522f475Smrg		break;
2731d522f475Smrg	    case fontMenu_fontsel:
2732d522f475Smrg		maxparams = 2;
2733d522f475Smrg		break;
2734d522f475Smrg	    default:
2735d522f475Smrg		Bell(XkbBI_MinorError, 0);
2736d522f475Smrg		return;
2737d522f475Smrg	    }
2738d522f475Smrg	    fontnum = result;
2739d522f475Smrg
2740d522f475Smrg	    if (*param_count > maxparams) {	/* see if extra args given */
2741d522f475Smrg		Bell(XkbBI_MinorError, 0);
2742d522f475Smrg		return;
2743d522f475Smrg	    }
2744d522f475Smrg	    switch (*param_count) {	/* assign 'em */
2745d522f475Smrg#if OPT_WIDE_CHARS
2746d522f475Smrg	    case 5:
2747d522f475Smrg		fonts.f_wb = params[4];
2748d522f475Smrg		/* FALLTHRU */
2749d522f475Smrg	    case 4:
2750d522f475Smrg		fonts.f_w = params[3];
2751d522f475Smrg		/* FALLTHRU */
2752d522f475Smrg#endif
2753d522f475Smrg	    case 3:
2754d522f475Smrg		fonts.f_b = params[2];
2755d522f475Smrg		/* FALLTHRU */
2756d522f475Smrg	    case 2:
2757d522f475Smrg		fonts.f_n = params[1];
2758d522f475Smrg		break;
2759d522f475Smrg	    }
2760d522f475Smrg	}
2761d522f475Smrg
2762956cc18dSsnj	SetVTFont(xw, fontnum, True, &fonts);
2763d522f475Smrg    }
2764d522f475Smrg}
2765d522f475Smrg
2766d522f475Smrgvoid
2767d522f475SmrgSetVTFont(XtermWidget xw,
2768d522f475Smrg	  int which,
2769d522f475Smrg	  Bool doresize,
2770d522f475Smrg	  const VTFontNames * fonts)
2771d522f475Smrg{
2772956cc18dSsnj    TScreen *screen = TScreenOf(xw);
2773d522f475Smrg
2774d522f475Smrg    TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which,
2775d522f475Smrg	   (fonts && fonts->f_n) ? fonts->f_n : "<null>",
2776d522f475Smrg	   (fonts && fonts->f_b) ? fonts->f_b : "<null>"));
2777d522f475Smrg
2778d522f475Smrg    if (IsIcon(screen)) {
2779d522f475Smrg	Bell(XkbBI_MinorError, 0);
2780d522f475Smrg    } else if (which >= 0 && which < NMENUFONTS) {
2781d522f475Smrg	VTFontNames myfonts;
2782d522f475Smrg
2783d522f475Smrg	memset(&myfonts, 0, sizeof(myfonts));
2784d522f475Smrg	if (fonts != 0)
2785d522f475Smrg	    myfonts = *fonts;
2786d522f475Smrg
2787d522f475Smrg	if (which == fontMenu_fontsel) {	/* go get the selection */
2788d522f475Smrg	    FindFontSelection(xw, myfonts.f_n, False);
2789d522f475Smrg	    return;
2790d522f475Smrg	} else {
2791d522f475Smrg	    int oldFont = screen->menu_font_number;
2792d522f475Smrg
2793d522f475Smrg#define USE_CACHED(field, name) \
2794d522f475Smrg	    if (myfonts.field == 0) { \
2795d522f475Smrg		myfonts.field = screen->menu_font_names[which][name]; \
2796d522f475Smrg		TRACE(("set myfonts." #field " from menu_font_names[%d][" #name "] %s\n", \
2797d522f475Smrg		       which, NonNull(myfonts.field))); \
2798d522f475Smrg	    } else { \
2799d522f475Smrg		TRACE(("set myfonts." #field " reused\n")); \
2800d522f475Smrg	    }
2801d522f475Smrg	    USE_CACHED(f_n, fNorm);
2802d522f475Smrg	    USE_CACHED(f_b, fBold);
2803d522f475Smrg#if OPT_WIDE_CHARS
2804d522f475Smrg	    USE_CACHED(f_w, fWide);
2805d522f475Smrg	    USE_CACHED(f_wb, fWBold);
2806d522f475Smrg#endif
2807d522f475Smrg	    if (xtermLoadFont(xw,
2808d522f475Smrg			      &myfonts,
2809d522f475Smrg			      doresize, which)) {
2810d522f475Smrg		return;
2811d522f475Smrg	    } else {
2812d522f475Smrg		xtermLoadFont(xw,
2813d522f475Smrg			      xtermFontName(screen->MenuFontName(oldFont)),
2814d522f475Smrg			      doresize, oldFont);
2815d522f475Smrg	    }
2816d522f475Smrg	}
2817d522f475Smrg    }
2818d522f475Smrg
2819d522f475Smrg    Bell(XkbBI_MinorError, 0);
2820d522f475Smrg    return;
2821d522f475Smrg}
2822