fontutils.c revision 20d2c4d2
1/* $XTermId: fontutils.c,v 1.344 2010/06/15 08:18:58 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 (name == 0) { 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(char *pattern, 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, char *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(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 = 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 (name != 0) { 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 char *menu_font_names[fontMenu_lastBuiltin + 1][fMAX]; 1238} SubResourceRec; 1239 1240#define MERGE_SUBFONT(src,dst,name) \ 1241 if (dst.name == 0) { \ 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] = 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 (myName == 0 || *myName == 0) { 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) = xw->misc.default_font.f_n; 1333 screen->menu_font_names[0][fBold] = xw->misc.default_font.f_b; 1334#if OPT_WIDE_CHARS 1335 screen->menu_font_names[0][fWide] = xw->misc.default_font.f_w; 1336 screen->menu_font_names[0][fWBold] = 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 buf[80]; 1425 char *myName = (char *) ((*param_count > 0) ? params[0] : empty); 1426 char *convert = (char *) ((*param_count > 1) ? params[1] : myName); 1427 char *myClass = (char *) MyStackAlloc(strlen(convert), buf); 1428 int n; 1429 1430 TRACE(("HandleLoadVTFonts(%d)\n", *param_count)); 1431 strcpy(myClass, convert); 1432 if (*param_count == 1) 1433 myClass[0] = x_toupper(myClass[0]); 1434 1435 if (xtermLoadVTFonts(xw, myName, myClass)) { 1436 /* 1437 * When switching fonts, try to preserve the font-menu selection, since 1438 * it is less surprising to do that (if the font-switching can be 1439 * undone) than to switch to "Default". 1440 */ 1441 int font_number = screen->menu_font_number; 1442 if (font_number > fontMenu_lastBuiltin) 1443 font_number = fontMenu_lastBuiltin; 1444 for (n = 0; n < NMENUFONTS; ++n) 1445 screen->menu_font_sizes[n] = 0; 1446 SetVTFont(xw, font_number, True, 1447 ((font_number == fontMenu_default) 1448 ? &(xw->misc.default_font) 1449 : NULL)); 1450 } 1451 1452 MyStackFree(myClass, buf); 1453 } 1454} 1455#endif /* OPT_LOAD_VTFONTS */ 1456 1457/* 1458 * Set the limits for the box that outlines the cursor. 1459 */ 1460void 1461xtermSetCursorBox(TScreen * screen) 1462{ 1463 static XPoint VTbox[NBOX]; 1464 XPoint *vp; 1465 int fw = FontWidth(screen) - 1; 1466 int fh = FontHeight(screen) - 1; 1467 int hh = screen->cursor_underline ? 1 : fh; 1468 1469 vp = &VTbox[1]; 1470 (vp++)->x = (short) fw; 1471 (vp++)->y = (short) hh; 1472 (vp++)->x = (short) -fw; 1473 vp->y = (short) -hh; 1474 1475 screen->box = VTbox; 1476} 1477 1478#define CACHE_XFT(dst,src) if (src != 0) {\ 1479 checkXft(xw, &(dst[fontnum]), src);\ 1480 TRACE(("Xft metrics %s[%d] = %d (%d,%d) advance %d, actual %d%s\n",\ 1481 #dst,\ 1482 fontnum,\ 1483 src->height,\ 1484 src->ascent,\ 1485 src->descent,\ 1486 src->max_advance_width,\ 1487 dst[fontnum].map.min_width,\ 1488 dst[fontnum].map.mixed ? " mixed" : ""));\ 1489 } 1490 1491#if OPT_RENDERFONT 1492 1493#if OPT_TRACE > 1 1494static FcChar32 1495xtermXftFirstChar(XftFont * xft) 1496{ 1497 FcChar32 map[FC_CHARSET_MAP_SIZE]; 1498 FcChar32 next; 1499 FcChar32 first; 1500 int i; 1501 1502 first = FcCharSetFirstPage(xft->charset, map, &next); 1503 for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) 1504 if (map[i]) { 1505 FcChar32 bits = map[i]; 1506 first += i * 32; 1507 while (!(bits & 0x1)) { 1508 bits >>= 1; 1509 first++; 1510 } 1511 break; 1512 } 1513 return first; 1514} 1515 1516static FcChar32 1517xtermXftLastChar(XftFont * xft) 1518{ 1519 FcChar32 this, last, next; 1520 FcChar32 map[FC_CHARSET_MAP_SIZE]; 1521 int i; 1522 last = FcCharSetFirstPage(xft->charset, map, &next); 1523 while ((this = FcCharSetNextPage(xft->charset, map, &next)) != FC_CHARSET_DONE) 1524 last = this; 1525 last &= ~0xff; 1526 for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--) 1527 if (map[i]) { 1528 FcChar32 bits = map[i]; 1529 last += i * 32 + 31; 1530 while (!(bits & 0x80000000)) { 1531 last--; 1532 bits <<= 1; 1533 } 1534 break; 1535 } 1536 return (long) last; 1537} 1538 1539static void 1540dumpXft(XtermWidget xw, XTermXftFonts * data) 1541{ 1542 XftFont *xft = data->font; 1543 TScreen *screen = TScreenOf(xw); 1544 VTwin *win = WhichVWin(screen); 1545 1546 FcChar32 c; 1547 FcChar32 first = xtermXftFirstChar(xft); 1548 FcChar32 last = xtermXftLastChar(xft); 1549 unsigned count = 0; 1550 unsigned outside = 0; 1551 1552 TRACE(("dumpXft {{\n")); 1553 TRACE((" data range %#6x..%#6x\n", first, last)); 1554 for (c = first; c <= last; ++c) { 1555 if (FcCharSetHasChar(xft->charset, c)) { 1556 int width = my_wcwidth((int) c); 1557 XGlyphInfo extents; 1558 1559 XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents); 1560 TRACE(("%#6x %2d %.1f\n", c, width, 1561 ((double) extents.width) / win->f_width)); 1562 if (extents.width > win->f_width) 1563 ++outside; 1564 ++count; 1565 } 1566 } 1567 TRACE(("}} %u total, %u outside\n", count, outside)); 1568} 1569#define DUMP_XFT(xw, data) dumpXft(xw, data) 1570#else 1571#define DUMP_XFT(xw, data) /* nothing */ 1572#endif 1573 1574static void 1575checkXft(XtermWidget xw, XTermXftFonts * data, XftFont * xft) 1576{ 1577 FcChar32 c; 1578 Dimension width = 0; 1579 1580 data->font = xft; 1581 data->map.min_width = 0; 1582 data->map.max_width = (Dimension) xft->max_advance_width; 1583 1584 /* 1585 * For each ASCII or ISO-8859-1 printable code, ask what its width is. 1586 * Given the maximum width for those, we have a reasonable estimate of 1587 * the single-column width. 1588 * 1589 * Ignore control characters - their extent information is misleading. 1590 */ 1591 for (c = 32; c < 256; ++c) { 1592 if (c >= 127 && c <= 159) 1593 continue; 1594 if (FcCharSetHasChar(xft->charset, c)) { 1595 XGlyphInfo extents; 1596 1597 XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents); 1598 if (width < extents.width && extents.width <= data->map.max_width) { 1599 width = extents.width; 1600 } 1601 } 1602 } 1603 data->map.min_width = width; 1604 data->map.mixed = (data->map.max_width >= (data->map.min_width + 1)); 1605} 1606 1607static XftFont * 1608xtermOpenXft(XtermWidget xw, const char *name, XftPattern * pat, const char *tag) 1609{ 1610 TScreen *screen = TScreenOf(xw); 1611 Display *dpy = screen->display; 1612 XftPattern *match; 1613 XftResult status; 1614 XftFont *result = 0; 1615 1616 if (pat != 0) { 1617 match = XftFontMatch(dpy, DefaultScreen(dpy), pat, &status); 1618 if (match != 0) { 1619 result = XftFontOpenPattern(dpy, match); 1620 if (result != 0) { 1621 TRACE(("...matched %s font\n", tag)); 1622 } else { 1623 TRACE(("...could did not open %s font\n", tag)); 1624 XftPatternDestroy(match); 1625 if (xw->misc.fontWarnings >= fwAlways) { 1626 TRACE(("OOPS cannot open %s font \"%s\"\n", tag, name)); 1627 fprintf(stderr, "%s: cannot open %s font \"%s\"\n", 1628 ProgramName, tag, name); 1629 } 1630 } 1631 } else { 1632 TRACE(("...did not match %s font\n", tag)); 1633 if (xw->misc.fontWarnings >= fwResource) { 1634 TRACE(("OOPS: cannot match %s font \"%s\"\n", tag, name)); 1635 fprintf(stderr, "%s: cannot match %s font \"%s\"\n", 1636 ProgramName, tag, name); 1637 } 1638 } 1639 } 1640 return result; 1641} 1642#endif 1643 1644#if OPT_RENDERFONT 1645#if OPT_SHIFT_FONTS 1646/* 1647 * Don't make a dependency on the math library for a single function. 1648 * (Newton Raphson). 1649 */ 1650static double 1651mySquareRoot(double value) 1652{ 1653 double result = 0.0; 1654 if (value > 0.0) { 1655 int n; 1656 double older = value; 1657 for (n = 0; n < 10; ++n) { 1658 double delta = (older * older - value) / (2.0 * older); 1659 double newer = older - delta; 1660 older = newer; 1661 result = newer; 1662 if (delta > -0.001 && delta < 0.001) 1663 break; 1664 } 1665 } 1666 return result; 1667} 1668#endif 1669 1670/* 1671 * Given the Xft font metrics, determine the actual font size. This is used 1672 * for each font to ensure that normal, bold and italic fonts follow the same 1673 * rule. 1674 */ 1675static void 1676setRenderFontsize(TScreen * screen, VTwin * win, XftFont * font, const char *tag) 1677{ 1678 if (font != 0) { 1679 int width, height, ascent, descent; 1680 1681 (void) screen; 1682 1683 width = font->max_advance_width; 1684 height = font->height; 1685 ascent = font->ascent; 1686 descent = font->descent; 1687 if (height < ascent + descent) { 1688 TRACE(("...increase height from %d\n", height)); 1689 height = ascent + descent; 1690 } 1691 if (is_double_width_font_xft(screen->display, font)) { 1692 TRACE(("...reduced width from %d\n", width)); 1693 width >>= 1; 1694 } 1695 if (tag == 0) { 1696 win->f_width = width; 1697 win->f_height = height; 1698 win->f_ascent = ascent; 1699 win->f_descent = descent; 1700 TRACE(("setRenderFontsize result %dx%d (%d+%d)\n", 1701 width, height, ascent, descent)); 1702 } else if (win->f_width < width || 1703 win->f_height < height || 1704 win->f_ascent < ascent || 1705 win->f_descent < descent) { 1706 TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n", 1707 tag, 1708 win->f_width, win->f_height, win->f_ascent, win->f_descent, 1709 width, height, ascent, descent)); 1710 1711 win->f_width = width; 1712 win->f_height = height; 1713 win->f_ascent = ascent; 1714 win->f_descent = descent; 1715 } else { 1716 TRACE(("setRenderFontsize %s unchanged\n", tag)); 1717 } 1718 } 1719} 1720#endif 1721 1722static void 1723checkFontInfo(int value, const char *tag) 1724{ 1725 if (value == 0) { 1726 fprintf(stderr, 1727 "Selected font has no non-zero %s for ISO-8859-1 encoding\n", tag); 1728 exit(1); 1729 } 1730} 1731 1732#if OPT_RENDERFONT 1733void 1734xtermCloseXft(TScreen * screen, XTermXftFonts * pub) 1735{ 1736 if (pub->font != 0) { 1737 XftFontClose(screen->display, pub->font); 1738 pub->font = 0; 1739 } 1740} 1741 1742/* 1743 * Get the faceName/faceDoublesize resource setting. Strip off "xft:", which 1744 * is not recognized by XftParseName(). 1745 */ 1746char * 1747getFaceName(XtermWidget xw, Bool wideName GCC_UNUSED) 1748{ 1749#if OPT_RENDERWIDE 1750 char *result = (wideName 1751 ? xw->misc.face_wide_name 1752 : xw->misc.face_name); 1753#else 1754 char *result = xw->misc.face_name; 1755#endif 1756 if (!IsEmpty(result) && !strncmp(result, "xft:", (size_t) 4)) 1757 result += 4; 1758 return x_nonempty(result); 1759} 1760 1761/* 1762 * If we change the faceName, we'll have to re-acquire all of the fonts that 1763 * are derived from it. 1764 */ 1765void 1766setFaceName(XtermWidget xw, const char *value) 1767{ 1768 TScreen *screen = TScreenOf(xw); 1769 int n; 1770 1771 xw->misc.face_name = x_strdup(value); 1772 for (n = 0; n < NMENUFONTS; ++n) { 1773 xw->misc.face_size[n] = -1.0; 1774 xtermCloseXft(screen, &(screen->renderFontNorm[n])); 1775 xtermCloseXft(screen, &(screen->renderFontBold[n])); 1776 xtermCloseXft(screen, &(screen->renderFontBold[n])); 1777#if OPT_RENDERWIDE 1778 xtermCloseXft(screen, &(screen->renderWideNorm[n])); 1779 xtermCloseXft(screen, &(screen->renderWideBold[n])); 1780 xtermCloseXft(screen, &(screen->renderWideItal[n])); 1781#endif 1782 } 1783} 1784#endif 1785 1786/* 1787 * Compute useful values for the font/window sizes 1788 */ 1789void 1790xtermComputeFontInfo(XtermWidget xw, 1791 VTwin * win, 1792 XFontStruct * font, 1793 int sbwidth) 1794{ 1795 TScreen *screen = TScreenOf(xw); 1796 1797 int i, j, width, height; 1798 1799#if OPT_RENDERFONT 1800 /* 1801 * xterm contains a lot of references to fonts, assuming they are fixed 1802 * size. This chunk of code overrides the actual font-selection (see 1803 * drawXtermText()), if the user has selected render-font. All of the 1804 * font-loading for fixed-fonts still goes on whether or not this chunk 1805 * overrides it. 1806 */ 1807 if (UsingRenderFont(xw)) { 1808 char *face_name = getFaceName(xw, False); 1809 int fontnum = screen->menu_font_number; 1810 XftFont *norm = screen->renderFontNorm[fontnum].font; 1811 XftFont *bold = screen->renderFontBold[fontnum].font; 1812 XftFont *ital = screen->renderFontItal[fontnum].font; 1813#if OPT_RENDERWIDE 1814 XftFont *wnorm = screen->renderWideNorm[fontnum].font; 1815 XftFont *wbold = screen->renderWideBold[fontnum].font; 1816 XftFont *wital = screen->renderWideItal[fontnum].font; 1817#endif 1818 1819 if (norm == 0 && face_name) { 1820 XftPattern *pat; 1821 double face_size = xw->misc.face_size[fontnum]; 1822 1823 TRACE(("xtermComputeFontInfo norm(face %s, size %f)\n", 1824 face_name, 1825 xw->misc.face_size[fontnum])); 1826 1827 if (face_size <= 0.0) { 1828#if OPT_SHIFT_FONTS 1829 /* 1830 * If the user is switching font-sizes, make it follow by 1831 * default the same ratios to the default as the fixed fonts 1832 * would, for easy comparison. There will be some differences 1833 * since the fixed fonts have a variety of height/width ratios, 1834 * but this is simpler than adding another resource value - and 1835 * as noted above, the data for the fixed fonts are available. 1836 */ 1837 lookupOneFontSize(xw, 0); 1838 lookupOneFontSize(xw, fontnum); 1839 if (fontnum == fontMenu_default) { 1840 face_size = 14.0; 1841 } else { 1842 double ratio; 1843 long num = screen->menu_font_sizes[fontnum]; 1844 long den = screen->menu_font_sizes[0]; 1845 1846 if (den <= 0) 1847 den = 1; 1848 ratio = mySquareRoot((double) num / (double) den); 1849 1850 face_size = (ratio * xw->misc.face_size[0]); 1851 TRACE(("scaled using %3ld/%ld = %.2f -> %f\n", 1852 num, den, ratio, face_size)); 1853 } 1854#else 1855 switch (fontnum) { 1856 case fontMenu_font1: 1857 face_size = 8.0; 1858 break; 1859 case fontMenu_font2: 1860 face_size = 10.0; 1861 break; 1862 case fontMenu_font3: 1863 face_size = 12.0; 1864 break; 1865 default: 1866 face_size = 14.0; 1867 break; 1868 case fontMenu_font4: 1869 face_size = 16.0; 1870 break; 1871 case fontMenu_font5: 1872 face_size = 18.0; 1873 break; 1874 case fontMenu_font6: 1875 face_size = 20.0; 1876 break; 1877 } 1878#endif 1879 xw->misc.face_size[fontnum] = (float) face_size; 1880 } 1881 1882 /* 1883 * By observation (there is no documentation), XftPatternBuild is 1884 * cumulative. Build the bold- and italic-patterns on top of the 1885 * normal pattern. 1886 */ 1887#define NormXftPattern \ 1888 XFT_FAMILY, XftTypeString, "mono", \ 1889 XFT_SIZE, XftTypeDouble, face_size, \ 1890 XFT_SPACING, XftTypeInteger, XFT_MONO 1891 1892#define BoldXftPattern(norm) \ 1893 XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \ 1894 XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width 1895 1896#define ItalXftPattern(norm) \ 1897 XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \ 1898 XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width 1899 1900 if ((pat = XftNameParse(face_name)) != 0) { 1901#define OPEN_XFT(tag) xtermOpenXft(xw, face_name, pat, tag) 1902 XftPatternBuild(pat, 1903 NormXftPattern, 1904 (void *) 0); 1905 norm = OPEN_XFT("normal"); 1906 1907 if (norm != 0) { 1908 XftPatternBuild(pat, 1909 BoldXftPattern(norm), 1910 (void *) 0); 1911 bold = OPEN_XFT("bold"); 1912 1913#if OPT_ISO_COLORS 1914 if (screen->italicULMode 1915 && (pat = XftNameParse(face_name)) != 0) { 1916 XftPatternBuild(pat, 1917 NormXftPattern, 1918 ItalXftPattern(norm), 1919 (void *) 0); 1920 ital = OPEN_XFT("italic"); 1921 } 1922#endif /* OPT_ISO_COLORS */ 1923#undef OPEN_XFT 1924 1925 /* 1926 * FIXME: just assume that the corresponding font has no 1927 * graphics characters. 1928 */ 1929 if (screen->fnt_boxes) { 1930 screen->fnt_boxes = False; 1931 TRACE(("Xft opened - will %suse internal line-drawing characters\n", 1932 screen->fnt_boxes ? "not " : "")); 1933 } 1934 } 1935 1936 XftPatternDestroy(pat); 1937 } 1938 1939 CACHE_XFT(screen->renderFontNorm, norm); 1940 CACHE_XFT(screen->renderFontBold, bold); 1941 CACHE_XFT(screen->renderFontItal, ital); 1942 1943 /* 1944 * See xtermXftDrawString(). 1945 */ 1946#if OPT_RENDERWIDE 1947 if (norm != 0 && screen->wide_chars) { 1948 int char_width = norm->max_advance_width * 2; 1949#ifdef FC_ASPECT 1950 double aspect = ((xw->misc.face_wide_name 1951 || screen->renderFontNorm[fontnum].map.mixed) 1952 ? 1.0 1953 : 2.0); 1954#endif 1955 1956 face_name = getFaceName(xw, True); 1957 TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n", 1958 NonNull(face_name), 1959 char_width)); 1960 1961#define WideXftPattern \ 1962 XFT_FAMILY, XftTypeString, "mono", \ 1963 XFT_SIZE, XftTypeDouble, face_size, \ 1964 XFT_SPACING, XftTypeInteger, XFT_MONO 1965 1966 if (face_name && (pat = XftNameParse(face_name)) != 0) { 1967#define OPEN_XFT(tag) xtermOpenXft(xw, face_name, pat, tag) 1968 XftPatternBuild(pat, 1969 WideXftPattern, 1970 XFT_CHAR_WIDTH, XftTypeInteger, char_width, 1971#ifdef FC_ASPECT 1972 FC_ASPECT, XftTypeDouble, aspect, 1973#endif 1974 (void *) 0); 1975 wnorm = OPEN_XFT("wide"); 1976 1977 if (wnorm != 0) { 1978 XftPatternBuild(pat, 1979 WideXftPattern, 1980 BoldXftPattern(wnorm), 1981 (void *) 0); 1982 wbold = OPEN_XFT("wide-bold"); 1983 1984#if OPT_ISO_COLORS 1985 if (screen->italicULMode 1986 && (pat = XftNameParse(face_name)) != 0) { 1987 XftPatternBuild(pat, 1988 WideXftPattern, 1989 ItalXftPattern(wnorm), 1990 (void *) 0); 1991 wital = OPEN_XFT("wide-italic"); 1992 } 1993#endif 1994#undef OPEN_XFT 1995 } 1996 XftPatternDestroy(pat); 1997 } 1998 1999 CACHE_XFT(screen->renderWideNorm, wnorm); 2000 CACHE_XFT(screen->renderWideBold, wbold); 2001 CACHE_XFT(screen->renderWideItal, wital); 2002 } 2003#endif /* OPT_RENDERWIDE */ 2004 } 2005 if (norm == 0) { 2006 TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum)); 2007 xw->misc.render_font = False; 2008 update_font_renderfont(); 2009 /* now we will fall through into the bitmap fonts */ 2010 } else { 2011 setRenderFontsize(screen, win, norm, NULL); 2012 setRenderFontsize(screen, win, bold, "bold"); 2013 setRenderFontsize(screen, win, ital, "ital"); 2014#if OPT_BOX_CHARS 2015 setupPackedFonts(xw); 2016 2017 if (screen->force_packed) { 2018 XTermXftFonts *use = &(screen->renderFontNorm[fontnum]); 2019 win->f_height = use->font->ascent + use->font->descent; 2020 win->f_width = use->map.min_width; 2021 TRACE(("...packed TrueType font %dx%d vs %d\n", 2022 win->f_height, 2023 win->f_width, 2024 use->map.max_width)); 2025 } 2026#endif 2027 DUMP_XFT(xw, &(screen->renderFontNorm[fontnum])); 2028 } 2029 } 2030 /* 2031 * Are we handling a bitmap font? 2032 */ 2033 if (!UsingRenderFont(xw)) 2034#endif /* OPT_RENDERFONT */ 2035 { 2036 if (is_double_width_font(font) && !(screen->fnt_prop)) { 2037 win->f_width = (font->min_bounds.width); 2038 } else { 2039 win->f_width = (font->max_bounds.width); 2040 } 2041 win->f_height = (font->ascent + font->descent); 2042 win->f_ascent = font->ascent; 2043 win->f_descent = font->descent; 2044 } 2045 i = 2 * screen->border + sbwidth; 2046 j = 2 * screen->border; 2047 width = MaxCols(screen) * win->f_width + i; 2048 height = MaxRows(screen) * win->f_height + j; 2049 win->fullwidth = (Dimension) width; 2050 win->fullheight = (Dimension) height; 2051 win->width = width - i; 2052 win->height = height - j; 2053 2054 TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n", 2055 win->height, 2056 win->width, 2057 win->fullheight, 2058 win->fullwidth, 2059 win->f_height, 2060 win->f_width, 2061 win->f_ascent, 2062 win->f_descent)); 2063 2064 checkFontInfo(win->f_height, "height"); 2065 checkFontInfo(win->f_width, "width"); 2066} 2067 2068/* save this information as a side-effect for double-sized characters */ 2069void 2070xtermSaveFontInfo(TScreen * screen, XFontStruct * font) 2071{ 2072 screen->fnt_wide = (Dimension) (font->max_bounds.width); 2073 screen->fnt_high = (Dimension) (font->ascent + font->descent); 2074 TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide)); 2075} 2076 2077/* 2078 * After loading a new font, update the structures that use its size. 2079 */ 2080void 2081xtermUpdateFontInfo(XtermWidget xw, Bool doresize) 2082{ 2083 TScreen *screen = TScreenOf(xw); 2084 2085 int scrollbar_width; 2086 VTwin *win = &(screen->fullVwin); 2087 2088 scrollbar_width = (xw->misc.scrollbar 2089 ? (screen->scrollWidget->core.width + 2090 BorderWidth(screen->scrollWidget)) 2091 : 0); 2092 xtermComputeFontInfo(xw, win, screen->fnts[fNorm].fs, scrollbar_width); 2093 xtermSaveFontInfo(screen, screen->fnts[fNorm].fs); 2094 2095 if (doresize) { 2096 if (VWindow(screen)) { 2097 xtermClear(xw); 2098 } 2099 TRACE(("xtermUpdateFontInfo {{\n")); 2100 DoResizeScreen(xw); /* set to the new natural size */ 2101 ResizeScrollBar(xw); 2102 Redraw(); 2103 TRACE(("... }} xtermUpdateFontInfo\n")); 2104#ifdef SCROLLBAR_RIGHT 2105 updateRightScrollbar(xw); 2106#endif 2107 } 2108 xtermSetCursorBox(screen); 2109} 2110 2111#if OPT_BOX_CHARS 2112 2113/* 2114 * Returns true if the given character is missing from the specified font. 2115 */ 2116Bool 2117xtermMissingChar(unsigned ch, XTermFonts * font) 2118{ 2119 Bool result = False; 2120 XFontStruct *fs = font->fs; 2121 static XCharStruct dft, *tmp = &dft, *pc = 0; 2122 2123 if (fs->max_byte1 == 0) { 2124#if OPT_WIDE_CHARS 2125 if (ch > 255) { 2126 TRACE(("xtermMissingChar %#04x (row)\n", ch)); 2127 return True; 2128 } 2129#endif 2130 CI_GET_CHAR_INFO_1D(fs, E2A(ch), tmp, pc); 2131 } 2132#if OPT_WIDE_CHARS 2133 else { 2134 CI_GET_CHAR_INFO_2D(fs, HI_BYTE(ch), LO_BYTE(ch), tmp, pc); 2135 } 2136#else 2137 2138 if (!pc) 2139 return False; /* Urgh! */ 2140#endif 2141 2142 if (CI_NONEXISTCHAR(pc)) { 2143 TRACE(("xtermMissingChar %#04x (!exists)\n", ch)); 2144 result = True; 2145 } 2146 if (ch < 256) { 2147 font->known_missing[ch] = (Char) (result ? 2 : 1); 2148 } 2149 return result; 2150} 2151 2152/* 2153 * The grid is arbitrary, enough resolution that nothing's lost in 2154 * initialization. 2155 */ 2156#define BOX_HIGH 60 2157#define BOX_WIDE 60 2158 2159#define MID_HIGH (BOX_HIGH/2) 2160#define MID_WIDE (BOX_WIDE/2) 2161 2162#define CHR_WIDE ((9*BOX_WIDE)/10) 2163#define CHR_HIGH ((9*BOX_HIGH)/10) 2164 2165/* 2166 * ...since we'll scale the values anyway. 2167 */ 2168#define SCALE_X(n) n = (n * (((int) font_width) - 1)) / (BOX_WIDE-1) 2169#define SCALE_Y(n) n = (n * (((int) font_height) - 1)) / (BOX_HIGH-1) 2170 2171#define SEG(x0,y0,x1,y1) x0,y0, x1,y1 2172 2173/* 2174 * Draw the given graphic character, if it is simple enough (i.e., a 2175 * line-drawing character). 2176 */ 2177void 2178xtermDrawBoxChar(XtermWidget xw, 2179 unsigned ch, 2180 unsigned flags, 2181 GC gc, 2182 int x, 2183 int y, 2184 int cells) 2185{ 2186 TScreen *screen = TScreenOf(xw); 2187 /* *INDENT-OFF* */ 2188 static const short glyph_ht[] = { 2189 SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,5*MID_HIGH/6), /* H */ 2190 SEG(6*BOX_WIDE/10, 0, 6*BOX_WIDE/10,5*MID_HIGH/6), 2191 SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12), 2192 SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 2193 SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 2194 -1 2195 }, glyph_ff[] = { 2196 SEG(1*BOX_WIDE/10, 0, 6*BOX_WIDE/10, 0), /* F */ 2197 SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12), 2198 SEG(1*BOX_WIDE/10, 0, 0*BOX_WIDE/3, 5*MID_HIGH/6), 2199 SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 2200 SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 2201 SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 2202 -1 2203 }, glyph_lf[] = { 2204 SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,9*MID_HIGH/12), /* L */ 2205 SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12), 2206 SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 2207 SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 2208 SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 2209 -1 2210 }, glyph_nl[] = { 2211 SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10, 0), /* N */ 2212 SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/6, 5*MID_HIGH/6), 2213 SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 2214 SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), /* L */ 2215 SEG(1*BOX_WIDE/3, CHR_HIGH, CHR_WIDE, CHR_HIGH), 2216 -1 2217 }, glyph_vt[] = { 2218 SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/12,5*MID_HIGH/6), /* V */ 2219 SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 2220 SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 2221 SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 2222 -1 2223 }, plus_or_minus[] = 2224 { 2225 SEG( 0, 5*BOX_HIGH/6, CHR_WIDE, 5*BOX_HIGH/6), 2226 SEG( MID_WIDE, 2*BOX_HIGH/6, MID_WIDE, 4*BOX_HIGH/6), 2227 SEG( 0, 3*BOX_HIGH/6, CHR_WIDE, 3*BOX_HIGH/6), 2228 -1 2229 }, lower_right_corner[] = 2230 { 2231 SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 2232 SEG( MID_WIDE, MID_HIGH, MID_WIDE, 0), 2233 -1 2234 }, upper_right_corner[] = 2235 { 2236 SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 2237 SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 2238 -1 2239 }, upper_left_corner[] = 2240 { 2241 SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 2242 SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 2243 -1 2244 }, lower_left_corner[] = 2245 { 2246 SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 2247 SEG( MID_WIDE, MID_WIDE, BOX_WIDE, MID_HIGH), 2248 -1 2249 }, cross[] = 2250 { 2251 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 2252 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 2253 -1 2254 }, scan_line_1[] = 2255 { 2256 SEG( 0, 0, BOX_WIDE, 0), 2257 -1 2258 }, scan_line_3[] = 2259 { 2260 SEG( 0, BOX_HIGH/4, BOX_WIDE, BOX_HIGH/4), 2261 -1 2262 }, scan_line_7[] = 2263 { 2264 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 2265 -1 2266 }, scan_line_9[] = 2267 { 2268 SEG( 0, 3*BOX_HIGH/4, BOX_WIDE, 3*BOX_HIGH/4), 2269 -1 2270 }, horizontal_line[] = 2271 { 2272 SEG( 0, BOX_HIGH, BOX_WIDE, BOX_HIGH), 2273 -1 2274 }, left_tee[] = 2275 { 2276 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 2277 SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 2278 -1 2279 }, right_tee[] = 2280 { 2281 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 2282 SEG( MID_WIDE, MID_HIGH, 0, MID_HIGH), 2283 -1 2284 }, bottom_tee[] = 2285 { 2286 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 2287 SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 2288 -1 2289 }, top_tee[] = 2290 { 2291 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 2292 SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 2293 -1 2294 }, vertical_line[] = 2295 { 2296 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 2297 -1 2298 }, less_than_or_equal[] = 2299 { 2300 SEG( CHR_WIDE, BOX_HIGH/3, 0, MID_HIGH), 2301 SEG( CHR_WIDE, 2*BOX_HIGH/3, 0, MID_HIGH), 2302 SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 2303 -1 2304 }, greater_than_or_equal[] = 2305 { 2306 SEG( 0, BOX_HIGH/3, CHR_WIDE, MID_HIGH), 2307 SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, MID_HIGH), 2308 SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 2309 -1 2310 }, greek_pi[] = 2311 { 2312 SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 2313 SEG(5*CHR_WIDE/6, MID_HIGH, 5*CHR_WIDE/6, CHR_HIGH), 2314 SEG(2*CHR_WIDE/6, MID_HIGH, 2*CHR_WIDE/6, CHR_HIGH), 2315 -1 2316 }, not_equal_to[] = 2317 { 2318 SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3, CHR_HIGH), 2319 SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, 2*BOX_HIGH/3), 2320 SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 2321 -1 2322 }; 2323 /* *INDENT-ON* */ 2324 2325 static const short *lines[] = 2326 { 2327 0, /* 00 (unused) */ 2328 0, /* 01 diamond */ 2329 0, /* 02 box */ 2330 glyph_ht, /* 03 HT */ 2331 glyph_ff, /* 04 FF */ 2332 0, /* 05 CR */ 2333 glyph_lf, /* 06 LF */ 2334 0, /* 07 degrees (small circle) */ 2335 plus_or_minus, /* 08 */ 2336 glyph_nl, /* 09 */ 2337 glyph_vt, /* 0A */ 2338 lower_right_corner, /* 0B */ 2339 upper_right_corner, /* 0C */ 2340 upper_left_corner, /* 0D */ 2341 lower_left_corner, /* 0E */ 2342 cross, /* 0F */ 2343 scan_line_1, /* 10 */ 2344 scan_line_3, /* 11 */ 2345 scan_line_7, /* 12 */ 2346 scan_line_9, /* 13 */ 2347 horizontal_line, /* 14 */ 2348 left_tee, /* 15 */ 2349 right_tee, /* 16 */ 2350 bottom_tee, /* 17 */ 2351 top_tee, /* 18 */ 2352 vertical_line, /* 19 */ 2353 less_than_or_equal, /* 1A */ 2354 greater_than_or_equal, /* 1B */ 2355 greek_pi, /* 1C */ 2356 not_equal_to, /* 1D */ 2357 0, /* 1E LB */ 2358 0, /* 1F bullet */ 2359 }; 2360 2361 GC gc2; 2362 CgsEnum cgsId = (ch == 2) ? gcDots : gcLine; 2363 VTwin *cgsWin = WhichVWin(screen); 2364 const short *p; 2365 unsigned font_width = (unsigned) (((flags & DOUBLEWFONT) ? 2 : 1) * screen->fnt_wide); 2366 unsigned font_height = (unsigned) (((flags & DOUBLEHFONT) ? 2 : 1) * screen->fnt_high); 2367 2368 if (cells > 1) 2369 font_width *= (unsigned) cells; 2370 2371#if OPT_WIDE_CHARS 2372 /* 2373 * Try to show line-drawing characters if we happen to be in UTF-8 2374 * mode, but have gotten an old-style font. 2375 */ 2376 if (screen->utf8_mode 2377#if OPT_RENDERFONT 2378 && !UsingRenderFont(xw) 2379#endif 2380 && (ch > 127) 2381 && (ch != UCS_REPL)) { 2382 unsigned n; 2383 for (n = 1; n < 32; n++) { 2384 if (dec2ucs(n) == ch 2385 && !((flags & BOLD) 2386 ? IsXtermMissingChar(screen, n, &screen->fnts[fBold]) 2387 : IsXtermMissingChar(screen, n, &screen->fnts[fNorm]))) { 2388 TRACE(("...use xterm-style linedrawing\n")); 2389 ch = n; 2390 break; 2391 } 2392 } 2393 } 2394#endif 2395 2396 TRACE(("DRAW_BOX(%d) cell %dx%d at %d,%d%s\n", 2397 ch, font_height, font_width, y, x, 2398 (ch >= (sizeof(lines) / sizeof(lines[0])) 2399 ? "-BAD" 2400 : ""))); 2401 2402 if (cgsId == gcDots) { 2403 setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc)); 2404 setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc)); 2405 setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 2406 } else { 2407 setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc)); 2408 setCgsFore(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 2409 setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 2410 } 2411 gc2 = getCgsGC(xw, cgsWin, cgsId); 2412 2413 if (!(flags & NOBACKGROUND)) { 2414 XFillRectangle(screen->display, VWindow(screen), gc2, x, y, 2415 font_width, 2416 font_height); 2417 } 2418 2419 setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc)); 2420 setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc)); 2421 setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 2422 gc2 = getCgsGC(xw, cgsWin, cgsId); 2423 2424 XSetLineAttributes(screen->display, gc2, 2425 (flags & BOLD) 2426 ? ((font_height > 12) 2427 ? font_height / 12 2428 : 1) 2429 : ((font_height > 16) 2430 ? font_height / 16 2431 : 1), 2432 LineSolid, 2433 CapProjecting, 2434 JoinMiter); 2435 2436 if (ch == 1) { /* diamond */ 2437 XPoint points[5]; 2438 int npoints = 5, n; 2439 2440 points[0].x = MID_WIDE; 2441 points[0].y = BOX_HIGH / 4; 2442 2443 points[1].x = 8 * BOX_WIDE / 8; 2444 points[1].y = MID_HIGH; 2445 2446 points[2].x = points[0].x; 2447 points[2].y = 3 * BOX_HIGH / 4; 2448 2449 points[3].x = 0 * BOX_WIDE / 8; 2450 points[3].y = points[1].y; 2451 2452 points[4].x = points[0].x; 2453 points[4].y = points[0].y; 2454 2455 for (n = 0; n < npoints; ++n) { 2456 SCALE_X(points[n].x); 2457 SCALE_Y(points[n].y); 2458 points[n].x += x; 2459 points[n].y += y; 2460 } 2461 2462 XFillPolygon(screen->display, 2463 VWindow(screen), gc2, 2464 points, npoints, 2465 Convex, CoordModeOrigin); 2466 } else if (ch == 7) { /* degrees */ 2467 unsigned width = (BOX_WIDE / 3); 2468 int x_coord = MID_WIDE - (int) (width / 2); 2469 int y_coord = MID_HIGH - (int) width; 2470 2471 SCALE_X(x_coord); 2472 SCALE_Y(y_coord); 2473 SCALE_X(width); 2474 2475 XDrawArc(screen->display, 2476 VWindow(screen), gc2, 2477 x + x_coord, y + y_coord, width, width, 2478 0, 2479 360 * 64); 2480 } else if (ch == 0x1f) { /* bullet */ 2481 unsigned width = 7 * BOX_WIDE / 10; 2482 int x_coord = MID_WIDE - (int) (width / 3); 2483 int y_coord = MID_HIGH - (int) (width / 3); 2484 2485 SCALE_X(x_coord); 2486 SCALE_Y(y_coord); 2487 SCALE_X(width); 2488 2489 XDrawArc(screen->display, 2490 VWindow(screen), gc2, 2491 x + x_coord, y + y_coord, width, width, 2492 0, 2493 360 * 64); 2494 } else if (ch < (sizeof(lines) / sizeof(lines[0])) 2495 && (p = lines[ch]) != 0) { 2496 int coord[4]; 2497 int n = 0; 2498 while (*p >= 0) { 2499 coord[n++] = *p++; 2500 if (n == 4) { 2501 SCALE_X(coord[0]); 2502 SCALE_Y(coord[1]); 2503 SCALE_X(coord[2]); 2504 SCALE_Y(coord[3]); 2505 XDrawLine(screen->display, 2506 VWindow(screen), gc2, 2507 x + coord[0], y + coord[1], 2508 x + coord[2], y + coord[3]); 2509 n = 0; 2510 } 2511 } 2512 } else if (screen->force_all_chars) { 2513 /* bounding rectangle, for debugging */ 2514 XDrawRectangle(screen->display, VWindow(screen), gc2, x, y, 2515 font_width - 1, 2516 font_height - 1); 2517 } 2518} 2519 2520#if OPT_RENDERFONT 2521 2522/* 2523 * Check if the given character has a glyph known to Xft. 2524 * 2525 * see xc/lib/Xft/xftglyphs.c 2526 */ 2527Bool 2528xtermXftMissing(XtermWidget xw, XftFont * font, unsigned wc) 2529{ 2530 Bool result = False; 2531 2532 if (font != 0) { 2533 TScreen *screen = TScreenOf(xw); 2534 if (!XftGlyphExists(screen->display, font, wc)) { 2535#if OPT_WIDE_CHARS 2536 TRACE(("xtermXftMissing %d (dec=%#x, ucs=%#x)\n", 2537 wc, ucs2dec(wc), dec2ucs(wc))); 2538#else 2539 TRACE(("xtermXftMissing %d\n", wc)); 2540#endif 2541 result = True; 2542 } 2543 } 2544 return result; 2545} 2546#endif /* OPT_RENDERFONT && OPT_WIDE_CHARS */ 2547 2548#endif /* OPT_BOX_CHARS */ 2549 2550#if OPT_WIDE_CHARS 2551#define MY_UCS(ucs,dec) case ucs: result = dec; break 2552unsigned 2553ucs2dec(unsigned ch) 2554{ 2555 unsigned result = ch; 2556 if ((ch > 127) 2557 && (ch != UCS_REPL)) { 2558 switch (ch) { 2559 MY_UCS(0x25ae, 0); /* black vertical rectangle */ 2560 MY_UCS(0x25c6, 1); /* black diamond */ 2561 MY_UCS(0x2592, 2); /* medium shade */ 2562 MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 2563 MY_UCS(0x240c, 4); /* symbol for form feed */ 2564 MY_UCS(0x240d, 5); /* symbol for carriage return */ 2565 MY_UCS(0x240a, 6); /* symbol for line feed */ 2566 MY_UCS(0x00b0, 7); /* degree sign */ 2567 MY_UCS(0x00b1, 8); /* plus-minus sign */ 2568 MY_UCS(0x2424, 9); /* symbol for newline */ 2569 MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 2570 MY_UCS(0x2518, 11); /* box drawings light up and left */ 2571 MY_UCS(0x2510, 12); /* box drawings light down and left */ 2572 MY_UCS(0x250c, 13); /* box drawings light down and right */ 2573 MY_UCS(0x2514, 14); /* box drawings light up and right */ 2574 MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 2575 MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 2576 MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 2577 MY_UCS(0x2500, 18); /* box drawings light horizontal */ 2578 MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 2579 MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 2580 MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 2581 MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 2582 MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 2583 MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 2584 MY_UCS(0x2502, 25); /* box drawings light vertical */ 2585 MY_UCS(0x2264, 26); /* less-than or equal to */ 2586 MY_UCS(0x2265, 27); /* greater-than or equal to */ 2587 MY_UCS(0x03c0, 28); /* greek small letter pi */ 2588 MY_UCS(0x2260, 29); /* not equal to */ 2589 MY_UCS(0x00a3, 30); /* pound sign */ 2590 MY_UCS(0x00b7, 31); /* middle dot */ 2591 } 2592 } 2593 return result; 2594} 2595 2596#undef MY_UCS 2597#define MY_UCS(ucs,dec) case dec: result = ucs; break 2598 2599unsigned 2600dec2ucs(unsigned ch) 2601{ 2602 unsigned result = ch; 2603 if (xtermIsDecGraphic(ch)) { 2604 switch (ch) { 2605 MY_UCS(0x25ae, 0); /* black vertical rectangle */ 2606 MY_UCS(0x25c6, 1); /* black diamond */ 2607 MY_UCS(0x2592, 2); /* medium shade */ 2608 MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 2609 MY_UCS(0x240c, 4); /* symbol for form feed */ 2610 MY_UCS(0x240d, 5); /* symbol for carriage return */ 2611 MY_UCS(0x240a, 6); /* symbol for line feed */ 2612 MY_UCS(0x00b0, 7); /* degree sign */ 2613 MY_UCS(0x00b1, 8); /* plus-minus sign */ 2614 MY_UCS(0x2424, 9); /* symbol for newline */ 2615 MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 2616 MY_UCS(0x2518, 11); /* box drawings light up and left */ 2617 MY_UCS(0x2510, 12); /* box drawings light down and left */ 2618 MY_UCS(0x250c, 13); /* box drawings light down and right */ 2619 MY_UCS(0x2514, 14); /* box drawings light up and right */ 2620 MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 2621 MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 2622 MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 2623 MY_UCS(0x2500, 18); /* box drawings light horizontal */ 2624 MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 2625 MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 2626 MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 2627 MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 2628 MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 2629 MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 2630 MY_UCS(0x2502, 25); /* box drawings light vertical */ 2631 MY_UCS(0x2264, 26); /* less-than or equal to */ 2632 MY_UCS(0x2265, 27); /* greater-than or equal to */ 2633 MY_UCS(0x03c0, 28); /* greek small letter pi */ 2634 MY_UCS(0x2260, 29); /* not equal to */ 2635 MY_UCS(0x00a3, 30); /* pound sign */ 2636 MY_UCS(0x00b7, 31); /* middle dot */ 2637 } 2638 } 2639 return result; 2640} 2641 2642#endif /* OPT_WIDE_CHARS */ 2643 2644#if OPT_SHIFT_FONTS 2645static void 2646lookupOneFontSize(XtermWidget xw, int fontnum) 2647{ 2648 TScreen *screen = TScreenOf(xw); 2649 2650 if (screen->menu_font_sizes[fontnum] == 0) { 2651 XTermFonts fnt; 2652 2653 memset(&fnt, 0, sizeof(fnt)); 2654 screen->menu_font_sizes[fontnum] = -1; 2655 if (xtermOpenFont(xw, screen->MenuFontName(fontnum), &fnt, fwAlways, True)) { 2656 if (fontnum <= fontMenu_lastBuiltin 2657 || strcmp(fnt.fn, DEFFONT)) 2658 screen->menu_font_sizes[fontnum] = FontSize(fnt.fs); 2659 xtermCloseFont(xw, &fnt); 2660 } 2661 } 2662} 2663 2664/* 2665 * Cache the font-sizes so subsequent larger/smaller font actions will go fast. 2666 */ 2667static void 2668lookupFontSizes(XtermWidget xw) 2669{ 2670 int n; 2671 2672 for (n = 0; n < NMENUFONTS; n++) { 2673 lookupOneFontSize(xw, n); 2674 } 2675} 2676 2677#if OPT_RENDERFONT 2678#define NMENU_RENDERFONTS (NMENUFONTS - 2) /* no selection or escape */ 2679static Boolean 2680useFaceSizes(XtermWidget xw) 2681{ 2682 Boolean result = False; 2683 int n; 2684 2685 if (UsingRenderFont(xw)) { 2686 result = True; 2687 for (n = 0; n < NMENU_RENDERFONTS; ++n) { 2688 if (xw->misc.face_size[n] <= 0.0) { 2689 result = False; 2690 break; 2691 } 2692 } 2693 if (!result) { 2694 Boolean broken_fonts = True; 2695 TScreen *screen = TScreenOf(xw); 2696 long first = screen->menu_font_sizes[0]; 2697 2698 lookupFontSizes(xw); 2699 for (n = 0; n < NMENUFONTS; n++) { 2700 if (screen->menu_font_sizes[n] > 0 2701 && screen->menu_font_sizes[n] != first) { 2702 broken_fonts = False; 2703 break; 2704 } 2705 } 2706 2707 /* 2708 * Workaround for breakage in font-packages - check if all of the 2709 * bitmap font sizes are the same, and if we're using TrueType 2710 * fonts. 2711 */ 2712 if (broken_fonts) { 2713 float lo_value = (float) 9.0e9; 2714 float hi_value = (float) 0.0; 2715 float value; 2716 2717 TRACE(("bitmap fonts are broken - set faceSize resources\n")); 2718 for (n = 0; n < NMENUFONTS; n++) { 2719 value = xw->misc.face_size[n]; 2720 if (value > 0.0) { 2721 if (lo_value > value) 2722 lo_value = value; 2723 if (hi_value < value) 2724 hi_value = value; 2725 } 2726 } 2727 2728 if (hi_value <= 0.0) 2729 sscanf(DEFFACESIZE, "%f", &value); 2730 else 2731 value = (float) ((hi_value + lo_value) / 2.0); 2732 if (value <= 0) 2733 value = (float) 14.0; 2734 2735 for (n = 0; n < NMENUFONTS; n++) { 2736 TRACE(("setting faceSize%d %.1f\n", n, value)); 2737 xw->misc.face_size[n] = value; 2738 value = (float) (value * 1.1); 2739 } 2740 result = True; 2741 } 2742 } 2743 } 2744 return result; 2745} 2746#endif 2747 2748/* 2749 * Find the index of a larger/smaller font (according to the sign of 'relative' 2750 * and its magnitude), starting from the 'old' index. 2751 */ 2752int 2753lookupRelativeFontSize(XtermWidget xw, int old, int relative) 2754{ 2755 TScreen *screen = TScreenOf(xw); 2756 int n, m = -1; 2757 2758 TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative)); 2759 if (!IsIcon(screen)) { 2760#if OPT_RENDERFONT 2761 if (useFaceSizes(xw)) { 2762 TRACE(("...using FaceSize\n")); 2763 if (relative != 0) { 2764 for (n = 0; n < NMENU_RENDERFONTS; ++n) { 2765 if (xw->misc.face_size[n] > 0 && 2766 xw->misc.face_size[n] != xw->misc.face_size[old]) { 2767 int cmp_0 = ((xw->misc.face_size[n] > 2768 xw->misc.face_size[old]) 2769 ? relative 2770 : -relative); 2771 int cmp_m = ((m < 0) 2772 ? 1 2773 : ((xw->misc.face_size[n] < 2774 xw->misc.face_size[m]) 2775 ? relative 2776 : -relative)); 2777 if (cmp_0 > 0 && cmp_m > 0) { 2778 m = n; 2779 } 2780 } 2781 } 2782 } 2783 } else 2784#endif 2785 { 2786 TRACE(("...using bitmap areas\n")); 2787 lookupFontSizes(xw); 2788 if (relative != 0) { 2789 for (n = 0; n < NMENUFONTS; ++n) { 2790 if (screen->menu_font_sizes[n] > 0 && 2791 screen->menu_font_sizes[n] != 2792 screen->menu_font_sizes[old]) { 2793 int cmp_0 = ((screen->menu_font_sizes[n] > 2794 screen->menu_font_sizes[old]) 2795 ? relative 2796 : -relative); 2797 int cmp_m = ((m < 0) 2798 ? 1 2799 : ((screen->menu_font_sizes[n] < 2800 screen->menu_font_sizes[m]) 2801 ? relative 2802 : -relative)); 2803 if (cmp_0 > 0 && cmp_m > 0) { 2804 m = n; 2805 } 2806 } 2807 } 2808 } 2809 } 2810 TRACE(("...new index %d\n", m)); 2811 if (m >= 0) { 2812 if (relative > 1) 2813 m = lookupRelativeFontSize(xw, m, relative - 1); 2814 else if (relative < -1) 2815 m = lookupRelativeFontSize(xw, m, relative + 1); 2816 } 2817 } 2818 return m; 2819} 2820 2821/* ARGSUSED */ 2822void 2823HandleLargerFont(Widget w GCC_UNUSED, 2824 XEvent * event GCC_UNUSED, 2825 String * params GCC_UNUSED, 2826 Cardinal *param_count GCC_UNUSED) 2827{ 2828 XtermWidget xw; 2829 2830 TRACE(("Handle larger-vt-font for %p\n", (void *) w)); 2831 if ((xw = getXtermWidget(w)) != 0) { 2832 if (xw->misc.shift_fonts) { 2833 TScreen *screen = TScreenOf(xw); 2834 int m; 2835 2836 m = lookupRelativeFontSize(xw, screen->menu_font_number, 1); 2837 if (m >= 0) { 2838 SetVTFont(xw, m, True, NULL); 2839 } else { 2840 Bell(xw, XkbBI_MinorError, 0); 2841 } 2842 } 2843 } 2844} 2845 2846/* ARGSUSED */ 2847void 2848HandleSmallerFont(Widget w GCC_UNUSED, 2849 XEvent * event GCC_UNUSED, 2850 String * params GCC_UNUSED, 2851 Cardinal *param_count GCC_UNUSED) 2852{ 2853 XtermWidget xw; 2854 2855 TRACE(("Handle smaller-vt-font for %p\n", (void *) w)); 2856 if ((xw = getXtermWidget(w)) != 0) { 2857 if (xw->misc.shift_fonts) { 2858 TScreen *screen = TScreenOf(xw); 2859 int m; 2860 2861 m = lookupRelativeFontSize(xw, screen->menu_font_number, -1); 2862 if (m >= 0) { 2863 SetVTFont(xw, m, True, NULL); 2864 } else { 2865 Bell(xw, XkbBI_MinorError, 0); 2866 } 2867 } 2868 } 2869} 2870#endif 2871 2872int 2873xtermGetFont(const char *param) 2874{ 2875 int fontnum; 2876 2877 switch (param[0]) { 2878 case 'd': 2879 case 'D': 2880 case '0': 2881 fontnum = fontMenu_default; 2882 break; 2883 case '1': 2884 fontnum = fontMenu_font1; 2885 break; 2886 case '2': 2887 fontnum = fontMenu_font2; 2888 break; 2889 case '3': 2890 fontnum = fontMenu_font3; 2891 break; 2892 case '4': 2893 fontnum = fontMenu_font4; 2894 break; 2895 case '5': 2896 fontnum = fontMenu_font5; 2897 break; 2898 case '6': 2899 fontnum = fontMenu_font6; 2900 break; 2901 case 'e': 2902 case 'E': 2903 fontnum = fontMenu_fontescape; 2904 break; 2905 case 's': 2906 case 'S': 2907 fontnum = fontMenu_fontsel; 2908 break; 2909 default: 2910 fontnum = -1; 2911 break; 2912 } 2913 return fontnum; 2914} 2915 2916/* ARGSUSED */ 2917void 2918HandleSetFont(Widget w GCC_UNUSED, 2919 XEvent * event GCC_UNUSED, 2920 String * params, 2921 Cardinal *param_count) 2922{ 2923 XtermWidget xw; 2924 2925 if ((xw = getXtermWidget(w)) != 0) { 2926 int fontnum; 2927 VTFontNames fonts; 2928 2929 memset(&fonts, 0, sizeof(fonts)); 2930 2931 if (*param_count == 0) { 2932 fontnum = fontMenu_default; 2933 } else { 2934 Cardinal maxparams = 1; /* total number of params allowed */ 2935 int result = xtermGetFont(params[0]); 2936 2937 switch (result) { 2938 case fontMenu_default: /* FALLTHRU */ 2939 case fontMenu_font1: /* FALLTHRU */ 2940 case fontMenu_font2: /* FALLTHRU */ 2941 case fontMenu_font3: /* FALLTHRU */ 2942 case fontMenu_font4: /* FALLTHRU */ 2943 case fontMenu_font5: /* FALLTHRU */ 2944 case fontMenu_font6: /* FALLTHRU */ 2945 break; 2946 case fontMenu_fontescape: 2947#if OPT_WIDE_CHARS 2948 maxparams = 5; 2949#else 2950 maxparams = 3; 2951#endif 2952 break; 2953 case fontMenu_fontsel: 2954 maxparams = 2; 2955 break; 2956 default: 2957 Bell(xw, XkbBI_MinorError, 0); 2958 return; 2959 } 2960 fontnum = result; 2961 2962 if (*param_count > maxparams) { /* see if extra args given */ 2963 Bell(xw, XkbBI_MinorError, 0); 2964 return; 2965 } 2966 switch (*param_count) { /* assign 'em */ 2967#if OPT_WIDE_CHARS 2968 case 5: 2969 fonts.f_wb = params[4]; 2970 /* FALLTHRU */ 2971 case 4: 2972 fonts.f_w = params[3]; 2973 /* FALLTHRU */ 2974#endif 2975 case 3: 2976 fonts.f_b = params[2]; 2977 /* FALLTHRU */ 2978 case 2: 2979 fonts.f_n = params[1]; 2980 break; 2981 } 2982 } 2983 2984 SetVTFont(xw, fontnum, True, &fonts); 2985 } 2986} 2987 2988void 2989SetVTFont(XtermWidget xw, 2990 int which, 2991 Bool doresize, 2992 const VTFontNames * fonts) 2993{ 2994 TScreen *screen = TScreenOf(xw); 2995 2996 TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which, 2997 (fonts && fonts->f_n) ? fonts->f_n : "<null>", 2998 (fonts && fonts->f_b) ? fonts->f_b : "<null>")); 2999 3000 if (IsIcon(screen)) { 3001 Bell(xw, XkbBI_MinorError, 0); 3002 } else if (which >= 0 && which < NMENUFONTS) { 3003 VTFontNames myfonts; 3004 3005 memset(&myfonts, 0, sizeof(myfonts)); 3006 if (fonts != 0) 3007 myfonts = *fonts; 3008 3009 if (which == fontMenu_fontsel) { /* go get the selection */ 3010 FindFontSelection(xw, myfonts.f_n, False); 3011 } else { 3012 int oldFont = screen->menu_font_number; 3013 3014#define USE_CACHED(field, name) \ 3015 if (myfonts.field == 0) { \ 3016 myfonts.field = screen->menu_font_names[which][name]; \ 3017 TRACE(("set myfonts." #field " from menu_font_names[%d][" #name "] %s\n", \ 3018 which, NonNull(myfonts.field))); \ 3019 } else { \ 3020 TRACE(("set myfonts." #field " reused\n")); \ 3021 } 3022#define SAVE_FNAME(field, name) \ 3023 if (myfonts.field != 0) { \ 3024 if (screen->menu_font_names[which][name] == 0 \ 3025 || strcmp(screen->menu_font_names[which][name], myfonts.field)) { \ 3026 TRACE(("updating menu_font_names[%d][" #name "] to %s\n", \ 3027 which, myfonts.field)); \ 3028 screen->menu_font_names[which][name] = x_strdup(myfonts.field); \ 3029 } \ 3030 } 3031 3032 USE_CACHED(f_n, fNorm); 3033 USE_CACHED(f_b, fBold); 3034#if OPT_WIDE_CHARS 3035 USE_CACHED(f_w, fWide); 3036 USE_CACHED(f_wb, fWBold); 3037#endif 3038 if (xtermLoadFont(xw, 3039 &myfonts, 3040 doresize, which)) { 3041 /* 3042 * If successful, save the data so that a subsequent query via 3043 * OSC-50 will return the expected values. 3044 */ 3045 SAVE_FNAME(f_n, fNorm); 3046 SAVE_FNAME(f_b, fBold); 3047#if OPT_WIDE_CHARS 3048 SAVE_FNAME(f_w, fWide); 3049 SAVE_FNAME(f_wb, fWBold); 3050#endif 3051 } else { 3052 xtermLoadFont(xw, 3053 xtermFontName(screen->MenuFontName(oldFont)), 3054 doresize, oldFont); 3055 Bell(xw, XkbBI_MinorError, 0); 3056 } 3057 } 3058 } else { 3059 Bell(xw, XkbBI_MinorError, 0); 3060 } 3061 return; 3062} 3063