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