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