fontutils.c revision 2eaa94a1
1/* $XTermId: fontutils.c,v 1.278 2008/12/30 17:32:06 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 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 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 = x_toupper(*pattern++); 509 int m = x_toupper(*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 myClass[0] = x_toupper(myClass[0]); 1306 1307 if (xtermLoadVTFonts(xw, myName, myClass)) { 1308 /* 1309 * When switching fonts, try to preserve the font-menu selection, since 1310 * it is less surprising to do that (if the font-switching can be 1311 * undone) than to switch to "Default". 1312 */ 1313 int font_number = xw->screen.menu_font_number; 1314 if (font_number > fontMenu_lastBuiltin) 1315 font_number = fontMenu_lastBuiltin; 1316 for (n = 0; n < NMENUFONTS; ++n) 1317 xw->screen.menu_font_sizes[n] = 0; 1318 SetVTFont(xw, font_number, True, 1319 ((font_number == fontMenu_default) 1320 ? &(xw->misc.default_font) 1321 : NULL)); 1322 } 1323 1324 MyStackFree(myClass, buf); 1325 } 1326} 1327#endif /* OPT_LOAD_VTFONTS */ 1328 1329/* 1330 * Set the limits for the box that outlines the cursor. 1331 */ 1332void 1333xtermSetCursorBox(TScreen * screen) 1334{ 1335 static XPoint VTbox[NBOX]; 1336 XPoint *vp; 1337 int fw = FontWidth(screen) - 1; 1338 int fh = FontHeight(screen) - 1; 1339 int hh = screen->cursor_underline ? 1 : fh; 1340 1341 vp = &VTbox[1]; 1342 (vp++)->x = (short) fw; 1343 (vp++)->y = (short) hh; 1344 (vp++)->x = (short) -fw; 1345 vp->y = (short) -hh; 1346 1347 screen->box = VTbox; 1348} 1349 1350#define CACHE_XFT(dst,src) if (src != 0) {\ 1351 dst[fontnum] = src;\ 1352 TRACE(("%s[%d] = %d (%d,%d) by %d\n",\ 1353 #dst,\ 1354 fontnum,\ 1355 src->height,\ 1356 src->ascent,\ 1357 src->descent,\ 1358 src->max_advance_width));\ 1359 } 1360 1361#if OPT_RENDERFONT 1362static XftFont * 1363xtermOpenXft(Display * dpy, XftPattern * pat, const char *tag GCC_UNUSED) 1364{ 1365 XftPattern *match; 1366 XftResult status; 1367 XftFont *result = 0; 1368 1369 if (pat != 0) { 1370 match = XftFontMatch(dpy, DefaultScreen(dpy), pat, &status); 1371 if (match != 0) { 1372 result = XftFontOpenPattern(dpy, match); 1373 if (result != 0) { 1374 TRACE(("...matched %s font\n", tag)); 1375 } else { 1376 TRACE(("...could did not open %s font\n", tag)); 1377 XftPatternDestroy(match); 1378 } 1379 } else { 1380 TRACE(("...did not match %s font\n", tag)); 1381 } 1382 } 1383 return result; 1384} 1385#endif 1386 1387#if OPT_RENDERFONT 1388#if OPT_SHIFT_FONTS 1389/* 1390 * Don't make a dependency on the math library for a single function. 1391 * (Newton Raphson). 1392 */ 1393static double 1394mySquareRoot(double value) 1395{ 1396 double result = 0.0; 1397 if (value > 0.0) { 1398 int n; 1399 double older = value; 1400 for (n = 0; n < 10; ++n) { 1401 double delta = (older * older - value) / (2.0 * older); 1402 double newer = older - delta; 1403 older = newer; 1404 result = newer; 1405 if (delta > -0.001 && delta < 0.001) 1406 break; 1407 } 1408 } 1409 return result; 1410} 1411#endif 1412 1413/* 1414 * Given the Xft font metrics, determine the actual font size. This is used 1415 * for each font to ensure that normal, bold and italic fonts follow the same 1416 * rule. 1417 */ 1418static void 1419setRenderFontsize(TScreen * screen, VTwin * win, XftFont * font, const char *tag) 1420{ 1421 if (font != 0) { 1422 int width, height, ascent, descent; 1423 1424 (void) screen; 1425 1426 width = font->max_advance_width; 1427 height = font->height; 1428 ascent = font->ascent; 1429 descent = font->descent; 1430 if (height < ascent + descent) { 1431 TRACE(("...increase height from %d\n", height)); 1432 height = ascent + descent; 1433 } 1434 if (is_double_width_font_xft(screen->display, font)) { 1435 TRACE(("...reduced width from %d\n", width)); 1436 width >>= 1; 1437 } 1438 if (tag == 0) { 1439 win->f_width = width; 1440 win->f_height = height; 1441 win->f_ascent = ascent; 1442 win->f_descent = descent; 1443 TRACE(("setRenderFontsize result %dx%d (%d+%d)\n", 1444 width, height, ascent, descent)); 1445 } else if (win->f_width < width || 1446 win->f_height < height || 1447 win->f_ascent < ascent || 1448 win->f_descent < descent) { 1449 TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n", 1450 tag, 1451 win->f_width, win->f_height, win->f_ascent, win->f_descent, 1452 width, height, ascent, descent)); 1453 1454 win->f_width = width; 1455 win->f_height = height; 1456 win->f_ascent = ascent; 1457 win->f_descent = descent; 1458 } else { 1459 TRACE(("setRenderFontsize %s unchanged\n", tag)); 1460 } 1461 } 1462} 1463#endif 1464 1465/* 1466 * Compute useful values for the font/window sizes 1467 */ 1468void 1469xtermComputeFontInfo(XtermWidget xw, 1470 VTwin * win, 1471 XFontStruct * font, 1472 int sbwidth) 1473{ 1474 TScreen *screen = &(xw->screen); 1475 1476 int i, j, width, height; 1477 1478#if OPT_RENDERFONT 1479 /* 1480 * xterm contains a lot of references to fonts, assuming they are fixed 1481 * size. This chunk of code overrides the actual font-selection (see 1482 * drawXtermText()), if the user has selected render-font. All of the 1483 * font-loading for fixed-fonts still goes on whether or not this chunk 1484 * overrides it. 1485 */ 1486 if (xw->misc.render_font && !IsIconWin(screen, win)) { 1487 Display *dpy = screen->display; 1488 int fontnum = screen->menu_font_number; 1489 XftFont *norm = screen->renderFontNorm[fontnum]; 1490 XftFont *bold = screen->renderFontBold[fontnum]; 1491 XftFont *ital = screen->renderFontItal[fontnum]; 1492#if OPT_RENDERWIDE 1493 XftFont *wnorm = screen->renderWideNorm[fontnum]; 1494 XftFont *wbold = screen->renderWideBold[fontnum]; 1495 XftFont *wital = screen->renderWideItal[fontnum]; 1496#endif 1497 1498 if (norm == 0 && xw->misc.face_name) { 1499 XftPattern *pat; 1500 double face_size = xw->misc.face_size[fontnum]; 1501 1502 TRACE(("xtermComputeFontInfo norm(face %s, size %f)\n", 1503 xw->misc.face_name, 1504 xw->misc.face_size[fontnum])); 1505 1506 if (face_size <= 0.0) { 1507#if OPT_SHIFT_FONTS 1508 /* 1509 * If the user is switching font-sizes, make it follow by 1510 * default the same ratios to the default as the fixed fonts 1511 * would, for easy comparison. There will be some differences 1512 * since the fixed fonts have a variety of height/width ratios, 1513 * but this is simpler than adding another resource value - and 1514 * as noted above, the data for the fixed fonts are available. 1515 */ 1516 lookupOneFontSize(xw, 0); 1517 lookupOneFontSize(xw, fontnum); 1518 if (fontnum == fontMenu_default) { 1519 face_size = 14.0; 1520 } else { 1521 double ratio; 1522 int num = screen->menu_font_sizes[fontnum]; 1523 int den = screen->menu_font_sizes[0]; 1524 1525 if (den <= 0) 1526 den = 1; 1527 ratio = mySquareRoot((1.0 * num) / den); 1528 1529 face_size = (ratio * xw->misc.face_size[0]); 1530 TRACE(("scaled using %3d/%d = %.2f -> %f\n", 1531 num, den, ratio, face_size)); 1532 } 1533#else 1534 switch (fontnum) { 1535 case fontMenu_font1: 1536 face_size = 8.0; 1537 break; 1538 case fontMenu_font2: 1539 face_size = 10.0; 1540 break; 1541 case fontMenu_font3: 1542 face_size = 12.0; 1543 break; 1544 default: 1545 face_size = 14.0; 1546 break; 1547 case fontMenu_font4: 1548 face_size = 16.0; 1549 break; 1550 case fontMenu_font5: 1551 face_size = 18.0; 1552 break; 1553 case fontMenu_font6: 1554 face_size = 20.0; 1555 break; 1556 } 1557#endif 1558 xw->misc.face_size[fontnum] = face_size; 1559 } 1560 1561 /* 1562 * By observation (there is no documentation), XftPatternBuild is 1563 * cumulative. Build the bold- and italic-patterns on top of the 1564 * normal pattern. 1565 */ 1566#define NormXftPattern \ 1567 XFT_FAMILY, XftTypeString, "mono", \ 1568 XFT_SIZE, XftTypeDouble, face_size, \ 1569 XFT_SPACING, XftTypeInteger, XFT_MONO 1570 1571#define BoldXftPattern(norm) \ 1572 XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \ 1573 XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width 1574 1575#define ItalXftPattern(norm) \ 1576 XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \ 1577 XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width 1578 1579 if ((pat = XftNameParse(xw->misc.face_name)) != 0) { 1580 XftPatternBuild(pat, 1581 NormXftPattern, 1582 (void *) 0); 1583 norm = xtermOpenXft(dpy, pat, "normal"); 1584 1585 if (norm != 0) { 1586 XftPatternBuild(pat, 1587 BoldXftPattern(norm), 1588 (void *) 0); 1589 bold = xtermOpenXft(dpy, pat, "bold"); 1590 1591#if OPT_ISO_COLORS 1592 if (screen->italicULMode 1593 && (pat = XftNameParse(xw->misc.face_name)) != 0) { 1594 XftPatternBuild(pat, 1595 NormXftPattern, 1596 ItalXftPattern(norm), 1597 (void *) 0); 1598 ital = xtermOpenXft(dpy, pat, "italic"); 1599 } 1600#endif /* OPT_ISO_COLORS */ 1601 1602 /* 1603 * FIXME: just assume that the corresponding font has no 1604 * graphics characters. 1605 */ 1606 if (screen->fnt_boxes) { 1607 screen->fnt_boxes = False; 1608 TRACE(("Xft opened - will %suse internal line-drawing characters\n", 1609 screen->fnt_boxes ? "not " : "")); 1610 } 1611 } 1612 1613 XftPatternDestroy(pat); 1614 } 1615 1616 CACHE_XFT(screen->renderFontNorm, norm); 1617 CACHE_XFT(screen->renderFontBold, bold); 1618 CACHE_XFT(screen->renderFontItal, ital); 1619 1620 /* 1621 * See xtermXftDrawString(). 1622 */ 1623#if OPT_RENDERWIDE 1624 if (norm != 0 && screen->wide_chars) { 1625 char *face_name = (xw->misc.face_wide_name 1626 ? xw->misc.face_wide_name 1627 : xw->misc.face_name); 1628 int char_width = norm->max_advance_width * 2; 1629 1630 TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n", 1631 face_name, 1632 char_width)); 1633 1634#define WideXftPattern \ 1635 XFT_FAMILY, XftTypeString, "mono", \ 1636 XFT_SIZE, XftTypeDouble, face_size, \ 1637 XFT_SPACING, XftTypeInteger, XFT_MONO 1638 1639 if ((pat = XftNameParse(face_name)) != 0) { 1640 XftPatternBuild(pat, 1641 WideXftPattern, 1642 XFT_CHAR_WIDTH, XftTypeInteger, char_width, 1643 (void *) 0); 1644 wnorm = xtermOpenXft(dpy, pat, "wide"); 1645 1646 if (wnorm != 0) { 1647 XftPatternBuild(pat, 1648 WideXftPattern, 1649 BoldXftPattern(wnorm), 1650 (void *) 0); 1651 wbold = xtermOpenXft(dpy, pat, "wide-bold"); 1652 1653#if OPT_ISO_COLORS 1654 if (screen->italicULMode 1655 && (pat = XftNameParse(face_name)) != 0) { 1656 XftPatternBuild(pat, 1657 WideXftPattern, 1658 ItalXftPattern(wnorm), 1659 (void *) 0); 1660 wital = xtermOpenXft(dpy, pat, "wide-italic"); 1661 } 1662#endif 1663 } 1664 XftPatternDestroy(pat); 1665 } 1666 1667 CACHE_XFT(screen->renderWideNorm, wnorm); 1668 CACHE_XFT(screen->renderWideBold, wbold); 1669 CACHE_XFT(screen->renderWideItal, wital); 1670 } 1671#endif /* OPT_RENDERWIDE */ 1672 } 1673 if (norm == 0) { 1674 TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum)); 1675 xw->misc.render_font = False; 1676 update_font_renderfont(); 1677 /* now we will fall through into the bitmap fonts */ 1678 } else { 1679 setRenderFontsize(screen, win, norm, NULL); 1680 setRenderFontsize(screen, win, bold, "bold"); 1681 setRenderFontsize(screen, win, ital, "ital"); 1682 } 1683 } 1684 /* 1685 * Are we handling a bitmap font? 1686 */ 1687 if (!xw->misc.render_font || IsIconWin(screen, win)) 1688#endif /* OPT_RENDERFONT */ 1689 { 1690 if (is_double_width_font(font)) { 1691 win->f_width = (font->min_bounds.width); 1692 } else { 1693 win->f_width = (font->max_bounds.width); 1694 } 1695 win->f_height = (font->ascent + font->descent); 1696 win->f_ascent = font->ascent; 1697 win->f_descent = font->descent; 1698 } 1699 i = 2 * screen->border + sbwidth; 1700 j = 2 * screen->border; 1701 width = MaxCols(screen) * win->f_width + i; 1702 height = MaxRows(screen) * win->f_height + j; 1703 win->fullwidth = width; 1704 win->fullheight = height; 1705 win->width = width - i; 1706 win->height = height - j; 1707 1708 TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n", 1709 win->height, 1710 win->width, 1711 win->fullheight, 1712 win->fullwidth, 1713 win->f_height, 1714 win->f_width, 1715 win->f_ascent, 1716 win->f_descent)); 1717} 1718 1719/* save this information as a side-effect for double-sized characters */ 1720void 1721xtermSaveFontInfo(TScreen * screen, XFontStruct * font) 1722{ 1723 screen->fnt_wide = (font->max_bounds.width); 1724 screen->fnt_high = (font->ascent + font->descent); 1725 TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide)); 1726} 1727 1728/* 1729 * After loading a new font, update the structures that use its size. 1730 */ 1731void 1732xtermUpdateFontInfo(XtermWidget xw, Bool doresize) 1733{ 1734 TScreen *screen = &(xw->screen); 1735 1736 int scrollbar_width; 1737 VTwin *win = &(screen->fullVwin); 1738 1739 scrollbar_width = (xw->misc.scrollbar 1740 ? (screen->scrollWidget->core.width + 1741 BorderWidth(screen->scrollWidget)) 1742 : 0); 1743 xtermComputeFontInfo(xw, win, screen->fnts[fNorm].fs, scrollbar_width); 1744 xtermSaveFontInfo(screen, screen->fnts[fNorm].fs); 1745 1746 if (doresize) { 1747 if (VWindow(screen)) { 1748 xtermClear(xw); 1749 } 1750 TRACE(("xtermUpdateFontInfo {{\n")); 1751 DoResizeScreen(xw); /* set to the new natural size */ 1752 ResizeScrollBar(xw); 1753 Redraw(); 1754 TRACE(("... }} xtermUpdateFontInfo\n")); 1755#ifdef SCROLLBAR_RIGHT 1756 updateRightScrollbar(xw); 1757#endif 1758 } 1759 xtermSetCursorBox(screen); 1760} 1761 1762#if OPT_BOX_CHARS 1763 1764/* 1765 * Returns true if the given character is missing from the specified font. 1766 */ 1767Bool 1768xtermMissingChar(XtermWidget xw, unsigned ch, XFontStruct * font) 1769{ 1770 if (font != 0 1771 && font->per_char != 0 1772 && !font->all_chars_exist) { 1773 static XCharStruct dft, *tmp = &dft, *pc = 0; 1774 1775 if (font->max_byte1 == 0) { 1776#if OPT_WIDE_CHARS 1777 if (ch > 255) { 1778 TRACE(("xtermMissingChar %#04x (row)\n", ch)); 1779 return True; 1780 } 1781#endif 1782 CI_GET_CHAR_INFO_1D(font, E2A(ch), tmp, pc); 1783 } 1784#if OPT_WIDE_CHARS 1785 else { 1786 CI_GET_CHAR_INFO_2D(font, HI_BYTE(ch), LO_BYTE(ch), tmp, pc); 1787 } 1788#else 1789 1790 if (!pc) 1791 return False; /* Urgh! */ 1792#endif 1793 1794 if (CI_NONEXISTCHAR(pc)) { 1795 TRACE(("xtermMissingChar %#04x (!exists)\n", ch)); 1796 return True; 1797 } 1798 } 1799 if (xtermIsDecGraphic(ch) 1800 && xw->screen.force_box_chars) { 1801 TRACE(("xtermMissingChar %#04x (forced off)\n", ch)); 1802 return True; 1803 } 1804 return False; 1805} 1806 1807/* 1808 * The grid is arbitrary, enough resolution that nothing's lost in 1809 * initialization. 1810 */ 1811#define BOX_HIGH 60 1812#define BOX_WIDE 60 1813 1814#define MID_HIGH (BOX_HIGH/2) 1815#define MID_WIDE (BOX_WIDE/2) 1816 1817#define CHR_WIDE ((9*BOX_WIDE)/10) 1818#define CHR_HIGH ((9*BOX_HIGH)/10) 1819 1820/* 1821 * ...since we'll scale the values anyway. 1822 */ 1823#define SCALE_X(n) n = (n * (font_width-1)) / (BOX_WIDE-1) 1824#define SCALE_Y(n) n = (n * (font_height-1)) / (BOX_HIGH-1) 1825 1826#define SEG(x0,y0,x1,y1) x0,y0, x1,y1 1827 1828/* 1829 * Draw the given graphic character, if it is simple enough (i.e., a 1830 * line-drawing character). 1831 */ 1832void 1833xtermDrawBoxChar(XtermWidget xw, 1834 unsigned ch, 1835 unsigned flags, 1836 GC gc, 1837 int x, 1838 int y, 1839 int cells) 1840{ 1841 TScreen *screen = &(xw->screen); 1842 /* *INDENT-OFF* */ 1843 static const short glyph_ht[] = { 1844 SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,5*MID_HIGH/6), /* H */ 1845 SEG(6*BOX_WIDE/10, 0, 6*BOX_WIDE/10,5*MID_HIGH/6), 1846 SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12), 1847 SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 1848 SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 1849 -1 1850 }, glyph_ff[] = { 1851 SEG(1*BOX_WIDE/10, 0, 6*BOX_WIDE/10, 0), /* F */ 1852 SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12), 1853 SEG(1*BOX_WIDE/10, 0, 0*BOX_WIDE/3, 5*MID_HIGH/6), 1854 SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 1855 SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 1856 SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 1857 -1 1858 }, glyph_lf[] = { 1859 SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,9*MID_HIGH/12), /* L */ 1860 SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12), 1861 SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 1862 SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 1863 SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 1864 -1 1865 }, glyph_nl[] = { 1866 SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10, 0), /* N */ 1867 SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/6, 5*MID_HIGH/6), 1868 SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 1869 SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), /* L */ 1870 SEG(1*BOX_WIDE/3, CHR_HIGH, CHR_WIDE, CHR_HIGH), 1871 -1 1872 }, glyph_vt[] = { 1873 SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/12,5*MID_HIGH/6), /* V */ 1874 SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 1875 SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 1876 SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 1877 -1 1878 }, plus_or_minus[] = 1879 { 1880 SEG( 0, 5*BOX_HIGH/6, CHR_WIDE, 5*BOX_HIGH/6), 1881 SEG( MID_WIDE, 2*BOX_HIGH/6, MID_WIDE, 4*BOX_HIGH/6), 1882 SEG( 0, 3*BOX_HIGH/6, CHR_WIDE, 3*BOX_HIGH/6), 1883 -1 1884 }, lower_right_corner[] = 1885 { 1886 SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 1887 SEG( MID_WIDE, MID_HIGH, MID_WIDE, 0), 1888 -1 1889 }, upper_right_corner[] = 1890 { 1891 SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 1892 SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 1893 -1 1894 }, upper_left_corner[] = 1895 { 1896 SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 1897 SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 1898 -1 1899 }, lower_left_corner[] = 1900 { 1901 SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 1902 SEG( MID_WIDE, MID_WIDE, BOX_WIDE, MID_HIGH), 1903 -1 1904 }, cross[] = 1905 { 1906 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 1907 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 1908 -1 1909 }, scan_line_1[] = 1910 { 1911 SEG( 0, 0, BOX_WIDE, 0), 1912 -1 1913 }, scan_line_3[] = 1914 { 1915 SEG( 0, BOX_HIGH/4, BOX_WIDE, BOX_HIGH/4), 1916 -1 1917 }, scan_line_7[] = 1918 { 1919 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 1920 -1 1921 }, scan_line_9[] = 1922 { 1923 SEG( 0, 3*BOX_HIGH/4, BOX_WIDE, 3*BOX_HIGH/4), 1924 -1 1925 }, horizontal_line[] = 1926 { 1927 SEG( 0, BOX_HIGH, BOX_WIDE, BOX_HIGH), 1928 -1 1929 }, left_tee[] = 1930 { 1931 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 1932 SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 1933 -1 1934 }, right_tee[] = 1935 { 1936 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 1937 SEG( MID_WIDE, MID_HIGH, 0, MID_HIGH), 1938 -1 1939 }, bottom_tee[] = 1940 { 1941 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 1942 SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 1943 -1 1944 }, top_tee[] = 1945 { 1946 SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 1947 SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 1948 -1 1949 }, vertical_line[] = 1950 { 1951 SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 1952 -1 1953 }, less_than_or_equal[] = 1954 { 1955 SEG( CHR_WIDE, BOX_HIGH/3, 0, MID_HIGH), 1956 SEG( CHR_WIDE, 2*BOX_HIGH/3, 0, MID_HIGH), 1957 SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 1958 -1 1959 }, greater_than_or_equal[] = 1960 { 1961 SEG( 0, BOX_HIGH/3, CHR_WIDE, MID_HIGH), 1962 SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, MID_HIGH), 1963 SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 1964 -1 1965 }, greek_pi[] = 1966 { 1967 SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 1968 SEG(5*CHR_WIDE/6, MID_HIGH, 5*CHR_WIDE/6, CHR_HIGH), 1969 SEG(2*CHR_WIDE/6, MID_HIGH, 2*CHR_WIDE/6, CHR_HIGH), 1970 -1 1971 }, not_equal_to[] = 1972 { 1973 SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3, CHR_HIGH), 1974 SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, 2*BOX_HIGH/3), 1975 SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 1976 -1 1977 }; 1978 /* *INDENT-ON* */ 1979 1980 static const short *lines[] = 1981 { 1982 0, /* 00 (unused) */ 1983 0, /* 01 diamond */ 1984 0, /* 02 box */ 1985 glyph_ht, /* 03 HT */ 1986 glyph_ff, /* 04 FF */ 1987 0, /* 05 CR */ 1988 glyph_lf, /* 06 LF */ 1989 0, /* 07 degrees (small circle) */ 1990 plus_or_minus, /* 08 */ 1991 glyph_nl, /* 09 */ 1992 glyph_vt, /* 0A */ 1993 lower_right_corner, /* 0B */ 1994 upper_right_corner, /* 0C */ 1995 upper_left_corner, /* 0D */ 1996 lower_left_corner, /* 0E */ 1997 cross, /* 0F */ 1998 scan_line_1, /* 10 */ 1999 scan_line_3, /* 11 */ 2000 scan_line_7, /* 12 */ 2001 scan_line_9, /* 13 */ 2002 horizontal_line, /* 14 */ 2003 left_tee, /* 15 */ 2004 right_tee, /* 16 */ 2005 bottom_tee, /* 17 */ 2006 top_tee, /* 18 */ 2007 vertical_line, /* 19 */ 2008 less_than_or_equal, /* 1A */ 2009 greater_than_or_equal, /* 1B */ 2010 greek_pi, /* 1C */ 2011 not_equal_to, /* 1D */ 2012 0, /* 1E LB */ 2013 0, /* 1F bullet */ 2014 }; 2015 2016 GC gc2; 2017 CgsEnum cgsId = (ch == 2) ? gcDots : gcLine; 2018 VTwin *cgsWin = WhichVWin(screen); 2019 const short *p; 2020 unsigned font_width = ((flags & DOUBLEWFONT) ? 2 : 1) * screen->fnt_wide; 2021 unsigned font_height = ((flags & DOUBLEHFONT) ? 2 : 1) * screen->fnt_high; 2022 2023 if (cells > 1) 2024 font_width *= cells; 2025 2026#if OPT_WIDE_CHARS 2027 /* 2028 * Try to show line-drawing characters if we happen to be in UTF-8 2029 * mode, but have gotten an old-style font. 2030 */ 2031 if (screen->utf8_mode 2032#if OPT_RENDERFONT 2033 && !UsingRenderFont(xw) 2034#endif 2035 && (ch > 127) 2036 && (ch != UCS_REPL)) { 2037 unsigned n; 2038 for (n = 1; n < 32; n++) { 2039 if (dec2ucs(n) == ch 2040 && !xtermMissingChar(xw, n, 2041 ((flags & BOLD) 2042 ? screen->fnts[fBold].fs 2043 : screen->fnts[fNorm].fs))) { 2044 TRACE(("...use xterm-style linedrawing\n")); 2045 ch = n; 2046 break; 2047 } 2048 } 2049 } 2050#endif 2051 2052 TRACE(("DRAW_BOX(%d) cell %dx%d at %d,%d%s\n", 2053 ch, font_height, font_width, y, x, 2054 (ch >= (sizeof(lines) / sizeof(lines[0])) 2055 ? "-BAD" 2056 : ""))); 2057 2058 if (cgsId == gcDots) { 2059 setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc)); 2060 setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc)); 2061 setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 2062 } else { 2063 setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc)); 2064 setCgsFore(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 2065 setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 2066 } 2067 gc2 = getCgsGC(xw, cgsWin, cgsId); 2068 2069 if (!(flags & NOBACKGROUND)) { 2070 XFillRectangle(screen->display, VWindow(screen), gc2, x, y, 2071 font_width, 2072 font_height); 2073 } 2074 2075 setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc)); 2076 setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc)); 2077 setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 2078 gc2 = getCgsGC(xw, cgsWin, cgsId); 2079 2080 XSetLineAttributes(screen->display, gc2, 2081 (flags & BOLD) 2082 ? ((font_height > 12) 2083 ? font_height / 12 2084 : 1) 2085 : ((font_height > 16) 2086 ? font_height / 16 2087 : 1), 2088 LineSolid, 2089 CapProjecting, 2090 JoinMiter); 2091 2092 if (ch == 1) { /* diamond */ 2093 XPoint points[5]; 2094 int npoints = 5, n; 2095 2096 points[0].x = MID_WIDE; 2097 points[0].y = BOX_HIGH / 4; 2098 2099 points[1].x = 8 * BOX_WIDE / 8; 2100 points[1].y = MID_HIGH; 2101 2102 points[2].x = points[0].x; 2103 points[2].y = 3 * BOX_HIGH / 4; 2104 2105 points[3].x = 0 * BOX_WIDE / 8; 2106 points[3].y = points[1].y; 2107 2108 points[4].x = points[0].x; 2109 points[4].y = points[0].y; 2110 2111 for (n = 0; n < npoints; ++n) { 2112 SCALE_X(points[n].x); 2113 SCALE_Y(points[n].y); 2114 points[n].x += x; 2115 points[n].y += y; 2116 } 2117 2118 XFillPolygon(screen->display, 2119 VWindow(screen), gc2, 2120 points, npoints, 2121 Convex, CoordModeOrigin); 2122 } else if (ch == 7) { /* degrees */ 2123 unsigned width = (BOX_WIDE / 3); 2124 int x_coord = MID_WIDE - (width / 2); 2125 int y_coord = MID_HIGH - width; 2126 2127 SCALE_X(x_coord); 2128 SCALE_Y(y_coord); 2129 SCALE_X(width); 2130 2131 XDrawArc(screen->display, 2132 VWindow(screen), gc2, 2133 x + x_coord, y + y_coord, width, width, 2134 0, 2135 360 * 64); 2136 } else if (ch == 0x1f) { /* bullet */ 2137 unsigned width = 7 * BOX_WIDE / 10; 2138 int x_coord = MID_WIDE - (width / 3); 2139 int y_coord = MID_HIGH - (width / 3); 2140 2141 SCALE_X(x_coord); 2142 SCALE_Y(y_coord); 2143 SCALE_X(width); 2144 2145 XDrawArc(screen->display, 2146 VWindow(screen), gc2, 2147 x + x_coord, y + y_coord, width, width, 2148 0, 2149 360 * 64); 2150 } else if (ch < (sizeof(lines) / sizeof(lines[0])) 2151 && (p = lines[ch]) != 0) { 2152 unsigned coord[4]; 2153 int n = 0; 2154 while (*p >= 0) { 2155 coord[n++] = *p++; 2156 if (n == 4) { 2157 SCALE_X(coord[0]); 2158 SCALE_Y(coord[1]); 2159 SCALE_X(coord[2]); 2160 SCALE_Y(coord[3]); 2161 XDrawLine(screen->display, 2162 VWindow(screen), gc2, 2163 x + coord[0], y + coord[1], 2164 x + coord[2], y + coord[3]); 2165 n = 0; 2166 } 2167 } 2168 } else if (screen->force_all_chars) { 2169 /* bounding rectangle, for debugging */ 2170 XDrawRectangle(screen->display, VWindow(screen), gc2, x, y, 2171 font_width - 1, 2172 font_height - 1); 2173 } 2174} 2175 2176#if OPT_RENDERFONT 2177 2178/* 2179 * Check if the given character has a glyph known to Xft. 2180 * 2181 * see xc/lib/Xft/xftglyphs.c 2182 */ 2183Bool 2184xtermXftMissing(XtermWidget xw, XftFont * font, unsigned wc) 2185{ 2186 Bool result = False; 2187 2188 if (font != 0) { 2189 if (!XftGlyphExists(xw->screen.display, font, wc)) { 2190#if OPT_WIDE_CHARS 2191 TRACE(("xtermXftMissing %d (dec=%#x, ucs=%#x)\n", 2192 wc, ucs2dec(wc), dec2ucs(wc))); 2193#else 2194 TRACE(("xtermXftMissing %d\n", wc)); 2195#endif 2196 result = True; 2197 } 2198 } 2199 return result; 2200} 2201#endif /* OPT_RENDERFONT && OPT_WIDE_CHARS */ 2202 2203#endif /* OPT_BOX_CHARS */ 2204 2205#if OPT_WIDE_CHARS 2206#define MY_UCS(ucs,dec) case ucs: result = dec; break 2207unsigned 2208ucs2dec(unsigned ch) 2209{ 2210 unsigned result = ch; 2211 if ((ch > 127) 2212 && (ch != UCS_REPL)) { 2213 switch (ch) { 2214 MY_UCS(0x25ae, 0); /* black vertical rectangle */ 2215 MY_UCS(0x25c6, 1); /* black diamond */ 2216 MY_UCS(0x2592, 2); /* medium shade */ 2217 MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 2218 MY_UCS(0x240c, 4); /* symbol for form feed */ 2219 MY_UCS(0x240d, 5); /* symbol for carriage return */ 2220 MY_UCS(0x240a, 6); /* symbol for line feed */ 2221 MY_UCS(0x00b0, 7); /* degree sign */ 2222 MY_UCS(0x00b1, 8); /* plus-minus sign */ 2223 MY_UCS(0x2424, 9); /* symbol for newline */ 2224 MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 2225 MY_UCS(0x2518, 11); /* box drawings light up and left */ 2226 MY_UCS(0x2510, 12); /* box drawings light down and left */ 2227 MY_UCS(0x250c, 13); /* box drawings light down and right */ 2228 MY_UCS(0x2514, 14); /* box drawings light up and right */ 2229 MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 2230 MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 2231 MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 2232 MY_UCS(0x2500, 18); /* box drawings light horizontal */ 2233 MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 2234 MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 2235 MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 2236 MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 2237 MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 2238 MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 2239 MY_UCS(0x2502, 25); /* box drawings light vertical */ 2240 MY_UCS(0x2264, 26); /* less-than or equal to */ 2241 MY_UCS(0x2265, 27); /* greater-than or equal to */ 2242 MY_UCS(0x03c0, 28); /* greek small letter pi */ 2243 MY_UCS(0x2260, 29); /* not equal to */ 2244 MY_UCS(0x00a3, 30); /* pound sign */ 2245 MY_UCS(0x00b7, 31); /* middle dot */ 2246 } 2247 } 2248 return result; 2249} 2250 2251#undef MY_UCS 2252#define MY_UCS(ucs,dec) case dec: result = ucs; break 2253 2254unsigned 2255dec2ucs(unsigned ch) 2256{ 2257 unsigned result = ch; 2258 if (xtermIsDecGraphic(ch)) { 2259 switch (ch) { 2260 MY_UCS(0x25ae, 0); /* black vertical rectangle */ 2261 MY_UCS(0x25c6, 1); /* black diamond */ 2262 MY_UCS(0x2592, 2); /* medium shade */ 2263 MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 2264 MY_UCS(0x240c, 4); /* symbol for form feed */ 2265 MY_UCS(0x240d, 5); /* symbol for carriage return */ 2266 MY_UCS(0x240a, 6); /* symbol for line feed */ 2267 MY_UCS(0x00b0, 7); /* degree sign */ 2268 MY_UCS(0x00b1, 8); /* plus-minus sign */ 2269 MY_UCS(0x2424, 9); /* symbol for newline */ 2270 MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 2271 MY_UCS(0x2518, 11); /* box drawings light up and left */ 2272 MY_UCS(0x2510, 12); /* box drawings light down and left */ 2273 MY_UCS(0x250c, 13); /* box drawings light down and right */ 2274 MY_UCS(0x2514, 14); /* box drawings light up and right */ 2275 MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 2276 MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 2277 MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 2278 MY_UCS(0x2500, 18); /* box drawings light horizontal */ 2279 MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 2280 MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 2281 MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 2282 MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 2283 MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 2284 MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 2285 MY_UCS(0x2502, 25); /* box drawings light vertical */ 2286 MY_UCS(0x2264, 26); /* less-than or equal to */ 2287 MY_UCS(0x2265, 27); /* greater-than or equal to */ 2288 MY_UCS(0x03c0, 28); /* greek small letter pi */ 2289 MY_UCS(0x2260, 29); /* not equal to */ 2290 MY_UCS(0x00a3, 30); /* pound sign */ 2291 MY_UCS(0x00b7, 31); /* middle dot */ 2292 } 2293 } 2294 return result; 2295} 2296 2297#endif /* OPT_WIDE_CHARS */ 2298 2299#if OPT_SHIFT_FONTS 2300static void 2301lookupOneFontSize(XtermWidget xw, int fontnum) 2302{ 2303 TScreen *screen = TScreenOf(xw); 2304 2305 if (screen->menu_font_sizes[fontnum] == 0) { 2306 XTermFonts fnt; 2307 2308 memset(&fnt, 0, sizeof(fnt)); 2309 screen->menu_font_sizes[fontnum] = -1; 2310 if (xtermOpenFont(xw, screen->MenuFontName(fontnum), &fnt)) { 2311 screen->menu_font_sizes[fontnum] = FontSize(fnt.fs); 2312 TRACE(("menu_font_sizes[%d] = %ld\n", fontnum, 2313 screen->menu_font_sizes[fontnum])); 2314 xtermCloseFont(xw, &fnt); 2315 } 2316 } 2317} 2318 2319/* 2320 * Cache the font-sizes so subsequent larger/smaller font actions will go fast. 2321 */ 2322static void 2323lookupFontSizes(XtermWidget xw) 2324{ 2325 int n; 2326 2327 for (n = 0; n < NMENUFONTS; n++) { 2328 lookupOneFontSize(xw, n); 2329 } 2330} 2331 2332#if OPT_RENDERFONT 2333#define NMENU_RENDERFONTS (NMENUFONTS - 2) /* no selection or escape */ 2334static Boolean 2335useFaceSizes(XtermWidget xw) 2336{ 2337 Boolean result = False; 2338 int n; 2339 2340 if (UsingRenderFont(xw)) { 2341 result = True; 2342 for (n = 0; n < NMENU_RENDERFONTS; ++n) { 2343 if (xw->misc.face_size[n] <= 0.0) { 2344 result = False; 2345 break; 2346 } 2347 } 2348 } 2349 return result; 2350} 2351#endif 2352 2353/* 2354 * Find the index of a larger/smaller font (according to the sign of 'relative' 2355 * and its magnitude), starting from the 'old' index. 2356 */ 2357int 2358lookupRelativeFontSize(XtermWidget xw, int old, int relative) 2359{ 2360 TScreen *screen = TScreenOf(xw); 2361 int n, m = -1; 2362 2363 TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative)); 2364 if (!IsIcon(screen)) { 2365#if OPT_RENDERFONT 2366 if (useFaceSizes(xw)) { 2367 TRACE(("...using FaceSize\n")); 2368 if (relative != 0) { 2369 for (n = 0; n < NMENU_RENDERFONTS; ++n) { 2370 if (xw->misc.face_size[n] > 0 && 2371 xw->misc.face_size[n] != xw->misc.face_size[old]) { 2372 int cmp_0 = ((xw->misc.face_size[n] > 2373 xw->misc.face_size[old]) 2374 ? relative 2375 : -relative); 2376 int cmp_m = ((m < 0) 2377 ? 1 2378 : ((xw->misc.face_size[n] < 2379 xw->misc.face_size[m]) 2380 ? relative 2381 : -relative)); 2382 if (cmp_0 > 0 && cmp_m > 0) { 2383 m = n; 2384 } 2385 } 2386 } 2387 } 2388 } else 2389#endif 2390 { 2391 TRACE(("...using bitmap areas\n")); 2392 lookupFontSizes(xw); 2393 if (relative != 0) { 2394 for (n = 0; n < NMENUFONTS; ++n) { 2395 if (screen->menu_font_sizes[n] > 0 && 2396 screen->menu_font_sizes[n] != 2397 screen->menu_font_sizes[old]) { 2398 int cmp_0 = ((screen->menu_font_sizes[n] > 2399 screen->menu_font_sizes[old]) 2400 ? relative 2401 : -relative); 2402 int cmp_m = ((m < 0) 2403 ? 1 2404 : ((screen->menu_font_sizes[n] < 2405 screen->menu_font_sizes[m]) 2406 ? relative 2407 : -relative)); 2408 if (cmp_0 > 0 && cmp_m > 0) { 2409 m = n; 2410 } 2411 } 2412 } 2413 } 2414 } 2415 TRACE(("...new index %d\n", m)); 2416 if (m >= 0) { 2417 if (relative > 1) 2418 m = lookupRelativeFontSize(xw, m, relative - 1); 2419 else if (relative < -1) 2420 m = lookupRelativeFontSize(xw, m, relative + 1); 2421 } 2422 } 2423 return m; 2424} 2425 2426/* ARGSUSED */ 2427void 2428HandleLargerFont(Widget w GCC_UNUSED, 2429 XEvent * event GCC_UNUSED, 2430 String * params GCC_UNUSED, 2431 Cardinal *param_count GCC_UNUSED) 2432{ 2433 if (IsXtermWidget(w)) { 2434 XtermWidget xw = (XtermWidget) w; 2435 2436 if (xw->misc.shift_fonts) { 2437 TScreen *screen = &xw->screen; 2438 int m; 2439 2440 m = lookupRelativeFontSize(xw, screen->menu_font_number, 1); 2441 if (m >= 0) { 2442 SetVTFont(xw, m, True, NULL); 2443 } else { 2444 Bell(XkbBI_MinorError, 0); 2445 } 2446 } 2447 } 2448} 2449 2450/* ARGSUSED */ 2451void 2452HandleSmallerFont(Widget w GCC_UNUSED, 2453 XEvent * event GCC_UNUSED, 2454 String * params GCC_UNUSED, 2455 Cardinal *param_count GCC_UNUSED) 2456{ 2457 if (IsXtermWidget(w)) { 2458 XtermWidget xw = (XtermWidget) w; 2459 2460 if (xw->misc.shift_fonts) { 2461 TScreen *screen = &xw->screen; 2462 int m; 2463 2464 m = lookupRelativeFontSize(xw, screen->menu_font_number, -1); 2465 if (m >= 0) { 2466 SetVTFont(xw, m, True, NULL); 2467 } else { 2468 Bell(XkbBI_MinorError, 0); 2469 } 2470 } 2471 } 2472} 2473#endif 2474 2475int 2476xtermGetFont(const char *param) 2477{ 2478 int fontnum; 2479 2480 switch (param[0]) { 2481 case 'd': 2482 case 'D': 2483 case '0': 2484 fontnum = fontMenu_default; 2485 break; 2486 case '1': 2487 fontnum = fontMenu_font1; 2488 break; 2489 case '2': 2490 fontnum = fontMenu_font2; 2491 break; 2492 case '3': 2493 fontnum = fontMenu_font3; 2494 break; 2495 case '4': 2496 fontnum = fontMenu_font4; 2497 break; 2498 case '5': 2499 fontnum = fontMenu_font5; 2500 break; 2501 case '6': 2502 fontnum = fontMenu_font6; 2503 break; 2504 case 'e': 2505 case 'E': 2506 fontnum = fontMenu_fontescape; 2507 break; 2508 case 's': 2509 case 'S': 2510 fontnum = fontMenu_fontsel; 2511 break; 2512 default: 2513 fontnum = -1; 2514 break; 2515 } 2516 return fontnum; 2517} 2518 2519/* ARGSUSED */ 2520void 2521HandleSetFont(Widget w GCC_UNUSED, 2522 XEvent * event GCC_UNUSED, 2523 String * params, 2524 Cardinal *param_count) 2525{ 2526 if (IsXtermWidget(w)) { 2527 int fontnum; 2528 VTFontNames fonts; 2529 2530 memset(&fonts, 0, sizeof(fonts)); 2531 2532 if (*param_count == 0) { 2533 fontnum = fontMenu_default; 2534 } else { 2535 Cardinal maxparams = 1; /* total number of params allowed */ 2536 int result = xtermGetFont(params[0]); 2537 2538 switch (result) { 2539 case fontMenu_default: /* FALLTHRU */ 2540 case fontMenu_font1: /* FALLTHRU */ 2541 case fontMenu_font2: /* FALLTHRU */ 2542 case fontMenu_font3: /* FALLTHRU */ 2543 case fontMenu_font4: /* FALLTHRU */ 2544 case fontMenu_font5: /* FALLTHRU */ 2545 case fontMenu_font6: /* FALLTHRU */ 2546 break; 2547 case fontMenu_fontescape: 2548#if OPT_WIDE_CHARS 2549 maxparams = 5; 2550#else 2551 maxparams = 3; 2552#endif 2553 break; 2554 case fontMenu_fontsel: 2555 maxparams = 2; 2556 break; 2557 default: 2558 Bell(XkbBI_MinorError, 0); 2559 return; 2560 } 2561 fontnum = result; 2562 2563 if (*param_count > maxparams) { /* see if extra args given */ 2564 Bell(XkbBI_MinorError, 0); 2565 return; 2566 } 2567 switch (*param_count) { /* assign 'em */ 2568#if OPT_WIDE_CHARS 2569 case 5: 2570 fonts.f_wb = params[4]; 2571 /* FALLTHRU */ 2572 case 4: 2573 fonts.f_w = params[3]; 2574 /* FALLTHRU */ 2575#endif 2576 case 3: 2577 fonts.f_b = params[2]; 2578 /* FALLTHRU */ 2579 case 2: 2580 fonts.f_n = params[1]; 2581 break; 2582 } 2583 } 2584 2585 SetVTFont((XtermWidget) w, fontnum, True, &fonts); 2586 } 2587} 2588 2589void 2590SetVTFont(XtermWidget xw, 2591 int which, 2592 Bool doresize, 2593 const VTFontNames * fonts) 2594{ 2595 TScreen *screen = &xw->screen; 2596 2597 TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which, 2598 (fonts && fonts->f_n) ? fonts->f_n : "<null>", 2599 (fonts && fonts->f_b) ? fonts->f_b : "<null>")); 2600 2601 if (IsIcon(screen)) { 2602 Bell(XkbBI_MinorError, 0); 2603 } else if (which >= 0 && which < NMENUFONTS) { 2604 VTFontNames myfonts; 2605 2606 memset(&myfonts, 0, sizeof(myfonts)); 2607 if (fonts != 0) 2608 myfonts = *fonts; 2609 2610 if (which == fontMenu_fontsel) { /* go get the selection */ 2611 FindFontSelection(xw, myfonts.f_n, False); 2612 return; 2613 } else { 2614 int oldFont = screen->menu_font_number; 2615 2616#define USE_CACHED(field, name) \ 2617 if (myfonts.field == 0) { \ 2618 myfonts.field = screen->menu_font_names[which][name]; \ 2619 TRACE(("set myfonts." #field " from menu_font_names[%d][" #name "] %s\n", \ 2620 which, NonNull(myfonts.field))); \ 2621 } else { \ 2622 TRACE(("set myfonts." #field " reused\n")); \ 2623 } 2624 USE_CACHED(f_n, fNorm); 2625 USE_CACHED(f_b, fBold); 2626#if OPT_WIDE_CHARS 2627 USE_CACHED(f_w, fWide); 2628 USE_CACHED(f_wb, fWBold); 2629#endif 2630 if (xtermLoadFont(xw, 2631 &myfonts, 2632 doresize, which)) { 2633 return; 2634 } else { 2635 xtermLoadFont(xw, 2636 xtermFontName(screen->MenuFontName(oldFont)), 2637 doresize, oldFont); 2638 } 2639 } 2640 } 2641 2642 Bell(XkbBI_MinorError, 0); 2643 return; 2644} 2645