1 /* $XTermId: fontutils.c,v 1.353 2010/10/23 00:27:22 tom Exp $ */
3 /************************************************************
5 Copyright 1998-2009,2010 by Thomas E. Dickey
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sublicense, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
17 The above copyright notice and this permission notice shall be included
18 in all copies or substantial portions of the Software.
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
24 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 Except as contained in this notice, the name(s) of the above copyright
29 holders shall not be used in advertising or otherwise to promote the
30 sale, use or other dealings in this Software without prior written
33 ********************************************************/
36 * A portion of this module (for FontNameProperties) was adapted from EMU 1.3;
37 * it constructs font names with specific properties changed, e.g., for bold
38 * and double-size characters.
41 #define RES_OFFSET(field) XtOffsetOf(SubResourceRec, field)
43 #include <fontutils.h>
44 #include <X11/Xmu/Drawing.h>
45 #include <X11/Xmu/CharSet.h>
56 /* from X11/Xlibint.h - not all vendors install this file */
57 #define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \
58 (((cs)->rbearing|(cs)->lbearing| \
59 (cs)->ascent|(cs)->descent) == 0))
61 #define CI_GET_CHAR_INFO_1D(fs,col,def,cs) \
64 if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
65 if (fs->per_char == NULL) { \
66 cs = &fs->min_bounds; \
68 cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \
69 if (CI_NONEXISTCHAR(cs)) cs = def; \
74 #define CI_GET_CHAR_INFO_2D(fs,row,col,def,cs) \
77 if (row >= fs->min_byte1 && row <= fs->max_byte1 && \
78 col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \
79 if (fs->per_char == NULL) { \
80 cs = &fs->min_bounds; \
82 cs = &fs->per_char[((row - fs->min_byte1) * \
83 (fs->max_char_or_byte2 - \
84 fs->min_char_or_byte2 + 1)) + \
85 (col - fs->min_char_or_byte2)]; \
86 if (CI_NONEXISTCHAR(cs)) cs = def; \
91 #define MAX_FONTNAME 200
94 * A structure to hold the relevant properties from a font
95 * we need to make a well formed font name for it.
98 /* registry, foundry, family */
114 /* charset registry, charset encoding */
116 } FontNameProperties;
119 static void lookupOneFontSize(XtermWidget, int);
124 countGlyphs(XFontStruct * fp)
129 if (fp->min_byte1 == 0 && fp->max_byte1 == 0) {
130 count = fp->max_char_or_byte2 - fp->min_char_or_byte2;
131 } else if (fp->min_char_or_byte2 < 256
132 && fp->max_char_or_byte2 < 256) {
133 unsigned first = (fp->min_byte1 << 8) + fp->min_char_or_byte2;
134 unsigned last = (fp->max_byte1 << 8) + fp->max_char_or_byte2;
135 count = last + 1 - first;
142 * Verify that the wide-bold font is at least a bold font with roughly as many
143 * glyphs as the wide font. The counts should be the same, but settle for
144 * filtering out the worst of the font mismatches.
147 compatibleWideCounts(XFontStruct * wfs, XFontStruct * wbfs)
149 unsigned count_w = countGlyphs(wfs);
150 unsigned count_wb = countGlyphs(wbfs);
151 if (count_w <= 256 ||
153 ((count_w / 4) * 3) > count_wb) {
154 TRACE(("...font server lied (count wide %u vs wide-bold %u)\n",
160 #endif /* OPT_WIDE_CHARS */
164 setupPackedFonts(XtermWidget xw)
166 TScreen *screen = TScreenOf(xw);
170 #define MIXED(name) screen->name[fontnum].map.mixed
171 if (xw->misc.render_font == True) {
172 int fontnum = screen->menu_font_number;
174 screen->allow_packing = (Boolean) (MIXED(renderFontNorm)
175 || MIXED(renderFontBold)
176 || MIXED(renderFontItal)
178 || MIXED(renderWideNorm)
179 || MIXED(renderWideBold)
180 || MIXED(renderWideItal)
185 #endif /* OPT_RENDERFONT */
187 value = screen->allow_packing;
189 SetItemSensitivity(fontMenuEntries[fontMenu_font_packedfont].widget, value);
194 * Returns the fields from start to stop in a dash- separated string. This
195 * function will modify the source, putting '\0's in the appropiate place and
196 * moving the beginning forward to after the '\0'
198 * This will NOT work for the last field (but we won't need it).
201 n_fields(char **source, int start, int stop)
207 * find the start-1th dash
209 for (i = start - 1, str = *source; i; i--, str++)
210 if ((str = strchr(str, '-')) == 0)
214 * find the stopth dash
216 for (i = stop - start + 1, str1 = str; i; i--, str1++)
217 if ((str1 = strchr(str1, '-')) == 0)
221 * put a \0 at the end of the fields
226 * move source forward
234 check_fontname(const char *name)
236 Boolean result = True;
239 TRACE(("fontname missing\n"));
241 } else if (strlen(name) >= MAX_FONTNAME - 1) {
242 TRACE(("fontname too large: %s\n", name));
249 * Gets the font properties from a given font structure. We use the FONT name
250 * to find them out, since that seems easier.
252 * Returns a pointer to a static FontNameProperties structure
255 static FontNameProperties *
256 get_font_name_props(Display * dpy, XFontStruct * fs, char *result)
258 static FontNameProperties props;
259 static char *last_name;
263 Atom fontatom = XInternAtom(dpy, "FONT", False);
268 * first get the full font name
271 for (i = 0, fp = fs->properties; i < fs->n_properties; i++, fp++) {
272 if (fp->name == fontatom) {
273 name = XGetAtomName(dpy, fp->card32);
283 * XGetAtomName allocates memory - don't leak
290 if (!check_fontname(name))
292 strcpy(result, name);
296 * Now split it up into parts and put them in
297 * their places. Since we are using parts of
298 * the original string, we must not free the Atom Name
301 /* registry, foundry, family */
302 if ((props.beginning = n_fields(&name, 1, 3)) == 0)
305 /* weight is the next */
306 if ((props.weight = n_fields(&name, 1, 1)) == 0)
310 if ((props.slant = n_fields(&name, 1, 1)) == 0)
314 if ((props.wideness = n_fields(&name, 1, 1)) == 0)
318 if ((props.add_style = n_fields(&name, 1, 1)) == 0)
322 if ((str = n_fields(&name, 1, 1)) == 0)
324 if ((props.pixel_size = atoi(str)) == 0)
328 if ((props.point_size = n_fields(&name, 1, 1)) == 0)
332 if ((str = n_fields(&name, 1, 1)) == 0)
334 if ((props.res_x = atoi(str)) == 0)
338 if ((str = n_fields(&name, 1, 1)) == 0)
340 if ((props.res_y = atoi(str)) == 0)
344 if ((props.spacing = n_fields(&name, 1, 1)) == 0)
348 if ((str = n_fields(&name, 1, 1)) == 0)
350 if ((props.average_width = atoi(str)) == 0)
353 /* the rest: charset registry and charset encoding */
359 #define ALLOCHUNK(n) ((n | 127) + 1)
362 alloca_fontname(char **result, size_t next)
364 size_t last = (*result != 0) ? strlen(*result) : 0;
365 size_t have = (*result != 0) ? ALLOCHUNK(last) : 0;
366 size_t want = last + next + 2;
369 want = ALLOCHUNK(want);
371 *result = TypeRealloc(char, want, *result);
373 if ((*result = TypeMallocN(char, want)) != 0)
380 append_fontname_str(char **result, const char *value)
384 alloca_fontname(result, strlen(value));
386 if (**result != '\0')
387 strcat(*result, "-");
388 strcat(*result, value);
393 append_fontname_num(char **result, int value)
396 append_fontname_str(result, "*");
399 sprintf(temp, "%d", value);
400 append_fontname_str(result, temp);
405 * Take the given font props and try to make a well formed font name specifying
406 * the same base font and size and everything, but with different weight/width
407 * according to the parameters. The return value is allocated, should be freed
411 derive_font_name(FontNameProperties * props,
412 const char *use_weight,
413 int use_average_width,
414 const char *use_encoding)
418 append_fontname_str(&result, props->beginning);
419 append_fontname_str(&result, use_weight);
420 append_fontname_str(&result, props->slant);
421 append_fontname_str(&result, 0);
422 append_fontname_str(&result, 0);
423 append_fontname_num(&result, props->pixel_size);
424 append_fontname_str(&result, props->point_size);
425 append_fontname_num(&result, props->res_x);
426 append_fontname_num(&result, props->res_y);
427 append_fontname_str(&result, props->spacing);
428 append_fontname_num(&result, use_average_width);
429 append_fontname_str(&result, use_encoding);
435 bold_font_name(FontNameProperties * props, int use_average_width)
437 return derive_font_name(props, "bold", use_average_width, props->end);
441 #define derive_wide_font(props, weight) \
442 derive_font_name(props, weight, props->average_width * 2, "ISO10646-1")
445 wide_font_name(FontNameProperties * props)
447 return derive_wide_font(props, "medium");
451 widebold_font_name(FontNameProperties * props)
453 return derive_wide_font(props, "bold");
455 #endif /* OPT_WIDE_CHARS */
459 * Take the given font props and try to make a well formed font name specifying
460 * the same base font but changed depending on the given attributes and chrset.
462 * For double width fonts, we just double the X-resolution, for double height
463 * fonts we double the pixel-size and Y-resolution
466 xtermSpecialFont(TScreen * screen, unsigned atts, unsigned chrset)
469 static char old_spacing[80];
470 static FontNameProperties old_props;
472 FontNameProperties *props;
479 props = get_font_name_props(screen->display, screen->fnts[fNorm].fs, 0);
483 pixel_size = props->pixel_size;
484 res_x = props->res_x;
485 res_y = props->res_y;
489 weight = props->weight;
491 if (CSET_DOUBLE(chrset))
494 if (chrset == CSET_DHL_TOP
495 || chrset == CSET_DHL_BOT) {
500 if (old_props.res_x != res_x
501 || old_props.res_x != res_y
502 || old_props.pixel_size != pixel_size
503 || strcmp(old_props.spacing, props->spacing)) {
504 TRACE(("xtermSpecialFont(atts = %#x, chrset = %#x)\n", atts, chrset));
505 TRACE(("res_x = %d\n", res_x));
506 TRACE(("res_y = %d\n", res_y));
507 TRACE(("point_size = %s\n", props->point_size));
508 TRACE(("pixel_size = %d\n", pixel_size));
509 TRACE(("spacing = %s\n", props->spacing));
510 old_props.res_x = res_x;
511 old_props.res_x = res_y;
512 old_props.pixel_size = pixel_size;
513 old_props.spacing = strcpy(old_spacing, props->spacing);
517 append_fontname_str(&result, props->beginning);
518 append_fontname_str(&result, weight);
519 append_fontname_str(&result, props->slant);
520 append_fontname_str(&result, props->wideness);
521 append_fontname_str(&result, props->add_style);
522 append_fontname_num(&result, pixel_size);
523 append_fontname_str(&result, props->point_size);
524 append_fontname_num(&result, (atts & NORESOLUTION) ? -1 : res_x);
525 append_fontname_num(&result, (atts & NORESOLUTION) ? -1 : res_y);
526 append_fontname_str(&result, props->spacing);
527 append_fontname_str(&result, 0);
528 append_fontname_str(&result, props->end);
532 #endif /* OPT_DEC_CHRSET */
535 * Case-independent comparison for font-names, including wildcards.
536 * XLFD allows '?' as a wildcard, but we do not handle that (no one seems
540 same_font_name(const char *pattern, const char *match)
544 if (pattern && match) {
545 while (*pattern && *match) {
546 if (*pattern == *match) {
549 } else if (*pattern == '*' || *match == '*') {
550 if (same_font_name(pattern + 1, match)) {
552 } else if (same_font_name(pattern, match + 1)) {
558 int p = x_toupper(*pattern++);
559 int m = x_toupper(*match++);
564 result = (*pattern == *match); /* both should be NUL */
570 * Double-check the fontname that we asked for versus what the font server
571 * actually gave us. The larger fixed fonts do not always have a matching bold
572 * font, and the font server may try to scale another font or otherwise
573 * substitute a mismatched font.
575 * If we cannot get what we requested, we will fallback to the original
576 * behavior, which simulates bold by overstriking each character at one pixel
580 got_bold_font(Display * dpy, XFontStruct * fs, String requested)
582 char actual[MAX_FONTNAME];
585 if (get_font_name_props(dpy, fs, actual) == 0)
588 got = same_font_name(requested, actual);
593 * If the font server tries to adjust another font, it may not adjust it
594 * properly. Check that the bounding boxes are compatible. Otherwise we'll
595 * leave trash on the display when we mix normal and bold fonts.
598 same_font_size(XtermWidget xw, XFontStruct * nfs, XFontStruct * bfs)
600 TScreen *screen = TScreenOf(xw);
601 TRACE(("same_font_size height %d/%d, min %d/%d max %d/%d\n",
602 nfs->ascent + nfs->descent,
603 bfs->ascent + bfs->descent,
604 nfs->min_bounds.width, bfs->min_bounds.width,
605 nfs->max_bounds.width, bfs->max_bounds.width));
606 return screen->free_bold_box
607 || ((nfs->ascent + nfs->descent) == (bfs->ascent + bfs->descent)
608 && (nfs->min_bounds.width == bfs->min_bounds.width
609 || nfs->min_bounds.width == bfs->min_bounds.width + 1)
610 && (nfs->max_bounds.width == bfs->max_bounds.width
611 || nfs->max_bounds.width == bfs->max_bounds.width + 1));
615 * Check if the font looks like it has fixed width
618 is_fixed_font(XFontStruct * fs)
621 return (fs->min_bounds.width == fs->max_bounds.width);
626 * Check if the font looks like a double width font (i.e. contains
627 * characters of width X and 2X
631 is_double_width_font(XFontStruct * fs)
633 return ((2 * fs->min_bounds.width) == fs->max_bounds.width);
636 #define is_double_width_font(fs) 0
639 #if OPT_WIDE_CHARS && OPT_RENDERFONT && defined(HAVE_TYPE_FCCHAR32)
640 #define HALF_WIDTH_TEST_STRING "1234567890"
642 /* '1234567890' in Chinese characters in UTF-8 */
643 #define FULL_WIDTH_TEST_STRING "\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89" \
644 "\xe5\x9b\x9b\xe4\xba\x94" \
645 "\xef\xa7\x91\xe4\xb8\x83\xe5\x85\xab" \
646 "\xe4\xb9\x9d\xef\xa6\xb2"
648 /* '1234567890' in Korean script in UTF-8 */
649 #define FULL_WIDTH_TEST_STRING2 "\xec\x9d\xbc\xec\x9d\xb4\xec\x82\xbc" \
650 "\xec\x82\xac\xec\x98\xa4" \
651 "\xec\x9c\xa1\xec\xb9\xa0\xed\x8c\x94" \
652 "\xea\xb5\xac\xec\x98\x81"
654 #define HALF_WIDTH_CHAR1 0x0031 /* '1' */
655 #define HALF_WIDTH_CHAR2 0x0057 /* 'W' */
656 #define FULL_WIDTH_CHAR1 0x4E00 /* CJK Ideograph 'number one' */
657 #define FULL_WIDTH_CHAR2 0xAC00 /* Korean script syllable 'Ka' */
660 is_double_width_font_xft(Display * dpy, XftFont * font)
663 FcChar32 c1 = HALF_WIDTH_CHAR1, c2 = HALF_WIDTH_CHAR2;
664 char *fwstr = FULL_WIDTH_TEST_STRING;
665 char *hwstr = HALF_WIDTH_TEST_STRING;
667 /* Some Korean fonts don't have Chinese characters at all. */
668 if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR1)) {
669 if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR2))
670 return False; /* Not a CJK font */
671 else /* a Korean font without CJK Ideographs */
672 fwstr = FULL_WIDTH_TEST_STRING2;
675 XftTextExtents32(dpy, font, &c1, 1, &gi1);
676 XftTextExtents32(dpy, font, &c2, 1, &gi2);
677 if (gi1.xOff != gi2.xOff) /* Not a fixed-width font */
680 XftTextExtentsUtf8(dpy, font, (FcChar8 *) hwstr, (int) strlen(hwstr), &gi1);
681 XftTextExtentsUtf8(dpy, font, (FcChar8 *) fwstr, (int) strlen(fwstr), &gi2);
684 * fontconfig and Xft prior to 2.2(?) set the width of half-width
685 * characters identical to that of full-width character in CJK double-width
686 * (bi-width / monospace) font even though the former is half as wide as
687 * the latter. This was fixed sometime before the release of fontconfig
688 * 2.2 in early 2003. See
689 * http://bugzilla.mozilla.org/show_bug.cgi?id=196312
690 * In the meantime, we have to check both possibilities.
692 return ((2 * gi1.xOff == gi2.xOff) || (gi1.xOff == gi2.xOff));
695 #define is_double_width_font_xft(dpy, xftfont) 0
698 #define EmptyFont(fs) (fs != 0 \
699 && ((fs)->ascent + (fs)->descent == 0 \
700 || (fs)->max_bounds.width == 0))
702 #define FontSize(fs) (((fs)->ascent + (fs)->descent) \
703 * (fs)->max_bounds.width)
706 xtermFontName(const char *normal)
708 static VTFontNames data;
710 free((void *) data.f_n);
711 memset(&data, 0, sizeof(data));
712 data.f_n = x_strdup(normal);
717 cache_menu_font_name(TScreen * screen, int fontnum, int which, const char *name)
720 char *last = (char *) screen->menu_font_names[fontnum][which];
722 if (strcmp(last, name)) {
724 TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name));
725 screen->menu_font_names[fontnum][which] = x_strdup(name);
728 TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name));
729 screen->menu_font_names[fontnum][which] = x_strdup(name);
735 * Open the given font and verify that it is non-empty. Return a null on
739 xtermOpenFont(XtermWidget xw,
742 fontWarningTypes warn,
746 TScreen *screen = TScreenOf(xw);
748 if (!IsEmpty(name)) {
749 if ((result->fs = XLoadQueryFont(screen->display, name)) != 0) {
751 if (EmptyFont(result->fs)) {
752 (void) xtermCloseFont(xw, result);
755 result->fn = x_strdup(name);
757 } else if (XmuCompareISOLatin1(name, DEFFONT) != 0) {
758 if (warn <= xw->misc.fontWarnings
760 && !UsingRenderFont(xw)
763 TRACE(("OOPS: cannot load font %s\n", name));
764 fprintf(stderr, "%s: cannot load font '%s'\n", ProgramName, name);
767 * Do a sanity check in case someone's mixed up xterm with
768 * one of those programs that read their resource data from
771 if (strchr(name, ':') != 0 || strchr(name, '=') != 0) {
773 "Use the \"-fa\" option for the Xft fonts\n");
777 TRACE(("xtermOpenFont: cannot load font '%s'\n", name));
780 code = xtermOpenFont(xw, DEFFONT, result, fwAlways, True);
788 * Close the font and free the font info.
791 xtermCloseFont(XtermWidget xw, XTermFonts * fnt)
793 if (fnt != 0 && fnt->fs != 0) {
794 TScreen *screen = TScreenOf(xw);
796 clrCgsFonts(xw, WhichVWin(screen), fnt);
797 XFreeFont(screen->display, fnt->fs);
798 xtermFreeFontInfo(fnt);
804 * Close the listed fonts, noting that some may use copies of the pointer.
807 xtermCloseFonts(XtermWidget xw, XTermFonts * fnts)
811 for (j = 0; j < fMAX; ++j) {
813 * Need to save the pointer since xtermCloseFont zeroes it
815 XFontStruct *thisFont = fnts[j].fs;
817 xtermCloseFont(xw, &fnts[j]);
818 for (k = j + 1; k < fMAX; ++k) {
819 if (thisFont == fnts[k].fs)
820 xtermFreeFontInfo(&fnts[k]);
827 * Make a copy of the source, assuming the XFontStruct's to be unique, but
828 * ensuring that the names are reallocated to simplify freeing.
831 xtermCopyFontInfo(XTermFonts * target, XTermFonts * source)
833 xtermFreeFontInfo(target);
834 target->chrset = source->chrset;
835 target->flags = source->flags;
836 target->fn = x_strdup(source->fn);
837 target->fs = source->fs;
841 xtermFreeFontInfo(XTermFonts * target)
845 if (target->fn != 0) {
853 xtermLoadFont(XtermWidget xw,
854 const VTFontNames * fonts,
858 TScreen *screen = TScreenOf(xw);
859 VTwin *win = WhichVWin(screen);
862 FontNameProperties *fp;
863 XTermFonts fnts[fMAX];
866 char *tmpname = NULL;
867 char normal[MAX_FONTNAME];
868 Boolean proportional = False;
869 fontWarningTypes warn[fMAX];
872 memset(&myfonts, 0, sizeof(myfonts));
873 memset(fnts, 0, sizeof(fnts));
877 if (!check_fontname(myfonts.f_n))
881 * Check the font names against the resource values, to see which were
882 * derived in a previous call. If so, we'll only warn about those if
883 * the warning level is set to "always".
885 for (j = 0; j < fMAX; ++j) {
888 #define CmpResource(field, index) \
889 if (same_font_name(screen->menu_font_names[fontnum][index], myfonts.field)) \
890 warn[index] = fwResource
892 CmpResource(f_n, fNorm);
893 if (fontnum == fontMenu_default) {
894 CmpResource(f_b, fBold);
896 CmpResource(f_b, fWide);
897 CmpResource(f_b, fWBold);
901 if (fontnum == fontMenu_fontescape
902 && myfonts.f_n != screen->MenuFontName(fontnum)) {
903 if ((tmpname = x_strdup(myfonts.f_n)) == 0)
907 TRACE(("Begin Cgs - xtermLoadFont(%s)\n", myfonts.f_n));
908 releaseWindowGCs(xw, win);
910 #define DbgResource(name, field, index) \
911 TRACE(("xtermLoadFont #%d "name" %s%s\n", \
913 (warn[index] == fwResource) ? "*" : " ", \
914 NonNull(myfonts.field)))
915 DbgResource("normal", f_n, fNorm);
916 DbgResource("bold ", f_b, fBold);
918 DbgResource("wide ", f_w, fWide);
919 DbgResource("w/bold", f_wb, fWBold);
922 if (!xtermOpenFont(xw, myfonts.f_n, &fnts[fNorm], warn[fNorm], True))
925 strcpy(normal, myfonts.f_n);
926 if (!check_fontname(myfonts.f_b)) {
927 warn[fBold] = fwAlways;
928 fp = get_font_name_props(screen->display, fnts[fNorm].fs, normal);
930 myfonts.f_b = bold_font_name(fp, fp->average_width);
931 if (!xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], fwAlways, False)) {
932 myfonts.f_b = bold_font_name(fp, -1);
933 xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], fwAlways, False);
935 TRACE(("...derived bold '%s'\n", NonNull(myfonts.f_b)));
937 if (fp == 0 || fnts[fBold].fs == 0) {
938 xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]);
939 TRACE(("...cannot load a matching bold font\n"));
940 } else if (same_font_size(xw, fnts[fNorm].fs, fnts[fBold].fs)
941 && got_bold_font(screen->display, fnts[fBold].fs, myfonts.f_b)) {
942 TRACE(("...got a matching bold font\n"));
943 cache_menu_font_name(screen, fontnum, fBold, myfonts.f_b);
945 xtermCloseFont(xw, &fnts[fBold]);
946 fnts[fBold] = fnts[fNorm];
947 TRACE(("...did not get a matching bold font\n"));
949 } else if (!xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], warn[fBold], False)) {
950 xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]);
951 warn[fBold] = fwAlways;
952 TRACE(("...cannot load bold font '%s'\n", NonNull(myfonts.f_b)));
954 cache_menu_font_name(screen, fontnum, fBold, myfonts.f_b);
958 * If there is no widefont specified, fake it by doubling AVERAGE_WIDTH
959 * of normal fonts XLFD, and asking for it. This plucks out 18x18ja
960 * and 12x13ja as the corresponding fonts for 9x18 and 6x13.
962 if_OPT_WIDE_CHARS(screen, {
964 char bold[MAX_FONTNAME];
966 if (check_fontname(myfonts.f_w)) {
967 cache_menu_font_name(screen, fontnum, fWide, myfonts.f_w);
968 } else if (!is_double_width_font(fnts[fNorm].fs)) {
969 fp = get_font_name_props(screen->display, fnts[fNorm].fs, normal);
971 myfonts.f_w = wide_font_name(fp);
972 warn[fWide] = fwAlways;
973 TRACE(("...derived wide %s\n", NonNull(myfonts.f_w)));
974 cache_menu_font_name(screen, fontnum, fWide, myfonts.f_w);
978 if (check_fontname(myfonts.f_w)) {
979 (void) xtermOpenFont(xw, myfonts.f_w, &fnts[fWide], warn[fWide], False);
981 xtermCopyFontInfo(&fnts[fWide], &fnts[fNorm]);
982 warn[fWide] = fwAlways;
986 if (!check_fontname(myfonts.f_wb)) {
987 fp = get_font_name_props(screen->display, fnts[fBold].fs, bold);
989 myfonts.f_wb = widebold_font_name(fp);
990 warn[fWBold] = fwAlways;
995 if (check_fontname(myfonts.f_wb)) {
997 xtermOpenFont(xw, myfonts.f_wb, &fnts[fWBold], warn[fWBold], False);
1000 && !compatibleWideCounts(fnts[fWide].fs, fnts[fWBold].fs)) {
1001 xtermCloseFont(xw, &fnts[fWBold]);
1003 if (fnts[fWBold].fs == 0) {
1004 myfonts.f_wb = myfonts.f_w;
1005 warn[fWBold] = fwAlways;
1006 xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
1007 TRACE(("...cannot load wide-bold, use wide %s\n", NonNull(myfonts.f_w)));
1009 TRACE(("...%s wide/bold %s\n",
1010 derived ? "derived" : "given",
1011 NonNull(myfonts.f_wb)));
1012 cache_menu_font_name(screen, fontnum, fWBold, myfonts.f_wb);
1014 } else if (is_double_width_font(fnts[fBold].fs)) {
1015 xtermCopyFontInfo(&fnts[fWBold], &fnts[fBold]);
1016 warn[fWBold] = fwAlways;
1017 TRACE(("...bold font is double-width, use it %s\n", NonNull(myfonts.f_b)));
1019 xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
1020 warn[fWBold] = fwAlways;
1021 TRACE(("...cannot load wide bold font, use wide %s\n", NonNull(myfonts.f_w)));
1024 if (EmptyFont(fnts[fWBold].fs))
1025 goto bad; /* can't use a 0-sized font */
1029 * Most of the time this call to load the font will succeed, even if
1030 * there is no wide font : the X server doubles the width of the
1031 * normal font, or similar.
1033 * But if it did fail for some reason, then nevermind.
1035 if (EmptyFont(fnts[fBold].fs))
1036 goto bad; /* can't use a 0-sized font */
1038 if (!same_font_size(xw, fnts[fNorm].fs, fnts[fBold].fs)
1039 && (is_fixed_font(fnts[fNorm].fs) && is_fixed_font(fnts[fBold].fs))) {
1040 TRACE(("...ignoring mismatched normal/bold fonts\n"));
1041 xtermCloseFont(xw, &fnts[fBold]);
1042 xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]);
1045 if_OPT_WIDE_CHARS(screen, {
1046 if (fnts[fWide].fs != 0
1047 && fnts[fWBold].fs != 0
1048 && !same_font_size(xw, fnts[fWide].fs, fnts[fWBold].fs)
1049 && (is_fixed_font(fnts[fWide].fs) && is_fixed_font(fnts[fWBold].fs))) {
1050 TRACE(("...ignoring mismatched normal/bold wide fonts\n"));
1051 xtermCloseFont(xw, &fnts[fWBold]);
1052 xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
1057 * Normal/bold fonts should be the same width. Also, the min/max
1058 * values should be the same.
1060 if (!is_fixed_font(fnts[fNorm].fs)
1061 || !is_fixed_font(fnts[fBold].fs)
1062 || fnts[fNorm].fs->max_bounds.width != fnts[fBold].fs->max_bounds.width) {
1063 TRACE(("Proportional font! normal %d/%d, bold %d/%d\n",
1064 fnts[fNorm].fs->min_bounds.width,
1065 fnts[fNorm].fs->max_bounds.width,
1066 fnts[fBold].fs->min_bounds.width,
1067 fnts[fBold].fs->max_bounds.width));
1068 proportional = True;
1071 if_OPT_WIDE_CHARS(screen, {
1072 if (fnts[fWide].fs != 0
1073 && fnts[fWBold].fs != 0
1074 && (!is_fixed_font(fnts[fWide].fs)
1075 || !is_fixed_font(fnts[fWBold].fs)
1076 || fnts[fWide].fs->max_bounds.width != fnts[fWBold].fs->max_bounds.width)) {
1077 TRACE(("Proportional font! wide %d/%d, wide bold %d/%d\n",
1078 fnts[fWide].fs->min_bounds.width,
1079 fnts[fWide].fs->max_bounds.width,
1080 fnts[fWBold].fs->min_bounds.width,
1081 fnts[fWBold].fs->max_bounds.width));
1082 proportional = True;
1086 /* TODO : enforce that the width of the wide font is 2* the width
1087 of the narrow font */
1090 * If we're switching fonts, free the old ones. Otherwise we'll leak
1091 * the memory that is associated with the old fonts. The
1092 * XLoadQueryFont call allocates a new XFontStruct.
1094 xtermCloseFonts(xw, screen->fnts);
1096 xtermCopyFontInfo(&(screen->fnts[fNorm]), &fnts[fNorm]);
1097 xtermCopyFontInfo(&(screen->fnts[fBold]), &fnts[fBold]);
1099 xtermCopyFontInfo(&(screen->fnts[fWide]), &fnts[fWide]);
1100 if (fnts[fWBold].fs == NULL)
1101 xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]);
1102 xtermCopyFontInfo(&(screen->fnts[fWBold]), &fnts[fWBold]);
1105 new_normal = getXtermForeground(xw, xw->flags, xw->cur_foreground);
1106 new_revers = getXtermBackground(xw, xw->flags, xw->cur_background);
1108 setCgsFore(xw, win, gcNorm, new_normal);
1109 setCgsBack(xw, win, gcNorm, new_revers);
1110 setCgsFont(xw, win, gcNorm, &(screen->fnts[fNorm]));
1112 copyCgs(xw, win, gcBold, gcNorm);
1113 setCgsFont(xw, win, gcBold, &(screen->fnts[fBold]));
1115 setCgsFore(xw, win, gcNormReverse, new_revers);
1116 setCgsBack(xw, win, gcNormReverse, new_normal);
1117 setCgsFont(xw, win, gcNormReverse, &(screen->fnts[fNorm]));
1119 copyCgs(xw, win, gcBoldReverse, gcNormReverse);
1120 setCgsFont(xw, win, gcBoldReverse, &(screen->fnts[fBold]));
1122 if_OPT_WIDE_CHARS(screen, {
1123 if (screen->fnts[fWide].fs != 0
1124 && screen->fnts[fWBold].fs != 0) {
1125 setCgsFore(xw, win, gcWide, new_normal);
1126 setCgsBack(xw, win, gcWide, new_revers);
1127 setCgsFont(xw, win, gcWide, &(screen->fnts[fWide]));
1129 copyCgs(xw, win, gcWBold, gcWide);
1130 setCgsFont(xw, win, gcWBold, &(screen->fnts[fWBold]));
1132 setCgsFore(xw, win, gcWideReverse, new_revers);
1133 setCgsBack(xw, win, gcWideReverse, new_normal);
1134 setCgsFont(xw, win, gcWideReverse, &(screen->fnts[fWide]));
1136 copyCgs(xw, win, gcWBoldReverse, gcWideReverse);
1137 setCgsFont(xw, win, gcWBoldReverse, &(screen->fnts[fWBold]));
1142 screen->allow_packing = proportional;
1143 setupPackedFonts(xw);
1145 screen->fnt_prop = (Boolean) (proportional && !(screen->force_packed));
1146 screen->fnt_boxes = True;
1150 * Xterm uses character positions 1-31 of a font for the line-drawing
1151 * characters. Check that they are all present. The null character
1152 * (0) is special, and is not used.
1155 if (UsingRenderFont(xw)) {
1157 * FIXME: we shouldn't even be here if we're using Xft.
1159 screen->fnt_boxes = False;
1160 TRACE(("assume Xft missing line-drawing chars\n"));
1166 for (ch = 1; ch < 32; ch++) {
1169 if (screen->utf8_mode || screen->unicode_font) {
1175 if (IsXtermMissingChar(screen, n, &fnts[fNorm])) {
1176 TRACE(("missing normal char #%d\n", n));
1177 screen->fnt_boxes = False;
1180 if (IsXtermMissingChar(screen, n, &fnts[fBold])) {
1181 TRACE(("missing bold char #%d\n", n));
1182 screen->fnt_boxes = False;
1187 TRACE(("Will %suse internal line-drawing characters\n",
1188 screen->fnt_boxes ? "not " : ""));
1191 if (screen->always_bold_mode) {
1192 screen->enbolden = screen->bold_mode;
1194 screen->enbolden = screen->bold_mode
1195 && ((fnts[fNorm].fs == fnts[fBold].fs)
1196 || same_font_name(normal, myfonts.f_b));
1198 TRACE(("Will %suse 1-pixel offset/overstrike to simulate bold\n",
1199 screen->enbolden ? "" : "not "));
1201 set_menu_font(False);
1202 screen->menu_font_number = fontnum;
1203 set_menu_font(True);
1204 if (tmpname) { /* if setting escape or sel */
1205 if (screen->MenuFontName(fontnum))
1206 free((void *) screen->MenuFontName(fontnum));
1207 screen->MenuFontName(fontnum) = tmpname;
1208 if (fontnum == fontMenu_fontescape) {
1209 SetItemSensitivity(fontMenuEntries[fontMenu_fontescape].widget,
1213 screen->menu_font_sizes[fontnum] = FontSize(fnts[fNorm].fs);
1217 xtermUpdateFontInfo(xw, doresize);
1218 TRACE(("Success Cgs - xtermLoadFont\n"));
1224 releaseWindowGCs(xw, win);
1226 xtermCloseFonts(xw, fnts);
1227 TRACE(("Fail Cgs - xtermLoadFont\n"));
1231 #if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS
1233 * Collect font-names that we can modify with the load-vt-fonts() action.
1236 VTFontNames default_font;
1237 String menu_font_names[fontMenu_lastBuiltin + 1][fMAX];
1240 #define MERGE_SUBFONT(src,dst,name) \
1241 if (IsEmpty(dst.name)) { \
1242 TRACE(("MERGE_SUBFONT " #dst "." #name " merge %s\n", NonNull(src.name))); \
1243 dst.name = src.name; \
1245 TRACE(("MERGE_SUBFONT " #dst "." #name " found %s\n", NonNull(dst.name))); \
1248 #define COPY_MENU_FONTS(src,dst) \
1249 TRACE(("COPY_MENU_FONTS " #src " to " #dst "\n")); \
1250 for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \
1251 for (m = 0; m < fMAX; ++m) { \
1252 dst.menu_font_names[n][m] = x_strdup(src.menu_font_names[n][m]); \
1257 * Load the "VT" font names from the given subresource name/class. These
1258 * correspond to the VT100 resources.
1261 xtermLoadVTFonts(XtermWidget xw, String myName, String myClass)
1263 static Bool initialized = False;
1264 static SubResourceRec original, referenceRec, subresourceRec;
1267 * These are duplicates of the VT100 font resources, but with a special
1268 * application/classname passed in to distinguish them.
1270 static XtResource font_resources[] =
1272 Sres(XtNfont, XtCFont, default_font.f_n, DEFFONT),
1273 Sres(XtNboldFont, XtCBoldFont, default_font.f_b, DEFBOLDFONT),
1275 Sres(XtNwideFont, XtCWideFont, default_font.f_w, DEFWIDEFONT),
1276 Sres(XtNwideBoldFont, XtCWideBoldFont, default_font.f_wb, DEFWIDEBOLDFONT),
1278 Sres(XtNfont1, XtCFont1, MenuFontName(fontMenu_font1), NULL),
1279 Sres(XtNfont2, XtCFont2, MenuFontName(fontMenu_font2), NULL),
1280 Sres(XtNfont3, XtCFont3, MenuFontName(fontMenu_font3), NULL),
1281 Sres(XtNfont4, XtCFont4, MenuFontName(fontMenu_font4), NULL),
1282 Sres(XtNfont5, XtCFont5, MenuFontName(fontMenu_font5), NULL),
1283 Sres(XtNfont6, XtCFont6, MenuFontName(fontMenu_font6), NULL),
1287 TScreen *screen = TScreenOf(xw);
1292 TRACE(("xtermLoadVTFonts saving original\n"));
1293 original.default_font = xw->misc.default_font;
1294 COPY_MENU_FONTS(xw->screen, original);
1297 if (IsEmpty(myName)) {
1298 TRACE(("xtermLoadVTFonts restoring original\n"));
1299 xw->misc.default_font = original.default_font;
1300 COPY_MENU_FONTS(original, xw->screen);
1301 for (n = 0; n < XtNumber(original.menu_font_names); ++n)
1302 screen->MenuFontName(n) = original.MenuFontName(n);
1304 TRACE(("xtermLoadVTFonts(%s, %s)\n", myName, myClass));
1306 memset(&subresourceRec, 0, sizeof(subresourceRec));
1307 XtGetSubresources((Widget) xw, (XtPointer) &subresourceRec,
1310 (Cardinal) XtNumber(font_resources),
1311 NULL, (Cardinal) 0);
1313 if (memcmp(&referenceRec, &subresourceRec, sizeof(referenceRec))) {
1316 * If a particular resource value was not found, use the original.
1318 MERGE_SUBFONT(xw->misc, subresourceRec, default_font.f_n);
1319 MERGE_SUBFONT(xw->misc, subresourceRec, default_font.f_b);
1321 MERGE_SUBFONT(xw->misc, subresourceRec, default_font.f_w);
1322 MERGE_SUBFONT(xw->misc, subresourceRec, default_font.f_wb);
1324 for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n)
1325 MERGE_SUBFONT(xw->screen, subresourceRec, MenuFontName(n));
1328 * Finally, copy the subresource data to the widget.
1330 xw->misc.default_font = subresourceRec.default_font;
1331 COPY_MENU_FONTS(subresourceRec, xw->screen);
1332 screen->MenuFontName(fontMenu_default) = x_strdup(xw->misc.default_font.f_n);
1333 screen->menu_font_names[0][fBold] = x_strdup(xw->misc.default_font.f_b);
1335 screen->menu_font_names[0][fWide] = x_strdup(xw->misc.default_font.f_w);
1336 screen->menu_font_names[0][fWBold] = x_strdup(xw->misc.default_font.f_wb);
1339 TRACE(("...no resources found\n"));
1348 isWideFont(XFontStruct * fp, const char *tag, Bool nullOk)
1350 Bool result = False;
1354 unsigned count = countGlyphs(fp);
1355 TRACE(("isWideFont(%s) found %d cells\n", tag, count));
1356 result = (count > 256) ? True : False;
1364 * If the current fonts are not wide, load the UTF8 fonts.
1366 * Called during initialization (for wide-character mode), the fonts have not
1367 * been setup, so we pass nullOk=True to isWideFont().
1369 * Called after initialization, e.g., in response to the UTF-8 menu entry
1370 * (starting from narrow character mode), it checks if the fonts are not wide.
1373 xtermLoadWideFonts(XtermWidget xw, Bool nullOk)
1375 TScreen *screen = TScreenOf(xw);
1378 if (EmptyFont(screen->fnts[fWide].fs)) {
1379 result = (isWideFont(screen->fnts[fNorm].fs, "normal", nullOk)
1380 && isWideFont(screen->fnts[fBold].fs, "bold", nullOk));
1382 result = (isWideFont(screen->fnts[fWide].fs, "wide", nullOk)
1383 && isWideFont(screen->fnts[fWBold].fs, "wide-bold", nullOk));
1384 if (result && !screen->utf8_latin1) {
1385 result = (isWideFont(screen->fnts[fNorm].fs, "normal", nullOk)
1386 && isWideFont(screen->fnts[fBold].fs, "bold", nullOk));
1390 TRACE(("current fonts are not all wide%s\n", nullOk ? " nullOk" : ""));
1391 result = xtermLoadVTFonts(xw, "utf8Fonts", "Utf8Fonts");
1393 TRACE(("xtermLoadWideFonts:%d\n", result));
1396 #endif /* OPT_WIDE_CHARS */
1399 * Restore the default fonts, i.e., if we had switched to wide-fonts.
1402 xtermLoadDefaultFonts(XtermWidget xw)
1405 result = xtermLoadVTFonts(xw, NULL, NULL);
1406 TRACE(("xtermLoadDefaultFonts:%d\n", result));
1409 #endif /* OPT_LOAD_VTFONTS || OPT_WIDE_CHARS */
1411 #if OPT_LOAD_VTFONTS
1413 HandleLoadVTFonts(Widget w,
1414 XEvent * event GCC_UNUSED,
1415 String * params GCC_UNUSED,
1416 Cardinal *param_count GCC_UNUSED)
1418 static char empty[] = ""; /* appease strict compilers */
1422 if ((xw = getXtermWidget(w)) != 0) {
1423 TScreen *screen = TScreenOf(xw);
1426 String name = (String) ((*param_count > 0) ? params[0] : empty);
1427 char *myName = (char *) MyStackAlloc(strlen(name), name_buf);
1428 String convert = (String) ((*param_count > 1) ? params[1] : myName);
1429 char *myClass = (char *) MyStackAlloc(strlen(convert), class_buf);
1432 TRACE(("HandleLoadVTFonts(%d)\n", *param_count));
1433 strcpy(myName, name);
1434 strcpy(myClass, convert);
1435 if (*param_count == 1)
1436 myClass[0] = x_toupper(myClass[0]);
1438 if (xtermLoadVTFonts(xw, myName, myClass)) {
1440 * When switching fonts, try to preserve the font-menu selection, since
1441 * it is less surprising to do that (if the font-switching can be
1442 * undone) than to switch to "Default".
1444 int font_number = screen->menu_font_number;
1445 if (font_number > fontMenu_lastBuiltin)
1446 font_number = fontMenu_lastBuiltin;
1447 for (n = 0; n < NMENUFONTS; ++n)
1448 screen->menu_font_sizes[n] = 0;
1449 SetVTFont(xw, font_number, True,
1450 ((font_number == fontMenu_default)
1451 ? &(xw->misc.default_font)
1455 MyStackFree(myName, name_buf);
1456 MyStackFree(myClass, class_buf);
1459 #endif /* OPT_LOAD_VTFONTS */
1462 * Set the limits for the box that outlines the cursor.
1465 xtermSetCursorBox(TScreen * screen)
1467 static XPoint VTbox[NBOX];
1469 int fw = FontWidth(screen) - 1;
1470 int fh = FontHeight(screen) - 1;
1471 int hh = screen->cursor_underline ? 1 : fh;
1474 (vp++)->x = (short) fw;
1475 (vp++)->y = (short) hh;
1476 (vp++)->x = (short) -fw;
1477 vp->y = (short) -hh;
1479 screen->box = VTbox;
1482 #define CACHE_XFT(dst,src) if (src != 0) {\
1483 checkXft(xw, &(dst[fontnum]), src);\
1484 TRACE(("Xft metrics %s[%d] = %d (%d,%d) advance %d, actual %d%s\n",\
1490 src->max_advance_width,\
1491 dst[fontnum].map.min_width,\
1492 dst[fontnum].map.mixed ? " mixed" : ""));\
1499 xtermXftFirstChar(XftFont * xft)
1501 FcChar32 map[FC_CHARSET_MAP_SIZE];
1506 first = FcCharSetFirstPage(xft->charset, map, &next);
1507 for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
1509 FcChar32 bits = map[i];
1511 while (!(bits & 0x1)) {
1521 xtermXftLastChar(XftFont * xft)
1523 FcChar32 this, last, next;
1524 FcChar32 map[FC_CHARSET_MAP_SIZE];
1526 last = FcCharSetFirstPage(xft->charset, map, &next);
1527 while ((this = FcCharSetNextPage(xft->charset, map, &next)) != FC_CHARSET_DONE)
1530 for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--)
1532 FcChar32 bits = map[i];
1533 last += i * 32 + 31;
1534 while (!(bits & 0x80000000)) {
1544 dumpXft(XtermWidget xw, XTermXftFonts * data)
1546 XftFont *xft = data->font;
1547 TScreen *screen = TScreenOf(xw);
1548 VTwin *win = WhichVWin(screen);
1551 FcChar32 first = xtermXftFirstChar(xft);
1552 FcChar32 last = xtermXftLastChar(xft);
1554 unsigned outside = 0;
1556 TRACE(("dumpXft {{\n"));
1557 TRACE((" data range %#6x..%#6x\n", first, last));
1558 for (c = first; c <= last; ++c) {
1559 if (FcCharSetHasChar(xft->charset, c)) {
1560 int width = my_wcwidth((int) c);
1563 XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents);
1564 TRACE(("%#6x %2d %.1f\n", c, width,
1565 ((double) extents.width) / win->f_width));
1566 if (extents.width > win->f_width)
1571 TRACE(("}} %u total, %u outside\n", count, outside));
1573 #define DUMP_XFT(xw, data) dumpXft(xw, data)
1575 #define DUMP_XFT(xw, data) /* nothing */
1579 checkXft(XtermWidget xw, XTermXftFonts * data, XftFont * xft)
1582 Dimension width = 0;
1585 data->map.min_width = 0;
1586 data->map.max_width = (Dimension) xft->max_advance_width;
1589 * For each ASCII or ISO-8859-1 printable code, ask what its width is.
1590 * Given the maximum width for those, we have a reasonable estimate of
1591 * the single-column width.
1593 * Ignore control characters - their extent information is misleading.
1595 for (c = 32; c < 256; ++c) {
1596 if (c >= 127 && c <= 159)
1598 if (FcCharSetHasChar(xft->charset, c)) {
1601 XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents);
1602 if (width < extents.width && extents.width <= data->map.max_width) {
1603 width = extents.width;
1607 data->map.min_width = width;
1608 data->map.mixed = (data->map.max_width >= (data->map.min_width + 1));
1612 xtermOpenXft(XtermWidget xw, const char *name, XftPattern * pat, const char *tag)
1614 TScreen *screen = TScreenOf(xw);
1615 Display *dpy = screen->display;
1618 XftFont *result = 0;
1621 match = XftFontMatch(dpy, DefaultScreen(dpy), pat, &status);
1623 result = XftFontOpenPattern(dpy, match);
1625 TRACE(("...matched %s font\n", tag));
1627 TRACE(("...could did not open %s font\n", tag));
1628 XftPatternDestroy(match);
1629 if (xw->misc.fontWarnings >= fwAlways) {
1630 TRACE(("OOPS cannot open %s font \"%s\"\n", tag, name));
1631 fprintf(stderr, "%s: cannot open %s font \"%s\"\n",
1632 ProgramName, tag, name);
1636 TRACE(("...did not match %s font\n", tag));
1637 if (xw->misc.fontWarnings >= fwResource) {
1638 TRACE(("OOPS: cannot match %s font \"%s\"\n", tag, name));
1639 fprintf(stderr, "%s: cannot match %s font \"%s\"\n",
1640 ProgramName, tag, name);
1651 * Don't make a dependency on the math library for a single function.
1655 mySquareRoot(double value)
1657 double result = 0.0;
1660 double older = value;
1661 for (n = 0; n < 10; ++n) {
1662 double delta = (older * older - value) / (2.0 * older);
1663 double newer = older - delta;
1666 if (delta > -0.001 && delta < 0.001)
1675 * Given the Xft font metrics, determine the actual font size. This is used
1676 * for each font to ensure that normal, bold and italic fonts follow the same
1680 setRenderFontsize(TScreen * screen, VTwin * win, XftFont * font, const char *tag)
1683 int width, height, ascent, descent;
1687 width = font->max_advance_width;
1688 height = font->height;
1689 ascent = font->ascent;
1690 descent = font->descent;
1691 if (height < ascent + descent) {
1692 TRACE(("...increase height from %d\n", height));
1693 height = ascent + descent;
1695 if (is_double_width_font_xft(screen->display, font)) {
1696 TRACE(("...reduced width from %d\n", width));
1700 win->f_width = width;
1701 win->f_height = height;
1702 win->f_ascent = ascent;
1703 win->f_descent = descent;
1704 TRACE(("setRenderFontsize result %dx%d (%d+%d)\n",
1705 width, height, ascent, descent));
1706 } else if (win->f_width < width ||
1707 win->f_height < height ||
1708 win->f_ascent < ascent ||
1709 win->f_descent < descent) {
1710 TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n",
1712 win->f_width, win->f_height, win->f_ascent, win->f_descent,
1713 width, height, ascent, descent));
1715 win->f_width = width;
1716 win->f_height = height;
1717 win->f_ascent = ascent;
1718 win->f_descent = descent;
1720 TRACE(("setRenderFontsize %s unchanged\n", tag));
1727 checkFontInfo(int value, const char *tag)
1731 "Selected font has no non-zero %s for ISO-8859-1 encoding\n", tag);
1738 xtermCloseXft(TScreen * screen, XTermXftFonts * pub)
1740 if (pub->font != 0) {
1741 XftFontClose(screen->display, pub->font);
1747 * Get the faceName/faceDoublesize resource setting. Strip off "xft:", which
1748 * is not recognized by XftParseName().
1751 getFaceName(XtermWidget xw, Bool wideName GCC_UNUSED)
1754 String result = (wideName
1755 ? xw->misc.face_wide_name
1756 : xw->misc.face_name);
1758 String result = xw->misc.face_name;
1760 if (!IsEmpty(result) && !strncmp(result, "xft:", (size_t) 4))
1762 return x_nonempty(result);
1766 * If we change the faceName, we'll have to re-acquire all of the fonts that
1767 * are derived from it.
1770 setFaceName(XtermWidget xw, const char *value)
1772 TScreen *screen = TScreenOf(xw);
1775 xw->misc.face_name = x_strdup(value);
1776 for (n = 0; n < NMENUFONTS; ++n) {
1777 xw->misc.face_size[n] = -1.0;
1778 xtermCloseXft(screen, &(screen->renderFontNorm[n]));
1779 xtermCloseXft(screen, &(screen->renderFontBold[n]));
1780 xtermCloseXft(screen, &(screen->renderFontBold[n]));
1782 xtermCloseXft(screen, &(screen->renderWideNorm[n]));
1783 xtermCloseXft(screen, &(screen->renderWideBold[n]));
1784 xtermCloseXft(screen, &(screen->renderWideItal[n]));
1791 * Compute useful values for the font/window sizes
1794 xtermComputeFontInfo(XtermWidget xw,
1799 TScreen *screen = TScreenOf(xw);
1801 int i, j, width, height;
1803 int fontnum = screen->menu_font_number;
1808 * xterm contains a lot of references to fonts, assuming they are fixed
1809 * size. This chunk of code overrides the actual font-selection (see
1810 * drawXtermText()), if the user has selected render-font. All of the
1811 * font-loading for fixed-fonts still goes on whether or not this chunk
1814 if (UsingRenderFont(xw) && fontnum >= 0) {
1815 String face_name = getFaceName(xw, False);
1816 XftFont *norm = screen->renderFontNorm[fontnum].font;
1817 XftFont *bold = screen->renderFontBold[fontnum].font;
1818 XftFont *ital = screen->renderFontItal[fontnum].font;
1820 XftFont *wnorm = screen->renderWideNorm[fontnum].font;
1821 XftFont *wbold = screen->renderWideBold[fontnum].font;
1822 XftFont *wital = screen->renderWideItal[fontnum].font;
1825 if (norm == 0 && face_name) {
1827 double face_size = xw->misc.face_size[fontnum];
1829 TRACE(("xtermComputeFontInfo font %d: norm(face %s, size %f)\n",
1831 xw->misc.face_size[fontnum]));
1833 if (face_size <= 0.0) {
1836 * If the user is switching font-sizes, make it follow by
1837 * default the same ratios to the default as the fixed fonts
1838 * would, for easy comparison. There will be some differences
1839 * since the fixed fonts have a variety of height/width ratios,
1840 * but this is simpler than adding another resource value - and
1841 * as noted above, the data for the fixed fonts are available.
1843 lookupOneFontSize(xw, 0);
1844 lookupOneFontSize(xw, fontnum);
1845 if (fontnum == fontMenu_default) {
1849 long num = screen->menu_font_sizes[fontnum];
1850 long den = screen->menu_font_sizes[0];
1854 ratio = mySquareRoot((double) num / (double) den);
1856 face_size = (ratio * xw->misc.face_size[0]);
1857 TRACE(("scaled using %3ld/%ld = %.2f -> %f\n",
1858 num, den, ratio, face_size));
1862 case fontMenu_font1:
1865 case fontMenu_font2:
1868 case fontMenu_font3:
1874 case fontMenu_font4:
1877 case fontMenu_font5:
1880 case fontMenu_font6:
1885 xw->misc.face_size[fontnum] = (float) face_size;
1889 * By observation (there is no documentation), XftPatternBuild is
1890 * cumulative. Build the bold- and italic-patterns on top of the
1893 #define NormXftPattern \
1894 XFT_FAMILY, XftTypeString, "mono", \
1895 XFT_SIZE, XftTypeDouble, face_size, \
1896 XFT_SPACING, XftTypeInteger, XFT_MONO
1898 #define BoldXftPattern(norm) \
1899 XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \
1900 XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width
1902 #define ItalXftPattern(norm) \
1903 XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \
1904 XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width
1906 if ((pat = XftNameParse(face_name)) != 0) {
1907 #define OPEN_XFT(tag) xtermOpenXft(xw, face_name, pat, tag)
1908 XftPatternBuild(pat,
1911 norm = OPEN_XFT("normal");
1914 XftPatternBuild(pat,
1915 BoldXftPattern(norm),
1917 bold = OPEN_XFT("bold");
1920 if (screen->italicULMode
1921 && (pat = XftNameParse(face_name)) != 0) {
1922 XftPatternBuild(pat,
1924 ItalXftPattern(norm),
1926 ital = OPEN_XFT("italic");
1928 #endif /* OPT_ISO_COLORS */
1932 * FIXME: just assume that the corresponding font has no
1933 * graphics characters.
1935 if (screen->fnt_boxes) {
1936 screen->fnt_boxes = False;
1937 TRACE(("Xft opened - will %suse internal line-drawing characters\n",
1938 screen->fnt_boxes ? "not " : ""));
1942 XftPatternDestroy(pat);
1945 CACHE_XFT(screen->renderFontNorm, norm);
1946 CACHE_XFT(screen->renderFontBold, bold);
1947 CACHE_XFT(screen->renderFontItal, ital);
1950 * See xtermXftDrawString().
1953 if (norm != 0 && screen->wide_chars) {
1954 int char_width = norm->max_advance_width * 2;
1956 double aspect = ((xw->misc.face_wide_name
1957 || screen->renderFontNorm[fontnum].map.mixed)
1962 face_name = getFaceName(xw, True);
1963 TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n",
1967 #define WideXftPattern \
1968 XFT_FAMILY, XftTypeString, "mono", \
1969 XFT_SIZE, XftTypeDouble, face_size, \
1970 XFT_SPACING, XftTypeInteger, XFT_MONO
1972 if (face_name && (pat = XftNameParse(face_name)) != 0) {
1973 #define OPEN_XFT(tag) xtermOpenXft(xw, face_name, pat, tag)
1974 XftPatternBuild(pat,
1976 XFT_CHAR_WIDTH, XftTypeInteger, char_width,
1978 FC_ASPECT, XftTypeDouble, aspect,
1981 wnorm = OPEN_XFT("wide");
1984 XftPatternBuild(pat,
1986 BoldXftPattern(wnorm),
1988 wbold = OPEN_XFT("wide-bold");
1991 if (screen->italicULMode
1992 && (pat = XftNameParse(face_name)) != 0) {
1993 XftPatternBuild(pat,
1995 ItalXftPattern(wnorm),
1997 wital = OPEN_XFT("wide-italic");
2002 XftPatternDestroy(pat);
2005 CACHE_XFT(screen->renderWideNorm, wnorm);
2006 CACHE_XFT(screen->renderWideBold, wbold);
2007 CACHE_XFT(screen->renderWideItal, wital);
2009 #endif /* OPT_RENDERWIDE */
2012 TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum));
2013 xw->misc.render_font = False;
2014 update_font_renderfont();
2015 /* now we will fall through into the bitmap fonts */
2017 setRenderFontsize(screen, win, norm, NULL);
2018 setRenderFontsize(screen, win, bold, "bold");
2019 setRenderFontsize(screen, win, ital, "ital");
2021 setupPackedFonts(xw);
2023 if (screen->force_packed) {
2024 XTermXftFonts *use = &(screen->renderFontNorm[fontnum]);
2025 win->f_height = use->font->ascent + use->font->descent;
2026 win->f_width = use->map.min_width;
2027 TRACE(("...packed TrueType font %dx%d vs %d\n",
2030 use->map.max_width));
2033 DUMP_XFT(xw, &(screen->renderFontNorm[fontnum]));
2037 * Are we handling a bitmap font?
2040 #endif /* OPT_RENDERFONT */
2042 if (is_double_width_font(font) && !(screen->fnt_prop)) {
2043 win->f_width = (font->min_bounds.width);
2045 win->f_width = (font->max_bounds.width);
2047 win->f_height = (font->ascent + font->descent);
2048 win->f_ascent = font->ascent;
2049 win->f_descent = font->descent;
2051 i = 2 * screen->border + sbwidth;
2052 j = 2 * screen->border;
2053 width = MaxCols(screen) * win->f_width + i;
2054 height = MaxRows(screen) * win->f_height + j;
2055 win->fullwidth = (Dimension) width;
2056 win->fullheight = (Dimension) height;
2057 win->width = width - i;
2058 win->height = height - j;
2060 TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n",
2070 checkFontInfo(win->f_height, "height");
2071 checkFontInfo(win->f_width, "width");
2074 /* save this information as a side-effect for double-sized characters */
2076 xtermSaveFontInfo(TScreen * screen, XFontStruct * font)
2078 screen->fnt_wide = (Dimension) (font->max_bounds.width);
2079 screen->fnt_high = (Dimension) (font->ascent + font->descent);
2080 TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide));
2084 * After loading a new font, update the structures that use its size.
2087 xtermUpdateFontInfo(XtermWidget xw, Bool doresize)
2089 TScreen *screen = TScreenOf(xw);
2091 int scrollbar_width;
2092 VTwin *win = &(screen->fullVwin);
2094 scrollbar_width = (xw->misc.scrollbar
2095 ? (screen->scrollWidget->core.width +
2096 BorderWidth(screen->scrollWidget))
2098 xtermComputeFontInfo(xw, win, screen->fnts[fNorm].fs, scrollbar_width);
2099 xtermSaveFontInfo(screen, screen->fnts[fNorm].fs);
2102 if (VWindow(screen)) {
2105 TRACE(("xtermUpdateFontInfo {{\n"));
2106 DoResizeScreen(xw); /* set to the new natural size */
2107 ResizeScrollBar(xw);
2109 TRACE(("... }} xtermUpdateFontInfo\n"));
2110 #ifdef SCROLLBAR_RIGHT
2111 updateRightScrollbar(xw);
2114 xtermSetCursorBox(screen);
2120 * Returns true if the given character is missing from the specified font.
2123 xtermMissingChar(unsigned ch, XTermFonts * font)
2125 Bool result = False;
2126 XFontStruct *fs = font->fs;
2127 static XCharStruct dft, *tmp = &dft, *pc = 0;
2129 if (fs->max_byte1 == 0) {
2132 TRACE(("xtermMissingChar %#04x (row)\n", ch));
2136 CI_GET_CHAR_INFO_1D(fs, E2A(ch), tmp, pc);
2140 CI_GET_CHAR_INFO_2D(fs, HI_BYTE(ch), LO_BYTE(ch), tmp, pc);
2145 return False; /* Urgh! */
2148 if (CI_NONEXISTCHAR(pc)) {
2149 TRACE(("xtermMissingChar %#04x (!exists)\n", ch));
2153 font->known_missing[ch] = (Char) (result ? 2 : 1);
2159 * The grid is arbitrary, enough resolution that nothing's lost in
2165 #define MID_HIGH (BOX_HIGH/2)
2166 #define MID_WIDE (BOX_WIDE/2)
2168 #define CHR_WIDE ((9*BOX_WIDE)/10)
2169 #define CHR_HIGH ((9*BOX_HIGH)/10)
2172 * ...since we'll scale the values anyway.
2174 #define SCALE_X(n) n = (n * (((int) font_width) - 1)) / (BOX_WIDE-1)
2175 #define SCALE_Y(n) n = (n * (((int) font_height) - 1)) / (BOX_HIGH-1)
2177 #define SEG(x0,y0,x1,y1) x0,y0, x1,y1
2180 * Draw the given graphic character, if it is simple enough (i.e., a
2181 * line-drawing character).
2184 xtermDrawBoxChar(XtermWidget xw,
2192 TScreen *screen = TScreenOf(xw);
2194 static const short glyph_ht[] = {
2195 SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,5*MID_HIGH/6), /* H */
2196 SEG(6*BOX_WIDE/10, 0, 6*BOX_WIDE/10,5*MID_HIGH/6),
2197 SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12),
2198 SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */
2199 SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH),
2202 SEG(1*BOX_WIDE/10, 0, 6*BOX_WIDE/10, 0), /* F */
2203 SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12),
2204 SEG(1*BOX_WIDE/10, 0, 0*BOX_WIDE/3, 5*MID_HIGH/6),
2205 SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */
2206 SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
2207 SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH),
2210 SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,9*MID_HIGH/12), /* L */
2211 SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12),
2212 SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */
2213 SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6),
2214 SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH),
2217 SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10, 0), /* N */
2218 SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/6, 5*MID_HIGH/6),
2219 SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6, 0),
2220 SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), /* L */
2221 SEG(1*BOX_WIDE/3, CHR_HIGH, CHR_WIDE, CHR_HIGH),
2224 SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/12,5*MID_HIGH/6), /* V */
2225 SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6, 0),
2226 SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */
2227 SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH),
2229 }, plus_or_minus[] =
2231 SEG( 0, 5*BOX_HIGH/6, CHR_WIDE, 5*BOX_HIGH/6),
2232 SEG( MID_WIDE, 2*BOX_HIGH/6, MID_WIDE, 4*BOX_HIGH/6),
2233 SEG( 0, 3*BOX_HIGH/6, CHR_WIDE, 3*BOX_HIGH/6),
2235 }, lower_right_corner[] =
2237 SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH),
2238 SEG( MID_WIDE, MID_HIGH, MID_WIDE, 0),
2240 }, upper_right_corner[] =
2242 SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH),
2243 SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH),
2245 }, upper_left_corner[] =
2247 SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH),
2248 SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH),
2250 }, lower_left_corner[] =
2252 SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH),
2253 SEG( MID_WIDE, MID_WIDE, BOX_WIDE, MID_HIGH),
2257 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH),
2258 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH),
2262 SEG( 0, 0, BOX_WIDE, 0),
2266 SEG( 0, BOX_HIGH/4, BOX_WIDE, BOX_HIGH/4),
2270 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH),
2274 SEG( 0, 3*BOX_HIGH/4, BOX_WIDE, 3*BOX_HIGH/4),
2276 }, horizontal_line[] =
2278 SEG( 0, BOX_HIGH, BOX_WIDE, BOX_HIGH),
2282 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH),
2283 SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH),
2287 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH),
2288 SEG( MID_WIDE, MID_HIGH, 0, MID_HIGH),
2292 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH),
2293 SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH),
2297 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH),
2298 SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH),
2300 }, vertical_line[] =
2302 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH),
2304 }, less_than_or_equal[] =
2306 SEG( CHR_WIDE, BOX_HIGH/3, 0, MID_HIGH),
2307 SEG( CHR_WIDE, 2*BOX_HIGH/3, 0, MID_HIGH),
2308 SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4),
2310 }, greater_than_or_equal[] =
2312 SEG( 0, BOX_HIGH/3, CHR_WIDE, MID_HIGH),
2313 SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, MID_HIGH),
2314 SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4),
2318 SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH),
2319 SEG(5*CHR_WIDE/6, MID_HIGH, 5*CHR_WIDE/6, CHR_HIGH),
2320 SEG(2*CHR_WIDE/6, MID_HIGH, 2*CHR_WIDE/6, CHR_HIGH),
2324 SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3, CHR_HIGH),
2325 SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, 2*BOX_HIGH/3),
2326 SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH),
2331 static const short *lines[] =
2333 0, /* 00 (unused) */
2336 glyph_ht, /* 03 HT */
2337 glyph_ff, /* 04 FF */
2339 glyph_lf, /* 06 LF */
2340 0, /* 07 degrees (small circle) */
2341 plus_or_minus, /* 08 */
2344 lower_right_corner, /* 0B */
2345 upper_right_corner, /* 0C */
2346 upper_left_corner, /* 0D */
2347 lower_left_corner, /* 0E */
2349 scan_line_1, /* 10 */
2350 scan_line_3, /* 11 */
2351 scan_line_7, /* 12 */
2352 scan_line_9, /* 13 */
2353 horizontal_line, /* 14 */
2356 bottom_tee, /* 17 */
2358 vertical_line, /* 19 */
2359 less_than_or_equal, /* 1A */
2360 greater_than_or_equal, /* 1B */
2362 not_equal_to, /* 1D */
2368 CgsEnum cgsId = (ch == 2) ? gcDots : gcLine;
2369 VTwin *cgsWin = WhichVWin(screen);
2371 unsigned font_width = (unsigned) (((flags & DOUBLEWFONT) ? 2 : 1) * screen->fnt_wide);
2372 unsigned font_height = (unsigned) (((flags & DOUBLEHFONT) ? 2 : 1) * screen->fnt_high);
2375 font_width *= (unsigned) cells;
2379 * Try to show line-drawing characters if we happen to be in UTF-8
2380 * mode, but have gotten an old-style font.
2382 if (screen->utf8_mode
2384 && !UsingRenderFont(xw)
2387 && (ch != UCS_REPL)) {
2389 for (n = 1; n < 32; n++) {
2390 if (dec2ucs(n) == ch
2392 ? IsXtermMissingChar(screen, n, &screen->fnts[fBold])
2393 : IsXtermMissingChar(screen, n, &screen->fnts[fNorm]))) {
2394 TRACE(("...use xterm-style linedrawing\n"));
2402 TRACE(("DRAW_BOX(%d) cell %dx%d at %d,%d%s\n",
2403 ch, font_height, font_width, y, x,
2404 (ch >= (sizeof(lines) / sizeof(lines[0]))
2408 if (cgsId == gcDots) {
2409 setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2410 setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc));
2411 setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2413 setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2414 setCgsFore(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2415 setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2417 gc2 = getCgsGC(xw, cgsWin, cgsId);
2419 if (!(flags & NOBACKGROUND)) {
2420 XFillRectangle(screen->display, VWindow(screen), gc2, x, y,
2425 setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc));
2426 setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc));
2427 setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc));
2428 gc2 = getCgsGC(xw, cgsWin, cgsId);
2430 XSetLineAttributes(screen->display, gc2,
2432 ? ((font_height > 12)
2435 : ((font_height > 16)
2442 if (ch == 1) { /* diamond */
2446 points[0].x = MID_WIDE;
2447 points[0].y = BOX_HIGH / 4;
2449 points[1].x = 8 * BOX_WIDE / 8;
2450 points[1].y = MID_HIGH;
2452 points[2].x = points[0].x;
2453 points[2].y = 3 * BOX_HIGH / 4;
2455 points[3].x = 0 * BOX_WIDE / 8;
2456 points[3].y = points[1].y;
2458 points[4].x = points[0].x;
2459 points[4].y = points[0].y;
2461 for (n = 0; n < npoints; ++n) {
2462 SCALE_X(points[n].x);
2463 SCALE_Y(points[n].y);
2468 XFillPolygon(screen->display,
2469 VWindow(screen), gc2,
2471 Convex, CoordModeOrigin);
2472 } else if (ch == 7) { /* degrees */
2473 unsigned width = (BOX_WIDE / 3);
2474 int x_coord = MID_WIDE - (int) (width / 2);
2475 int y_coord = MID_HIGH - (int) width;
2481 XDrawArc(screen->display,
2482 VWindow(screen), gc2,
2483 x + x_coord, y + y_coord, width, width,
2486 } else if (ch == 0x1f) { /* bullet */
2487 unsigned width = 7 * BOX_WIDE / 10;
2488 int x_coord = MID_WIDE - (int) (width / 3);
2489 int y_coord = MID_HIGH - (int) (width / 3);
2495 XDrawArc(screen->display,
2496 VWindow(screen), gc2,
2497 x + x_coord, y + y_coord, width, width,
2500 } else if (ch < (sizeof(lines) / sizeof(lines[0]))
2501 && (p = lines[ch]) != 0) {
2511 XDrawLine(screen->display,
2512 VWindow(screen), gc2,
2513 x + coord[0], y + coord[1],
2514 x + coord[2], y + coord[3]);
2518 } else if (screen->force_all_chars) {
2519 /* bounding rectangle, for debugging */
2520 XDrawRectangle(screen->display, VWindow(screen), gc2, x, y,
2529 * Check if the given character has a glyph known to Xft.
2531 * see xc/lib/Xft/xftglyphs.c
2534 xtermXftMissing(XtermWidget xw, XftFont * font, unsigned wc)
2536 Bool result = False;
2539 TScreen *screen = TScreenOf(xw);
2540 if (!XftGlyphExists(screen->display, font, wc)) {
2542 TRACE(("xtermXftMissing %d (dec=%#x, ucs=%#x)\n",
2543 wc, ucs2dec(wc), dec2ucs(wc)));
2545 TRACE(("xtermXftMissing %d\n", wc));
2552 #endif /* OPT_RENDERFONT && OPT_WIDE_CHARS */
2554 #endif /* OPT_BOX_CHARS */
2557 #define MY_UCS(ucs,dec) case ucs: result = dec; break
2559 ucs2dec(unsigned ch)
2561 unsigned result = ch;
2563 && (ch != UCS_REPL)) {
2565 MY_UCS(0x25ae, 0); /* black vertical rectangle */
2566 MY_UCS(0x25c6, 1); /* black diamond */
2567 MY_UCS(0x2592, 2); /* medium shade */
2568 MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */
2569 MY_UCS(0x240c, 4); /* symbol for form feed */
2570 MY_UCS(0x240d, 5); /* symbol for carriage return */
2571 MY_UCS(0x240a, 6); /* symbol for line feed */
2572 MY_UCS(0x00b0, 7); /* degree sign */
2573 MY_UCS(0x00b1, 8); /* plus-minus sign */
2574 MY_UCS(0x2424, 9); /* symbol for newline */
2575 MY_UCS(0x240b, 10); /* symbol for vertical tabulation */
2576 MY_UCS(0x2518, 11); /* box drawings light up and left */
2577 MY_UCS(0x2510, 12); /* box drawings light down and left */
2578 MY_UCS(0x250c, 13); /* box drawings light down and right */
2579 MY_UCS(0x2514, 14); /* box drawings light up and right */
2580 MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */
2581 MY_UCS(0x23ba, 16); /* box drawings scan 1 */
2582 MY_UCS(0x23bb, 17); /* box drawings scan 3 */
2583 MY_UCS(0x2500, 18); /* box drawings light horizontal */
2584 MY_UCS(0x23bc, 19); /* box drawings scan 7 */
2585 MY_UCS(0x23bd, 20); /* box drawings scan 9 */
2586 MY_UCS(0x251c, 21); /* box drawings light vertical and right */
2587 MY_UCS(0x2524, 22); /* box drawings light vertical and left */
2588 MY_UCS(0x2534, 23); /* box drawings light up and horizontal */
2589 MY_UCS(0x252c, 24); /* box drawings light down and horizontal */
2590 MY_UCS(0x2502, 25); /* box drawings light vertical */
2591 MY_UCS(0x2264, 26); /* less-than or equal to */
2592 MY_UCS(0x2265, 27); /* greater-than or equal to */
2593 MY_UCS(0x03c0, 28); /* greek small letter pi */
2594 MY_UCS(0x2260, 29); /* not equal to */
2595 MY_UCS(0x00a3, 30); /* pound sign */
2596 MY_UCS(0x00b7, 31); /* middle dot */
2603 #define MY_UCS(ucs,dec) case dec: result = ucs; break
2606 dec2ucs(unsigned ch)
2608 unsigned result = ch;
2609 if (xtermIsDecGraphic(ch)) {
2611 MY_UCS(0x25ae, 0); /* black vertical rectangle */
2612 MY_UCS(0x25c6, 1); /* black diamond */
2613 MY_UCS(0x2592, 2); /* medium shade */
2614 MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */
2615 MY_UCS(0x240c, 4); /* symbol for form feed */
2616 MY_UCS(0x240d, 5); /* symbol for carriage return */
2617 MY_UCS(0x240a, 6); /* symbol for line feed */
2618 MY_UCS(0x00b0, 7); /* degree sign */
2619 MY_UCS(0x00b1, 8); /* plus-minus sign */
2620 MY_UCS(0x2424, 9); /* symbol for newline */
2621 MY_UCS(0x240b, 10); /* symbol for vertical tabulation */
2622 MY_UCS(0x2518, 11); /* box drawings light up and left */
2623 MY_UCS(0x2510, 12); /* box drawings light down and left */
2624 MY_UCS(0x250c, 13); /* box drawings light down and right */
2625 MY_UCS(0x2514, 14); /* box drawings light up and right */
2626 MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */
2627 MY_UCS(0x23ba, 16); /* box drawings scan 1 */
2628 MY_UCS(0x23bb, 17); /* box drawings scan 3 */
2629 MY_UCS(0x2500, 18); /* box drawings light horizontal */
2630 MY_UCS(0x23bc, 19); /* box drawings scan 7 */
2631 MY_UCS(0x23bd, 20); /* box drawings scan 9 */
2632 MY_UCS(0x251c, 21); /* box drawings light vertical and right */
2633 MY_UCS(0x2524, 22); /* box drawings light vertical and left */
2634 MY_UCS(0x2534, 23); /* box drawings light up and horizontal */
2635 MY_UCS(0x252c, 24); /* box drawings light down and horizontal */
2636 MY_UCS(0x2502, 25); /* box drawings light vertical */
2637 MY_UCS(0x2264, 26); /* less-than or equal to */
2638 MY_UCS(0x2265, 27); /* greater-than or equal to */
2639 MY_UCS(0x03c0, 28); /* greek small letter pi */
2640 MY_UCS(0x2260, 29); /* not equal to */
2641 MY_UCS(0x00a3, 30); /* pound sign */
2642 MY_UCS(0x00b7, 31); /* middle dot */
2648 #endif /* OPT_WIDE_CHARS */
2652 lookupOneFontSize(XtermWidget xw, int fontnum)
2654 TScreen *screen = TScreenOf(xw);
2656 if (screen->menu_font_sizes[fontnum] == 0) {
2659 memset(&fnt, 0, sizeof(fnt));
2660 screen->menu_font_sizes[fontnum] = -1;
2661 if (xtermOpenFont(xw, screen->MenuFontName(fontnum), &fnt, fwAlways, True)) {
2662 if (fontnum <= fontMenu_lastBuiltin
2663 || strcmp(fnt.fn, DEFFONT))
2664 screen->menu_font_sizes[fontnum] = FontSize(fnt.fs);
2665 xtermCloseFont(xw, &fnt);
2671 * Cache the font-sizes so subsequent larger/smaller font actions will go fast.
2674 lookupFontSizes(XtermWidget xw)
2678 for (n = 0; n < NMENUFONTS; n++) {
2679 lookupOneFontSize(xw, n);
2684 #define NMENU_RENDERFONTS (NMENUFONTS - 2) /* no selection or escape */
2686 useFaceSizes(XtermWidget xw)
2688 Boolean result = False;
2691 if (UsingRenderFont(xw)) {
2693 for (n = 0; n < NMENU_RENDERFONTS; ++n) {
2694 if (xw->misc.face_size[n] <= 0.0) {
2700 Boolean broken_fonts = True;
2701 TScreen *screen = TScreenOf(xw);
2702 long first = screen->menu_font_sizes[0];
2704 lookupFontSizes(xw);
2705 for (n = 0; n < NMENUFONTS; n++) {
2706 if (screen->menu_font_sizes[n] > 0
2707 && screen->menu_font_sizes[n] != first) {
2708 broken_fonts = False;
2714 * Workaround for breakage in font-packages - check if all of the
2715 * bitmap font sizes are the same, and if we're using TrueType
2719 float lo_value = (float) 9.0e9;
2720 float hi_value = (float) 0.0;
2723 TRACE(("bitmap fonts are broken - set faceSize resources\n"));
2724 for (n = 0; n < NMENUFONTS; n++) {
2725 value = xw->misc.face_size[n];
2727 if (lo_value > value)
2729 if (hi_value < value)
2734 if (hi_value <= 0.0)
2735 sscanf(DEFFACESIZE, "%f", &value);
2737 value = (float) ((hi_value + lo_value) / 2.0);
2739 value = (float) 14.0;
2741 for (n = 0; n < NMENUFONTS; n++) {
2742 TRACE(("setting faceSize%d %.1f\n", n, value));
2743 xw->misc.face_size[n] = value;
2744 value = (float) (value * 1.1);
2755 * Find the index of a larger/smaller font (according to the sign of 'relative'
2756 * and its magnitude), starting from the 'old' index.
2759 lookupRelativeFontSize(XtermWidget xw, int old, int relative)
2761 TScreen *screen = TScreenOf(xw);
2764 TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative));
2765 if (!IsIcon(screen)) {
2767 if (useFaceSizes(xw)) {
2768 TRACE(("...using FaceSize\n"));
2769 if (relative != 0) {
2770 for (n = 0; n < NMENU_RENDERFONTS; ++n) {
2771 if (xw->misc.face_size[n] > 0 &&
2772 xw->misc.face_size[n] != xw->misc.face_size[old]) {
2773 int cmp_0 = ((xw->misc.face_size[n] >
2774 xw->misc.face_size[old])
2777 int cmp_m = ((m < 0)
2779 : ((xw->misc.face_size[n] <
2780 xw->misc.face_size[m])
2783 if (cmp_0 > 0 && cmp_m > 0) {
2792 TRACE(("...using bitmap areas\n"));
2793 lookupFontSizes(xw);
2794 if (relative != 0) {
2795 for (n = 0; n < NMENUFONTS; ++n) {
2796 if (screen->menu_font_sizes[n] > 0 &&
2797 screen->menu_font_sizes[n] !=
2798 screen->menu_font_sizes[old]) {
2799 int cmp_0 = ((screen->menu_font_sizes[n] >
2800 screen->menu_font_sizes[old])
2803 int cmp_m = ((m < 0)
2805 : ((screen->menu_font_sizes[n] <
2806 screen->menu_font_sizes[m])
2809 if (cmp_0 > 0 && cmp_m > 0) {
2816 TRACE(("...new index %d\n", m));
2819 m = lookupRelativeFontSize(xw, m, relative - 1);
2820 else if (relative < -1)
2821 m = lookupRelativeFontSize(xw, m, relative + 1);
2829 HandleLargerFont(Widget w GCC_UNUSED,
2830 XEvent * event GCC_UNUSED,
2831 String * params GCC_UNUSED,
2832 Cardinal *param_count GCC_UNUSED)
2836 TRACE(("Handle larger-vt-font for %p\n", (void *) w));
2837 if ((xw = getXtermWidget(w)) != 0) {
2838 if (xw->misc.shift_fonts) {
2839 TScreen *screen = TScreenOf(xw);
2842 m = lookupRelativeFontSize(xw, screen->menu_font_number, 1);
2844 SetVTFont(xw, m, True, NULL);
2846 Bell(xw, XkbBI_MinorError, 0);
2854 HandleSmallerFont(Widget w GCC_UNUSED,
2855 XEvent * event GCC_UNUSED,
2856 String * params GCC_UNUSED,
2857 Cardinal *param_count GCC_UNUSED)
2861 TRACE(("Handle smaller-vt-font for %p\n", (void *) w));
2862 if ((xw = getXtermWidget(w)) != 0) {
2863 if (xw->misc.shift_fonts) {
2864 TScreen *screen = TScreenOf(xw);
2867 m = lookupRelativeFontSize(xw, screen->menu_font_number, -1);
2869 SetVTFont(xw, m, True, NULL);
2871 Bell(xw, XkbBI_MinorError, 0);
2879 xtermGetFont(const char *param)
2887 fontnum = fontMenu_default;
2890 fontnum = fontMenu_font1;
2893 fontnum = fontMenu_font2;
2896 fontnum = fontMenu_font3;
2899 fontnum = fontMenu_font4;
2902 fontnum = fontMenu_font5;
2905 fontnum = fontMenu_font6;
2909 fontnum = fontMenu_fontescape;
2913 fontnum = fontMenu_fontsel;
2924 HandleSetFont(Widget w GCC_UNUSED,
2925 XEvent * event GCC_UNUSED,
2927 Cardinal *param_count)
2931 if ((xw = getXtermWidget(w)) != 0) {
2935 memset(&fonts, 0, sizeof(fonts));
2937 if (*param_count == 0) {
2938 fontnum = fontMenu_default;
2940 Cardinal maxparams = 1; /* total number of params allowed */
2941 int result = xtermGetFont(params[0]);
2944 case fontMenu_default: /* FALLTHRU */
2945 case fontMenu_font1: /* FALLTHRU */
2946 case fontMenu_font2: /* FALLTHRU */
2947 case fontMenu_font3: /* FALLTHRU */
2948 case fontMenu_font4: /* FALLTHRU */
2949 case fontMenu_font5: /* FALLTHRU */
2950 case fontMenu_font6: /* FALLTHRU */
2952 case fontMenu_fontescape:
2959 case fontMenu_fontsel:
2963 Bell(xw, XkbBI_MinorError, 0);
2968 if (*param_count > maxparams) { /* see if extra args given */
2969 Bell(xw, XkbBI_MinorError, 0);
2972 switch (*param_count) { /* assign 'em */
2975 fonts.f_wb = params[4];
2978 fonts.f_w = params[3];
2982 fonts.f_b = params[2];
2985 fonts.f_n = params[1];
2990 SetVTFont(xw, fontnum, True, &fonts);
2995 SetVTFont(XtermWidget xw,
2998 const VTFontNames * fonts)
3000 TScreen *screen = TScreenOf(xw);
3002 TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which,
3003 (fonts && fonts->f_n) ? fonts->f_n : "<null>",
3004 (fonts && fonts->f_b) ? fonts->f_b : "<null>"));
3006 if (IsIcon(screen)) {
3007 Bell(xw, XkbBI_MinorError, 0);
3008 } else if (which >= 0 && which < NMENUFONTS) {
3009 VTFontNames myfonts;
3011 memset(&myfonts, 0, sizeof(myfonts));
3015 if (which == fontMenu_fontsel) { /* go get the selection */
3016 FindFontSelection(xw, myfonts.f_n, False);
3018 int oldFont = screen->menu_font_number;
3020 #define USE_CACHED(field, name) \
3021 if (myfonts.field == 0) { \
3022 myfonts.field = x_strdup(screen->menu_font_names[which][name]); \
3023 TRACE(("set myfonts." #field " from menu_font_names[%d][" #name "] %s\n", \
3024 which, NonNull(myfonts.field))); \
3026 TRACE(("set myfonts." #field " reused\n")); \
3028 #define SAVE_FNAME(field, name) \
3029 if (myfonts.field != 0) { \
3030 if (screen->menu_font_names[which][name] == 0 \
3031 || strcmp(screen->menu_font_names[which][name], myfonts.field)) { \
3032 TRACE(("updating menu_font_names[%d][" #name "] to %s\n", \
3033 which, myfonts.field)); \
3034 screen->menu_font_names[which][name] = x_strdup(myfonts.field); \
3038 USE_CACHED(f_n, fNorm);
3039 USE_CACHED(f_b, fBold);
3041 USE_CACHED(f_w, fWide);
3042 USE_CACHED(f_wb, fWBold);
3044 if (xtermLoadFont(xw,
3048 * If successful, save the data so that a subsequent query via
3049 * OSC-50 will return the expected values.
3051 SAVE_FNAME(f_n, fNorm);
3052 SAVE_FNAME(f_b, fBold);
3054 SAVE_FNAME(f_w, fWide);
3055 SAVE_FNAME(f_wb, fWBold);
3059 xtermFontName(screen->MenuFontName(oldFont)),
3061 Bell(xw, XkbBI_MinorError, 0);
3065 Bell(xw, XkbBI_MinorError, 0);