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