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