fontutils.c revision 0bd37d32
1/* $XTermId: fontutils.c,v 1.387 2013/05/15 00:31:56 tom Exp $ */ 2 3/* 4 * Copyright 1998-2011,2012 by Thomas E. Dickey 5 * 6 * All Rights Reserved 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sublicense, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 * Except as contained in this notice, the name(s) of the above copyright 28 * holders shall not be used in advertising or otherwise to promote the 29 * sale, use or other dealings in this Software without prior written 30 * authorization. 31 */ 32 33/* 34 * A portion of this module (for FontNameProperties) was adapted from EMU 1.3; 35 * it constructs font names with specific properties changed, e.g., for bold 36 * and double-size characters. 37 */ 38 39#define RES_OFFSET(field) XtOffsetOf(SubResourceRec, field) 40 41#include <fontutils.h> 42#include <X11/Xmu/Drawing.h> 43#include <X11/Xmu/CharSet.h> 44 45#include <main.h> 46#include <data.h> 47#include <menu.h> 48#include <xstrings.h> 49#include <xterm.h> 50 51#include <stdio.h> 52#include <ctype.h> 53 54#define SetFontWidth(screen,dst,src) (dst)->f_width = (src) 55#define SetFontHeight(screen,dst,src) (dst)->f_height = dimRound((screen)->scale_height * (float) (src)) 56 57/* from X11/Xlibint.h - not all vendors install this file */ 58#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \ 59 (((cs)->rbearing|(cs)->lbearing| \ 60 (cs)->ascent|(cs)->descent) == 0)) 61 62#define CI_GET_CHAR_INFO_1D(fs,col,def,cs) \ 63{ \ 64 cs = def; \ 65 if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \ 66 if (fs->per_char == NULL) { \ 67 cs = &fs->min_bounds; \ 68 } else { \ 69 cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \ 70 if (CI_NONEXISTCHAR(cs)) cs = def; \ 71 } \ 72 } \ 73} 74 75#define CI_GET_CHAR_INFO_2D(fs,row,col,def,cs) \ 76{ \ 77 cs = def; \ 78 if (row >= fs->min_byte1 && row <= fs->max_byte1 && \ 79 col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \ 80 if (fs->per_char == NULL) { \ 81 cs = &fs->min_bounds; \ 82 } else { \ 83 cs = &fs->per_char[((row - fs->min_byte1) * \ 84 (fs->max_char_or_byte2 - \ 85 fs->min_char_or_byte2 + 1)) + \ 86 (col - fs->min_char_or_byte2)]; \ 87 if (CI_NONEXISTCHAR(cs)) cs = def; \ 88 } \ 89 } \ 90} 91 92/* 93 * A structure to hold the relevant properties from a font 94 * we need to make a well formed font name for it. 95 */ 96typedef struct { 97 /* registry, foundry, family */ 98 char *beginning; 99 /* weight */ 100 char *weight; 101 /* slant */ 102 char *slant; 103 /* wideness */ 104 char *wideness; 105 /* add style */ 106 char *add_style; 107 int pixel_size; 108 char *point_size; 109 int res_x; 110 int res_y; 111 char *spacing; 112 int average_width; 113 /* charset registry, charset encoding */ 114 char *end; 115} FontNameProperties; 116 117#if OPT_RENDERFONT 118static void fillInFaceSize(XtermWidget, int); 119#endif 120 121#if OPT_SHIFT_FONTS 122static int lookupOneFontSize(XtermWidget, int); 123#endif 124 125#if OPT_WIDE_CHARS 126static unsigned 127countGlyphs(XFontStruct * fp) 128{ 129 unsigned count = 0; 130 131 if (fp != 0) { 132 if (fp->min_byte1 == 0 && fp->max_byte1 == 0) { 133 count = fp->max_char_or_byte2 - fp->min_char_or_byte2; 134 } else if (fp->min_char_or_byte2 < 256 135 && fp->max_char_or_byte2 < 256) { 136 unsigned first = (fp->min_byte1 << 8) + fp->min_char_or_byte2; 137 unsigned last = (fp->max_byte1 << 8) + fp->max_char_or_byte2; 138 count = last + 1 - first; 139 } 140 } 141 return count; 142} 143 144/* 145 * Verify that the wide-bold font is at least a bold font with roughly as many 146 * glyphs as the wide font. The counts should be the same, but settle for 147 * filtering out the worst of the font mismatches. 148 */ 149static Bool 150compatibleWideCounts(XFontStruct * wfs, XFontStruct * wbfs) 151{ 152 unsigned count_w = countGlyphs(wfs); 153 unsigned count_wb = countGlyphs(wbfs); 154 if (count_w <= 256 || 155 count_wb <= 256 || 156 ((count_w / 4) * 3) > count_wb) { 157 TRACE(("...font server lied (count wide %u vs wide-bold %u)\n", 158 count_w, count_wb)); 159 return False; 160 } 161 return True; 162} 163#endif /* OPT_WIDE_CHARS */ 164 165#if OPT_BOX_CHARS 166static void 167setupPackedFonts(XtermWidget xw) 168{ 169 TScreen *screen = TScreenOf(xw); 170 Bool value = False; 171 172#if OPT_RENDERFONT 173#define MIXED(name) screen->name[fontnum].map.mixed 174 if (xw->work.render_font == True) { 175 int fontnum = screen->menu_font_number; 176 177 screen->allow_packing = (Boolean) (MIXED(renderFontNorm) 178 || MIXED(renderFontBold) 179 || MIXED(renderFontItal) 180#if OPT_RENDERWIDE 181 || MIXED(renderWideNorm) 182 || MIXED(renderWideBold) 183 || MIXED(renderWideItal) 184#endif 185 ); 186#undef MIXED 187 } 188#endif /* OPT_RENDERFONT */ 189 190 value = screen->allow_packing; 191 192 SetItemSensitivity(fontMenuEntries[fontMenu_font_packedfont].widget, value); 193} 194#endif 195 196/* 197 * Returns the fields from start to stop in a dash- separated string. This 198 * function will modify the source, putting '\0's in the appropiate place and 199 * moving the beginning forward to after the '\0' 200 * 201 * This will NOT work for the last field (but we won't need it). 202 */ 203static char * 204n_fields(char **source, int start, int stop) 205{ 206 int i; 207 char *str, *str1; 208 209 /* 210 * find the start-1th dash 211 */ 212 for (i = start - 1, str = *source; i; i--, str++) 213 if ((str = strchr(str, '-')) == 0) 214 return 0; 215 216 /* 217 * find the stopth dash 218 */ 219 for (i = stop - start + 1, str1 = str; i; i--, str1++) 220 if ((str1 = strchr(str1, '-')) == 0) 221 return 0; 222 223 /* 224 * put a \0 at the end of the fields 225 */ 226 *(str1 - 1) = '\0'; 227 228 /* 229 * move source forward 230 */ 231 *source = str1; 232 233 return str; 234} 235 236static Boolean 237check_fontname(const char *name) 238{ 239 Boolean result = True; 240 241 if (IsEmpty(name)) { 242 TRACE(("fontname missing\n")); 243 result = False; 244 } 245 return result; 246} 247 248/* 249 * Gets the font properties from a given font structure. We use the FONT name 250 * to find them out, since that seems easier. 251 * 252 * Returns a pointer to a static FontNameProperties structure 253 * or NULL on error. 254 */ 255static FontNameProperties * 256get_font_name_props(Display * dpy, XFontStruct * fs, char **result) 257{ 258 static FontNameProperties props; 259 static char *last_name; 260 261 XFontProp *fp; 262 int i; 263 Atom fontatom = XInternAtom(dpy, "FONT", False); 264 char *name = 0; 265 char *str; 266 267 /* 268 * first get the full font name 269 */ 270 if (fontatom != 0) { 271 for (i = 0, fp = fs->properties; i < fs->n_properties; i++, fp++) { 272 if (fp->name == fontatom) { 273 name = XGetAtomName(dpy, fp->card32); 274 break; 275 } 276 } 277 } 278 279 if (name == 0) 280 return 0; 281 282 /* 283 * XGetAtomName allocates memory - don't leak 284 */ 285 if (last_name != 0) 286 XFree(last_name); 287 last_name = name; 288 289 if (result != 0) { 290 if (!check_fontname(name)) 291 return 0; 292 if (*result != 0) 293 free(*result); 294 *result = x_strdup(name); 295 } 296 297 /* 298 * Now split it up into parts and put them in 299 * their places. Since we are using parts of 300 * the original string, we must not free the Atom Name 301 */ 302 303 /* registry, foundry, family */ 304 if ((props.beginning = n_fields(&name, 1, 3)) == 0) 305 return 0; 306 307 /* weight is the next */ 308 if ((props.weight = n_fields(&name, 1, 1)) == 0) 309 return 0; 310 311 /* slant */ 312 if ((props.slant = n_fields(&name, 1, 1)) == 0) 313 return 0; 314 315 /* width */ 316 if ((props.wideness = n_fields(&name, 1, 1)) == 0) 317 return 0; 318 319 /* add style */ 320 if ((props.add_style = n_fields(&name, 1, 1)) == 0) 321 return 0; 322 323 /* pixel size */ 324 if ((str = n_fields(&name, 1, 1)) == 0) 325 return 0; 326 if ((props.pixel_size = atoi(str)) == 0) 327 return 0; 328 329 /* point size */ 330 if ((props.point_size = n_fields(&name, 1, 1)) == 0) 331 return 0; 332 333 /* res_x */ 334 if ((str = n_fields(&name, 1, 1)) == 0) 335 return 0; 336 if ((props.res_x = atoi(str)) == 0) 337 return 0; 338 339 /* res_y */ 340 if ((str = n_fields(&name, 1, 1)) == 0) 341 return 0; 342 if ((props.res_y = atoi(str)) == 0) 343 return 0; 344 345 /* spacing */ 346 if ((props.spacing = n_fields(&name, 1, 1)) == 0) 347 return 0; 348 349 /* average width */ 350 if ((str = n_fields(&name, 1, 1)) == 0) 351 return 0; 352 if ((props.average_width = atoi(str)) == 0) 353 return 0; 354 355 /* the rest: charset registry and charset encoding */ 356 props.end = name; 357 358 return &props; 359} 360 361#define ALLOCHUNK(n) ((n | 127) + 1) 362 363static void 364alloca_fontname(char **result, size_t next) 365{ 366 size_t last = (*result != 0) ? strlen(*result) : 0; 367 size_t have = (*result != 0) ? ALLOCHUNK(last) : 0; 368 size_t want = last + next + 2; 369 370 if (want >= have) { 371 want = ALLOCHUNK(want); 372 if (last != 0) { 373 *result = TypeRealloc(char, want, *result); 374 } else { 375 if ((*result = TypeMallocN(char, want)) != 0) 376 **result = '\0'; 377 } 378 } 379} 380 381static void 382append_fontname_str(char **result, const char *value) 383{ 384 if (value == 0) 385 value = "*"; 386 alloca_fontname(result, strlen(value)); 387 if (*result != 0) { 388 if (**result != '\0') 389 strcat(*result, "-"); 390 strcat(*result, value); 391 } 392} 393 394static void 395append_fontname_num(char **result, int value) 396{ 397 if (value < 0) { 398 append_fontname_str(result, "*"); 399 } else { 400 char temp[100]; 401 sprintf(temp, "%d", value); 402 append_fontname_str(result, temp); 403 } 404} 405 406/* 407 * Take the given font props and try to make a well formed font name specifying 408 * the same base font and size and everything, but with different weight/width 409 * according to the parameters. The return value is allocated, should be freed 410 * by the caller. 411 */ 412static char * 413derive_font_name(FontNameProperties * props, 414 const char *use_weight, 415 int use_average_width, 416 const char *use_encoding) 417{ 418 char *result = 0; 419 420 append_fontname_str(&result, props->beginning); 421 append_fontname_str(&result, use_weight); 422 append_fontname_str(&result, props->slant); 423 append_fontname_str(&result, 0); 424 append_fontname_str(&result, 0); 425 append_fontname_num(&result, props->pixel_size); 426 append_fontname_str(&result, props->point_size); 427 append_fontname_num(&result, props->res_x); 428 append_fontname_num(&result, props->res_y); 429 append_fontname_str(&result, props->spacing); 430 append_fontname_num(&result, use_average_width); 431 append_fontname_str(&result, use_encoding); 432 433 return result; 434} 435 436static char * 437bold_font_name(FontNameProperties * props, int use_average_width) 438{ 439 return derive_font_name(props, "bold", use_average_width, props->end); 440} 441 442#if OPT_WIDE_CHARS 443#define derive_wide_font(props, weight) \ 444 derive_font_name(props, weight, props->average_width * 2, "ISO10646-1") 445 446static char * 447wide_font_name(FontNameProperties * props) 448{ 449 return derive_wide_font(props, "medium"); 450} 451 452static char * 453widebold_font_name(FontNameProperties * props) 454{ 455 return derive_wide_font(props, "bold"); 456} 457#endif /* OPT_WIDE_CHARS */ 458 459#if OPT_DEC_CHRSET 460/* 461 * Take the given font props and try to make a well formed font name specifying 462 * the same base font but changed depending on the given attributes and chrset. 463 * 464 * For double width fonts, we just double the X-resolution, for double height 465 * fonts we double the pixel-size and Y-resolution 466 */ 467char * 468xtermSpecialFont(TScreen * screen, unsigned atts, unsigned chrset) 469{ 470#if OPT_TRACE 471 static char old_spacing[80]; 472 static FontNameProperties old_props; 473#endif 474 FontNameProperties *props; 475 char *result = 0; 476 const char *weight; 477 int pixel_size; 478 int res_x; 479 int res_y; 480 481 props = get_font_name_props(screen->display, screen->fnts[fNorm].fs, 0); 482 if (props == 0) 483 return result; 484 485 pixel_size = props->pixel_size; 486 res_x = props->res_x; 487 res_y = props->res_y; 488 if (atts & BOLD) 489 weight = "bold"; 490 else 491 weight = props->weight; 492 493 if (CSET_DOUBLE(chrset)) 494 res_x *= 2; 495 496 if (chrset == CSET_DHL_TOP 497 || chrset == CSET_DHL_BOT) { 498 res_y *= 2; 499 pixel_size *= 2; 500 } 501#if OPT_TRACE 502 if (old_props.res_x != res_x 503 || old_props.res_x != res_y 504 || old_props.pixel_size != pixel_size 505 || strcmp(old_props.spacing, props->spacing)) { 506 TRACE(("xtermSpecialFont(atts = %#x, chrset = %#x)\n", atts, chrset)); 507 TRACE(("res_x = %d\n", res_x)); 508 TRACE(("res_y = %d\n", res_y)); 509 TRACE(("point_size = %s\n", props->point_size)); 510 TRACE(("pixel_size = %d\n", pixel_size)); 511 TRACE(("spacing = %s\n", props->spacing)); 512 old_props.res_x = res_x; 513 old_props.res_x = res_y; 514 old_props.pixel_size = pixel_size; 515 old_props.spacing = old_spacing; 516 sprintf(old_spacing, "%.*s", (int) sizeof(old_spacing) - 2, props->spacing); 517 } 518#endif 519 520 append_fontname_str(&result, props->beginning); 521 append_fontname_str(&result, weight); 522 append_fontname_str(&result, props->slant); 523 append_fontname_str(&result, props->wideness); 524 append_fontname_str(&result, props->add_style); 525 append_fontname_num(&result, pixel_size); 526 append_fontname_str(&result, props->point_size); 527 append_fontname_num(&result, (atts & NORESOLUTION) ? -1 : res_x); 528 append_fontname_num(&result, (atts & NORESOLUTION) ? -1 : res_y); 529 append_fontname_str(&result, props->spacing); 530 append_fontname_str(&result, 0); 531 append_fontname_str(&result, props->end); 532 533 return result; 534} 535#endif /* OPT_DEC_CHRSET */ 536 537/* 538 * Case-independent comparison for font-names, including wildcards. 539 * XLFD allows '?' as a wildcard, but we do not handle that (no one seems 540 * to use it). 541 */ 542static Bool 543same_font_name(const char *pattern, const char *match) 544{ 545 Bool result = False; 546 547 if (pattern && match) { 548 while (*pattern && *match) { 549 if (*pattern == *match) { 550 pattern++; 551 match++; 552 } else if (*pattern == '*' || *match == '*') { 553 if (same_font_name(pattern + 1, match)) { 554 return True; 555 } else if (same_font_name(pattern, match + 1)) { 556 return True; 557 } else { 558 return False; 559 } 560 } else { 561 int p = x_toupper(*pattern++); 562 int m = x_toupper(*match++); 563 if (p != m) 564 return False; 565 } 566 } 567 result = (*pattern == *match); /* both should be NUL */ 568 } 569 return result; 570} 571 572/* 573 * Double-check the fontname that we asked for versus what the font server 574 * actually gave us. The larger fixed fonts do not always have a matching bold 575 * font, and the font server may try to scale another font or otherwise 576 * substitute a mismatched font. 577 * 578 * If we cannot get what we requested, we will fallback to the original 579 * behavior, which simulates bold by overstriking each character at one pixel 580 * offset. 581 */ 582static int 583got_bold_font(Display * dpy, XFontStruct * fs, String requested) 584{ 585 char *actual = 0; 586 int got; 587 588 if (get_font_name_props(dpy, fs, &actual) == 0) 589 got = 0; 590 else 591 got = same_font_name(requested, actual); 592 free(actual); 593 return got; 594} 595 596/* 597 * If the font server tries to adjust another font, it may not adjust it 598 * properly. Check that the bounding boxes are compatible. Otherwise we'll 599 * leave trash on the display when we mix normal and bold fonts. 600 */ 601static int 602same_font_size(XtermWidget xw, XFontStruct * nfs, XFontStruct * bfs) 603{ 604 TScreen *screen = TScreenOf(xw); 605 TRACE(("same_font_size height %d/%d, min %d/%d max %d/%d\n", 606 nfs->ascent + nfs->descent, 607 bfs->ascent + bfs->descent, 608 nfs->min_bounds.width, bfs->min_bounds.width, 609 nfs->max_bounds.width, bfs->max_bounds.width)); 610 return screen->free_bold_box 611 || ((nfs->ascent + nfs->descent) == (bfs->ascent + bfs->descent) 612 && (nfs->min_bounds.width == bfs->min_bounds.width 613 || nfs->min_bounds.width == bfs->min_bounds.width + 1) 614 && (nfs->max_bounds.width == bfs->max_bounds.width 615 || nfs->max_bounds.width == bfs->max_bounds.width + 1)); 616} 617 618/* 619 * Check if the font looks like it has fixed width 620 */ 621static int 622is_fixed_font(XFontStruct * fs) 623{ 624 if (fs) 625 return (fs->min_bounds.width == fs->max_bounds.width); 626 return 1; 627} 628 629/* 630 * Check if the font looks like a double width font (i.e. contains 631 * characters of width X and 2X 632 */ 633#if OPT_WIDE_CHARS 634static int 635is_double_width_font(XFontStruct * fs) 636{ 637 return ((2 * fs->min_bounds.width) == fs->max_bounds.width); 638} 639#else 640#define is_double_width_font(fs) 0 641#endif 642 643#if OPT_WIDE_CHARS && OPT_RENDERFONT && defined(HAVE_TYPE_FCCHAR32) 644#define HALF_WIDTH_TEST_STRING "1234567890" 645 646/* '1234567890' in Chinese characters in UTF-8 */ 647#define FULL_WIDTH_TEST_STRING "\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89" \ 648 "\xe5\x9b\x9b\xe4\xba\x94" \ 649 "\xef\xa7\x91\xe4\xb8\x83\xe5\x85\xab" \ 650 "\xe4\xb9\x9d\xef\xa6\xb2" 651 652/* '1234567890' in Korean script in UTF-8 */ 653#define FULL_WIDTH_TEST_STRING2 "\xec\x9d\xbc\xec\x9d\xb4\xec\x82\xbc" \ 654 "\xec\x82\xac\xec\x98\xa4" \ 655 "\xec\x9c\xa1\xec\xb9\xa0\xed\x8c\x94" \ 656 "\xea\xb5\xac\xec\x98\x81" 657 658#define HALF_WIDTH_CHAR1 0x0031 /* '1' */ 659#define HALF_WIDTH_CHAR2 0x0057 /* 'W' */ 660#define FULL_WIDTH_CHAR1 0x4E00 /* CJK Ideograph 'number one' */ 661#define FULL_WIDTH_CHAR2 0xAC00 /* Korean script syllable 'Ka' */ 662 663static Bool 664is_double_width_font_xft(Display * dpy, XftFont * font) 665{ 666 XGlyphInfo gi1, gi2; 667 FcChar32 c1 = HALF_WIDTH_CHAR1, c2 = HALF_WIDTH_CHAR2; 668 String fwstr = FULL_WIDTH_TEST_STRING; 669 String hwstr = HALF_WIDTH_TEST_STRING; 670 671 /* Some Korean fonts don't have Chinese characters at all. */ 672 if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR1)) { 673 if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR2)) 674 return False; /* Not a CJK font */ 675 else /* a Korean font without CJK Ideographs */ 676 fwstr = FULL_WIDTH_TEST_STRING2; 677 } 678 679 XftTextExtents32(dpy, font, &c1, 1, &gi1); 680 XftTextExtents32(dpy, font, &c2, 1, &gi2); 681 if (gi1.xOff != gi2.xOff) /* Not a fixed-width font */ 682 return False; 683 684 XftTextExtentsUtf8(dpy, 685 font, 686 (_Xconst FcChar8 *) hwstr, 687 (int) strlen(hwstr), 688 &gi1); 689 XftTextExtentsUtf8(dpy, 690 font, 691 (_Xconst FcChar8 *) fwstr, 692 (int) strlen(fwstr), 693 &gi2); 694 695 /* 696 * fontconfig and Xft prior to 2.2(?) set the width of half-width 697 * characters identical to that of full-width character in CJK double-width 698 * (bi-width / monospace) font even though the former is half as wide as 699 * the latter. This was fixed sometime before the release of fontconfig 700 * 2.2 in early 2003. See 701 * http://bugzilla.mozilla.org/show_bug.cgi?id=196312 702 * In the meantime, we have to check both possibilities. 703 */ 704 return ((2 * gi1.xOff == gi2.xOff) || (gi1.xOff == gi2.xOff)); 705} 706#else 707#define is_double_width_font_xft(dpy, xftfont) 0 708#endif 709 710#define EmptyFont(fs) (fs != 0 \ 711 && ((fs)->ascent + (fs)->descent == 0 \ 712 || (fs)->max_bounds.width == 0)) 713 714#define FontSize(fs) (((fs)->ascent + (fs)->descent) \ 715 * (fs)->max_bounds.width) 716 717const VTFontNames * 718xtermFontName(const char *normal) 719{ 720 static VTFontNames data; 721 if (data.f_n) 722 free((void *) data.f_n); 723 memset(&data, 0, sizeof(data)); 724 data.f_n = x_strdup(normal); 725 return &data; 726} 727 728static void 729cache_menu_font_name(TScreen * screen, int fontnum, int which, const char *name) 730{ 731 if (name != 0) { 732 char *last = (char *) screen->menu_font_names[fontnum][which]; 733 if (last != 0) { 734 if (strcmp(last, name)) { 735 free(last); 736 TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name)); 737 screen->menu_font_names[fontnum][which] = x_strdup(name); 738 } 739 } else { 740 TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name)); 741 screen->menu_font_names[fontnum][which] = x_strdup(name); 742 } 743 } 744} 745 746/* 747 * Open the given font and verify that it is non-empty. Return a null on 748 * failure. 749 */ 750Bool 751xtermOpenFont(XtermWidget xw, 752 const char *name, 753 XTermFonts * result, 754 fontWarningTypes warn, 755 Bool force) 756{ 757 Bool code = False; 758 TScreen *screen = TScreenOf(xw); 759 760 if (!IsEmpty(name)) { 761 if ((result->fs = XLoadQueryFont(screen->display, name)) != 0) { 762 code = True; 763 if (EmptyFont(result->fs)) { 764 (void) xtermCloseFont(xw, result); 765 code = False; 766 } else { 767 result->fn = x_strdup(name); 768 } 769 } else if (XmuCompareISOLatin1(name, DEFFONT) != 0) { 770 if (warn <= xw->misc.fontWarnings 771#if OPT_RENDERFONT 772 && !UsingRenderFont(xw) 773#endif 774 ) { 775 TRACE(("OOPS: cannot load font %s\n", name)); 776 xtermWarning("cannot load font '%s'\n", name); 777#if OPT_RENDERFONT 778 /* 779 * Do a sanity check in case someone's mixed up xterm with 780 * one of those programs that read their resource data from 781 * xterm's namespace. 782 */ 783 if (strchr(name, ':') != 0 || strchr(name, '=') != 0) { 784 xtermWarning("Use the \"-fa\" option for the Xft fonts\n"); 785 } 786#endif 787 } else { 788 TRACE(("xtermOpenFont: cannot load font '%s'\n", name)); 789 } 790 if (force) { 791 code = xtermOpenFont(xw, DEFFONT, result, fwAlways, True); 792 } 793 } 794 } 795 return code; 796} 797 798/* 799 * Close the font and free the font info. 800 */ 801XTermFonts * 802xtermCloseFont(XtermWidget xw, XTermFonts * fnt) 803{ 804 if (fnt != 0 && fnt->fs != 0) { 805 TScreen *screen = TScreenOf(xw); 806 807 clrCgsFonts(xw, WhichVWin(screen), fnt); 808 XFreeFont(screen->display, fnt->fs); 809 xtermFreeFontInfo(fnt); 810 } 811 return 0; 812} 813 814/* 815 * Close the listed fonts, noting that some may use copies of the pointer. 816 */ 817void 818xtermCloseFonts(XtermWidget xw, XTermFonts * fnts) 819{ 820 int j, k; 821 822 for (j = 0; j < fMAX; ++j) { 823 /* 824 * Need to save the pointer since xtermCloseFont zeroes it 825 */ 826 XFontStruct *thisFont = fnts[j].fs; 827 if (thisFont != 0) { 828 xtermCloseFont(xw, &fnts[j]); 829 for (k = j + 1; k < fMAX; ++k) { 830 if (thisFont == fnts[k].fs) 831 xtermFreeFontInfo(&fnts[k]); 832 } 833 } 834 } 835} 836 837/* 838 * Make a copy of the source, assuming the XFontStruct's to be unique, but 839 * ensuring that the names are reallocated to simplify freeing. 840 */ 841void 842xtermCopyFontInfo(XTermFonts * target, XTermFonts * source) 843{ 844 xtermFreeFontInfo(target); 845 target->chrset = source->chrset; 846 target->flags = source->flags; 847 target->fn = x_strdup(source->fn); 848 target->fs = source->fs; 849} 850 851void 852xtermFreeFontInfo(XTermFonts * target) 853{ 854 target->chrset = 0; 855 target->flags = 0; 856 if (target->fn != 0) { 857 free(target->fn); 858 target->fn = 0; 859 } 860 target->fs = 0; 861} 862 863int 864xtermLoadFont(XtermWidget xw, 865 const VTFontNames * fonts, 866 Bool doresize, 867 int fontnum) 868{ 869 TScreen *screen = TScreenOf(xw); 870 VTwin *win = WhichVWin(screen); 871 872 VTFontNames myfonts; 873 FontNameProperties *fp; 874 XTermFonts fnts[fMAX]; 875 Pixel new_normal; 876 Pixel new_revers; 877 char *tmpname = NULL; 878 char *normal = NULL; 879 Boolean proportional = False; 880 fontWarningTypes warn[fMAX]; 881 int j; 882 883 memset(&myfonts, 0, sizeof(myfonts)); 884 memset(fnts, 0, sizeof(fnts)); 885 886 if (fonts != 0) 887 myfonts = *fonts; 888 if (!check_fontname(myfonts.f_n)) 889 return 0; 890 891 /* 892 * Check the font names against the resource values, to see which were 893 * derived in a previous call. If so, we'll only warn about those if 894 * the warning level is set to "always". 895 */ 896 for (j = 0; j < fMAX; ++j) { 897 warn[j] = fwAlways; 898 } 899#define CmpResource(field, index) \ 900 if (same_font_name(screen->menu_font_names[fontnum][index], myfonts.field)) \ 901 warn[index] = fwResource 902 903 CmpResource(f_n, fNorm); 904 if (fontnum == fontMenu_default) { 905 CmpResource(f_b, fBold); 906#if OPT_WIDE_CHARS 907 CmpResource(f_b, fWide); 908 CmpResource(f_b, fWBold); 909#endif 910 } 911 912 if (fontnum == fontMenu_fontescape 913 && myfonts.f_n != screen->MenuFontName(fontnum)) { 914 if ((tmpname = x_strdup(myfonts.f_n)) == 0) 915 return 0; 916 } 917 918 TRACE(("Begin Cgs - xtermLoadFont(%s)\n", myfonts.f_n)); 919 releaseWindowGCs(xw, win); 920 921#define DbgResource(name, field, index) \ 922 TRACE(("xtermLoadFont #%d "name" %s%s\n", \ 923 fontnum, \ 924 (warn[index] == fwResource) ? "*" : " ", \ 925 NonNull(myfonts.field))) 926 DbgResource("normal", f_n, fNorm); 927 DbgResource("bold ", f_b, fBold); 928#if OPT_WIDE_CHARS 929 DbgResource("wide ", f_w, fWide); 930 DbgResource("w/bold", f_wb, fWBold); 931#endif 932 933 /* 934 * If we are opening the default font, and it happens to be missing, force 935 * that to the compiled-in default font, e.g., "fixed". If we cannot open 936 * the font, disable it from the menu. 937 */ 938 if (!xtermOpenFont(xw, 939 myfonts.f_n, 940 &fnts[fNorm], 941 warn[fNorm], 942 (fontnum == fontMenu_default))) { 943 SetItemSensitivity(fontMenuEntries[fontnum].widget, False); 944 goto bad; 945 } 946 947 normal = x_strdup(myfonts.f_n); 948 if (!check_fontname(myfonts.f_b)) { 949 warn[fBold] = fwAlways; 950 fp = get_font_name_props(screen->display, fnts[fNorm].fs, &normal); 951 if (fp != 0) { 952 myfonts.f_b = bold_font_name(fp, fp->average_width); 953 if (!xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], fwAlways, False)) { 954 myfonts.f_b = bold_font_name(fp, -1); 955 xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], fwAlways, False); 956 } 957 TRACE(("...derived bold '%s'\n", NonNull(myfonts.f_b))); 958 } 959 if (fp == 0 || fnts[fBold].fs == 0) { 960 xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]); 961 TRACE(("...cannot load a matching bold font\n")); 962 } else if (same_font_size(xw, fnts[fNorm].fs, fnts[fBold].fs) 963 && got_bold_font(screen->display, fnts[fBold].fs, myfonts.f_b)) { 964 TRACE(("...got a matching bold font\n")); 965 cache_menu_font_name(screen, fontnum, fBold, myfonts.f_b); 966 } else { 967 xtermCloseFont(xw, &fnts[fBold]); 968 fnts[fBold] = fnts[fNorm]; 969 TRACE(("...did not get a matching bold font\n")); 970 } 971 } else if (!xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], warn[fBold], False)) { 972 xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]); 973 warn[fBold] = fwAlways; 974 TRACE(("...cannot load bold font '%s'\n", NonNull(myfonts.f_b))); 975 } else { 976 cache_menu_font_name(screen, fontnum, fBold, myfonts.f_b); 977 } 978 979 /* 980 * If there is no widefont specified, fake it by doubling AVERAGE_WIDTH 981 * of normal fonts XLFD, and asking for it. This plucks out 18x18ja 982 * and 12x13ja as the corresponding fonts for 9x18 and 6x13. 983 */ 984 if_OPT_WIDE_CHARS(screen, { 985 Boolean derived; 986 char *bold = NULL; 987 988 if (check_fontname(myfonts.f_w)) { 989 cache_menu_font_name(screen, fontnum, fWide, myfonts.f_w); 990 } else if (screen->utf8_fonts && !is_double_width_font(fnts[fNorm].fs)) { 991 fp = get_font_name_props(screen->display, fnts[fNorm].fs, &normal); 992 if (fp != 0) { 993 myfonts.f_w = wide_font_name(fp); 994 warn[fWide] = fwAlways; 995 TRACE(("...derived wide %s\n", NonNull(myfonts.f_w))); 996 cache_menu_font_name(screen, fontnum, fWide, myfonts.f_w); 997 } 998 } 999 1000 if (check_fontname(myfonts.f_w)) { 1001 (void) xtermOpenFont(xw, myfonts.f_w, &fnts[fWide], warn[fWide], False); 1002 } else { 1003 xtermCopyFontInfo(&fnts[fWide], &fnts[fNorm]); 1004 warn[fWide] = fwAlways; 1005 } 1006 1007 derived = False; 1008 if (!check_fontname(myfonts.f_wb)) { 1009 fp = get_font_name_props(screen->display, fnts[fBold].fs, &bold); 1010 if (fp != 0) { 1011 myfonts.f_wb = widebold_font_name(fp); 1012 warn[fWBold] = fwAlways; 1013 derived = True; 1014 } 1015 } 1016 1017 if (check_fontname(myfonts.f_wb)) { 1018 1019 xtermOpenFont(xw, 1020 myfonts.f_wb, 1021 &fnts[fWBold], 1022 (screen->utf8_fonts 1023 ? warn[fWBold] 1024 : (fontWarningTypes) (xw->misc.fontWarnings + 1)), 1025 False); 1026 1027 if (derived 1028 && !compatibleWideCounts(fnts[fWide].fs, fnts[fWBold].fs)) { 1029 xtermCloseFont(xw, &fnts[fWBold]); 1030 } 1031 if (fnts[fWBold].fs == 0) { 1032 if (IsEmpty(myfonts.f_w)) { 1033 myfonts.f_wb = myfonts.f_b; 1034 warn[fWBold] = fwAlways; 1035 xtermCopyFontInfo(&fnts[fWBold], &fnts[fBold]); 1036 TRACE(("...cannot load wide-bold, use bold %s\n", 1037 NonNull(myfonts.f_b))); 1038 } else { 1039 myfonts.f_wb = myfonts.f_w; 1040 warn[fWBold] = fwAlways; 1041 xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]); 1042 TRACE(("...cannot load wide-bold, use wide %s\n", 1043 NonNull(myfonts.f_w))); 1044 } 1045 } else { 1046 TRACE(("...%s wide/bold %s\n", 1047 derived ? "derived" : "given", 1048 NonNull(myfonts.f_wb))); 1049 cache_menu_font_name(screen, fontnum, fWBold, myfonts.f_wb); 1050 } 1051 } else if (is_double_width_font(fnts[fBold].fs)) { 1052 xtermCopyFontInfo(&fnts[fWBold], &fnts[fBold]); 1053 warn[fWBold] = fwAlways; 1054 TRACE(("...bold font is double-width, use it %s\n", NonNull(myfonts.f_b))); 1055 } else { 1056 xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]); 1057 warn[fWBold] = fwAlways; 1058 TRACE(("...cannot load wide bold font, use wide %s\n", NonNull(myfonts.f_w))); 1059 } 1060 1061 free(bold); 1062 1063 if (EmptyFont(fnts[fWBold].fs)) 1064 goto bad; /* can't use a 0-sized font */ 1065 }); 1066 1067 /* 1068 * Most of the time this call to load the font will succeed, even if 1069 * there is no wide font : the X server doubles the width of the 1070 * normal font, or similar. 1071 * 1072 * But if it did fail for some reason, then nevermind. 1073 */ 1074 if (EmptyFont(fnts[fBold].fs)) 1075 goto bad; /* can't use a 0-sized font */ 1076 1077 if (!same_font_size(xw, fnts[fNorm].fs, fnts[fBold].fs) 1078 && (is_fixed_font(fnts[fNorm].fs) && is_fixed_font(fnts[fBold].fs))) { 1079 TRACE(("...ignoring mismatched normal/bold fonts\n")); 1080 xtermCloseFont(xw, &fnts[fBold]); 1081 xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]); 1082 } 1083 1084 if_OPT_WIDE_CHARS(screen, { 1085 if (fnts[fWide].fs != 0 1086 && fnts[fWBold].fs != 0 1087 && !same_font_size(xw, fnts[fWide].fs, fnts[fWBold].fs) 1088 && (is_fixed_font(fnts[fWide].fs) && is_fixed_font(fnts[fWBold].fs))) { 1089 TRACE(("...ignoring mismatched normal/bold wide fonts\n")); 1090 xtermCloseFont(xw, &fnts[fWBold]); 1091 xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]); 1092 } 1093 }); 1094 1095 /* 1096 * Normal/bold fonts should be the same width. Also, the min/max 1097 * values should be the same. 1098 */ 1099 if (!is_fixed_font(fnts[fNorm].fs) 1100 || !is_fixed_font(fnts[fBold].fs) 1101 || fnts[fNorm].fs->max_bounds.width != fnts[fBold].fs->max_bounds.width) { 1102 TRACE(("Proportional font! normal %d/%d, bold %d/%d\n", 1103 fnts[fNorm].fs->min_bounds.width, 1104 fnts[fNorm].fs->max_bounds.width, 1105 fnts[fBold].fs->min_bounds.width, 1106 fnts[fBold].fs->max_bounds.width)); 1107 proportional = True; 1108 } 1109 1110 if_OPT_WIDE_CHARS(screen, { 1111 if (fnts[fWide].fs != 0 1112 && fnts[fWBold].fs != 0 1113 && (!is_fixed_font(fnts[fWide].fs) 1114 || !is_fixed_font(fnts[fWBold].fs) 1115 || fnts[fWide].fs->max_bounds.width != fnts[fWBold].fs->max_bounds.width)) { 1116 TRACE(("Proportional font! wide %d/%d, wide bold %d/%d\n", 1117 fnts[fWide].fs->min_bounds.width, 1118 fnts[fWide].fs->max_bounds.width, 1119 fnts[fWBold].fs->min_bounds.width, 1120 fnts[fWBold].fs->max_bounds.width)); 1121 proportional = True; 1122 } 1123 }); 1124 1125 /* TODO : enforce that the width of the wide font is 2* the width 1126 of the narrow font */ 1127 1128 /* 1129 * If we're switching fonts, free the old ones. Otherwise we'll leak 1130 * the memory that is associated with the old fonts. The 1131 * XLoadQueryFont call allocates a new XFontStruct. 1132 */ 1133 xtermCloseFonts(xw, screen->fnts); 1134 1135 xtermCopyFontInfo(&(screen->fnts[fNorm]), &fnts[fNorm]); 1136 xtermCopyFontInfo(&(screen->fnts[fBold]), &fnts[fBold]); 1137#if OPT_WIDE_CHARS 1138 xtermCopyFontInfo(&(screen->fnts[fWide]), &fnts[fWide]); 1139 if (fnts[fWBold].fs == NULL) 1140 xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]); 1141 xtermCopyFontInfo(&(screen->fnts[fWBold]), &fnts[fWBold]); 1142#endif 1143 1144 new_normal = getXtermForeground(xw, xw->flags, xw->cur_foreground); 1145 new_revers = getXtermBackground(xw, xw->flags, xw->cur_background); 1146 1147 setCgsFore(xw, win, gcNorm, new_normal); 1148 setCgsBack(xw, win, gcNorm, new_revers); 1149 setCgsFont(xw, win, gcNorm, &(screen->fnts[fNorm])); 1150 1151 copyCgs(xw, win, gcBold, gcNorm); 1152 setCgsFont(xw, win, gcBold, &(screen->fnts[fBold])); 1153 1154 setCgsFore(xw, win, gcNormReverse, new_revers); 1155 setCgsBack(xw, win, gcNormReverse, new_normal); 1156 setCgsFont(xw, win, gcNormReverse, &(screen->fnts[fNorm])); 1157 1158 copyCgs(xw, win, gcBoldReverse, gcNormReverse); 1159 setCgsFont(xw, win, gcBoldReverse, &(screen->fnts[fBold])); 1160 1161 if_OPT_WIDE_CHARS(screen, { 1162 if (screen->fnts[fWide].fs != 0 1163 && screen->fnts[fWBold].fs != 0) { 1164 setCgsFore(xw, win, gcWide, new_normal); 1165 setCgsBack(xw, win, gcWide, new_revers); 1166 setCgsFont(xw, win, gcWide, &(screen->fnts[fWide])); 1167 1168 copyCgs(xw, win, gcWBold, gcWide); 1169 setCgsFont(xw, win, gcWBold, &(screen->fnts[fWBold])); 1170 1171 setCgsFore(xw, win, gcWideReverse, new_revers); 1172 setCgsBack(xw, win, gcWideReverse, new_normal); 1173 setCgsFont(xw, win, gcWideReverse, &(screen->fnts[fWide])); 1174 1175 copyCgs(xw, win, gcWBoldReverse, gcWideReverse); 1176 setCgsFont(xw, win, gcWBoldReverse, &(screen->fnts[fWBold])); 1177 } 1178 }); 1179 1180#if OPT_BOX_CHARS 1181 screen->allow_packing = proportional; 1182 setupPackedFonts(xw); 1183#endif 1184 screen->fnt_prop = (Boolean) (proportional && !(screen->force_packed)); 1185 screen->fnt_boxes = True; 1186 1187#if OPT_BOX_CHARS 1188 /* 1189 * Xterm uses character positions 1-31 of a font for the line-drawing 1190 * characters. Check that they are all present. The null character 1191 * (0) is special, and is not used. 1192 */ 1193#if OPT_RENDERFONT 1194 if (UsingRenderFont(xw)) { 1195 /* 1196 * FIXME: we shouldn't even be here if we're using Xft. 1197 */ 1198 screen->fnt_boxes = False; 1199 TRACE(("assume Xft missing line-drawing chars\n")); 1200 } else 1201#endif 1202 { 1203 unsigned ch; 1204 1205 for (ch = 1; ch < 32; ch++) { 1206 unsigned n = ch; 1207#if OPT_WIDE_CHARS 1208 if (screen->utf8_mode || screen->unicode_font) { 1209 n = dec2ucs(ch); 1210 if (n == UCS_REPL) 1211 continue; 1212 } 1213#endif 1214 if (IsXtermMissingChar(screen, n, &fnts[fNorm])) { 1215 TRACE(("missing normal char #%d\n", n)); 1216 screen->fnt_boxes = False; 1217 break; 1218 } 1219 if (IsXtermMissingChar(screen, n, &fnts[fBold])) { 1220 TRACE(("missing bold char #%d\n", n)); 1221 screen->fnt_boxes = False; 1222 break; 1223 } 1224 } 1225 } 1226 TRACE(("Will %suse internal line-drawing characters\n", 1227 screen->fnt_boxes ? "not " : "")); 1228#endif 1229 1230 if (screen->always_bold_mode) { 1231 screen->enbolden = screen->bold_mode; 1232 } else { 1233 screen->enbolden = screen->bold_mode 1234 && ((fnts[fNorm].fs == fnts[fBold].fs) 1235 || same_font_name(normal, myfonts.f_b)); 1236 } 1237 TRACE(("Will %suse 1-pixel offset/overstrike to simulate bold\n", 1238 screen->enbolden ? "" : "not ")); 1239 1240 set_menu_font(False); 1241 screen->menu_font_number = fontnum; 1242 set_menu_font(True); 1243 if (tmpname) { /* if setting escape or sel */ 1244 if (screen->MenuFontName(fontnum)) 1245 free((void *) screen->MenuFontName(fontnum)); 1246 screen->MenuFontName(fontnum) = tmpname; 1247 if (fontnum == fontMenu_fontescape) { 1248 SetItemSensitivity(fontMenuEntries[fontMenu_fontescape].widget, 1249 True); 1250 } 1251#if OPT_SHIFT_FONTS 1252 screen->menu_font_sizes[fontnum] = FontSize(fnts[fNorm].fs); 1253#endif 1254 } 1255 if (normal) 1256 free(normal); 1257 set_cursor_gcs(xw); 1258 xtermUpdateFontInfo(xw, doresize); 1259 TRACE(("Success Cgs - xtermLoadFont\n")); 1260 return 1; 1261 1262 bad: 1263 if (normal) 1264 free(normal); 1265 if (tmpname) 1266 free(tmpname); 1267 1268#if OPT_RENDERFONT 1269 if (x_strcasecmp(myfonts.f_n, DEFFONT)) { 1270 int code; 1271 1272 myfonts.f_n = DEFFONT; 1273 TRACE(("...recovering for TrueType fonts\n")); 1274 code = xtermLoadFont(xw, &myfonts, doresize, fontnum); 1275 if (code) { 1276 SetItemSensitivity(fontMenuEntries[fontnum].widget, 1277 UsingRenderFont(xw)); 1278 TRACE(("...recovered size %dx%d\n", 1279 FontHeight(screen), 1280 FontWidth(screen))); 1281 } 1282 return code; 1283 } 1284#endif 1285 1286 releaseWindowGCs(xw, win); 1287 1288 xtermCloseFonts(xw, fnts); 1289 TRACE(("Fail Cgs - xtermLoadFont\n")); 1290 return 0; 1291} 1292 1293#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 1294/* 1295 * Collect font-names that we can modify with the load-vt-fonts() action. 1296 */ 1297#define MERGE_SUBFONT(src,dst,name) \ 1298 if (IsEmpty(dst.name)) { \ 1299 TRACE(("MERGE_SUBFONT " #dst "." #name " merge %s\n", NonNull(src.name))); \ 1300 dst.name = src.name; \ 1301 } else { \ 1302 TRACE(("MERGE_SUBFONT " #dst "." #name " found %s\n", NonNull(dst.name))); \ 1303 } 1304 1305#define INFER_SUBFONT(src,dst,name) \ 1306 if (IsEmpty(dst.name)) { \ 1307 TRACE(("INFER_SUBFONT " #dst "." #name " will infer\n")); \ 1308 dst.name = x_strdup(""); \ 1309 } else { \ 1310 TRACE(("INFER_SUBFONT " #dst "." #name " found %s\n", NonNull(dst.name))); \ 1311 } 1312 1313#define COPY_MENU_FONTS(src,dst) \ 1314 TRACE(("COPY_MENU_FONTS " #src " to " #dst "\n")); \ 1315 for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \ 1316 for (m = 0; m < fMAX; ++m) { \ 1317 dst.menu_font_names[n][m] = x_strdup(src.menu_font_names[n][m]); \ 1318 } \ 1319 TRACE((".. " #dst ".menu_fonts_names[%d] = %s\n", n, dst.menu_font_names[n][fNorm])); \ 1320 } 1321 1322void 1323xtermSaveVTFonts(XtermWidget xw) 1324{ 1325 TScreen *screen = TScreenOf(xw); 1326 Cardinal n, m; 1327 1328 if (!screen->savedVTFonts) { 1329 1330 screen->savedVTFonts = True; 1331 TRACE(("xtermSaveVTFonts saving original\n")); 1332 screen->cacheVTFonts.default_font = xw->misc.default_font; 1333 COPY_MENU_FONTS(xw->screen, screen->cacheVTFonts); 1334 } 1335} 1336 1337#define SAME_STRING(x,y) ((x) == (y) || ((x) && (y) && !strcmp(x, y))) 1338#define SAME_MEMBER(n) SAME_STRING(a->n, b->n) 1339 1340static Boolean 1341sameSubResources(SubResourceRec * a, SubResourceRec * b) 1342{ 1343 Boolean result = True; 1344 int n; 1345 1346 if (!SAME_MEMBER(default_font.f_n) 1347 || !SAME_MEMBER(default_font.f_b) 1348#if OPT_WIDE_CHARS 1349 || !SAME_MEMBER(default_font.f_w) 1350 || !SAME_MEMBER(default_font.f_wb) 1351#endif 1352 ) { 1353 TRACE(("sameSubResources: default_font differs\n")); 1354 result = False; 1355 } else { 1356 for (n = 0; n < NMENUFONTS; ++n) { 1357 if (!SAME_MEMBER(menu_font_names[n][fNorm])) { 1358 TRACE(("sameSubResources: menu_font_names[%d] differs\n", n)); 1359 result = False; 1360 break; 1361 } 1362 } 1363 } 1364 1365 return result; 1366} 1367 1368/* 1369 * Load the "VT" font names from the given subresource name/class. These 1370 * correspond to the VT100 resources. 1371 */ 1372static Bool 1373xtermLoadVTFonts(XtermWidget xw, String myName, String myClass) 1374{ 1375 SubResourceRec subresourceRec; 1376 SubResourceRec referenceRec; 1377 1378 /* 1379 * These are duplicates of the VT100 font resources, but with a special 1380 * application/classname passed in to distinguish them. 1381 */ 1382 static XtResource font_resources[] = 1383 { 1384 Sres(XtNfont, XtCFont, default_font.f_n, DEFFONT), 1385 Sres(XtNboldFont, XtCBoldFont, default_font.f_b, DEFBOLDFONT), 1386#if OPT_WIDE_CHARS 1387 Sres(XtNwideFont, XtCWideFont, default_font.f_w, DEFWIDEFONT), 1388 Sres(XtNwideBoldFont, XtCWideBoldFont, default_font.f_wb, DEFWIDEBOLDFONT), 1389#endif 1390 Sres(XtNfont1, XtCFont1, MenuFontName(fontMenu_font1), NULL), 1391 Sres(XtNfont2, XtCFont2, MenuFontName(fontMenu_font2), NULL), 1392 Sres(XtNfont3, XtCFont3, MenuFontName(fontMenu_font3), NULL), 1393 Sres(XtNfont4, XtCFont4, MenuFontName(fontMenu_font4), NULL), 1394 Sres(XtNfont5, XtCFont5, MenuFontName(fontMenu_font5), NULL), 1395 Sres(XtNfont6, XtCFont6, MenuFontName(fontMenu_font6), NULL), 1396 }; 1397 Cardinal n, m; 1398 Bool status = True; 1399 TScreen *screen = TScreenOf(xw); 1400 1401 TRACE(("called xtermLoadVTFonts(name=%s, class=%s)\n", 1402 NonNull(myName), NonNull(myClass))); 1403 1404 xtermSaveVTFonts(xw); 1405 1406 if (IsEmpty(myName)) { 1407 TRACE(("xtermLoadVTFonts restoring original\n")); 1408 xw->misc.default_font = screen->cacheVTFonts.default_font; 1409 COPY_MENU_FONTS(screen->cacheVTFonts, xw->screen); 1410 for (n = 0; n < XtNumber(screen->cacheVTFonts.menu_font_names); ++n) { 1411 screen->MenuFontName(n) = screen->cacheVTFonts.MenuFontName(n); 1412 } 1413 } else { 1414 TRACE(("xtermLoadVTFonts(%s, %s)\n", myName, myClass)); 1415 1416 memset(&referenceRec, 0, sizeof(referenceRec)); 1417 memset(&subresourceRec, 0, sizeof(subresourceRec)); 1418 XtGetSubresources((Widget) xw, (XtPointer) &subresourceRec, 1419 myName, myClass, 1420 font_resources, 1421 (Cardinal) XtNumber(font_resources), 1422 NULL, (Cardinal) 0); 1423 1424 /* 1425 * XtGetSubresources returns no status, so we compare the returned 1426 * data against a zero'd struct to see if any data is returned. 1427 */ 1428 if (memcmp(&referenceRec, &subresourceRec, sizeof(referenceRec)) 1429 && !sameSubResources(&(screen->cacheVTFonts), &subresourceRec)) { 1430 1431 screen->mergedVTFonts = True; 1432 1433 /* 1434 * If a particular resource value was not found, use the original. 1435 */ 1436 MERGE_SUBFONT(xw->misc, subresourceRec, default_font.f_n); 1437 INFER_SUBFONT(xw->misc, subresourceRec, default_font.f_b); 1438#if OPT_WIDE_CHARS 1439 INFER_SUBFONT(xw->misc, subresourceRec, default_font.f_w); 1440 INFER_SUBFONT(xw->misc, subresourceRec, default_font.f_wb); 1441#endif 1442 for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) 1443 MERGE_SUBFONT(xw->screen, subresourceRec, MenuFontName(n)); 1444 1445 /* 1446 * Finally, copy the subresource data to the widget. 1447 */ 1448 xw->misc.default_font = subresourceRec.default_font; 1449 COPY_MENU_FONTS(subresourceRec, xw->screen); 1450 screen->MenuFontName(fontMenu_default) = x_strdup(xw->misc.default_font.f_n); 1451 screen->menu_font_names[0][fBold] = x_strdup(xw->misc.default_font.f_b); 1452#if OPT_WIDE_CHARS 1453 screen->menu_font_names[0][fWide] = x_strdup(xw->misc.default_font.f_w); 1454 screen->menu_font_names[0][fWBold] = x_strdup(xw->misc.default_font.f_wb); 1455#endif 1456 } else { 1457 TRACE(("...no resources found\n")); 1458 status = False; 1459 } 1460 } 1461 return status; 1462} 1463 1464#if OPT_WIDE_CHARS 1465static Bool 1466isWideFont(XFontStruct * fp, const char *tag, Bool nullOk) 1467{ 1468 Bool result = False; 1469 1470 (void) tag; 1471 if (okFont(fp)) { 1472 unsigned count = countGlyphs(fp); 1473 TRACE(("isWideFont(%s) found %d cells\n", tag, count)); 1474 result = (count > 256) ? True : False; 1475 } else { 1476 result = nullOk; 1477 } 1478 return result; 1479} 1480 1481/* 1482 * If the current fonts are not wide, load the UTF8 fonts. 1483 * 1484 * Called during initialization (for wide-character mode), the fonts have not 1485 * been setup, so we pass nullOk=True to isWideFont(). 1486 * 1487 * Called after initialization, e.g., in response to the UTF-8 menu entry 1488 * (starting from narrow character mode), it checks if the fonts are not wide. 1489 */ 1490Bool 1491xtermLoadWideFonts(XtermWidget xw, Bool nullOk) 1492{ 1493 TScreen *screen = TScreenOf(xw); 1494 Bool result; 1495 1496 if (EmptyFont(screen->fnts[fWide].fs)) { 1497 result = (isWideFont(screen->fnts[fNorm].fs, "normal", nullOk) 1498 && isWideFont(screen->fnts[fBold].fs, "bold", nullOk)); 1499 } else { 1500 result = (isWideFont(screen->fnts[fWide].fs, "wide", nullOk) 1501 && isWideFont(screen->fnts[fWBold].fs, "wide-bold", nullOk)); 1502 if (result && !screen->utf8_latin1) { 1503 result = (isWideFont(screen->fnts[fNorm].fs, "normal", nullOk) 1504 && isWideFont(screen->fnts[fBold].fs, "bold", nullOk)); 1505 } 1506 } 1507 if (!result) { 1508 TRACE(("current fonts are not all wide%s\n", nullOk ? " nullOk" : "")); 1509 result = xtermLoadVTFonts(xw, XtNutf8Fonts, XtCUtf8Fonts); 1510 } 1511 TRACE(("xtermLoadWideFonts:%d\n", result)); 1512 return result; 1513} 1514#endif /* OPT_WIDE_CHARS */ 1515 1516/* 1517 * Restore the default fonts, i.e., if we had switched to wide-fonts. 1518 */ 1519Bool 1520xtermLoadDefaultFonts(XtermWidget xw) 1521{ 1522 Bool result; 1523 result = xtermLoadVTFonts(xw, NULL, NULL); 1524 TRACE(("xtermLoadDefaultFonts:%d\n", result)); 1525 return result; 1526} 1527#endif /* OPT_LOAD_VTFONTS || OPT_WIDE_CHARS */ 1528 1529#if OPT_LOAD_VTFONTS 1530void 1531HandleLoadVTFonts(Widget w, 1532 XEvent * event GCC_UNUSED, 1533 String * params GCC_UNUSED, 1534 Cardinal *param_count GCC_UNUSED) 1535{ 1536 static char empty[] = ""; /* appease strict compilers */ 1537 1538 XtermWidget xw; 1539 1540 if ((xw = getXtermWidget(w)) != 0) { 1541 TScreen *screen = TScreenOf(xw); 1542 char name_buf[80]; 1543 char class_buf[80]; 1544 String name = (String) ((*param_count > 0) ? params[0] : empty); 1545 char *myName = (char *) MyStackAlloc(strlen(name) + 1, name_buf); 1546 String convert = (String) ((*param_count > 1) ? params[1] : myName); 1547 char *myClass = (char *) MyStackAlloc(strlen(convert) + 1, class_buf); 1548 int n; 1549 1550 TRACE(("HandleLoadVTFonts(%d)\n", *param_count)); 1551 strcpy(myName, name); 1552 strcpy(myClass, convert); 1553 if (*param_count == 1) 1554 myClass[0] = x_toupper(myClass[0]); 1555 1556 if (xtermLoadVTFonts(xw, myName, myClass)) { 1557 /* 1558 * When switching fonts, try to preserve the font-menu selection, since 1559 * it is less surprising to do that (if the font-switching can be 1560 * undone) than to switch to "Default". 1561 */ 1562 int font_number = screen->menu_font_number; 1563 if (font_number > fontMenu_lastBuiltin) 1564 font_number = fontMenu_lastBuiltin; 1565 for (n = 0; n < NMENUFONTS; ++n) 1566 screen->menu_font_sizes[n] = 0; 1567 SetVTFont(xw, font_number, True, 1568 ((font_number == fontMenu_default) 1569 ? &(xw->misc.default_font) 1570 : NULL)); 1571 } 1572 1573 MyStackFree(myName, name_buf); 1574 MyStackFree(myClass, class_buf); 1575 } 1576} 1577#endif /* OPT_LOAD_VTFONTS */ 1578 1579/* 1580 * Set the limits for the box that outlines the cursor. 1581 */ 1582void 1583xtermSetCursorBox(TScreen * screen) 1584{ 1585 static XPoint VTbox[NBOX]; 1586 XPoint *vp; 1587 int fw = FontWidth(screen) - 1; 1588 int fh = FontHeight(screen) - 1; 1589 int ww = isCursorBar(screen) ? 1 : fw; 1590 int hh = isCursorUnderline(screen) ? 1 : fh; 1591 1592 vp = &VTbox[1]; 1593 (vp++)->x = (short) ww; 1594 (vp++)->y = (short) hh; 1595 (vp++)->x = (short) -ww; 1596 vp->y = (short) -hh; 1597 1598 screen->box = VTbox; 1599} 1600 1601#define CACHE_XFT(dst,src) if (src != 0) {\ 1602 checkXft(xw, &(dst[fontnum]), src);\ 1603 TRACE(("Xft metrics %s[%d] = %d (%d,%d)%s advance %d, actual %d%s\n",\ 1604 #dst,\ 1605 fontnum,\ 1606 src->height,\ 1607 src->ascent,\ 1608 src->descent,\ 1609 ((src->ascent + src->descent) > src->height ? "*" : ""),\ 1610 src->max_advance_width,\ 1611 dst[fontnum].map.min_width,\ 1612 dst[fontnum].map.mixed ? " mixed" : ""));\ 1613 } 1614 1615#if OPT_RENDERFONT 1616 1617#if OPT_TRACE > 1 1618static FcChar32 1619xtermXftFirstChar(XftFont * xft) 1620{ 1621 FcChar32 map[FC_CHARSET_MAP_SIZE]; 1622 FcChar32 next; 1623 FcChar32 first; 1624 int i; 1625 1626 first = FcCharSetFirstPage(xft->charset, map, &next); 1627 for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) 1628 if (map[i]) { 1629 FcChar32 bits = map[i]; 1630 first += i * 32; 1631 while (!(bits & 0x1)) { 1632 bits >>= 1; 1633 first++; 1634 } 1635 break; 1636 } 1637 return first; 1638} 1639 1640static FcChar32 1641xtermXftLastChar(XftFont * xft) 1642{ 1643 FcChar32 this, last, next; 1644 FcChar32 map[FC_CHARSET_MAP_SIZE]; 1645 int i; 1646 last = FcCharSetFirstPage(xft->charset, map, &next); 1647 while ((this = FcCharSetNextPage(xft->charset, map, &next)) != FC_CHARSET_DONE) 1648 last = this; 1649 last &= ~0xff; 1650 for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--) 1651 if (map[i]) { 1652 FcChar32 bits = map[i]; 1653 last += i * 32 + 31; 1654 while (!(bits & 0x80000000)) { 1655 last--; 1656 bits <<= 1; 1657 } 1658 break; 1659 } 1660 return (long) last; 1661} 1662 1663static void 1664dumpXft(XtermWidget xw, XTermXftFonts * data) 1665{ 1666 XftFont *xft = data->font; 1667 TScreen *screen = TScreenOf(xw); 1668 VTwin *win = WhichVWin(screen); 1669 1670 FcChar32 c; 1671 FcChar32 first = xtermXftFirstChar(xft); 1672 FcChar32 last = xtermXftLastChar(xft); 1673 unsigned count = 0; 1674 unsigned outside = 0; 1675 1676 TRACE(("dumpXft {{\n")); 1677 TRACE((" data range %#6x..%#6x\n", first, last)); 1678 for (c = first; c <= last; ++c) { 1679 if (FcCharSetHasChar(xft->charset, c)) { 1680 int width = my_wcwidth((int) c); 1681 XGlyphInfo extents; 1682 1683 XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents); 1684 TRACE(("%#6x %2d %.1f\n", c, width, 1685 ((double) extents.width) / win->f_width)); 1686 if (extents.width > win->f_width) 1687 ++outside; 1688 ++count; 1689 } 1690 } 1691 TRACE(("}} %u total, %u outside\n", count, outside)); 1692} 1693#define DUMP_XFT(xw, data) dumpXft(xw, data) 1694#else 1695#define DUMP_XFT(xw, data) /* nothing */ 1696#endif 1697 1698static void 1699checkXft(XtermWidget xw, XTermXftFonts * data, XftFont * xft) 1700{ 1701 FcChar32 c; 1702 Dimension width = 0; 1703 1704 data->font = xft; 1705 data->map.min_width = 0; 1706 data->map.max_width = (Dimension) xft->max_advance_width; 1707 1708 /* 1709 * For each ASCII or ISO-8859-1 printable code, ask what its width is. 1710 * Given the maximum width for those, we have a reasonable estimate of 1711 * the single-column width. 1712 * 1713 * Ignore control characters - their extent information is misleading. 1714 */ 1715 for (c = 32; c < 256; ++c) { 1716 if (c >= 127 && c <= 159) 1717 continue; 1718 if (FcCharSetHasChar(xft->charset, c)) { 1719 XGlyphInfo extents; 1720 1721 XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents); 1722 if (width < extents.width && extents.width <= data->map.max_width) { 1723 width = extents.width; 1724 } 1725 } 1726 } 1727 data->map.min_width = width; 1728 data->map.mixed = (data->map.max_width >= (data->map.min_width + 1)); 1729} 1730 1731static XftFont * 1732xtermOpenXft(XtermWidget xw, const char *name, XftPattern * pat, const char *tag) 1733{ 1734 TScreen *screen = TScreenOf(xw); 1735 Display *dpy = screen->display; 1736 XftPattern *match; 1737 XftResult status; 1738 XftFont *result = 0; 1739 1740 if (pat != 0) { 1741 match = XftFontMatch(dpy, DefaultScreen(dpy), pat, &status); 1742 if (match != 0) { 1743 result = XftFontOpenPattern(dpy, match); 1744 if (result != 0) { 1745 TRACE(("...matched %s font\n", tag)); 1746 } else { 1747 TRACE(("...could did not open %s font\n", tag)); 1748 XftPatternDestroy(match); 1749 if (xw->misc.fontWarnings >= fwAlways) { 1750 TRACE(("OOPS cannot open %s font \"%s\"\n", tag, name)); 1751 xtermWarning("cannot open %s font \"%s\"\n", tag, name); 1752 } 1753 } 1754 } else { 1755 TRACE(("...did not match %s font\n", tag)); 1756 if (xw->misc.fontWarnings >= fwResource) { 1757 TRACE(("OOPS: cannot match %s font \"%s\"\n", tag, name)); 1758 xtermWarning("cannot match %s font \"%s\"\n", tag, name); 1759 } 1760 } 1761 } 1762 return result; 1763} 1764#endif 1765 1766#if OPT_RENDERFONT 1767#if OPT_SHIFT_FONTS 1768/* 1769 * Don't make a dependency on the math library for a single function. 1770 * (Newton Raphson). 1771 */ 1772static double 1773dimSquareRoot(double value) 1774{ 1775 double result = 0.0; 1776 if (value > 0.0) { 1777 int n; 1778 double older = value; 1779 for (n = 0; n < 10; ++n) { 1780 double delta = (older * older - value) / (2.0 * older); 1781 double newer = older - delta; 1782 older = newer; 1783 result = newer; 1784 if (delta > -0.001 && delta < 0.001) 1785 break; 1786 } 1787 } 1788 return result; 1789} 1790#endif 1791 1792/* 1793 * Given the Xft font metrics, determine the actual font size. This is used 1794 * for each font to ensure that normal, bold and italic fonts follow the same 1795 * rule. 1796 */ 1797static void 1798setRenderFontsize(TScreen * screen, VTwin * win, XftFont * font, const char *tag) 1799{ 1800 if (font != 0) { 1801 int width, height, ascent, descent; 1802 1803 (void) screen; 1804 1805 width = font->max_advance_width; 1806 height = font->height; 1807 ascent = font->ascent; 1808 descent = font->descent; 1809 if (height < ascent + descent) { 1810 TRACE(("...increase height from %d\n", height)); 1811 height = ascent + descent; 1812 } 1813 if (is_double_width_font_xft(screen->display, font)) { 1814 TRACE(("...reduced width from %d\n", width)); 1815 width >>= 1; 1816 } 1817 if (tag == 0) { 1818 SetFontWidth(screen, win, width); 1819 SetFontHeight(screen, win, height); 1820 win->f_ascent = ascent; 1821 win->f_descent = descent; 1822 TRACE(("setRenderFontsize result %dx%d (%d+%d)\n", 1823 width, height, ascent, descent)); 1824 } else if (win->f_width < width || 1825 win->f_height < height || 1826 win->f_ascent < ascent || 1827 win->f_descent < descent) { 1828 TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n", 1829 tag, 1830 win->f_width, win->f_height, win->f_ascent, win->f_descent, 1831 width, height, ascent, descent)); 1832 1833 SetFontWidth(screen, win, width); 1834 SetFontHeight(screen, win, height); 1835 win->f_ascent = ascent; 1836 win->f_descent = descent; 1837 } else { 1838 TRACE(("setRenderFontsize %s unchanged\n", tag)); 1839 } 1840 } 1841} 1842#endif 1843 1844static void 1845checkFontInfo(int value, const char *tag) 1846{ 1847 if (value == 0) { 1848 xtermWarning("Selected font has no non-zero %s for ISO-8859-1 encoding\n", tag); 1849 exit(1); 1850 } 1851} 1852 1853#if OPT_RENDERFONT 1854void 1855xtermCloseXft(TScreen * screen, XTermXftFonts * pub) 1856{ 1857 if (pub->font != 0) { 1858 XftFontClose(screen->display, pub->font); 1859 pub->font = 0; 1860 } 1861} 1862 1863/* 1864 * Get the faceName/faceDoublesize resource setting. Strip off "xft:", which 1865 * is not recognized by XftNameParse(). 1866 */ 1867String 1868getFaceName(XtermWidget xw, Bool wideName GCC_UNUSED) 1869{ 1870#if OPT_RENDERWIDE 1871 String result = (wideName 1872 ? xw->misc.face_wide_name 1873 : xw->misc.face_name); 1874#else 1875 String result = xw->misc.face_name; 1876#endif 1877 if (!IsEmpty(result) && !strncmp(result, "xft:", (size_t) 4)) 1878 result += 4; 1879 return x_nonempty(result); 1880} 1881 1882/* 1883 * If we change the faceName, we'll have to re-acquire all of the fonts that 1884 * are derived from it. 1885 */ 1886void 1887setFaceName(XtermWidget xw, const char *value) 1888{ 1889 TScreen *screen = TScreenOf(xw); 1890 int n; 1891 Boolean changed = (Boolean) ((xw->misc.face_name == 0) 1892 || strcmp(xw->misc.face_name, value)); 1893 1894 if (changed) { 1895 xw->misc.face_name = x_strdup(value); 1896 for (n = 0; n < NMENUFONTS; ++n) { 1897 xw->misc.face_size[n] = -1.0; 1898 xtermCloseXft(screen, &(screen->renderFontNorm[n])); 1899 xtermCloseXft(screen, &(screen->renderFontBold[n])); 1900 xtermCloseXft(screen, &(screen->renderFontBold[n])); 1901#if OPT_RENDERWIDE 1902 xtermCloseXft(screen, &(screen->renderWideNorm[n])); 1903 xtermCloseXft(screen, &(screen->renderWideBold[n])); 1904 xtermCloseXft(screen, &(screen->renderWideItal[n])); 1905#endif 1906 } 1907 } 1908} 1909#endif 1910 1911/* 1912 * Compute useful values for the font/window sizes 1913 */ 1914void 1915xtermComputeFontInfo(XtermWidget xw, 1916 VTwin * win, 1917 XFontStruct * font, 1918 int sbwidth) 1919{ 1920 TScreen *screen = TScreenOf(xw); 1921 1922 int i, j, width, height; 1923#if OPT_RENDERFONT 1924 int fontnum = screen->menu_font_number; 1925#endif 1926 1927#if OPT_RENDERFONT 1928 /* 1929 * xterm contains a lot of references to fonts, assuming they are fixed 1930 * size. This chunk of code overrides the actual font-selection (see 1931 * drawXtermText()), if the user has selected render-font. All of the 1932 * font-loading for fixed-fonts still goes on whether or not this chunk 1933 * overrides it. 1934 */ 1935 if (UsingRenderFont(xw) && fontnum >= 0) { 1936 String face_name = getFaceName(xw, False); 1937 XftFont *norm = screen->renderFontNorm[fontnum].font; 1938 XftFont *bold = screen->renderFontBold[fontnum].font; 1939 XftFont *ital = screen->renderFontItal[fontnum].font; 1940#if OPT_RENDERWIDE 1941 XftFont *wnorm = screen->renderWideNorm[fontnum].font; 1942 XftFont *wbold = screen->renderWideBold[fontnum].font; 1943 XftFont *wital = screen->renderWideItal[fontnum].font; 1944#endif 1945 1946 if (norm == 0 && face_name) { 1947 XftPattern *pat; 1948 double face_size; 1949 1950 TRACE(("xtermComputeFontInfo font %d: norm(face %s, size %.1f)\n", 1951 fontnum, face_name, 1952 xw->misc.face_size[fontnum])); 1953 1954 fillInFaceSize(xw, fontnum); 1955 face_size = xw->misc.face_size[fontnum]; 1956 1957 /* 1958 * By observation (there is no documentation), XftPatternBuild is 1959 * cumulative. Build the bold- and italic-patterns on top of the 1960 * normal pattern. 1961 */ 1962#define NormXftPattern \ 1963 XFT_FAMILY, XftTypeString, "mono", \ 1964 XFT_SIZE, XftTypeDouble, face_size, \ 1965 XFT_SPACING, XftTypeInteger, XFT_MONO 1966 1967#define BoldXftPattern(norm) \ 1968 XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \ 1969 XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width 1970 1971#define ItalXftPattern(norm) \ 1972 XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \ 1973 XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width 1974 1975 if ((pat = XftNameParse(face_name)) != 0) { 1976#define OPEN_XFT(tag) xtermOpenXft(xw, face_name, pat, tag) 1977 XftPatternBuild(pat, 1978 NormXftPattern, 1979 (void *) 0); 1980 norm = OPEN_XFT("normal"); 1981 1982 if (norm != 0) { 1983 XftPatternBuild(pat, 1984 BoldXftPattern(norm), 1985 (void *) 0); 1986 bold = OPEN_XFT("bold"); 1987 1988#if OPT_ISO_COLORS 1989 if (screen->italicULMode 1990 && (pat = XftNameParse(face_name)) != 0) { 1991 XftPatternBuild(pat, 1992 NormXftPattern, 1993 ItalXftPattern(norm), 1994 (void *) 0); 1995 ital = OPEN_XFT("italic"); 1996 } 1997#endif /* OPT_ISO_COLORS */ 1998#undef OPEN_XFT 1999 2000 /* 2001 * FIXME: just assume that the corresponding font has no 2002 * graphics characters. 2003 */ 2004 if (screen->fnt_boxes) { 2005 screen->fnt_boxes = False; 2006 TRACE(("Xft opened - will %suse internal line-drawing characters\n", 2007 screen->fnt_boxes ? "not " : "")); 2008 } 2009 } 2010 2011 XftPatternDestroy(pat); 2012 } 2013 2014 CACHE_XFT(screen->renderFontNorm, norm); 2015 CACHE_XFT(screen->renderFontBold, bold); 2016 CACHE_XFT(screen->renderFontItal, ital); 2017 2018 /* 2019 * See xtermXftDrawString(). 2020 */ 2021#if OPT_RENDERWIDE 2022 if (norm != 0 && screen->wide_chars) { 2023 int char_width = norm->max_advance_width * 2; 2024#ifdef FC_ASPECT 2025 double aspect = ((xw->misc.face_wide_name 2026 || screen->renderFontNorm[fontnum].map.mixed) 2027 ? 1.0 2028 : 2.0); 2029#endif 2030 2031 face_name = getFaceName(xw, True); 2032 TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n", 2033 NonNull(face_name), 2034 char_width)); 2035 2036#define WideXftPattern \ 2037 XFT_FAMILY, XftTypeString, "mono", \ 2038 XFT_SIZE, XftTypeDouble, face_size, \ 2039 XFT_SPACING, XftTypeInteger, XFT_MONO 2040 2041 if (face_name && (pat = XftNameParse(face_name)) != 0) { 2042#define OPEN_XFT(tag) xtermOpenXft(xw, face_name, pat, tag) 2043 XftPatternBuild(pat, 2044 WideXftPattern, 2045 XFT_CHAR_WIDTH, XftTypeInteger, char_width, 2046#ifdef FC_ASPECT 2047 FC_ASPECT, XftTypeDouble, aspect, 2048#endif 2049 (void *) 0); 2050 wnorm = OPEN_XFT("wide"); 2051 2052 if (wnorm != 0) { 2053 XftPatternBuild(pat, 2054 WideXftPattern, 2055 BoldXftPattern(wnorm), 2056 (void *) 0); 2057 wbold = OPEN_XFT("wide-bold"); 2058 2059#if OPT_ISO_COLORS 2060 if (screen->italicULMode 2061 && (pat = XftNameParse(face_name)) != 0) { 2062 XftPatternBuild(pat, 2063 WideXftPattern, 2064 ItalXftPattern(wnorm), 2065 (void *) 0); 2066 wital = OPEN_XFT("wide-italic"); 2067 } 2068#endif 2069#undef OPEN_XFT 2070 } 2071 XftPatternDestroy(pat); 2072 } 2073 2074 CACHE_XFT(screen->renderWideNorm, wnorm); 2075 CACHE_XFT(screen->renderWideBold, wbold); 2076 CACHE_XFT(screen->renderWideItal, wital); 2077 } 2078#endif /* OPT_RENDERWIDE */ 2079 } 2080 if (norm == 0) { 2081 TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum)); 2082 xw->work.render_font = False; 2083 update_font_renderfont(); 2084 /* now we will fall through into the bitmap fonts */ 2085 } else { 2086 setRenderFontsize(screen, win, norm, NULL); 2087 setRenderFontsize(screen, win, bold, "bold"); 2088 setRenderFontsize(screen, win, ital, "ital"); 2089#if OPT_BOX_CHARS 2090 setupPackedFonts(xw); 2091 2092 if (screen->force_packed) { 2093 XTermXftFonts *use = &(screen->renderFontNorm[fontnum]); 2094 SetFontHeight(screen, win, use->font->ascent + use->font->descent); 2095 SetFontWidth(screen, win, use->map.min_width); 2096 TRACE(("...packed TrueType font %dx%d vs %d\n", 2097 win->f_height, 2098 win->f_width, 2099 use->map.max_width)); 2100 } 2101#endif 2102 DUMP_XFT(xw, &(screen->renderFontNorm[fontnum])); 2103 } 2104 } 2105 /* 2106 * Are we handling a bitmap font? 2107 */ 2108 else 2109#endif /* OPT_RENDERFONT */ 2110 { 2111 if (is_double_width_font(font) && !(screen->fnt_prop)) { 2112 SetFontWidth(screen, win, font->min_bounds.width); 2113 } else { 2114 SetFontWidth(screen, win, font->max_bounds.width); 2115 } 2116 SetFontHeight(screen, win, font->ascent + font->descent); 2117 win->f_ascent = font->ascent; 2118 win->f_descent = font->descent; 2119 } 2120 i = 2 * screen->border + sbwidth; 2121 j = 2 * screen->border; 2122 width = MaxCols(screen) * win->f_width + i; 2123 height = MaxRows(screen) * win->f_height + j; 2124 win->fullwidth = (Dimension) width; 2125 win->fullheight = (Dimension) height; 2126 win->width = width - i; 2127 win->height = height - j; 2128 2129 TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n", 2130 win->height, 2131 win->width, 2132 win->fullheight, 2133 win->fullwidth, 2134 win->f_height, 2135 win->f_width, 2136 win->f_ascent, 2137 win->f_descent)); 2138 2139 checkFontInfo(win->f_height, "height"); 2140 checkFontInfo(win->f_width, "width"); 2141} 2142 2143/* save this information as a side-effect for double-sized characters */ 2144void 2145xtermSaveFontInfo(TScreen * screen, XFontStruct * font) 2146{ 2147 screen->fnt_wide = (Dimension) (font->max_bounds.width); 2148 screen->fnt_high = (Dimension) (font->ascent + font->descent); 2149 TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide)); 2150} 2151 2152/* 2153 * After loading a new font, update the structures that use its size. 2154 */ 2155void 2156xtermUpdateFontInfo(XtermWidget xw, Bool doresize) 2157{ 2158 TScreen *screen = TScreenOf(xw); 2159 2160 int scrollbar_width; 2161 VTwin *win = &(screen->fullVwin); 2162 2163 scrollbar_width = (xw->misc.scrollbar 2164 ? (screen->scrollWidget->core.width + 2165 BorderWidth(screen->scrollWidget)) 2166 : 0); 2167 xtermComputeFontInfo(xw, win, screen->fnts[fNorm].fs, scrollbar_width); 2168 xtermSaveFontInfo(screen, screen->fnts[fNorm].fs); 2169 2170 if (doresize) { 2171 if (VWindow(screen)) { 2172 xtermClear(xw); 2173 } 2174 TRACE(("xtermUpdateFontInfo {{\n")); 2175 DoResizeScreen(xw); /* set to the new natural size */ 2176 ResizeScrollBar(xw); 2177 Redraw(); 2178 TRACE(("... }} xtermUpdateFontInfo\n")); 2179#ifdef SCROLLBAR_RIGHT 2180 updateRightScrollbar(xw); 2181#endif 2182 } 2183 xtermSetCursorBox(screen); 2184} 2185 2186#if OPT_BOX_CHARS 2187 2188/* 2189 * Returns true if the given character is missing from the specified font. 2190 */ 2191Bool 2192xtermMissingChar(unsigned ch, XTermFonts * font) 2193{ 2194 Bool result = False; 2195 XFontStruct *fs = font->fs; 2196 static XCharStruct dft, *tmp = &dft, *pc = 0; 2197 2198 if (fs->max_byte1 == 0) { 2199#if OPT_WIDE_CHARS 2200 if (ch > 255) { 2201 TRACE(("xtermMissingChar %#04x (row)\n", ch)); 2202 return True; 2203 } 2204#endif 2205 CI_GET_CHAR_INFO_1D(fs, E2A(ch), tmp, pc); 2206 } 2207#if OPT_WIDE_CHARS 2208 else { 2209 CI_GET_CHAR_INFO_2D(fs, HI_BYTE(ch), LO_BYTE(ch), tmp, pc); 2210 } 2211#else 2212 2213 if (!pc) 2214 return False; /* Urgh! */ 2215#endif 2216 2217 if (CI_NONEXISTCHAR(pc)) { 2218 TRACE(("xtermMissingChar %#04x (!exists)\n", ch)); 2219 result = True; 2220 } 2221 if (ch < 256) { 2222 font->known_missing[ch] = (Char) (result ? 2 : 1); 2223 } 2224 return result; 2225} 2226 2227/* 2228 * The grid is arbitrary, enough resolution that nothing's lost in 2229 * initialization. 2230 */ 2231#define BOX_HIGH 60 2232#define BOX_WIDE 60 2233 2234#define MID_HIGH (BOX_HIGH/2) 2235#define MID_WIDE (BOX_WIDE/2) 2236 2237#define CHR_WIDE ((9*BOX_WIDE)/10) 2238#define CHR_HIGH ((9*BOX_HIGH)/10) 2239 2240/* 2241 * ...since we'll scale the values anyway. 2242 */ 2243#define SCALED_X(n) ((int)(n) * (((int) font_width) - 1)) / (BOX_WIDE-1) 2244#define SCALED_Y(n) ((int)(n) * (((int) font_height) - 1)) / (BOX_HIGH-1) 2245#define SCALE_X(n) n = SCALED_X(n) 2246#define SCALE_Y(n) n = SCALED_Y(n) 2247 2248#define SEG(x0,y0,x1,y1) x0,y0, x1,y1 2249 2250/* 2251 * Draw the given graphic character, if it is simple enough (i.e., a 2252 * line-drawing character). 2253 */ 2254void 2255xtermDrawBoxChar(XtermWidget xw, 2256 unsigned ch, 2257 unsigned flags, 2258 GC gc, 2259 int x, 2260 int y, 2261 int cells) 2262{ 2263 TScreen *screen = TScreenOf(xw); 2264 /* *INDENT-OFF* */ 2265 static const short glyph_ht[] = { 2266 SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,5*MID_HIGH/6), /* H */ 2267 SEG(6*BOX_WIDE/10, 0, 6*BOX_WIDE/10,5*MID_HIGH/6), 2268 SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12), 2269 SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 2270 SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 2271 -1 2272 }, glyph_ff[] = { 2273 SEG(1*BOX_WIDE/10, 0, 6*BOX_WIDE/10, 0), /* F */ 2274 SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12), 2275 SEG(1*BOX_WIDE/10, 0, 0*BOX_WIDE/3, 5*MID_HIGH/6), 2276 SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 2277 SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 2278 SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 2279 -1 2280 }, glyph_lf[] = { 2281 SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,9*MID_HIGH/12), /* L */ 2282 SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12), 2283 SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 2284 SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 2285 SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 2286 -1 2287 }, glyph_nl[] = { 2288 SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10, 0), /* N */ 2289 SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/6, 5*MID_HIGH/6), 2290 SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 2291 SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), /* L */ 2292 SEG(1*BOX_WIDE/3, CHR_HIGH, CHR_WIDE, CHR_HIGH), 2293 -1 2294 }, glyph_vt[] = { 2295 SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/12,5*MID_HIGH/6), /* V */ 2296 SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 2297 SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 2298 SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 2299 -1 2300 }, plus_or_minus[] = 2301 { 2302 SEG( 0, 5*BOX_HIGH/6, CHR_WIDE, 5*BOX_HIGH/6), 2303 SEG( MID_WIDE, 2*BOX_HIGH/6, MID_WIDE, 4*BOX_HIGH/6), 2304 SEG( 0, 3*BOX_HIGH/6, CHR_WIDE, 3*BOX_HIGH/6), 2305 -1 2306 }, lower_right_corner[] = 2307 { 2308 SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 2309 SEG( MID_WIDE, MID_HIGH, MID_WIDE, 0), 2310 -1 2311 }, upper_right_corner[] = 2312 { 2313 SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 2314 SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 2315 -1 2316 }, upper_left_corner[] = 2317 { 2318 SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 2319 SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 2320 -1 2321 }, lower_left_corner[] = 2322 { 2323 SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 2324 SEG( MID_WIDE, MID_WIDE, BOX_WIDE, MID_HIGH), 2325 -1 2326 }, cross[] = 2327 { 2328 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 2329 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 2330 -1 2331 }, scan_line_1[] = 2332 { 2333 SEG( 0, 0, BOX_WIDE, 0), 2334 -1 2335 }, scan_line_3[] = 2336 { 2337 SEG( 0, BOX_HIGH/4, BOX_WIDE, BOX_HIGH/4), 2338 -1 2339 }, scan_line_7[] = 2340 { 2341 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 2342 -1 2343 }, scan_line_9[] = 2344 { 2345 SEG( 0, 3*BOX_HIGH/4, BOX_WIDE, 3*BOX_HIGH/4), 2346 -1 2347 }, horizontal_line[] = 2348 { 2349 SEG( 0, BOX_HIGH, BOX_WIDE, BOX_HIGH), 2350 -1 2351 }, left_tee[] = 2352 { 2353 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 2354 SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 2355 -1 2356 }, right_tee[] = 2357 { 2358 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 2359 SEG( MID_WIDE, MID_HIGH, 0, MID_HIGH), 2360 -1 2361 }, bottom_tee[] = 2362 { 2363 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 2364 SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 2365 -1 2366 }, top_tee[] = 2367 { 2368 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 2369 SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 2370 -1 2371 }, vertical_line[] = 2372 { 2373 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 2374 -1 2375 }, less_than_or_equal[] = 2376 { 2377 SEG( CHR_WIDE, BOX_HIGH/3, 0, MID_HIGH), 2378 SEG( CHR_WIDE, 2*BOX_HIGH/3, 0, MID_HIGH), 2379 SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 2380 -1 2381 }, greater_than_or_equal[] = 2382 { 2383 SEG( 0, BOX_HIGH/3, CHR_WIDE, MID_HIGH), 2384 SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, MID_HIGH), 2385 SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 2386 -1 2387 }, greek_pi[] = 2388 { 2389 SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 2390 SEG(5*CHR_WIDE/6, MID_HIGH, 5*CHR_WIDE/6, CHR_HIGH), 2391 SEG(2*CHR_WIDE/6, MID_HIGH, 2*CHR_WIDE/6, CHR_HIGH), 2392 -1 2393 }, not_equal_to[] = 2394 { 2395 SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3, CHR_HIGH), 2396 SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, 2*BOX_HIGH/3), 2397 SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 2398 -1 2399 }; 2400 /* *INDENT-ON* */ 2401 2402 static const short *lines[] = 2403 { 2404 0, /* 00 (unused) */ 2405 0, /* 01 diamond */ 2406 0, /* 02 box */ 2407 glyph_ht, /* 03 HT */ 2408 glyph_ff, /* 04 FF */ 2409 0, /* 05 CR */ 2410 glyph_lf, /* 06 LF */ 2411 0, /* 07 degrees (small circle) */ 2412 plus_or_minus, /* 08 */ 2413 glyph_nl, /* 09 */ 2414 glyph_vt, /* 0A */ 2415 lower_right_corner, /* 0B */ 2416 upper_right_corner, /* 0C */ 2417 upper_left_corner, /* 0D */ 2418 lower_left_corner, /* 0E */ 2419 cross, /* 0F */ 2420 scan_line_1, /* 10 */ 2421 scan_line_3, /* 11 */ 2422 scan_line_7, /* 12 */ 2423 scan_line_9, /* 13 */ 2424 horizontal_line, /* 14 */ 2425 left_tee, /* 15 */ 2426 right_tee, /* 16 */ 2427 bottom_tee, /* 17 */ 2428 top_tee, /* 18 */ 2429 vertical_line, /* 19 */ 2430 less_than_or_equal, /* 1A */ 2431 greater_than_or_equal, /* 1B */ 2432 greek_pi, /* 1C */ 2433 not_equal_to, /* 1D */ 2434 0, /* 1E LB */ 2435 0, /* 1F bullet */ 2436 }; 2437 2438 GC gc2; 2439 CgsEnum cgsId = (ch == 2) ? gcDots : gcLine; 2440 VTwin *cgsWin = WhichVWin(screen); 2441 const short *p; 2442 unsigned font_width = (unsigned) (((flags & DOUBLEWFONT) ? 2 : 1) * screen->fnt_wide); 2443 unsigned font_height = (unsigned) (((flags & DOUBLEHFONT) ? 2 : 1) * screen->fnt_high); 2444 2445 if (cells > 1) 2446 font_width *= (unsigned) cells; 2447 2448#if OPT_WIDE_CHARS 2449 /* 2450 * Try to show line-drawing characters if we happen to be in UTF-8 2451 * mode, but have gotten an old-style font. 2452 */ 2453 if (screen->utf8_mode 2454#if OPT_RENDERFONT 2455 && !UsingRenderFont(xw) 2456#endif 2457 && (ch > 127) 2458 && (ch != UCS_REPL)) { 2459 unsigned n; 2460 for (n = 1; n < 32; n++) { 2461 if (dec2ucs(n) == ch 2462 && !((flags & BOLD) 2463 ? IsXtermMissingChar(screen, n, &screen->fnts[fBold]) 2464 : IsXtermMissingChar(screen, n, &screen->fnts[fNorm]))) { 2465 TRACE(("...use xterm-style linedrawing\n")); 2466 ch = n; 2467 break; 2468 } 2469 } 2470 } 2471#endif 2472 2473 TRACE(("DRAW_BOX(%d) cell %dx%d at %d,%d%s\n", 2474 ch, font_height, font_width, y, x, 2475 (ch >= (sizeof(lines) / sizeof(lines[0])) 2476 ? "-BAD" 2477 : ""))); 2478 2479 if (cgsId == gcDots) { 2480 setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc)); 2481 setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc)); 2482 setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 2483 } else { 2484 setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc)); 2485 setCgsFore(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 2486 setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 2487 } 2488 gc2 = getCgsGC(xw, cgsWin, cgsId); 2489 2490 if (!(flags & NOBACKGROUND)) { 2491 XFillRectangle(screen->display, VDrawable(screen), gc2, x, y, 2492 font_width, 2493 font_height); 2494 } 2495 2496 setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc)); 2497 setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc)); 2498 setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 2499 gc2 = getCgsGC(xw, cgsWin, cgsId); 2500 2501 XSetLineAttributes(screen->display, gc2, 2502 (flags & BOLD) 2503 ? ((font_height > 12) 2504 ? font_height / 12 2505 : 1) 2506 : ((font_height > 16) 2507 ? font_height / 16 2508 : 1), 2509 LineSolid, 2510 CapProjecting, 2511 JoinMiter); 2512 2513 if (ch == 1) { /* diamond */ 2514 XPoint points[5]; 2515 int npoints = 5, n; 2516 2517 points[0].x = MID_WIDE; 2518 points[0].y = BOX_HIGH / 4; 2519 2520 points[1].x = 8 * BOX_WIDE / 8; 2521 points[1].y = MID_HIGH; 2522 2523 points[2].x = points[0].x; 2524 points[2].y = 3 * BOX_HIGH / 4; 2525 2526 points[3].x = 0 * BOX_WIDE / 8; 2527 points[3].y = points[1].y; 2528 2529 points[4].x = points[0].x; 2530 points[4].y = points[0].y; 2531 2532 for (n = 0; n < npoints; ++n) { 2533 points[n].x = (short) SCALED_X(points[n].x); 2534 points[n].y = (short) SCALED_Y(points[n].y); 2535 points[n].x = (short) (points[n].x + x); 2536 points[n].y = (short) (points[n].y + y); 2537 } 2538 2539 XFillPolygon(screen->display, 2540 VDrawable(screen), gc2, 2541 points, npoints, 2542 Convex, CoordModeOrigin); 2543 } else if (ch == 7) { /* degrees */ 2544 unsigned width = (BOX_WIDE / 3); 2545 int x_coord = MID_WIDE - (int) (width / 2); 2546 int y_coord = MID_HIGH - (int) width; 2547 2548 SCALE_X(x_coord); 2549 SCALE_Y(y_coord); 2550 width = (unsigned) SCALED_X(width); 2551 2552 XDrawArc(screen->display, 2553 VDrawable(screen), gc2, 2554 x + x_coord, y + y_coord, width, width, 2555 0, 2556 360 * 64); 2557 } else if (ch == 0x1f) { /* bullet */ 2558 unsigned width = 7 * BOX_WIDE / 10; 2559 int x_coord = MID_WIDE - (int) (width / 3); 2560 int y_coord = MID_HIGH - (int) (width / 3); 2561 2562 SCALE_X(x_coord); 2563 SCALE_Y(y_coord); 2564 width = (unsigned) SCALED_X(width); 2565 2566 XDrawArc(screen->display, 2567 VDrawable(screen), gc2, 2568 x + x_coord, y + y_coord, width, width, 2569 0, 2570 360 * 64); 2571 } else if (ch < (sizeof(lines) / sizeof(lines[0])) 2572 && (p = lines[ch]) != 0) { 2573 int coord[4]; 2574 int n = 0; 2575 while (*p >= 0) { 2576 coord[n++] = *p++; 2577 if (n == 4) { 2578 SCALE_X(coord[0]); 2579 SCALE_Y(coord[1]); 2580 SCALE_X(coord[2]); 2581 SCALE_Y(coord[3]); 2582 XDrawLine(screen->display, 2583 VDrawable(screen), gc2, 2584 x + coord[0], y + coord[1], 2585 x + coord[2], y + coord[3]); 2586 n = 0; 2587 } 2588 } 2589 } else if (screen->force_all_chars) { 2590 /* bounding rectangle, for debugging */ 2591 XDrawRectangle(screen->display, VDrawable(screen), gc2, x, y, 2592 font_width - 1, 2593 font_height - 1); 2594 } 2595} 2596 2597#if OPT_RENDERFONT 2598 2599/* 2600 * Check if the given character has a glyph known to Xft. 2601 * 2602 * see xc/lib/Xft/xftglyphs.c 2603 */ 2604Bool 2605xtermXftMissing(XtermWidget xw, XftFont * font, unsigned wc) 2606{ 2607 Bool result = False; 2608 2609 if (font != 0) { 2610 TScreen *screen = TScreenOf(xw); 2611 if (!XftGlyphExists(screen->display, font, wc)) { 2612#if OPT_WIDE_CHARS 2613 TRACE(("xtermXftMissing %d (dec=%#x, ucs=%#x)\n", 2614 wc, ucs2dec(wc), dec2ucs(wc))); 2615#else 2616 TRACE(("xtermXftMissing %d\n", wc)); 2617#endif 2618 result = True; 2619 } 2620 } 2621 return result; 2622} 2623#endif /* OPT_RENDERFONT && OPT_WIDE_CHARS */ 2624 2625#endif /* OPT_BOX_CHARS */ 2626 2627#if OPT_WIDE_CHARS 2628#define MY_UCS(ucs,dec) case ucs: result = dec; break 2629unsigned 2630ucs2dec(unsigned ch) 2631{ 2632 unsigned result = ch; 2633 if ((ch > 127) 2634 && (ch != UCS_REPL)) { 2635 switch (ch) { 2636 MY_UCS(0x25ae, 0); /* black vertical rectangle */ 2637 MY_UCS(0x25c6, 1); /* black diamond */ 2638 MY_UCS(0x2592, 2); /* medium shade */ 2639 MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 2640 MY_UCS(0x240c, 4); /* symbol for form feed */ 2641 MY_UCS(0x240d, 5); /* symbol for carriage return */ 2642 MY_UCS(0x240a, 6); /* symbol for line feed */ 2643 MY_UCS(0x00b0, 7); /* degree sign */ 2644 MY_UCS(0x00b1, 8); /* plus-minus sign */ 2645 MY_UCS(0x2424, 9); /* symbol for newline */ 2646 MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 2647 MY_UCS(0x2518, 11); /* box drawings light up and left */ 2648 MY_UCS(0x2510, 12); /* box drawings light down and left */ 2649 MY_UCS(0x250c, 13); /* box drawings light down and right */ 2650 MY_UCS(0x2514, 14); /* box drawings light up and right */ 2651 MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 2652 MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 2653 MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 2654 MY_UCS(0x2500, 18); /* box drawings light horizontal */ 2655 MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 2656 MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 2657 MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 2658 MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 2659 MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 2660 MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 2661 MY_UCS(0x2502, 25); /* box drawings light vertical */ 2662 MY_UCS(0x2264, 26); /* less-than or equal to */ 2663 MY_UCS(0x2265, 27); /* greater-than or equal to */ 2664 MY_UCS(0x03c0, 28); /* greek small letter pi */ 2665 MY_UCS(0x2260, 29); /* not equal to */ 2666 MY_UCS(0x00a3, 30); /* pound sign */ 2667 MY_UCS(0x00b7, 31); /* middle dot */ 2668 } 2669 } 2670 return result; 2671} 2672 2673#undef MY_UCS 2674#define MY_UCS(ucs,dec) case dec: result = ucs; break 2675 2676unsigned 2677dec2ucs(unsigned ch) 2678{ 2679 unsigned result = ch; 2680 if (xtermIsDecGraphic(ch)) { 2681 switch (ch) { 2682 MY_UCS(0x25ae, 0); /* black vertical rectangle */ 2683 MY_UCS(0x25c6, 1); /* black diamond */ 2684 MY_UCS(0x2592, 2); /* medium shade */ 2685 MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 2686 MY_UCS(0x240c, 4); /* symbol for form feed */ 2687 MY_UCS(0x240d, 5); /* symbol for carriage return */ 2688 MY_UCS(0x240a, 6); /* symbol for line feed */ 2689 MY_UCS(0x00b0, 7); /* degree sign */ 2690 MY_UCS(0x00b1, 8); /* plus-minus sign */ 2691 MY_UCS(0x2424, 9); /* symbol for newline */ 2692 MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 2693 MY_UCS(0x2518, 11); /* box drawings light up and left */ 2694 MY_UCS(0x2510, 12); /* box drawings light down and left */ 2695 MY_UCS(0x250c, 13); /* box drawings light down and right */ 2696 MY_UCS(0x2514, 14); /* box drawings light up and right */ 2697 MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 2698 MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 2699 MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 2700 MY_UCS(0x2500, 18); /* box drawings light horizontal */ 2701 MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 2702 MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 2703 MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 2704 MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 2705 MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 2706 MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 2707 MY_UCS(0x2502, 25); /* box drawings light vertical */ 2708 MY_UCS(0x2264, 26); /* less-than or equal to */ 2709 MY_UCS(0x2265, 27); /* greater-than or equal to */ 2710 MY_UCS(0x03c0, 28); /* greek small letter pi */ 2711 MY_UCS(0x2260, 29); /* not equal to */ 2712 MY_UCS(0x00a3, 30); /* pound sign */ 2713 MY_UCS(0x00b7, 31); /* middle dot */ 2714 } 2715 } 2716 return result; 2717} 2718 2719#endif /* OPT_WIDE_CHARS */ 2720 2721#if OPT_SHIFT_FONTS 2722static int 2723lookupOneFontSize(XtermWidget xw, int fontnum) 2724{ 2725 TScreen *screen = TScreenOf(xw); 2726 2727 if (screen->menu_font_sizes[fontnum] == 0) { 2728 XTermFonts fnt; 2729 2730 memset(&fnt, 0, sizeof(fnt)); 2731 screen->menu_font_sizes[fontnum] = -1; 2732 if (xtermOpenFont(xw, 2733 screen->MenuFontName(fontnum), 2734 &fnt, 2735 ((fontnum <= fontMenu_lastBuiltin) 2736 ? fwAlways 2737 : fwResource), 2738 True)) { 2739 if (fontnum <= fontMenu_lastBuiltin 2740 || strcmp(fnt.fn, DEFFONT)) { 2741 screen->menu_font_sizes[fontnum] = FontSize(fnt.fs); 2742 if (screen->menu_font_sizes[fontnum] <= 0) 2743 screen->menu_font_sizes[fontnum] = -1; 2744 } 2745 xtermCloseFont(xw, &fnt); 2746 } 2747 } 2748 return (screen->menu_font_sizes[fontnum] > 0); 2749} 2750 2751/* 2752 * Cache the font-sizes so subsequent larger/smaller font actions will go fast. 2753 */ 2754static void 2755lookupFontSizes(XtermWidget xw) 2756{ 2757 int n; 2758 2759 for (n = 0; n < NMENUFONTS; n++) { 2760 (void) lookupOneFontSize(xw, n); 2761 } 2762} 2763 2764#if OPT_RENDERFONT 2765static void 2766fillInFaceSize(XtermWidget xw, int fontnum) 2767{ 2768 TScreen *screen = TScreenOf(xw); 2769 float value; 2770 double face_size = xw->misc.face_size[fontnum]; 2771 2772 if (face_size <= 0.0) { 2773#if OPT_SHIFT_FONTS 2774 /* 2775 * If the user is switching font-sizes, make it follow by 2776 * default the same ratios to the default as the fixed fonts 2777 * would, for easy comparison. There will be some differences 2778 * since the fixed fonts have a variety of height/width ratios, 2779 * but this is simpler than adding another resource value - and 2780 * as noted above, the data for the fixed fonts are available. 2781 */ 2782 (void) lookupOneFontSize(xw, 0); 2783 if (fontnum == fontMenu_default) { 2784 sscanf(DEFFACESIZE, "%f", &value); 2785 face_size = value; 2786 } else if (lookupOneFontSize(xw, fontnum) 2787 && (screen->menu_font_sizes[0] 2788 != screen->menu_font_sizes[fontnum])) { 2789 double ratio; 2790 long num = screen->menu_font_sizes[fontnum]; 2791 long den = screen->menu_font_sizes[0]; 2792 2793 if (den <= 0) 2794 den = 1; 2795 ratio = dimSquareRoot((double) num / (double) den); 2796 2797 face_size = (ratio * xw->misc.face_size[0]); 2798 TRACE(("scaled[%d] using %3ld/%ld = %.2f -> %f\n", 2799 fontnum, num, den, ratio, face_size)); 2800 } else 2801#endif 2802 { 2803#define LikeBitmap(s) (((s) / 78.0) * xw->misc.face_size[fontMenu_default]) 2804 switch (fontnum) { 2805 case fontMenu_font1: 2806 face_size = LikeBitmap(2.0); 2807 break; 2808 case fontMenu_font2: 2809 face_size = LikeBitmap(35.0); 2810 break; 2811 case fontMenu_font3: 2812 face_size = LikeBitmap(60.0); 2813 break; 2814 default: 2815 sscanf(DEFFACESIZE, "%f", &value); 2816 face_size = value; 2817 break; 2818 case fontMenu_font4: 2819 face_size = LikeBitmap(90.0); 2820 break; 2821 case fontMenu_font5: 2822 face_size = LikeBitmap(135.0); 2823 break; 2824 case fontMenu_font6: 2825 face_size = LikeBitmap(200.0); 2826 break; 2827 } 2828 TRACE(("builtin[%d] -> %f\n", fontnum, face_size)); 2829 } 2830 xw->misc.face_size[fontnum] = (float) face_size; 2831 } 2832} 2833 2834/* no selection or escape */ 2835#define NMENU_RENDERFONTS (fontMenu_lastBuiltin + 1) 2836 2837/* 2838 * Workaround for breakage in font-packages - check if all of the bitmap font 2839 * sizes are the same, and if we're using TrueType fonts. 2840 */ 2841static Boolean 2842useFaceSizes(XtermWidget xw) 2843{ 2844 Boolean result = False; 2845 int n; 2846 2847 TRACE(("useFaceSizes {{\n")); 2848 if (UsingRenderFont(xw)) { 2849 Boolean nonzero = True; 2850 2851 for (n = 0; n < NMENU_RENDERFONTS; ++n) { 2852 if (xw->misc.face_size[n] <= 0.0) { 2853 nonzero = False; 2854 break; 2855 } 2856 } 2857 if (!nonzero) { 2858 Boolean broken_fonts = True; 2859 TScreen *screen = TScreenOf(xw); 2860 long first; 2861 2862 lookupFontSizes(xw); 2863 first = screen->menu_font_sizes[0]; 2864 for (n = 0; n < NMENUFONTS; n++) { 2865 if (screen->menu_font_sizes[n] > 0 2866 && screen->menu_font_sizes[n] != first) { 2867 broken_fonts = False; 2868 break; 2869 } 2870 } 2871 2872 if (broken_fonts) { 2873 2874 TRACE(("bitmap fonts are broken - set faceSize resources\n")); 2875 for (n = 0; n < NMENUFONTS; n++) { 2876 fillInFaceSize(xw, n); 2877 } 2878 2879 } 2880 } 2881 result = True; 2882 } 2883 TRACE(("...}}useFaceSizes %d\n", result)); 2884 return result; 2885} 2886#endif /* OPT_RENDERFONT */ 2887 2888/* 2889 * Find the index of a larger/smaller font (according to the sign of 'relative' 2890 * and its magnitude), starting from the 'old' index. 2891 */ 2892int 2893lookupRelativeFontSize(XtermWidget xw, int old, int relative) 2894{ 2895 TScreen *screen = TScreenOf(xw); 2896 int n, m = -1; 2897 2898 TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative)); 2899 if (!IsIcon(screen)) { 2900#if OPT_RENDERFONT 2901 if (useFaceSizes(xw)) { 2902 TRACE(("...using FaceSize\n")); 2903 if (relative != 0) { 2904 for (n = 0; n < NMENU_RENDERFONTS; ++n) { 2905 fillInFaceSize(xw, n); 2906 if (xw->misc.face_size[n] > 0 && 2907 xw->misc.face_size[n] != xw->misc.face_size[old]) { 2908 int cmp_0 = ((xw->misc.face_size[n] > 2909 xw->misc.face_size[old]) 2910 ? relative 2911 : -relative); 2912 int cmp_m = ((m < 0) 2913 ? 1 2914 : ((xw->misc.face_size[n] < 2915 xw->misc.face_size[m]) 2916 ? relative 2917 : -relative)); 2918 if (cmp_0 > 0 && cmp_m > 0) { 2919 m = n; 2920 } 2921 } 2922 } 2923 } 2924 } else 2925#endif 2926 { 2927 TRACE(("...using bitmap areas\n")); 2928 lookupFontSizes(xw); 2929 if (relative != 0) { 2930 for (n = 0; n < NMENUFONTS; ++n) { 2931 if (screen->menu_font_sizes[n] > 0 && 2932 screen->menu_font_sizes[n] != 2933 screen->menu_font_sizes[old]) { 2934 int cmp_0 = ((screen->menu_font_sizes[n] > 2935 screen->menu_font_sizes[old]) 2936 ? relative 2937 : -relative); 2938 int cmp_m = ((m < 0) 2939 ? 1 2940 : ((screen->menu_font_sizes[n] < 2941 screen->menu_font_sizes[m]) 2942 ? relative 2943 : -relative)); 2944 if (cmp_0 > 0 && cmp_m > 0) { 2945 m = n; 2946 } 2947 } 2948 } 2949 } 2950 } 2951 TRACE(("...new index %d\n", m)); 2952 if (m >= 0) { 2953 if (relative > 1) 2954 m = lookupRelativeFontSize(xw, m, relative - 1); 2955 else if (relative < -1) 2956 m = lookupRelativeFontSize(xw, m, relative + 1); 2957 } 2958 } 2959 return m; 2960} 2961 2962/* ARGSUSED */ 2963void 2964HandleLargerFont(Widget w GCC_UNUSED, 2965 XEvent * event GCC_UNUSED, 2966 String * params GCC_UNUSED, 2967 Cardinal *param_count GCC_UNUSED) 2968{ 2969 XtermWidget xw; 2970 2971 TRACE(("Handle larger-vt-font for %p\n", (void *) w)); 2972 if ((xw = getXtermWidget(w)) != 0) { 2973 if (xw->misc.shift_fonts) { 2974 TScreen *screen = TScreenOf(xw); 2975 int m; 2976 2977 m = lookupRelativeFontSize(xw, screen->menu_font_number, 1); 2978 if (m >= 0) { 2979 SetVTFont(xw, m, True, NULL); 2980 } else { 2981 Bell(xw, XkbBI_MinorError, 0); 2982 } 2983 } 2984 } 2985} 2986 2987/* ARGSUSED */ 2988void 2989HandleSmallerFont(Widget w GCC_UNUSED, 2990 XEvent * event GCC_UNUSED, 2991 String * params GCC_UNUSED, 2992 Cardinal *param_count GCC_UNUSED) 2993{ 2994 XtermWidget xw; 2995 2996 TRACE(("Handle smaller-vt-font for %p\n", (void *) w)); 2997 if ((xw = getXtermWidget(w)) != 0) { 2998 if (xw->misc.shift_fonts) { 2999 TScreen *screen = TScreenOf(xw); 3000 int m; 3001 3002 m = lookupRelativeFontSize(xw, screen->menu_font_number, -1); 3003 if (m >= 0) { 3004 SetVTFont(xw, m, True, NULL); 3005 } else { 3006 Bell(xw, XkbBI_MinorError, 0); 3007 } 3008 } 3009 } 3010} 3011#endif 3012 3013int 3014xtermGetFont(const char *param) 3015{ 3016 int fontnum; 3017 3018 switch (param[0]) { 3019 case 'd': 3020 case 'D': 3021 case '0': 3022 fontnum = fontMenu_default; 3023 break; 3024 case '1': 3025 fontnum = fontMenu_font1; 3026 break; 3027 case '2': 3028 fontnum = fontMenu_font2; 3029 break; 3030 case '3': 3031 fontnum = fontMenu_font3; 3032 break; 3033 case '4': 3034 fontnum = fontMenu_font4; 3035 break; 3036 case '5': 3037 fontnum = fontMenu_font5; 3038 break; 3039 case '6': 3040 fontnum = fontMenu_font6; 3041 break; 3042 case 'e': 3043 case 'E': 3044 fontnum = fontMenu_fontescape; 3045 break; 3046 case 's': 3047 case 'S': 3048 fontnum = fontMenu_fontsel; 3049 break; 3050 default: 3051 fontnum = -1; 3052 break; 3053 } 3054 return fontnum; 3055} 3056 3057/* ARGSUSED */ 3058void 3059HandleSetFont(Widget w GCC_UNUSED, 3060 XEvent * event GCC_UNUSED, 3061 String * params, 3062 Cardinal *param_count) 3063{ 3064 XtermWidget xw; 3065 3066 if ((xw = getXtermWidget(w)) != 0) { 3067 int fontnum; 3068 VTFontNames fonts; 3069 3070 memset(&fonts, 0, sizeof(fonts)); 3071 3072 if (*param_count == 0) { 3073 fontnum = fontMenu_default; 3074 } else { 3075 Cardinal maxparams = 1; /* total number of params allowed */ 3076 int result = xtermGetFont(params[0]); 3077 3078 switch (result) { 3079 case fontMenu_default: /* FALLTHRU */ 3080 case fontMenu_font1: /* FALLTHRU */ 3081 case fontMenu_font2: /* FALLTHRU */ 3082 case fontMenu_font3: /* FALLTHRU */ 3083 case fontMenu_font4: /* FALLTHRU */ 3084 case fontMenu_font5: /* FALLTHRU */ 3085 case fontMenu_font6: /* FALLTHRU */ 3086 break; 3087 case fontMenu_fontescape: 3088#if OPT_WIDE_CHARS 3089 maxparams = 5; 3090#else 3091 maxparams = 3; 3092#endif 3093 break; 3094 case fontMenu_fontsel: 3095 maxparams = 2; 3096 break; 3097 default: 3098 Bell(xw, XkbBI_MinorError, 0); 3099 return; 3100 } 3101 fontnum = result; 3102 3103 if (*param_count > maxparams) { /* see if extra args given */ 3104 Bell(xw, XkbBI_MinorError, 0); 3105 return; 3106 } 3107 switch (*param_count) { /* assign 'em */ 3108#if OPT_WIDE_CHARS 3109 case 5: 3110 fonts.f_wb = params[4]; 3111 /* FALLTHRU */ 3112 case 4: 3113 fonts.f_w = params[3]; 3114 /* FALLTHRU */ 3115#endif 3116 case 3: 3117 fonts.f_b = params[2]; 3118 /* FALLTHRU */ 3119 case 2: 3120 fonts.f_n = params[1]; 3121 break; 3122 } 3123 } 3124 3125 SetVTFont(xw, fontnum, True, &fonts); 3126 } 3127} 3128 3129void 3130SetVTFont(XtermWidget xw, 3131 int which, 3132 Bool doresize, 3133 const VTFontNames * fonts) 3134{ 3135 TScreen *screen = TScreenOf(xw); 3136 3137 TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which, 3138 (fonts && fonts->f_n) ? fonts->f_n : "<null>", 3139 (fonts && fonts->f_b) ? fonts->f_b : "<null>")); 3140 3141 if (IsIcon(screen)) { 3142 Bell(xw, XkbBI_MinorError, 0); 3143 } else if (which >= 0 && which < NMENUFONTS) { 3144 VTFontNames myfonts; 3145 3146 memset(&myfonts, 0, sizeof(myfonts)); 3147 if (fonts != 0) 3148 myfonts = *fonts; 3149 3150 if (which == fontMenu_fontsel) { /* go get the selection */ 3151 FindFontSelection(xw, myfonts.f_n, False); 3152 } else { 3153 int oldFont = screen->menu_font_number; 3154 3155#define USE_CACHED(field, name) \ 3156 if (myfonts.field == 0) { \ 3157 myfonts.field = x_strdup(screen->menu_font_names[which][name]); \ 3158 TRACE(("set myfonts." #field " from menu_font_names[%d][" #name "] %s\n", \ 3159 which, NonNull(myfonts.field))); \ 3160 } else { \ 3161 TRACE(("set myfonts." #field " reused\n")); \ 3162 } 3163#define SAVE_FNAME(field, name) \ 3164 if (myfonts.field != 0) { \ 3165 if (screen->menu_font_names[which][name] == 0 \ 3166 || strcmp(screen->menu_font_names[which][name], myfonts.field)) { \ 3167 TRACE(("updating menu_font_names[%d][" #name "] to %s\n", \ 3168 which, myfonts.field)); \ 3169 screen->menu_font_names[which][name] = x_strdup(myfonts.field); \ 3170 } \ 3171 } 3172 3173 USE_CACHED(f_n, fNorm); 3174 USE_CACHED(f_b, fBold); 3175#if OPT_WIDE_CHARS 3176 USE_CACHED(f_w, fWide); 3177 USE_CACHED(f_wb, fWBold); 3178#endif 3179 if (xtermLoadFont(xw, 3180 &myfonts, 3181 doresize, which)) { 3182 /* 3183 * If successful, save the data so that a subsequent query via 3184 * OSC-50 will return the expected values. 3185 */ 3186 SAVE_FNAME(f_n, fNorm); 3187 SAVE_FNAME(f_b, fBold); 3188#if OPT_WIDE_CHARS 3189 SAVE_FNAME(f_w, fWide); 3190 SAVE_FNAME(f_wb, fWBold); 3191#endif 3192 } else { 3193 xtermLoadFont(xw, 3194 xtermFontName(screen->MenuFontName(oldFont)), 3195 doresize, oldFont); 3196 Bell(xw, XkbBI_MinorError, 0); 3197 } 3198 } 3199 } else { 3200 Bell(xw, XkbBI_MinorError, 0); 3201 } 3202 return; 3203} 3204