aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/programs/xterm/fontutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'nx-X11/programs/xterm/fontutils.c')
-rw-r--r--nx-X11/programs/xterm/fontutils.c2371
1 files changed, 2371 insertions, 0 deletions
diff --git a/nx-X11/programs/xterm/fontutils.c b/nx-X11/programs/xterm/fontutils.c
new file mode 100644
index 000000000..fb4c6373c
--- /dev/null
+++ b/nx-X11/programs/xterm/fontutils.c
@@ -0,0 +1,2371 @@
+/* $XTermId: fontutils.c,v 1.184 2005/11/03 13:17:27 tom Exp $ */
+
+/*
+ * $XFree86: xc/programs/xterm/fontutils.c,v 1.55 2005/11/03 13:17:27 dickey Exp $
+ */
+
+/************************************************************
+
+Copyright 1998-2004,2005 by Thomas E. Dickey
+
+ All Rights Reserved
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name(s) of the above copyright
+holders shall not be used in advertising or otherwise to promote the
+sale, use or other dealings in this Software without prior written
+authorization.
+
+********************************************************/
+
+/*
+ * A portion of this module (for FontNameProperties) was adapted from EMU 1.3;
+ * it constructs font names with specific properties changed, e.g., for bold
+ * and double-size characters.
+ */
+
+#define RES_OFFSET(field) XtOffsetOf(SubResourceRec, field)
+
+#include <fontutils.h>
+#include <X11/Xmu/Drawing.h>
+
+#include <main.h>
+#include <data.h>
+#include <menu.h>
+#include <xstrings.h>
+#include <xterm.h>
+
+#include <stdio.h>
+#include <ctype.h>
+
+/* from X11/Xlibint.h - not all vendors install this file */
+#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
+ (((cs)->rbearing|(cs)->lbearing| \
+ (cs)->ascent|(cs)->descent) == 0))
+
+#define CI_GET_CHAR_INFO_1D(fs,col,def,cs) \
+{ \
+ cs = def; \
+ if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
+ if (fs->per_char == NULL) { \
+ cs = &fs->min_bounds; \
+ } else { \
+ cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
+ if (CI_NONEXISTCHAR(cs)) cs = def; \
+ } \
+ } \
+}
+
+#define CI_GET_CHAR_INFO_2D(fs,row,col,def,cs) \
+{ \
+ cs = def; \
+ if (row >= fs->min_byte1 && row <= fs->max_byte1 && \
+ col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
+ if (fs->per_char == NULL) { \
+ cs = &fs->min_bounds; \
+ } else { \
+ cs = &fs->per_char[((row - fs->min_byte1) * \
+ (fs->max_char_or_byte2 - \
+ fs->min_char_or_byte2 + 1)) + \
+ (col - fs->min_char_or_byte2)]; \
+ if (CI_NONEXISTCHAR(cs)) cs = def; \
+ } \
+ } \
+}
+
+#define MAX_FONTNAME 200
+
+/*
+ * A structure to hold the relevant properties from a font
+ * we need to make a well formed font name for it.
+ */
+typedef struct {
+ /* registry, foundry, family */
+ char *beginning;
+ /* weight */
+ char *weight;
+ /* slant */
+ char *slant;
+ /* wideness */
+ char *wideness;
+ /* add style */
+ char *add_style;
+ int pixel_size;
+ char *point_size;
+ int res_x;
+ int res_y;
+ char *spacing;
+ int average_width;
+ /* charset registry, charset encoding */
+ char *end;
+} FontNameProperties;
+
+#if OPT_SHIFT_FONTS
+static void lookupOneFontSize(TScreen *, int);
+#endif
+
+/*
+ * Returns the fields from start to stop in a dash- separated string. This
+ * function will modify the source, putting '\0's in the appropiate place and
+ * moving the beginning forward to after the '\0'
+ *
+ * This will NOT work for the last field (but we won't need it).
+ */
+static char *
+n_fields(char **source, int start, int stop)
+{
+ int i;
+ char *str, *str1;
+
+ /*
+ * find the start-1th dash
+ */
+ for (i = start - 1, str = *source; i; i--, str++)
+ if ((str = strchr(str, '-')) == 0)
+ return 0;
+
+ /*
+ * find the stopth dash
+ */
+ for (i = stop - start + 1, str1 = str; i; i--, str1++)
+ if ((str1 = strchr(str1, '-')) == 0)
+ return 0;
+
+ /*
+ * put a \0 at the end of the fields
+ */
+ *(str1 - 1) = '\0';
+
+ /*
+ * move source forward
+ */
+ *source = str1;
+
+ return str;
+}
+
+/*
+ * Gets the font properties from a given font structure. We use the FONT name
+ * to find them out, since that seems easier.
+ *
+ * Returns a pointer to a static FontNameProperties structure
+ * or NULL on error.
+ */
+static FontNameProperties *
+get_font_name_props(Display * dpy, XFontStruct * fs, char *result)
+{
+ static FontNameProperties props;
+ static char *last_name;
+
+ XFontProp *fp;
+ int i;
+ Atom fontatom = XInternAtom(dpy, "FONT", False);
+ char *name;
+ char *str;
+
+ /*
+ * first get the full font name
+ */
+ for (name = 0, i = 0, fp = fs->properties;
+ i < fs->n_properties;
+ i++, fp++)
+ if (fp->name == fontatom)
+ name = XGetAtomName(dpy, fp->card32);
+
+ if (name == 0)
+ return 0;
+
+ /*
+ * XGetAtomName allocates memory - don't leak
+ */
+ if (last_name != 0)
+ XFree(last_name);
+ last_name = name;
+
+ if (result != 0) {
+ if (strlen(name) < MAX_FONTNAME - 1) {
+ strcpy(result, name);
+ } else {
+ TRACE(("fontname too large: %s\n", name));
+ return 0;
+ }
+ }
+
+ /*
+ * Now split it up into parts and put them in
+ * their places. Since we are using parts of
+ * the original string, we must not free the Atom Name
+ */
+
+ /* registry, foundry, family */
+ if ((props.beginning = n_fields(&name, 1, 3)) == 0)
+ return 0;
+
+ /* weight is the next */
+ if ((props.weight = n_fields(&name, 1, 1)) == 0)
+ return 0;
+
+ /* slant */
+ if ((props.slant = n_fields(&name, 1, 1)) == 0)
+ return 0;
+
+ /* width */
+ if ((props.wideness = n_fields(&name, 1, 1)) == 0)
+ return 0;
+
+ /* add style */
+ if ((props.add_style = n_fields(&name, 1, 1)) == 0)
+ return 0;
+
+ /* pixel size */
+ if ((str = n_fields(&name, 1, 1)) == 0)
+ return 0;
+ if ((props.pixel_size = atoi(str)) == 0)
+ return 0;
+
+ /* point size */
+ if ((props.point_size = n_fields(&name, 1, 1)) == 0)
+ return 0;
+
+ /* res_x */
+ if ((str = n_fields(&name, 1, 1)) == 0)
+ return 0;
+ if ((props.res_x = atoi(str)) == 0)
+ return 0;
+
+ /* res_y */
+ if ((str = n_fields(&name, 1, 1)) == 0)
+ return 0;
+ if ((props.res_y = atoi(str)) == 0)
+ return 0;
+
+ /* spacing */
+ if ((props.spacing = n_fields(&name, 1, 1)) == 0)
+ return 0;
+
+ /* average width */
+ if ((str = n_fields(&name, 1, 1)) == 0)
+ return 0;
+ if ((props.average_width = atoi(str)) == 0)
+ return 0;
+
+ /* the rest: charset registry and charset encoding */
+ props.end = name;
+
+ return &props;
+}
+
+#define ALLOCHUNK(n) ((n | 127) + 1)
+
+static void
+alloca_fontname(char **result, unsigned next)
+{
+ unsigned last = (*result != 0) ? strlen(*result) : 0;
+ unsigned have = (*result != 0) ? ALLOCHUNK(last) : 0;
+ unsigned want = last + next + 2;
+
+ if (want >= have) {
+ want = ALLOCHUNK(want);
+ if (last != 0) {
+ *result = TypeRealloc(char, want, *result);
+ } else {
+ if ((*result = TypeMallocN(char, want)) != 0)
+ **result = '\0';
+ }
+ }
+}
+
+static void
+append_fontname_str(char **result, char *value)
+{
+ if (value == 0)
+ value = "*";
+ alloca_fontname(result, strlen(value));
+ if (*result != 0) {
+ if (**result != '\0')
+ strcat(*result, "-");
+ strcat(*result, value);
+ }
+}
+
+static void
+append_fontname_num(char **result, int value)
+{
+ if (value < 0) {
+ append_fontname_str(result, "*");
+ } else {
+ char temp[100];
+ sprintf(temp, "%d", value);
+ append_fontname_str(result, temp);
+ }
+}
+
+/*
+ * Take the given font props and try to make a well formed font name specifying
+ * the same base font and size and everything, but with different weight/width
+ * according to the parameters. The return value is allocated, should be freed
+ * by the caller.
+ */
+static char *
+derive_font_name(FontNameProperties * props,
+ char *use_weight,
+ int use_average_width,
+ char *use_encoding)
+{
+ char *result = 0;
+
+ append_fontname_str(&result, props->beginning);
+ append_fontname_str(&result, use_weight);
+ append_fontname_str(&result, props->slant);
+ append_fontname_str(&result, 0);
+ append_fontname_str(&result, 0);
+ append_fontname_num(&result, props->pixel_size);
+ append_fontname_str(&result, props->point_size);
+ append_fontname_num(&result, props->res_x);
+ append_fontname_num(&result, props->res_y);
+ append_fontname_str(&result, props->spacing);
+ append_fontname_num(&result, use_average_width);
+ append_fontname_str(&result, use_encoding);
+
+ return result;
+}
+
+static char *
+bold_font_name(FontNameProperties * props, int use_average_width)
+{
+ return derive_font_name(props, "bold", use_average_width, props->end);
+}
+
+#if OPT_WIDE_CHARS
+#define derive_wide_font(props, weight) \
+ derive_font_name(props, weight, props->average_width * 2, "ISO10646-1")
+
+static char *
+wide_font_name(FontNameProperties * props)
+{
+ return derive_wide_font(props, "medium");
+}
+
+static char *
+widebold_font_name(FontNameProperties * props)
+{
+ return derive_wide_font(props, "bold");
+}
+#endif /* OPT_WIDE_CHARS */
+
+#if OPT_DEC_CHRSET
+/*
+ * Take the given font props and try to make a well formed font name specifying
+ * the same base font but changed depending on the given attributes and chrset.
+ *
+ * For double width fonts, we just double the X-resolution, for double height
+ * fonts we double the pixel-size and Y-resolution
+ */
+char *
+xtermSpecialFont(TScreen * screen, unsigned atts, unsigned chrset)
+{
+#if OPT_TRACE
+ static char old_spacing[80];
+ static FontNameProperties old_props;
+#endif
+ FontNameProperties *props;
+ char *result = 0;
+ char *weight;
+ int pixel_size;
+ int res_x;
+ int res_y;
+
+ props = get_font_name_props(screen->display, screen->fnt_norm, (char *) 0);
+ if (props == 0)
+ return result;
+
+ pixel_size = props->pixel_size;
+ res_x = props->res_x;
+ res_y = props->res_y;
+ if (atts & BOLD)
+ weight = "bold";
+ else
+ weight = props->weight;
+
+ if (CSET_DOUBLE(chrset))
+ res_x *= 2;
+
+ if (chrset == CSET_DHL_TOP
+ || chrset == CSET_DHL_BOT) {
+ res_y *= 2;
+ pixel_size *= 2;
+ }
+#if OPT_TRACE
+ if (old_props.res_x != res_x
+ || old_props.res_x != res_y
+ || old_props.pixel_size != pixel_size
+ || strcmp(old_props.spacing, props->spacing)) {
+ TRACE(("xtermSpecialFont(atts = %#x, chrset = %#x)\n", atts, chrset));
+ TRACE(("res_x = %d\n", res_x));
+ TRACE(("res_y = %d\n", res_y));
+ TRACE(("point_size = %s\n", props->point_size));
+ TRACE(("pixel_size = %d\n", pixel_size));
+ TRACE(("spacing = %s\n", props->spacing));
+ old_props.res_x = res_x;
+ old_props.res_x = res_y;
+ old_props.pixel_size = pixel_size;
+ old_props.spacing = strcpy(old_spacing, props->spacing);
+ }
+#endif
+
+ append_fontname_str(&result, props->beginning);
+ append_fontname_str(&result, weight);
+ append_fontname_str(&result, props->slant);
+ append_fontname_str(&result, props->wideness);
+ append_fontname_str(&result, props->add_style);
+ append_fontname_num(&result, pixel_size);
+ append_fontname_str(&result, props->point_size);
+ append_fontname_num(&result, (atts & NORESOLUTION) ? -1 : res_x);
+ append_fontname_num(&result, (atts & NORESOLUTION) ? -1 : res_y);
+ append_fontname_str(&result, props->spacing);
+ append_fontname_str(&result, 0);
+ append_fontname_str(&result, props->end);
+
+ return result;
+}
+#endif /* OPT_DEC_CHRSET */
+
+/*
+ * Case-independent comparison for font-names, including wildcards.
+ * XLFD allows '?' as a wildcard, but we do not handle that (no one seems
+ * to use it).
+ */
+static Bool
+same_font_name(char *pattern, char *match)
+{
+ while (*pattern && *match) {
+ if (*pattern == *match) {
+ pattern++;
+ match++;
+ } else if (*pattern == '*' || *match == '*') {
+ if (same_font_name(pattern + 1, match)) {
+ return True;
+ } else if (same_font_name(pattern, match + 1)) {
+ return True;
+ } else {
+ return False;
+ }
+ } else {
+ int p = char2lower(*pattern++);
+ int m = char2lower(*match++);
+ if (p != m)
+ return False;
+ }
+ }
+ return (*pattern == *match); /* both should be NUL */
+}
+
+/*
+ * Double-check the fontname that we asked for versus what the font server
+ * actually gave us. The larger fixed fonts do not always have a matching bold
+ * font, and the font server may try to scale another font or otherwise
+ * substitute a mismatched font.
+ *
+ * If we cannot get what we requested, we will fallback to the original
+ * behavior, which simulates bold by overstriking each character at one pixel
+ * offset.
+ */
+static int
+got_bold_font(Display * dpy, XFontStruct * fs, char *requested)
+{
+ char actual[MAX_FONTNAME];
+ int got;
+
+ if (get_font_name_props(dpy, fs, actual) == 0)
+ got = 0;
+ else
+ got = same_font_name(requested, actual);
+ return got;
+}
+
+/*
+ * If the font server tries to adjust another font, it may not adjust it
+ * properly. Check that the bounding boxes are compatible. Otherwise we'll
+ * leave trash on the display when we mix normal and bold fonts.
+ */
+static int
+same_font_size(XtermWidget xw, XFontStruct * nfs, XFontStruct * bfs)
+{
+ TRACE(("same_font_size height %d/%d, min %d/%d max %d/%d\n",
+ nfs->ascent + nfs->descent,
+ bfs->ascent + bfs->descent,
+ nfs->min_bounds.width, bfs->min_bounds.width,
+ nfs->max_bounds.width, bfs->max_bounds.width));
+ return xw->screen.free_bold_box
+ || ((nfs->ascent + nfs->descent) == (bfs->ascent + bfs->descent)
+ && (nfs->min_bounds.width == bfs->min_bounds.width
+ || nfs->min_bounds.width == bfs->min_bounds.width + 1)
+ && (nfs->max_bounds.width == bfs->max_bounds.width
+ || nfs->max_bounds.width == bfs->max_bounds.width + 1));
+}
+
+/*
+ * Check if the font looks like it has fixed width
+ */
+static int
+is_fixed_font(XFontStruct * fs)
+{
+ if (fs)
+ return (fs->min_bounds.width == fs->max_bounds.width);
+ return 1;
+}
+
+/*
+ * Check if the font looks like a double width font (i.e. contains
+ * characters of width X and 2X
+ */
+#if OPT_WIDE_CHARS
+static int
+is_double_width_font(XFontStruct * fs)
+{
+ return ((2 * fs->min_bounds.width) == fs->max_bounds.width);
+}
+#else
+#define is_double_width_font(fs) 0
+#endif
+
+#if OPT_WIDE_CHARS && OPT_RENDERFONT && defined(HAVE_TYPE_FCCHAR32)
+#define HALF_WIDTH_TEST_STRING "1234567890"
+
+/* '1234567890' in Chinese characters in UTF-8 */
+#define FULL_WIDTH_TEST_STRING "\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89" \
+ "\xe5\x9b\x9b\xe4\xba\x94" \
+ "\xef\xa7\x91\xe4\xb8\x83\xe5\x85\xab" \
+ "\xe4\xb9\x9d\xef\xa6\xb2"
+
+/* '1234567890' in Korean script in UTF-8 */
+#define FULL_WIDTH_TEST_STRING2 "\xec\x9d\xbc\xec\x9d\xb4\xec\x82\xbc" \
+ "\xec\x82\xac\xec\x98\xa4" \
+ "\xec\x9c\xa1\xec\xb9\xa0\xed\x8c\x94" \
+ "\xea\xb5\xac\xec\x98\x81"
+
+#define HALF_WIDTH_CHAR1 0x0031 /* 'l' */
+#define HALF_WIDTH_CHAR2 0x0057 /* 'W' */
+#define FULL_WIDTH_CHAR1 0x4E00 /* CJK Ideograph 'number one' */
+#define FULL_WIDTH_CHAR2 0xAC00 /* Korean script syllable 'Ka' */
+
+static int
+is_double_width_font_xft(Display * dpy, XftFont * font)
+{
+ XGlyphInfo gi1, gi2;
+ FcChar32 c1 = HALF_WIDTH_CHAR1, c2 = HALF_WIDTH_CHAR2;
+ char *fwstr = FULL_WIDTH_TEST_STRING;
+ char *hwstr = HALF_WIDTH_TEST_STRING;
+
+ /* Some Korean fonts don't have Chinese characters at all. */
+ if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR1)) {
+ if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR2))
+ return 0; /* Not a CJK font */
+ else /* a Korean font without CJK Ideographs */
+ fwstr = FULL_WIDTH_TEST_STRING2;
+ }
+
+ XftTextExtents32(dpy, font, &c1, 1, &gi1);
+ XftTextExtents32(dpy, font, &c2, 1, &gi2);
+ if (gi1.xOff != gi2.xOff) /* Not a fixed-width font */
+ return 0;
+
+ XftTextExtentsUtf8(dpy, font, (FcChar8 *) hwstr, (int) strlen(hwstr), &gi1);
+ XftTextExtentsUtf8(dpy, font, (FcChar8 *) fwstr, (int) strlen(fwstr), &gi2);
+
+ /*
+ * fontconfig and Xft prior to 2.2(?) set the width of half-width
+ * characters identical to that of full-width character in CJK double-width
+ * (bi-width / monospace) font even though the former is half as wide as
+ * the latter. This was fixed sometime before the release of fontconfig
+ * 2.2 in early 2003. See
+ * http://bugzilla.mozilla.org/show_bug.cgi?id=196312
+ * In the meantime, we have to check both possibilities.
+ */
+ return ((2 * gi1.xOff == gi2.xOff) || (gi1.xOff == gi2.xOff));
+}
+#else
+#define is_double_width_font_xft(dpy, xftfont) 0
+#endif
+
+#define EmptyFont(fs) (fs != 0 \
+ && ((fs)->ascent + (fs)->descent == 0 \
+ || (fs)->max_bounds.width == 0))
+
+#define FontSize(fs) (((fs)->ascent + (fs)->descent) \
+ * (fs)->max_bounds.width)
+
+const VTFontNames *
+xtermFontName(char *normal)
+{
+ static VTFontNames data;
+ memset(&data, 0, sizeof(data));
+ data.f_n = normal;
+ return &data;
+}
+
+static void
+cache_menu_font_name(TScreen * screen, int fontnum, int which, const char *name)
+{
+ if (name != 0) {
+ char *last = screen->menu_font_names[fontnum][which];
+ if (last != 0) {
+ if (strcmp(last, name)) {
+ free(last);
+ TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name));
+ screen->menu_font_names[fontnum][which] = x_strdup(name);
+ }
+ } else {
+ TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name));
+ screen->menu_font_names[fontnum][which] = x_strdup(name);
+ }
+ }
+}
+
+int
+xtermLoadFont(XtermWidget xw,
+ const VTFontNames * fonts,
+ Bool doresize,
+ int fontnum)
+{
+ TScreen *screen = &(xw->screen);
+
+ VTFontNames myfonts;
+ /* FIXME: use XFreeFontInfo */
+ FontNameProperties *fp;
+ XFontStruct *nfs = NULL;
+ XFontStruct *bfs = NULL;
+#if OPT_WIDE_CHARS
+ XFontStruct *wfs = NULL;
+ XFontStruct *wbfs = NULL;
+#endif
+ XGCValues xgcv;
+ unsigned long mask;
+ GC new_normalGC = NULL;
+ GC new_normalboldGC = NULL;
+ GC new_reverseGC = NULL;
+ GC new_reverseboldGC = NULL;
+ Pixel new_normal;
+ Pixel new_revers;
+ char *tmpname = NULL;
+ char normal[MAX_FONTNAME];
+ Bool proportional = False;
+
+ memset(&myfonts, 0, sizeof(myfonts));
+ if (fonts != 0)
+ myfonts = *fonts;
+ if (myfonts.f_n == 0)
+ return 0;
+
+ if (fontnum == fontMenu_fontescape
+ && myfonts.f_n != screen->MenuFontName(fontnum)) {
+ if ((tmpname = x_strdup(myfonts.f_n)) == 0)
+ return 0;
+ }
+
+ TRACE(("xtermLoadFont #%d normal %s\n", fontnum, NonNull(myfonts.f_n)));
+ TRACE(("xtermLoadFont #%d bold %s\n", fontnum, NonNull(myfonts.f_b)));
+#if OPT_WIDE_CHARS
+ TRACE(("xtermLoadFont #%d wide %s\n", fontnum, NonNull(myfonts.f_w)));
+ TRACE(("xtermLoadFont #%d w/bold %s\n", fontnum, NonNull(myfonts.f_wb)));
+#endif
+
+ if (!(nfs = XLoadQueryFont(screen->display, myfonts.f_n)))
+ goto bad;
+ if (EmptyFont(nfs))
+ goto bad; /* can't use a 0-sized font */
+
+ strcpy(normal, myfonts.f_n);
+ if (myfonts.f_b == 0) {
+ fp = get_font_name_props(screen->display, nfs, normal);
+ if (fp != 0) {
+ myfonts.f_b = bold_font_name(fp, fp->average_width);
+ if ((bfs = XLoadQueryFont(screen->display, myfonts.f_b)) == 0) {
+ myfonts.f_b = bold_font_name(fp, -1);
+ bfs = XLoadQueryFont(screen->display, myfonts.f_b);
+ }
+ TRACE(("...derived bold %s\n", myfonts.f_b));
+ }
+ if (fp == 0 || bfs == 0) {
+ bfs = nfs;
+ TRACE(("...cannot load a matching bold font\n"));
+ } else if (same_font_size(xw, nfs, bfs)
+ && got_bold_font(screen->display, bfs, myfonts.f_b)) {
+ TRACE(("...got a matching bold font\n"));
+ cache_menu_font_name(screen, fontnum, fBold, myfonts.f_b);
+ } else {
+ XFreeFont(screen->display, bfs);
+ bfs = nfs;
+ TRACE(("...did not get a matching bold font\n"));
+ }
+ } else if ((bfs = XLoadQueryFont(screen->display, myfonts.f_b)) == 0) {
+ bfs = nfs;
+ TRACE(("...cannot load bold font %s\n", myfonts.f_b));
+ } else {
+ cache_menu_font_name(screen, fontnum, fBold, myfonts.f_b);
+ }
+
+ /*
+ * If there is no widefont specified, fake it by doubling AVERAGE_WIDTH
+ * of normal fonts XLFD, and asking for it. This plucks out 18x18ja
+ * and 12x13ja as the corresponding fonts for 9x18 and 6x13.
+ */
+ if_OPT_WIDE_CHARS(screen, {
+ char bold[MAX_FONTNAME];
+
+ if (myfonts.f_w != 0) {
+ cache_menu_font_name(screen, fontnum, fWide, myfonts.f_w);
+ } else if (!is_double_width_font(nfs)) {
+ fp = get_font_name_props(screen->display, nfs, normal);
+ if (fp != 0) {
+ myfonts.f_w = wide_font_name(fp);
+ TRACE(("...derived wide %s\n", myfonts.f_w));
+ cache_menu_font_name(screen, fontnum, fWide, myfonts.f_w);
+ }
+ }
+
+ if (myfonts.f_w) {
+ wfs = XLoadQueryFont(screen->display, myfonts.f_w);
+ } else {
+ wfs = nfs;
+ }
+
+ if (myfonts.f_wb != 0) {
+ cache_menu_font_name(screen, fontnum, fWBold, myfonts.f_wb);
+ } else if (!is_double_width_font(bfs)) {
+ fp = get_font_name_props(screen->display, bfs, bold);
+ if (fp != 0) {
+ myfonts.f_wb = widebold_font_name(fp);
+ TRACE(("...derived wide/bold %s\n", myfonts.f_wb));
+ cache_menu_font_name(screen, fontnum, fWBold, myfonts.f_wb);
+ }
+ }
+
+ if (myfonts.f_wb) {
+ wbfs = XLoadQueryFont(screen->display, myfonts.f_wb);
+ } else if (is_double_width_font(bfs)) {
+ wbfs = bfs;
+ } else {
+ wbfs = wfs;
+ TRACE(("...cannot load wide bold font %s\n", myfonts.f_wb));
+ }
+
+ if (EmptyFont(wbfs))
+ goto bad; /* can't use a 0-sized font */
+ });
+
+ /*
+ * Most of the time this call to load the font will succeed, even if
+ * there is no wide font : the X server doubles the width of the
+ * normal font, or similar.
+ *
+ * But if it did fail for some reason, then nevermind.
+ */
+ if (EmptyFont(bfs))
+ goto bad; /* can't use a 0-sized font */
+
+ if (!same_font_size(xw, nfs, bfs)
+ && (is_fixed_font(nfs) && is_fixed_font(bfs))) {
+ TRACE(("...ignoring mismatched normal/bold fonts\n"));
+ XFreeFont(screen->display, bfs);
+ bfs = nfs;
+ }
+
+ if_OPT_WIDE_CHARS(screen, {
+ if (wfs != 0
+ && wbfs != 0
+ && !same_font_size(xw, wfs, wbfs)
+ && (is_fixed_font(wfs) && is_fixed_font(wbfs))) {
+ TRACE(("...ignoring mismatched normal/bold wide fonts\n"));
+ XFreeFont(screen->display, wbfs);
+ wbfs = wfs;
+ }
+ });
+
+ /*
+ * Normal/bold fonts should be the same width. Also, the min/max
+ * values should be the same.
+ */
+ if (!is_fixed_font(nfs)
+ || !is_fixed_font(bfs)
+ || nfs->max_bounds.width != bfs->max_bounds.width) {
+ TRACE(("Proportional font! normal %d/%d, bold %d/%d\n",
+ nfs->min_bounds.width,
+ nfs->max_bounds.width,
+ bfs->min_bounds.width,
+ bfs->max_bounds.width));
+ proportional = True;
+ }
+
+ if_OPT_WIDE_CHARS(screen, {
+ if (wfs != 0
+ && wbfs != 0
+ && (!is_fixed_font(wfs)
+ || !is_fixed_font(wbfs)
+ || wfs->max_bounds.width != wbfs->max_bounds.width)) {
+ TRACE(("Proportional font! wide %d/%d, wide bold %d/%d\n",
+ wfs->min_bounds.width,
+ wfs->max_bounds.width,
+ wbfs->min_bounds.width,
+ wbfs->max_bounds.width));
+ proportional = True;
+ }
+ });
+
+ /* TODO : enforce that the width of the wide font is 2* the width
+ of the narrow font */
+
+ mask = (GCFont | GCForeground | GCBackground | GCGraphicsExposures |
+ GCFunction);
+
+ new_normal = getXtermForeground(xw->flags, xw->cur_foreground);
+ new_revers = getXtermBackground(xw->flags, xw->cur_background);
+
+ xgcv.font = nfs->fid;
+ xgcv.foreground = new_normal;
+ xgcv.background = new_revers;
+ xgcv.graphics_exposures = True; /* default */
+ xgcv.function = GXcopy;
+
+ new_normalGC = XtGetGC((Widget) xw, mask, &xgcv);
+ if (!new_normalGC)
+ goto bad;
+
+ if (nfs == bfs) { /* there is no bold font */
+ new_normalboldGC = new_normalGC;
+ } else {
+ xgcv.font = bfs->fid;
+ new_normalboldGC = XtGetGC((Widget) xw, mask, &xgcv);
+ if (!new_normalboldGC)
+ goto bad;
+ }
+
+ xgcv.font = nfs->fid;
+ xgcv.foreground = new_revers;
+ xgcv.background = new_normal;
+ new_reverseGC = XtGetGC((Widget) xw, mask, &xgcv);
+ if (!new_reverseGC)
+ goto bad;
+
+ if (nfs == bfs) { /* there is no bold font */
+ new_reverseboldGC = new_reverseGC;
+ } else {
+ xgcv.font = bfs->fid;
+ new_reverseboldGC = XtGetGC((Widget) xw, mask, &xgcv);
+ if (!new_reverseboldGC)
+ goto bad;
+ }
+
+ if (NormalGC(screen) != NormalBoldGC(screen))
+ XtReleaseGC((Widget) xw, NormalBoldGC(screen));
+ XtReleaseGC((Widget) xw, NormalGC(screen));
+
+ if (ReverseGC(screen) != ReverseBoldGC(screen))
+ XtReleaseGC((Widget) xw, ReverseBoldGC(screen));
+ XtReleaseGC((Widget) xw, ReverseGC(screen));
+
+ NormalGC(screen) = new_normalGC;
+ NormalBoldGC(screen) = new_normalboldGC;
+ ReverseGC(screen) = new_reverseGC;
+ ReverseBoldGC(screen) = new_reverseboldGC;
+
+ /*
+ * If we're switching fonts, free the old ones. Otherwise we'll leak
+ * the memory that is associated with the old fonts. The
+ * XLoadQueryFont call allocates a new XFontStruct.
+ */
+ if (screen->fnt_bold != 0
+ && screen->fnt_bold != screen->fnt_norm)
+ XFreeFont(screen->display, screen->fnt_bold);
+ if (screen->fnt_norm != 0)
+ XFreeFont(screen->display, screen->fnt_norm);
+
+ screen->fnt_norm = nfs;
+ screen->fnt_bold = bfs;
+#if OPT_WIDE_CHARS
+ screen->fnt_dwd = wfs;
+ if (wbfs == NULL)
+ wbfs = wfs;
+ screen->fnt_dwdb = wbfs;
+#endif
+ screen->fnt_prop = proportional;
+ screen->fnt_boxes = True;
+
+#if OPT_BOX_CHARS
+ /*
+ * Xterm uses character positions 1-31 of a font for the line-drawing
+ * characters. Check that they are all present. The null character
+ * (0) is special, and is not used.
+ */
+#if OPT_RENDERFONT
+ if (UsingRenderFont(xw)) {
+ /*
+ * FIXME: we shouldn't even be here if we're using Xft.
+ */
+ screen->fnt_boxes = False;
+ TRACE(("assume Xft missing line-drawing chars\n"));
+ } else
+#endif
+ {
+ unsigned ch;
+
+ for (ch = 1; ch < 32; ch++) {
+ unsigned n = ch;
+#if OPT_WIDE_CHARS
+ if (screen->utf8_mode || screen->unicode_font) {
+ n = dec2ucs(ch);
+ if (n == UCS_REPL)
+ continue;
+ }
+#endif
+ if (xtermMissingChar(xw, n, nfs)) {
+ TRACE(("missing normal char #%d\n", n));
+ screen->fnt_boxes = False;
+ break;
+ }
+ if (xtermMissingChar(xw, n, bfs)) {
+ TRACE(("missing bold char #%d\n", n));
+ screen->fnt_boxes = False;
+ break;
+ }
+ }
+ }
+ TRACE(("Will %suse internal line-drawing characters\n",
+ screen->fnt_boxes ? "not " : ""));
+#endif
+
+ screen->enbolden = screen->bold_mode
+ && ((nfs == bfs) || same_font_name(normal, myfonts.f_b));
+ TRACE(("Will %suse 1-pixel offset/overstrike to simulate bold\n",
+ screen->enbolden ? "" : "not "));
+
+ set_menu_font(False);
+ screen->menu_font_number = fontnum;
+ set_menu_font(True);
+ if (tmpname) { /* if setting escape or sel */
+ if (screen->MenuFontName(fontnum))
+ free(screen->MenuFontName(fontnum));
+ screen->MenuFontName(fontnum) = tmpname;
+ if (fontnum == fontMenu_fontescape) {
+ set_sensitivity(xw->screen.fontMenu,
+ fontMenuEntries[fontMenu_fontescape].widget,
+ True);
+ }
+#if OPT_SHIFT_FONTS
+ screen->menu_font_sizes[fontnum] = FontSize(nfs);
+#endif
+ }
+ set_cursor_gcs(screen);
+ xtermUpdateFontInfo(xw, doresize);
+ return 1;
+
+ bad:
+ if (tmpname)
+ free(tmpname);
+ if (new_normalGC)
+ XtReleaseGC((Widget) xw, new_normalGC);
+ if (new_normalboldGC && new_normalGC != new_normalboldGC)
+ XtReleaseGC((Widget) xw, new_normalboldGC);
+ if (new_reverseGC)
+ XtReleaseGC((Widget) xw, new_reverseGC);
+ if (new_reverseboldGC && new_reverseGC != new_reverseboldGC)
+ XtReleaseGC((Widget) xw, new_reverseboldGC);
+ if (nfs)
+ XFreeFont(screen->display, nfs);
+ if (bfs && nfs != bfs)
+ XFreeFont(screen->display, bfs);
+#if OPT_WIDE_CHARS
+ if (wfs)
+ XFreeFont(screen->display, wfs);
+ if (wbfs && wbfs != wfs)
+ XFreeFont(screen->display, wbfs);
+#endif
+ return 0;
+}
+
+#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
+/*
+ * Collect font-names that we can modify with the load-vt-fonts() action.
+ */
+typedef struct {
+ VTFontNames default_font;
+ char *menu_font_names[fontMenu_lastBuiltin + 1][fMAX];
+} SubResourceRec;
+
+#define MERGE_SUBFONT(src,dst,name) \
+ if (dst.name == 0) { \
+ TRACE(("MERGE_SUBFONT " #dst "." #name " merge %s\n", NonNull(src.name))); \
+ dst.name = src.name; \
+ } else { \
+ TRACE(("MERGE_SUBFONT " #dst "." #name " found %s\n", NonNull(dst.name))); \
+ }
+
+#define COPY_MENU_FONTS(src,dst) \
+ TRACE(("COPY_MENU_FONTS " #src " to " #dst "\n")); \
+ for (n = fontMenu_fontdefault; n <= fontMenu_lastBuiltin; ++n) { \
+ for (m = 0; m < fMAX; ++m) { \
+ dst.menu_font_names[n][m] = src.menu_font_names[n][m]; \
+ } \
+ }
+
+/*
+ * Load the "VT" font names from the given subresource name/class. These
+ * correspond to the VT100 resources.
+ */
+static Bool
+xtermLoadVTFonts(XtermWidget w, char *myName, char *myClass)
+{
+ static Bool initialized = False;
+ static SubResourceRec original, referenceRec, subresourceRec;
+
+ /*
+ * These are duplicates of the VT100 font resources, but with a special
+ * application/classname passed in to distinguish them.
+ */
+ static XtResource font_resources[] =
+ {
+ Sres(XtNfont, XtCFont, default_font.f_n, DEFFONT),
+ Sres(XtNboldFont, XtCBoldFont, default_font.f_b, DEFBOLDFONT),
+#if OPT_WIDE_CHARS
+ Sres(XtNwideFont, XtCWideFont, default_font.f_w, DEFWIDEFONT),
+ Sres(XtNwideBoldFont, XtCWideBoldFont, default_font.f_wb, DEFWIDEBOLDFONT),
+#endif
+ Sres(XtNfont1, XtCFont1, MenuFontName(fontMenu_font1), NULL),
+ Sres(XtNfont2, XtCFont2, MenuFontName(fontMenu_font2), NULL),
+ Sres(XtNfont3, XtCFont3, MenuFontName(fontMenu_font3), NULL),
+ Sres(XtNfont4, XtCFont4, MenuFontName(fontMenu_font4), NULL),
+ Sres(XtNfont5, XtCFont5, MenuFontName(fontMenu_font5), NULL),
+ Sres(XtNfont6, XtCFont6, MenuFontName(fontMenu_font6), NULL),
+ };
+ Cardinal n, m;
+ Bool status = True;
+
+ if (!initialized) {
+
+ initialized = True;
+ TRACE(("xtermLoadVTFonts saving original\n"));
+ original.default_font = w->misc.default_font;
+ COPY_MENU_FONTS(w->screen, original);
+ }
+
+ if (myName == 0 || *myName == 0) {
+ TRACE(("xtermLoadVTFonts restoring original\n"));
+ w->misc.default_font = original.default_font;
+ COPY_MENU_FONTS(original, w->screen);
+ for (n = 0; n < XtNumber(original.menu_font_names); ++n)
+ w->screen.MenuFontName(n) = original.MenuFontName(n);
+ } else {
+ TRACE(("xtermLoadVTFonts(%s, %s)\n", myName, myClass));
+
+ memset(&subresourceRec, 0, sizeof(subresourceRec));
+ XtGetSubresources((Widget) w, (XtPointer) &subresourceRec,
+ myName, myClass,
+ font_resources,
+ (Cardinal) XtNumber(font_resources),
+ NULL, (Cardinal) 0);
+
+ if (memcmp(&referenceRec, &subresourceRec, sizeof(referenceRec))) {
+
+ /*
+ * If a particular resource value was not found, use the original.
+ */
+ MERGE_SUBFONT(w->misc, subresourceRec, default_font.f_n);
+ MERGE_SUBFONT(w->misc, subresourceRec, default_font.f_b);
+#if OPT_WIDE_CHARS
+ MERGE_SUBFONT(w->misc, subresourceRec, default_font.f_w);
+ MERGE_SUBFONT(w->misc, subresourceRec, default_font.f_wb);
+#endif
+ for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n)
+ MERGE_SUBFONT(w->screen, subresourceRec, MenuFontName(n));
+
+ /*
+ * Finally, copy the subresource data to the widget.
+ */
+ w->misc.default_font = subresourceRec.default_font;
+ COPY_MENU_FONTS(subresourceRec, w->screen);
+ w->screen.MenuFontName(fontMenu_fontdefault) = w->misc.default_font.f_n;
+ } else {
+ TRACE(("...no resources found\n"));
+ status = False;
+ }
+ }
+ return status;
+}
+
+#if OPT_WIDE_CHARS
+static Bool
+isWideFont(XFontStruct * fp, char *tag, Bool nullOk)
+{
+ Bool result = False;
+
+ (void) tag;
+ if (fp != 0) {
+ unsigned count = 0;
+ if (fp->min_byte1 == 0 && fp->max_byte1 == 0) {
+ count = fp->max_char_or_byte2 - fp->min_char_or_byte2;
+ } else if (fp->min_char_or_byte2 < 256
+ && fp->max_char_or_byte2 < 256) {
+ unsigned first = (fp->min_byte1 << 8) + fp->min_char_or_byte2;
+ unsigned last = (fp->max_byte1 << 8) + fp->max_char_or_byte2;
+ count = last + 1 - first;
+ }
+ TRACE(("isWideFont(%s) found %d cells\n", tag, count));
+ result = (count > 256) ? True : False;
+ } else {
+ result = nullOk;
+ }
+ return result;
+}
+
+static Bool
+currentFontsAreWide(XtermWidget w, Bool nullOk)
+{
+ Bool result = True;
+ TScreen *screen = &(w->screen);
+
+ result = (isWideFont(screen->fnt_norm, "normal", nullOk)
+ && isWideFont(screen->fnt_bold, "bold", nullOk)
+ && isWideFont(screen->fnt_dwd, "wide", nullOk)
+ && isWideFont(screen->fnt_dwdb, "wide-bold", nullOk));
+
+ TRACE(("currentFontsAreWide returns %d\n", result));
+ return result;
+}
+
+/*
+ * If the current fonts are not wide, load the UTF8 fonts.
+ *
+ * Called during initialization (for wide-character mode), the fonts have not
+ * been setup, so we pass nullOk=True to currentFontsAreWide().
+ *
+ * Called after initialization, e.g., in response to the UTF-8 menu entry
+ * (starting from narrow character mode), it checks if the fonts are not wide.
+ */
+Bool
+xtermLoadWideFonts(XtermWidget w, Bool nullOk)
+{
+ Bool result = currentFontsAreWide(w, nullOk);
+
+ /* FIXME: add a test for wide-font */
+ if (!result) {
+ result = xtermLoadVTFonts(w, "utf8Fonts", "Utf8Fonts");
+ }
+ TRACE(("xtermLoadWideFonts:%d\n", result));
+ return result;
+}
+#endif /* OPT_WIDE_CHARS */
+
+/*
+ * Restore the default fonts, i.e., if we had switched to wide-fonts.
+ */
+Bool
+xtermLoadDefaultFonts(XtermWidget w)
+{
+ Bool result;
+ result = xtermLoadVTFonts(w, NULL, NULL);
+ TRACE(("xtermLoadDefaultFonts:%d\n", result));
+ return result;
+}
+#endif /* OPT_LOAD_VTFONTS || OPT_WIDE_CHARS */
+
+#if OPT_LOAD_VTFONTS
+void
+HandleLoadVTFonts(Widget w GCC_UNUSED,
+ XEvent * event GCC_UNUSED,
+ String * params GCC_UNUSED,
+ Cardinal *param_count GCC_UNUSED)
+{
+ static char empty[] = ""; /* appease strict compilers */
+
+ char buf[80];
+ char *myName = (*param_count > 0) ? params[0] : empty;
+ char *convert = (*param_count > 1) ? params[1] : myName;
+ char *myClass = (char *) MyStackAlloc(strlen(convert), buf);
+ int n;
+
+ TRACE(("HandleLoadVTFonts(%d)\n", *param_count));
+ strcpy(myClass, convert);
+ if (*param_count == 1
+ && islower(CharOf(myClass[0])))
+ myClass[0] = toupper(CharOf(myClass[0]));
+
+ if (xtermLoadVTFonts(term, myName, myClass)) {
+ /*
+ * When switching fonts, try to preserve the font-menu selection, since
+ * it is less surprising to do that (if the font-switching can be
+ * undone) than to switch to "Default".
+ */
+ int font_number = term->screen.menu_font_number;
+ if (font_number > fontMenu_lastBuiltin)
+ font_number = fontMenu_lastBuiltin;
+ for (n = 0; n < NMENUFONTS; ++n)
+ term->screen.menu_font_sizes[n] = 0;
+ SetVTFont(term, font_number, True,
+ ((font_number == fontMenu_fontdefault)
+ ? &(term->misc.default_font)
+ : NULL));
+ }
+
+ MyStackFree(myClass, buf);
+}
+#endif /* OPT_LOAD_VTFONTS */
+
+/*
+ * Set the limits for the box that outlines the cursor.
+ */
+void
+xtermSetCursorBox(TScreen * screen)
+{
+ static XPoint VTbox[NBOX];
+ XPoint *vp;
+
+ vp = &VTbox[1];
+ (vp++)->x = FontWidth(screen) - 1;
+ (vp++)->y = FontHeight(screen) - 1;
+ (vp++)->x = -(FontWidth(screen) - 1);
+ vp->y = -(FontHeight(screen) - 1);
+ screen->box = VTbox;
+}
+
+#define CACHE_XFT(dst,src) if (src != 0) {\
+ dst[fontnum] = src;\
+ TRACE(("%s[%d] = %d (%d,%d) by %d\n",\
+ #dst,\
+ fontnum,\
+ src->height,\
+ src->ascent,\
+ src->descent,\
+ src->max_advance_width));\
+ }
+
+#if OPT_RENDERFONT
+static XftFont *
+xtermOpenXft(Display * dpy, XftPattern * pat, const char *tag GCC_UNUSED)
+{
+ XftPattern *match;
+ XftResult status;
+ XftFont *result = 0;
+
+ if (pat != 0) {
+ match = XftFontMatch(dpy, DefaultScreen(dpy), pat, &status);
+ result = XftFontOpenPattern(dpy, match);
+ if ((result == 0) && match) {
+ TRACE(("...did not match %s font\n", tag));
+ XftPatternDestroy(match);
+ } else {
+ TRACE(("...matched %s font\n", tag));
+ }
+ }
+ return result;
+}
+#endif
+
+/*
+ * Compute useful values for the font/window sizes
+ */
+void
+xtermComputeFontInfo(XtermWidget xw,
+ struct _vtwin *win,
+ XFontStruct * font,
+ int sbwidth)
+{
+ TScreen *screen = &(xw->screen);
+
+ int i, j, width, height;
+
+#if OPT_RENDERFONT
+ /*
+ * xterm contains a lot of references to fonts, assuming they are fixed
+ * size. This chunk of code overrides the actual font-selection (see
+ * drawXtermText()), if the user has selected render-font. All of the
+ * font-loading for fixed-fonts still goes on whether or not this chunk
+ * overrides it.
+ */
+ if (xw->misc.render_font && !IsIconWin(screen, win)) {
+ Display *dpy = screen->display;
+ int fontnum = screen->menu_font_number;
+ XftFont *norm = screen->renderFontNorm[fontnum];
+ XftFont *bold = screen->renderFontBold[fontnum];
+ XftFont *ital = screen->renderFontItal[fontnum];
+#if OPT_RENDERWIDE
+ XftFont *wnorm = screen->renderWideNorm[fontnum];
+ XftFont *wbold = screen->renderWideBold[fontnum];
+ XftFont *wital = screen->renderWideItal[fontnum];
+#endif
+
+ if (norm == 0 && xw->misc.face_name) {
+ XftPattern *pat;
+ double face_size = xw->misc.face_size;
+
+ TRACE(("xtermComputeFontInfo norm(face %s, size %f)\n",
+ xw->misc.face_name,
+ xw->misc.face_size));
+
+#if OPT_SHIFT_FONTS
+ /*
+ * If the user is switching font-sizes, make it follow the same
+ * ratios to the default as the fixed fonts would, for easy
+ * comparison. There will be some differences since the fixed
+ * fonts have a variety of height/width ratios, but this is simpler
+ * than adding another resource value - and as noted above, the
+ * data for the fixed fonts are available.
+ */
+ lookupOneFontSize(screen, fontnum);
+ if (fontnum != fontMenu_fontdefault) {
+ int num = screen->menu_font_sizes[fontnum];
+ int den = screen->menu_font_sizes[0];
+ face_size = (1.0 * face_size * num) / den;
+ TRACE(("scaled using %d/%d -> %f\n", num, den, face_size));
+ }
+#endif
+
+ pat = XftNameParse(xw->misc.face_name);
+ XftPatternBuild(pat,
+ XFT_FAMILY, XftTypeString, "mono",
+ XFT_SIZE, XftTypeDouble, face_size,
+ XFT_SPACING, XftTypeInteger, XFT_MONO,
+ (void *) 0);
+ norm = xtermOpenXft(dpy, pat, "normal");
+
+ if (norm != 0) {
+ XftPatternBuild(pat,
+ XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD,
+ XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width,
+ (void *) 0);
+ bold = xtermOpenXft(dpy, pat, "bold");
+
+#if OPT_ISO_COLORS
+ if (screen->italicULMode) {
+ XftPatternBuild(pat,
+ XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC,
+ XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width,
+ (void *) 0);
+ ital = xtermOpenXft(dpy, pat, "italic");
+ }
+#endif /* OPT_ISO_COLORS */
+
+ /*
+ * FIXME: just assume that the corresponding font has no
+ * graphics characters.
+ */
+ if (screen->fnt_boxes) {
+ screen->fnt_boxes = False;
+ TRACE(("Xft opened - will %suse internal line-drawing characters\n",
+ screen->fnt_boxes ? "not " : ""));
+ }
+ }
+
+ if (pat)
+ XftPatternDestroy(pat);
+
+ CACHE_XFT(screen->renderFontNorm, norm);
+ CACHE_XFT(screen->renderFontBold, bold);
+ CACHE_XFT(screen->renderFontItal, ital);
+
+ /*
+ * See xtermXftDrawString().
+ */
+#if OPT_RENDERWIDE
+ if (norm != 0 && screen->wide_chars) {
+ char *face_name = (xw->misc.face_wide_name
+ ? xw->misc.face_wide_name
+ : xw->misc.face_name);
+ int char_width = norm->max_advance_width * 2;
+
+ TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n",
+ face_name,
+ char_width));
+
+ pat = XftNameParse(xw->misc.face_name);
+ XftPatternBuild(pat,
+ XFT_FAMILY, XftTypeString, face_name,
+ XFT_SIZE, XftTypeDouble, face_size,
+ XFT_SPACING, XftTypeInteger, XFT_MONO,
+ XFT_CHAR_WIDTH, XftTypeInteger, char_width,
+ (void *) 0);
+ wnorm = xtermOpenXft(dpy, pat, "wide");
+
+ if (wnorm != 0) {
+ XftPatternBuild(pat,
+ XFT_FAMILY, XftTypeString, face_name,
+ XFT_SIZE, XftTypeDouble, face_size,
+ XFT_SPACING, XftTypeInteger, XFT_MONO,
+ XFT_CHAR_WIDTH, XftTypeInteger, char_width,
+ XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD,
+ (void *) 0);
+ wbold = xtermOpenXft(dpy, pat, "wide-bold");
+
+ if (screen->italicULMode) {
+ XftPatternBuild(pat,
+ XFT_FAMILY, XftTypeString, face_name,
+ XFT_SIZE, XftTypeDouble, face_size,
+ XFT_SPACING, XftTypeInteger, XFT_MONO,
+ XFT_CHAR_WIDTH, XftTypeInteger, char_width,
+ XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC,
+ (void *) 0);
+ wital = xtermOpenXft(dpy, pat, "wide-italic");
+ }
+ }
+
+ if (pat)
+ XftPatternDestroy(pat);
+
+ CACHE_XFT(screen->renderWideNorm, wnorm);
+ CACHE_XFT(screen->renderWideBold, wbold);
+ CACHE_XFT(screen->renderWideItal, wital);
+ }
+#endif
+ }
+ if (norm == 0) {
+ xw->misc.render_font = False;
+ update_font_renderfont();
+ } else {
+ win->f_width = norm->max_advance_width;
+ win->f_height = norm->height;
+ win->f_ascent = norm->ascent;
+ win->f_descent = norm->descent;
+ if (win->f_height < win->f_ascent + win->f_descent)
+ win->f_height = win->f_ascent + win->f_descent;
+ if (is_double_width_font_xft(screen->display, norm))
+ win->f_width >>= 1;
+ }
+ }
+ if (!xw->misc.render_font || IsIconWin(screen, win))
+#endif
+ {
+ if (is_double_width_font(font)) {
+ win->f_width = (font->min_bounds.width);
+ } else {
+ win->f_width = (font->max_bounds.width);
+ }
+ win->f_height = (font->ascent + font->descent);
+ win->f_ascent = font->ascent;
+ win->f_descent = font->descent;
+ }
+ i = 2 * screen->border + sbwidth;
+ j = 2 * screen->border;
+ width = MaxCols(screen) * win->f_width + i;
+ height = MaxRows(screen) * win->f_height + j;
+ win->fullwidth = width;
+ win->fullheight = height;
+ win->width = width - i;
+ win->height = height - j;
+
+ TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n",
+ win->height,
+ win->width,
+ win->fullheight,
+ win->fullwidth,
+ win->f_height,
+ win->f_width,
+ win->f_ascent,
+ win->f_descent));
+}
+
+/* save this information as a side-effect for double-sized characters */
+void
+xtermSaveFontInfo(TScreen * screen, XFontStruct * font)
+{
+ screen->fnt_wide = (font->max_bounds.width);
+ screen->fnt_high = (font->ascent + font->descent);
+ TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide));
+}
+
+/*
+ * After loading a new font, update the structures that use its size.
+ */
+void
+xtermUpdateFontInfo(XtermWidget xw, Bool doresize)
+{
+ TScreen *screen = &(xw->screen);
+
+ int scrollbar_width;
+ struct _vtwin *win = &(screen->fullVwin);
+
+ scrollbar_width = (xw->misc.scrollbar
+ ? (screen->scrollWidget->core.width +
+ screen->scrollWidget->core.border_width)
+ : 0);
+ xtermComputeFontInfo(xw, win, screen->fnt_norm, scrollbar_width);
+ xtermSaveFontInfo(screen, screen->fnt_norm);
+
+ if (doresize) {
+ if (VWindow(screen)) {
+ XClearWindow(screen->display, VWindow(screen));
+ }
+ TRACE(("xtermUpdateFontInfo {{\n"));
+ DoResizeScreen(xw); /* set to the new natural size */
+ if (screen->scrollWidget)
+ ResizeScrollBar(xw);
+ Redraw();
+ TRACE(("... }} xtermUpdateFontInfo\n"));
+#ifdef SCROLLBAR_RIGHT
+ updateRightScrollbar(term);
+#endif
+ }
+ xtermSetCursorBox(screen);
+}
+
+#if OPT_BOX_CHARS
+
+/*
+ * Returns true if the given character is missing from the specified font.
+ */
+Bool
+xtermMissingChar(XtermWidget xw, unsigned ch, XFontStruct * font)
+{
+ if (font != 0
+ && font->per_char != 0
+ && !font->all_chars_exist) {
+ static XCharStruct dft, *tmp = &dft, *pc = 0;
+
+ if (font->max_byte1 == 0) {
+#if OPT_WIDE_CHARS
+ if (ch > 255) {
+ TRACE(("xtermMissingChar %#04x (row)\n", ch));
+ return True;
+ }
+#endif
+ CI_GET_CHAR_INFO_1D(font, E2A(ch), tmp, pc);
+ }
+#if OPT_WIDE_CHARS
+ else {
+ CI_GET_CHAR_INFO_2D(font, (ch >> 8), (ch & 0xff), tmp, pc);
+ }
+#else
+
+ if (!pc)
+ return False; /* Urgh! */
+#endif
+
+ if (CI_NONEXISTCHAR(pc)) {
+ TRACE(("xtermMissingChar %#04x (!exists)\n", ch));
+ return True;
+ }
+ }
+ if (ch < 32
+ && xw->screen.force_box_chars) {
+ TRACE(("xtermMissingChar %#04x (forced off)\n", ch));
+ return True;
+ }
+ return False;
+}
+
+/*
+ * The grid is arbitrary, enough resolution that nothing's lost in
+ * initialization.
+ */
+#define BOX_HIGH 60
+#define BOX_WIDE 60
+
+#define MID_HIGH (BOX_HIGH/2)
+#define MID_WIDE (BOX_WIDE/2)
+
+#define CHR_WIDE ((9*BOX_WIDE)/10)
+#define CHR_HIGH ((9*BOX_HIGH)/10)
+
+/*
+ * ...since we'll scale the values anyway.
+ */
+#define SCALE_X(n) n = (n * (font_width-1)) / (BOX_WIDE-1)
+#define SCALE_Y(n) n = (n * (font_height-1)) / (BOX_HIGH-1)
+
+#define SEG(x0,y0,x1,y1) x0,y0, x1,y1
+
+/*
+ * Draw the given graphic character, if it is simple enough (i.e., a
+ * line-drawing character).
+ */
+void
+xtermDrawBoxChar(XtermWidget xw,
+ unsigned ch,
+ unsigned flags,
+ GC gc,
+ int x,
+ int y)
+{
+ TScreen *screen = &(xw->screen);
+ /* *INDENT-OFF* */
+ static const short glyph_ht[] = {
+ SEG( 0, 0, 0, 5*MID_HIGH/6), /* H */
+ SEG(6*BOX_WIDE/10, 0, 6*BOX_WIDE/10,5*MID_HIGH/6),
+ SEG( 0, 5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12),
+ SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */
+ SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH),
+ -1
+ }, glyph_ff[] = {
+ SEG( 0, 0, 6*BOX_WIDE/10, 0), /* F */
+ SEG( 0, 5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12),
+ SEG( 0, 0, 0*BOX_WIDE/3, 5*MID_HIGH/6),
+ SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */
+ SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
+ SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH),
+ -1
+ }, glyph_lf[] = {
+ SEG( 0, 0, 0, 5*MID_HIGH/6), /* L */
+ SEG( 0, 5*MID_HIGH/6, 6*BOX_WIDE/10,5*MID_HIGH/6),
+ SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */
+ SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
+ SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH),
+ -1
+ }, glyph_nl[] = {
+ SEG( 0, 5*MID_HIGH/6, 0, 0), /* N */
+ SEG( 0, 0, 5*BOX_WIDE/6, 5*MID_HIGH/6),
+ SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6, 0),
+ SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), /* L */
+ SEG(1*BOX_WIDE/3, CHR_HIGH, CHR_WIDE, CHR_HIGH),
+ -1
+ }, glyph_vt[] = {
+ SEG( 0, 0, 5*BOX_WIDE/12,5*MID_HIGH/6), /* V */
+ SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6, 0),
+ SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */
+ SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH),
+ -1
+ }, plus_or_minus[] =
+ {
+ SEG( 0, 5*BOX_HIGH/6, CHR_WIDE, 5*BOX_HIGH/6),
+ SEG( MID_WIDE, 2*BOX_HIGH/6, MID_WIDE, 4*BOX_HIGH/6),
+ SEG( 0, 3*BOX_HIGH/6, CHR_WIDE, 3*BOX_HIGH/6),
+ -1
+ }, lower_right_corner[] =
+ {
+ SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH),
+ SEG( MID_WIDE, MID_HIGH, MID_WIDE, 0),
+ -1
+ }, upper_right_corner[] =
+ {
+ SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH),
+ SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH),
+ -1
+ }, upper_left_corner[] =
+ {
+ SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH),
+ SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH),
+ -1
+ }, lower_left_corner[] =
+ {
+ SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH),
+ SEG( MID_WIDE, MID_WIDE, BOX_WIDE, MID_HIGH),
+ -1
+ }, cross[] =
+ {
+ SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH),
+ SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH),
+ -1
+ }, scan_line_1[] =
+ {
+ SEG( 0, 0, BOX_WIDE, 0),
+ -1
+ }, scan_line_3[] =
+ {
+ SEG( 0, BOX_HIGH/4, BOX_WIDE, BOX_HIGH/4),
+ -1
+ }, scan_line_7[] =
+ {
+ SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH),
+ -1
+ }, scan_line_9[] =
+ {
+ SEG( 0, 3*BOX_HIGH/4, BOX_WIDE, 3*BOX_HIGH/4),
+ -1
+ }, horizontal_line[] =
+ {
+ SEG( 0, BOX_HIGH, BOX_WIDE, BOX_HIGH),
+ -1
+ }, left_tee[] =
+ {
+ SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH),
+ SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH),
+ -1
+ }, right_tee[] =
+ {
+ SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH),
+ SEG( MID_WIDE, MID_HIGH, 0, MID_HIGH),
+ -1
+ }, bottom_tee[] =
+ {
+ SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH),
+ SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH),
+ -1
+ }, top_tee[] =
+ {
+ SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH),
+ SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH),
+ -1
+ }, vertical_line[] =
+ {
+ SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH),
+ -1
+ }, less_than_or_equal[] =
+ {
+ SEG( CHR_WIDE, BOX_HIGH/3, 0, MID_HIGH),
+ SEG( CHR_WIDE, 2*BOX_HIGH/3, 0, MID_HIGH),
+ SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4),
+ -1
+ }, greater_than_or_equal[] =
+ {
+ SEG( 0, BOX_HIGH/3, CHR_WIDE, MID_HIGH),
+ SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, MID_HIGH),
+ SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4),
+ -1
+ }, greek_pi[] =
+ {
+ SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH),
+ SEG(5*CHR_WIDE/6, MID_HIGH, 5*CHR_WIDE/6, CHR_HIGH),
+ SEG(2*CHR_WIDE/6, MID_HIGH, 2*CHR_WIDE/6, CHR_HIGH),
+ -1
+ }, not_equal_to[] =
+ {
+ SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3, CHR_HIGH),
+ SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, 2*BOX_HIGH/3),
+ SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH),
+ -1
+ };
+ /* *INDENT-ON* */
+
+ static const short *lines[] =
+ {
+ 0, /* 00 (unused) */
+ 0, /* 01 diamond */
+ 0, /* 02 box */
+ glyph_ht, /* 03 HT */
+ glyph_ff, /* 04 FF */
+ 0, /* 05 CR */
+ glyph_lf, /* 06 LF */
+ 0, /* 07 degrees (small circle) */
+ plus_or_minus, /* 08 */
+ glyph_nl, /* 09 */
+ glyph_vt, /* 0A */
+ lower_right_corner, /* 0B */
+ upper_right_corner, /* 0C */
+ upper_left_corner, /* 0D */
+ lower_left_corner, /* 0E */
+ cross, /* 0F */
+ scan_line_1, /* 10 */
+ scan_line_3, /* 11 */
+ scan_line_7, /* 12 */
+ scan_line_9, /* 13 */
+ horizontal_line, /* 14 */
+ left_tee, /* 15 */
+ right_tee, /* 16 */
+ bottom_tee, /* 17 */
+ top_tee, /* 18 */
+ vertical_line, /* 19 */
+ less_than_or_equal, /* 1A */
+ greater_than_or_equal, /* 1B */
+ greek_pi, /* 1C */
+ not_equal_to, /* 1D */
+ 0, /* 1E LB */
+ 0, /* 1F bullet */
+ };
+
+ XGCValues values;
+ unsigned long mask;
+ GC gc2;
+ const short *p;
+ unsigned font_width = ((flags & DOUBLEWFONT) ? 2 : 1) * screen->fnt_wide;
+ unsigned font_height = ((flags & DOUBLEHFONT) ? 2 : 1) * screen->fnt_high;
+
+#if OPT_WIDE_CHARS
+ /*
+ * Try to show line-drawing characters if we happen to be in UTF-8
+ * mode, but have gotten an old-style font.
+ */
+ if (screen->utf8_mode
+#if OPT_RENDERFONT
+ && !UsingRenderFont(xw)
+#endif
+ && (ch > 127)
+ && (ch != UCS_REPL)) {
+ unsigned n;
+ for (n = 1; n < 32; n++) {
+ if (dec2ucs(n) == ch
+ && !xtermMissingChar(xw, n, (flags & BOLD)
+ ? screen->fnt_bold
+ : screen->fnt_norm)) {
+ TRACE(("...use xterm-style linedrawing\n"));
+ ch = n;
+ break;
+ }
+ }
+ }
+#endif
+
+ TRACE(("DRAW_BOX(%d) cell %dx%d at %d,%d%s\n",
+ ch, font_height, font_width, y, x,
+ (ch >= (sizeof(lines) / sizeof(lines[0]))
+ ? "-BAD"
+ : "")));
+
+ if (!XGetGCValues(screen->display, gc, GCBackground, &values))
+ return;
+
+ mask = GCForeground;
+ if (ch == 2) {
+ values.tile =
+ XmuCreateStippledPixmap(XtScreen((Widget) xw),
+ getXtermForeground(xw->flags, xw->cur_foreground),
+ getXtermBackground(xw->flags, xw->cur_background),
+ xw->core.depth);
+ if (values.stipple != XtUnspecifiedPixmap) {
+ mask |= GCBackground | GCTile | GCFillStyle;
+ values.fill_style = FillTiled;
+ } else {
+ ch = (unsigned) (~0); /* make this not match anything */
+ }
+ } else {
+ values.foreground = values.background;
+ }
+ gc2 = XCreateGC(screen->display,
+ VWindow(screen),
+ mask,
+ &values);
+
+ if (!(flags & NOBACKGROUND)) {
+ XFillRectangle(screen->display, VWindow(screen), gc2, x, y,
+ font_width,
+ font_height);
+ }
+
+ XCopyGC(screen->display, gc, (1 << GCLastBit) - 1, gc2);
+ XSetLineAttributes(screen->display, gc2,
+ (flags & BOLD)
+ ? ((font_height > 12)
+ ? font_height / 12
+ : 1)
+ : ((font_height > 16)
+ ? font_height / 16
+ : 1),
+ LineSolid,
+ CapProjecting,
+ JoinMiter);
+
+ if (ch == 1) { /* diamond */
+ XPoint points[5];
+ int npoints = 5, n;
+
+ points[0].x = MID_WIDE;
+ points[0].y = BOX_HIGH / 4;
+
+ points[1].x = 3 * BOX_WIDE / 4;
+ points[1].y = MID_HIGH;
+
+ points[2].x = points[0].x;
+ points[2].y = 3 * BOX_HIGH / 4;
+
+ points[3].x = BOX_WIDE / 4;
+ points[3].y = points[1].y;
+
+ points[4].x = points[0].x;
+ points[4].y = points[0].y;
+
+ for (n = 0; n < npoints; ++n) {
+ SCALE_X(points[n].x);
+ SCALE_Y(points[n].y);
+ points[n].x += x;
+ points[n].y += y;
+ }
+
+ XFillPolygon(screen->display,
+ VWindow(screen), gc2,
+ points, npoints,
+ Convex, CoordModeOrigin);
+ } else if (ch == 2) { /* box */
+ XmuReleaseStippledPixmap(XtScreen((Widget) xw), values.tile);
+ } else if (ch == 7) { /* degrees */
+ unsigned width = (BOX_WIDE / 3);
+ int x_coord = MID_WIDE - (width / 2);
+ int y_coord = MID_HIGH - width;
+
+ SCALE_X(x_coord);
+ SCALE_Y(y_coord);
+ SCALE_X(width);
+
+ XDrawArc(screen->display,
+ VWindow(screen), gc2,
+ x + x_coord, y + y_coord, width, width,
+ 0,
+ 360 * 64);
+ } else if (ch == 0x1f) { /* bullet */
+ unsigned width = 7 * BOX_WIDE / 10;
+ int x_coord = MID_WIDE - (width / 3);
+ int y_coord = MID_HIGH - (width / 3);
+
+ SCALE_X(x_coord);
+ SCALE_Y(y_coord);
+ SCALE_X(width);
+
+ XFillArc(screen->display,
+ VWindow(screen), gc2,
+ x + x_coord, y + y_coord, width, width,
+ 0,
+ 360 * 64);
+ } else if (ch < (sizeof(lines) / sizeof(lines[0]))
+ && (p = lines[ch]) != 0) {
+ int coord[4];
+ int n = 0;
+ while (*p >= 0) {
+ coord[n++] = *p++;
+ if (n == 4) {
+ SCALE_X(coord[0]);
+ SCALE_Y(coord[1]);
+ SCALE_X(coord[2]);
+ SCALE_Y(coord[3]);
+ XDrawLine(screen->display,
+ VWindow(screen), gc2,
+ x + coord[0], y + coord[1],
+ x + coord[2], y + coord[3]);
+ n = 0;
+ }
+ }
+ } else if (screen->force_all_chars) {
+ /* bounding rectangle, for debugging */
+ XDrawRectangle(screen->display, VWindow(screen), gc2, x, y,
+ font_width - 1,
+ font_height - 1);
+ }
+
+ XFreeGC(screen->display, gc2);
+}
+
+#if OPT_RENDERFONT && OPT_WIDE_CHARS
+
+/*
+ * Check if the given character has a glyph known to Xft.
+ *
+ * see xc/lib/Xft/xftglyphs.c
+ */
+Bool
+xtermXftMissing(XtermWidget xw, XftFont * font, unsigned wc)
+{
+ unsigned check = XftCharIndex(xw->screen.display, font, wc);
+ Bool result = False;
+
+ if (check == 0) {
+ TRACE(("missingXft %d (%d)\n", wc, ucs2dec(wc)));
+ result = True;
+ }
+ return result;
+}
+
+/*
+ * Check if the character corresponds to one of xterm's internal codes for
+ * line-drawing characters. That is only a subset of the 1-31 codes used for
+ * graphic characters. We want to know specifically about the line-drawing
+ * characters because the fonts used by Xft do not always give useful glyphs
+ * for line-drawing, and there is no reliable way to detect this.
+ */
+Bool
+xtermIsLineDrawing(unsigned wc)
+{
+ Bool result;
+ switch (wc) {
+ case 0x0B: /* lower_right_corner */
+ case 0x0C: /* upper_right_corner */
+ case 0x0D: /* upper_left_corner */
+ case 0x0E: /* lower_left_corner */
+ case 0x0F: /* cross */
+ case 0x10: /* scan_line_1 */
+ case 0x11: /* scan_line_3 */
+ case 0x12: /* scan_line_7 */
+ case 0x13: /* scan_line_9 */
+ case 0x14: /* horizontal_line */
+ case 0x15: /* left_tee */
+ case 0x16: /* right_tee */
+ case 0x17: /* bottom_tee */
+ case 0x18: /* top_tee */
+ case 0x19: /* vertical_line */
+ result = True;
+ TRACE(("xtermIsLineDrawing %d\n", wc));
+ break;
+ default:
+ result = False;
+ break;
+ }
+ return result;
+}
+#endif /* OPT_RENDERFONT && OPT_WIDE_CHARS */
+
+#endif /* OPT_BOX_CHARS */
+
+#if OPT_WIDE_CHARS
+#define MY_UCS(ucs,dec) case ucs: result = dec; break
+unsigned
+ucs2dec(unsigned ch)
+{
+ unsigned result = ch;
+ if ((ch > 127)
+ && (ch != UCS_REPL)) {
+ switch (ch) {
+ MY_UCS(0x25ae, 0); /* black vertical rectangle */
+ MY_UCS(0x25c6, 1); /* black diamond */
+ MY_UCS(0x2592, 2); /* medium shade */
+ MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */
+ MY_UCS(0x240c, 4); /* symbol for form feed */
+ MY_UCS(0x240d, 5); /* symbol for carriage return */
+ MY_UCS(0x240a, 6); /* symbol for line feed */
+ MY_UCS(0x00b0, 7); /* degree sign */
+ MY_UCS(0x00b1, 8); /* plus-minus sign */
+ MY_UCS(0x2424, 9); /* symbol for newline */
+ MY_UCS(0x240b, 10); /* symbol for vertical tabulation */
+ MY_UCS(0x2518, 11); /* box drawings light up and left */
+ MY_UCS(0x2510, 12); /* box drawings light down and left */
+ MY_UCS(0x250c, 13); /* box drawings light down and right */
+ MY_UCS(0x2514, 14); /* box drawings light up and right */
+ MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */
+ MY_UCS(0x23ba, 16); /* box drawings scan 1 */
+ MY_UCS(0x23bb, 17); /* box drawings scan 3 */
+ MY_UCS(0x2500, 18); /* box drawings light horizontal */
+ MY_UCS(0x23bc, 19); /* box drawings scan 7 */
+ MY_UCS(0x23bd, 20); /* box drawings scan 9 */
+ MY_UCS(0x251c, 21); /* box drawings light vertical and right */
+ MY_UCS(0x2524, 22); /* box drawings light vertical and left */
+ MY_UCS(0x2534, 23); /* box drawings light up and horizontal */
+ MY_UCS(0x252c, 24); /* box drawings light down and horizontal */
+ MY_UCS(0x2502, 25); /* box drawings light vertical */
+ MY_UCS(0x2264, 26); /* less-than or equal to */
+ MY_UCS(0x2265, 27); /* greater-than or equal to */
+ MY_UCS(0x03c0, 28); /* greek small letter pi */
+ MY_UCS(0x2260, 29); /* not equal to */
+ MY_UCS(0x00a3, 30); /* pound sign */
+ MY_UCS(0x00b7, 31); /* middle dot */
+ }
+ }
+ return result;
+}
+
+#undef MY_UCS
+#define MY_UCS(ucs,dec) case dec: result = ucs; break
+
+unsigned
+dec2ucs(unsigned ch)
+{
+ unsigned result = ch;
+ if (ch < 32) {
+ switch (ch) {
+ MY_UCS(0x25ae, 0); /* black vertical rectangle */
+ MY_UCS(0x25c6, 1); /* black diamond */
+ MY_UCS(0x2592, 2); /* medium shade */
+ MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */
+ MY_UCS(0x240c, 4); /* symbol for form feed */
+ MY_UCS(0x240d, 5); /* symbol for carriage return */
+ MY_UCS(0x240a, 6); /* symbol for line feed */
+ MY_UCS(0x00b0, 7); /* degree sign */
+ MY_UCS(0x00b1, 8); /* plus-minus sign */
+ MY_UCS(0x2424, 9); /* symbol for newline */
+ MY_UCS(0x240b, 10); /* symbol for vertical tabulation */
+ MY_UCS(0x2518, 11); /* box drawings light up and left */
+ MY_UCS(0x2510, 12); /* box drawings light down and left */
+ MY_UCS(0x250c, 13); /* box drawings light down and right */
+ MY_UCS(0x2514, 14); /* box drawings light up and right */
+ MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */
+ MY_UCS(0x23ba, 16); /* box drawings scan 1 */
+ MY_UCS(0x23bb, 17); /* box drawings scan 3 */
+ MY_UCS(0x2500, 18); /* box drawings light horizontal */
+ MY_UCS(0x23bc, 19); /* box drawings scan 7 */
+ MY_UCS(0x23bd, 20); /* box drawings scan 9 */
+ MY_UCS(0x251c, 21); /* box drawings light vertical and right */
+ MY_UCS(0x2524, 22); /* box drawings light vertical and left */
+ MY_UCS(0x2534, 23); /* box drawings light up and horizontal */
+ MY_UCS(0x252c, 24); /* box drawings light down and horizontal */
+ MY_UCS(0x2502, 25); /* box drawings light vertical */
+ MY_UCS(0x2264, 26); /* less-than or equal to */
+ MY_UCS(0x2265, 27); /* greater-than or equal to */
+ MY_UCS(0x03c0, 28); /* greek small letter pi */
+ MY_UCS(0x2260, 29); /* not equal to */
+ MY_UCS(0x00a3, 30); /* pound sign */
+ MY_UCS(0x00b7, 31); /* middle dot */
+ }
+ }
+ return result;
+}
+
+#endif /* OPT_WIDE_CHARS */
+
+#if OPT_SHIFT_FONTS
+static XFontStruct *
+xtermFindFont(TScreen * screen, int fontnum)
+{
+ XFontStruct *nfs = 0;
+ char *name;
+
+ if ((name = screen->MenuFontName(fontnum)) != 0
+ && (nfs = XLoadQueryFont(screen->display, name)) != 0) {
+ if (EmptyFont(nfs)) {
+ XFreeFont(screen->display, nfs);
+ nfs = 0;
+ }
+ }
+ return nfs;
+}
+
+static void
+lookupOneFontSize(TScreen * screen, int fontnum)
+{
+ if (screen->menu_font_sizes[fontnum] == 0) {
+ XFontStruct *fs = xtermFindFont(screen, fontnum);
+ screen->menu_font_sizes[fontnum] = -1;
+ if (fs != 0) {
+ screen->menu_font_sizes[fontnum] = FontSize(fs);
+ TRACE(("menu_font_sizes[%d] = %ld\n", fontnum,
+ screen->menu_font_sizes[fontnum]));
+ XFreeFont(screen->display, fs);
+ }
+ }
+}
+
+/*
+ * Cache the font-sizes so subsequent larger/smaller font actions will go fast.
+ */
+static void
+lookupFontSizes(TScreen * screen)
+{
+ int n;
+
+ for (n = 0; n < NMENUFONTS; n++) {
+ lookupOneFontSize(screen, n);
+ }
+}
+
+/*
+ * Find the index of a larger/smaller font (according to the sign of 'relative'
+ * and its magnitude), starting from the 'old' index.
+ */
+int
+lookupRelativeFontSize(TScreen * screen, int old, int relative)
+{
+ int n, m = -1;
+
+ if (!IsIcon(screen)) {
+ lookupFontSizes(screen);
+ if (relative != 0) {
+ for (n = 0; n < NMENUFONTS; ++n) {
+ if (screen->menu_font_sizes[n] > 0 &&
+ screen->menu_font_sizes[n] != screen->menu_font_sizes[old]) {
+ int cmp_0 = ((screen->menu_font_sizes[n] >
+ screen->menu_font_sizes[old])
+ ? relative
+ : -relative);
+ int cmp_m = ((m < 0)
+ ? 1
+ : ((screen->menu_font_sizes[n] <
+ screen->menu_font_sizes[m])
+ ? relative
+ : -relative));
+ if (cmp_0 > 0 && cmp_m > 0) {
+ m = n;
+ }
+ }
+ }
+ if (m >= 0) {
+ if (relative > 1)
+ m = lookupRelativeFontSize(screen, m, relative - 1);
+ else if (relative < -1)
+ m = lookupRelativeFontSize(screen, m, relative + 1);
+ }
+ }
+ }
+ return m;
+}
+
+/* ARGSUSED */
+void
+HandleLargerFont(Widget w GCC_UNUSED,
+ XEvent * event GCC_UNUSED,
+ String * params GCC_UNUSED,
+ Cardinal *param_count GCC_UNUSED)
+{
+ if (term->misc.shift_fonts) {
+ TScreen *screen = &term->screen;
+ int m;
+
+ m = lookupRelativeFontSize(screen, screen->menu_font_number, 1);
+ if (m >= 0) {
+ SetVTFont(term, m, True, NULL);
+ } else {
+ Bell(XkbBI_MinorError, 0);
+ }
+ }
+}
+
+/* ARGSUSED */
+void
+HandleSmallerFont(Widget w GCC_UNUSED,
+ XEvent * event GCC_UNUSED,
+ String * params GCC_UNUSED,
+ Cardinal *param_count GCC_UNUSED)
+{
+ if (term->misc.shift_fonts) {
+ TScreen *screen = &term->screen;
+ int m;
+
+ m = lookupRelativeFontSize(screen, screen->menu_font_number, -1);
+ if (m >= 0) {
+ SetVTFont(term, m, True, NULL);
+ } else {
+ Bell(XkbBI_MinorError, 0);
+ }
+ }
+}
+#endif
+
+/* ARGSUSED */
+void
+HandleSetFont(Widget w GCC_UNUSED,
+ XEvent * event GCC_UNUSED,
+ String * params,
+ Cardinal *param_count)
+{
+ int fontnum;
+ VTFontNames fonts;
+
+ memset(&fonts, 0, sizeof(fonts));
+
+ if (*param_count == 0) {
+ fontnum = fontMenu_fontdefault;
+ } else {
+ Cardinal maxparams = 1; /* total number of params allowed */
+
+ switch (params[0][0]) {
+ case 'd':
+ case 'D':
+ case '0':
+ fontnum = fontMenu_fontdefault;
+ break;
+ case '1':
+ fontnum = fontMenu_font1;
+ break;
+ case '2':
+ fontnum = fontMenu_font2;
+ break;
+ case '3':
+ fontnum = fontMenu_font3;
+ break;
+ case '4':
+ fontnum = fontMenu_font4;
+ break;
+ case '5':
+ fontnum = fontMenu_font5;
+ break;
+ case '6':
+ fontnum = fontMenu_font6;
+ break;
+ case 'e':
+ case 'E':
+ fontnum = fontMenu_fontescape;
+#if OPT_WIDE_CHARS
+ maxparams = 5;
+#else
+ maxparams = 3;
+#endif
+ break;
+ case 's':
+ case 'S':
+ fontnum = fontMenu_fontsel;
+ maxparams = 2;
+ break;
+ default:
+ Bell(XkbBI_MinorError, 0);
+ return;
+ }
+ if (*param_count > maxparams) { /* see if extra args given */
+ Bell(XkbBI_MinorError, 0);
+ return;
+ }
+ switch (*param_count) { /* assign 'em */
+#if OPT_WIDE_CHARS
+ case 5:
+ fonts.f_wb = params[4];
+ /* FALLTHRU */
+ case 4:
+ fonts.f_w = params[3];
+ /* FALLTHRU */
+#endif
+ case 3:
+ fonts.f_b = params[2];
+ /* FALLTHRU */
+ case 2:
+ fonts.f_n = params[1];
+ break;
+ }
+ }
+
+ SetVTFont(term, fontnum, True, &fonts);
+}
+
+void
+SetVTFont(XtermWidget xw,
+ int which,
+ Bool doresize,
+ const VTFontNames * fonts)
+{
+ TScreen *screen = &xw->screen;
+
+ TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which,
+ (fonts && fonts->f_n) ? fonts->f_n : "<null>",
+ (fonts && fonts->f_b) ? fonts->f_b : "<null>"));
+
+ if (IsIcon(screen)) {
+ Bell(XkbBI_MinorError, 0);
+ } else if (which >= 0 && which < NMENUFONTS) {
+ VTFontNames myfonts;
+
+ memset(&myfonts, 0, sizeof(myfonts));
+ if (fonts != 0)
+ myfonts = *fonts;
+
+ if (which == fontMenu_fontsel) { /* go get the selection */
+ FindFontSelection(myfonts.f_n, False);
+ return;
+ } else {
+ if (myfonts.f_n == 0) {
+ myfonts.f_n = screen->MenuFontName(which);
+ TRACE(("set myfonts.f_n from menu_font_names[%d][fNorm] %s\n",
+ which, NonNull(myfonts.f_n)));
+ }
+ if (myfonts.f_b == 0) {
+ myfonts.f_b = screen->menu_font_names[which][fBold];
+ TRACE(("set myfonts.f_b from menu_font_names[%d][fBold] %s\n",
+ which, NonNull(myfonts.f_b)));
+ }
+#if OPT_WIDE_CHARS
+ if (myfonts.f_w == 0) {
+ myfonts.f_w = screen->menu_font_names[which][fWide];
+ TRACE(("set myfonts.f_w from menu_font_names[%d][fWide] %s\n",
+ which, NonNull(myfonts.f_w)));
+ }
+ if (myfonts.f_wb == 0) {
+ myfonts.f_wb = screen->menu_font_names[which][fWBold];
+ TRACE(("set myfonts.f_wb from menu_font_names[%d][fWBold] %s\n",
+ which, NonNull(myfonts.f_wb)));
+ }
+#endif
+ if (xtermLoadFont(xw,
+ &myfonts,
+ doresize, which)) {
+ return;
+ }
+ }
+ }
+
+ Bell(XkbBI_MinorError, 0);
+ return;
+}