fontutils.c revision d522f475
1d522f475Smrg/* $XTermId: fontutils.c,v 1.272 2008/04/17 23:23:37 tom Exp $ */
2d522f475Smrg
3d522f475Smrg/************************************************************
4d522f475Smrg
5d522f475SmrgCopyright 1998-2007,2008 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
122d522f475Smrgstatic Bool
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
201d522f475Smrg/*
202d522f475Smrg * Gets the font properties from a given font structure.  We use the FONT name
203d522f475Smrg * to find them out, since that seems easier.
204d522f475Smrg *
205d522f475Smrg * Returns a pointer to a static FontNameProperties structure
206d522f475Smrg * or NULL on error.
207d522f475Smrg */
208d522f475Smrgstatic FontNameProperties *
209d522f475Smrgget_font_name_props(Display * dpy, XFontStruct * fs, char *result)
210d522f475Smrg{
211d522f475Smrg    static FontNameProperties props;
212d522f475Smrg    static char *last_name;
213d522f475Smrg
214d522f475Smrg    XFontProp *fp;
215d522f475Smrg    int i;
216d522f475Smrg    Atom fontatom = XInternAtom(dpy, "FONT", False);
217d522f475Smrg    char *name;
218d522f475Smrg    char *str;
219d522f475Smrg
220d522f475Smrg    /*
221d522f475Smrg     * first get the full font name
222d522f475Smrg     */
223d522f475Smrg    for (name = 0, i = 0, fp = fs->properties;
224d522f475Smrg	 i < fs->n_properties;
225d522f475Smrg	 i++, fp++)
226d522f475Smrg	if (fp->name == fontatom)
227d522f475Smrg	    name = XGetAtomName(dpy, fp->card32);
228d522f475Smrg
229d522f475Smrg    if (name == 0)
230d522f475Smrg	return 0;
231d522f475Smrg
232d522f475Smrg    /*
233d522f475Smrg     * XGetAtomName allocates memory - don't leak
234d522f475Smrg     */
235d522f475Smrg    if (last_name != 0)
236d522f475Smrg	XFree(last_name);
237d522f475Smrg    last_name = name;
238d522f475Smrg
239d522f475Smrg    if (result != 0) {
240d522f475Smrg	if (strlen(name) < MAX_FONTNAME - 1) {
241d522f475Smrg	    strcpy(result, name);
242d522f475Smrg	} else {
243d522f475Smrg	    TRACE(("fontname too large: %s\n", name));
244d522f475Smrg	    return 0;
245d522f475Smrg	}
246d522f475Smrg    }
247d522f475Smrg
248d522f475Smrg    /*
249d522f475Smrg     * Now split it up into parts and put them in
250d522f475Smrg     * their places. Since we are using parts of
251d522f475Smrg     * the original string, we must not free the Atom Name
252d522f475Smrg     */
253d522f475Smrg
254d522f475Smrg    /* registry, foundry, family */
255d522f475Smrg    if ((props.beginning = n_fields(&name, 1, 3)) == 0)
256d522f475Smrg	return 0;
257d522f475Smrg
258d522f475Smrg    /* weight is the next */
259d522f475Smrg    if ((props.weight = n_fields(&name, 1, 1)) == 0)
260d522f475Smrg	return 0;
261d522f475Smrg
262d522f475Smrg    /* slant */
263d522f475Smrg    if ((props.slant = n_fields(&name, 1, 1)) == 0)
264d522f475Smrg	return 0;
265d522f475Smrg
266d522f475Smrg    /* width */
267d522f475Smrg    if ((props.wideness = n_fields(&name, 1, 1)) == 0)
268d522f475Smrg	return 0;
269d522f475Smrg
270d522f475Smrg    /* add style */
271d522f475Smrg    if ((props.add_style = n_fields(&name, 1, 1)) == 0)
272d522f475Smrg	return 0;
273d522f475Smrg
274d522f475Smrg    /* pixel size */
275d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
276d522f475Smrg	return 0;
277d522f475Smrg    if ((props.pixel_size = atoi(str)) == 0)
278d522f475Smrg	return 0;
279d522f475Smrg
280d522f475Smrg    /* point size */
281d522f475Smrg    if ((props.point_size = n_fields(&name, 1, 1)) == 0)
282d522f475Smrg	return 0;
283d522f475Smrg
284d522f475Smrg    /* res_x */
285d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
286d522f475Smrg	return 0;
287d522f475Smrg    if ((props.res_x = atoi(str)) == 0)
288d522f475Smrg	return 0;
289d522f475Smrg
290d522f475Smrg    /* res_y */
291d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
292d522f475Smrg	return 0;
293d522f475Smrg    if ((props.res_y = atoi(str)) == 0)
294d522f475Smrg	return 0;
295d522f475Smrg
296d522f475Smrg    /* spacing */
297d522f475Smrg    if ((props.spacing = n_fields(&name, 1, 1)) == 0)
298d522f475Smrg	return 0;
299d522f475Smrg
300d522f475Smrg    /* average width */
301d522f475Smrg    if ((str = n_fields(&name, 1, 1)) == 0)
302d522f475Smrg	return 0;
303d522f475Smrg    if ((props.average_width = atoi(str)) == 0)
304d522f475Smrg	return 0;
305d522f475Smrg
306d522f475Smrg    /* the rest: charset registry and charset encoding */
307d522f475Smrg    props.end = name;
308d522f475Smrg
309d522f475Smrg    return &props;
310d522f475Smrg}
311d522f475Smrg
312d522f475Smrg#define ALLOCHUNK(n) ((n | 127) + 1)
313d522f475Smrg
314d522f475Smrgstatic void
315d522f475Smrgalloca_fontname(char **result, unsigned next)
316d522f475Smrg{
317d522f475Smrg    unsigned last = (*result != 0) ? strlen(*result) : 0;
318d522f475Smrg    unsigned have = (*result != 0) ? ALLOCHUNK(last) : 0;
319d522f475Smrg    unsigned want = last + next + 2;
320d522f475Smrg
321d522f475Smrg    if (want >= have) {
322d522f475Smrg	want = ALLOCHUNK(want);
323d522f475Smrg	if (last != 0) {
324d522f475Smrg	    *result = TypeRealloc(char, want, *result);
325d522f475Smrg	} else {
326d522f475Smrg	    if ((*result = TypeMallocN(char, want)) != 0)
327d522f475Smrg		**result = '\0';
328d522f475Smrg	}
329d522f475Smrg    }
330d522f475Smrg}
331d522f475Smrg
332d522f475Smrgstatic void
333d522f475Smrgappend_fontname_str(char **result, char *value)
334d522f475Smrg{
335d522f475Smrg    if (value == 0)
336d522f475Smrg	value = "*";
337d522f475Smrg    alloca_fontname(result, strlen(value));
338d522f475Smrg    if (*result != 0) {
339d522f475Smrg	if (**result != '\0')
340d522f475Smrg	    strcat(*result, "-");
341d522f475Smrg	strcat(*result, value);
342d522f475Smrg    }
343d522f475Smrg}
344d522f475Smrg
345d522f475Smrgstatic void
346d522f475Smrgappend_fontname_num(char **result, int value)
347d522f475Smrg{
348d522f475Smrg    if (value < 0) {
349d522f475Smrg	append_fontname_str(result, "*");
350d522f475Smrg    } else {
351d522f475Smrg	char temp[100];
352d522f475Smrg	sprintf(temp, "%d", value);
353d522f475Smrg	append_fontname_str(result, temp);
354d522f475Smrg    }
355d522f475Smrg}
356d522f475Smrg
357d522f475Smrg/*
358d522f475Smrg * Take the given font props and try to make a well formed font name specifying
359d522f475Smrg * the same base font and size and everything, but with different weight/width
360d522f475Smrg * according to the parameters.  The return value is allocated, should be freed
361d522f475Smrg * by the caller.
362d522f475Smrg */
363d522f475Smrgstatic char *
364d522f475Smrgderive_font_name(FontNameProperties * props,
365d522f475Smrg		 char *use_weight,
366d522f475Smrg		 int use_average_width,
367d522f475Smrg		 char *use_encoding)
368d522f475Smrg{
369d522f475Smrg    char *result = 0;
370d522f475Smrg
371d522f475Smrg    append_fontname_str(&result, props->beginning);
372d522f475Smrg    append_fontname_str(&result, use_weight);
373d522f475Smrg    append_fontname_str(&result, props->slant);
374d522f475Smrg    append_fontname_str(&result, 0);
375d522f475Smrg    append_fontname_str(&result, 0);
376d522f475Smrg    append_fontname_num(&result, props->pixel_size);
377d522f475Smrg    append_fontname_str(&result, props->point_size);
378d522f475Smrg    append_fontname_num(&result, props->res_x);
379d522f475Smrg    append_fontname_num(&result, props->res_y);
380d522f475Smrg    append_fontname_str(&result, props->spacing);
381d522f475Smrg    append_fontname_num(&result, use_average_width);
382d522f475Smrg    append_fontname_str(&result, use_encoding);
383d522f475Smrg
384d522f475Smrg    return result;
385d522f475Smrg}
386d522f475Smrg
387d522f475Smrgstatic char *
388d522f475Smrgbold_font_name(FontNameProperties * props, int use_average_width)
389d522f475Smrg{
390d522f475Smrg    return derive_font_name(props, "bold", use_average_width, props->end);
391d522f475Smrg}
392d522f475Smrg
393d522f475Smrg#if OPT_WIDE_CHARS
394d522f475Smrg#define derive_wide_font(props, weight) \
395d522f475Smrg	derive_font_name(props, weight, props->average_width * 2, "ISO10646-1")
396d522f475Smrg
397d522f475Smrgstatic char *
398d522f475Smrgwide_font_name(FontNameProperties * props)
399d522f475Smrg{
400d522f475Smrg    return derive_wide_font(props, "medium");
401d522f475Smrg}
402d522f475Smrg
403d522f475Smrgstatic char *
404d522f475Smrgwidebold_font_name(FontNameProperties * props)
405d522f475Smrg{
406d522f475Smrg    return derive_wide_font(props, "bold");
407d522f475Smrg}
408d522f475Smrg#endif /* OPT_WIDE_CHARS */
409d522f475Smrg
410d522f475Smrg#if OPT_DEC_CHRSET
411d522f475Smrg/*
412d522f475Smrg * Take the given font props and try to make a well formed font name specifying
413d522f475Smrg * the same base font but changed depending on the given attributes and chrset.
414d522f475Smrg *
415d522f475Smrg * For double width fonts, we just double the X-resolution, for double height
416d522f475Smrg * fonts we double the pixel-size and Y-resolution
417d522f475Smrg */
418d522f475Smrgchar *
419d522f475SmrgxtermSpecialFont(TScreen * screen, unsigned atts, unsigned chrset)
420d522f475Smrg{
421d522f475Smrg#if OPT_TRACE
422d522f475Smrg    static char old_spacing[80];
423d522f475Smrg    static FontNameProperties old_props;
424d522f475Smrg#endif
425d522f475Smrg    FontNameProperties *props;
426d522f475Smrg    char *result = 0;
427d522f475Smrg    char *weight;
428d522f475Smrg    int pixel_size;
429d522f475Smrg    int res_x;
430d522f475Smrg    int res_y;
431d522f475Smrg
432d522f475Smrg    props = get_font_name_props(screen->display, screen->fnts[fNorm].fs, 0);
433d522f475Smrg    if (props == 0)
434d522f475Smrg	return result;
435d522f475Smrg
436d522f475Smrg    pixel_size = props->pixel_size;
437d522f475Smrg    res_x = props->res_x;
438d522f475Smrg    res_y = props->res_y;
439d522f475Smrg    if (atts & BOLD)
440d522f475Smrg	weight = "bold";
441d522f475Smrg    else
442d522f475Smrg	weight = props->weight;
443d522f475Smrg
444d522f475Smrg    if (CSET_DOUBLE(chrset))
445d522f475Smrg	res_x *= 2;
446d522f475Smrg
447d522f475Smrg    if (chrset == CSET_DHL_TOP
448d522f475Smrg	|| chrset == CSET_DHL_BOT) {
449d522f475Smrg	res_y *= 2;
450d522f475Smrg	pixel_size *= 2;
451d522f475Smrg    }
452d522f475Smrg#if OPT_TRACE
453d522f475Smrg    if (old_props.res_x != res_x
454d522f475Smrg	|| old_props.res_x != res_y
455d522f475Smrg	|| old_props.pixel_size != pixel_size
456d522f475Smrg	|| strcmp(old_props.spacing, props->spacing)) {
457d522f475Smrg	TRACE(("xtermSpecialFont(atts = %#x, chrset = %#x)\n", atts, chrset));
458d522f475Smrg	TRACE(("res_x      = %d\n", res_x));
459d522f475Smrg	TRACE(("res_y      = %d\n", res_y));
460d522f475Smrg	TRACE(("point_size = %s\n", props->point_size));
461d522f475Smrg	TRACE(("pixel_size = %d\n", pixel_size));
462d522f475Smrg	TRACE(("spacing    = %s\n", props->spacing));
463d522f475Smrg	old_props.res_x = res_x;
464d522f475Smrg	old_props.res_x = res_y;
465d522f475Smrg	old_props.pixel_size = pixel_size;
466d522f475Smrg	old_props.spacing = strcpy(old_spacing, props->spacing);
467d522f475Smrg    }
468d522f475Smrg#endif
469d522f475Smrg
470d522f475Smrg    append_fontname_str(&result, props->beginning);
471d522f475Smrg    append_fontname_str(&result, weight);
472d522f475Smrg    append_fontname_str(&result, props->slant);
473d522f475Smrg    append_fontname_str(&result, props->wideness);
474d522f475Smrg    append_fontname_str(&result, props->add_style);
475d522f475Smrg    append_fontname_num(&result, pixel_size);
476d522f475Smrg    append_fontname_str(&result, props->point_size);
477d522f475Smrg    append_fontname_num(&result, (atts & NORESOLUTION) ? -1 : res_x);
478d522f475Smrg    append_fontname_num(&result, (atts & NORESOLUTION) ? -1 : res_y);
479d522f475Smrg    append_fontname_str(&result, props->spacing);
480d522f475Smrg    append_fontname_str(&result, 0);
481d522f475Smrg    append_fontname_str(&result, props->end);
482d522f475Smrg
483d522f475Smrg    return result;
484d522f475Smrg}
485d522f475Smrg#endif /* OPT_DEC_CHRSET */
486d522f475Smrg
487d522f475Smrg/*
488d522f475Smrg * Case-independent comparison for font-names, including wildcards.
489d522f475Smrg * XLFD allows '?' as a wildcard, but we do not handle that (no one seems
490d522f475Smrg * to use it).
491d522f475Smrg */
492d522f475Smrgstatic Bool
493d522f475Smrgsame_font_name(char *pattern, char *match)
494d522f475Smrg{
495d522f475Smrg    while (*pattern && *match) {
496d522f475Smrg	if (*pattern == *match) {
497d522f475Smrg	    pattern++;
498d522f475Smrg	    match++;
499d522f475Smrg	} else if (*pattern == '*' || *match == '*') {
500d522f475Smrg	    if (same_font_name(pattern + 1, match)) {
501d522f475Smrg		return True;
502d522f475Smrg	    } else if (same_font_name(pattern, match + 1)) {
503d522f475Smrg		return True;
504d522f475Smrg	    } else {
505d522f475Smrg		return False;
506d522f475Smrg	    }
507d522f475Smrg	} else {
508d522f475Smrg	    int p = char2lower(*pattern++);
509d522f475Smrg	    int m = char2lower(*match++);
510d522f475Smrg	    if (p != m)
511d522f475Smrg		return False;
512d522f475Smrg	}
513d522f475Smrg    }
514d522f475Smrg    return (*pattern == *match);	/* both should be NUL */
515d522f475Smrg}
516d522f475Smrg
517d522f475Smrg/*
518d522f475Smrg * Double-check the fontname that we asked for versus what the font server
519d522f475Smrg * actually gave us.  The larger fixed fonts do not always have a matching bold
520d522f475Smrg * font, and the font server may try to scale another font or otherwise
521d522f475Smrg * substitute a mismatched font.
522d522f475Smrg *
523d522f475Smrg * If we cannot get what we requested, we will fallback to the original
524d522f475Smrg * behavior, which simulates bold by overstriking each character at one pixel
525d522f475Smrg * offset.
526d522f475Smrg */
527d522f475Smrgstatic int
528d522f475Smrggot_bold_font(Display * dpy, XFontStruct * fs, char *requested)
529d522f475Smrg{
530d522f475Smrg    char actual[MAX_FONTNAME];
531d522f475Smrg    int got;
532d522f475Smrg
533d522f475Smrg    if (get_font_name_props(dpy, fs, actual) == 0)
534d522f475Smrg	got = 0;
535d522f475Smrg    else
536d522f475Smrg	got = same_font_name(requested, actual);
537d522f475Smrg    return got;
538d522f475Smrg}
539d522f475Smrg
540d522f475Smrg/*
541d522f475Smrg * If the font server tries to adjust another font, it may not adjust it
542d522f475Smrg * properly.  Check that the bounding boxes are compatible.  Otherwise we'll
543d522f475Smrg * leave trash on the display when we mix normal and bold fonts.
544d522f475Smrg */
545d522f475Smrgstatic int
546d522f475Smrgsame_font_size(XtermWidget xw, XFontStruct * nfs, XFontStruct * bfs)
547d522f475Smrg{
548d522f475Smrg    TRACE(("same_font_size height %d/%d, min %d/%d max %d/%d\n",
549d522f475Smrg	   nfs->ascent + nfs->descent,
550d522f475Smrg	   bfs->ascent + bfs->descent,
551d522f475Smrg	   nfs->min_bounds.width, bfs->min_bounds.width,
552d522f475Smrg	   nfs->max_bounds.width, bfs->max_bounds.width));
553d522f475Smrg    return xw->screen.free_bold_box
554d522f475Smrg	|| ((nfs->ascent + nfs->descent) == (bfs->ascent + bfs->descent)
555d522f475Smrg	    && (nfs->min_bounds.width == bfs->min_bounds.width
556d522f475Smrg		|| nfs->min_bounds.width == bfs->min_bounds.width + 1)
557d522f475Smrg	    && (nfs->max_bounds.width == bfs->max_bounds.width
558d522f475Smrg		|| nfs->max_bounds.width == bfs->max_bounds.width + 1));
559d522f475Smrg}
560d522f475Smrg
561d522f475Smrg/*
562d522f475Smrg * Check if the font looks like it has fixed width
563d522f475Smrg */
564d522f475Smrgstatic int
565d522f475Smrgis_fixed_font(XFontStruct * fs)
566d522f475Smrg{
567d522f475Smrg    if (fs)
568d522f475Smrg	return (fs->min_bounds.width == fs->max_bounds.width);
569d522f475Smrg    return 1;
570d522f475Smrg}
571d522f475Smrg
572d522f475Smrg/*
573d522f475Smrg * Check if the font looks like a double width font (i.e. contains
574d522f475Smrg * characters of width X and 2X
575d522f475Smrg */
576d522f475Smrg#if OPT_WIDE_CHARS
577d522f475Smrgstatic int
578d522f475Smrgis_double_width_font(XFontStruct * fs)
579d522f475Smrg{
580d522f475Smrg    return ((2 * fs->min_bounds.width) == fs->max_bounds.width);
581d522f475Smrg}
582d522f475Smrg#else
583d522f475Smrg#define is_double_width_font(fs) 0
584d522f475Smrg#endif
585d522f475Smrg
586d522f475Smrg#if OPT_WIDE_CHARS && OPT_RENDERFONT && defined(HAVE_TYPE_FCCHAR32)
587d522f475Smrg#define HALF_WIDTH_TEST_STRING "1234567890"
588d522f475Smrg
589d522f475Smrg/* '1234567890' in Chinese characters in UTF-8 */
590d522f475Smrg#define FULL_WIDTH_TEST_STRING "\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89" \
591d522f475Smrg                               "\xe5\x9b\x9b\xe4\xba\x94" \
592d522f475Smrg			       "\xef\xa7\x91\xe4\xb8\x83\xe5\x85\xab" \
593d522f475Smrg			       "\xe4\xb9\x9d\xef\xa6\xb2"
594d522f475Smrg
595d522f475Smrg/* '1234567890' in Korean script in UTF-8 */
596d522f475Smrg#define FULL_WIDTH_TEST_STRING2 "\xec\x9d\xbc\xec\x9d\xb4\xec\x82\xbc" \
597d522f475Smrg                                "\xec\x82\xac\xec\x98\xa4" \
598d522f475Smrg			        "\xec\x9c\xa1\xec\xb9\xa0\xed\x8c\x94" \
599d522f475Smrg			        "\xea\xb5\xac\xec\x98\x81"
600d522f475Smrg
601d522f475Smrg#define HALF_WIDTH_CHAR1  0x0031	/* '1' */
602d522f475Smrg#define HALF_WIDTH_CHAR2  0x0057	/* 'W' */
603d522f475Smrg#define FULL_WIDTH_CHAR1  0x4E00	/* CJK Ideograph 'number one' */
604d522f475Smrg#define FULL_WIDTH_CHAR2  0xAC00	/* Korean script syllable 'Ka' */
605d522f475Smrg
606d522f475Smrgstatic Bool
607d522f475Smrgis_double_width_font_xft(Display * dpy, XftFont * font)
608d522f475Smrg{
609d522f475Smrg    XGlyphInfo gi1, gi2;
610d522f475Smrg    FcChar32 c1 = HALF_WIDTH_CHAR1, c2 = HALF_WIDTH_CHAR2;
611d522f475Smrg    char *fwstr = FULL_WIDTH_TEST_STRING;
612d522f475Smrg    char *hwstr = HALF_WIDTH_TEST_STRING;
613d522f475Smrg
614d522f475Smrg    /* Some Korean fonts don't have Chinese characters at all. */
615d522f475Smrg    if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR1)) {
616d522f475Smrg	if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR2))
617d522f475Smrg	    return False;	/* Not a CJK font */
618d522f475Smrg	else			/* a Korean font without CJK Ideographs */
619d522f475Smrg	    fwstr = FULL_WIDTH_TEST_STRING2;
620d522f475Smrg    }
621d522f475Smrg
622d522f475Smrg    XftTextExtents32(dpy, font, &c1, 1, &gi1);
623d522f475Smrg    XftTextExtents32(dpy, font, &c2, 1, &gi2);
624d522f475Smrg    if (gi1.xOff != gi2.xOff)	/* Not a fixed-width font */
625d522f475Smrg	return False;
626d522f475Smrg
627d522f475Smrg    XftTextExtentsUtf8(dpy, font, (FcChar8 *) hwstr, (int) strlen(hwstr), &gi1);
628d522f475Smrg    XftTextExtentsUtf8(dpy, font, (FcChar8 *) fwstr, (int) strlen(fwstr), &gi2);
629d522f475Smrg
630d522f475Smrg    /*
631d522f475Smrg     * fontconfig and Xft prior to 2.2(?) set the width of half-width
632d522f475Smrg     * characters identical to that of full-width character in CJK double-width
633d522f475Smrg     * (bi-width / monospace) font even though the former is half as wide as
634d522f475Smrg     * the latter.  This was fixed sometime before the release of fontconfig
635d522f475Smrg     * 2.2 in early 2003.  See
636d522f475Smrg     *  http://bugzilla.mozilla.org/show_bug.cgi?id=196312
637d522f475Smrg     * In the meantime, we have to check both possibilities.
638d522f475Smrg     */
639d522f475Smrg    return ((2 * gi1.xOff == gi2.xOff) || (gi1.xOff == gi2.xOff));
640d522f475Smrg}
641d522f475Smrg#else
642d522f475Smrg#define is_double_width_font_xft(dpy, xftfont) 0
643d522f475Smrg#endif
644d522f475Smrg
645d522f475Smrg#define EmptyFont(fs) (fs != 0 \
646d522f475Smrg		   && ((fs)->ascent + (fs)->descent == 0 \
647d522f475Smrg		    || (fs)->max_bounds.width == 0))
648d522f475Smrg
649d522f475Smrg#define FontSize(fs) (((fs)->ascent + (fs)->descent) \
650d522f475Smrg		    *  (fs)->max_bounds.width)
651d522f475Smrg
652d522f475Smrgconst VTFontNames *
653d522f475SmrgxtermFontName(char *normal)
654d522f475Smrg{
655d522f475Smrg    static VTFontNames data;
656d522f475Smrg    memset(&data, 0, sizeof(data));
657d522f475Smrg    data.f_n = normal;
658d522f475Smrg    return &data;
659d522f475Smrg}
660d522f475Smrg
661d522f475Smrgstatic void
662d522f475Smrgcache_menu_font_name(TScreen * screen, int fontnum, int which, const char *name)
663d522f475Smrg{
664d522f475Smrg    if (name != 0) {
665d522f475Smrg	char *last = screen->menu_font_names[fontnum][which];
666d522f475Smrg	if (last != 0) {
667d522f475Smrg	    if (strcmp(last, name)) {
668d522f475Smrg		free(last);
669d522f475Smrg		TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name));
670d522f475Smrg		screen->menu_font_names[fontnum][which] = x_strdup(name);
671d522f475Smrg	    }
672d522f475Smrg	} else {
673d522f475Smrg	    TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name));
674d522f475Smrg	    screen->menu_font_names[fontnum][which] = x_strdup(name);
675d522f475Smrg	}
676d522f475Smrg    }
677d522f475Smrg}
678d522f475Smrg
679d522f475Smrg/*
680d522f475Smrg * Open the given font and verify that it is non-empty.  Return a null on
681d522f475Smrg * failure.
682d522f475Smrg */
683d522f475SmrgBool
684d522f475SmrgxtermOpenFont(XtermWidget xw, char *name, XTermFonts * result)
685d522f475Smrg{
686d522f475Smrg    Bool code = False;
687d522f475Smrg    TScreen *screen = TScreenOf(xw);
688d522f475Smrg
689d522f475Smrg    if (name != 0
690d522f475Smrg	&& (result->fs = XLoadQueryFont(screen->display, name)) != 0) {
691d522f475Smrg	code = True;
692d522f475Smrg	if (EmptyFont(result->fs)) {
693d522f475Smrg	    result = xtermCloseFont(xw, result);
694d522f475Smrg	    code = False;
695d522f475Smrg	} else {
696d522f475Smrg	    result->fn = x_strdup(name);
697d522f475Smrg	}
698d522f475Smrg    }
699d522f475Smrg    return code;
700d522f475Smrg}
701d522f475Smrg
702d522f475Smrg/*
703d522f475Smrg * Close the font and Free the font info
704d522f475Smrg */
705d522f475SmrgXTermFonts *
706d522f475SmrgxtermCloseFont(XtermWidget xw, XTermFonts * fnt)
707d522f475Smrg{
708d522f475Smrg    if (fnt != 0 && fnt->fs != 0) {
709d522f475Smrg	TScreen *screen = TScreenOf(xw);
710d522f475Smrg
711d522f475Smrg	clrCgsFonts(xw, WhichVWin(screen), fnt);
712d522f475Smrg	XFreeFont(screen->display, fnt->fs);
713d522f475Smrg	xtermFreeFontInfo(fnt);
714d522f475Smrg    }
715d522f475Smrg    return 0;
716d522f475Smrg}
717d522f475Smrg
718d522f475Smrg/*
719d522f475Smrg * Close the listed fonts, noting that some may use copies of the pointer.
720d522f475Smrg */
721d522f475Smrgvoid
722d522f475SmrgxtermCloseFonts(XtermWidget xw, XTermFonts * fnts)
723d522f475Smrg{
724d522f475Smrg    int j, k;
725d522f475Smrg
726d522f475Smrg    for (j = 0; j < fMAX; ++j) {
727d522f475Smrg	/*
728d522f475Smrg	 * Need to save the pointer since xtermCloseFont zeroes it
729d522f475Smrg	 */
730d522f475Smrg	XFontStruct *thisFont = fnts[j].fs;
731d522f475Smrg	if (thisFont != 0) {
732d522f475Smrg	    xtermCloseFont(xw, &fnts[j]);
733d522f475Smrg	    for (k = j + 1; k < fMAX; ++k) {
734d522f475Smrg		if (thisFont == fnts[k].fs)
735d522f475Smrg		    xtermFreeFontInfo(&fnts[k]);
736d522f475Smrg	    }
737d522f475Smrg	}
738d522f475Smrg    }
739d522f475Smrg}
740d522f475Smrg
741d522f475Smrg/*
742d522f475Smrg * Make a copy of the source, assuming the XFontStruct's to be unique, but
743d522f475Smrg * ensuring that the names are reallocated to simplify freeing.
744d522f475Smrg */
745d522f475Smrgvoid
746d522f475SmrgxtermCopyFontInfo(XTermFonts * target, XTermFonts * source)
747d522f475Smrg{
748d522f475Smrg    xtermFreeFontInfo(target);
749d522f475Smrg    target->chrset = source->chrset;
750d522f475Smrg    target->flags = source->flags;
751d522f475Smrg    target->fn = x_strdup(source->fn);
752d522f475Smrg    target->fs = source->fs;
753d522f475Smrg}
754d522f475Smrg
755d522f475Smrgvoid
756d522f475SmrgxtermFreeFontInfo(XTermFonts * target)
757d522f475Smrg{
758d522f475Smrg    target->chrset = 0;
759d522f475Smrg    target->flags = 0;
760d522f475Smrg    if (target->fn != 0) {
761d522f475Smrg	free(target->fn);
762d522f475Smrg	target->fn = 0;
763d522f475Smrg    }
764d522f475Smrg    target->fs = 0;
765d522f475Smrg}
766d522f475Smrg
767d522f475Smrgint
768d522f475SmrgxtermLoadFont(XtermWidget xw,
769d522f475Smrg	      const VTFontNames * fonts,
770d522f475Smrg	      Bool doresize,
771d522f475Smrg	      int fontnum)
772d522f475Smrg{
773d522f475Smrg    TScreen *screen = &(xw->screen);
774d522f475Smrg    VTwin *win = WhichVWin(screen);
775d522f475Smrg
776d522f475Smrg    VTFontNames myfonts;
777d522f475Smrg    FontNameProperties *fp;
778d522f475Smrg    XTermFonts fnts[fMAX];
779d522f475Smrg    Pixel new_normal;
780d522f475Smrg    Pixel new_revers;
781d522f475Smrg    char *tmpname = NULL;
782d522f475Smrg    char normal[MAX_FONTNAME];
783d522f475Smrg    Bool proportional = False;
784d522f475Smrg
785d522f475Smrg    memset(&myfonts, 0, sizeof(myfonts));
786d522f475Smrg    memset(fnts, 0, sizeof(fnts));
787d522f475Smrg
788d522f475Smrg    if (fonts != 0)
789d522f475Smrg	myfonts = *fonts;
790d522f475Smrg    if (myfonts.f_n == 0)
791d522f475Smrg	return 0;
792d522f475Smrg
793d522f475Smrg    if (fontnum == fontMenu_fontescape
794d522f475Smrg	&& myfonts.f_n != screen->MenuFontName(fontnum)) {
795d522f475Smrg	if ((tmpname = x_strdup(myfonts.f_n)) == 0)
796d522f475Smrg	    return 0;
797d522f475Smrg    }
798d522f475Smrg
799d522f475Smrg    TRACE(("Begin Cgs - xtermLoadFont(%s)\n", myfonts.f_n));
800d522f475Smrg    releaseWindowGCs(xw, win);
801d522f475Smrg
802d522f475Smrg    TRACE(("xtermLoadFont #%d normal %s\n", fontnum, NonNull(myfonts.f_n)));
803d522f475Smrg    TRACE(("xtermLoadFont #%d bold   %s\n", fontnum, NonNull(myfonts.f_b)));
804d522f475Smrg#if OPT_WIDE_CHARS
805d522f475Smrg    TRACE(("xtermLoadFont #%d wide   %s\n", fontnum, NonNull(myfonts.f_w)));
806d522f475Smrg    TRACE(("xtermLoadFont #%d w/bold %s\n", fontnum, NonNull(myfonts.f_wb)));
807d522f475Smrg#endif
808d522f475Smrg
809d522f475Smrg    if (!xtermOpenFont(xw, myfonts.f_n, &fnts[fNorm]))
810d522f475Smrg	goto bad;
811d522f475Smrg
812d522f475Smrg    strcpy(normal, myfonts.f_n);
813d522f475Smrg    if (myfonts.f_b == 0) {
814d522f475Smrg	fp = get_font_name_props(screen->display, fnts[fNorm].fs, normal);
815d522f475Smrg	if (fp != 0) {
816d522f475Smrg	    myfonts.f_b = bold_font_name(fp, fp->average_width);
817d522f475Smrg	    if (!xtermOpenFont(xw, myfonts.f_b, &fnts[fBold])) {
818d522f475Smrg		myfonts.f_b = bold_font_name(fp, -1);
819d522f475Smrg		(void) xtermOpenFont(xw, myfonts.f_b, &fnts[fBold]);
820d522f475Smrg	    }
821d522f475Smrg	    TRACE(("...derived bold %s\n", NonNull(myfonts.f_b)));
822d522f475Smrg	}
823d522f475Smrg	if (fp == 0 || fnts[fBold].fs == 0) {
824d522f475Smrg	    xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]);
825d522f475Smrg	    TRACE(("...cannot load a matching bold font\n"));
826d522f475Smrg	} else if (same_font_size(xw, fnts[fNorm].fs, fnts[fBold].fs)
827d522f475Smrg		   && got_bold_font(screen->display, fnts[fBold].fs, myfonts.f_b)) {
828d522f475Smrg	    TRACE(("...got a matching bold font\n"));
829d522f475Smrg	    cache_menu_font_name(screen, fontnum, fBold, myfonts.f_b);
830d522f475Smrg	} else {
831d522f475Smrg	    xtermCloseFont(xw, &fnts[fBold]);
832d522f475Smrg	    fnts[fBold] = fnts[fNorm];
833d522f475Smrg	    TRACE(("...did not get a matching bold font\n"));
834d522f475Smrg	}
835d522f475Smrg    } else if (!xtermOpenFont(xw, myfonts.f_b, &fnts[fBold])) {
836d522f475Smrg	xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]);
837d522f475Smrg	TRACE(("...cannot load bold font %s\n", NonNull(myfonts.f_b)));
838d522f475Smrg    } else {
839d522f475Smrg	cache_menu_font_name(screen, fontnum, fBold, myfonts.f_b);
840d522f475Smrg    }
841d522f475Smrg
842d522f475Smrg    /*
843d522f475Smrg     * If there is no widefont specified, fake it by doubling AVERAGE_WIDTH
844d522f475Smrg     * of normal fonts XLFD, and asking for it.  This plucks out 18x18ja
845d522f475Smrg     * and 12x13ja as the corresponding fonts for 9x18 and 6x13.
846d522f475Smrg     */
847d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
848d522f475Smrg	Bool derived;
849d522f475Smrg	char bold[MAX_FONTNAME];
850d522f475Smrg
851d522f475Smrg	if (myfonts.f_w != 0) {
852d522f475Smrg	    cache_menu_font_name(screen, fontnum, fWide, myfonts.f_w);
853d522f475Smrg	} else if (!is_double_width_font(fnts[fNorm].fs)) {
854d522f475Smrg	    fp = get_font_name_props(screen->display, fnts[fNorm].fs, normal);
855d522f475Smrg	    if (fp != 0) {
856d522f475Smrg		myfonts.f_w = wide_font_name(fp);
857d522f475Smrg		TRACE(("...derived wide %s\n", NonNull(myfonts.f_w)));
858d522f475Smrg		cache_menu_font_name(screen, fontnum, fWide, myfonts.f_w);
859d522f475Smrg	    }
860d522f475Smrg	}
861d522f475Smrg
862d522f475Smrg	if (myfonts.f_w) {
863d522f475Smrg	    (void) xtermOpenFont(xw, myfonts.f_w, &fnts[fWide]);
864d522f475Smrg	} else {
865d522f475Smrg	    xtermCopyFontInfo(&fnts[fWide], &fnts[fNorm]);
866d522f475Smrg	}
867d522f475Smrg
868d522f475Smrg	derived = False;
869d522f475Smrg	if (myfonts.f_wb == 0) {
870d522f475Smrg	    fp = get_font_name_props(screen->display, fnts[fBold].fs, bold);
871d522f475Smrg	    if (fp != 0) {
872d522f475Smrg		myfonts.f_wb = widebold_font_name(fp);
873d522f475Smrg		derived = True;
874d522f475Smrg	    }
875d522f475Smrg	}
876d522f475Smrg
877d522f475Smrg	if (myfonts.f_wb) {
878d522f475Smrg
879d522f475Smrg	    (void) xtermOpenFont(xw, myfonts.f_wb, &fnts[fWBold]);
880d522f475Smrg
881d522f475Smrg	    if (derived
882d522f475Smrg		&& !compatibleWideCounts(fnts[fWide].fs, fnts[fWBold].fs)) {
883d522f475Smrg		xtermCloseFont(xw, &fnts[fWBold]);
884d522f475Smrg	    }
885d522f475Smrg	    if (fnts[fWBold].fs == 0) {
886d522f475Smrg		myfonts.f_wb = myfonts.f_w;
887d522f475Smrg		xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
888d522f475Smrg		TRACE(("...cannot load wide-bold, use wide %s\n", NonNull(myfonts.f_w)));
889d522f475Smrg	    } else {
890d522f475Smrg		TRACE(("...%s wide/bold %s\n",
891d522f475Smrg		       derived ? "derived" : "given",
892d522f475Smrg		       NonNull(myfonts.f_wb)));
893d522f475Smrg		cache_menu_font_name(screen, fontnum, fWBold, myfonts.f_wb);
894d522f475Smrg	    }
895d522f475Smrg	} else if (is_double_width_font(fnts[fBold].fs)) {
896d522f475Smrg	    xtermCopyFontInfo(&fnts[fWBold], &fnts[fBold]);
897d522f475Smrg	    TRACE(("...bold font is double-width, use it %s\n", NonNull(myfonts.f_b)));
898d522f475Smrg	} else {
899d522f475Smrg	    xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
900d522f475Smrg	    TRACE(("...cannot load wide bold font, use wide %s\n", NonNull(myfonts.f_w)));
901d522f475Smrg	}
902d522f475Smrg
903d522f475Smrg	if (EmptyFont(fnts[fWBold].fs))
904d522f475Smrg	    goto bad;		/* can't use a 0-sized font */
905d522f475Smrg    });
906d522f475Smrg
907d522f475Smrg    /*
908d522f475Smrg     * Most of the time this call to load the font will succeed, even if
909d522f475Smrg     * there is no wide font :  the X server doubles the width of the
910d522f475Smrg     * normal font, or similar.
911d522f475Smrg     *
912d522f475Smrg     * But if it did fail for some reason, then nevermind.
913d522f475Smrg     */
914d522f475Smrg    if (EmptyFont(fnts[fBold].fs))
915d522f475Smrg	goto bad;		/* can't use a 0-sized font */
916d522f475Smrg
917d522f475Smrg    if (!same_font_size(xw, fnts[fNorm].fs, fnts[fBold].fs)
918d522f475Smrg	&& (is_fixed_font(fnts[fNorm].fs) && is_fixed_font(fnts[fBold].fs))) {
919d522f475Smrg	TRACE(("...ignoring mismatched normal/bold fonts\n"));
920d522f475Smrg	xtermCloseFont(xw, &fnts[fBold]);
921d522f475Smrg	xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]);
922d522f475Smrg    }
923d522f475Smrg
924d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
925d522f475Smrg	if (fnts[fWide].fs != 0
926d522f475Smrg	    && fnts[fWBold].fs != 0
927d522f475Smrg	    && !same_font_size(xw, fnts[fWide].fs, fnts[fWBold].fs)
928d522f475Smrg	    && (is_fixed_font(fnts[fWide].fs) && is_fixed_font(fnts[fWBold].fs))) {
929d522f475Smrg	    TRACE(("...ignoring mismatched normal/bold wide fonts\n"));
930d522f475Smrg	    xtermCloseFont(xw, &fnts[fWBold]);
931d522f475Smrg	    xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
932d522f475Smrg	}
933d522f475Smrg    });
934d522f475Smrg
935d522f475Smrg    /*
936d522f475Smrg     * Normal/bold fonts should be the same width.  Also, the min/max
937d522f475Smrg     * values should be the same.
938d522f475Smrg     */
939d522f475Smrg    if (!is_fixed_font(fnts[fNorm].fs)
940d522f475Smrg	|| !is_fixed_font(fnts[fBold].fs)
941d522f475Smrg	|| fnts[fNorm].fs->max_bounds.width != fnts[fBold].fs->max_bounds.width) {
942d522f475Smrg	TRACE(("Proportional font! normal %d/%d, bold %d/%d\n",
943d522f475Smrg	       fnts[fNorm].fs->min_bounds.width,
944d522f475Smrg	       fnts[fNorm].fs->max_bounds.width,
945d522f475Smrg	       fnts[fBold].fs->min_bounds.width,
946d522f475Smrg	       fnts[fBold].fs->max_bounds.width));
947d522f475Smrg	proportional = True;
948d522f475Smrg    }
949d522f475Smrg
950d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
951d522f475Smrg	if (fnts[fWide].fs != 0
952d522f475Smrg	    && fnts[fWBold].fs != 0
953d522f475Smrg	    && (!is_fixed_font(fnts[fWide].fs)
954d522f475Smrg		|| !is_fixed_font(fnts[fWBold].fs)
955d522f475Smrg		|| fnts[fWide].fs->max_bounds.width != fnts[fWBold].fs->max_bounds.width)) {
956d522f475Smrg	    TRACE(("Proportional font! wide %d/%d, wide bold %d/%d\n",
957d522f475Smrg		   fnts[fWide].fs->min_bounds.width,
958d522f475Smrg		   fnts[fWide].fs->max_bounds.width,
959d522f475Smrg		   fnts[fWBold].fs->min_bounds.width,
960d522f475Smrg		   fnts[fWBold].fs->max_bounds.width));
961d522f475Smrg	    proportional = True;
962d522f475Smrg	}
963d522f475Smrg    });
964d522f475Smrg
965d522f475Smrg    /* TODO : enforce that the width of the wide font is 2* the width
966d522f475Smrg       of the narrow font */
967d522f475Smrg
968d522f475Smrg    /*
969d522f475Smrg     * If we're switching fonts, free the old ones.  Otherwise we'll leak
970d522f475Smrg     * the memory that is associated with the old fonts.  The
971d522f475Smrg     * XLoadQueryFont call allocates a new XFontStruct.
972d522f475Smrg     */
973d522f475Smrg    xtermCloseFonts(xw, screen->fnts);
974d522f475Smrg
975d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fNorm]), &fnts[fNorm]);
976d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fBold]), &fnts[fBold]);
977d522f475Smrg#if OPT_WIDE_CHARS
978d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fWide]), &fnts[fWide]);
979d522f475Smrg    if (fnts[fWBold].fs == NULL)
980d522f475Smrg	xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
981d522f475Smrg    xtermCopyFontInfo(&(screen->fnts[fWBold]), &fnts[fWBold]);
982d522f475Smrg#endif
983d522f475Smrg
984d522f475Smrg    new_normal = getXtermForeground(xw, xw->flags, xw->cur_foreground);
985d522f475Smrg    new_revers = getXtermBackground(xw, xw->flags, xw->cur_background);
986d522f475Smrg
987d522f475Smrg    setCgsFore(xw, win, gcNorm, new_normal);
988d522f475Smrg    setCgsBack(xw, win, gcNorm, new_revers);
989d522f475Smrg    setCgsFont(xw, win, gcNorm, &(screen->fnts[fNorm]));
990d522f475Smrg
991d522f475Smrg    copyCgs(xw, win, gcBold, gcNorm);
992d522f475Smrg    setCgsFont(xw, win, gcBold, &(screen->fnts[fBold]));
993d522f475Smrg
994d522f475Smrg    setCgsFore(xw, win, gcNormReverse, new_revers);
995d522f475Smrg    setCgsBack(xw, win, gcNormReverse, new_normal);
996d522f475Smrg    setCgsFont(xw, win, gcNormReverse, &(screen->fnts[fNorm]));
997d522f475Smrg
998d522f475Smrg    copyCgs(xw, win, gcBoldReverse, gcNormReverse);
999d522f475Smrg    setCgsFont(xw, win, gcBoldReverse, &(screen->fnts[fBold]));
1000d522f475Smrg
1001d522f475Smrg    if_OPT_WIDE_CHARS(screen, {
1002d522f475Smrg	if (screen->fnts[fWide].fs != 0
1003d522f475Smrg	    && screen->fnts[fWBold].fs != 0) {
1004d522f475Smrg	    setCgsFore(xw, win, gcWide, new_normal);
1005d522f475Smrg	    setCgsBack(xw, win, gcWide, new_revers);
1006d522f475Smrg	    setCgsFont(xw, win, gcWide, &(screen->fnts[fWide]));
1007d522f475Smrg
1008d522f475Smrg	    copyCgs(xw, win, gcWBold, gcWide);
1009d522f475Smrg	    setCgsFont(xw, win, gcWBold, &(screen->fnts[fWBold]));
1010d522f475Smrg
1011d522f475Smrg	    setCgsFore(xw, win, gcWideReverse, new_revers);
1012d522f475Smrg	    setCgsBack(xw, win, gcWideReverse, new_normal);
1013d522f475Smrg	    setCgsFont(xw, win, gcWideReverse, &(screen->fnts[fWide]));
1014d522f475Smrg
1015d522f475Smrg	    copyCgs(xw, win, gcWBoldReverse, gcWideReverse);
1016d522f475Smrg	    setCgsFont(xw, win, gcWBoldReverse, &(screen->fnts[fWBold]));
1017d522f475Smrg	}
1018d522f475Smrg    });
1019d522f475Smrg
1020d522f475Smrg    screen->fnt_prop = proportional;
1021d522f475Smrg    screen->fnt_boxes = True;
1022d522f475Smrg
1023d522f475Smrg#if OPT_BOX_CHARS
1024d522f475Smrg    /*
1025d522f475Smrg     * Xterm uses character positions 1-31 of a font for the line-drawing
1026d522f475Smrg     * characters.  Check that they are all present.  The null character
1027d522f475Smrg     * (0) is special, and is not used.
1028d522f475Smrg     */
1029d522f475Smrg#if OPT_RENDERFONT
1030d522f475Smrg    if (UsingRenderFont(xw)) {
1031d522f475Smrg	/*
1032d522f475Smrg	 * FIXME: we shouldn't even be here if we're using Xft.
1033d522f475Smrg	 */
1034d522f475Smrg	screen->fnt_boxes = False;
1035d522f475Smrg	TRACE(("assume Xft missing line-drawing chars\n"));
1036d522f475Smrg    } else
1037d522f475Smrg#endif
1038d522f475Smrg    {
1039d522f475Smrg	unsigned ch;
1040d522f475Smrg
1041d522f475Smrg	for (ch = 1; ch < 32; ch++) {
1042d522f475Smrg	    unsigned n = ch;
1043d522f475Smrg#if OPT_WIDE_CHARS
1044d522f475Smrg	    if (screen->utf8_mode || screen->unicode_font) {
1045d522f475Smrg		n = dec2ucs(ch);
1046d522f475Smrg		if (n == UCS_REPL)
1047d522f475Smrg		    continue;
1048d522f475Smrg	    }
1049d522f475Smrg#endif
1050d522f475Smrg	    if (xtermMissingChar(xw, n, fnts[fNorm].fs)) {
1051d522f475Smrg		TRACE(("missing normal char #%d\n", n));
1052d522f475Smrg		screen->fnt_boxes = False;
1053d522f475Smrg		break;
1054d522f475Smrg	    }
1055d522f475Smrg	    if (xtermMissingChar(xw, n, fnts[fBold].fs)) {
1056d522f475Smrg		TRACE(("missing bold char #%d\n", n));
1057d522f475Smrg		screen->fnt_boxes = False;
1058d522f475Smrg		break;
1059d522f475Smrg	    }
1060d522f475Smrg	}
1061d522f475Smrg    }
1062d522f475Smrg    TRACE(("Will %suse internal line-drawing characters\n",
1063d522f475Smrg	   screen->fnt_boxes ? "not " : ""));
1064d522f475Smrg#endif
1065d522f475Smrg
1066d522f475Smrg    if (screen->always_bold_mode) {
1067d522f475Smrg	screen->enbolden = screen->bold_mode;
1068d522f475Smrg    } else {
1069d522f475Smrg	screen->enbolden = screen->bold_mode
1070d522f475Smrg	    && ((fnts[fNorm].fs == fnts[fBold].fs)
1071d522f475Smrg		|| same_font_name(normal, myfonts.f_b));
1072d522f475Smrg    }
1073d522f475Smrg    TRACE(("Will %suse 1-pixel offset/overstrike to simulate bold\n",
1074d522f475Smrg	   screen->enbolden ? "" : "not "));
1075d522f475Smrg
1076d522f475Smrg    set_menu_font(False);
1077d522f475Smrg    screen->menu_font_number = fontnum;
1078d522f475Smrg    set_menu_font(True);
1079d522f475Smrg    if (tmpname) {		/* if setting escape or sel */
1080d522f475Smrg	if (screen->MenuFontName(fontnum))
1081d522f475Smrg	    free(screen->MenuFontName(fontnum));
1082d522f475Smrg	screen->MenuFontName(fontnum) = tmpname;
1083d522f475Smrg	if (fontnum == fontMenu_fontescape) {
1084d522f475Smrg	    SetItemSensitivity(fontMenuEntries[fontMenu_fontescape].widget,
1085d522f475Smrg			       True);
1086d522f475Smrg	}
1087d522f475Smrg#if OPT_SHIFT_FONTS
1088d522f475Smrg	screen->menu_font_sizes[fontnum] = FontSize(fnts[fNorm].fs);
1089d522f475Smrg#endif
1090d522f475Smrg    }
1091d522f475Smrg    set_cursor_gcs(xw);
1092d522f475Smrg    xtermUpdateFontInfo(xw, doresize);
1093d522f475Smrg    TRACE(("Success Cgs - xtermLoadFont\n"));
1094d522f475Smrg    return 1;
1095d522f475Smrg
1096d522f475Smrg  bad:
1097d522f475Smrg    if (tmpname)
1098d522f475Smrg	free(tmpname);
1099d522f475Smrg    releaseWindowGCs(xw, win);
1100d522f475Smrg
1101d522f475Smrg    xtermCloseFonts(xw, fnts);
1102d522f475Smrg    TRACE(("Fail Cgs - xtermLoadFont\n"));
1103d522f475Smrg    return 0;
1104d522f475Smrg}
1105d522f475Smrg
1106d522f475Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
1107d522f475Smrg/*
1108d522f475Smrg * Collect font-names that we can modify with the load-vt-fonts() action.
1109d522f475Smrg */
1110d522f475Smrgtypedef struct {
1111d522f475Smrg    VTFontNames default_font;
1112d522f475Smrg    char *menu_font_names[fontMenu_lastBuiltin + 1][fMAX];
1113d522f475Smrg} SubResourceRec;
1114d522f475Smrg
1115d522f475Smrg#define MERGE_SUBFONT(src,dst,name) \
1116d522f475Smrg	if (dst.name == 0) { \
1117d522f475Smrg	    TRACE(("MERGE_SUBFONT " #dst "." #name " merge %s\n", NonNull(src.name))); \
1118d522f475Smrg	    dst.name = src.name; \
1119d522f475Smrg	} else { \
1120d522f475Smrg	    TRACE(("MERGE_SUBFONT " #dst "." #name " found %s\n", NonNull(dst.name))); \
1121d522f475Smrg	}
1122d522f475Smrg
1123d522f475Smrg#define COPY_MENU_FONTS(src,dst) \
1124d522f475Smrg	TRACE(("COPY_MENU_FONTS " #src " to " #dst "\n")); \
1125d522f475Smrg	for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \
1126d522f475Smrg	    for (m = 0; m < fMAX; ++m) { \
1127d522f475Smrg		dst.menu_font_names[n][m] = src.menu_font_names[n][m]; \
1128d522f475Smrg	    } \
1129d522f475Smrg	}
1130d522f475Smrg
1131d522f475Smrg/*
1132d522f475Smrg * Load the "VT" font names from the given subresource name/class.  These
1133d522f475Smrg * correspond to the VT100 resources.
1134d522f475Smrg */
1135d522f475Smrgstatic Bool
1136d522f475SmrgxtermLoadVTFonts(XtermWidget w, char *myName, char *myClass)
1137d522f475Smrg{
1138d522f475Smrg    static Bool initialized = False;
1139d522f475Smrg    static SubResourceRec original, referenceRec, subresourceRec;
1140d522f475Smrg
1141d522f475Smrg    /*
1142d522f475Smrg     * These are duplicates of the VT100 font resources, but with a special
1143d522f475Smrg     * application/classname passed in to distinguish them.
1144d522f475Smrg     */
1145d522f475Smrg    static XtResource font_resources[] =
1146d522f475Smrg    {
1147d522f475Smrg	Sres(XtNfont, XtCFont, default_font.f_n, DEFFONT),
1148d522f475Smrg	Sres(XtNboldFont, XtCBoldFont, default_font.f_b, DEFBOLDFONT),
1149d522f475Smrg#if OPT_WIDE_CHARS
1150d522f475Smrg	Sres(XtNwideFont, XtCWideFont, default_font.f_w, DEFWIDEFONT),
1151d522f475Smrg	Sres(XtNwideBoldFont, XtCWideBoldFont, default_font.f_wb, DEFWIDEBOLDFONT),
1152d522f475Smrg#endif
1153d522f475Smrg	Sres(XtNfont1, XtCFont1, MenuFontName(fontMenu_font1), NULL),
1154d522f475Smrg	Sres(XtNfont2, XtCFont2, MenuFontName(fontMenu_font2), NULL),
1155d522f475Smrg	Sres(XtNfont3, XtCFont3, MenuFontName(fontMenu_font3), NULL),
1156d522f475Smrg	Sres(XtNfont4, XtCFont4, MenuFontName(fontMenu_font4), NULL),
1157d522f475Smrg	Sres(XtNfont5, XtCFont5, MenuFontName(fontMenu_font5), NULL),
1158d522f475Smrg	Sres(XtNfont6, XtCFont6, MenuFontName(fontMenu_font6), NULL),
1159d522f475Smrg    };
1160d522f475Smrg    Cardinal n, m;
1161d522f475Smrg    Bool status = True;
1162d522f475Smrg
1163d522f475Smrg    if (!initialized) {
1164d522f475Smrg
1165d522f475Smrg	initialized = True;
1166d522f475Smrg	TRACE(("xtermLoadVTFonts saving original\n"));
1167d522f475Smrg	original.default_font = w->misc.default_font;
1168d522f475Smrg	COPY_MENU_FONTS(w->screen, original);
1169d522f475Smrg    }
1170d522f475Smrg
1171d522f475Smrg    if (myName == 0 || *myName == 0) {
1172d522f475Smrg	TRACE(("xtermLoadVTFonts restoring original\n"));
1173d522f475Smrg	w->misc.default_font = original.default_font;
1174d522f475Smrg	COPY_MENU_FONTS(original, w->screen);
1175d522f475Smrg	for (n = 0; n < XtNumber(original.menu_font_names); ++n)
1176d522f475Smrg	    w->screen.MenuFontName(n) = original.MenuFontName(n);
1177d522f475Smrg    } else {
1178d522f475Smrg	TRACE(("xtermLoadVTFonts(%s, %s)\n", myName, myClass));
1179d522f475Smrg
1180d522f475Smrg	memset(&subresourceRec, 0, sizeof(subresourceRec));
1181d522f475Smrg	XtGetSubresources((Widget) w, (XtPointer) &subresourceRec,
1182d522f475Smrg			  myName, myClass,
1183d522f475Smrg			  font_resources,
1184d522f475Smrg			  (Cardinal) XtNumber(font_resources),
1185d522f475Smrg			  NULL, (Cardinal) 0);
1186d522f475Smrg
1187d522f475Smrg	if (memcmp(&referenceRec, &subresourceRec, sizeof(referenceRec))) {
1188d522f475Smrg
1189d522f475Smrg	    /*
1190d522f475Smrg	     * If a particular resource value was not found, use the original.
1191d522f475Smrg	     */
1192d522f475Smrg	    MERGE_SUBFONT(w->misc, subresourceRec, default_font.f_n);
1193d522f475Smrg	    MERGE_SUBFONT(w->misc, subresourceRec, default_font.f_b);
1194d522f475Smrg#if OPT_WIDE_CHARS
1195d522f475Smrg	    MERGE_SUBFONT(w->misc, subresourceRec, default_font.f_w);
1196d522f475Smrg	    MERGE_SUBFONT(w->misc, subresourceRec, default_font.f_wb);
1197d522f475Smrg#endif
1198d522f475Smrg	    for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n)
1199d522f475Smrg		MERGE_SUBFONT(w->screen, subresourceRec, MenuFontName(n));
1200d522f475Smrg
1201d522f475Smrg	    /*
1202d522f475Smrg	     * Finally, copy the subresource data to the widget.
1203d522f475Smrg	     */
1204d522f475Smrg	    w->misc.default_font = subresourceRec.default_font;
1205d522f475Smrg	    COPY_MENU_FONTS(subresourceRec, w->screen);
1206d522f475Smrg	    w->screen.MenuFontName(fontMenu_default) = w->misc.default_font.f_n;
1207d522f475Smrg	    w->screen.menu_font_names[0][fBold] = w->misc.default_font.f_b;
1208d522f475Smrg#if OPT_WIDE_CHARS
1209d522f475Smrg	    w->screen.menu_font_names[0][fWide] = w->misc.default_font.f_w;
1210d522f475Smrg	    w->screen.menu_font_names[0][fWBold] = w->misc.default_font.f_wb;
1211d522f475Smrg#endif
1212d522f475Smrg	} else {
1213d522f475Smrg	    TRACE(("...no resources found\n"));
1214d522f475Smrg	    status = False;
1215d522f475Smrg	}
1216d522f475Smrg    }
1217d522f475Smrg    return status;
1218d522f475Smrg}
1219d522f475Smrg
1220d522f475Smrg#if OPT_WIDE_CHARS
1221d522f475Smrgstatic Bool
1222d522f475SmrgisWideFont(XFontStruct * fp, char *tag, Bool nullOk)
1223d522f475Smrg{
1224d522f475Smrg    Bool result = False;
1225d522f475Smrg
1226d522f475Smrg    (void) tag;
1227d522f475Smrg    if (okFont(fp)) {
1228d522f475Smrg	unsigned count = countGlyphs(fp);
1229d522f475Smrg	TRACE(("isWideFont(%s) found %d cells\n", tag, count));
1230d522f475Smrg	result = (count > 256) ? True : False;
1231d522f475Smrg    } else {
1232d522f475Smrg	result = nullOk;
1233d522f475Smrg    }
1234d522f475Smrg    return result;
1235d522f475Smrg}
1236d522f475Smrg
1237d522f475Smrg/*
1238d522f475Smrg * If the current fonts are not wide, load the UTF8 fonts.
1239d522f475Smrg *
1240d522f475Smrg * Called during initialization (for wide-character mode), the fonts have not
1241d522f475Smrg * been setup, so we pass nullOk=True to isWideFont().
1242d522f475Smrg *
1243d522f475Smrg * Called after initialization, e.g., in response to the UTF-8 menu entry
1244d522f475Smrg * (starting from narrow character mode), it checks if the fonts are not wide.
1245d522f475Smrg */
1246d522f475SmrgBool
1247d522f475SmrgxtermLoadWideFonts(XtermWidget xw, Bool nullOk)
1248d522f475Smrg{
1249d522f475Smrg    TScreen *screen = &(xw->screen);
1250d522f475Smrg    Bool result;
1251d522f475Smrg
1252d522f475Smrg    if (EmptyFont(screen->fnts[fWide].fs)) {
1253d522f475Smrg	result = (isWideFont(screen->fnts[fNorm].fs, "normal", nullOk)
1254d522f475Smrg		  && isWideFont(screen->fnts[fBold].fs, "bold", nullOk));
1255d522f475Smrg    } else {
1256d522f475Smrg	result = (isWideFont(screen->fnts[fWide].fs, "wide", nullOk)
1257d522f475Smrg		  && isWideFont(screen->fnts[fWBold].fs, "wide-bold", nullOk));
1258d522f475Smrg	if (result && !screen->utf8_latin1) {
1259d522f475Smrg	    result = (isWideFont(screen->fnts[fNorm].fs, "normal", nullOk)
1260d522f475Smrg		      && isWideFont(screen->fnts[fBold].fs, "bold", nullOk));
1261d522f475Smrg	}
1262d522f475Smrg    }
1263d522f475Smrg    if (!result) {
1264d522f475Smrg	TRACE(("current fonts are not all wide%s\n", nullOk ? " nullOk" : ""));
1265d522f475Smrg	result = xtermLoadVTFonts(xw, "utf8Fonts", "Utf8Fonts");
1266d522f475Smrg    }
1267d522f475Smrg    TRACE(("xtermLoadWideFonts:%d\n", result));
1268d522f475Smrg    return result;
1269d522f475Smrg}
1270d522f475Smrg#endif /* OPT_WIDE_CHARS */
1271d522f475Smrg
1272d522f475Smrg/*
1273d522f475Smrg * Restore the default fonts, i.e., if we had switched to wide-fonts.
1274d522f475Smrg */
1275d522f475SmrgBool
1276d522f475SmrgxtermLoadDefaultFonts(XtermWidget w)
1277d522f475Smrg{
1278d522f475Smrg    Bool result;
1279d522f475Smrg    result = xtermLoadVTFonts(w, NULL, NULL);
1280d522f475Smrg    TRACE(("xtermLoadDefaultFonts:%d\n", result));
1281d522f475Smrg    return result;
1282d522f475Smrg}
1283d522f475Smrg#endif /* OPT_LOAD_VTFONTS || OPT_WIDE_CHARS */
1284d522f475Smrg
1285d522f475Smrg#if OPT_LOAD_VTFONTS
1286d522f475Smrgvoid
1287d522f475SmrgHandleLoadVTFonts(Widget w,
1288d522f475Smrg		  XEvent * event GCC_UNUSED,
1289d522f475Smrg		  String * params GCC_UNUSED,
1290d522f475Smrg		  Cardinal *param_count GCC_UNUSED)
1291d522f475Smrg{
1292d522f475Smrg    static char empty[] = "";	/* appease strict compilers */
1293d522f475Smrg
1294d522f475Smrg    if (IsXtermWidget(w)) {
1295d522f475Smrg	XtermWidget xw = (XtermWidget) w;
1296d522f475Smrg	char buf[80];
1297d522f475Smrg	char *myName = (*param_count > 0) ? params[0] : empty;
1298d522f475Smrg	char *convert = (*param_count > 1) ? params[1] : myName;
1299d522f475Smrg	char *myClass = (char *) MyStackAlloc(strlen(convert), buf);
1300d522f475Smrg	int n;
1301d522f475Smrg
1302d522f475Smrg	TRACE(("HandleLoadVTFonts(%d)\n", *param_count));
1303d522f475Smrg	strcpy(myClass, convert);
1304d522f475Smrg	if (*param_count == 1
1305d522f475Smrg	    && islower(CharOf(myClass[0])))
1306d522f475Smrg	    myClass[0] = toupper(CharOf(myClass[0]));
1307d522f475Smrg
1308d522f475Smrg	if (xtermLoadVTFonts(xw, myName, myClass)) {
1309d522f475Smrg	    /*
1310d522f475Smrg	     * When switching fonts, try to preserve the font-menu selection, since
1311d522f475Smrg	     * it is less surprising to do that (if the font-switching can be
1312d522f475Smrg	     * undone) than to switch to "Default".
1313d522f475Smrg	     */
1314d522f475Smrg	    int font_number = xw->screen.menu_font_number;
1315d522f475Smrg	    if (font_number > fontMenu_lastBuiltin)
1316d522f475Smrg		font_number = fontMenu_lastBuiltin;
1317d522f475Smrg	    for (n = 0; n < NMENUFONTS; ++n)
1318d522f475Smrg		xw->screen.menu_font_sizes[n] = 0;
1319d522f475Smrg	    SetVTFont(xw, font_number, True,
1320d522f475Smrg		      ((font_number == fontMenu_default)
1321d522f475Smrg		       ? &(xw->misc.default_font)
1322d522f475Smrg		       : NULL));
1323d522f475Smrg	}
1324d522f475Smrg
1325d522f475Smrg	MyStackFree(myClass, buf);
1326d522f475Smrg    }
1327d522f475Smrg}
1328d522f475Smrg#endif /* OPT_LOAD_VTFONTS */
1329d522f475Smrg
1330d522f475Smrg/*
1331d522f475Smrg * Set the limits for the box that outlines the cursor.
1332d522f475Smrg */
1333d522f475Smrgvoid
1334d522f475SmrgxtermSetCursorBox(TScreen * screen)
1335d522f475Smrg{
1336d522f475Smrg    static XPoint VTbox[NBOX];
1337d522f475Smrg    XPoint *vp;
1338d522f475Smrg
1339d522f475Smrg    vp = &VTbox[1];
1340d522f475Smrg    (vp++)->x = FontWidth(screen) - 1;
1341d522f475Smrg    (vp++)->y = FontHeight(screen) - 1;
1342d522f475Smrg    (vp++)->x = -(FontWidth(screen) - 1);
1343d522f475Smrg    vp->y = -(FontHeight(screen) - 1);
1344d522f475Smrg    screen->box = VTbox;
1345d522f475Smrg}
1346d522f475Smrg
1347d522f475Smrg#define CACHE_XFT(dst,src) if (src != 0) {\
1348d522f475Smrg	    dst[fontnum] = src;\
1349d522f475Smrg	    TRACE(("%s[%d] = %d (%d,%d) by %d\n",\
1350d522f475Smrg		#dst,\
1351d522f475Smrg	    	fontnum,\
1352d522f475Smrg		src->height,\
1353d522f475Smrg		src->ascent,\
1354d522f475Smrg		src->descent,\
1355d522f475Smrg		src->max_advance_width));\
1356d522f475Smrg	}
1357d522f475Smrg
1358d522f475Smrg#if OPT_RENDERFONT
1359d522f475Smrgstatic XftFont *
1360d522f475SmrgxtermOpenXft(Display * dpy, XftPattern * pat, const char *tag GCC_UNUSED)
1361d522f475Smrg{
1362d522f475Smrg    XftPattern *match;
1363d522f475Smrg    XftResult status;
1364d522f475Smrg    XftFont *result = 0;
1365d522f475Smrg
1366d522f475Smrg    if (pat != 0) {
1367d522f475Smrg	match = XftFontMatch(dpy, DefaultScreen(dpy), pat, &status);
1368d522f475Smrg	if (match != 0) {
1369d522f475Smrg	    result = XftFontOpenPattern(dpy, match);
1370d522f475Smrg	    if (result != 0) {
1371d522f475Smrg		TRACE(("...matched %s font\n", tag));
1372d522f475Smrg	    } else {
1373d522f475Smrg		TRACE(("...could did not open %s font\n", tag));
1374d522f475Smrg		XftPatternDestroy(match);
1375d522f475Smrg	    }
1376d522f475Smrg	} else {
1377d522f475Smrg	    TRACE(("...did not match %s font\n", tag));
1378d522f475Smrg	}
1379d522f475Smrg    }
1380d522f475Smrg    return result;
1381d522f475Smrg}
1382d522f475Smrg#endif
1383d522f475Smrg
1384d522f475Smrg#if OPT_RENDERFONT
1385d522f475Smrg#if OPT_SHIFT_FONTS
1386d522f475Smrg/*
1387d522f475Smrg * Don't make a dependency on the math library for a single function.
1388d522f475Smrg * (Newton Raphson).
1389d522f475Smrg */
1390d522f475Smrgstatic double
1391d522f475SmrgmySquareRoot(double value)
1392d522f475Smrg{
1393d522f475Smrg    double result = 0.0;
1394d522f475Smrg    if (value > 0.0) {
1395d522f475Smrg	int n;
1396d522f475Smrg	double older = value;
1397d522f475Smrg	for (n = 0; n < 10; ++n) {
1398d522f475Smrg	    double delta = (older * older - value) / (2.0 * older);
1399d522f475Smrg	    double newer = older - delta;
1400d522f475Smrg	    older = newer;
1401d522f475Smrg	    result = newer;
1402d522f475Smrg	    if (delta > -0.001 && delta < 0.001)
1403d522f475Smrg		break;
1404d522f475Smrg	}
1405d522f475Smrg    }
1406d522f475Smrg    return result;
1407d522f475Smrg}
1408d522f475Smrg#endif
1409d522f475Smrg
1410d522f475Smrg/*
1411d522f475Smrg * Given the Xft font metrics, determine the actual font size.  This is used
1412d522f475Smrg * for each font to ensure that normal, bold and italic fonts follow the same
1413d522f475Smrg * rule.
1414d522f475Smrg */
1415d522f475Smrgstatic void
1416d522f475SmrgsetRenderFontsize(TScreen * screen, VTwin * win, XftFont * font, const char *tag)
1417d522f475Smrg{
1418d522f475Smrg    if (font != 0) {
1419d522f475Smrg	int width, height, ascent, descent;
1420d522f475Smrg
1421d522f475Smrg	(void) screen;
1422d522f475Smrg
1423d522f475Smrg	width = font->max_advance_width;
1424d522f475Smrg	height = font->height;
1425d522f475Smrg	ascent = font->ascent;
1426d522f475Smrg	descent = font->descent;
1427d522f475Smrg	if (height < ascent + descent) {
1428d522f475Smrg	    TRACE(("...increase height from %d\n", height));
1429d522f475Smrg	    height = ascent + descent;
1430d522f475Smrg	}
1431d522f475Smrg	if (is_double_width_font_xft(screen->display, font)) {
1432d522f475Smrg	    TRACE(("...reduced width from %d\n", width));
1433d522f475Smrg	    width >>= 1;
1434d522f475Smrg	}
1435d522f475Smrg	if (tag == 0) {
1436d522f475Smrg	    win->f_width = width;
1437d522f475Smrg	    win->f_height = height;
1438d522f475Smrg	    win->f_ascent = ascent;
1439d522f475Smrg	    win->f_descent = descent;
1440d522f475Smrg	    TRACE(("setRenderFontsize result %dx%d (%d+%d)\n",
1441d522f475Smrg		   width, height, ascent, descent));
1442d522f475Smrg	} else if (win->f_width < width ||
1443d522f475Smrg		   win->f_height < height ||
1444d522f475Smrg		   win->f_ascent < ascent ||
1445d522f475Smrg		   win->f_descent < descent) {
1446d522f475Smrg	    TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n",
1447d522f475Smrg		   tag,
1448d522f475Smrg		   win->f_width, win->f_height, win->f_ascent, win->f_descent,
1449d522f475Smrg		   width, height, ascent, descent));
1450d522f475Smrg
1451d522f475Smrg	    win->f_width = width;
1452d522f475Smrg	    win->f_height = height;
1453d522f475Smrg	    win->f_ascent = ascent;
1454d522f475Smrg	    win->f_descent = descent;
1455d522f475Smrg	} else {
1456d522f475Smrg	    TRACE(("setRenderFontsize %s unchanged\n", tag));
1457d522f475Smrg	}
1458d522f475Smrg    }
1459d522f475Smrg}
1460d522f475Smrg#endif
1461d522f475Smrg
1462d522f475Smrg/*
1463d522f475Smrg * Compute useful values for the font/window sizes
1464d522f475Smrg */
1465d522f475Smrgvoid
1466d522f475SmrgxtermComputeFontInfo(XtermWidget xw,
1467d522f475Smrg		     VTwin * win,
1468d522f475Smrg		     XFontStruct * font,
1469d522f475Smrg		     int sbwidth)
1470d522f475Smrg{
1471d522f475Smrg    TScreen *screen = &(xw->screen);
1472d522f475Smrg
1473d522f475Smrg    int i, j, width, height;
1474d522f475Smrg
1475d522f475Smrg#if OPT_RENDERFONT
1476d522f475Smrg    /*
1477d522f475Smrg     * xterm contains a lot of references to fonts, assuming they are fixed
1478d522f475Smrg     * size.  This chunk of code overrides the actual font-selection (see
1479d522f475Smrg     * drawXtermText()), if the user has selected render-font.  All of the
1480d522f475Smrg     * font-loading for fixed-fonts still goes on whether or not this chunk
1481d522f475Smrg     * overrides it.
1482d522f475Smrg     */
1483d522f475Smrg    if (xw->misc.render_font && !IsIconWin(screen, win)) {
1484d522f475Smrg	Display *dpy = screen->display;
1485d522f475Smrg	int fontnum = screen->menu_font_number;
1486d522f475Smrg	XftFont *norm = screen->renderFontNorm[fontnum];
1487d522f475Smrg	XftFont *bold = screen->renderFontBold[fontnum];
1488d522f475Smrg	XftFont *ital = screen->renderFontItal[fontnum];
1489d522f475Smrg#if OPT_RENDERWIDE
1490d522f475Smrg	XftFont *wnorm = screen->renderWideNorm[fontnum];
1491d522f475Smrg	XftFont *wbold = screen->renderWideBold[fontnum];
1492d522f475Smrg	XftFont *wital = screen->renderWideItal[fontnum];
1493d522f475Smrg#endif
1494d522f475Smrg
1495d522f475Smrg	if (norm == 0 && xw->misc.face_name) {
1496d522f475Smrg	    XftPattern *pat;
1497d522f475Smrg	    double face_size = xw->misc.face_size[fontnum];
1498d522f475Smrg
1499d522f475Smrg	    TRACE(("xtermComputeFontInfo norm(face %s, size %f)\n",
1500d522f475Smrg		   xw->misc.face_name,
1501d522f475Smrg		   xw->misc.face_size[fontnum]));
1502d522f475Smrg
1503d522f475Smrg	    if (face_size <= 0.0) {
1504d522f475Smrg#if OPT_SHIFT_FONTS
1505d522f475Smrg		/*
1506d522f475Smrg		 * If the user is switching font-sizes, make it follow by
1507d522f475Smrg		 * default the same ratios to the default as the fixed fonts
1508d522f475Smrg		 * would, for easy comparison.  There will be some differences
1509d522f475Smrg		 * since the fixed fonts have a variety of height/width ratios,
1510d522f475Smrg		 * but this is simpler than adding another resource value - and
1511d522f475Smrg		 * as noted above, the data for the fixed fonts are available.
1512d522f475Smrg		 */
1513d522f475Smrg		lookupOneFontSize(xw, 0);
1514d522f475Smrg		lookupOneFontSize(xw, fontnum);
1515d522f475Smrg		if (fontnum == fontMenu_default) {
1516d522f475Smrg		    face_size = 14.0;
1517d522f475Smrg		} else {
1518d522f475Smrg		    double ratio;
1519d522f475Smrg		    int num = screen->menu_font_sizes[fontnum];
1520d522f475Smrg		    int den = screen->menu_font_sizes[0];
1521d522f475Smrg
1522d522f475Smrg		    if (den <= 0)
1523d522f475Smrg			den = 1;
1524d522f475Smrg		    ratio = mySquareRoot((1.0 * num) / den);
1525d522f475Smrg
1526d522f475Smrg		    face_size = (ratio * xw->misc.face_size[0]);
1527d522f475Smrg		    TRACE(("scaled using %3d/%d = %.2f -> %f\n",
1528d522f475Smrg			   num, den, ratio, face_size));
1529d522f475Smrg		}
1530d522f475Smrg#else
1531d522f475Smrg		switch (fontnum) {
1532d522f475Smrg		case fontMenu_font1:
1533d522f475Smrg		    face_size = 8.0;
1534d522f475Smrg		    break;
1535d522f475Smrg		case fontMenu_font2:
1536d522f475Smrg		    face_size = 10.0;
1537d522f475Smrg		    break;
1538d522f475Smrg		case fontMenu_font3:
1539d522f475Smrg		    face_size = 12.0;
1540d522f475Smrg		    break;
1541d522f475Smrg		default:
1542d522f475Smrg		    face_size = 14.0;
1543d522f475Smrg		    break;
1544d522f475Smrg		case fontMenu_font4:
1545d522f475Smrg		    face_size = 16.0;
1546d522f475Smrg		    break;
1547d522f475Smrg		case fontMenu_font5:
1548d522f475Smrg		    face_size = 18.0;
1549d522f475Smrg		    break;
1550d522f475Smrg		case fontMenu_font6:
1551d522f475Smrg		    face_size = 20.0;
1552d522f475Smrg		    break;
1553d522f475Smrg		}
1554d522f475Smrg#endif
1555d522f475Smrg		xw->misc.face_size[fontnum] = face_size;
1556d522f475Smrg	    }
1557d522f475Smrg
1558d522f475Smrg	    /*
1559d522f475Smrg	     * By observation (there is no documentation), XftPatternBuild is
1560d522f475Smrg	     * cumulative.  Build the bold- and italic-patterns on top of the
1561d522f475Smrg	     * normal pattern.
1562d522f475Smrg	     */
1563d522f475Smrg#define NormXftPattern \
1564d522f475Smrg	    XFT_FAMILY, XftTypeString, "mono", \
1565d522f475Smrg	    XFT_SIZE, XftTypeDouble, face_size, \
1566d522f475Smrg	    XFT_SPACING, XftTypeInteger, XFT_MONO
1567d522f475Smrg
1568d522f475Smrg#define BoldXftPattern(norm) \
1569d522f475Smrg	    XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \
1570d522f475Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width
1571d522f475Smrg
1572d522f475Smrg#define ItalXftPattern(norm) \
1573d522f475Smrg	    XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \
1574d522f475Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width
1575d522f475Smrg
1576d522f475Smrg	    if ((pat = XftNameParse(xw->misc.face_name)) != 0) {
1577d522f475Smrg		XftPatternBuild(pat,
1578d522f475Smrg				NormXftPattern,
1579d522f475Smrg				(void *) 0);
1580d522f475Smrg		norm = xtermOpenXft(dpy, pat, "normal");
1581d522f475Smrg
1582d522f475Smrg		if (norm != 0) {
1583d522f475Smrg		    XftPatternBuild(pat,
1584d522f475Smrg				    BoldXftPattern(norm),
1585d522f475Smrg				    (void *) 0);
1586d522f475Smrg		    bold = xtermOpenXft(dpy, pat, "bold");
1587d522f475Smrg
1588d522f475Smrg#if OPT_ISO_COLORS
1589d522f475Smrg		    if (screen->italicULMode
1590d522f475Smrg			&& (pat = XftNameParse(xw->misc.face_name)) != 0) {
1591d522f475Smrg			XftPatternBuild(pat,
1592d522f475Smrg					NormXftPattern,
1593d522f475Smrg					ItalXftPattern(norm),
1594d522f475Smrg					(void *) 0);
1595d522f475Smrg			ital = xtermOpenXft(dpy, pat, "italic");
1596d522f475Smrg		    }
1597d522f475Smrg#endif /* OPT_ISO_COLORS */
1598d522f475Smrg
1599d522f475Smrg		    /*
1600d522f475Smrg		     * FIXME:  just assume that the corresponding font has no
1601d522f475Smrg		     * graphics characters.
1602d522f475Smrg		     */
1603d522f475Smrg		    if (screen->fnt_boxes) {
1604d522f475Smrg			screen->fnt_boxes = False;
1605d522f475Smrg			TRACE(("Xft opened - will %suse internal line-drawing characters\n",
1606d522f475Smrg			       screen->fnt_boxes ? "not " : ""));
1607d522f475Smrg		    }
1608d522f475Smrg		}
1609d522f475Smrg
1610d522f475Smrg		XftPatternDestroy(pat);
1611d522f475Smrg	    }
1612d522f475Smrg
1613d522f475Smrg	    CACHE_XFT(screen->renderFontNorm, norm);
1614d522f475Smrg	    CACHE_XFT(screen->renderFontBold, bold);
1615d522f475Smrg	    CACHE_XFT(screen->renderFontItal, ital);
1616d522f475Smrg
1617d522f475Smrg	    /*
1618d522f475Smrg	     * See xtermXftDrawString().
1619d522f475Smrg	     */
1620d522f475Smrg#if OPT_RENDERWIDE
1621d522f475Smrg	    if (norm != 0 && screen->wide_chars) {
1622d522f475Smrg		char *face_name = (xw->misc.face_wide_name
1623d522f475Smrg				   ? xw->misc.face_wide_name
1624d522f475Smrg				   : xw->misc.face_name);
1625d522f475Smrg		int char_width = norm->max_advance_width * 2;
1626d522f475Smrg
1627d522f475Smrg		TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n",
1628d522f475Smrg		       face_name,
1629d522f475Smrg		       char_width));
1630d522f475Smrg
1631d522f475Smrg#define WideXftPattern \
1632d522f475Smrg		XFT_FAMILY, XftTypeString, "mono", \
1633d522f475Smrg		XFT_SIZE, XftTypeDouble, face_size, \
1634d522f475Smrg		XFT_SPACING, XftTypeInteger, XFT_MONO
1635d522f475Smrg
1636d522f475Smrg		if ((pat = XftNameParse(face_name)) != 0) {
1637d522f475Smrg		    XftPatternBuild(pat,
1638d522f475Smrg				    WideXftPattern,
1639d522f475Smrg				    XFT_CHAR_WIDTH, XftTypeInteger, char_width,
1640d522f475Smrg				    (void *) 0);
1641d522f475Smrg		    wnorm = xtermOpenXft(dpy, pat, "wide");
1642d522f475Smrg
1643d522f475Smrg		    if (wnorm != 0) {
1644d522f475Smrg			XftPatternBuild(pat,
1645d522f475Smrg					WideXftPattern,
1646d522f475Smrg					BoldXftPattern(wnorm),
1647d522f475Smrg					(void *) 0);
1648d522f475Smrg			wbold = xtermOpenXft(dpy, pat, "wide-bold");
1649d522f475Smrg
1650d522f475Smrg#if OPT_ISO_COLORS
1651d522f475Smrg			if (screen->italicULMode
1652d522f475Smrg			    && (pat = XftNameParse(face_name)) != 0) {
1653d522f475Smrg			    XftPatternBuild(pat,
1654d522f475Smrg					    WideXftPattern,
1655d522f475Smrg					    ItalXftPattern(wnorm),
1656d522f475Smrg					    (void *) 0);
1657d522f475Smrg			    wital = xtermOpenXft(dpy, pat, "wide-italic");
1658d522f475Smrg			}
1659d522f475Smrg#endif
1660d522f475Smrg		    }
1661d522f475Smrg		    XftPatternDestroy(pat);
1662d522f475Smrg		}
1663d522f475Smrg
1664d522f475Smrg		CACHE_XFT(screen->renderWideNorm, wnorm);
1665d522f475Smrg		CACHE_XFT(screen->renderWideBold, wbold);
1666d522f475Smrg		CACHE_XFT(screen->renderWideItal, wital);
1667d522f475Smrg	    }
1668d522f475Smrg#endif /* OPT_RENDERWIDE */
1669d522f475Smrg	}
1670d522f475Smrg	if (norm == 0) {
1671d522f475Smrg	    xw->misc.render_font = False;
1672d522f475Smrg	    update_font_renderfont();
1673d522f475Smrg	    /* now we will fall through into the bitmap fonts */
1674d522f475Smrg	} else {
1675d522f475Smrg	    setRenderFontsize(screen, win, norm, NULL);
1676d522f475Smrg	    setRenderFontsize(screen, win, bold, "bold");
1677d522f475Smrg	    setRenderFontsize(screen, win, ital, "ital");
1678d522f475Smrg	}
1679d522f475Smrg    }
1680d522f475Smrg    /*
1681d522f475Smrg     * Are we handling a bitmap font?
1682d522f475Smrg     */
1683d522f475Smrg    if (!xw->misc.render_font || IsIconWin(screen, win))
1684d522f475Smrg#endif /* OPT_RENDERFONT */
1685d522f475Smrg    {
1686d522f475Smrg	if (is_double_width_font(font)) {
1687d522f475Smrg	    win->f_width = (font->min_bounds.width);
1688d522f475Smrg	} else {
1689d522f475Smrg	    win->f_width = (font->max_bounds.width);
1690d522f475Smrg	}
1691d522f475Smrg	win->f_height = (font->ascent + font->descent);
1692d522f475Smrg	win->f_ascent = font->ascent;
1693d522f475Smrg	win->f_descent = font->descent;
1694d522f475Smrg    }
1695d522f475Smrg    i = 2 * screen->border + sbwidth;
1696d522f475Smrg    j = 2 * screen->border;
1697d522f475Smrg    width = MaxCols(screen) * win->f_width + i;
1698d522f475Smrg    height = MaxRows(screen) * win->f_height + j;
1699d522f475Smrg    win->fullwidth = width;
1700d522f475Smrg    win->fullheight = height;
1701d522f475Smrg    win->width = width - i;
1702d522f475Smrg    win->height = height - j;
1703d522f475Smrg
1704d522f475Smrg    TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n",
1705d522f475Smrg	   win->height,
1706d522f475Smrg	   win->width,
1707d522f475Smrg	   win->fullheight,
1708d522f475Smrg	   win->fullwidth,
1709d522f475Smrg	   win->f_height,
1710d522f475Smrg	   win->f_width,
1711d522f475Smrg	   win->f_ascent,
1712d522f475Smrg	   win->f_descent));
1713d522f475Smrg}
1714d522f475Smrg
1715d522f475Smrg/* save this information as a side-effect for double-sized characters */
1716d522f475Smrgvoid
1717d522f475SmrgxtermSaveFontInfo(TScreen * screen, XFontStruct * font)
1718d522f475Smrg{
1719d522f475Smrg    screen->fnt_wide = (font->max_bounds.width);
1720d522f475Smrg    screen->fnt_high = (font->ascent + font->descent);
1721d522f475Smrg    TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide));
1722d522f475Smrg}
1723d522f475Smrg
1724d522f475Smrg/*
1725d522f475Smrg * After loading a new font, update the structures that use its size.
1726d522f475Smrg */
1727d522f475Smrgvoid
1728d522f475SmrgxtermUpdateFontInfo(XtermWidget xw, Bool doresize)
1729d522f475Smrg{
1730d522f475Smrg    TScreen *screen = &(xw->screen);
1731d522f475Smrg
1732d522f475Smrg    int scrollbar_width;
1733d522f475Smrg    VTwin *win = &(screen->fullVwin);
1734d522f475Smrg
1735d522f475Smrg    scrollbar_width = (xw->misc.scrollbar
1736d522f475Smrg		       ? (screen->scrollWidget->core.width +
1737d522f475Smrg			  BorderWidth(screen->scrollWidget))
1738d522f475Smrg		       : 0);
1739d522f475Smrg    xtermComputeFontInfo(xw, win, screen->fnts[fNorm].fs, scrollbar_width);
1740d522f475Smrg    xtermSaveFontInfo(screen, screen->fnts[fNorm].fs);
1741d522f475Smrg
1742d522f475Smrg    if (doresize) {
1743d522f475Smrg	if (VWindow(screen)) {
1744d522f475Smrg	    xtermClear(xw);
1745d522f475Smrg	}
1746d522f475Smrg	TRACE(("xtermUpdateFontInfo {{\n"));
1747d522f475Smrg	DoResizeScreen(xw);	/* set to the new natural size */
1748d522f475Smrg	ResizeScrollBar(xw);
1749d522f475Smrg	Redraw();
1750d522f475Smrg	TRACE(("... }} xtermUpdateFontInfo\n"));
1751d522f475Smrg#ifdef SCROLLBAR_RIGHT
1752d522f475Smrg	updateRightScrollbar(xw);
1753d522f475Smrg#endif
1754d522f475Smrg    }
1755d522f475Smrg    xtermSetCursorBox(screen);
1756d522f475Smrg}
1757d522f475Smrg
1758d522f475Smrg#if OPT_BOX_CHARS
1759d522f475Smrg
1760d522f475Smrg/*
1761d522f475Smrg * Returns true if the given character is missing from the specified font.
1762d522f475Smrg */
1763d522f475SmrgBool
1764d522f475SmrgxtermMissingChar(XtermWidget xw, unsigned ch, XFontStruct * font)
1765d522f475Smrg{
1766d522f475Smrg    if (font != 0
1767d522f475Smrg	&& font->per_char != 0
1768d522f475Smrg	&& !font->all_chars_exist) {
1769d522f475Smrg	static XCharStruct dft, *tmp = &dft, *pc = 0;
1770d522f475Smrg
1771d522f475Smrg	if (font->max_byte1 == 0) {
1772d522f475Smrg#if OPT_WIDE_CHARS
1773d522f475Smrg	    if (ch > 255) {
1774d522f475Smrg		TRACE(("xtermMissingChar %#04x (row)\n", ch));
1775d522f475Smrg		return True;
1776d522f475Smrg	    }
1777d522f475Smrg#endif
1778d522f475Smrg	    CI_GET_CHAR_INFO_1D(font, E2A(ch), tmp, pc);
1779d522f475Smrg	}
1780d522f475Smrg#if OPT_WIDE_CHARS
1781d522f475Smrg	else {
1782d522f475Smrg	    CI_GET_CHAR_INFO_2D(font, HI_BYTE(ch), LO_BYTE(ch), tmp, pc);
1783d522f475Smrg	}
1784d522f475Smrg#else
1785d522f475Smrg
1786d522f475Smrg	if (!pc)
1787d522f475Smrg	    return False;	/* Urgh! */
1788d522f475Smrg#endif
1789d522f475Smrg
1790d522f475Smrg	if (CI_NONEXISTCHAR(pc)) {
1791d522f475Smrg	    TRACE(("xtermMissingChar %#04x (!exists)\n", ch));
1792d522f475Smrg	    return True;
1793d522f475Smrg	}
1794d522f475Smrg    }
1795d522f475Smrg    if (xtermIsDecGraphic(ch)
1796d522f475Smrg	&& xw->screen.force_box_chars) {
1797d522f475Smrg	TRACE(("xtermMissingChar %#04x (forced off)\n", ch));
1798d522f475Smrg	return True;
1799d522f475Smrg    }
1800d522f475Smrg    return False;
1801d522f475Smrg}
1802d522f475Smrg
1803d522f475Smrg/*
1804d522f475Smrg * The grid is arbitrary, enough resolution that nothing's lost in
1805d522f475Smrg * initialization.
1806d522f475Smrg */
1807d522f475Smrg#define BOX_HIGH 60
1808d522f475Smrg#define BOX_WIDE 60
1809d522f475Smrg
1810d522f475Smrg#define MID_HIGH (BOX_HIGH/2)
1811d522f475Smrg#define MID_WIDE (BOX_WIDE/2)
1812d522f475Smrg
1813d522f475Smrg#define CHR_WIDE ((9*BOX_WIDE)/10)
1814d522f475Smrg#define CHR_HIGH ((9*BOX_HIGH)/10)
1815d522f475Smrg
1816d522f475Smrg/*
1817d522f475Smrg * ...since we'll scale the values anyway.
1818d522f475Smrg */
1819d522f475Smrg#define SCALE_X(n) n = (n * (font_width-1)) / (BOX_WIDE-1)
1820d522f475Smrg#define SCALE_Y(n) n = (n * (font_height-1)) / (BOX_HIGH-1)
1821d522f475Smrg
1822d522f475Smrg#define SEG(x0,y0,x1,y1) x0,y0, x1,y1
1823d522f475Smrg
1824d522f475Smrg/*
1825d522f475Smrg * Draw the given graphic character, if it is simple enough (i.e., a
1826d522f475Smrg * line-drawing character).
1827d522f475Smrg */
1828d522f475Smrgvoid
1829d522f475SmrgxtermDrawBoxChar(XtermWidget xw,
1830d522f475Smrg		 unsigned ch,
1831d522f475Smrg		 unsigned flags,
1832d522f475Smrg		 GC gc,
1833d522f475Smrg		 int x,
1834d522f475Smrg		 int y,
1835d522f475Smrg		 int cells)
1836d522f475Smrg{
1837d522f475Smrg    TScreen *screen = &(xw->screen);
1838d522f475Smrg    /* *INDENT-OFF* */
1839d522f475Smrg    static const short glyph_ht[] = {
1840d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,5*MID_HIGH/6),	/* H */
1841d522f475Smrg	SEG(6*BOX_WIDE/10,  0,		6*BOX_WIDE/10,5*MID_HIGH/6),
1842d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12),
1843d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
1844d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
1845d522f475Smrg	-1
1846d522f475Smrg    }, glyph_ff[] = {
1847d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		6*BOX_WIDE/10,	0),		/* F */
1848d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12),
1849d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		0*BOX_WIDE/3, 5*MID_HIGH/6),
1850d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
1851d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
1852d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
1853d522f475Smrg	-1
1854d522f475Smrg    }, glyph_lf[] = {
1855d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,9*MID_HIGH/12),	/* L */
1856d522f475Smrg	SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12),
1857d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
1858d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
1859d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
1860d522f475Smrg	-1
1861d522f475Smrg    }, glyph_nl[] = {
1862d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10,	0),		/* N */
1863d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		5*BOX_WIDE/6, 5*MID_HIGH/6),
1864d522f475Smrg	SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
1865d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),	/* L */
1866d522f475Smrg	SEG(1*BOX_WIDE/3,   CHR_HIGH,	  CHR_WIDE,	CHR_HIGH),
1867d522f475Smrg	-1
1868d522f475Smrg    }, glyph_vt[] = {
1869d522f475Smrg	SEG(1*BOX_WIDE/10,   0,		5*BOX_WIDE/12,5*MID_HIGH/6),	/* V */
1870d522f475Smrg	SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
1871d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
1872d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
1873d522f475Smrg	-1
1874d522f475Smrg    }, plus_or_minus[] =
1875d522f475Smrg    {
1876d522f475Smrg	SEG(  0,	  5*BOX_HIGH/6,	  CHR_WIDE,   5*BOX_HIGH/6),
1877d522f475Smrg	SEG(  MID_WIDE,	  2*BOX_HIGH/6,	  MID_WIDE,   4*BOX_HIGH/6),
1878d522f475Smrg	SEG(  0,	  3*BOX_HIGH/6,	  CHR_WIDE,   3*BOX_HIGH/6),
1879d522f475Smrg	-1
1880d522f475Smrg    }, lower_right_corner[] =
1881d522f475Smrg    {
1882d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
1883d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	0),
1884d522f475Smrg	-1
1885d522f475Smrg    }, upper_right_corner[] =
1886d522f475Smrg    {
1887d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
1888d522f475Smrg	SEG( MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
1889d522f475Smrg	-1
1890d522f475Smrg    }, upper_left_corner[] =
1891d522f475Smrg    {
1892d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
1893d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
1894d522f475Smrg	-1
1895d522f475Smrg    }, lower_left_corner[] =
1896d522f475Smrg    {
1897d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
1898d522f475Smrg	SEG(  MID_WIDE,	    MID_WIDE,	  BOX_WIDE,	MID_HIGH),
1899d522f475Smrg	-1
1900d522f475Smrg    }, cross[] =
1901d522f475Smrg    {
1902d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
1903d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
1904d522f475Smrg	-1
1905d522f475Smrg    }, scan_line_1[] =
1906d522f475Smrg    {
1907d522f475Smrg	SEG(  0,	    0,		  BOX_WIDE,	0),
1908d522f475Smrg	-1
1909d522f475Smrg    }, scan_line_3[] =
1910d522f475Smrg    {
1911d522f475Smrg	SEG(  0,	    BOX_HIGH/4,	  BOX_WIDE,	BOX_HIGH/4),
1912d522f475Smrg	-1
1913d522f475Smrg    }, scan_line_7[] =
1914d522f475Smrg    {
1915d522f475Smrg	SEG( 0,		    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
1916d522f475Smrg	-1
1917d522f475Smrg    }, scan_line_9[] =
1918d522f475Smrg    {
1919d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  BOX_WIDE,   3*BOX_HIGH/4),
1920d522f475Smrg	-1
1921d522f475Smrg    }, horizontal_line[] =
1922d522f475Smrg    {
1923d522f475Smrg	SEG(  0,	    BOX_HIGH,	  BOX_WIDE,	BOX_HIGH),
1924d522f475Smrg	-1
1925d522f475Smrg    }, left_tee[] =
1926d522f475Smrg    {
1927d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
1928d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
1929d522f475Smrg	-1
1930d522f475Smrg    }, right_tee[] =
1931d522f475Smrg    {
1932d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
1933d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  0,		MID_HIGH),
1934d522f475Smrg	-1
1935d522f475Smrg    }, bottom_tee[] =
1936d522f475Smrg    {
1937d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
1938d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
1939d522f475Smrg	-1
1940d522f475Smrg    }, top_tee[] =
1941d522f475Smrg    {
1942d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
1943d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
1944d522f475Smrg	-1
1945d522f475Smrg    }, vertical_line[] =
1946d522f475Smrg    {
1947d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
1948d522f475Smrg	-1
1949d522f475Smrg    }, less_than_or_equal[] =
1950d522f475Smrg    {
1951d522f475Smrg	SEG(  CHR_WIDE,	    BOX_HIGH/3,	  0,		MID_HIGH),
1952d522f475Smrg	SEG(  CHR_WIDE,	  2*BOX_HIGH/3,	  0,		MID_HIGH),
1953d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
1954d522f475Smrg	-1
1955d522f475Smrg    }, greater_than_or_equal[] =
1956d522f475Smrg    {
1957d522f475Smrg	SEG(  0,	    BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
1958d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
1959d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
1960d522f475Smrg	-1
1961d522f475Smrg    }, greek_pi[] =
1962d522f475Smrg    {
1963d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
1964d522f475Smrg	SEG(5*CHR_WIDE/6,   MID_HIGH,	5*CHR_WIDE/6,	CHR_HIGH),
1965d522f475Smrg	SEG(2*CHR_WIDE/6,   MID_HIGH,	2*CHR_WIDE/6,	CHR_HIGH),
1966d522f475Smrg	-1
1967d522f475Smrg    }, not_equal_to[] =
1968d522f475Smrg    {
1969d522f475Smrg	SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3,	CHR_HIGH),
1970d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,   2*BOX_HIGH/3),
1971d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
1972d522f475Smrg	-1
1973d522f475Smrg    };
1974d522f475Smrg    /* *INDENT-ON* */
1975d522f475Smrg
1976d522f475Smrg    static const short *lines[] =
1977d522f475Smrg    {
1978d522f475Smrg	0,			/* 00 (unused) */
1979d522f475Smrg	0,			/* 01 diamond */
1980d522f475Smrg	0,			/* 02 box */
1981d522f475Smrg	glyph_ht,		/* 03 HT */
1982d522f475Smrg	glyph_ff,		/* 04 FF */
1983d522f475Smrg	0,			/* 05 CR */
1984d522f475Smrg	glyph_lf,		/* 06 LF */
1985d522f475Smrg	0,			/* 07 degrees (small circle) */
1986d522f475Smrg	plus_or_minus,		/* 08 */
1987d522f475Smrg	glyph_nl,		/* 09 */
1988d522f475Smrg	glyph_vt,		/* 0A */
1989d522f475Smrg	lower_right_corner,	/* 0B */
1990d522f475Smrg	upper_right_corner,	/* 0C */
1991d522f475Smrg	upper_left_corner,	/* 0D */
1992d522f475Smrg	lower_left_corner,	/* 0E */
1993d522f475Smrg	cross,			/* 0F */
1994d522f475Smrg	scan_line_1,		/* 10 */
1995d522f475Smrg	scan_line_3,		/* 11 */
1996d522f475Smrg	scan_line_7,		/* 12 */
1997d522f475Smrg	scan_line_9,		/* 13 */
1998d522f475Smrg	horizontal_line,	/* 14 */
1999d522f475Smrg	left_tee,		/* 15 */
2000d522f475Smrg	right_tee,		/* 16 */
2001d522f475Smrg	bottom_tee,		/* 17 */
2002d522f475Smrg	top_tee,		/* 18 */
2003d522f475Smrg	vertical_line,		/* 19 */
2004d522f475Smrg	less_than_or_equal,	/* 1A */
2005d522f475Smrg	greater_than_or_equal,	/* 1B */
2006d522f475Smrg	greek_pi,		/* 1C */
2007d522f475Smrg	not_equal_to,		/* 1D */
2008d522f475Smrg	0,			/* 1E LB */
2009d522f475Smrg	0,			/* 1F bullet */
2010d522f475Smrg    };
2011d522f475Smrg
2012d522f475Smrg    GC gc2;
2013d522f475Smrg    CgsEnum cgsId = (ch == 2) ? gcDots : gcLine;
2014d522f475Smrg    VTwin *cgsWin = WhichVWin(screen);
2015d522f475Smrg    const short *p;
2016d522f475Smrg    unsigned font_width = ((flags & DOUBLEWFONT) ? 2 : 1) * screen->fnt_wide;
2017d522f475Smrg    unsigned font_height = ((flags & DOUBLEHFONT) ? 2 : 1) * screen->fnt_high;
2018d522f475Smrg
2019d522f475Smrg    if (cells > 1)
2020d522f475Smrg	font_width *= cells;
2021d522f475Smrg
2022d522f475Smrg#if OPT_WIDE_CHARS
2023d522f475Smrg    /*
2024d522f475Smrg     * Try to show line-drawing characters if we happen to be in UTF-8
2025d522f475Smrg     * mode, but have gotten an old-style font.
2026d522f475Smrg     */
2027d522f475Smrg    if (screen->utf8_mode
2028d522f475Smrg#if OPT_RENDERFONT
2029d522f475Smrg	&& !UsingRenderFont(xw)
2030d522f475Smrg#endif
2031d522f475Smrg	&& (ch > 127)
2032d522f475Smrg	&& (ch != UCS_REPL)) {
2033d522f475Smrg	unsigned n;
2034d522f475Smrg	for (n = 1; n < 32; n++) {
2035d522f475Smrg	    if (dec2ucs(n) == ch
2036d522f475Smrg		&& !xtermMissingChar(xw, n,
2037d522f475Smrg				     ((flags & BOLD)
2038d522f475Smrg				      ? screen->fnts[fBold].fs
2039d522f475Smrg				      : screen->fnts[fNorm].fs))) {
2040d522f475Smrg		TRACE(("...use xterm-style linedrawing\n"));
2041d522f475Smrg		ch = n;
2042d522f475Smrg		break;
2043d522f475Smrg	    }
2044d522f475Smrg	}
2045d522f475Smrg    }
2046d522f475Smrg#endif
2047d522f475Smrg
2048d522f475Smrg    TRACE(("DRAW_BOX(%d) cell %dx%d at %d,%d%s\n",
2049d522f475Smrg	   ch, font_height, font_width, y, x,
2050d522f475Smrg	   (ch >= (sizeof(lines) / sizeof(lines[0]))
2051d522f475Smrg	    ? "-BAD"
2052d522f475Smrg	    : "")));
2053d522f475Smrg
2054d522f475Smrg    if (cgsId == gcDots) {
2055d522f475Smrg	setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2056d522f475Smrg	setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc));
2057d522f475Smrg	setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2058d522f475Smrg    } else {
2059d522f475Smrg	setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2060d522f475Smrg	setCgsFore(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2061d522f475Smrg	setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2062d522f475Smrg    }
2063d522f475Smrg    gc2 = getCgsGC(xw, cgsWin, cgsId);
2064d522f475Smrg
2065d522f475Smrg    if (!(flags & NOBACKGROUND)) {
2066d522f475Smrg	XFillRectangle(screen->display, VWindow(screen), gc2, x, y,
2067d522f475Smrg		       font_width,
2068d522f475Smrg		       font_height);
2069d522f475Smrg    }
2070d522f475Smrg
2071d522f475Smrg    setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2072d522f475Smrg    setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc));
2073d522f475Smrg    setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2074d522f475Smrg    gc2 = getCgsGC(xw, cgsWin, cgsId);
2075d522f475Smrg
2076d522f475Smrg    XSetLineAttributes(screen->display, gc2,
2077d522f475Smrg		       (flags & BOLD)
2078d522f475Smrg		       ? ((font_height > 12)
2079d522f475Smrg			  ? font_height / 12
2080d522f475Smrg			  : 1)
2081d522f475Smrg		       : ((font_height > 16)
2082d522f475Smrg			  ? font_height / 16
2083d522f475Smrg			  : 1),
2084d522f475Smrg		       LineSolid,
2085d522f475Smrg		       CapProjecting,
2086d522f475Smrg		       JoinMiter);
2087d522f475Smrg
2088d522f475Smrg    if (ch == 1) {		/* diamond */
2089d522f475Smrg	XPoint points[5];
2090d522f475Smrg	int npoints = 5, n;
2091d522f475Smrg
2092d522f475Smrg	points[0].x = MID_WIDE;
2093d522f475Smrg	points[0].y = BOX_HIGH / 4;
2094d522f475Smrg
2095d522f475Smrg	points[1].x = 8 * BOX_WIDE / 8;
2096d522f475Smrg	points[1].y = MID_HIGH;
2097d522f475Smrg
2098d522f475Smrg	points[2].x = points[0].x;
2099d522f475Smrg	points[2].y = 3 * BOX_HIGH / 4;
2100d522f475Smrg
2101d522f475Smrg	points[3].x = 0 * BOX_WIDE / 8;
2102d522f475Smrg	points[3].y = points[1].y;
2103d522f475Smrg
2104d522f475Smrg	points[4].x = points[0].x;
2105d522f475Smrg	points[4].y = points[0].y;
2106d522f475Smrg
2107d522f475Smrg	for (n = 0; n < npoints; ++n) {
2108d522f475Smrg	    SCALE_X(points[n].x);
2109d522f475Smrg	    SCALE_Y(points[n].y);
2110d522f475Smrg	    points[n].x += x;
2111d522f475Smrg	    points[n].y += y;
2112d522f475Smrg	}
2113d522f475Smrg
2114d522f475Smrg	XFillPolygon(screen->display,
2115d522f475Smrg		     VWindow(screen), gc2,
2116d522f475Smrg		     points, npoints,
2117d522f475Smrg		     Convex, CoordModeOrigin);
2118d522f475Smrg    } else if (ch == 7) {	/* degrees */
2119d522f475Smrg	unsigned width = (BOX_WIDE / 3);
2120d522f475Smrg	int x_coord = MID_WIDE - (width / 2);
2121d522f475Smrg	int y_coord = MID_HIGH - width;
2122d522f475Smrg
2123d522f475Smrg	SCALE_X(x_coord);
2124d522f475Smrg	SCALE_Y(y_coord);
2125d522f475Smrg	SCALE_X(width);
2126d522f475Smrg
2127d522f475Smrg	XDrawArc(screen->display,
2128d522f475Smrg		 VWindow(screen), gc2,
2129d522f475Smrg		 x + x_coord, y + y_coord, width, width,
2130d522f475Smrg		 0,
2131d522f475Smrg		 360 * 64);
2132d522f475Smrg    } else if (ch == 0x1f) {	/* bullet */
2133d522f475Smrg	unsigned width = 7 * BOX_WIDE / 10;
2134d522f475Smrg	int x_coord = MID_WIDE - (width / 3);
2135d522f475Smrg	int y_coord = MID_HIGH - (width / 3);
2136d522f475Smrg
2137d522f475Smrg	SCALE_X(x_coord);
2138d522f475Smrg	SCALE_Y(y_coord);
2139d522f475Smrg	SCALE_X(width);
2140d522f475Smrg
2141d522f475Smrg	XDrawArc(screen->display,
2142d522f475Smrg		 VWindow(screen), gc2,
2143d522f475Smrg		 x + x_coord, y + y_coord, width, width,
2144d522f475Smrg		 0,
2145d522f475Smrg		 360 * 64);
2146d522f475Smrg    } else if (ch < (sizeof(lines) / sizeof(lines[0]))
2147d522f475Smrg	       && (p = lines[ch]) != 0) {
2148d522f475Smrg	int coord[4];
2149d522f475Smrg	int n = 0;
2150d522f475Smrg	while (*p >= 0) {
2151d522f475Smrg	    coord[n++] = *p++;
2152d522f475Smrg	    if (n == 4) {
2153d522f475Smrg		SCALE_X(coord[0]);
2154d522f475Smrg		SCALE_Y(coord[1]);
2155d522f475Smrg		SCALE_X(coord[2]);
2156d522f475Smrg		SCALE_Y(coord[3]);
2157d522f475Smrg		XDrawLine(screen->display,
2158d522f475Smrg			  VWindow(screen), gc2,
2159d522f475Smrg			  x + coord[0], y + coord[1],
2160d522f475Smrg			  x + coord[2], y + coord[3]);
2161d522f475Smrg		n = 0;
2162d522f475Smrg	    }
2163d522f475Smrg	}
2164d522f475Smrg    } else if (screen->force_all_chars) {
2165d522f475Smrg	/* bounding rectangle, for debugging */
2166d522f475Smrg	XDrawRectangle(screen->display, VWindow(screen), gc2, x, y,
2167d522f475Smrg		       font_width - 1,
2168d522f475Smrg		       font_height - 1);
2169d522f475Smrg    }
2170d522f475Smrg}
2171d522f475Smrg
2172d522f475Smrg#if OPT_RENDERFONT
2173d522f475Smrg
2174d522f475Smrg/*
2175d522f475Smrg * Check if the given character has a glyph known to Xft.
2176d522f475Smrg *
2177d522f475Smrg * see xc/lib/Xft/xftglyphs.c
2178d522f475Smrg */
2179d522f475SmrgBool
2180d522f475SmrgxtermXftMissing(XtermWidget xw, XftFont * font, unsigned wc)
2181d522f475Smrg{
2182d522f475Smrg    Bool result = False;
2183d522f475Smrg
2184d522f475Smrg    if (font != 0) {
2185d522f475Smrg	if (!XftGlyphExists(xw->screen.display, font, wc)) {
2186d522f475Smrg#if OPT_WIDE_CHARS
2187d522f475Smrg	    TRACE(("xtermXftMissing %d (dec=%#x, ucs=%#x)\n",
2188d522f475Smrg		   wc, ucs2dec(wc), dec2ucs(wc)));
2189d522f475Smrg#else
2190d522f475Smrg	    TRACE(("xtermXftMissing %d\n", wc));
2191d522f475Smrg#endif
2192d522f475Smrg	    result = True;
2193d522f475Smrg	}
2194d522f475Smrg    }
2195d522f475Smrg    return result;
2196d522f475Smrg}
2197d522f475Smrg#endif /* OPT_RENDERFONT && OPT_WIDE_CHARS */
2198d522f475Smrg
2199d522f475Smrg#endif /* OPT_BOX_CHARS */
2200d522f475Smrg
2201d522f475Smrg#if OPT_WIDE_CHARS
2202d522f475Smrg#define MY_UCS(ucs,dec) case ucs: result = dec; break
2203d522f475Smrgunsigned
2204d522f475Smrgucs2dec(unsigned ch)
2205d522f475Smrg{
2206d522f475Smrg    unsigned result = ch;
2207d522f475Smrg    if ((ch > 127)
2208d522f475Smrg	&& (ch != UCS_REPL)) {
2209d522f475Smrg	switch (ch) {
2210d522f475Smrg	    MY_UCS(0x25ae, 0);	/* black vertical rectangle                   */
2211d522f475Smrg	    MY_UCS(0x25c6, 1);	/* black diamond                              */
2212d522f475Smrg	    MY_UCS(0x2592, 2);	/* medium shade                               */
2213d522f475Smrg	    MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation           */
2214d522f475Smrg	    MY_UCS(0x240c, 4);	/* symbol for form feed                       */
2215d522f475Smrg	    MY_UCS(0x240d, 5);	/* symbol for carriage return                 */
2216d522f475Smrg	    MY_UCS(0x240a, 6);	/* symbol for line feed                       */
2217d522f475Smrg	    MY_UCS(0x00b0, 7);	/* degree sign                                */
2218d522f475Smrg	    MY_UCS(0x00b1, 8);	/* plus-minus sign                            */
2219d522f475Smrg	    MY_UCS(0x2424, 9);	/* symbol for newline                         */
2220d522f475Smrg	    MY_UCS(0x240b, 10);	/* symbol for vertical tabulation             */
2221d522f475Smrg	    MY_UCS(0x2518, 11);	/* box drawings light up and left             */
2222d522f475Smrg	    MY_UCS(0x2510, 12);	/* box drawings light down and left           */
2223d522f475Smrg	    MY_UCS(0x250c, 13);	/* box drawings light down and right          */
2224d522f475Smrg	    MY_UCS(0x2514, 14);	/* box drawings light up and right            */
2225d522f475Smrg	    MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
2226d522f475Smrg	    MY_UCS(0x23ba, 16);	/* box drawings scan 1                        */
2227d522f475Smrg	    MY_UCS(0x23bb, 17);	/* box drawings scan 3                        */
2228d522f475Smrg	    MY_UCS(0x2500, 18);	/* box drawings light horizontal              */
2229d522f475Smrg	    MY_UCS(0x23bc, 19);	/* box drawings scan 7                        */
2230d522f475Smrg	    MY_UCS(0x23bd, 20);	/* box drawings scan 9                        */
2231d522f475Smrg	    MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
2232d522f475Smrg	    MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
2233d522f475Smrg	    MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
2234d522f475Smrg	    MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
2235d522f475Smrg	    MY_UCS(0x2502, 25);	/* box drawings light vertical                */
2236d522f475Smrg	    MY_UCS(0x2264, 26);	/* less-than or equal to                      */
2237d522f475Smrg	    MY_UCS(0x2265, 27);	/* greater-than or equal to                   */
2238d522f475Smrg	    MY_UCS(0x03c0, 28);	/* greek small letter pi                      */
2239d522f475Smrg	    MY_UCS(0x2260, 29);	/* not equal to                               */
2240d522f475Smrg	    MY_UCS(0x00a3, 30);	/* pound sign                                 */
2241d522f475Smrg	    MY_UCS(0x00b7, 31);	/* middle dot                                 */
2242d522f475Smrg	}
2243d522f475Smrg    }
2244d522f475Smrg    return result;
2245d522f475Smrg}
2246d522f475Smrg
2247d522f475Smrg#undef  MY_UCS
2248d522f475Smrg#define MY_UCS(ucs,dec) case dec: result = ucs; break
2249d522f475Smrg
2250d522f475Smrgunsigned
2251d522f475Smrgdec2ucs(unsigned ch)
2252d522f475Smrg{
2253d522f475Smrg    unsigned result = ch;
2254d522f475Smrg    if (xtermIsDecGraphic(ch)) {
2255d522f475Smrg	switch (ch) {
2256d522f475Smrg	    MY_UCS(0x25ae, 0);	/* black vertical rectangle                   */
2257d522f475Smrg	    MY_UCS(0x25c6, 1);	/* black diamond                              */
2258d522f475Smrg	    MY_UCS(0x2592, 2);	/* medium shade                               */
2259d522f475Smrg	    MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation           */
2260d522f475Smrg	    MY_UCS(0x240c, 4);	/* symbol for form feed                       */
2261d522f475Smrg	    MY_UCS(0x240d, 5);	/* symbol for carriage return                 */
2262d522f475Smrg	    MY_UCS(0x240a, 6);	/* symbol for line feed                       */
2263d522f475Smrg	    MY_UCS(0x00b0, 7);	/* degree sign                                */
2264d522f475Smrg	    MY_UCS(0x00b1, 8);	/* plus-minus sign                            */
2265d522f475Smrg	    MY_UCS(0x2424, 9);	/* symbol for newline                         */
2266d522f475Smrg	    MY_UCS(0x240b, 10);	/* symbol for vertical tabulation             */
2267d522f475Smrg	    MY_UCS(0x2518, 11);	/* box drawings light up and left             */
2268d522f475Smrg	    MY_UCS(0x2510, 12);	/* box drawings light down and left           */
2269d522f475Smrg	    MY_UCS(0x250c, 13);	/* box drawings light down and right          */
2270d522f475Smrg	    MY_UCS(0x2514, 14);	/* box drawings light up and right            */
2271d522f475Smrg	    MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
2272d522f475Smrg	    MY_UCS(0x23ba, 16);	/* box drawings scan 1                        */
2273d522f475Smrg	    MY_UCS(0x23bb, 17);	/* box drawings scan 3                        */
2274d522f475Smrg	    MY_UCS(0x2500, 18);	/* box drawings light horizontal              */
2275d522f475Smrg	    MY_UCS(0x23bc, 19);	/* box drawings scan 7                        */
2276d522f475Smrg	    MY_UCS(0x23bd, 20);	/* box drawings scan 9                        */
2277d522f475Smrg	    MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
2278d522f475Smrg	    MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
2279d522f475Smrg	    MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
2280d522f475Smrg	    MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
2281d522f475Smrg	    MY_UCS(0x2502, 25);	/* box drawings light vertical                */
2282d522f475Smrg	    MY_UCS(0x2264, 26);	/* less-than or equal to                      */
2283d522f475Smrg	    MY_UCS(0x2265, 27);	/* greater-than or equal to                   */
2284d522f475Smrg	    MY_UCS(0x03c0, 28);	/* greek small letter pi                      */
2285d522f475Smrg	    MY_UCS(0x2260, 29);	/* not equal to                               */
2286d522f475Smrg	    MY_UCS(0x00a3, 30);	/* pound sign                                 */
2287d522f475Smrg	    MY_UCS(0x00b7, 31);	/* middle dot                                 */
2288d522f475Smrg	}
2289d522f475Smrg    }
2290d522f475Smrg    return result;
2291d522f475Smrg}
2292d522f475Smrg
2293d522f475Smrg#endif /* OPT_WIDE_CHARS */
2294d522f475Smrg
2295d522f475Smrg#if OPT_SHIFT_FONTS
2296d522f475Smrgstatic void
2297d522f475SmrglookupOneFontSize(XtermWidget xw, int fontnum)
2298d522f475Smrg{
2299d522f475Smrg    TScreen *screen = TScreenOf(xw);
2300d522f475Smrg
2301d522f475Smrg    if (screen->menu_font_sizes[fontnum] == 0) {
2302d522f475Smrg	XTermFonts fnt;
2303d522f475Smrg
2304d522f475Smrg	memset(&fnt, 0, sizeof(fnt));
2305d522f475Smrg	screen->menu_font_sizes[fontnum] = -1;
2306d522f475Smrg	if (xtermOpenFont(xw, screen->MenuFontName(fontnum), &fnt)) {
2307d522f475Smrg	    screen->menu_font_sizes[fontnum] = FontSize(fnt.fs);
2308d522f475Smrg	    TRACE(("menu_font_sizes[%d] = %ld\n", fontnum,
2309d522f475Smrg		   screen->menu_font_sizes[fontnum]));
2310d522f475Smrg	    xtermCloseFont(xw, &fnt);
2311d522f475Smrg	}
2312d522f475Smrg    }
2313d522f475Smrg}
2314d522f475Smrg
2315d522f475Smrg/*
2316d522f475Smrg * Cache the font-sizes so subsequent larger/smaller font actions will go fast.
2317d522f475Smrg */
2318d522f475Smrgstatic void
2319d522f475SmrglookupFontSizes(XtermWidget xw)
2320d522f475Smrg{
2321d522f475Smrg    int n;
2322d522f475Smrg
2323d522f475Smrg    for (n = 0; n < NMENUFONTS; n++) {
2324d522f475Smrg	lookupOneFontSize(xw, n);
2325d522f475Smrg    }
2326d522f475Smrg}
2327d522f475Smrg
2328d522f475Smrg/*
2329d522f475Smrg * Find the index of a larger/smaller font (according to the sign of 'relative'
2330d522f475Smrg * and its magnitude), starting from the 'old' index.
2331d522f475Smrg */
2332d522f475Smrgint
2333d522f475SmrglookupRelativeFontSize(XtermWidget xw, int old, int relative)
2334d522f475Smrg{
2335d522f475Smrg    TScreen *screen = TScreenOf(xw);
2336d522f475Smrg    int n, m = -1;
2337d522f475Smrg
2338d522f475Smrg    if (!IsIcon(screen)) {
2339d522f475Smrg	lookupFontSizes(xw);
2340d522f475Smrg	if (relative != 0) {
2341d522f475Smrg	    for (n = 0; n < NMENUFONTS; ++n) {
2342d522f475Smrg		if (screen->menu_font_sizes[n] > 0 &&
2343d522f475Smrg		    screen->menu_font_sizes[n] != screen->menu_font_sizes[old]) {
2344d522f475Smrg		    int cmp_0 = ((screen->menu_font_sizes[n] >
2345d522f475Smrg				  screen->menu_font_sizes[old])
2346d522f475Smrg				 ? relative
2347d522f475Smrg				 : -relative);
2348d522f475Smrg		    int cmp_m = ((m < 0)
2349d522f475Smrg				 ? 1
2350d522f475Smrg				 : ((screen->menu_font_sizes[n] <
2351d522f475Smrg				     screen->menu_font_sizes[m])
2352d522f475Smrg				    ? relative
2353d522f475Smrg				    : -relative));
2354d522f475Smrg		    if (cmp_0 > 0 && cmp_m > 0) {
2355d522f475Smrg			m = n;
2356d522f475Smrg		    }
2357d522f475Smrg		}
2358d522f475Smrg	    }
2359d522f475Smrg	    if (m >= 0) {
2360d522f475Smrg		if (relative > 1)
2361d522f475Smrg		    m = lookupRelativeFontSize(xw, m, relative - 1);
2362d522f475Smrg		else if (relative < -1)
2363d522f475Smrg		    m = lookupRelativeFontSize(xw, m, relative + 1);
2364d522f475Smrg	    }
2365d522f475Smrg	}
2366d522f475Smrg    }
2367d522f475Smrg    return m;
2368d522f475Smrg}
2369d522f475Smrg
2370d522f475Smrg/* ARGSUSED */
2371d522f475Smrgvoid
2372d522f475SmrgHandleLargerFont(Widget w GCC_UNUSED,
2373d522f475Smrg		 XEvent * event GCC_UNUSED,
2374d522f475Smrg		 String * params GCC_UNUSED,
2375d522f475Smrg		 Cardinal *param_count GCC_UNUSED)
2376d522f475Smrg{
2377d522f475Smrg    if (IsXtermWidget(w)) {
2378d522f475Smrg	XtermWidget xw = (XtermWidget) w;
2379d522f475Smrg
2380d522f475Smrg	if (xw->misc.shift_fonts) {
2381d522f475Smrg	    TScreen *screen = &xw->screen;
2382d522f475Smrg	    int m;
2383d522f475Smrg
2384d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, 1);
2385d522f475Smrg	    if (m >= 0) {
2386d522f475Smrg		SetVTFont(xw, m, True, NULL);
2387d522f475Smrg	    } else {
2388d522f475Smrg		Bell(XkbBI_MinorError, 0);
2389d522f475Smrg	    }
2390d522f475Smrg	}
2391d522f475Smrg    }
2392d522f475Smrg}
2393d522f475Smrg
2394d522f475Smrg/* ARGSUSED */
2395d522f475Smrgvoid
2396d522f475SmrgHandleSmallerFont(Widget w GCC_UNUSED,
2397d522f475Smrg		  XEvent * event GCC_UNUSED,
2398d522f475Smrg		  String * params GCC_UNUSED,
2399d522f475Smrg		  Cardinal *param_count GCC_UNUSED)
2400d522f475Smrg{
2401d522f475Smrg    if (IsXtermWidget(w)) {
2402d522f475Smrg	XtermWidget xw = (XtermWidget) w;
2403d522f475Smrg
2404d522f475Smrg	if (xw->misc.shift_fonts) {
2405d522f475Smrg	    TScreen *screen = &xw->screen;
2406d522f475Smrg	    int m;
2407d522f475Smrg
2408d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, -1);
2409d522f475Smrg	    if (m >= 0) {
2410d522f475Smrg		SetVTFont(xw, m, True, NULL);
2411d522f475Smrg	    } else {
2412d522f475Smrg		Bell(XkbBI_MinorError, 0);
2413d522f475Smrg	    }
2414d522f475Smrg	}
2415d522f475Smrg    }
2416d522f475Smrg}
2417d522f475Smrg#endif
2418d522f475Smrg
2419d522f475Smrgint
2420d522f475SmrgxtermGetFont(const char *param)
2421d522f475Smrg{
2422d522f475Smrg    int fontnum;
2423d522f475Smrg
2424d522f475Smrg    switch (param[0]) {
2425d522f475Smrg    case 'd':
2426d522f475Smrg    case 'D':
2427d522f475Smrg    case '0':
2428d522f475Smrg	fontnum = fontMenu_default;
2429d522f475Smrg	break;
2430d522f475Smrg    case '1':
2431d522f475Smrg	fontnum = fontMenu_font1;
2432d522f475Smrg	break;
2433d522f475Smrg    case '2':
2434d522f475Smrg	fontnum = fontMenu_font2;
2435d522f475Smrg	break;
2436d522f475Smrg    case '3':
2437d522f475Smrg	fontnum = fontMenu_font3;
2438d522f475Smrg	break;
2439d522f475Smrg    case '4':
2440d522f475Smrg	fontnum = fontMenu_font4;
2441d522f475Smrg	break;
2442d522f475Smrg    case '5':
2443d522f475Smrg	fontnum = fontMenu_font5;
2444d522f475Smrg	break;
2445d522f475Smrg    case '6':
2446d522f475Smrg	fontnum = fontMenu_font6;
2447d522f475Smrg	break;
2448d522f475Smrg    case 'e':
2449d522f475Smrg    case 'E':
2450d522f475Smrg	fontnum = fontMenu_fontescape;
2451d522f475Smrg	break;
2452d522f475Smrg    case 's':
2453d522f475Smrg    case 'S':
2454d522f475Smrg	fontnum = fontMenu_fontsel;
2455d522f475Smrg	break;
2456d522f475Smrg    default:
2457d522f475Smrg	fontnum = -1;
2458d522f475Smrg	break;
2459d522f475Smrg    }
2460d522f475Smrg    return fontnum;
2461d522f475Smrg}
2462d522f475Smrg
2463d522f475Smrg/* ARGSUSED */
2464d522f475Smrgvoid
2465d522f475SmrgHandleSetFont(Widget w GCC_UNUSED,
2466d522f475Smrg	      XEvent * event GCC_UNUSED,
2467d522f475Smrg	      String * params,
2468d522f475Smrg	      Cardinal *param_count)
2469d522f475Smrg{
2470d522f475Smrg    if (IsXtermWidget(w)) {
2471d522f475Smrg	int fontnum;
2472d522f475Smrg	VTFontNames fonts;
2473d522f475Smrg
2474d522f475Smrg	memset(&fonts, 0, sizeof(fonts));
2475d522f475Smrg
2476d522f475Smrg	if (*param_count == 0) {
2477d522f475Smrg	    fontnum = fontMenu_default;
2478d522f475Smrg	} else {
2479d522f475Smrg	    Cardinal maxparams = 1;	/* total number of params allowed */
2480d522f475Smrg	    int result = xtermGetFont(params[0]);
2481d522f475Smrg
2482d522f475Smrg	    switch (result) {
2483d522f475Smrg	    case fontMenu_default:	/* FALLTHRU */
2484d522f475Smrg	    case fontMenu_font1:	/* FALLTHRU */
2485d522f475Smrg	    case fontMenu_font2:	/* FALLTHRU */
2486d522f475Smrg	    case fontMenu_font3:	/* FALLTHRU */
2487d522f475Smrg	    case fontMenu_font4:	/* FALLTHRU */
2488d522f475Smrg	    case fontMenu_font5:	/* FALLTHRU */
2489d522f475Smrg	    case fontMenu_font6:	/* FALLTHRU */
2490d522f475Smrg		break;
2491d522f475Smrg	    case fontMenu_fontescape:
2492d522f475Smrg#if OPT_WIDE_CHARS
2493d522f475Smrg		maxparams = 5;
2494d522f475Smrg#else
2495d522f475Smrg		maxparams = 3;
2496d522f475Smrg#endif
2497d522f475Smrg		break;
2498d522f475Smrg	    case fontMenu_fontsel:
2499d522f475Smrg		maxparams = 2;
2500d522f475Smrg		break;
2501d522f475Smrg	    default:
2502d522f475Smrg		Bell(XkbBI_MinorError, 0);
2503d522f475Smrg		return;
2504d522f475Smrg	    }
2505d522f475Smrg	    fontnum = result;
2506d522f475Smrg
2507d522f475Smrg	    if (*param_count > maxparams) {	/* see if extra args given */
2508d522f475Smrg		Bell(XkbBI_MinorError, 0);
2509d522f475Smrg		return;
2510d522f475Smrg	    }
2511d522f475Smrg	    switch (*param_count) {	/* assign 'em */
2512d522f475Smrg#if OPT_WIDE_CHARS
2513d522f475Smrg	    case 5:
2514d522f475Smrg		fonts.f_wb = params[4];
2515d522f475Smrg		/* FALLTHRU */
2516d522f475Smrg	    case 4:
2517d522f475Smrg		fonts.f_w = params[3];
2518d522f475Smrg		/* FALLTHRU */
2519d522f475Smrg#endif
2520d522f475Smrg	    case 3:
2521d522f475Smrg		fonts.f_b = params[2];
2522d522f475Smrg		/* FALLTHRU */
2523d522f475Smrg	    case 2:
2524d522f475Smrg		fonts.f_n = params[1];
2525d522f475Smrg		break;
2526d522f475Smrg	    }
2527d522f475Smrg	}
2528d522f475Smrg
2529d522f475Smrg	SetVTFont((XtermWidget) w, fontnum, True, &fonts);
2530d522f475Smrg    }
2531d522f475Smrg}
2532d522f475Smrg
2533d522f475Smrgvoid
2534d522f475SmrgSetVTFont(XtermWidget xw,
2535d522f475Smrg	  int which,
2536d522f475Smrg	  Bool doresize,
2537d522f475Smrg	  const VTFontNames * fonts)
2538d522f475Smrg{
2539d522f475Smrg    TScreen *screen = &xw->screen;
2540d522f475Smrg
2541d522f475Smrg    TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which,
2542d522f475Smrg	   (fonts && fonts->f_n) ? fonts->f_n : "<null>",
2543d522f475Smrg	   (fonts && fonts->f_b) ? fonts->f_b : "<null>"));
2544d522f475Smrg
2545d522f475Smrg    if (IsIcon(screen)) {
2546d522f475Smrg	Bell(XkbBI_MinorError, 0);
2547d522f475Smrg    } else if (which >= 0 && which < NMENUFONTS) {
2548d522f475Smrg	VTFontNames myfonts;
2549d522f475Smrg
2550d522f475Smrg	memset(&myfonts, 0, sizeof(myfonts));
2551d522f475Smrg	if (fonts != 0)
2552d522f475Smrg	    myfonts = *fonts;
2553d522f475Smrg
2554d522f475Smrg	if (which == fontMenu_fontsel) {	/* go get the selection */
2555d522f475Smrg	    FindFontSelection(xw, myfonts.f_n, False);
2556d522f475Smrg	    return;
2557d522f475Smrg	} else {
2558d522f475Smrg	    int oldFont = screen->menu_font_number;
2559d522f475Smrg
2560d522f475Smrg#define USE_CACHED(field, name) \
2561d522f475Smrg	    if (myfonts.field == 0) { \
2562d522f475Smrg		myfonts.field = screen->menu_font_names[which][name]; \
2563d522f475Smrg		TRACE(("set myfonts." #field " from menu_font_names[%d][" #name "] %s\n", \
2564d522f475Smrg		       which, NonNull(myfonts.field))); \
2565d522f475Smrg	    } else { \
2566d522f475Smrg		TRACE(("set myfonts." #field " reused\n")); \
2567d522f475Smrg	    }
2568d522f475Smrg	    USE_CACHED(f_n, fNorm);
2569d522f475Smrg	    USE_CACHED(f_b, fBold);
2570d522f475Smrg#if OPT_WIDE_CHARS
2571d522f475Smrg	    USE_CACHED(f_w, fWide);
2572d522f475Smrg	    USE_CACHED(f_wb, fWBold);
2573d522f475Smrg#endif
2574d522f475Smrg	    if (xtermLoadFont(xw,
2575d522f475Smrg			      &myfonts,
2576d522f475Smrg			      doresize, which)) {
2577d522f475Smrg		return;
2578d522f475Smrg	    } else {
2579d522f475Smrg		xtermLoadFont(xw,
2580d522f475Smrg			      xtermFontName(screen->MenuFontName(oldFont)),
2581d522f475Smrg			      doresize, oldFont);
2582d522f475Smrg	    }
2583d522f475Smrg	}
2584d522f475Smrg    }
2585d522f475Smrg
2586d522f475Smrg    Bell(XkbBI_MinorError, 0);
2587d522f475Smrg    return;
2588d522f475Smrg}
2589