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