fontutils.c revision 2eaa94a1
12eaa94a1Schristos/* $XTermId: fontutils.c,v 1.278 2008/12/30 17:32:06 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
1222eaa94a1Schristosstatic unsigned
123d522f475SmrgcountGlyphs(XFontStruct * fp)
124d522f475Smrg{
125d522f475Smrg    unsigned count = 0;
126d522f475Smrg
127d522f475Smrg    if (fp != 0) {
128d522f475Smrg	if (fp->min_byte1 == 0 && fp->max_byte1 == 0) {
129d522f475Smrg	    count = fp->max_char_or_byte2 - fp->min_char_or_byte2;
130d522f475Smrg	} else if (fp->min_char_or_byte2 < 256
131d522f475Smrg		   && fp->max_char_or_byte2 < 256) {
132d522f475Smrg	    unsigned first = (fp->min_byte1 << 8) + fp->min_char_or_byte2;
133d522f475Smrg	    unsigned last = (fp->max_byte1 << 8) + fp->max_char_or_byte2;
134d522f475Smrg	    count = last + 1 - first;
135d522f475Smrg	}
136d522f475Smrg    }
137d522f475Smrg    return count;
138d522f475Smrg}
139d522f475Smrg
140d522f475Smrg/*
141d522f475Smrg * Verify that the wide-bold font is at least a bold font with roughly as many
142d522f475Smrg * glyphs as the wide font.  The counts should be the same, but settle for
143d522f475Smrg * filtering out the worst of the font mismatches.
144d522f475Smrg */
145d522f475Smrgstatic Bool
146d522f475SmrgcompatibleWideCounts(XFontStruct * wfs, XFontStruct * wbfs)
147d522f475Smrg{
148d522f475Smrg    unsigned count_w = countGlyphs(wfs);
149d522f475Smrg    unsigned count_wb = countGlyphs(wbfs);
150d522f475Smrg    if (count_w <= 256 ||
151d522f475Smrg	count_wb <= 256 ||
152d522f475Smrg	((count_w / 4) * 3) > count_wb) {
153d522f475Smrg	TRACE(("...font server lied (count wide %u vs wide-bold %u)\n",
154d522f475Smrg	       count_w, count_wb));
155d522f475Smrg	return False;
156d522f475Smrg    }
157d522f475Smrg    return True;
158d522f475Smrg}
159d522f475Smrg#endif /* OPT_WIDE_CHARS */
160d522f475Smrg
161d522f475Smrg/*
162d522f475Smrg * Returns the fields from start to stop in a dash- separated string.  This
163d522f475Smrg * function will modify the source, putting '\0's in the appropiate place and
164d522f475Smrg * moving the beginning forward to after the '\0'
165d522f475Smrg *
166d522f475Smrg * This will NOT work for the last field (but we won't need it).
167d522f475Smrg */
168d522f475Smrgstatic char *
169d522f475Smrgn_fields(char **source, int start, int stop)
170d522f475Smrg{
171d522f475Smrg    int i;
172d522f475Smrg    char *str, *str1;
173d522f475Smrg
174d522f475Smrg    /*
175d522f475Smrg     * find the start-1th dash
176d522f475Smrg     */
177d522f475Smrg    for (i = start - 1, str = *source; i; i--, str++)
178d522f475Smrg	if ((str = strchr(str, '-')) == 0)
179d522f475Smrg	    return 0;
180d522f475Smrg
181d522f475Smrg    /*
182d522f475Smrg     * find the stopth dash
183d522f475Smrg     */
184d522f475Smrg    for (i = stop - start + 1, str1 = str; i; i--, str1++)
185d522f475Smrg	if ((str1 = strchr(str1, '-')) == 0)
186d522f475Smrg	    return 0;
187d522f475Smrg
188d522f475Smrg    /*
189d522f475Smrg     * put a \0 at the end of the fields
190d522f475Smrg     */
191d522f475Smrg    *(str1 - 1) = '\0';
192d522f475Smrg
193d522f475Smrg    /*
194d522f475Smrg     * move source forward
195d522f475Smrg     */
196d522f475Smrg    *source = str1;
197d522f475Smrg
198d522f475Smrg    return str;
199d522f475Smrg}
200d522f475Smrg
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 {
5082eaa94a1Schristos	    int p = x_toupper(*pattern++);
5092eaa94a1Schristos	    int m = x_toupper(*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);
13042eaa94a1Schristos	if (*param_count == 1)
13052eaa94a1Schristos	    myClass[0] = x_toupper(myClass[0]);
1306d522f475Smrg
1307d522f475Smrg	if (xtermLoadVTFonts(xw, myName, myClass)) {
1308d522f475Smrg	    /*
1309d522f475Smrg	     * When switching fonts, try to preserve the font-menu selection, since
1310d522f475Smrg	     * it is less surprising to do that (if the font-switching can be
1311d522f475Smrg	     * undone) than to switch to "Default".
1312d522f475Smrg	     */
1313d522f475Smrg	    int font_number = xw->screen.menu_font_number;
1314d522f475Smrg	    if (font_number > fontMenu_lastBuiltin)
1315d522f475Smrg		font_number = fontMenu_lastBuiltin;
1316d522f475Smrg	    for (n = 0; n < NMENUFONTS; ++n)
1317d522f475Smrg		xw->screen.menu_font_sizes[n] = 0;
1318d522f475Smrg	    SetVTFont(xw, font_number, True,
1319d522f475Smrg		      ((font_number == fontMenu_default)
1320d522f475Smrg		       ? &(xw->misc.default_font)
1321d522f475Smrg		       : NULL));
1322d522f475Smrg	}
1323d522f475Smrg
1324d522f475Smrg	MyStackFree(myClass, buf);
1325d522f475Smrg    }
1326d522f475Smrg}
1327d522f475Smrg#endif /* OPT_LOAD_VTFONTS */
1328d522f475Smrg
1329d522f475Smrg/*
1330d522f475Smrg * Set the limits for the box that outlines the cursor.
1331d522f475Smrg */
1332d522f475Smrgvoid
1333d522f475SmrgxtermSetCursorBox(TScreen * screen)
1334d522f475Smrg{
1335d522f475Smrg    static XPoint VTbox[NBOX];
1336d522f475Smrg    XPoint *vp;
13372eaa94a1Schristos    int fw = FontWidth(screen) - 1;
13382eaa94a1Schristos    int fh = FontHeight(screen) - 1;
13392eaa94a1Schristos    int hh = screen->cursor_underline ? 1 : fh;
1340d522f475Smrg
1341d522f475Smrg    vp = &VTbox[1];
13422eaa94a1Schristos    (vp++)->x = (short) fw;
13432eaa94a1Schristos    (vp++)->y = (short) hh;
13442eaa94a1Schristos    (vp++)->x = (short) -fw;
13452eaa94a1Schristos    vp->y = (short) -hh;
13462eaa94a1Schristos
1347d522f475Smrg    screen->box = VTbox;
1348d522f475Smrg}
1349d522f475Smrg
1350d522f475Smrg#define CACHE_XFT(dst,src) if (src != 0) {\
1351d522f475Smrg	    dst[fontnum] = src;\
1352d522f475Smrg	    TRACE(("%s[%d] = %d (%d,%d) by %d\n",\
1353d522f475Smrg		#dst,\
1354d522f475Smrg	    	fontnum,\
1355d522f475Smrg		src->height,\
1356d522f475Smrg		src->ascent,\
1357d522f475Smrg		src->descent,\
1358d522f475Smrg		src->max_advance_width));\
1359d522f475Smrg	}
1360d522f475Smrg
1361d522f475Smrg#if OPT_RENDERFONT
1362d522f475Smrgstatic XftFont *
1363d522f475SmrgxtermOpenXft(Display * dpy, XftPattern * pat, const char *tag GCC_UNUSED)
1364d522f475Smrg{
1365d522f475Smrg    XftPattern *match;
1366d522f475Smrg    XftResult status;
1367d522f475Smrg    XftFont *result = 0;
1368d522f475Smrg
1369d522f475Smrg    if (pat != 0) {
1370d522f475Smrg	match = XftFontMatch(dpy, DefaultScreen(dpy), pat, &status);
1371d522f475Smrg	if (match != 0) {
1372d522f475Smrg	    result = XftFontOpenPattern(dpy, match);
1373d522f475Smrg	    if (result != 0) {
1374d522f475Smrg		TRACE(("...matched %s font\n", tag));
1375d522f475Smrg	    } else {
1376d522f475Smrg		TRACE(("...could did not open %s font\n", tag));
1377d522f475Smrg		XftPatternDestroy(match);
1378d522f475Smrg	    }
1379d522f475Smrg	} else {
1380d522f475Smrg	    TRACE(("...did not match %s font\n", tag));
1381d522f475Smrg	}
1382d522f475Smrg    }
1383d522f475Smrg    return result;
1384d522f475Smrg}
1385d522f475Smrg#endif
1386d522f475Smrg
1387d522f475Smrg#if OPT_RENDERFONT
1388d522f475Smrg#if OPT_SHIFT_FONTS
1389d522f475Smrg/*
1390d522f475Smrg * Don't make a dependency on the math library for a single function.
1391d522f475Smrg * (Newton Raphson).
1392d522f475Smrg */
1393d522f475Smrgstatic double
1394d522f475SmrgmySquareRoot(double value)
1395d522f475Smrg{
1396d522f475Smrg    double result = 0.0;
1397d522f475Smrg    if (value > 0.0) {
1398d522f475Smrg	int n;
1399d522f475Smrg	double older = value;
1400d522f475Smrg	for (n = 0; n < 10; ++n) {
1401d522f475Smrg	    double delta = (older * older - value) / (2.0 * older);
1402d522f475Smrg	    double newer = older - delta;
1403d522f475Smrg	    older = newer;
1404d522f475Smrg	    result = newer;
1405d522f475Smrg	    if (delta > -0.001 && delta < 0.001)
1406d522f475Smrg		break;
1407d522f475Smrg	}
1408d522f475Smrg    }
1409d522f475Smrg    return result;
1410d522f475Smrg}
1411d522f475Smrg#endif
1412d522f475Smrg
1413d522f475Smrg/*
1414d522f475Smrg * Given the Xft font metrics, determine the actual font size.  This is used
1415d522f475Smrg * for each font to ensure that normal, bold and italic fonts follow the same
1416d522f475Smrg * rule.
1417d522f475Smrg */
1418d522f475Smrgstatic void
1419d522f475SmrgsetRenderFontsize(TScreen * screen, VTwin * win, XftFont * font, const char *tag)
1420d522f475Smrg{
1421d522f475Smrg    if (font != 0) {
1422d522f475Smrg	int width, height, ascent, descent;
1423d522f475Smrg
1424d522f475Smrg	(void) screen;
1425d522f475Smrg
1426d522f475Smrg	width = font->max_advance_width;
1427d522f475Smrg	height = font->height;
1428d522f475Smrg	ascent = font->ascent;
1429d522f475Smrg	descent = font->descent;
1430d522f475Smrg	if (height < ascent + descent) {
1431d522f475Smrg	    TRACE(("...increase height from %d\n", height));
1432d522f475Smrg	    height = ascent + descent;
1433d522f475Smrg	}
1434d522f475Smrg	if (is_double_width_font_xft(screen->display, font)) {
1435d522f475Smrg	    TRACE(("...reduced width from %d\n", width));
1436d522f475Smrg	    width >>= 1;
1437d522f475Smrg	}
1438d522f475Smrg	if (tag == 0) {
1439d522f475Smrg	    win->f_width = width;
1440d522f475Smrg	    win->f_height = height;
1441d522f475Smrg	    win->f_ascent = ascent;
1442d522f475Smrg	    win->f_descent = descent;
1443d522f475Smrg	    TRACE(("setRenderFontsize result %dx%d (%d+%d)\n",
1444d522f475Smrg		   width, height, ascent, descent));
1445d522f475Smrg	} else if (win->f_width < width ||
1446d522f475Smrg		   win->f_height < height ||
1447d522f475Smrg		   win->f_ascent < ascent ||
1448d522f475Smrg		   win->f_descent < descent) {
1449d522f475Smrg	    TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n",
1450d522f475Smrg		   tag,
1451d522f475Smrg		   win->f_width, win->f_height, win->f_ascent, win->f_descent,
1452d522f475Smrg		   width, height, ascent, descent));
1453d522f475Smrg
1454d522f475Smrg	    win->f_width = width;
1455d522f475Smrg	    win->f_height = height;
1456d522f475Smrg	    win->f_ascent = ascent;
1457d522f475Smrg	    win->f_descent = descent;
1458d522f475Smrg	} else {
1459d522f475Smrg	    TRACE(("setRenderFontsize %s unchanged\n", tag));
1460d522f475Smrg	}
1461d522f475Smrg    }
1462d522f475Smrg}
1463d522f475Smrg#endif
1464d522f475Smrg
1465d522f475Smrg/*
1466d522f475Smrg * Compute useful values for the font/window sizes
1467d522f475Smrg */
1468d522f475Smrgvoid
1469d522f475SmrgxtermComputeFontInfo(XtermWidget xw,
1470d522f475Smrg		     VTwin * win,
1471d522f475Smrg		     XFontStruct * font,
1472d522f475Smrg		     int sbwidth)
1473d522f475Smrg{
1474d522f475Smrg    TScreen *screen = &(xw->screen);
1475d522f475Smrg
1476d522f475Smrg    int i, j, width, height;
1477d522f475Smrg
1478d522f475Smrg#if OPT_RENDERFONT
1479d522f475Smrg    /*
1480d522f475Smrg     * xterm contains a lot of references to fonts, assuming they are fixed
1481d522f475Smrg     * size.  This chunk of code overrides the actual font-selection (see
1482d522f475Smrg     * drawXtermText()), if the user has selected render-font.  All of the
1483d522f475Smrg     * font-loading for fixed-fonts still goes on whether or not this chunk
1484d522f475Smrg     * overrides it.
1485d522f475Smrg     */
1486d522f475Smrg    if (xw->misc.render_font && !IsIconWin(screen, win)) {
1487d522f475Smrg	Display *dpy = screen->display;
1488d522f475Smrg	int fontnum = screen->menu_font_number;
1489d522f475Smrg	XftFont *norm = screen->renderFontNorm[fontnum];
1490d522f475Smrg	XftFont *bold = screen->renderFontBold[fontnum];
1491d522f475Smrg	XftFont *ital = screen->renderFontItal[fontnum];
1492d522f475Smrg#if OPT_RENDERWIDE
1493d522f475Smrg	XftFont *wnorm = screen->renderWideNorm[fontnum];
1494d522f475Smrg	XftFont *wbold = screen->renderWideBold[fontnum];
1495d522f475Smrg	XftFont *wital = screen->renderWideItal[fontnum];
1496d522f475Smrg#endif
1497d522f475Smrg
1498d522f475Smrg	if (norm == 0 && xw->misc.face_name) {
1499d522f475Smrg	    XftPattern *pat;
1500d522f475Smrg	    double face_size = xw->misc.face_size[fontnum];
1501d522f475Smrg
1502d522f475Smrg	    TRACE(("xtermComputeFontInfo norm(face %s, size %f)\n",
1503d522f475Smrg		   xw->misc.face_name,
1504d522f475Smrg		   xw->misc.face_size[fontnum]));
1505d522f475Smrg
1506d522f475Smrg	    if (face_size <= 0.0) {
1507d522f475Smrg#if OPT_SHIFT_FONTS
1508d522f475Smrg		/*
1509d522f475Smrg		 * If the user is switching font-sizes, make it follow by
1510d522f475Smrg		 * default the same ratios to the default as the fixed fonts
1511d522f475Smrg		 * would, for easy comparison.  There will be some differences
1512d522f475Smrg		 * since the fixed fonts have a variety of height/width ratios,
1513d522f475Smrg		 * but this is simpler than adding another resource value - and
1514d522f475Smrg		 * as noted above, the data for the fixed fonts are available.
1515d522f475Smrg		 */
1516d522f475Smrg		lookupOneFontSize(xw, 0);
1517d522f475Smrg		lookupOneFontSize(xw, fontnum);
1518d522f475Smrg		if (fontnum == fontMenu_default) {
1519d522f475Smrg		    face_size = 14.0;
1520d522f475Smrg		} else {
1521d522f475Smrg		    double ratio;
1522d522f475Smrg		    int num = screen->menu_font_sizes[fontnum];
1523d522f475Smrg		    int den = screen->menu_font_sizes[0];
1524d522f475Smrg
1525d522f475Smrg		    if (den <= 0)
1526d522f475Smrg			den = 1;
1527d522f475Smrg		    ratio = mySquareRoot((1.0 * num) / den);
1528d522f475Smrg
1529d522f475Smrg		    face_size = (ratio * xw->misc.face_size[0]);
1530d522f475Smrg		    TRACE(("scaled using %3d/%d = %.2f -> %f\n",
1531d522f475Smrg			   num, den, ratio, face_size));
1532d522f475Smrg		}
1533d522f475Smrg#else
1534d522f475Smrg		switch (fontnum) {
1535d522f475Smrg		case fontMenu_font1:
1536d522f475Smrg		    face_size = 8.0;
1537d522f475Smrg		    break;
1538d522f475Smrg		case fontMenu_font2:
1539d522f475Smrg		    face_size = 10.0;
1540d522f475Smrg		    break;
1541d522f475Smrg		case fontMenu_font3:
1542d522f475Smrg		    face_size = 12.0;
1543d522f475Smrg		    break;
1544d522f475Smrg		default:
1545d522f475Smrg		    face_size = 14.0;
1546d522f475Smrg		    break;
1547d522f475Smrg		case fontMenu_font4:
1548d522f475Smrg		    face_size = 16.0;
1549d522f475Smrg		    break;
1550d522f475Smrg		case fontMenu_font5:
1551d522f475Smrg		    face_size = 18.0;
1552d522f475Smrg		    break;
1553d522f475Smrg		case fontMenu_font6:
1554d522f475Smrg		    face_size = 20.0;
1555d522f475Smrg		    break;
1556d522f475Smrg		}
1557d522f475Smrg#endif
1558d522f475Smrg		xw->misc.face_size[fontnum] = face_size;
1559d522f475Smrg	    }
1560d522f475Smrg
1561d522f475Smrg	    /*
1562d522f475Smrg	     * By observation (there is no documentation), XftPatternBuild is
1563d522f475Smrg	     * cumulative.  Build the bold- and italic-patterns on top of the
1564d522f475Smrg	     * normal pattern.
1565d522f475Smrg	     */
1566d522f475Smrg#define NormXftPattern \
1567d522f475Smrg	    XFT_FAMILY, XftTypeString, "mono", \
1568d522f475Smrg	    XFT_SIZE, XftTypeDouble, face_size, \
1569d522f475Smrg	    XFT_SPACING, XftTypeInteger, XFT_MONO
1570d522f475Smrg
1571d522f475Smrg#define BoldXftPattern(norm) \
1572d522f475Smrg	    XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \
1573d522f475Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width
1574d522f475Smrg
1575d522f475Smrg#define ItalXftPattern(norm) \
1576d522f475Smrg	    XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \
1577d522f475Smrg	    XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width
1578d522f475Smrg
1579d522f475Smrg	    if ((pat = XftNameParse(xw->misc.face_name)) != 0) {
1580d522f475Smrg		XftPatternBuild(pat,
1581d522f475Smrg				NormXftPattern,
1582d522f475Smrg				(void *) 0);
1583d522f475Smrg		norm = xtermOpenXft(dpy, pat, "normal");
1584d522f475Smrg
1585d522f475Smrg		if (norm != 0) {
1586d522f475Smrg		    XftPatternBuild(pat,
1587d522f475Smrg				    BoldXftPattern(norm),
1588d522f475Smrg				    (void *) 0);
1589d522f475Smrg		    bold = xtermOpenXft(dpy, pat, "bold");
1590d522f475Smrg
1591d522f475Smrg#if OPT_ISO_COLORS
1592d522f475Smrg		    if (screen->italicULMode
1593d522f475Smrg			&& (pat = XftNameParse(xw->misc.face_name)) != 0) {
1594d522f475Smrg			XftPatternBuild(pat,
1595d522f475Smrg					NormXftPattern,
1596d522f475Smrg					ItalXftPattern(norm),
1597d522f475Smrg					(void *) 0);
1598d522f475Smrg			ital = xtermOpenXft(dpy, pat, "italic");
1599d522f475Smrg		    }
1600d522f475Smrg#endif /* OPT_ISO_COLORS */
1601d522f475Smrg
1602d522f475Smrg		    /*
1603d522f475Smrg		     * FIXME:  just assume that the corresponding font has no
1604d522f475Smrg		     * graphics characters.
1605d522f475Smrg		     */
1606d522f475Smrg		    if (screen->fnt_boxes) {
1607d522f475Smrg			screen->fnt_boxes = False;
1608d522f475Smrg			TRACE(("Xft opened - will %suse internal line-drawing characters\n",
1609d522f475Smrg			       screen->fnt_boxes ? "not " : ""));
1610d522f475Smrg		    }
1611d522f475Smrg		}
1612d522f475Smrg
1613d522f475Smrg		XftPatternDestroy(pat);
1614d522f475Smrg	    }
1615d522f475Smrg
1616d522f475Smrg	    CACHE_XFT(screen->renderFontNorm, norm);
1617d522f475Smrg	    CACHE_XFT(screen->renderFontBold, bold);
1618d522f475Smrg	    CACHE_XFT(screen->renderFontItal, ital);
1619d522f475Smrg
1620d522f475Smrg	    /*
1621d522f475Smrg	     * See xtermXftDrawString().
1622d522f475Smrg	     */
1623d522f475Smrg#if OPT_RENDERWIDE
1624d522f475Smrg	    if (norm != 0 && screen->wide_chars) {
1625d522f475Smrg		char *face_name = (xw->misc.face_wide_name
1626d522f475Smrg				   ? xw->misc.face_wide_name
1627d522f475Smrg				   : xw->misc.face_name);
1628d522f475Smrg		int char_width = norm->max_advance_width * 2;
1629d522f475Smrg
1630d522f475Smrg		TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n",
1631d522f475Smrg		       face_name,
1632d522f475Smrg		       char_width));
1633d522f475Smrg
1634d522f475Smrg#define WideXftPattern \
1635d522f475Smrg		XFT_FAMILY, XftTypeString, "mono", \
1636d522f475Smrg		XFT_SIZE, XftTypeDouble, face_size, \
1637d522f475Smrg		XFT_SPACING, XftTypeInteger, XFT_MONO
1638d522f475Smrg
1639d522f475Smrg		if ((pat = XftNameParse(face_name)) != 0) {
1640d522f475Smrg		    XftPatternBuild(pat,
1641d522f475Smrg				    WideXftPattern,
1642d522f475Smrg				    XFT_CHAR_WIDTH, XftTypeInteger, char_width,
1643d522f475Smrg				    (void *) 0);
1644d522f475Smrg		    wnorm = xtermOpenXft(dpy, pat, "wide");
1645d522f475Smrg
1646d522f475Smrg		    if (wnorm != 0) {
1647d522f475Smrg			XftPatternBuild(pat,
1648d522f475Smrg					WideXftPattern,
1649d522f475Smrg					BoldXftPattern(wnorm),
1650d522f475Smrg					(void *) 0);
1651d522f475Smrg			wbold = xtermOpenXft(dpy, pat, "wide-bold");
1652d522f475Smrg
1653d522f475Smrg#if OPT_ISO_COLORS
1654d522f475Smrg			if (screen->italicULMode
1655d522f475Smrg			    && (pat = XftNameParse(face_name)) != 0) {
1656d522f475Smrg			    XftPatternBuild(pat,
1657d522f475Smrg					    WideXftPattern,
1658d522f475Smrg					    ItalXftPattern(wnorm),
1659d522f475Smrg					    (void *) 0);
1660d522f475Smrg			    wital = xtermOpenXft(dpy, pat, "wide-italic");
1661d522f475Smrg			}
1662d522f475Smrg#endif
1663d522f475Smrg		    }
1664d522f475Smrg		    XftPatternDestroy(pat);
1665d522f475Smrg		}
1666d522f475Smrg
1667d522f475Smrg		CACHE_XFT(screen->renderWideNorm, wnorm);
1668d522f475Smrg		CACHE_XFT(screen->renderWideBold, wbold);
1669d522f475Smrg		CACHE_XFT(screen->renderWideItal, wital);
1670d522f475Smrg	    }
1671d522f475Smrg#endif /* OPT_RENDERWIDE */
1672d522f475Smrg	}
1673d522f475Smrg	if (norm == 0) {
16742eaa94a1Schristos	    TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum));
1675d522f475Smrg	    xw->misc.render_font = False;
1676d522f475Smrg	    update_font_renderfont();
1677d522f475Smrg	    /* now we will fall through into the bitmap fonts */
1678d522f475Smrg	} else {
1679d522f475Smrg	    setRenderFontsize(screen, win, norm, NULL);
1680d522f475Smrg	    setRenderFontsize(screen, win, bold, "bold");
1681d522f475Smrg	    setRenderFontsize(screen, win, ital, "ital");
1682d522f475Smrg	}
1683d522f475Smrg    }
1684d522f475Smrg    /*
1685d522f475Smrg     * Are we handling a bitmap font?
1686d522f475Smrg     */
1687d522f475Smrg    if (!xw->misc.render_font || IsIconWin(screen, win))
1688d522f475Smrg#endif /* OPT_RENDERFONT */
1689d522f475Smrg    {
1690d522f475Smrg	if (is_double_width_font(font)) {
1691d522f475Smrg	    win->f_width = (font->min_bounds.width);
1692d522f475Smrg	} else {
1693d522f475Smrg	    win->f_width = (font->max_bounds.width);
1694d522f475Smrg	}
1695d522f475Smrg	win->f_height = (font->ascent + font->descent);
1696d522f475Smrg	win->f_ascent = font->ascent;
1697d522f475Smrg	win->f_descent = font->descent;
1698d522f475Smrg    }
1699d522f475Smrg    i = 2 * screen->border + sbwidth;
1700d522f475Smrg    j = 2 * screen->border;
1701d522f475Smrg    width = MaxCols(screen) * win->f_width + i;
1702d522f475Smrg    height = MaxRows(screen) * win->f_height + j;
1703d522f475Smrg    win->fullwidth = width;
1704d522f475Smrg    win->fullheight = height;
1705d522f475Smrg    win->width = width - i;
1706d522f475Smrg    win->height = height - j;
1707d522f475Smrg
1708d522f475Smrg    TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n",
1709d522f475Smrg	   win->height,
1710d522f475Smrg	   win->width,
1711d522f475Smrg	   win->fullheight,
1712d522f475Smrg	   win->fullwidth,
1713d522f475Smrg	   win->f_height,
1714d522f475Smrg	   win->f_width,
1715d522f475Smrg	   win->f_ascent,
1716d522f475Smrg	   win->f_descent));
1717d522f475Smrg}
1718d522f475Smrg
1719d522f475Smrg/* save this information as a side-effect for double-sized characters */
1720d522f475Smrgvoid
1721d522f475SmrgxtermSaveFontInfo(TScreen * screen, XFontStruct * font)
1722d522f475Smrg{
1723d522f475Smrg    screen->fnt_wide = (font->max_bounds.width);
1724d522f475Smrg    screen->fnt_high = (font->ascent + font->descent);
1725d522f475Smrg    TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide));
1726d522f475Smrg}
1727d522f475Smrg
1728d522f475Smrg/*
1729d522f475Smrg * After loading a new font, update the structures that use its size.
1730d522f475Smrg */
1731d522f475Smrgvoid
1732d522f475SmrgxtermUpdateFontInfo(XtermWidget xw, Bool doresize)
1733d522f475Smrg{
1734d522f475Smrg    TScreen *screen = &(xw->screen);
1735d522f475Smrg
1736d522f475Smrg    int scrollbar_width;
1737d522f475Smrg    VTwin *win = &(screen->fullVwin);
1738d522f475Smrg
1739d522f475Smrg    scrollbar_width = (xw->misc.scrollbar
1740d522f475Smrg		       ? (screen->scrollWidget->core.width +
1741d522f475Smrg			  BorderWidth(screen->scrollWidget))
1742d522f475Smrg		       : 0);
1743d522f475Smrg    xtermComputeFontInfo(xw, win, screen->fnts[fNorm].fs, scrollbar_width);
1744d522f475Smrg    xtermSaveFontInfo(screen, screen->fnts[fNorm].fs);
1745d522f475Smrg
1746d522f475Smrg    if (doresize) {
1747d522f475Smrg	if (VWindow(screen)) {
1748d522f475Smrg	    xtermClear(xw);
1749d522f475Smrg	}
1750d522f475Smrg	TRACE(("xtermUpdateFontInfo {{\n"));
1751d522f475Smrg	DoResizeScreen(xw);	/* set to the new natural size */
1752d522f475Smrg	ResizeScrollBar(xw);
1753d522f475Smrg	Redraw();
1754d522f475Smrg	TRACE(("... }} xtermUpdateFontInfo\n"));
1755d522f475Smrg#ifdef SCROLLBAR_RIGHT
1756d522f475Smrg	updateRightScrollbar(xw);
1757d522f475Smrg#endif
1758d522f475Smrg    }
1759d522f475Smrg    xtermSetCursorBox(screen);
1760d522f475Smrg}
1761d522f475Smrg
1762d522f475Smrg#if OPT_BOX_CHARS
1763d522f475Smrg
1764d522f475Smrg/*
1765d522f475Smrg * Returns true if the given character is missing from the specified font.
1766d522f475Smrg */
1767d522f475SmrgBool
1768d522f475SmrgxtermMissingChar(XtermWidget xw, unsigned ch, XFontStruct * font)
1769d522f475Smrg{
1770d522f475Smrg    if (font != 0
1771d522f475Smrg	&& font->per_char != 0
1772d522f475Smrg	&& !font->all_chars_exist) {
1773d522f475Smrg	static XCharStruct dft, *tmp = &dft, *pc = 0;
1774d522f475Smrg
1775d522f475Smrg	if (font->max_byte1 == 0) {
1776d522f475Smrg#if OPT_WIDE_CHARS
1777d522f475Smrg	    if (ch > 255) {
1778d522f475Smrg		TRACE(("xtermMissingChar %#04x (row)\n", ch));
1779d522f475Smrg		return True;
1780d522f475Smrg	    }
1781d522f475Smrg#endif
1782d522f475Smrg	    CI_GET_CHAR_INFO_1D(font, E2A(ch), tmp, pc);
1783d522f475Smrg	}
1784d522f475Smrg#if OPT_WIDE_CHARS
1785d522f475Smrg	else {
1786d522f475Smrg	    CI_GET_CHAR_INFO_2D(font, HI_BYTE(ch), LO_BYTE(ch), tmp, pc);
1787d522f475Smrg	}
1788d522f475Smrg#else
1789d522f475Smrg
1790d522f475Smrg	if (!pc)
1791d522f475Smrg	    return False;	/* Urgh! */
1792d522f475Smrg#endif
1793d522f475Smrg
1794d522f475Smrg	if (CI_NONEXISTCHAR(pc)) {
1795d522f475Smrg	    TRACE(("xtermMissingChar %#04x (!exists)\n", ch));
1796d522f475Smrg	    return True;
1797d522f475Smrg	}
1798d522f475Smrg    }
1799d522f475Smrg    if (xtermIsDecGraphic(ch)
1800d522f475Smrg	&& xw->screen.force_box_chars) {
1801d522f475Smrg	TRACE(("xtermMissingChar %#04x (forced off)\n", ch));
1802d522f475Smrg	return True;
1803d522f475Smrg    }
1804d522f475Smrg    return False;
1805d522f475Smrg}
1806d522f475Smrg
1807d522f475Smrg/*
1808d522f475Smrg * The grid is arbitrary, enough resolution that nothing's lost in
1809d522f475Smrg * initialization.
1810d522f475Smrg */
1811d522f475Smrg#define BOX_HIGH 60
1812d522f475Smrg#define BOX_WIDE 60
1813d522f475Smrg
1814d522f475Smrg#define MID_HIGH (BOX_HIGH/2)
1815d522f475Smrg#define MID_WIDE (BOX_WIDE/2)
1816d522f475Smrg
1817d522f475Smrg#define CHR_WIDE ((9*BOX_WIDE)/10)
1818d522f475Smrg#define CHR_HIGH ((9*BOX_HIGH)/10)
1819d522f475Smrg
1820d522f475Smrg/*
1821d522f475Smrg * ...since we'll scale the values anyway.
1822d522f475Smrg */
1823d522f475Smrg#define SCALE_X(n) n = (n * (font_width-1)) / (BOX_WIDE-1)
1824d522f475Smrg#define SCALE_Y(n) n = (n * (font_height-1)) / (BOX_HIGH-1)
1825d522f475Smrg
1826d522f475Smrg#define SEG(x0,y0,x1,y1) x0,y0, x1,y1
1827d522f475Smrg
1828d522f475Smrg/*
1829d522f475Smrg * Draw the given graphic character, if it is simple enough (i.e., a
1830d522f475Smrg * line-drawing character).
1831d522f475Smrg */
1832d522f475Smrgvoid
1833d522f475SmrgxtermDrawBoxChar(XtermWidget xw,
1834d522f475Smrg		 unsigned ch,
1835d522f475Smrg		 unsigned flags,
1836d522f475Smrg		 GC gc,
1837d522f475Smrg		 int x,
1838d522f475Smrg		 int y,
1839d522f475Smrg		 int cells)
1840d522f475Smrg{
1841d522f475Smrg    TScreen *screen = &(xw->screen);
1842d522f475Smrg    /* *INDENT-OFF* */
1843d522f475Smrg    static const short glyph_ht[] = {
1844d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,5*MID_HIGH/6),	/* H */
1845d522f475Smrg	SEG(6*BOX_WIDE/10,  0,		6*BOX_WIDE/10,5*MID_HIGH/6),
1846d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12),
1847d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
1848d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
1849d522f475Smrg	-1
1850d522f475Smrg    }, glyph_ff[] = {
1851d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		6*BOX_WIDE/10,	0),		/* F */
1852d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12),
1853d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		0*BOX_WIDE/3, 5*MID_HIGH/6),
1854d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
1855d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
1856d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
1857d522f475Smrg	-1
1858d522f475Smrg    }, glyph_lf[] = {
1859d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		1*BOX_WIDE/10,9*MID_HIGH/12),	/* L */
1860d522f475Smrg	SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12),
1861d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* F */
1862d522f475Smrg	SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
1863d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),
1864d522f475Smrg	-1
1865d522f475Smrg    }, glyph_nl[] = {
1866d522f475Smrg	SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10,	0),		/* N */
1867d522f475Smrg	SEG(1*BOX_WIDE/10,  0,		5*BOX_WIDE/6, 5*MID_HIGH/6),
1868d522f475Smrg	SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
1869d522f475Smrg	SEG(1*BOX_WIDE/3,   MID_HIGH,	1*BOX_WIDE/3,	CHR_HIGH),	/* L */
1870d522f475Smrg	SEG(1*BOX_WIDE/3,   CHR_HIGH,	  CHR_WIDE,	CHR_HIGH),
1871d522f475Smrg	-1
1872d522f475Smrg    }, glyph_vt[] = {
1873d522f475Smrg	SEG(1*BOX_WIDE/10,   0,		5*BOX_WIDE/12,5*MID_HIGH/6),	/* V */
1874d522f475Smrg	SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6,	0),
1875d522f475Smrg	SEG(2*BOX_WIDE/10,  MID_HIGH,	  CHR_WIDE,	MID_HIGH),	/* T */
1876d522f475Smrg	SEG(6*BOX_WIDE/10,  MID_HIGH,	6*BOX_WIDE/10,	CHR_HIGH),
1877d522f475Smrg	-1
1878d522f475Smrg    }, plus_or_minus[] =
1879d522f475Smrg    {
1880d522f475Smrg	SEG(  0,	  5*BOX_HIGH/6,	  CHR_WIDE,   5*BOX_HIGH/6),
1881d522f475Smrg	SEG(  MID_WIDE,	  2*BOX_HIGH/6,	  MID_WIDE,   4*BOX_HIGH/6),
1882d522f475Smrg	SEG(  0,	  3*BOX_HIGH/6,	  CHR_WIDE,   3*BOX_HIGH/6),
1883d522f475Smrg	-1
1884d522f475Smrg    }, lower_right_corner[] =
1885d522f475Smrg    {
1886d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
1887d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	0),
1888d522f475Smrg	-1
1889d522f475Smrg    }, upper_right_corner[] =
1890d522f475Smrg    {
1891d522f475Smrg	SEG(  0,	    MID_HIGH,	  MID_WIDE,	MID_HIGH),
1892d522f475Smrg	SEG( MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
1893d522f475Smrg	-1
1894d522f475Smrg    }, upper_left_corner[] =
1895d522f475Smrg    {
1896d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
1897d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
1898d522f475Smrg	-1
1899d522f475Smrg    }, lower_left_corner[] =
1900d522f475Smrg    {
1901d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
1902d522f475Smrg	SEG(  MID_WIDE,	    MID_WIDE,	  BOX_WIDE,	MID_HIGH),
1903d522f475Smrg	-1
1904d522f475Smrg    }, cross[] =
1905d522f475Smrg    {
1906d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
1907d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
1908d522f475Smrg	-1
1909d522f475Smrg    }, scan_line_1[] =
1910d522f475Smrg    {
1911d522f475Smrg	SEG(  0,	    0,		  BOX_WIDE,	0),
1912d522f475Smrg	-1
1913d522f475Smrg    }, scan_line_3[] =
1914d522f475Smrg    {
1915d522f475Smrg	SEG(  0,	    BOX_HIGH/4,	  BOX_WIDE,	BOX_HIGH/4),
1916d522f475Smrg	-1
1917d522f475Smrg    }, scan_line_7[] =
1918d522f475Smrg    {
1919d522f475Smrg	SEG( 0,		    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
1920d522f475Smrg	-1
1921d522f475Smrg    }, scan_line_9[] =
1922d522f475Smrg    {
1923d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  BOX_WIDE,   3*BOX_HIGH/4),
1924d522f475Smrg	-1
1925d522f475Smrg    }, horizontal_line[] =
1926d522f475Smrg    {
1927d522f475Smrg	SEG(  0,	    BOX_HIGH,	  BOX_WIDE,	BOX_HIGH),
1928d522f475Smrg	-1
1929d522f475Smrg    }, left_tee[] =
1930d522f475Smrg    {
1931d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
1932d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
1933d522f475Smrg	-1
1934d522f475Smrg    }, right_tee[] =
1935d522f475Smrg    {
1936d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
1937d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  0,		MID_HIGH),
1938d522f475Smrg	-1
1939d522f475Smrg    }, bottom_tee[] =
1940d522f475Smrg    {
1941d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
1942d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	MID_HIGH),
1943d522f475Smrg	-1
1944d522f475Smrg    }, top_tee[] =
1945d522f475Smrg    {
1946d522f475Smrg	SEG(  0,	    MID_HIGH,	  BOX_WIDE,	MID_HIGH),
1947d522f475Smrg	SEG(  MID_WIDE,	    MID_HIGH,	  MID_WIDE,	BOX_HIGH),
1948d522f475Smrg	-1
1949d522f475Smrg    }, vertical_line[] =
1950d522f475Smrg    {
1951d522f475Smrg	SEG(  MID_WIDE,	    0,		  MID_WIDE,	BOX_HIGH),
1952d522f475Smrg	-1
1953d522f475Smrg    }, less_than_or_equal[] =
1954d522f475Smrg    {
1955d522f475Smrg	SEG(  CHR_WIDE,	    BOX_HIGH/3,	  0,		MID_HIGH),
1956d522f475Smrg	SEG(  CHR_WIDE,	  2*BOX_HIGH/3,	  0,		MID_HIGH),
1957d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
1958d522f475Smrg	-1
1959d522f475Smrg    }, greater_than_or_equal[] =
1960d522f475Smrg    {
1961d522f475Smrg	SEG(  0,	    BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
1962d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,	MID_HIGH),
1963d522f475Smrg	SEG(  0,	  3*BOX_HIGH/4,	  CHR_WIDE,   3*BOX_HIGH/4),
1964d522f475Smrg	-1
1965d522f475Smrg    }, greek_pi[] =
1966d522f475Smrg    {
1967d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
1968d522f475Smrg	SEG(5*CHR_WIDE/6,   MID_HIGH,	5*CHR_WIDE/6,	CHR_HIGH),
1969d522f475Smrg	SEG(2*CHR_WIDE/6,   MID_HIGH,	2*CHR_WIDE/6,	CHR_HIGH),
1970d522f475Smrg	-1
1971d522f475Smrg    }, not_equal_to[] =
1972d522f475Smrg    {
1973d522f475Smrg	SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3,	CHR_HIGH),
1974d522f475Smrg	SEG(  0,	  2*BOX_HIGH/3,	  CHR_WIDE,   2*BOX_HIGH/3),
1975d522f475Smrg	SEG(  0,	    MID_HIGH,	  CHR_WIDE,	MID_HIGH),
1976d522f475Smrg	-1
1977d522f475Smrg    };
1978d522f475Smrg    /* *INDENT-ON* */
1979d522f475Smrg
1980d522f475Smrg    static const short *lines[] =
1981d522f475Smrg    {
1982d522f475Smrg	0,			/* 00 (unused) */
1983d522f475Smrg	0,			/* 01 diamond */
1984d522f475Smrg	0,			/* 02 box */
1985d522f475Smrg	glyph_ht,		/* 03 HT */
1986d522f475Smrg	glyph_ff,		/* 04 FF */
1987d522f475Smrg	0,			/* 05 CR */
1988d522f475Smrg	glyph_lf,		/* 06 LF */
1989d522f475Smrg	0,			/* 07 degrees (small circle) */
1990d522f475Smrg	plus_or_minus,		/* 08 */
1991d522f475Smrg	glyph_nl,		/* 09 */
1992d522f475Smrg	glyph_vt,		/* 0A */
1993d522f475Smrg	lower_right_corner,	/* 0B */
1994d522f475Smrg	upper_right_corner,	/* 0C */
1995d522f475Smrg	upper_left_corner,	/* 0D */
1996d522f475Smrg	lower_left_corner,	/* 0E */
1997d522f475Smrg	cross,			/* 0F */
1998d522f475Smrg	scan_line_1,		/* 10 */
1999d522f475Smrg	scan_line_3,		/* 11 */
2000d522f475Smrg	scan_line_7,		/* 12 */
2001d522f475Smrg	scan_line_9,		/* 13 */
2002d522f475Smrg	horizontal_line,	/* 14 */
2003d522f475Smrg	left_tee,		/* 15 */
2004d522f475Smrg	right_tee,		/* 16 */
2005d522f475Smrg	bottom_tee,		/* 17 */
2006d522f475Smrg	top_tee,		/* 18 */
2007d522f475Smrg	vertical_line,		/* 19 */
2008d522f475Smrg	less_than_or_equal,	/* 1A */
2009d522f475Smrg	greater_than_or_equal,	/* 1B */
2010d522f475Smrg	greek_pi,		/* 1C */
2011d522f475Smrg	not_equal_to,		/* 1D */
2012d522f475Smrg	0,			/* 1E LB */
2013d522f475Smrg	0,			/* 1F bullet */
2014d522f475Smrg    };
2015d522f475Smrg
2016d522f475Smrg    GC gc2;
2017d522f475Smrg    CgsEnum cgsId = (ch == 2) ? gcDots : gcLine;
2018d522f475Smrg    VTwin *cgsWin = WhichVWin(screen);
2019d522f475Smrg    const short *p;
2020d522f475Smrg    unsigned font_width = ((flags & DOUBLEWFONT) ? 2 : 1) * screen->fnt_wide;
2021d522f475Smrg    unsigned font_height = ((flags & DOUBLEHFONT) ? 2 : 1) * screen->fnt_high;
2022d522f475Smrg
2023d522f475Smrg    if (cells > 1)
2024d522f475Smrg	font_width *= cells;
2025d522f475Smrg
2026d522f475Smrg#if OPT_WIDE_CHARS
2027d522f475Smrg    /*
2028d522f475Smrg     * Try to show line-drawing characters if we happen to be in UTF-8
2029d522f475Smrg     * mode, but have gotten an old-style font.
2030d522f475Smrg     */
2031d522f475Smrg    if (screen->utf8_mode
2032d522f475Smrg#if OPT_RENDERFONT
2033d522f475Smrg	&& !UsingRenderFont(xw)
2034d522f475Smrg#endif
2035d522f475Smrg	&& (ch > 127)
2036d522f475Smrg	&& (ch != UCS_REPL)) {
2037d522f475Smrg	unsigned n;
2038d522f475Smrg	for (n = 1; n < 32; n++) {
2039d522f475Smrg	    if (dec2ucs(n) == ch
2040d522f475Smrg		&& !xtermMissingChar(xw, n,
2041d522f475Smrg				     ((flags & BOLD)
2042d522f475Smrg				      ? screen->fnts[fBold].fs
2043d522f475Smrg				      : screen->fnts[fNorm].fs))) {
2044d522f475Smrg		TRACE(("...use xterm-style linedrawing\n"));
2045d522f475Smrg		ch = n;
2046d522f475Smrg		break;
2047d522f475Smrg	    }
2048d522f475Smrg	}
2049d522f475Smrg    }
2050d522f475Smrg#endif
2051d522f475Smrg
2052d522f475Smrg    TRACE(("DRAW_BOX(%d) cell %dx%d at %d,%d%s\n",
2053d522f475Smrg	   ch, font_height, font_width, y, x,
2054d522f475Smrg	   (ch >= (sizeof(lines) / sizeof(lines[0]))
2055d522f475Smrg	    ? "-BAD"
2056d522f475Smrg	    : "")));
2057d522f475Smrg
2058d522f475Smrg    if (cgsId == gcDots) {
2059d522f475Smrg	setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2060d522f475Smrg	setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc));
2061d522f475Smrg	setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2062d522f475Smrg    } else {
2063d522f475Smrg	setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2064d522f475Smrg	setCgsFore(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2065d522f475Smrg	setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2066d522f475Smrg    }
2067d522f475Smrg    gc2 = getCgsGC(xw, cgsWin, cgsId);
2068d522f475Smrg
2069d522f475Smrg    if (!(flags & NOBACKGROUND)) {
2070d522f475Smrg	XFillRectangle(screen->display, VWindow(screen), gc2, x, y,
2071d522f475Smrg		       font_width,
2072d522f475Smrg		       font_height);
2073d522f475Smrg    }
2074d522f475Smrg
2075d522f475Smrg    setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2076d522f475Smrg    setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc));
2077d522f475Smrg    setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2078d522f475Smrg    gc2 = getCgsGC(xw, cgsWin, cgsId);
2079d522f475Smrg
2080d522f475Smrg    XSetLineAttributes(screen->display, gc2,
2081d522f475Smrg		       (flags & BOLD)
2082d522f475Smrg		       ? ((font_height > 12)
2083d522f475Smrg			  ? font_height / 12
2084d522f475Smrg			  : 1)
2085d522f475Smrg		       : ((font_height > 16)
2086d522f475Smrg			  ? font_height / 16
2087d522f475Smrg			  : 1),
2088d522f475Smrg		       LineSolid,
2089d522f475Smrg		       CapProjecting,
2090d522f475Smrg		       JoinMiter);
2091d522f475Smrg
2092d522f475Smrg    if (ch == 1) {		/* diamond */
2093d522f475Smrg	XPoint points[5];
2094d522f475Smrg	int npoints = 5, n;
2095d522f475Smrg
2096d522f475Smrg	points[0].x = MID_WIDE;
2097d522f475Smrg	points[0].y = BOX_HIGH / 4;
2098d522f475Smrg
2099d522f475Smrg	points[1].x = 8 * BOX_WIDE / 8;
2100d522f475Smrg	points[1].y = MID_HIGH;
2101d522f475Smrg
2102d522f475Smrg	points[2].x = points[0].x;
2103d522f475Smrg	points[2].y = 3 * BOX_HIGH / 4;
2104d522f475Smrg
2105d522f475Smrg	points[3].x = 0 * BOX_WIDE / 8;
2106d522f475Smrg	points[3].y = points[1].y;
2107d522f475Smrg
2108d522f475Smrg	points[4].x = points[0].x;
2109d522f475Smrg	points[4].y = points[0].y;
2110d522f475Smrg
2111d522f475Smrg	for (n = 0; n < npoints; ++n) {
2112d522f475Smrg	    SCALE_X(points[n].x);
2113d522f475Smrg	    SCALE_Y(points[n].y);
2114d522f475Smrg	    points[n].x += x;
2115d522f475Smrg	    points[n].y += y;
2116d522f475Smrg	}
2117d522f475Smrg
2118d522f475Smrg	XFillPolygon(screen->display,
2119d522f475Smrg		     VWindow(screen), gc2,
2120d522f475Smrg		     points, npoints,
2121d522f475Smrg		     Convex, CoordModeOrigin);
2122d522f475Smrg    } else if (ch == 7) {	/* degrees */
2123d522f475Smrg	unsigned width = (BOX_WIDE / 3);
2124d522f475Smrg	int x_coord = MID_WIDE - (width / 2);
2125d522f475Smrg	int y_coord = MID_HIGH - width;
2126d522f475Smrg
2127d522f475Smrg	SCALE_X(x_coord);
2128d522f475Smrg	SCALE_Y(y_coord);
2129d522f475Smrg	SCALE_X(width);
2130d522f475Smrg
2131d522f475Smrg	XDrawArc(screen->display,
2132d522f475Smrg		 VWindow(screen), gc2,
2133d522f475Smrg		 x + x_coord, y + y_coord, width, width,
2134d522f475Smrg		 0,
2135d522f475Smrg		 360 * 64);
2136d522f475Smrg    } else if (ch == 0x1f) {	/* bullet */
2137d522f475Smrg	unsigned width = 7 * BOX_WIDE / 10;
2138d522f475Smrg	int x_coord = MID_WIDE - (width / 3);
2139d522f475Smrg	int y_coord = MID_HIGH - (width / 3);
2140d522f475Smrg
2141d522f475Smrg	SCALE_X(x_coord);
2142d522f475Smrg	SCALE_Y(y_coord);
2143d522f475Smrg	SCALE_X(width);
2144d522f475Smrg
2145d522f475Smrg	XDrawArc(screen->display,
2146d522f475Smrg		 VWindow(screen), gc2,
2147d522f475Smrg		 x + x_coord, y + y_coord, width, width,
2148d522f475Smrg		 0,
2149d522f475Smrg		 360 * 64);
2150d522f475Smrg    } else if (ch < (sizeof(lines) / sizeof(lines[0]))
2151d522f475Smrg	       && (p = lines[ch]) != 0) {
21522eaa94a1Schristos	unsigned coord[4];
2153d522f475Smrg	int n = 0;
2154d522f475Smrg	while (*p >= 0) {
2155d522f475Smrg	    coord[n++] = *p++;
2156d522f475Smrg	    if (n == 4) {
2157d522f475Smrg		SCALE_X(coord[0]);
2158d522f475Smrg		SCALE_Y(coord[1]);
2159d522f475Smrg		SCALE_X(coord[2]);
2160d522f475Smrg		SCALE_Y(coord[3]);
2161d522f475Smrg		XDrawLine(screen->display,
2162d522f475Smrg			  VWindow(screen), gc2,
2163d522f475Smrg			  x + coord[0], y + coord[1],
2164d522f475Smrg			  x + coord[2], y + coord[3]);
2165d522f475Smrg		n = 0;
2166d522f475Smrg	    }
2167d522f475Smrg	}
2168d522f475Smrg    } else if (screen->force_all_chars) {
2169d522f475Smrg	/* bounding rectangle, for debugging */
2170d522f475Smrg	XDrawRectangle(screen->display, VWindow(screen), gc2, x, y,
2171d522f475Smrg		       font_width - 1,
2172d522f475Smrg		       font_height - 1);
2173d522f475Smrg    }
2174d522f475Smrg}
2175d522f475Smrg
2176d522f475Smrg#if OPT_RENDERFONT
2177d522f475Smrg
2178d522f475Smrg/*
2179d522f475Smrg * Check if the given character has a glyph known to Xft.
2180d522f475Smrg *
2181d522f475Smrg * see xc/lib/Xft/xftglyphs.c
2182d522f475Smrg */
2183d522f475SmrgBool
2184d522f475SmrgxtermXftMissing(XtermWidget xw, XftFont * font, unsigned wc)
2185d522f475Smrg{
2186d522f475Smrg    Bool result = False;
2187d522f475Smrg
2188d522f475Smrg    if (font != 0) {
2189d522f475Smrg	if (!XftGlyphExists(xw->screen.display, font, wc)) {
2190d522f475Smrg#if OPT_WIDE_CHARS
2191d522f475Smrg	    TRACE(("xtermXftMissing %d (dec=%#x, ucs=%#x)\n",
2192d522f475Smrg		   wc, ucs2dec(wc), dec2ucs(wc)));
2193d522f475Smrg#else
2194d522f475Smrg	    TRACE(("xtermXftMissing %d\n", wc));
2195d522f475Smrg#endif
2196d522f475Smrg	    result = True;
2197d522f475Smrg	}
2198d522f475Smrg    }
2199d522f475Smrg    return result;
2200d522f475Smrg}
2201d522f475Smrg#endif /* OPT_RENDERFONT && OPT_WIDE_CHARS */
2202d522f475Smrg
2203d522f475Smrg#endif /* OPT_BOX_CHARS */
2204d522f475Smrg
2205d522f475Smrg#if OPT_WIDE_CHARS
2206d522f475Smrg#define MY_UCS(ucs,dec) case ucs: result = dec; break
2207d522f475Smrgunsigned
2208d522f475Smrgucs2dec(unsigned ch)
2209d522f475Smrg{
2210d522f475Smrg    unsigned result = ch;
2211d522f475Smrg    if ((ch > 127)
2212d522f475Smrg	&& (ch != UCS_REPL)) {
2213d522f475Smrg	switch (ch) {
2214d522f475Smrg	    MY_UCS(0x25ae, 0);	/* black vertical rectangle                   */
2215d522f475Smrg	    MY_UCS(0x25c6, 1);	/* black diamond                              */
2216d522f475Smrg	    MY_UCS(0x2592, 2);	/* medium shade                               */
2217d522f475Smrg	    MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation           */
2218d522f475Smrg	    MY_UCS(0x240c, 4);	/* symbol for form feed                       */
2219d522f475Smrg	    MY_UCS(0x240d, 5);	/* symbol for carriage return                 */
2220d522f475Smrg	    MY_UCS(0x240a, 6);	/* symbol for line feed                       */
2221d522f475Smrg	    MY_UCS(0x00b0, 7);	/* degree sign                                */
2222d522f475Smrg	    MY_UCS(0x00b1, 8);	/* plus-minus sign                            */
2223d522f475Smrg	    MY_UCS(0x2424, 9);	/* symbol for newline                         */
2224d522f475Smrg	    MY_UCS(0x240b, 10);	/* symbol for vertical tabulation             */
2225d522f475Smrg	    MY_UCS(0x2518, 11);	/* box drawings light up and left             */
2226d522f475Smrg	    MY_UCS(0x2510, 12);	/* box drawings light down and left           */
2227d522f475Smrg	    MY_UCS(0x250c, 13);	/* box drawings light down and right          */
2228d522f475Smrg	    MY_UCS(0x2514, 14);	/* box drawings light up and right            */
2229d522f475Smrg	    MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
2230d522f475Smrg	    MY_UCS(0x23ba, 16);	/* box drawings scan 1                        */
2231d522f475Smrg	    MY_UCS(0x23bb, 17);	/* box drawings scan 3                        */
2232d522f475Smrg	    MY_UCS(0x2500, 18);	/* box drawings light horizontal              */
2233d522f475Smrg	    MY_UCS(0x23bc, 19);	/* box drawings scan 7                        */
2234d522f475Smrg	    MY_UCS(0x23bd, 20);	/* box drawings scan 9                        */
2235d522f475Smrg	    MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
2236d522f475Smrg	    MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
2237d522f475Smrg	    MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
2238d522f475Smrg	    MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
2239d522f475Smrg	    MY_UCS(0x2502, 25);	/* box drawings light vertical                */
2240d522f475Smrg	    MY_UCS(0x2264, 26);	/* less-than or equal to                      */
2241d522f475Smrg	    MY_UCS(0x2265, 27);	/* greater-than or equal to                   */
2242d522f475Smrg	    MY_UCS(0x03c0, 28);	/* greek small letter pi                      */
2243d522f475Smrg	    MY_UCS(0x2260, 29);	/* not equal to                               */
2244d522f475Smrg	    MY_UCS(0x00a3, 30);	/* pound sign                                 */
2245d522f475Smrg	    MY_UCS(0x00b7, 31);	/* middle dot                                 */
2246d522f475Smrg	}
2247d522f475Smrg    }
2248d522f475Smrg    return result;
2249d522f475Smrg}
2250d522f475Smrg
2251d522f475Smrg#undef  MY_UCS
2252d522f475Smrg#define MY_UCS(ucs,dec) case dec: result = ucs; break
2253d522f475Smrg
2254d522f475Smrgunsigned
2255d522f475Smrgdec2ucs(unsigned ch)
2256d522f475Smrg{
2257d522f475Smrg    unsigned result = ch;
2258d522f475Smrg    if (xtermIsDecGraphic(ch)) {
2259d522f475Smrg	switch (ch) {
2260d522f475Smrg	    MY_UCS(0x25ae, 0);	/* black vertical rectangle                   */
2261d522f475Smrg	    MY_UCS(0x25c6, 1);	/* black diamond                              */
2262d522f475Smrg	    MY_UCS(0x2592, 2);	/* medium shade                               */
2263d522f475Smrg	    MY_UCS(0x2409, 3);	/* symbol for horizontal tabulation           */
2264d522f475Smrg	    MY_UCS(0x240c, 4);	/* symbol for form feed                       */
2265d522f475Smrg	    MY_UCS(0x240d, 5);	/* symbol for carriage return                 */
2266d522f475Smrg	    MY_UCS(0x240a, 6);	/* symbol for line feed                       */
2267d522f475Smrg	    MY_UCS(0x00b0, 7);	/* degree sign                                */
2268d522f475Smrg	    MY_UCS(0x00b1, 8);	/* plus-minus sign                            */
2269d522f475Smrg	    MY_UCS(0x2424, 9);	/* symbol for newline                         */
2270d522f475Smrg	    MY_UCS(0x240b, 10);	/* symbol for vertical tabulation             */
2271d522f475Smrg	    MY_UCS(0x2518, 11);	/* box drawings light up and left             */
2272d522f475Smrg	    MY_UCS(0x2510, 12);	/* box drawings light down and left           */
2273d522f475Smrg	    MY_UCS(0x250c, 13);	/* box drawings light down and right          */
2274d522f475Smrg	    MY_UCS(0x2514, 14);	/* box drawings light up and right            */
2275d522f475Smrg	    MY_UCS(0x253c, 15);	/* box drawings light vertical and horizontal */
2276d522f475Smrg	    MY_UCS(0x23ba, 16);	/* box drawings scan 1                        */
2277d522f475Smrg	    MY_UCS(0x23bb, 17);	/* box drawings scan 3                        */
2278d522f475Smrg	    MY_UCS(0x2500, 18);	/* box drawings light horizontal              */
2279d522f475Smrg	    MY_UCS(0x23bc, 19);	/* box drawings scan 7                        */
2280d522f475Smrg	    MY_UCS(0x23bd, 20);	/* box drawings scan 9                        */
2281d522f475Smrg	    MY_UCS(0x251c, 21);	/* box drawings light vertical and right      */
2282d522f475Smrg	    MY_UCS(0x2524, 22);	/* box drawings light vertical and left       */
2283d522f475Smrg	    MY_UCS(0x2534, 23);	/* box drawings light up and horizontal       */
2284d522f475Smrg	    MY_UCS(0x252c, 24);	/* box drawings light down and horizontal     */
2285d522f475Smrg	    MY_UCS(0x2502, 25);	/* box drawings light vertical                */
2286d522f475Smrg	    MY_UCS(0x2264, 26);	/* less-than or equal to                      */
2287d522f475Smrg	    MY_UCS(0x2265, 27);	/* greater-than or equal to                   */
2288d522f475Smrg	    MY_UCS(0x03c0, 28);	/* greek small letter pi                      */
2289d522f475Smrg	    MY_UCS(0x2260, 29);	/* not equal to                               */
2290d522f475Smrg	    MY_UCS(0x00a3, 30);	/* pound sign                                 */
2291d522f475Smrg	    MY_UCS(0x00b7, 31);	/* middle dot                                 */
2292d522f475Smrg	}
2293d522f475Smrg    }
2294d522f475Smrg    return result;
2295d522f475Smrg}
2296d522f475Smrg
2297d522f475Smrg#endif /* OPT_WIDE_CHARS */
2298d522f475Smrg
2299d522f475Smrg#if OPT_SHIFT_FONTS
2300d522f475Smrgstatic void
2301d522f475SmrglookupOneFontSize(XtermWidget xw, int fontnum)
2302d522f475Smrg{
2303d522f475Smrg    TScreen *screen = TScreenOf(xw);
2304d522f475Smrg
2305d522f475Smrg    if (screen->menu_font_sizes[fontnum] == 0) {
2306d522f475Smrg	XTermFonts fnt;
2307d522f475Smrg
2308d522f475Smrg	memset(&fnt, 0, sizeof(fnt));
2309d522f475Smrg	screen->menu_font_sizes[fontnum] = -1;
2310d522f475Smrg	if (xtermOpenFont(xw, screen->MenuFontName(fontnum), &fnt)) {
2311d522f475Smrg	    screen->menu_font_sizes[fontnum] = FontSize(fnt.fs);
2312d522f475Smrg	    TRACE(("menu_font_sizes[%d] = %ld\n", fontnum,
2313d522f475Smrg		   screen->menu_font_sizes[fontnum]));
2314d522f475Smrg	    xtermCloseFont(xw, &fnt);
2315d522f475Smrg	}
2316d522f475Smrg    }
2317d522f475Smrg}
2318d522f475Smrg
2319d522f475Smrg/*
2320d522f475Smrg * Cache the font-sizes so subsequent larger/smaller font actions will go fast.
2321d522f475Smrg */
2322d522f475Smrgstatic void
2323d522f475SmrglookupFontSizes(XtermWidget xw)
2324d522f475Smrg{
2325d522f475Smrg    int n;
2326d522f475Smrg
2327d522f475Smrg    for (n = 0; n < NMENUFONTS; n++) {
2328d522f475Smrg	lookupOneFontSize(xw, n);
2329d522f475Smrg    }
2330d522f475Smrg}
2331d522f475Smrg
23322eaa94a1Schristos#if OPT_RENDERFONT
23332eaa94a1Schristos#define NMENU_RENDERFONTS (NMENUFONTS - 2)	/* no selection or escape */
23342eaa94a1Schristosstatic Boolean
23352eaa94a1SchristosuseFaceSizes(XtermWidget xw)
23362eaa94a1Schristos{
23372eaa94a1Schristos    Boolean result = False;
23382eaa94a1Schristos    int n;
23392eaa94a1Schristos
23402eaa94a1Schristos    if (UsingRenderFont(xw)) {
23412eaa94a1Schristos	result = True;
23422eaa94a1Schristos	for (n = 0; n < NMENU_RENDERFONTS; ++n) {
23432eaa94a1Schristos	    if (xw->misc.face_size[n] <= 0.0) {
23442eaa94a1Schristos		result = False;
23452eaa94a1Schristos		break;
23462eaa94a1Schristos	    }
23472eaa94a1Schristos	}
23482eaa94a1Schristos    }
23492eaa94a1Schristos    return result;
23502eaa94a1Schristos}
23512eaa94a1Schristos#endif
23522eaa94a1Schristos
2353d522f475Smrg/*
2354d522f475Smrg * Find the index of a larger/smaller font (according to the sign of 'relative'
2355d522f475Smrg * and its magnitude), starting from the 'old' index.
2356d522f475Smrg */
2357d522f475Smrgint
2358d522f475SmrglookupRelativeFontSize(XtermWidget xw, int old, int relative)
2359d522f475Smrg{
2360d522f475Smrg    TScreen *screen = TScreenOf(xw);
2361d522f475Smrg    int n, m = -1;
2362d522f475Smrg
23632eaa94a1Schristos    TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative));
2364d522f475Smrg    if (!IsIcon(screen)) {
23652eaa94a1Schristos#if OPT_RENDERFONT
23662eaa94a1Schristos	if (useFaceSizes(xw)) {
23672eaa94a1Schristos	    TRACE(("...using FaceSize\n"));
23682eaa94a1Schristos	    if (relative != 0) {
23692eaa94a1Schristos		for (n = 0; n < NMENU_RENDERFONTS; ++n) {
23702eaa94a1Schristos		    if (xw->misc.face_size[n] > 0 &&
23712eaa94a1Schristos			xw->misc.face_size[n] != xw->misc.face_size[old]) {
23722eaa94a1Schristos			int cmp_0 = ((xw->misc.face_size[n] >
23732eaa94a1Schristos				      xw->misc.face_size[old])
23742eaa94a1Schristos				     ? relative
23752eaa94a1Schristos				     : -relative);
23762eaa94a1Schristos			int cmp_m = ((m < 0)
23772eaa94a1Schristos				     ? 1
23782eaa94a1Schristos				     : ((xw->misc.face_size[n] <
23792eaa94a1Schristos					 xw->misc.face_size[m])
23802eaa94a1Schristos					? relative
23812eaa94a1Schristos					: -relative));
23822eaa94a1Schristos			if (cmp_0 > 0 && cmp_m > 0) {
23832eaa94a1Schristos			    m = n;
23842eaa94a1Schristos			}
2385d522f475Smrg		    }
2386d522f475Smrg		}
2387d522f475Smrg	    }
23882eaa94a1Schristos	} else
23892eaa94a1Schristos#endif
23902eaa94a1Schristos	{
23912eaa94a1Schristos	    TRACE(("...using bitmap areas\n"));
23922eaa94a1Schristos	    lookupFontSizes(xw);
23932eaa94a1Schristos	    if (relative != 0) {
23942eaa94a1Schristos		for (n = 0; n < NMENUFONTS; ++n) {
23952eaa94a1Schristos		    if (screen->menu_font_sizes[n] > 0 &&
23962eaa94a1Schristos			screen->menu_font_sizes[n] !=
23972eaa94a1Schristos			screen->menu_font_sizes[old]) {
23982eaa94a1Schristos			int cmp_0 = ((screen->menu_font_sizes[n] >
23992eaa94a1Schristos				      screen->menu_font_sizes[old])
24002eaa94a1Schristos				     ? relative
24012eaa94a1Schristos				     : -relative);
24022eaa94a1Schristos			int cmp_m = ((m < 0)
24032eaa94a1Schristos				     ? 1
24042eaa94a1Schristos				     : ((screen->menu_font_sizes[n] <
24052eaa94a1Schristos					 screen->menu_font_sizes[m])
24062eaa94a1Schristos					? relative
24072eaa94a1Schristos					: -relative));
24082eaa94a1Schristos			if (cmp_0 > 0 && cmp_m > 0) {
24092eaa94a1Schristos			    m = n;
24102eaa94a1Schristos			}
24112eaa94a1Schristos		    }
24122eaa94a1Schristos		}
2413d522f475Smrg	    }
2414d522f475Smrg	}
24152eaa94a1Schristos	TRACE(("...new index %d\n", m));
24162eaa94a1Schristos	if (m >= 0) {
24172eaa94a1Schristos	    if (relative > 1)
24182eaa94a1Schristos		m = lookupRelativeFontSize(xw, m, relative - 1);
24192eaa94a1Schristos	    else if (relative < -1)
24202eaa94a1Schristos		m = lookupRelativeFontSize(xw, m, relative + 1);
24212eaa94a1Schristos	}
2422d522f475Smrg    }
2423d522f475Smrg    return m;
2424d522f475Smrg}
2425d522f475Smrg
2426d522f475Smrg/* ARGSUSED */
2427d522f475Smrgvoid
2428d522f475SmrgHandleLargerFont(Widget w GCC_UNUSED,
2429d522f475Smrg		 XEvent * event GCC_UNUSED,
2430d522f475Smrg		 String * params GCC_UNUSED,
2431d522f475Smrg		 Cardinal *param_count GCC_UNUSED)
2432d522f475Smrg{
2433d522f475Smrg    if (IsXtermWidget(w)) {
2434d522f475Smrg	XtermWidget xw = (XtermWidget) w;
2435d522f475Smrg
2436d522f475Smrg	if (xw->misc.shift_fonts) {
2437d522f475Smrg	    TScreen *screen = &xw->screen;
2438d522f475Smrg	    int m;
2439d522f475Smrg
2440d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, 1);
2441d522f475Smrg	    if (m >= 0) {
2442d522f475Smrg		SetVTFont(xw, m, True, NULL);
2443d522f475Smrg	    } else {
2444d522f475Smrg		Bell(XkbBI_MinorError, 0);
2445d522f475Smrg	    }
2446d522f475Smrg	}
2447d522f475Smrg    }
2448d522f475Smrg}
2449d522f475Smrg
2450d522f475Smrg/* ARGSUSED */
2451d522f475Smrgvoid
2452d522f475SmrgHandleSmallerFont(Widget w GCC_UNUSED,
2453d522f475Smrg		  XEvent * event GCC_UNUSED,
2454d522f475Smrg		  String * params GCC_UNUSED,
2455d522f475Smrg		  Cardinal *param_count GCC_UNUSED)
2456d522f475Smrg{
2457d522f475Smrg    if (IsXtermWidget(w)) {
2458d522f475Smrg	XtermWidget xw = (XtermWidget) w;
2459d522f475Smrg
2460d522f475Smrg	if (xw->misc.shift_fonts) {
2461d522f475Smrg	    TScreen *screen = &xw->screen;
2462d522f475Smrg	    int m;
2463d522f475Smrg
2464d522f475Smrg	    m = lookupRelativeFontSize(xw, screen->menu_font_number, -1);
2465d522f475Smrg	    if (m >= 0) {
2466d522f475Smrg		SetVTFont(xw, m, True, NULL);
2467d522f475Smrg	    } else {
2468d522f475Smrg		Bell(XkbBI_MinorError, 0);
2469d522f475Smrg	    }
2470d522f475Smrg	}
2471d522f475Smrg    }
2472d522f475Smrg}
2473d522f475Smrg#endif
2474d522f475Smrg
2475d522f475Smrgint
2476d522f475SmrgxtermGetFont(const char *param)
2477d522f475Smrg{
2478d522f475Smrg    int fontnum;
2479d522f475Smrg
2480d522f475Smrg    switch (param[0]) {
2481d522f475Smrg    case 'd':
2482d522f475Smrg    case 'D':
2483d522f475Smrg    case '0':
2484d522f475Smrg	fontnum = fontMenu_default;
2485d522f475Smrg	break;
2486d522f475Smrg    case '1':
2487d522f475Smrg	fontnum = fontMenu_font1;
2488d522f475Smrg	break;
2489d522f475Smrg    case '2':
2490d522f475Smrg	fontnum = fontMenu_font2;
2491d522f475Smrg	break;
2492d522f475Smrg    case '3':
2493d522f475Smrg	fontnum = fontMenu_font3;
2494d522f475Smrg	break;
2495d522f475Smrg    case '4':
2496d522f475Smrg	fontnum = fontMenu_font4;
2497d522f475Smrg	break;
2498d522f475Smrg    case '5':
2499d522f475Smrg	fontnum = fontMenu_font5;
2500d522f475Smrg	break;
2501d522f475Smrg    case '6':
2502d522f475Smrg	fontnum = fontMenu_font6;
2503d522f475Smrg	break;
2504d522f475Smrg    case 'e':
2505d522f475Smrg    case 'E':
2506d522f475Smrg	fontnum = fontMenu_fontescape;
2507d522f475Smrg	break;
2508d522f475Smrg    case 's':
2509d522f475Smrg    case 'S':
2510d522f475Smrg	fontnum = fontMenu_fontsel;
2511d522f475Smrg	break;
2512d522f475Smrg    default:
2513d522f475Smrg	fontnum = -1;
2514d522f475Smrg	break;
2515d522f475Smrg    }
2516d522f475Smrg    return fontnum;
2517d522f475Smrg}
2518d522f475Smrg
2519d522f475Smrg/* ARGSUSED */
2520d522f475Smrgvoid
2521d522f475SmrgHandleSetFont(Widget w GCC_UNUSED,
2522d522f475Smrg	      XEvent * event GCC_UNUSED,
2523d522f475Smrg	      String * params,
2524d522f475Smrg	      Cardinal *param_count)
2525d522f475Smrg{
2526d522f475Smrg    if (IsXtermWidget(w)) {
2527d522f475Smrg	int fontnum;
2528d522f475Smrg	VTFontNames fonts;
2529d522f475Smrg
2530d522f475Smrg	memset(&fonts, 0, sizeof(fonts));
2531d522f475Smrg
2532d522f475Smrg	if (*param_count == 0) {
2533d522f475Smrg	    fontnum = fontMenu_default;
2534d522f475Smrg	} else {
2535d522f475Smrg	    Cardinal maxparams = 1;	/* total number of params allowed */
2536d522f475Smrg	    int result = xtermGetFont(params[0]);
2537d522f475Smrg
2538d522f475Smrg	    switch (result) {
2539d522f475Smrg	    case fontMenu_default:	/* FALLTHRU */
2540d522f475Smrg	    case fontMenu_font1:	/* FALLTHRU */
2541d522f475Smrg	    case fontMenu_font2:	/* FALLTHRU */
2542d522f475Smrg	    case fontMenu_font3:	/* FALLTHRU */
2543d522f475Smrg	    case fontMenu_font4:	/* FALLTHRU */
2544d522f475Smrg	    case fontMenu_font5:	/* FALLTHRU */
2545d522f475Smrg	    case fontMenu_font6:	/* FALLTHRU */
2546d522f475Smrg		break;
2547d522f475Smrg	    case fontMenu_fontescape:
2548d522f475Smrg#if OPT_WIDE_CHARS
2549d522f475Smrg		maxparams = 5;
2550d522f475Smrg#else
2551d522f475Smrg		maxparams = 3;
2552d522f475Smrg#endif
2553d522f475Smrg		break;
2554d522f475Smrg	    case fontMenu_fontsel:
2555d522f475Smrg		maxparams = 2;
2556d522f475Smrg		break;
2557d522f475Smrg	    default:
2558d522f475Smrg		Bell(XkbBI_MinorError, 0);
2559d522f475Smrg		return;
2560d522f475Smrg	    }
2561d522f475Smrg	    fontnum = result;
2562d522f475Smrg
2563d522f475Smrg	    if (*param_count > maxparams) {	/* see if extra args given */
2564d522f475Smrg		Bell(XkbBI_MinorError, 0);
2565d522f475Smrg		return;
2566d522f475Smrg	    }
2567d522f475Smrg	    switch (*param_count) {	/* assign 'em */
2568d522f475Smrg#if OPT_WIDE_CHARS
2569d522f475Smrg	    case 5:
2570d522f475Smrg		fonts.f_wb = params[4];
2571d522f475Smrg		/* FALLTHRU */
2572d522f475Smrg	    case 4:
2573d522f475Smrg		fonts.f_w = params[3];
2574d522f475Smrg		/* FALLTHRU */
2575d522f475Smrg#endif
2576d522f475Smrg	    case 3:
2577d522f475Smrg		fonts.f_b = params[2];
2578d522f475Smrg		/* FALLTHRU */
2579d522f475Smrg	    case 2:
2580d522f475Smrg		fonts.f_n = params[1];
2581d522f475Smrg		break;
2582d522f475Smrg	    }
2583d522f475Smrg	}
2584d522f475Smrg
2585d522f475Smrg	SetVTFont((XtermWidget) w, fontnum, True, &fonts);
2586d522f475Smrg    }
2587d522f475Smrg}
2588d522f475Smrg
2589d522f475Smrgvoid
2590d522f475SmrgSetVTFont(XtermWidget xw,
2591d522f475Smrg	  int which,
2592d522f475Smrg	  Bool doresize,
2593d522f475Smrg	  const VTFontNames * fonts)
2594d522f475Smrg{
2595d522f475Smrg    TScreen *screen = &xw->screen;
2596d522f475Smrg
2597d522f475Smrg    TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which,
2598d522f475Smrg	   (fonts && fonts->f_n) ? fonts->f_n : "<null>",
2599d522f475Smrg	   (fonts && fonts->f_b) ? fonts->f_b : "<null>"));
2600d522f475Smrg
2601d522f475Smrg    if (IsIcon(screen)) {
2602d522f475Smrg	Bell(XkbBI_MinorError, 0);
2603d522f475Smrg    } else if (which >= 0 && which < NMENUFONTS) {
2604d522f475Smrg	VTFontNames myfonts;
2605d522f475Smrg
2606d522f475Smrg	memset(&myfonts, 0, sizeof(myfonts));
2607d522f475Smrg	if (fonts != 0)
2608d522f475Smrg	    myfonts = *fonts;
2609d522f475Smrg
2610d522f475Smrg	if (which == fontMenu_fontsel) {	/* go get the selection */
2611d522f475Smrg	    FindFontSelection(xw, myfonts.f_n, False);
2612d522f475Smrg	    return;
2613d522f475Smrg	} else {
2614d522f475Smrg	    int oldFont = screen->menu_font_number;
2615d522f475Smrg
2616d522f475Smrg#define USE_CACHED(field, name) \
2617d522f475Smrg	    if (myfonts.field == 0) { \
2618d522f475Smrg		myfonts.field = screen->menu_font_names[which][name]; \
2619d522f475Smrg		TRACE(("set myfonts." #field " from menu_font_names[%d][" #name "] %s\n", \
2620d522f475Smrg		       which, NonNull(myfonts.field))); \
2621d522f475Smrg	    } else { \
2622d522f475Smrg		TRACE(("set myfonts." #field " reused\n")); \
2623d522f475Smrg	    }
2624d522f475Smrg	    USE_CACHED(f_n, fNorm);
2625d522f475Smrg	    USE_CACHED(f_b, fBold);
2626d522f475Smrg#if OPT_WIDE_CHARS
2627d522f475Smrg	    USE_CACHED(f_w, fWide);
2628d522f475Smrg	    USE_CACHED(f_wb, fWBold);
2629d522f475Smrg#endif
2630d522f475Smrg	    if (xtermLoadFont(xw,
2631d522f475Smrg			      &myfonts,
2632d522f475Smrg			      doresize, which)) {
2633d522f475Smrg		return;
2634d522f475Smrg	    } else {
2635d522f475Smrg		xtermLoadFont(xw,
2636d522f475Smrg			      xtermFontName(screen->MenuFontName(oldFont)),
2637d522f475Smrg			      doresize, oldFont);
2638d522f475Smrg	    }
2639d522f475Smrg	}
2640d522f475Smrg    }
2641d522f475Smrg
2642d522f475Smrg    Bell(XkbBI_MinorError, 0);
2643d522f475Smrg    return;
2644d522f475Smrg}
2645