fontutils.c revision fa3f02f3
1fa3f02f3Smrg/* $XTermId: fontutils.c,v 1.400 2013/12/09 12:20:31 tom Exp $ */ 2d522f475Smrg 30bd37d32Smrg/* 4fa3f02f3Smrg * Copyright 1998-2012,2013 by Thomas E. Dickey 50bd37d32Smrg * 60bd37d32Smrg * All Rights Reserved 70bd37d32Smrg * 80bd37d32Smrg * Permission is hereby granted, free of charge, to any person obtaining a 90bd37d32Smrg * copy of this software and associated documentation files (the 100bd37d32Smrg * "Software"), to deal in the Software without restriction, including 110bd37d32Smrg * without limitation the rights to use, copy, modify, merge, publish, 120bd37d32Smrg * distribute, sublicense, and/or sell copies of the Software, and to 130bd37d32Smrg * permit persons to whom the Software is furnished to do so, subject to 140bd37d32Smrg * the following conditions: 150bd37d32Smrg * 160bd37d32Smrg * The above copyright notice and this permission notice shall be included 170bd37d32Smrg * in all copies or substantial portions of the Software. 180bd37d32Smrg * 190bd37d32Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 200bd37d32Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 210bd37d32Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 220bd37d32Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 230bd37d32Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 240bd37d32Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 250bd37d32Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 260bd37d32Smrg * 270bd37d32Smrg * Except as contained in this notice, the name(s) of the above copyright 280bd37d32Smrg * holders shall not be used in advertising or otherwise to promote the 290bd37d32Smrg * sale, use or other dealings in this Software without prior written 300bd37d32Smrg * authorization. 310bd37d32Smrg */ 32d522f475Smrg 33d522f475Smrg/* 34d522f475Smrg * A portion of this module (for FontNameProperties) was adapted from EMU 1.3; 35d522f475Smrg * it constructs font names with specific properties changed, e.g., for bold 36d522f475Smrg * and double-size characters. 37d522f475Smrg */ 38d522f475Smrg 39d522f475Smrg#define RES_OFFSET(field) XtOffsetOf(SubResourceRec, field) 40d522f475Smrg 41d522f475Smrg#include <fontutils.h> 42d522f475Smrg#include <X11/Xmu/Drawing.h> 4320d2c4d2Smrg#include <X11/Xmu/CharSet.h> 44d522f475Smrg 45d522f475Smrg#include <main.h> 46d522f475Smrg#include <data.h> 47d522f475Smrg#include <menu.h> 48d522f475Smrg#include <xstrings.h> 49d522f475Smrg#include <xterm.h> 50d522f475Smrg 51d522f475Smrg#include <stdio.h> 52d522f475Smrg#include <ctype.h> 53d522f475Smrg 540bd37d32Smrg#define SetFontWidth(screen,dst,src) (dst)->f_width = (src) 550bd37d32Smrg#define SetFontHeight(screen,dst,src) (dst)->f_height = dimRound((screen)->scale_height * (float) (src)) 560bd37d32Smrg 57d522f475Smrg/* from X11/Xlibint.h - not all vendors install this file */ 58d522f475Smrg#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \ 59d522f475Smrg (((cs)->rbearing|(cs)->lbearing| \ 60d522f475Smrg (cs)->ascent|(cs)->descent) == 0)) 61d522f475Smrg 62fa3f02f3Smrg#define CI_GET_CHAR_INFO_1D(fs,col,cs) \ 63d522f475Smrg{ \ 64fa3f02f3Smrg cs = 0; \ 65d522f475Smrg if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \ 66d522f475Smrg if (fs->per_char == NULL) { \ 67d522f475Smrg cs = &fs->min_bounds; \ 68d522f475Smrg } else { \ 69d522f475Smrg cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \ 70d522f475Smrg } \ 71fa3f02f3Smrg if (CI_NONEXISTCHAR(cs)) cs = 0; \ 72d522f475Smrg } \ 73d522f475Smrg} 74d522f475Smrg 75fa3f02f3Smrg#define CI_GET_CHAR_INFO_2D(fs,row,col,cs) \ 76d522f475Smrg{ \ 77fa3f02f3Smrg cs = 0; \ 78d522f475Smrg if (row >= fs->min_byte1 && row <= fs->max_byte1 && \ 79d522f475Smrg col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \ 80d522f475Smrg if (fs->per_char == NULL) { \ 81d522f475Smrg cs = &fs->min_bounds; \ 82d522f475Smrg } else { \ 83d522f475Smrg cs = &fs->per_char[((row - fs->min_byte1) * \ 84d522f475Smrg (fs->max_char_or_byte2 - \ 85d522f475Smrg fs->min_char_or_byte2 + 1)) + \ 86d522f475Smrg (col - fs->min_char_or_byte2)]; \ 87d522f475Smrg } \ 88fa3f02f3Smrg if (CI_NONEXISTCHAR(cs)) cs = 0; \ 89d522f475Smrg } \ 90d522f475Smrg} 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 1170bd37d32Smrg#if OPT_RENDERFONT 1180bd37d32Smrgstatic void fillInFaceSize(XtermWidget, int); 1190bd37d32Smrg#endif 1200bd37d32Smrg 121d522f475Smrg#if OPT_SHIFT_FONTS 1220bd37d32Smrgstatic int lookupOneFontSize(XtermWidget, int); 123d522f475Smrg#endif 124d522f475Smrg 125fa3f02f3Smrg#if OPT_REPORT_FONTS || OPT_WIDE_CHARS 1262eaa94a1Schristosstatic unsigned 127d522f475SmrgcountGlyphs(XFontStruct * fp) 128d522f475Smrg{ 129d522f475Smrg unsigned count = 0; 130d522f475Smrg 131d522f475Smrg if (fp != 0) { 132d522f475Smrg if (fp->min_byte1 == 0 && fp->max_byte1 == 0) { 133fa3f02f3Smrg count = fp->max_char_or_byte2 - fp->min_char_or_byte2 + 1; 134d522f475Smrg } else if (fp->min_char_or_byte2 < 256 135d522f475Smrg && fp->max_char_or_byte2 < 256) { 136d522f475Smrg unsigned first = (fp->min_byte1 << 8) + fp->min_char_or_byte2; 137d522f475Smrg unsigned last = (fp->max_byte1 << 8) + fp->max_char_or_byte2; 138d522f475Smrg count = last + 1 - first; 139d522f475Smrg } 140d522f475Smrg } 141d522f475Smrg return count; 142d522f475Smrg} 143fa3f02f3Smrg#endif 144d522f475Smrg 145fa3f02f3Smrg#if OPT_WIDE_CHARS 146d522f475Smrg/* 147d522f475Smrg * Verify that the wide-bold font is at least a bold font with roughly as many 148d522f475Smrg * glyphs as the wide font. The counts should be the same, but settle for 149d522f475Smrg * filtering out the worst of the font mismatches. 150d522f475Smrg */ 151d522f475Smrgstatic Bool 152d522f475SmrgcompatibleWideCounts(XFontStruct * wfs, XFontStruct * wbfs) 153d522f475Smrg{ 154d522f475Smrg unsigned count_w = countGlyphs(wfs); 155d522f475Smrg unsigned count_wb = countGlyphs(wbfs); 156d522f475Smrg if (count_w <= 256 || 157d522f475Smrg count_wb <= 256 || 158d522f475Smrg ((count_w / 4) * 3) > count_wb) { 159d522f475Smrg TRACE(("...font server lied (count wide %u vs wide-bold %u)\n", 160d522f475Smrg count_w, count_wb)); 161d522f475Smrg return False; 162d522f475Smrg } 163d522f475Smrg return True; 164d522f475Smrg} 165d522f475Smrg#endif /* OPT_WIDE_CHARS */ 166d522f475Smrg 16720d2c4d2Smrg#if OPT_BOX_CHARS 16820d2c4d2Smrgstatic void 16920d2c4d2SmrgsetupPackedFonts(XtermWidget xw) 17020d2c4d2Smrg{ 17120d2c4d2Smrg TScreen *screen = TScreenOf(xw); 17220d2c4d2Smrg Bool value = False; 17320d2c4d2Smrg 17420d2c4d2Smrg#if OPT_RENDERFONT 17520d2c4d2Smrg#define MIXED(name) screen->name[fontnum].map.mixed 1760bd37d32Smrg if (xw->work.render_font == True) { 17720d2c4d2Smrg int fontnum = screen->menu_font_number; 17820d2c4d2Smrg 17920d2c4d2Smrg screen->allow_packing = (Boolean) (MIXED(renderFontNorm) 18020d2c4d2Smrg || MIXED(renderFontBold) 18120d2c4d2Smrg || MIXED(renderFontItal) 18220d2c4d2Smrg#if OPT_RENDERWIDE 18320d2c4d2Smrg || MIXED(renderWideNorm) 18420d2c4d2Smrg || MIXED(renderWideBold) 18520d2c4d2Smrg || MIXED(renderWideItal) 18620d2c4d2Smrg#endif 18720d2c4d2Smrg ); 18820d2c4d2Smrg#undef MIXED 18920d2c4d2Smrg } 19020d2c4d2Smrg#endif /* OPT_RENDERFONT */ 19120d2c4d2Smrg 19220d2c4d2Smrg value = screen->allow_packing; 19320d2c4d2Smrg 19420d2c4d2Smrg SetItemSensitivity(fontMenuEntries[fontMenu_font_packedfont].widget, value); 19520d2c4d2Smrg} 19620d2c4d2Smrg#endif 19720d2c4d2Smrg 198d522f475Smrg/* 199d522f475Smrg * Returns the fields from start to stop in a dash- separated string. This 200d522f475Smrg * function will modify the source, putting '\0's in the appropiate place and 201d522f475Smrg * moving the beginning forward to after the '\0' 202d522f475Smrg * 203d522f475Smrg * This will NOT work for the last field (but we won't need it). 204d522f475Smrg */ 205d522f475Smrgstatic char * 206d522f475Smrgn_fields(char **source, int start, int stop) 207d522f475Smrg{ 208d522f475Smrg int i; 209d522f475Smrg char *str, *str1; 210d522f475Smrg 211d522f475Smrg /* 212d522f475Smrg * find the start-1th dash 213d522f475Smrg */ 214d522f475Smrg for (i = start - 1, str = *source; i; i--, str++) 215d522f475Smrg if ((str = strchr(str, '-')) == 0) 216d522f475Smrg return 0; 217d522f475Smrg 218d522f475Smrg /* 219d522f475Smrg * find the stopth dash 220d522f475Smrg */ 221d522f475Smrg for (i = stop - start + 1, str1 = str; i; i--, str1++) 222d522f475Smrg if ((str1 = strchr(str1, '-')) == 0) 223d522f475Smrg return 0; 224d522f475Smrg 225d522f475Smrg /* 226d522f475Smrg * put a \0 at the end of the fields 227d522f475Smrg */ 228d522f475Smrg *(str1 - 1) = '\0'; 229d522f475Smrg 230d522f475Smrg /* 231d522f475Smrg * move source forward 232d522f475Smrg */ 233d522f475Smrg *source = str1; 234d522f475Smrg 235d522f475Smrg return str; 236d522f475Smrg} 237d522f475Smrg 238956cc18dSsnjstatic Boolean 239956cc18dSsnjcheck_fontname(const char *name) 240956cc18dSsnj{ 241956cc18dSsnj Boolean result = True; 242956cc18dSsnj 243492d43a5Smrg if (IsEmpty(name)) { 244956cc18dSsnj TRACE(("fontname missing\n")); 245956cc18dSsnj result = False; 246956cc18dSsnj } 247956cc18dSsnj return result; 248956cc18dSsnj} 249956cc18dSsnj 250d522f475Smrg/* 251d522f475Smrg * Gets the font properties from a given font structure. We use the FONT name 252d522f475Smrg * to find them out, since that seems easier. 253d522f475Smrg * 254d522f475Smrg * Returns a pointer to a static FontNameProperties structure 255d522f475Smrg * or NULL on error. 256d522f475Smrg */ 257d522f475Smrgstatic FontNameProperties * 258fa3f02f3Smrgget_font_name_props(Display *dpy, XFontStruct * fs, char **result) 259d522f475Smrg{ 260d522f475Smrg static FontNameProperties props; 261d522f475Smrg static char *last_name; 262d522f475Smrg 263d522f475Smrg XFontProp *fp; 264d522f475Smrg int i; 265d522f475Smrg Atom fontatom = XInternAtom(dpy, "FONT", False); 26620d2c4d2Smrg char *name = 0; 267d522f475Smrg char *str; 268d522f475Smrg 269d522f475Smrg /* 270d522f475Smrg * first get the full font name 271d522f475Smrg */ 27220d2c4d2Smrg if (fontatom != 0) { 27320d2c4d2Smrg for (i = 0, fp = fs->properties; i < fs->n_properties; i++, fp++) { 27420d2c4d2Smrg if (fp->name == fontatom) { 27520d2c4d2Smrg name = XGetAtomName(dpy, fp->card32); 27620d2c4d2Smrg break; 27720d2c4d2Smrg } 27820d2c4d2Smrg } 27920d2c4d2Smrg } 280d522f475Smrg 281d522f475Smrg if (name == 0) 282d522f475Smrg return 0; 283d522f475Smrg 284d522f475Smrg /* 285d522f475Smrg * XGetAtomName allocates memory - don't leak 286d522f475Smrg */ 287d522f475Smrg if (last_name != 0) 288d522f475Smrg XFree(last_name); 289d522f475Smrg last_name = name; 290d522f475Smrg 291d522f475Smrg if (result != 0) { 292956cc18dSsnj if (!check_fontname(name)) 293d522f475Smrg return 0; 2940bd37d32Smrg if (*result != 0) 2950bd37d32Smrg free(*result); 2960bd37d32Smrg *result = x_strdup(name); 297d522f475Smrg } 298d522f475Smrg 299d522f475Smrg /* 300d522f475Smrg * Now split it up into parts and put them in 301d522f475Smrg * their places. Since we are using parts of 302d522f475Smrg * the original string, we must not free the Atom Name 303d522f475Smrg */ 304d522f475Smrg 305d522f475Smrg /* registry, foundry, family */ 306d522f475Smrg if ((props.beginning = n_fields(&name, 1, 3)) == 0) 307d522f475Smrg return 0; 308d522f475Smrg 309d522f475Smrg /* weight is the next */ 310d522f475Smrg if ((props.weight = n_fields(&name, 1, 1)) == 0) 311d522f475Smrg return 0; 312d522f475Smrg 313d522f475Smrg /* slant */ 314d522f475Smrg if ((props.slant = n_fields(&name, 1, 1)) == 0) 315d522f475Smrg return 0; 316d522f475Smrg 317d522f475Smrg /* width */ 318d522f475Smrg if ((props.wideness = n_fields(&name, 1, 1)) == 0) 319d522f475Smrg return 0; 320d522f475Smrg 321d522f475Smrg /* add style */ 322d522f475Smrg if ((props.add_style = n_fields(&name, 1, 1)) == 0) 323d522f475Smrg return 0; 324d522f475Smrg 325d522f475Smrg /* pixel size */ 326d522f475Smrg if ((str = n_fields(&name, 1, 1)) == 0) 327d522f475Smrg return 0; 328d522f475Smrg if ((props.pixel_size = atoi(str)) == 0) 329d522f475Smrg return 0; 330d522f475Smrg 331d522f475Smrg /* point size */ 332d522f475Smrg if ((props.point_size = n_fields(&name, 1, 1)) == 0) 333d522f475Smrg return 0; 334d522f475Smrg 335d522f475Smrg /* res_x */ 336d522f475Smrg if ((str = n_fields(&name, 1, 1)) == 0) 337d522f475Smrg return 0; 338d522f475Smrg if ((props.res_x = atoi(str)) == 0) 339d522f475Smrg return 0; 340d522f475Smrg 341d522f475Smrg /* res_y */ 342d522f475Smrg if ((str = n_fields(&name, 1, 1)) == 0) 343d522f475Smrg return 0; 344d522f475Smrg if ((props.res_y = atoi(str)) == 0) 345d522f475Smrg return 0; 346d522f475Smrg 347d522f475Smrg /* spacing */ 348d522f475Smrg if ((props.spacing = n_fields(&name, 1, 1)) == 0) 349d522f475Smrg return 0; 350d522f475Smrg 351d522f475Smrg /* average width */ 352d522f475Smrg if ((str = n_fields(&name, 1, 1)) == 0) 353d522f475Smrg return 0; 354d522f475Smrg if ((props.average_width = atoi(str)) == 0) 355d522f475Smrg return 0; 356d522f475Smrg 357d522f475Smrg /* the rest: charset registry and charset encoding */ 358d522f475Smrg props.end = name; 359d522f475Smrg 360d522f475Smrg return &props; 361d522f475Smrg} 362d522f475Smrg 363d522f475Smrg#define ALLOCHUNK(n) ((n | 127) + 1) 364d522f475Smrg 365d522f475Smrgstatic void 366956cc18dSsnjalloca_fontname(char **result, size_t next) 367d522f475Smrg{ 368956cc18dSsnj size_t last = (*result != 0) ? strlen(*result) : 0; 369956cc18dSsnj size_t have = (*result != 0) ? ALLOCHUNK(last) : 0; 370956cc18dSsnj size_t want = last + next + 2; 371d522f475Smrg 372d522f475Smrg if (want >= have) { 373d522f475Smrg want = ALLOCHUNK(want); 374d522f475Smrg if (last != 0) { 375d522f475Smrg *result = TypeRealloc(char, want, *result); 376d522f475Smrg } else { 377d522f475Smrg if ((*result = TypeMallocN(char, want)) != 0) 378d522f475Smrg **result = '\0'; 379d522f475Smrg } 380d522f475Smrg } 381d522f475Smrg} 382d522f475Smrg 383d522f475Smrgstatic void 38420d2c4d2Smrgappend_fontname_str(char **result, const char *value) 385d522f475Smrg{ 386d522f475Smrg if (value == 0) 387d522f475Smrg value = "*"; 388d522f475Smrg alloca_fontname(result, strlen(value)); 389d522f475Smrg if (*result != 0) { 390d522f475Smrg if (**result != '\0') 391d522f475Smrg strcat(*result, "-"); 392d522f475Smrg strcat(*result, value); 393d522f475Smrg } 394d522f475Smrg} 395d522f475Smrg 396d522f475Smrgstatic void 397d522f475Smrgappend_fontname_num(char **result, int value) 398d522f475Smrg{ 399d522f475Smrg if (value < 0) { 400d522f475Smrg append_fontname_str(result, "*"); 401d522f475Smrg } else { 402d522f475Smrg char temp[100]; 403d522f475Smrg sprintf(temp, "%d", value); 404d522f475Smrg append_fontname_str(result, temp); 405d522f475Smrg } 406d522f475Smrg} 407d522f475Smrg 408d522f475Smrg/* 409d522f475Smrg * Take the given font props and try to make a well formed font name specifying 410d522f475Smrg * the same base font and size and everything, but with different weight/width 411d522f475Smrg * according to the parameters. The return value is allocated, should be freed 412d522f475Smrg * by the caller. 413d522f475Smrg */ 414d522f475Smrgstatic char * 415d522f475Smrgderive_font_name(FontNameProperties * props, 41620d2c4d2Smrg const char *use_weight, 417d522f475Smrg int use_average_width, 41820d2c4d2Smrg const char *use_encoding) 419d522f475Smrg{ 420d522f475Smrg char *result = 0; 421d522f475Smrg 422d522f475Smrg append_fontname_str(&result, props->beginning); 423d522f475Smrg append_fontname_str(&result, use_weight); 424d522f475Smrg append_fontname_str(&result, props->slant); 425d522f475Smrg append_fontname_str(&result, 0); 426d522f475Smrg append_fontname_str(&result, 0); 427d522f475Smrg append_fontname_num(&result, props->pixel_size); 428d522f475Smrg append_fontname_str(&result, props->point_size); 429d522f475Smrg append_fontname_num(&result, props->res_x); 430d522f475Smrg append_fontname_num(&result, props->res_y); 431d522f475Smrg append_fontname_str(&result, props->spacing); 432d522f475Smrg append_fontname_num(&result, use_average_width); 433d522f475Smrg append_fontname_str(&result, use_encoding); 434d522f475Smrg 435d522f475Smrg return result; 436d522f475Smrg} 437d522f475Smrg 438d522f475Smrgstatic char * 439d522f475Smrgbold_font_name(FontNameProperties * props, int use_average_width) 440d522f475Smrg{ 441d522f475Smrg return derive_font_name(props, "bold", use_average_width, props->end); 442d522f475Smrg} 443d522f475Smrg 444d522f475Smrg#if OPT_WIDE_CHARS 445d522f475Smrg#define derive_wide_font(props, weight) \ 446d522f475Smrg derive_font_name(props, weight, props->average_width * 2, "ISO10646-1") 447d522f475Smrg 448d522f475Smrgstatic char * 449d522f475Smrgwide_font_name(FontNameProperties * props) 450d522f475Smrg{ 451d522f475Smrg return derive_wide_font(props, "medium"); 452d522f475Smrg} 453d522f475Smrg 454d522f475Smrgstatic char * 455d522f475Smrgwidebold_font_name(FontNameProperties * props) 456d522f475Smrg{ 457d522f475Smrg return derive_wide_font(props, "bold"); 458d522f475Smrg} 459d522f475Smrg#endif /* OPT_WIDE_CHARS */ 460d522f475Smrg 461d522f475Smrg#if OPT_DEC_CHRSET 462d522f475Smrg/* 463d522f475Smrg * Take the given font props and try to make a well formed font name specifying 464d522f475Smrg * the same base font but changed depending on the given attributes and chrset. 465d522f475Smrg * 466d522f475Smrg * For double width fonts, we just double the X-resolution, for double height 467d522f475Smrg * fonts we double the pixel-size and Y-resolution 468d522f475Smrg */ 469d522f475Smrgchar * 470fa3f02f3SmrgxtermSpecialFont(TScreen *screen, unsigned atts, unsigned chrset) 471d522f475Smrg{ 472d522f475Smrg#if OPT_TRACE 473d522f475Smrg static char old_spacing[80]; 474d522f475Smrg static FontNameProperties old_props; 475d522f475Smrg#endif 476d522f475Smrg FontNameProperties *props; 477d522f475Smrg char *result = 0; 47820d2c4d2Smrg const char *weight; 479d522f475Smrg int pixel_size; 480d522f475Smrg int res_x; 481d522f475Smrg int res_y; 482d522f475Smrg 483d522f475Smrg props = get_font_name_props(screen->display, screen->fnts[fNorm].fs, 0); 484d522f475Smrg if (props == 0) 485d522f475Smrg return result; 486d522f475Smrg 487d522f475Smrg pixel_size = props->pixel_size; 488d522f475Smrg res_x = props->res_x; 489d522f475Smrg res_y = props->res_y; 490d522f475Smrg if (atts & BOLD) 491d522f475Smrg weight = "bold"; 492d522f475Smrg else 493d522f475Smrg weight = props->weight; 494d522f475Smrg 495d522f475Smrg if (CSET_DOUBLE(chrset)) 496d522f475Smrg res_x *= 2; 497d522f475Smrg 498d522f475Smrg if (chrset == CSET_DHL_TOP 499d522f475Smrg || chrset == CSET_DHL_BOT) { 500d522f475Smrg res_y *= 2; 501d522f475Smrg pixel_size *= 2; 502d522f475Smrg } 503d522f475Smrg#if OPT_TRACE 504d522f475Smrg if (old_props.res_x != res_x 505d522f475Smrg || old_props.res_x != res_y 506d522f475Smrg || old_props.pixel_size != pixel_size 507d522f475Smrg || strcmp(old_props.spacing, props->spacing)) { 508d522f475Smrg TRACE(("xtermSpecialFont(atts = %#x, chrset = %#x)\n", atts, chrset)); 509d522f475Smrg TRACE(("res_x = %d\n", res_x)); 510d522f475Smrg TRACE(("res_y = %d\n", res_y)); 511d522f475Smrg TRACE(("point_size = %s\n", props->point_size)); 512d522f475Smrg TRACE(("pixel_size = %d\n", pixel_size)); 513d522f475Smrg TRACE(("spacing = %s\n", props->spacing)); 514d522f475Smrg old_props.res_x = res_x; 515d522f475Smrg old_props.res_x = res_y; 516d522f475Smrg old_props.pixel_size = pixel_size; 5170bd37d32Smrg old_props.spacing = old_spacing; 5180bd37d32Smrg sprintf(old_spacing, "%.*s", (int) sizeof(old_spacing) - 2, props->spacing); 519d522f475Smrg } 520d522f475Smrg#endif 521d522f475Smrg 522d522f475Smrg append_fontname_str(&result, props->beginning); 523d522f475Smrg append_fontname_str(&result, weight); 524d522f475Smrg append_fontname_str(&result, props->slant); 525d522f475Smrg append_fontname_str(&result, props->wideness); 526d522f475Smrg append_fontname_str(&result, props->add_style); 527d522f475Smrg append_fontname_num(&result, pixel_size); 528d522f475Smrg append_fontname_str(&result, props->point_size); 529d522f475Smrg append_fontname_num(&result, (atts & NORESOLUTION) ? -1 : res_x); 530d522f475Smrg append_fontname_num(&result, (atts & NORESOLUTION) ? -1 : res_y); 531d522f475Smrg append_fontname_str(&result, props->spacing); 532d522f475Smrg append_fontname_str(&result, 0); 533d522f475Smrg append_fontname_str(&result, props->end); 534d522f475Smrg 535d522f475Smrg return result; 536d522f475Smrg} 537d522f475Smrg#endif /* OPT_DEC_CHRSET */ 538d522f475Smrg 539d522f475Smrg/* 540d522f475Smrg * Case-independent comparison for font-names, including wildcards. 541d522f475Smrg * XLFD allows '?' as a wildcard, but we do not handle that (no one seems 542d522f475Smrg * to use it). 543d522f475Smrg */ 544d522f475Smrgstatic Bool 545492d43a5Smrgsame_font_name(const char *pattern, const char *match) 546d522f475Smrg{ 547956cc18dSsnj Bool result = False; 548956cc18dSsnj 549956cc18dSsnj if (pattern && match) { 550956cc18dSsnj while (*pattern && *match) { 551956cc18dSsnj if (*pattern == *match) { 552956cc18dSsnj pattern++; 553956cc18dSsnj match++; 554956cc18dSsnj } else if (*pattern == '*' || *match == '*') { 555956cc18dSsnj if (same_font_name(pattern + 1, match)) { 556956cc18dSsnj return True; 557956cc18dSsnj } else if (same_font_name(pattern, match + 1)) { 558956cc18dSsnj return True; 559956cc18dSsnj } else { 560956cc18dSsnj return False; 561956cc18dSsnj } 562d522f475Smrg } else { 563956cc18dSsnj int p = x_toupper(*pattern++); 564956cc18dSsnj int m = x_toupper(*match++); 565956cc18dSsnj if (p != m) 566956cc18dSsnj return False; 567d522f475Smrg } 568d522f475Smrg } 569956cc18dSsnj result = (*pattern == *match); /* both should be NUL */ 570d522f475Smrg } 571956cc18dSsnj return result; 572d522f475Smrg} 573d522f475Smrg 574d522f475Smrg/* 575d522f475Smrg * Double-check the fontname that we asked for versus what the font server 576d522f475Smrg * actually gave us. The larger fixed fonts do not always have a matching bold 577d522f475Smrg * font, and the font server may try to scale another font or otherwise 578d522f475Smrg * substitute a mismatched font. 579d522f475Smrg * 580d522f475Smrg * If we cannot get what we requested, we will fallback to the original 581d522f475Smrg * behavior, which simulates bold by overstriking each character at one pixel 582d522f475Smrg * offset. 583d522f475Smrg */ 584d522f475Smrgstatic int 585fa3f02f3Smrggot_bold_font(Display *dpy, XFontStruct * fs, String requested) 586d522f475Smrg{ 5870bd37d32Smrg char *actual = 0; 588d522f475Smrg int got; 589d522f475Smrg 5900bd37d32Smrg if (get_font_name_props(dpy, fs, &actual) == 0) 591d522f475Smrg got = 0; 592d522f475Smrg else 593d522f475Smrg got = same_font_name(requested, actual); 5940bd37d32Smrg free(actual); 595d522f475Smrg return got; 596d522f475Smrg} 597d522f475Smrg 598d522f475Smrg/* 599d522f475Smrg * If the font server tries to adjust another font, it may not adjust it 600d522f475Smrg * properly. Check that the bounding boxes are compatible. Otherwise we'll 601d522f475Smrg * leave trash on the display when we mix normal and bold fonts. 602d522f475Smrg */ 603d522f475Smrgstatic int 604d522f475Smrgsame_font_size(XtermWidget xw, XFontStruct * nfs, XFontStruct * bfs) 605d522f475Smrg{ 606956cc18dSsnj TScreen *screen = TScreenOf(xw); 607d522f475Smrg TRACE(("same_font_size height %d/%d, min %d/%d max %d/%d\n", 608d522f475Smrg nfs->ascent + nfs->descent, 609d522f475Smrg bfs->ascent + bfs->descent, 610d522f475Smrg nfs->min_bounds.width, bfs->min_bounds.width, 611d522f475Smrg nfs->max_bounds.width, bfs->max_bounds.width)); 612956cc18dSsnj return screen->free_bold_box 613d522f475Smrg || ((nfs->ascent + nfs->descent) == (bfs->ascent + bfs->descent) 614d522f475Smrg && (nfs->min_bounds.width == bfs->min_bounds.width 615d522f475Smrg || nfs->min_bounds.width == bfs->min_bounds.width + 1) 616d522f475Smrg && (nfs->max_bounds.width == bfs->max_bounds.width 617d522f475Smrg || nfs->max_bounds.width == bfs->max_bounds.width + 1)); 618d522f475Smrg} 619d522f475Smrg 620d522f475Smrg/* 621d522f475Smrg * Check if the font looks like it has fixed width 622d522f475Smrg */ 623d522f475Smrgstatic int 624d522f475Smrgis_fixed_font(XFontStruct * fs) 625d522f475Smrg{ 626d522f475Smrg if (fs) 627d522f475Smrg return (fs->min_bounds.width == fs->max_bounds.width); 628d522f475Smrg return 1; 629d522f475Smrg} 630d522f475Smrg 631d522f475Smrg/* 632d522f475Smrg * Check if the font looks like a double width font (i.e. contains 633d522f475Smrg * characters of width X and 2X 634d522f475Smrg */ 635d522f475Smrg#if OPT_WIDE_CHARS 636d522f475Smrgstatic int 637d522f475Smrgis_double_width_font(XFontStruct * fs) 638d522f475Smrg{ 639d522f475Smrg return ((2 * fs->min_bounds.width) == fs->max_bounds.width); 640d522f475Smrg} 641d522f475Smrg#else 642d522f475Smrg#define is_double_width_font(fs) 0 643d522f475Smrg#endif 644d522f475Smrg 645d522f475Smrg#if OPT_WIDE_CHARS && OPT_RENDERFONT && defined(HAVE_TYPE_FCCHAR32) 646d522f475Smrg#define HALF_WIDTH_TEST_STRING "1234567890" 647d522f475Smrg 648d522f475Smrg/* '1234567890' in Chinese characters in UTF-8 */ 649d522f475Smrg#define FULL_WIDTH_TEST_STRING "\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89" \ 650d522f475Smrg "\xe5\x9b\x9b\xe4\xba\x94" \ 651d522f475Smrg "\xef\xa7\x91\xe4\xb8\x83\xe5\x85\xab" \ 652d522f475Smrg "\xe4\xb9\x9d\xef\xa6\xb2" 653d522f475Smrg 654d522f475Smrg/* '1234567890' in Korean script in UTF-8 */ 655d522f475Smrg#define FULL_WIDTH_TEST_STRING2 "\xec\x9d\xbc\xec\x9d\xb4\xec\x82\xbc" \ 656d522f475Smrg "\xec\x82\xac\xec\x98\xa4" \ 657d522f475Smrg "\xec\x9c\xa1\xec\xb9\xa0\xed\x8c\x94" \ 658d522f475Smrg "\xea\xb5\xac\xec\x98\x81" 659d522f475Smrg 660d522f475Smrg#define HALF_WIDTH_CHAR1 0x0031 /* '1' */ 661d522f475Smrg#define HALF_WIDTH_CHAR2 0x0057 /* 'W' */ 662d522f475Smrg#define FULL_WIDTH_CHAR1 0x4E00 /* CJK Ideograph 'number one' */ 663d522f475Smrg#define FULL_WIDTH_CHAR2 0xAC00 /* Korean script syllable 'Ka' */ 664d522f475Smrg 665d522f475Smrgstatic Bool 666fa3f02f3Smrgis_double_width_font_xft(Display *dpy, XftFont * font) 667d522f475Smrg{ 668d522f475Smrg XGlyphInfo gi1, gi2; 669d522f475Smrg FcChar32 c1 = HALF_WIDTH_CHAR1, c2 = HALF_WIDTH_CHAR2; 6700bd37d32Smrg String fwstr = FULL_WIDTH_TEST_STRING; 6710bd37d32Smrg String hwstr = HALF_WIDTH_TEST_STRING; 672d522f475Smrg 673d522f475Smrg /* Some Korean fonts don't have Chinese characters at all. */ 674d522f475Smrg if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR1)) { 675d522f475Smrg if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR2)) 676d522f475Smrg return False; /* Not a CJK font */ 677d522f475Smrg else /* a Korean font without CJK Ideographs */ 678d522f475Smrg fwstr = FULL_WIDTH_TEST_STRING2; 679d522f475Smrg } 680d522f475Smrg 681d522f475Smrg XftTextExtents32(dpy, font, &c1, 1, &gi1); 682d522f475Smrg XftTextExtents32(dpy, font, &c2, 1, &gi2); 683d522f475Smrg if (gi1.xOff != gi2.xOff) /* Not a fixed-width font */ 684d522f475Smrg return False; 685d522f475Smrg 6860bd37d32Smrg XftTextExtentsUtf8(dpy, 6870bd37d32Smrg font, 6880bd37d32Smrg (_Xconst FcChar8 *) hwstr, 6890bd37d32Smrg (int) strlen(hwstr), 6900bd37d32Smrg &gi1); 6910bd37d32Smrg XftTextExtentsUtf8(dpy, 6920bd37d32Smrg font, 6930bd37d32Smrg (_Xconst FcChar8 *) fwstr, 6940bd37d32Smrg (int) strlen(fwstr), 6950bd37d32Smrg &gi2); 696d522f475Smrg 697d522f475Smrg /* 698d522f475Smrg * fontconfig and Xft prior to 2.2(?) set the width of half-width 699d522f475Smrg * characters identical to that of full-width character in CJK double-width 700d522f475Smrg * (bi-width / monospace) font even though the former is half as wide as 701d522f475Smrg * the latter. This was fixed sometime before the release of fontconfig 702d522f475Smrg * 2.2 in early 2003. See 703d522f475Smrg * http://bugzilla.mozilla.org/show_bug.cgi?id=196312 704d522f475Smrg * In the meantime, we have to check both possibilities. 705d522f475Smrg */ 706d522f475Smrg return ((2 * gi1.xOff == gi2.xOff) || (gi1.xOff == gi2.xOff)); 707d522f475Smrg} 708d522f475Smrg#else 709d522f475Smrg#define is_double_width_font_xft(dpy, xftfont) 0 710d522f475Smrg#endif 711d522f475Smrg 712d522f475Smrg#define EmptyFont(fs) (fs != 0 \ 713d522f475Smrg && ((fs)->ascent + (fs)->descent == 0 \ 714d522f475Smrg || (fs)->max_bounds.width == 0)) 715d522f475Smrg 716d522f475Smrg#define FontSize(fs) (((fs)->ascent + (fs)->descent) \ 717d522f475Smrg * (fs)->max_bounds.width) 718d522f475Smrg 719d522f475Smrgconst VTFontNames * 72020d2c4d2SmrgxtermFontName(const char *normal) 721d522f475Smrg{ 722d522f475Smrg static VTFontNames data; 72320d2c4d2Smrg if (data.f_n) 724492d43a5Smrg free((void *) data.f_n); 725d522f475Smrg memset(&data, 0, sizeof(data)); 72620d2c4d2Smrg data.f_n = x_strdup(normal); 727d522f475Smrg return &data; 728d522f475Smrg} 729d522f475Smrg 730d522f475Smrgstatic void 731fa3f02f3Smrgcache_menu_font_name(TScreen *screen, int fontnum, int which, const char *name) 732d522f475Smrg{ 733d522f475Smrg if (name != 0) { 734492d43a5Smrg char *last = (char *) screen->menu_font_names[fontnum][which]; 735d522f475Smrg if (last != 0) { 736d522f475Smrg if (strcmp(last, name)) { 737d522f475Smrg free(last); 738d522f475Smrg TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name)); 739d522f475Smrg screen->menu_font_names[fontnum][which] = x_strdup(name); 740d522f475Smrg } 741d522f475Smrg } else { 742d522f475Smrg TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name)); 743d522f475Smrg screen->menu_font_names[fontnum][which] = x_strdup(name); 744d522f475Smrg } 745d522f475Smrg } 746d522f475Smrg} 747d522f475Smrg 748d522f475Smrg/* 749d522f475Smrg * Open the given font and verify that it is non-empty. Return a null on 750d522f475Smrg * failure. 751d522f475Smrg */ 752d522f475SmrgBool 753956cc18dSsnjxtermOpenFont(XtermWidget xw, 754956cc18dSsnj const char *name, 755956cc18dSsnj XTermFonts * result, 756956cc18dSsnj fontWarningTypes warn, 757956cc18dSsnj Bool force) 758d522f475Smrg{ 759d522f475Smrg Bool code = False; 760d522f475Smrg TScreen *screen = TScreenOf(xw); 761d522f475Smrg 762492d43a5Smrg if (!IsEmpty(name)) { 763956cc18dSsnj if ((result->fs = XLoadQueryFont(screen->display, name)) != 0) { 764956cc18dSsnj code = True; 765956cc18dSsnj if (EmptyFont(result->fs)) { 76620d2c4d2Smrg (void) xtermCloseFont(xw, result); 767956cc18dSsnj code = False; 768956cc18dSsnj } else { 769956cc18dSsnj result->fn = x_strdup(name); 770956cc18dSsnj } 77120d2c4d2Smrg } else if (XmuCompareISOLatin1(name, DEFFONT) != 0) { 772956cc18dSsnj if (warn <= xw->misc.fontWarnings 773956cc18dSsnj#if OPT_RENDERFONT 774956cc18dSsnj && !UsingRenderFont(xw) 775956cc18dSsnj#endif 776956cc18dSsnj ) { 777956cc18dSsnj TRACE(("OOPS: cannot load font %s\n", name)); 7780bd37d32Smrg xtermWarning("cannot load font '%s'\n", name); 77920d2c4d2Smrg#if OPT_RENDERFONT 78020d2c4d2Smrg /* 78120d2c4d2Smrg * Do a sanity check in case someone's mixed up xterm with 78220d2c4d2Smrg * one of those programs that read their resource data from 78320d2c4d2Smrg * xterm's namespace. 78420d2c4d2Smrg */ 78520d2c4d2Smrg if (strchr(name, ':') != 0 || strchr(name, '=') != 0) { 7860bd37d32Smrg xtermWarning("Use the \"-fa\" option for the Xft fonts\n"); 78720d2c4d2Smrg } 78820d2c4d2Smrg#endif 789956cc18dSsnj } else { 790492d43a5Smrg TRACE(("xtermOpenFont: cannot load font '%s'\n", name)); 791956cc18dSsnj } 792956cc18dSsnj if (force) { 793956cc18dSsnj code = xtermOpenFont(xw, DEFFONT, result, fwAlways, True); 794956cc18dSsnj } 795d522f475Smrg } 796d522f475Smrg } 797d522f475Smrg return code; 798d522f475Smrg} 799d522f475Smrg 800d522f475Smrg/* 801956cc18dSsnj * Close the font and free the font info. 802d522f475Smrg */ 803d522f475SmrgXTermFonts * 804d522f475SmrgxtermCloseFont(XtermWidget xw, XTermFonts * fnt) 805d522f475Smrg{ 806d522f475Smrg if (fnt != 0 && fnt->fs != 0) { 807d522f475Smrg TScreen *screen = TScreenOf(xw); 808d522f475Smrg 809d522f475Smrg clrCgsFonts(xw, WhichVWin(screen), fnt); 810d522f475Smrg XFreeFont(screen->display, fnt->fs); 811d522f475Smrg xtermFreeFontInfo(fnt); 812d522f475Smrg } 813d522f475Smrg return 0; 814d522f475Smrg} 815d522f475Smrg 816d522f475Smrg/* 817d522f475Smrg * Close the listed fonts, noting that some may use copies of the pointer. 818d522f475Smrg */ 819d522f475Smrgvoid 820d522f475SmrgxtermCloseFonts(XtermWidget xw, XTermFonts * fnts) 821d522f475Smrg{ 822d522f475Smrg int j, k; 823d522f475Smrg 824d522f475Smrg for (j = 0; j < fMAX; ++j) { 825d522f475Smrg /* 826d522f475Smrg * Need to save the pointer since xtermCloseFont zeroes it 827d522f475Smrg */ 828d522f475Smrg XFontStruct *thisFont = fnts[j].fs; 829d522f475Smrg if (thisFont != 0) { 830d522f475Smrg xtermCloseFont(xw, &fnts[j]); 831d522f475Smrg for (k = j + 1; k < fMAX; ++k) { 832d522f475Smrg if (thisFont == fnts[k].fs) 833d522f475Smrg xtermFreeFontInfo(&fnts[k]); 834d522f475Smrg } 835d522f475Smrg } 836d522f475Smrg } 837d522f475Smrg} 838d522f475Smrg 839d522f475Smrg/* 840d522f475Smrg * Make a copy of the source, assuming the XFontStruct's to be unique, but 841d522f475Smrg * ensuring that the names are reallocated to simplify freeing. 842d522f475Smrg */ 843d522f475Smrgvoid 844d522f475SmrgxtermCopyFontInfo(XTermFonts * target, XTermFonts * source) 845d522f475Smrg{ 846d522f475Smrg xtermFreeFontInfo(target); 847d522f475Smrg target->chrset = source->chrset; 848d522f475Smrg target->flags = source->flags; 849d522f475Smrg target->fn = x_strdup(source->fn); 850d522f475Smrg target->fs = source->fs; 851d522f475Smrg} 852d522f475Smrg 853d522f475Smrgvoid 854d522f475SmrgxtermFreeFontInfo(XTermFonts * target) 855d522f475Smrg{ 856d522f475Smrg target->chrset = 0; 857d522f475Smrg target->flags = 0; 858d522f475Smrg if (target->fn != 0) { 859d522f475Smrg free(target->fn); 860d522f475Smrg target->fn = 0; 861d522f475Smrg } 862d522f475Smrg target->fs = 0; 863d522f475Smrg} 864d522f475Smrg 865fa3f02f3Smrg#if OPT_REPORT_FONTS 866fa3f02f3Smrgstatic void 867fa3f02f3SmrgreportXCharStruct(const char *tag, XCharStruct * cs) 868fa3f02f3Smrg{ 869fa3f02f3Smrg printf("\t\t%s:\n", tag); 870fa3f02f3Smrg printf("\t\t\tlbearing: %d\n", cs->lbearing); 871fa3f02f3Smrg printf("\t\t\trbearing: %d\n", cs->rbearing); 872fa3f02f3Smrg printf("\t\t\twidth: %d\n", cs->width); 873fa3f02f3Smrg printf("\t\t\tascent: %d\n", cs->ascent); 874fa3f02f3Smrg printf("\t\t\tdescent: %d\n", cs->descent); 875fa3f02f3Smrg} 876fa3f02f3Smrg 877fa3f02f3Smrgstatic void 878fa3f02f3SmrgreportOneVTFont(const char *tag, 879fa3f02f3Smrg XTermFonts * fnt) 880fa3f02f3Smrg{ 881fa3f02f3Smrg if (!IsEmpty(fnt->fn)) { 882fa3f02f3Smrg XFontStruct *fs = fnt->fs; 883fa3f02f3Smrg unsigned missing = 0; 884fa3f02f3Smrg unsigned first_char = 0; 885fa3f02f3Smrg unsigned last_char = 0; 886fa3f02f3Smrg unsigned ch; 887fa3f02f3Smrg 888fa3f02f3Smrg if (fs->max_byte1 == 0) { 889fa3f02f3Smrg first_char = fs->min_char_or_byte2; 890fa3f02f3Smrg last_char = fs->max_char_or_byte2; 891fa3f02f3Smrg } else { 892fa3f02f3Smrg first_char = (fs->min_byte1 * 256) + fs->min_char_or_byte2; 893fa3f02f3Smrg last_char = (fs->max_byte1 * 256) + fs->max_char_or_byte2; 894fa3f02f3Smrg } 895fa3f02f3Smrg 896fa3f02f3Smrg for (ch = first_char; ch <= last_char; ++ch) { 897fa3f02f3Smrg if (xtermMissingChar(ch, fnt)) { 898fa3f02f3Smrg ++missing; 899fa3f02f3Smrg } 900fa3f02f3Smrg } 901fa3f02f3Smrg 902fa3f02f3Smrg printf("\t%s: %s\n", tag, NonNull(fnt->fn)); 903fa3f02f3Smrg printf("\t\tall chars: %s\n", fs->all_chars_exist ? "yes" : "no"); 904fa3f02f3Smrg printf("\t\tdefault char: %d\n", fs->default_char); 905fa3f02f3Smrg printf("\t\tdirection: %d\n", fs->direction); 906fa3f02f3Smrg printf("\t\tascent: %d\n", fs->ascent); 907fa3f02f3Smrg printf("\t\tdescent: %d\n", fs->descent); 908fa3f02f3Smrg printf("\t\tfirst char: %u\n", first_char); 909fa3f02f3Smrg printf("\t\tlast char: %u\n", last_char); 910fa3f02f3Smrg printf("\t\tmaximum-chars: %u\n", countGlyphs(fs)); 911fa3f02f3Smrg printf("\t\tmissing-chars: %u\n", missing); 912fa3f02f3Smrg printf("\t\tpresent-chars: %u\n", countGlyphs(fs) - missing); 913fa3f02f3Smrg printf("\t\tmin_byte1: %d\n", fs->min_byte1); 914fa3f02f3Smrg printf("\t\tmax_byte1: %d\n", fs->max_byte1); 915fa3f02f3Smrg printf("\t\tproperties: %d\n", fs->n_properties); 916fa3f02f3Smrg reportXCharStruct("min_bounds", &(fs->min_bounds)); 917fa3f02f3Smrg reportXCharStruct("max_bounds", &(fs->max_bounds)); 918fa3f02f3Smrg /* TODO: report fs->properties and fs->per_char */ 919fa3f02f3Smrg } 920fa3f02f3Smrg} 921fa3f02f3Smrg 922fa3f02f3Smrgstatic void 923fa3f02f3SmrgreportVTFontInfo(XtermWidget xw, int fontnum) 924fa3f02f3Smrg{ 925fa3f02f3Smrg if (resource.reportFonts) { 926fa3f02f3Smrg TScreen *screen = TScreenOf(xw); 927fa3f02f3Smrg 928fa3f02f3Smrg if (fontnum) { 929fa3f02f3Smrg printf("Loaded VTFonts(font%d)\n", fontnum); 930fa3f02f3Smrg } else { 931fa3f02f3Smrg printf("Loaded VTFonts(default)\n"); 932fa3f02f3Smrg } 933fa3f02f3Smrg reportOneVTFont("fNorm", &screen->fnts[fNorm]); 934fa3f02f3Smrg reportOneVTFont("fBold", &screen->fnts[fBold]); 935fa3f02f3Smrg#if OPT_WIDE_CHARS 936fa3f02f3Smrg reportOneVTFont("fWide", &screen->fnts[fWide]); 937fa3f02f3Smrg reportOneVTFont("fWBold", &screen->fnts[fWBold]); 938fa3f02f3Smrg#endif 939fa3f02f3Smrg } 940fa3f02f3Smrg} 941fa3f02f3Smrg#endif 942fa3f02f3Smrg 943d522f475Smrgint 944d522f475SmrgxtermLoadFont(XtermWidget xw, 945d522f475Smrg const VTFontNames * fonts, 946d522f475Smrg Bool doresize, 947d522f475Smrg int fontnum) 948d522f475Smrg{ 949956cc18dSsnj TScreen *screen = TScreenOf(xw); 950d522f475Smrg VTwin *win = WhichVWin(screen); 951d522f475Smrg 952d522f475Smrg VTFontNames myfonts; 953d522f475Smrg FontNameProperties *fp; 954d522f475Smrg XTermFonts fnts[fMAX]; 955d522f475Smrg Pixel new_normal; 956d522f475Smrg Pixel new_revers; 957d522f475Smrg char *tmpname = NULL; 9580bd37d32Smrg char *normal = NULL; 959956cc18dSsnj Boolean proportional = False; 960956cc18dSsnj fontWarningTypes warn[fMAX]; 961956cc18dSsnj int j; 962d522f475Smrg 963d522f475Smrg memset(&myfonts, 0, sizeof(myfonts)); 964d522f475Smrg memset(fnts, 0, sizeof(fnts)); 965d522f475Smrg 966d522f475Smrg if (fonts != 0) 967d522f475Smrg myfonts = *fonts; 968956cc18dSsnj if (!check_fontname(myfonts.f_n)) 969d522f475Smrg return 0; 970d522f475Smrg 971956cc18dSsnj /* 972956cc18dSsnj * Check the font names against the resource values, to see which were 973956cc18dSsnj * derived in a previous call. If so, we'll only warn about those if 974956cc18dSsnj * the warning level is set to "always". 975956cc18dSsnj */ 976956cc18dSsnj for (j = 0; j < fMAX; ++j) { 977956cc18dSsnj warn[j] = fwAlways; 978956cc18dSsnj } 979956cc18dSsnj#define CmpResource(field, index) \ 980956cc18dSsnj if (same_font_name(screen->menu_font_names[fontnum][index], myfonts.field)) \ 981956cc18dSsnj warn[index] = fwResource 982956cc18dSsnj 983956cc18dSsnj CmpResource(f_n, fNorm); 984956cc18dSsnj if (fontnum == fontMenu_default) { 985956cc18dSsnj CmpResource(f_b, fBold); 986956cc18dSsnj#if OPT_WIDE_CHARS 987956cc18dSsnj CmpResource(f_b, fWide); 988956cc18dSsnj CmpResource(f_b, fWBold); 989956cc18dSsnj#endif 990956cc18dSsnj } 991956cc18dSsnj 992d522f475Smrg if (fontnum == fontMenu_fontescape 993d522f475Smrg && myfonts.f_n != screen->MenuFontName(fontnum)) { 994d522f475Smrg if ((tmpname = x_strdup(myfonts.f_n)) == 0) 995d522f475Smrg return 0; 996d522f475Smrg } 997d522f475Smrg 998d522f475Smrg TRACE(("Begin Cgs - xtermLoadFont(%s)\n", myfonts.f_n)); 999d522f475Smrg releaseWindowGCs(xw, win); 1000d522f475Smrg 1001956cc18dSsnj#define DbgResource(name, field, index) \ 1002956cc18dSsnj TRACE(("xtermLoadFont #%d "name" %s%s\n", \ 1003956cc18dSsnj fontnum, \ 1004956cc18dSsnj (warn[index] == fwResource) ? "*" : " ", \ 1005492d43a5Smrg NonNull(myfonts.field))) 1006956cc18dSsnj DbgResource("normal", f_n, fNorm); 1007956cc18dSsnj DbgResource("bold ", f_b, fBold); 1008d522f475Smrg#if OPT_WIDE_CHARS 1009956cc18dSsnj DbgResource("wide ", f_w, fWide); 1010956cc18dSsnj DbgResource("w/bold", f_wb, fWBold); 1011d522f475Smrg#endif 1012d522f475Smrg 1013e39b573cSmrg /* 1014e39b573cSmrg * If we are opening the default font, and it happens to be missing, force 1015e39b573cSmrg * that to the compiled-in default font, e.g., "fixed". If we cannot open 1016e39b573cSmrg * the font, disable it from the menu. 1017e39b573cSmrg */ 1018e39b573cSmrg if (!xtermOpenFont(xw, 1019e39b573cSmrg myfonts.f_n, 1020e39b573cSmrg &fnts[fNorm], 1021e39b573cSmrg warn[fNorm], 1022e39b573cSmrg (fontnum == fontMenu_default))) { 1023e39b573cSmrg SetItemSensitivity(fontMenuEntries[fontnum].widget, False); 1024d522f475Smrg goto bad; 1025e39b573cSmrg } 1026d522f475Smrg 10270bd37d32Smrg normal = x_strdup(myfonts.f_n); 1028956cc18dSsnj if (!check_fontname(myfonts.f_b)) { 1029956cc18dSsnj warn[fBold] = fwAlways; 10300bd37d32Smrg fp = get_font_name_props(screen->display, fnts[fNorm].fs, &normal); 1031d522f475Smrg if (fp != 0) { 1032d522f475Smrg myfonts.f_b = bold_font_name(fp, fp->average_width); 1033956cc18dSsnj if (!xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], fwAlways, False)) { 1034d522f475Smrg myfonts.f_b = bold_font_name(fp, -1); 1035956cc18dSsnj xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], fwAlways, False); 1036d522f475Smrg } 1037492d43a5Smrg TRACE(("...derived bold '%s'\n", NonNull(myfonts.f_b))); 1038d522f475Smrg } 1039d522f475Smrg if (fp == 0 || fnts[fBold].fs == 0) { 1040d522f475Smrg xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]); 1041d522f475Smrg TRACE(("...cannot load a matching bold font\n")); 1042d522f475Smrg } else if (same_font_size(xw, fnts[fNorm].fs, fnts[fBold].fs) 1043d522f475Smrg && got_bold_font(screen->display, fnts[fBold].fs, myfonts.f_b)) { 1044d522f475Smrg TRACE(("...got a matching bold font\n")); 1045d522f475Smrg cache_menu_font_name(screen, fontnum, fBold, myfonts.f_b); 1046d522f475Smrg } else { 1047d522f475Smrg xtermCloseFont(xw, &fnts[fBold]); 1048d522f475Smrg fnts[fBold] = fnts[fNorm]; 1049d522f475Smrg TRACE(("...did not get a matching bold font\n")); 1050d522f475Smrg } 1051956cc18dSsnj } else if (!xtermOpenFont(xw, myfonts.f_b, &fnts[fBold], warn[fBold], False)) { 1052d522f475Smrg xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]); 1053956cc18dSsnj warn[fBold] = fwAlways; 1054492d43a5Smrg TRACE(("...cannot load bold font '%s'\n", NonNull(myfonts.f_b))); 1055d522f475Smrg } else { 1056d522f475Smrg cache_menu_font_name(screen, fontnum, fBold, myfonts.f_b); 1057d522f475Smrg } 1058d522f475Smrg 1059d522f475Smrg /* 1060d522f475Smrg * If there is no widefont specified, fake it by doubling AVERAGE_WIDTH 1061d522f475Smrg * of normal fonts XLFD, and asking for it. This plucks out 18x18ja 1062d522f475Smrg * and 12x13ja as the corresponding fonts for 9x18 and 6x13. 1063d522f475Smrg */ 1064d522f475Smrg if_OPT_WIDE_CHARS(screen, { 10650bd37d32Smrg Boolean derived; 10660bd37d32Smrg char *bold = NULL; 1067d522f475Smrg 1068956cc18dSsnj if (check_fontname(myfonts.f_w)) { 1069d522f475Smrg cache_menu_font_name(screen, fontnum, fWide, myfonts.f_w); 1070e39b573cSmrg } else if (screen->utf8_fonts && !is_double_width_font(fnts[fNorm].fs)) { 10710bd37d32Smrg fp = get_font_name_props(screen->display, fnts[fNorm].fs, &normal); 1072d522f475Smrg if (fp != 0) { 1073d522f475Smrg myfonts.f_w = wide_font_name(fp); 1074956cc18dSsnj warn[fWide] = fwAlways; 1075d522f475Smrg TRACE(("...derived wide %s\n", NonNull(myfonts.f_w))); 1076d522f475Smrg cache_menu_font_name(screen, fontnum, fWide, myfonts.f_w); 1077d522f475Smrg } 1078d522f475Smrg } 1079d522f475Smrg 1080956cc18dSsnj if (check_fontname(myfonts.f_w)) { 1081956cc18dSsnj (void) xtermOpenFont(xw, myfonts.f_w, &fnts[fWide], warn[fWide], False); 1082d522f475Smrg } else { 1083d522f475Smrg xtermCopyFontInfo(&fnts[fWide], &fnts[fNorm]); 1084956cc18dSsnj warn[fWide] = fwAlways; 1085d522f475Smrg } 1086d522f475Smrg 1087d522f475Smrg derived = False; 1088956cc18dSsnj if (!check_fontname(myfonts.f_wb)) { 10890bd37d32Smrg fp = get_font_name_props(screen->display, fnts[fBold].fs, &bold); 1090d522f475Smrg if (fp != 0) { 1091d522f475Smrg myfonts.f_wb = widebold_font_name(fp); 1092956cc18dSsnj warn[fWBold] = fwAlways; 1093d522f475Smrg derived = True; 1094d522f475Smrg } 1095d522f475Smrg } 1096d522f475Smrg 1097956cc18dSsnj if (check_fontname(myfonts.f_wb)) { 1098d522f475Smrg 1099e39b573cSmrg xtermOpenFont(xw, 1100e39b573cSmrg myfonts.f_wb, 1101e39b573cSmrg &fnts[fWBold], 1102e39b573cSmrg (screen->utf8_fonts 1103e39b573cSmrg ? warn[fWBold] 11040bd37d32Smrg : (fontWarningTypes) (xw->misc.fontWarnings + 1)), 1105e39b573cSmrg False); 1106d522f475Smrg 1107d522f475Smrg if (derived 1108d522f475Smrg && !compatibleWideCounts(fnts[fWide].fs, fnts[fWBold].fs)) { 1109d522f475Smrg xtermCloseFont(xw, &fnts[fWBold]); 1110d522f475Smrg } 1111d522f475Smrg if (fnts[fWBold].fs == 0) { 1112e39b573cSmrg if (IsEmpty(myfonts.f_w)) { 1113e39b573cSmrg myfonts.f_wb = myfonts.f_b; 1114e39b573cSmrg warn[fWBold] = fwAlways; 1115e39b573cSmrg xtermCopyFontInfo(&fnts[fWBold], &fnts[fBold]); 1116e39b573cSmrg TRACE(("...cannot load wide-bold, use bold %s\n", 1117e39b573cSmrg NonNull(myfonts.f_b))); 1118e39b573cSmrg } else { 1119e39b573cSmrg myfonts.f_wb = myfonts.f_w; 1120e39b573cSmrg warn[fWBold] = fwAlways; 1121e39b573cSmrg xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]); 1122e39b573cSmrg TRACE(("...cannot load wide-bold, use wide %s\n", 1123e39b573cSmrg NonNull(myfonts.f_w))); 1124e39b573cSmrg } 1125d522f475Smrg } else { 1126d522f475Smrg TRACE(("...%s wide/bold %s\n", 1127d522f475Smrg derived ? "derived" : "given", 1128d522f475Smrg NonNull(myfonts.f_wb))); 1129d522f475Smrg cache_menu_font_name(screen, fontnum, fWBold, myfonts.f_wb); 1130d522f475Smrg } 1131d522f475Smrg } else if (is_double_width_font(fnts[fBold].fs)) { 1132d522f475Smrg xtermCopyFontInfo(&fnts[fWBold], &fnts[fBold]); 1133956cc18dSsnj warn[fWBold] = fwAlways; 1134d522f475Smrg TRACE(("...bold font is double-width, use it %s\n", NonNull(myfonts.f_b))); 1135d522f475Smrg } else { 1136d522f475Smrg xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]); 1137956cc18dSsnj warn[fWBold] = fwAlways; 1138d522f475Smrg TRACE(("...cannot load wide bold font, use wide %s\n", NonNull(myfonts.f_w))); 1139d522f475Smrg } 1140d522f475Smrg 11410bd37d32Smrg free(bold); 11420bd37d32Smrg 1143d522f475Smrg if (EmptyFont(fnts[fWBold].fs)) 1144d522f475Smrg goto bad; /* can't use a 0-sized font */ 1145d522f475Smrg }); 1146d522f475Smrg 1147d522f475Smrg /* 1148d522f475Smrg * Most of the time this call to load the font will succeed, even if 1149d522f475Smrg * there is no wide font : the X server doubles the width of the 1150d522f475Smrg * normal font, or similar. 1151d522f475Smrg * 1152d522f475Smrg * But if it did fail for some reason, then nevermind. 1153d522f475Smrg */ 1154d522f475Smrg if (EmptyFont(fnts[fBold].fs)) 1155d522f475Smrg goto bad; /* can't use a 0-sized font */ 1156d522f475Smrg 1157d522f475Smrg if (!same_font_size(xw, fnts[fNorm].fs, fnts[fBold].fs) 1158d522f475Smrg && (is_fixed_font(fnts[fNorm].fs) && is_fixed_font(fnts[fBold].fs))) { 1159d522f475Smrg TRACE(("...ignoring mismatched normal/bold fonts\n")); 1160d522f475Smrg xtermCloseFont(xw, &fnts[fBold]); 1161d522f475Smrg xtermCopyFontInfo(&fnts[fBold], &fnts[fNorm]); 1162d522f475Smrg } 1163d522f475Smrg 1164d522f475Smrg if_OPT_WIDE_CHARS(screen, { 1165d522f475Smrg if (fnts[fWide].fs != 0 1166d522f475Smrg && fnts[fWBold].fs != 0 1167d522f475Smrg && !same_font_size(xw, fnts[fWide].fs, fnts[fWBold].fs) 1168d522f475Smrg && (is_fixed_font(fnts[fWide].fs) && is_fixed_font(fnts[fWBold].fs))) { 1169d522f475Smrg TRACE(("...ignoring mismatched normal/bold wide fonts\n")); 1170d522f475Smrg xtermCloseFont(xw, &fnts[fWBold]); 1171d522f475Smrg xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]); 1172d522f475Smrg } 1173d522f475Smrg }); 1174d522f475Smrg 1175d522f475Smrg /* 1176d522f475Smrg * Normal/bold fonts should be the same width. Also, the min/max 1177d522f475Smrg * values should be the same. 1178d522f475Smrg */ 1179d522f475Smrg if (!is_fixed_font(fnts[fNorm].fs) 1180d522f475Smrg || !is_fixed_font(fnts[fBold].fs) 1181d522f475Smrg || fnts[fNorm].fs->max_bounds.width != fnts[fBold].fs->max_bounds.width) { 1182d522f475Smrg TRACE(("Proportional font! normal %d/%d, bold %d/%d\n", 1183d522f475Smrg fnts[fNorm].fs->min_bounds.width, 1184d522f475Smrg fnts[fNorm].fs->max_bounds.width, 1185d522f475Smrg fnts[fBold].fs->min_bounds.width, 1186d522f475Smrg fnts[fBold].fs->max_bounds.width)); 1187d522f475Smrg proportional = True; 1188d522f475Smrg } 1189d522f475Smrg 1190d522f475Smrg if_OPT_WIDE_CHARS(screen, { 1191d522f475Smrg if (fnts[fWide].fs != 0 1192d522f475Smrg && fnts[fWBold].fs != 0 1193d522f475Smrg && (!is_fixed_font(fnts[fWide].fs) 1194d522f475Smrg || !is_fixed_font(fnts[fWBold].fs) 1195d522f475Smrg || fnts[fWide].fs->max_bounds.width != fnts[fWBold].fs->max_bounds.width)) { 1196d522f475Smrg TRACE(("Proportional font! wide %d/%d, wide bold %d/%d\n", 1197d522f475Smrg fnts[fWide].fs->min_bounds.width, 1198d522f475Smrg fnts[fWide].fs->max_bounds.width, 1199d522f475Smrg fnts[fWBold].fs->min_bounds.width, 1200d522f475Smrg fnts[fWBold].fs->max_bounds.width)); 1201d522f475Smrg proportional = True; 1202d522f475Smrg } 1203d522f475Smrg }); 1204d522f475Smrg 1205d522f475Smrg /* TODO : enforce that the width of the wide font is 2* the width 1206d522f475Smrg of the narrow font */ 1207d522f475Smrg 1208d522f475Smrg /* 1209d522f475Smrg * If we're switching fonts, free the old ones. Otherwise we'll leak 1210d522f475Smrg * the memory that is associated with the old fonts. The 1211d522f475Smrg * XLoadQueryFont call allocates a new XFontStruct. 1212d522f475Smrg */ 1213d522f475Smrg xtermCloseFonts(xw, screen->fnts); 1214d522f475Smrg 1215d522f475Smrg xtermCopyFontInfo(&(screen->fnts[fNorm]), &fnts[fNorm]); 1216d522f475Smrg xtermCopyFontInfo(&(screen->fnts[fBold]), &fnts[fBold]); 1217d522f475Smrg#if OPT_WIDE_CHARS 1218d522f475Smrg xtermCopyFontInfo(&(screen->fnts[fWide]), &fnts[fWide]); 1219d522f475Smrg if (fnts[fWBold].fs == NULL) 1220d522f475Smrg xtermCopyFontInfo(&fnts[fWBold], &fnts[fWide]); 1221d522f475Smrg xtermCopyFontInfo(&(screen->fnts[fWBold]), &fnts[fWBold]); 1222d522f475Smrg#endif 1223d522f475Smrg 1224d522f475Smrg new_normal = getXtermForeground(xw, xw->flags, xw->cur_foreground); 1225d522f475Smrg new_revers = getXtermBackground(xw, xw->flags, xw->cur_background); 1226d522f475Smrg 1227d522f475Smrg setCgsFore(xw, win, gcNorm, new_normal); 1228d522f475Smrg setCgsBack(xw, win, gcNorm, new_revers); 1229d522f475Smrg setCgsFont(xw, win, gcNorm, &(screen->fnts[fNorm])); 1230d522f475Smrg 1231d522f475Smrg copyCgs(xw, win, gcBold, gcNorm); 1232d522f475Smrg setCgsFont(xw, win, gcBold, &(screen->fnts[fBold])); 1233d522f475Smrg 1234d522f475Smrg setCgsFore(xw, win, gcNormReverse, new_revers); 1235d522f475Smrg setCgsBack(xw, win, gcNormReverse, new_normal); 1236d522f475Smrg setCgsFont(xw, win, gcNormReverse, &(screen->fnts[fNorm])); 1237d522f475Smrg 1238d522f475Smrg copyCgs(xw, win, gcBoldReverse, gcNormReverse); 1239d522f475Smrg setCgsFont(xw, win, gcBoldReverse, &(screen->fnts[fBold])); 1240d522f475Smrg 1241d522f475Smrg if_OPT_WIDE_CHARS(screen, { 1242d522f475Smrg if (screen->fnts[fWide].fs != 0 1243d522f475Smrg && screen->fnts[fWBold].fs != 0) { 1244d522f475Smrg setCgsFore(xw, win, gcWide, new_normal); 1245d522f475Smrg setCgsBack(xw, win, gcWide, new_revers); 1246d522f475Smrg setCgsFont(xw, win, gcWide, &(screen->fnts[fWide])); 1247d522f475Smrg 1248d522f475Smrg copyCgs(xw, win, gcWBold, gcWide); 1249d522f475Smrg setCgsFont(xw, win, gcWBold, &(screen->fnts[fWBold])); 1250d522f475Smrg 1251d522f475Smrg setCgsFore(xw, win, gcWideReverse, new_revers); 1252d522f475Smrg setCgsBack(xw, win, gcWideReverse, new_normal); 1253d522f475Smrg setCgsFont(xw, win, gcWideReverse, &(screen->fnts[fWide])); 1254d522f475Smrg 1255d522f475Smrg copyCgs(xw, win, gcWBoldReverse, gcWideReverse); 1256d522f475Smrg setCgsFont(xw, win, gcWBoldReverse, &(screen->fnts[fWBold])); 1257d522f475Smrg } 1258d522f475Smrg }); 1259d522f475Smrg 126020d2c4d2Smrg#if OPT_BOX_CHARS 126120d2c4d2Smrg screen->allow_packing = proportional; 126220d2c4d2Smrg setupPackedFonts(xw); 126320d2c4d2Smrg#endif 126420d2c4d2Smrg screen->fnt_prop = (Boolean) (proportional && !(screen->force_packed)); 1265d522f475Smrg screen->fnt_boxes = True; 1266d522f475Smrg 1267d522f475Smrg#if OPT_BOX_CHARS 1268d522f475Smrg /* 1269d522f475Smrg * Xterm uses character positions 1-31 of a font for the line-drawing 1270d522f475Smrg * characters. Check that they are all present. The null character 1271d522f475Smrg * (0) is special, and is not used. 1272d522f475Smrg */ 1273d522f475Smrg#if OPT_RENDERFONT 1274d522f475Smrg if (UsingRenderFont(xw)) { 1275d522f475Smrg /* 1276d522f475Smrg * FIXME: we shouldn't even be here if we're using Xft. 1277d522f475Smrg */ 1278d522f475Smrg screen->fnt_boxes = False; 1279d522f475Smrg TRACE(("assume Xft missing line-drawing chars\n")); 1280d522f475Smrg } else 1281d522f475Smrg#endif 1282d522f475Smrg { 1283d522f475Smrg unsigned ch; 1284d522f475Smrg 1285fa3f02f3Smrg TRACE(("normal font is %scomplete\n", 1286fa3f02f3Smrg FontIsIncomplete(&fnts[fNorm]) ? "in" : "")); 1287fa3f02f3Smrg TRACE(("bold font is %scomplete\n", 1288fa3f02f3Smrg FontIsIncomplete(&fnts[fBold]) ? "in" : "")); 1289fa3f02f3Smrg 1290d522f475Smrg for (ch = 1; ch < 32; ch++) { 1291d522f475Smrg unsigned n = ch; 1292d522f475Smrg#if OPT_WIDE_CHARS 1293d522f475Smrg if (screen->utf8_mode || screen->unicode_font) { 1294d522f475Smrg n = dec2ucs(ch); 1295d522f475Smrg if (n == UCS_REPL) 1296d522f475Smrg continue; 1297d522f475Smrg } 1298d522f475Smrg#endif 1299956cc18dSsnj if (IsXtermMissingChar(screen, n, &fnts[fNorm])) { 1300d522f475Smrg TRACE(("missing normal char #%d\n", n)); 1301d522f475Smrg screen->fnt_boxes = False; 1302d522f475Smrg break; 1303d522f475Smrg } 1304956cc18dSsnj if (IsXtermMissingChar(screen, n, &fnts[fBold])) { 1305d522f475Smrg TRACE(("missing bold char #%d\n", n)); 1306d522f475Smrg screen->fnt_boxes = False; 1307d522f475Smrg break; 1308d522f475Smrg } 1309d522f475Smrg } 1310d522f475Smrg } 1311d522f475Smrg TRACE(("Will %suse internal line-drawing characters\n", 1312d522f475Smrg screen->fnt_boxes ? "not " : "")); 1313d522f475Smrg#endif 1314d522f475Smrg 1315d522f475Smrg if (screen->always_bold_mode) { 1316d522f475Smrg screen->enbolden = screen->bold_mode; 1317d522f475Smrg } else { 1318d522f475Smrg screen->enbolden = screen->bold_mode 1319d522f475Smrg && ((fnts[fNorm].fs == fnts[fBold].fs) 1320d522f475Smrg || same_font_name(normal, myfonts.f_b)); 1321d522f475Smrg } 1322d522f475Smrg TRACE(("Will %suse 1-pixel offset/overstrike to simulate bold\n", 1323d522f475Smrg screen->enbolden ? "" : "not ")); 1324d522f475Smrg 1325d522f475Smrg set_menu_font(False); 1326d522f475Smrg screen->menu_font_number = fontnum; 1327d522f475Smrg set_menu_font(True); 1328d522f475Smrg if (tmpname) { /* if setting escape or sel */ 1329d522f475Smrg if (screen->MenuFontName(fontnum)) 133020d2c4d2Smrg free((void *) screen->MenuFontName(fontnum)); 1331d522f475Smrg screen->MenuFontName(fontnum) = tmpname; 1332d522f475Smrg if (fontnum == fontMenu_fontescape) { 1333d522f475Smrg SetItemSensitivity(fontMenuEntries[fontMenu_fontescape].widget, 1334d522f475Smrg True); 1335d522f475Smrg } 1336d522f475Smrg#if OPT_SHIFT_FONTS 1337d522f475Smrg screen->menu_font_sizes[fontnum] = FontSize(fnts[fNorm].fs); 1338d522f475Smrg#endif 1339d522f475Smrg } 13400bd37d32Smrg if (normal) 13410bd37d32Smrg free(normal); 1342d522f475Smrg set_cursor_gcs(xw); 1343d522f475Smrg xtermUpdateFontInfo(xw, doresize); 1344d522f475Smrg TRACE(("Success Cgs - xtermLoadFont\n")); 1345fa3f02f3Smrg#if OPT_REPORT_FONTS 1346fa3f02f3Smrg reportVTFontInfo(xw, fontnum); 1347fa3f02f3Smrg#endif 1348d522f475Smrg return 1; 1349d522f475Smrg 1350d522f475Smrg bad: 13510bd37d32Smrg if (normal) 13520bd37d32Smrg free(normal); 1353d522f475Smrg if (tmpname) 1354d522f475Smrg free(tmpname); 13550bd37d32Smrg 13560bd37d32Smrg#if OPT_RENDERFONT 13570bd37d32Smrg if (x_strcasecmp(myfonts.f_n, DEFFONT)) { 13580bd37d32Smrg int code; 13590bd37d32Smrg 13600bd37d32Smrg myfonts.f_n = DEFFONT; 13610bd37d32Smrg TRACE(("...recovering for TrueType fonts\n")); 13620bd37d32Smrg code = xtermLoadFont(xw, &myfonts, doresize, fontnum); 13630bd37d32Smrg if (code) { 13640bd37d32Smrg SetItemSensitivity(fontMenuEntries[fontnum].widget, 13650bd37d32Smrg UsingRenderFont(xw)); 13660bd37d32Smrg TRACE(("...recovered size %dx%d\n", 13670bd37d32Smrg FontHeight(screen), 13680bd37d32Smrg FontWidth(screen))); 13690bd37d32Smrg } 13700bd37d32Smrg return code; 13710bd37d32Smrg } 13720bd37d32Smrg#endif 13730bd37d32Smrg 1374d522f475Smrg releaseWindowGCs(xw, win); 1375d522f475Smrg 1376d522f475Smrg xtermCloseFonts(xw, fnts); 1377d522f475Smrg TRACE(("Fail Cgs - xtermLoadFont\n")); 1378d522f475Smrg return 0; 1379d522f475Smrg} 1380d522f475Smrg 1381d522f475Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 1382d522f475Smrg/* 1383d522f475Smrg * Collect font-names that we can modify with the load-vt-fonts() action. 1384d522f475Smrg */ 1385d522f475Smrg#define MERGE_SUBFONT(src,dst,name) \ 1386492d43a5Smrg if (IsEmpty(dst.name)) { \ 1387d522f475Smrg TRACE(("MERGE_SUBFONT " #dst "." #name " merge %s\n", NonNull(src.name))); \ 1388d522f475Smrg dst.name = src.name; \ 1389d522f475Smrg } else { \ 1390d522f475Smrg TRACE(("MERGE_SUBFONT " #dst "." #name " found %s\n", NonNull(dst.name))); \ 1391d522f475Smrg } 1392d522f475Smrg 1393e39b573cSmrg#define INFER_SUBFONT(src,dst,name) \ 1394e39b573cSmrg if (IsEmpty(dst.name)) { \ 1395e39b573cSmrg TRACE(("INFER_SUBFONT " #dst "." #name " will infer\n")); \ 1396e39b573cSmrg dst.name = x_strdup(""); \ 1397e39b573cSmrg } else { \ 1398e39b573cSmrg TRACE(("INFER_SUBFONT " #dst "." #name " found %s\n", NonNull(dst.name))); \ 1399e39b573cSmrg } 1400e39b573cSmrg 1401d522f475Smrg#define COPY_MENU_FONTS(src,dst) \ 1402d522f475Smrg TRACE(("COPY_MENU_FONTS " #src " to " #dst "\n")); \ 1403d522f475Smrg for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \ 1404d522f475Smrg for (m = 0; m < fMAX; ++m) { \ 1405492d43a5Smrg dst.menu_font_names[n][m] = x_strdup(src.menu_font_names[n][m]); \ 1406d522f475Smrg } \ 1407e39b573cSmrg TRACE((".. " #dst ".menu_fonts_names[%d] = %s\n", n, dst.menu_font_names[n][fNorm])); \ 1408e39b573cSmrg } 1409e39b573cSmrg 1410e39b573cSmrgvoid 1411e39b573cSmrgxtermSaveVTFonts(XtermWidget xw) 1412e39b573cSmrg{ 1413e39b573cSmrg TScreen *screen = TScreenOf(xw); 1414e39b573cSmrg Cardinal n, m; 1415e39b573cSmrg 1416e39b573cSmrg if (!screen->savedVTFonts) { 1417e39b573cSmrg 1418e39b573cSmrg screen->savedVTFonts = True; 1419e39b573cSmrg TRACE(("xtermSaveVTFonts saving original\n")); 1420e39b573cSmrg screen->cacheVTFonts.default_font = xw->misc.default_font; 1421e39b573cSmrg COPY_MENU_FONTS(xw->screen, screen->cacheVTFonts); 1422e39b573cSmrg } 1423e39b573cSmrg} 1424e39b573cSmrg 1425e39b573cSmrg#define SAME_STRING(x,y) ((x) == (y) || ((x) && (y) && !strcmp(x, y))) 1426e39b573cSmrg#define SAME_MEMBER(n) SAME_STRING(a->n, b->n) 1427e39b573cSmrg 1428e39b573cSmrgstatic Boolean 1429e39b573cSmrgsameSubResources(SubResourceRec * a, SubResourceRec * b) 1430e39b573cSmrg{ 1431e39b573cSmrg Boolean result = True; 1432e39b573cSmrg int n; 1433e39b573cSmrg 1434e39b573cSmrg if (!SAME_MEMBER(default_font.f_n) 1435e39b573cSmrg || !SAME_MEMBER(default_font.f_b) 14360bd37d32Smrg#if OPT_WIDE_CHARS 1437e39b573cSmrg || !SAME_MEMBER(default_font.f_w) 14380bd37d32Smrg || !SAME_MEMBER(default_font.f_wb) 14390bd37d32Smrg#endif 14400bd37d32Smrg ) { 1441e39b573cSmrg TRACE(("sameSubResources: default_font differs\n")); 1442e39b573cSmrg result = False; 1443e39b573cSmrg } else { 1444e39b573cSmrg for (n = 0; n < NMENUFONTS; ++n) { 1445e39b573cSmrg if (!SAME_MEMBER(menu_font_names[n][fNorm])) { 1446e39b573cSmrg TRACE(("sameSubResources: menu_font_names[%d] differs\n", n)); 1447e39b573cSmrg result = False; 1448e39b573cSmrg break; 1449e39b573cSmrg } 1450d522f475Smrg } 1451e39b573cSmrg } 1452e39b573cSmrg 1453e39b573cSmrg return result; 1454e39b573cSmrg} 1455d522f475Smrg 1456d522f475Smrg/* 1457d522f475Smrg * Load the "VT" font names from the given subresource name/class. These 1458d522f475Smrg * correspond to the VT100 resources. 1459d522f475Smrg */ 1460d522f475Smrgstatic Bool 146120d2c4d2SmrgxtermLoadVTFonts(XtermWidget xw, String myName, String myClass) 1462d522f475Smrg{ 1463e39b573cSmrg SubResourceRec subresourceRec; 1464e39b573cSmrg SubResourceRec referenceRec; 1465d522f475Smrg 1466d522f475Smrg /* 1467d522f475Smrg * These are duplicates of the VT100 font resources, but with a special 1468d522f475Smrg * application/classname passed in to distinguish them. 1469d522f475Smrg */ 1470d522f475Smrg static XtResource font_resources[] = 1471d522f475Smrg { 1472d522f475Smrg Sres(XtNfont, XtCFont, default_font.f_n, DEFFONT), 1473d522f475Smrg Sres(XtNboldFont, XtCBoldFont, default_font.f_b, DEFBOLDFONT), 1474d522f475Smrg#if OPT_WIDE_CHARS 1475d522f475Smrg Sres(XtNwideFont, XtCWideFont, default_font.f_w, DEFWIDEFONT), 1476d522f475Smrg Sres(XtNwideBoldFont, XtCWideBoldFont, default_font.f_wb, DEFWIDEBOLDFONT), 1477d522f475Smrg#endif 1478d522f475Smrg Sres(XtNfont1, XtCFont1, MenuFontName(fontMenu_font1), NULL), 1479d522f475Smrg Sres(XtNfont2, XtCFont2, MenuFontName(fontMenu_font2), NULL), 1480d522f475Smrg Sres(XtNfont3, XtCFont3, MenuFontName(fontMenu_font3), NULL), 1481d522f475Smrg Sres(XtNfont4, XtCFont4, MenuFontName(fontMenu_font4), NULL), 1482d522f475Smrg Sres(XtNfont5, XtCFont5, MenuFontName(fontMenu_font5), NULL), 1483d522f475Smrg Sres(XtNfont6, XtCFont6, MenuFontName(fontMenu_font6), NULL), 1484d522f475Smrg }; 1485d522f475Smrg Cardinal n, m; 1486d522f475Smrg Bool status = True; 1487956cc18dSsnj TScreen *screen = TScreenOf(xw); 1488d522f475Smrg 1489e39b573cSmrg TRACE(("called xtermLoadVTFonts(name=%s, class=%s)\n", 1490e39b573cSmrg NonNull(myName), NonNull(myClass))); 1491d522f475Smrg 1492e39b573cSmrg xtermSaveVTFonts(xw); 1493d522f475Smrg 1494492d43a5Smrg if (IsEmpty(myName)) { 1495d522f475Smrg TRACE(("xtermLoadVTFonts restoring original\n")); 1496e39b573cSmrg xw->misc.default_font = screen->cacheVTFonts.default_font; 1497e39b573cSmrg COPY_MENU_FONTS(screen->cacheVTFonts, xw->screen); 1498e39b573cSmrg for (n = 0; n < XtNumber(screen->cacheVTFonts.menu_font_names); ++n) { 1499e39b573cSmrg screen->MenuFontName(n) = screen->cacheVTFonts.MenuFontName(n); 1500e39b573cSmrg } 1501d522f475Smrg } else { 1502d522f475Smrg TRACE(("xtermLoadVTFonts(%s, %s)\n", myName, myClass)); 1503d522f475Smrg 1504e39b573cSmrg memset(&referenceRec, 0, sizeof(referenceRec)); 1505d522f475Smrg memset(&subresourceRec, 0, sizeof(subresourceRec)); 1506956cc18dSsnj XtGetSubresources((Widget) xw, (XtPointer) &subresourceRec, 1507d522f475Smrg myName, myClass, 1508d522f475Smrg font_resources, 1509d522f475Smrg (Cardinal) XtNumber(font_resources), 1510d522f475Smrg NULL, (Cardinal) 0); 1511d522f475Smrg 1512e39b573cSmrg /* 1513e39b573cSmrg * XtGetSubresources returns no status, so we compare the returned 1514e39b573cSmrg * data against a zero'd struct to see if any data is returned. 1515e39b573cSmrg */ 1516e39b573cSmrg if (memcmp(&referenceRec, &subresourceRec, sizeof(referenceRec)) 1517e39b573cSmrg && !sameSubResources(&(screen->cacheVTFonts), &subresourceRec)) { 1518e39b573cSmrg 1519e39b573cSmrg screen->mergedVTFonts = True; 1520d522f475Smrg 1521d522f475Smrg /* 1522d522f475Smrg * If a particular resource value was not found, use the original. 1523d522f475Smrg */ 1524956cc18dSsnj MERGE_SUBFONT(xw->misc, subresourceRec, default_font.f_n); 1525e39b573cSmrg INFER_SUBFONT(xw->misc, subresourceRec, default_font.f_b); 1526d522f475Smrg#if OPT_WIDE_CHARS 1527e39b573cSmrg INFER_SUBFONT(xw->misc, subresourceRec, default_font.f_w); 1528e39b573cSmrg INFER_SUBFONT(xw->misc, subresourceRec, default_font.f_wb); 1529d522f475Smrg#endif 1530d522f475Smrg for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) 1531956cc18dSsnj MERGE_SUBFONT(xw->screen, subresourceRec, MenuFontName(n)); 1532d522f475Smrg 1533d522f475Smrg /* 1534d522f475Smrg * Finally, copy the subresource data to the widget. 1535d522f475Smrg */ 1536956cc18dSsnj xw->misc.default_font = subresourceRec.default_font; 1537956cc18dSsnj COPY_MENU_FONTS(subresourceRec, xw->screen); 1538492d43a5Smrg screen->MenuFontName(fontMenu_default) = x_strdup(xw->misc.default_font.f_n); 1539492d43a5Smrg screen->menu_font_names[0][fBold] = x_strdup(xw->misc.default_font.f_b); 1540d522f475Smrg#if OPT_WIDE_CHARS 1541492d43a5Smrg screen->menu_font_names[0][fWide] = x_strdup(xw->misc.default_font.f_w); 1542492d43a5Smrg screen->menu_font_names[0][fWBold] = x_strdup(xw->misc.default_font.f_wb); 1543d522f475Smrg#endif 1544d522f475Smrg } else { 1545d522f475Smrg TRACE(("...no resources found\n")); 1546d522f475Smrg status = False; 1547d522f475Smrg } 1548d522f475Smrg } 1549d522f475Smrg return status; 1550d522f475Smrg} 1551d522f475Smrg 1552d522f475Smrg#if OPT_WIDE_CHARS 1553d522f475Smrgstatic Bool 155420d2c4d2SmrgisWideFont(XFontStruct * fp, const char *tag, Bool nullOk) 1555d522f475Smrg{ 1556d522f475Smrg Bool result = False; 1557d522f475Smrg 1558d522f475Smrg (void) tag; 1559d522f475Smrg if (okFont(fp)) { 1560d522f475Smrg unsigned count = countGlyphs(fp); 1561d522f475Smrg TRACE(("isWideFont(%s) found %d cells\n", tag, count)); 1562d522f475Smrg result = (count > 256) ? True : False; 1563d522f475Smrg } else { 1564d522f475Smrg result = nullOk; 1565d522f475Smrg } 1566d522f475Smrg return result; 1567d522f475Smrg} 1568d522f475Smrg 1569d522f475Smrg/* 1570d522f475Smrg * If the current fonts are not wide, load the UTF8 fonts. 1571d522f475Smrg * 1572d522f475Smrg * Called during initialization (for wide-character mode), the fonts have not 1573d522f475Smrg * been setup, so we pass nullOk=True to isWideFont(). 1574d522f475Smrg * 1575d522f475Smrg * Called after initialization, e.g., in response to the UTF-8 menu entry 1576d522f475Smrg * (starting from narrow character mode), it checks if the fonts are not wide. 1577d522f475Smrg */ 1578d522f475SmrgBool 1579d522f475SmrgxtermLoadWideFonts(XtermWidget xw, Bool nullOk) 1580d522f475Smrg{ 1581956cc18dSsnj TScreen *screen = TScreenOf(xw); 1582d522f475Smrg Bool result; 1583d522f475Smrg 1584d522f475Smrg if (EmptyFont(screen->fnts[fWide].fs)) { 1585d522f475Smrg result = (isWideFont(screen->fnts[fNorm].fs, "normal", nullOk) 1586d522f475Smrg && isWideFont(screen->fnts[fBold].fs, "bold", nullOk)); 1587d522f475Smrg } else { 1588d522f475Smrg result = (isWideFont(screen->fnts[fWide].fs, "wide", nullOk) 1589d522f475Smrg && isWideFont(screen->fnts[fWBold].fs, "wide-bold", nullOk)); 1590d522f475Smrg if (result && !screen->utf8_latin1) { 1591d522f475Smrg result = (isWideFont(screen->fnts[fNorm].fs, "normal", nullOk) 1592d522f475Smrg && isWideFont(screen->fnts[fBold].fs, "bold", nullOk)); 1593d522f475Smrg } 1594d522f475Smrg } 1595d522f475Smrg if (!result) { 1596d522f475Smrg TRACE(("current fonts are not all wide%s\n", nullOk ? " nullOk" : "")); 1597e39b573cSmrg result = xtermLoadVTFonts(xw, XtNutf8Fonts, XtCUtf8Fonts); 1598d522f475Smrg } 1599d522f475Smrg TRACE(("xtermLoadWideFonts:%d\n", result)); 1600d522f475Smrg return result; 1601d522f475Smrg} 1602d522f475Smrg#endif /* OPT_WIDE_CHARS */ 1603d522f475Smrg 1604d522f475Smrg/* 1605d522f475Smrg * Restore the default fonts, i.e., if we had switched to wide-fonts. 1606d522f475Smrg */ 1607d522f475SmrgBool 1608956cc18dSsnjxtermLoadDefaultFonts(XtermWidget xw) 1609d522f475Smrg{ 1610d522f475Smrg Bool result; 1611956cc18dSsnj result = xtermLoadVTFonts(xw, NULL, NULL); 1612d522f475Smrg TRACE(("xtermLoadDefaultFonts:%d\n", result)); 1613d522f475Smrg return result; 1614d522f475Smrg} 1615d522f475Smrg#endif /* OPT_LOAD_VTFONTS || OPT_WIDE_CHARS */ 1616d522f475Smrg 1617d522f475Smrg#if OPT_LOAD_VTFONTS 1618d522f475Smrgvoid 1619d522f475SmrgHandleLoadVTFonts(Widget w, 1620d522f475Smrg XEvent * event GCC_UNUSED, 1621fa3f02f3Smrg String *params GCC_UNUSED, 1622d522f475Smrg Cardinal *param_count GCC_UNUSED) 1623d522f475Smrg{ 1624d522f475Smrg static char empty[] = ""; /* appease strict compilers */ 1625d522f475Smrg 1626956cc18dSsnj XtermWidget xw; 1627956cc18dSsnj 1628956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 1629956cc18dSsnj TScreen *screen = TScreenOf(xw); 1630492d43a5Smrg char name_buf[80]; 1631492d43a5Smrg char class_buf[80]; 1632492d43a5Smrg String name = (String) ((*param_count > 0) ? params[0] : empty); 16330bd37d32Smrg char *myName = (char *) MyStackAlloc(strlen(name) + 1, name_buf); 1634492d43a5Smrg String convert = (String) ((*param_count > 1) ? params[1] : myName); 16350bd37d32Smrg char *myClass = (char *) MyStackAlloc(strlen(convert) + 1, class_buf); 1636d522f475Smrg int n; 1637d522f475Smrg 1638d522f475Smrg TRACE(("HandleLoadVTFonts(%d)\n", *param_count)); 1639492d43a5Smrg strcpy(myName, name); 1640d522f475Smrg strcpy(myClass, convert); 16412eaa94a1Schristos if (*param_count == 1) 16422eaa94a1Schristos myClass[0] = x_toupper(myClass[0]); 1643d522f475Smrg 1644d522f475Smrg if (xtermLoadVTFonts(xw, myName, myClass)) { 1645d522f475Smrg /* 1646d522f475Smrg * When switching fonts, try to preserve the font-menu selection, since 1647d522f475Smrg * it is less surprising to do that (if the font-switching can be 1648d522f475Smrg * undone) than to switch to "Default". 1649d522f475Smrg */ 1650956cc18dSsnj int font_number = screen->menu_font_number; 1651d522f475Smrg if (font_number > fontMenu_lastBuiltin) 1652d522f475Smrg font_number = fontMenu_lastBuiltin; 1653d522f475Smrg for (n = 0; n < NMENUFONTS; ++n) 1654956cc18dSsnj screen->menu_font_sizes[n] = 0; 1655d522f475Smrg SetVTFont(xw, font_number, True, 1656d522f475Smrg ((font_number == fontMenu_default) 1657d522f475Smrg ? &(xw->misc.default_font) 1658d522f475Smrg : NULL)); 1659d522f475Smrg } 1660d522f475Smrg 1661492d43a5Smrg MyStackFree(myName, name_buf); 1662492d43a5Smrg MyStackFree(myClass, class_buf); 1663d522f475Smrg } 1664d522f475Smrg} 1665d522f475Smrg#endif /* OPT_LOAD_VTFONTS */ 1666d522f475Smrg 1667d522f475Smrg/* 1668d522f475Smrg * Set the limits for the box that outlines the cursor. 1669d522f475Smrg */ 1670d522f475Smrgvoid 1671fa3f02f3SmrgxtermSetCursorBox(TScreen *screen) 1672d522f475Smrg{ 1673d522f475Smrg static XPoint VTbox[NBOX]; 1674d522f475Smrg XPoint *vp; 16752eaa94a1Schristos int fw = FontWidth(screen) - 1; 16762eaa94a1Schristos int fh = FontHeight(screen) - 1; 16770bd37d32Smrg int ww = isCursorBar(screen) ? 1 : fw; 16780bd37d32Smrg int hh = isCursorUnderline(screen) ? 1 : fh; 1679d522f475Smrg 1680d522f475Smrg vp = &VTbox[1]; 16810bd37d32Smrg (vp++)->x = (short) ww; 16822eaa94a1Schristos (vp++)->y = (short) hh; 16830bd37d32Smrg (vp++)->x = (short) -ww; 16842eaa94a1Schristos vp->y = (short) -hh; 16852eaa94a1Schristos 1686d522f475Smrg screen->box = VTbox; 1687d522f475Smrg} 1688d522f475Smrg 1689d522f475Smrg#define CACHE_XFT(dst,src) if (src != 0) {\ 1690956cc18dSsnj checkXft(xw, &(dst[fontnum]), src);\ 16910bd37d32Smrg TRACE(("Xft metrics %s[%d] = %d (%d,%d)%s advance %d, actual %d%s\n",\ 1692d522f475Smrg #dst,\ 1693d522f475Smrg fontnum,\ 1694d522f475Smrg src->height,\ 1695d522f475Smrg src->ascent,\ 1696d522f475Smrg src->descent,\ 16970bd37d32Smrg ((src->ascent + src->descent) > src->height ? "*" : ""),\ 1698956cc18dSsnj src->max_advance_width,\ 1699956cc18dSsnj dst[fontnum].map.min_width,\ 1700956cc18dSsnj dst[fontnum].map.mixed ? " mixed" : ""));\ 1701d522f475Smrg } 1702d522f475Smrg 1703d522f475Smrg#if OPT_RENDERFONT 1704956cc18dSsnj 170520d2c4d2Smrgstatic FcChar32 170620d2c4d2SmrgxtermXftFirstChar(XftFont * xft) 170720d2c4d2Smrg{ 170820d2c4d2Smrg FcChar32 map[FC_CHARSET_MAP_SIZE]; 170920d2c4d2Smrg FcChar32 next; 171020d2c4d2Smrg FcChar32 first; 171120d2c4d2Smrg int i; 171220d2c4d2Smrg 171320d2c4d2Smrg first = FcCharSetFirstPage(xft->charset, map, &next); 171420d2c4d2Smrg for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) 171520d2c4d2Smrg if (map[i]) { 171620d2c4d2Smrg FcChar32 bits = map[i]; 1717fa3f02f3Smrg first += (FcChar32) i *32; 171820d2c4d2Smrg while (!(bits & 0x1)) { 171920d2c4d2Smrg bits >>= 1; 172020d2c4d2Smrg first++; 172120d2c4d2Smrg } 172220d2c4d2Smrg break; 172320d2c4d2Smrg } 172420d2c4d2Smrg return first; 172520d2c4d2Smrg} 172620d2c4d2Smrg 172720d2c4d2Smrgstatic FcChar32 172820d2c4d2SmrgxtermXftLastChar(XftFont * xft) 172920d2c4d2Smrg{ 173020d2c4d2Smrg FcChar32 this, last, next; 173120d2c4d2Smrg FcChar32 map[FC_CHARSET_MAP_SIZE]; 173220d2c4d2Smrg int i; 173320d2c4d2Smrg last = FcCharSetFirstPage(xft->charset, map, &next); 173420d2c4d2Smrg while ((this = FcCharSetNextPage(xft->charset, map, &next)) != FC_CHARSET_DONE) 173520d2c4d2Smrg last = this; 1736fa3f02f3Smrg last &= (FcChar32) ~ 0xff; 173720d2c4d2Smrg for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--) 173820d2c4d2Smrg if (map[i]) { 173920d2c4d2Smrg FcChar32 bits = map[i]; 1740fa3f02f3Smrg last += (FcChar32) i *32 + 31; 174120d2c4d2Smrg while (!(bits & 0x80000000)) { 174220d2c4d2Smrg last--; 174320d2c4d2Smrg bits <<= 1; 174420d2c4d2Smrg } 174520d2c4d2Smrg break; 174620d2c4d2Smrg } 174720d2c4d2Smrg return (long) last; 174820d2c4d2Smrg} 174920d2c4d2Smrg 1750fa3f02f3Smrg#if OPT_TRACE > 1 175120d2c4d2Smrgstatic void 175220d2c4d2SmrgdumpXft(XtermWidget xw, XTermXftFonts * data) 175320d2c4d2Smrg{ 175420d2c4d2Smrg XftFont *xft = data->font; 175520d2c4d2Smrg TScreen *screen = TScreenOf(xw); 175620d2c4d2Smrg VTwin *win = WhichVWin(screen); 175720d2c4d2Smrg 175820d2c4d2Smrg FcChar32 c; 175920d2c4d2Smrg FcChar32 first = xtermXftFirstChar(xft); 176020d2c4d2Smrg FcChar32 last = xtermXftLastChar(xft); 176120d2c4d2Smrg unsigned count = 0; 176220d2c4d2Smrg unsigned outside = 0; 176320d2c4d2Smrg 176420d2c4d2Smrg TRACE(("dumpXft {{\n")); 176520d2c4d2Smrg TRACE((" data range %#6x..%#6x\n", first, last)); 176620d2c4d2Smrg for (c = first; c <= last; ++c) { 176720d2c4d2Smrg if (FcCharSetHasChar(xft->charset, c)) { 176820d2c4d2Smrg int width = my_wcwidth((int) c); 176920d2c4d2Smrg XGlyphInfo extents; 177020d2c4d2Smrg 177120d2c4d2Smrg XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents); 177220d2c4d2Smrg TRACE(("%#6x %2d %.1f\n", c, width, 177320d2c4d2Smrg ((double) extents.width) / win->f_width)); 177420d2c4d2Smrg if (extents.width > win->f_width) 177520d2c4d2Smrg ++outside; 177620d2c4d2Smrg ++count; 177720d2c4d2Smrg } 177820d2c4d2Smrg } 177920d2c4d2Smrg TRACE(("}} %u total, %u outside\n", count, outside)); 178020d2c4d2Smrg} 178120d2c4d2Smrg#define DUMP_XFT(xw, data) dumpXft(xw, data) 178220d2c4d2Smrg#else 178320d2c4d2Smrg#define DUMP_XFT(xw, data) /* nothing */ 178420d2c4d2Smrg#endif 178520d2c4d2Smrg 1786956cc18dSsnjstatic void 1787956cc18dSsnjcheckXft(XtermWidget xw, XTermXftFonts * data, XftFont * xft) 1788956cc18dSsnj{ 1789956cc18dSsnj FcChar32 c; 1790956cc18dSsnj Dimension width = 0; 1791956cc18dSsnj 1792956cc18dSsnj data->font = xft; 1793956cc18dSsnj data->map.min_width = 0; 1794956cc18dSsnj data->map.max_width = (Dimension) xft->max_advance_width; 1795956cc18dSsnj 179620d2c4d2Smrg /* 179720d2c4d2Smrg * For each ASCII or ISO-8859-1 printable code, ask what its width is. 179820d2c4d2Smrg * Given the maximum width for those, we have a reasonable estimate of 179920d2c4d2Smrg * the single-column width. 180020d2c4d2Smrg * 180120d2c4d2Smrg * Ignore control characters - their extent information is misleading. 180220d2c4d2Smrg */ 1803956cc18dSsnj for (c = 32; c < 256; ++c) { 180420d2c4d2Smrg if (c >= 127 && c <= 159) 180520d2c4d2Smrg continue; 1806956cc18dSsnj if (FcCharSetHasChar(xft->charset, c)) { 1807956cc18dSsnj XGlyphInfo extents; 1808956cc18dSsnj 1809956cc18dSsnj XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents); 181020d2c4d2Smrg if (width < extents.width && extents.width <= data->map.max_width) { 1811956cc18dSsnj width = extents.width; 181220d2c4d2Smrg } 1813956cc18dSsnj } 1814956cc18dSsnj } 1815956cc18dSsnj data->map.min_width = width; 1816956cc18dSsnj data->map.mixed = (data->map.max_width >= (data->map.min_width + 1)); 1817956cc18dSsnj} 1818956cc18dSsnj 1819fa3f02f3Smrgstatic void 1820fa3f02f3SmrgreportXftFonts(XtermWidget xw, 1821fa3f02f3Smrg XftFont * fp, 1822fa3f02f3Smrg const char *name, 1823fa3f02f3Smrg const char *tag, 1824fa3f02f3Smrg XftPattern * match) 1825fa3f02f3Smrg{ 1826fa3f02f3Smrg if (resource.reportFonts) { 1827fa3f02f3Smrg char buffer[1024]; 1828fa3f02f3Smrg FcChar32 first_char = xtermXftFirstChar(fp); 1829fa3f02f3Smrg FcChar32 last_char = xtermXftLastChar(fp); 1830fa3f02f3Smrg FcChar32 ch; 1831fa3f02f3Smrg unsigned missing = 0; 1832fa3f02f3Smrg 1833fa3f02f3Smrg printf("Loaded XftFonts(%s:%s)\n", name, tag); 1834fa3f02f3Smrg 1835fa3f02f3Smrg for (ch = first_char; ch <= last_char; ++ch) { 1836fa3f02f3Smrg if (xtermXftMissing(xw, fp, ch)) { 1837fa3f02f3Smrg ++missing; 1838fa3f02f3Smrg } 1839fa3f02f3Smrg } 1840fa3f02f3Smrg printf("\t\tfirst char: %u\n", first_char); 1841fa3f02f3Smrg printf("\t\tlast char: %u\n", last_char); 1842fa3f02f3Smrg printf("\t\tmissing-chars: %u\n", missing); 1843fa3f02f3Smrg printf("\t\tpresent-chars: %u\n", (last_char - first_char) + 1 - missing); 1844fa3f02f3Smrg 1845fa3f02f3Smrg if (XftNameUnparse(match, buffer, (int) sizeof(buffer))) { 1846fa3f02f3Smrg char *target; 1847fa3f02f3Smrg char *source = buffer; 1848fa3f02f3Smrg while ((target = strtok(source, ":")) != 0) { 1849fa3f02f3Smrg printf("\t%s\n", target); 1850fa3f02f3Smrg source = 0; 1851fa3f02f3Smrg } 1852fa3f02f3Smrg } 1853fa3f02f3Smrg } 1854fa3f02f3Smrg} 1855fa3f02f3Smrg 1856d522f475Smrgstatic XftFont * 1857956cc18dSsnjxtermOpenXft(XtermWidget xw, const char *name, XftPattern * pat, const char *tag) 1858d522f475Smrg{ 1859956cc18dSsnj TScreen *screen = TScreenOf(xw); 1860956cc18dSsnj Display *dpy = screen->display; 1861d522f475Smrg XftPattern *match; 1862d522f475Smrg XftResult status; 1863d522f475Smrg XftFont *result = 0; 1864d522f475Smrg 1865d522f475Smrg if (pat != 0) { 1866d522f475Smrg match = XftFontMatch(dpy, DefaultScreen(dpy), pat, &status); 1867d522f475Smrg if (match != 0) { 1868d522f475Smrg result = XftFontOpenPattern(dpy, match); 1869d522f475Smrg if (result != 0) { 1870d522f475Smrg TRACE(("...matched %s font\n", tag)); 1871fa3f02f3Smrg reportXftFonts(xw, result, name, tag, match); 1872d522f475Smrg } else { 1873d522f475Smrg TRACE(("...could did not open %s font\n", tag)); 1874d522f475Smrg XftPatternDestroy(match); 1875956cc18dSsnj if (xw->misc.fontWarnings >= fwAlways) { 1876956cc18dSsnj TRACE(("OOPS cannot open %s font \"%s\"\n", tag, name)); 18770bd37d32Smrg xtermWarning("cannot open %s font \"%s\"\n", tag, name); 1878956cc18dSsnj } 1879d522f475Smrg } 1880d522f475Smrg } else { 1881d522f475Smrg TRACE(("...did not match %s font\n", tag)); 1882956cc18dSsnj if (xw->misc.fontWarnings >= fwResource) { 1883956cc18dSsnj TRACE(("OOPS: cannot match %s font \"%s\"\n", tag, name)); 18840bd37d32Smrg xtermWarning("cannot match %s font \"%s\"\n", tag, name); 1885956cc18dSsnj } 1886d522f475Smrg } 1887d522f475Smrg } 1888d522f475Smrg return result; 1889d522f475Smrg} 1890d522f475Smrg#endif 1891d522f475Smrg 1892d522f475Smrg#if OPT_RENDERFONT 1893d522f475Smrg#if OPT_SHIFT_FONTS 1894d522f475Smrg/* 1895d522f475Smrg * Don't make a dependency on the math library for a single function. 1896d522f475Smrg * (Newton Raphson). 1897d522f475Smrg */ 1898d522f475Smrgstatic double 18990bd37d32SmrgdimSquareRoot(double value) 1900d522f475Smrg{ 1901d522f475Smrg double result = 0.0; 1902d522f475Smrg if (value > 0.0) { 1903d522f475Smrg int n; 1904d522f475Smrg double older = value; 1905d522f475Smrg for (n = 0; n < 10; ++n) { 1906d522f475Smrg double delta = (older * older - value) / (2.0 * older); 1907d522f475Smrg double newer = older - delta; 1908d522f475Smrg older = newer; 1909d522f475Smrg result = newer; 1910d522f475Smrg if (delta > -0.001 && delta < 0.001) 1911d522f475Smrg break; 1912d522f475Smrg } 1913d522f475Smrg } 1914d522f475Smrg return result; 1915d522f475Smrg} 1916d522f475Smrg#endif 1917d522f475Smrg 1918d522f475Smrg/* 1919d522f475Smrg * Given the Xft font metrics, determine the actual font size. This is used 1920d522f475Smrg * for each font to ensure that normal, bold and italic fonts follow the same 1921d522f475Smrg * rule. 1922d522f475Smrg */ 1923d522f475Smrgstatic void 1924fa3f02f3SmrgsetRenderFontsize(TScreen *screen, VTwin * win, XftFont * font, const char *tag) 1925d522f475Smrg{ 1926d522f475Smrg if (font != 0) { 1927d522f475Smrg int width, height, ascent, descent; 1928d522f475Smrg 1929d522f475Smrg (void) screen; 1930d522f475Smrg 1931d522f475Smrg width = font->max_advance_width; 1932d522f475Smrg height = font->height; 1933d522f475Smrg ascent = font->ascent; 1934d522f475Smrg descent = font->descent; 1935d522f475Smrg if (height < ascent + descent) { 1936d522f475Smrg TRACE(("...increase height from %d\n", height)); 1937d522f475Smrg height = ascent + descent; 1938d522f475Smrg } 1939d522f475Smrg if (is_double_width_font_xft(screen->display, font)) { 1940d522f475Smrg TRACE(("...reduced width from %d\n", width)); 1941d522f475Smrg width >>= 1; 1942d522f475Smrg } 1943d522f475Smrg if (tag == 0) { 19440bd37d32Smrg SetFontWidth(screen, win, width); 19450bd37d32Smrg SetFontHeight(screen, win, height); 1946d522f475Smrg win->f_ascent = ascent; 1947d522f475Smrg win->f_descent = descent; 1948d522f475Smrg TRACE(("setRenderFontsize result %dx%d (%d+%d)\n", 1949d522f475Smrg width, height, ascent, descent)); 1950d522f475Smrg } else if (win->f_width < width || 1951d522f475Smrg win->f_height < height || 1952d522f475Smrg win->f_ascent < ascent || 1953d522f475Smrg win->f_descent < descent) { 1954d522f475Smrg TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n", 1955d522f475Smrg tag, 1956d522f475Smrg win->f_width, win->f_height, win->f_ascent, win->f_descent, 1957d522f475Smrg width, height, ascent, descent)); 1958d522f475Smrg 19590bd37d32Smrg SetFontWidth(screen, win, width); 19600bd37d32Smrg SetFontHeight(screen, win, height); 1961d522f475Smrg win->f_ascent = ascent; 1962d522f475Smrg win->f_descent = descent; 1963d522f475Smrg } else { 1964d522f475Smrg TRACE(("setRenderFontsize %s unchanged\n", tag)); 1965d522f475Smrg } 1966d522f475Smrg } 1967d522f475Smrg} 1968d522f475Smrg#endif 1969d522f475Smrg 197020d2c4d2Smrgstatic void 197120d2c4d2SmrgcheckFontInfo(int value, const char *tag) 197220d2c4d2Smrg{ 197320d2c4d2Smrg if (value == 0) { 19740bd37d32Smrg xtermWarning("Selected font has no non-zero %s for ISO-8859-1 encoding\n", tag); 197520d2c4d2Smrg exit(1); 197620d2c4d2Smrg } 197720d2c4d2Smrg} 197820d2c4d2Smrg 197920d2c4d2Smrg#if OPT_RENDERFONT 198020d2c4d2Smrgvoid 1981fa3f02f3SmrgxtermCloseXft(TScreen *screen, XTermXftFonts * pub) 198220d2c4d2Smrg{ 198320d2c4d2Smrg if (pub->font != 0) { 198420d2c4d2Smrg XftFontClose(screen->display, pub->font); 198520d2c4d2Smrg pub->font = 0; 198620d2c4d2Smrg } 198720d2c4d2Smrg} 198820d2c4d2Smrg 198920d2c4d2Smrg/* 199020d2c4d2Smrg * Get the faceName/faceDoublesize resource setting. Strip off "xft:", which 19910bd37d32Smrg * is not recognized by XftNameParse(). 199220d2c4d2Smrg */ 1993492d43a5SmrgString 199420d2c4d2SmrggetFaceName(XtermWidget xw, Bool wideName GCC_UNUSED) 199520d2c4d2Smrg{ 199620d2c4d2Smrg#if OPT_RENDERWIDE 1997492d43a5Smrg String result = (wideName 1998492d43a5Smrg ? xw->misc.face_wide_name 1999492d43a5Smrg : xw->misc.face_name); 200020d2c4d2Smrg#else 2001492d43a5Smrg String result = xw->misc.face_name; 200220d2c4d2Smrg#endif 200320d2c4d2Smrg if (!IsEmpty(result) && !strncmp(result, "xft:", (size_t) 4)) 200420d2c4d2Smrg result += 4; 200520d2c4d2Smrg return x_nonempty(result); 200620d2c4d2Smrg} 200720d2c4d2Smrg 200820d2c4d2Smrg/* 200920d2c4d2Smrg * If we change the faceName, we'll have to re-acquire all of the fonts that 201020d2c4d2Smrg * are derived from it. 201120d2c4d2Smrg */ 201220d2c4d2Smrgvoid 201320d2c4d2SmrgsetFaceName(XtermWidget xw, const char *value) 201420d2c4d2Smrg{ 201520d2c4d2Smrg TScreen *screen = TScreenOf(xw); 201620d2c4d2Smrg int n; 20170bd37d32Smrg Boolean changed = (Boolean) ((xw->misc.face_name == 0) 20180bd37d32Smrg || strcmp(xw->misc.face_name, value)); 201920d2c4d2Smrg 20200bd37d32Smrg if (changed) { 20210bd37d32Smrg xw->misc.face_name = x_strdup(value); 20220bd37d32Smrg for (n = 0; n < NMENUFONTS; ++n) { 20230bd37d32Smrg xw->misc.face_size[n] = -1.0; 20240bd37d32Smrg xtermCloseXft(screen, &(screen->renderFontNorm[n])); 20250bd37d32Smrg xtermCloseXft(screen, &(screen->renderFontBold[n])); 20260bd37d32Smrg xtermCloseXft(screen, &(screen->renderFontBold[n])); 202720d2c4d2Smrg#if OPT_RENDERWIDE 20280bd37d32Smrg xtermCloseXft(screen, &(screen->renderWideNorm[n])); 20290bd37d32Smrg xtermCloseXft(screen, &(screen->renderWideBold[n])); 20300bd37d32Smrg xtermCloseXft(screen, &(screen->renderWideItal[n])); 203120d2c4d2Smrg#endif 20320bd37d32Smrg } 203320d2c4d2Smrg } 203420d2c4d2Smrg} 203520d2c4d2Smrg#endif 203620d2c4d2Smrg 2037d522f475Smrg/* 2038d522f475Smrg * Compute useful values for the font/window sizes 2039d522f475Smrg */ 2040d522f475Smrgvoid 2041d522f475SmrgxtermComputeFontInfo(XtermWidget xw, 2042d522f475Smrg VTwin * win, 2043d522f475Smrg XFontStruct * font, 2044d522f475Smrg int sbwidth) 2045d522f475Smrg{ 2046956cc18dSsnj TScreen *screen = TScreenOf(xw); 2047d522f475Smrg 2048d522f475Smrg int i, j, width, height; 2049492d43a5Smrg#if OPT_RENDERFONT 2050492d43a5Smrg int fontnum = screen->menu_font_number; 2051492d43a5Smrg#endif 2052d522f475Smrg 2053d522f475Smrg#if OPT_RENDERFONT 2054d522f475Smrg /* 2055d522f475Smrg * xterm contains a lot of references to fonts, assuming they are fixed 2056d522f475Smrg * size. This chunk of code overrides the actual font-selection (see 2057d522f475Smrg * drawXtermText()), if the user has selected render-font. All of the 2058d522f475Smrg * font-loading for fixed-fonts still goes on whether or not this chunk 2059d522f475Smrg * overrides it. 2060d522f475Smrg */ 2061492d43a5Smrg if (UsingRenderFont(xw) && fontnum >= 0) { 2062492d43a5Smrg String face_name = getFaceName(xw, False); 2063956cc18dSsnj XftFont *norm = screen->renderFontNorm[fontnum].font; 2064956cc18dSsnj XftFont *bold = screen->renderFontBold[fontnum].font; 2065956cc18dSsnj XftFont *ital = screen->renderFontItal[fontnum].font; 2066d522f475Smrg#if OPT_RENDERWIDE 2067956cc18dSsnj XftFont *wnorm = screen->renderWideNorm[fontnum].font; 2068956cc18dSsnj XftFont *wbold = screen->renderWideBold[fontnum].font; 2069956cc18dSsnj XftFont *wital = screen->renderWideItal[fontnum].font; 2070d522f475Smrg#endif 2071d522f475Smrg 207220d2c4d2Smrg if (norm == 0 && face_name) { 2073d522f475Smrg XftPattern *pat; 20740bd37d32Smrg double face_size; 2075d522f475Smrg 20760bd37d32Smrg TRACE(("xtermComputeFontInfo font %d: norm(face %s, size %.1f)\n", 2077492d43a5Smrg fontnum, face_name, 2078d522f475Smrg xw->misc.face_size[fontnum])); 2079d522f475Smrg 20800bd37d32Smrg fillInFaceSize(xw, fontnum); 20810bd37d32Smrg face_size = xw->misc.face_size[fontnum]; 2082d522f475Smrg 2083d522f475Smrg /* 2084d522f475Smrg * By observation (there is no documentation), XftPatternBuild is 2085d522f475Smrg * cumulative. Build the bold- and italic-patterns on top of the 2086d522f475Smrg * normal pattern. 2087d522f475Smrg */ 2088d522f475Smrg#define NormXftPattern \ 2089d522f475Smrg XFT_FAMILY, XftTypeString, "mono", \ 2090d522f475Smrg XFT_SIZE, XftTypeDouble, face_size, \ 2091d522f475Smrg XFT_SPACING, XftTypeInteger, XFT_MONO 2092d522f475Smrg 2093d522f475Smrg#define BoldXftPattern(norm) \ 2094d522f475Smrg XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \ 2095d522f475Smrg XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width 2096d522f475Smrg 2097d522f475Smrg#define ItalXftPattern(norm) \ 2098d522f475Smrg XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \ 2099d522f475Smrg XFT_CHAR_WIDTH, XftTypeInteger, norm->max_advance_width 2100d522f475Smrg 210120d2c4d2Smrg if ((pat = XftNameParse(face_name)) != 0) { 210220d2c4d2Smrg#define OPEN_XFT(tag) xtermOpenXft(xw, face_name, pat, tag) 2103d522f475Smrg XftPatternBuild(pat, 2104d522f475Smrg NormXftPattern, 2105d522f475Smrg (void *) 0); 2106956cc18dSsnj norm = OPEN_XFT("normal"); 2107d522f475Smrg 2108d522f475Smrg if (norm != 0) { 2109d522f475Smrg XftPatternBuild(pat, 2110d522f475Smrg BoldXftPattern(norm), 2111d522f475Smrg (void *) 0); 2112956cc18dSsnj bold = OPEN_XFT("bold"); 2113d522f475Smrg 2114d522f475Smrg#if OPT_ISO_COLORS 2115d522f475Smrg if (screen->italicULMode 211620d2c4d2Smrg && (pat = XftNameParse(face_name)) != 0) { 2117d522f475Smrg XftPatternBuild(pat, 2118d522f475Smrg NormXftPattern, 2119d522f475Smrg ItalXftPattern(norm), 2120d522f475Smrg (void *) 0); 2121956cc18dSsnj ital = OPEN_XFT("italic"); 2122d522f475Smrg } 2123d522f475Smrg#endif /* OPT_ISO_COLORS */ 2124956cc18dSsnj#undef OPEN_XFT 2125d522f475Smrg 2126d522f475Smrg /* 2127d522f475Smrg * FIXME: just assume that the corresponding font has no 2128d522f475Smrg * graphics characters. 2129d522f475Smrg */ 2130d522f475Smrg if (screen->fnt_boxes) { 2131d522f475Smrg screen->fnt_boxes = False; 2132d522f475Smrg TRACE(("Xft opened - will %suse internal line-drawing characters\n", 2133d522f475Smrg screen->fnt_boxes ? "not " : "")); 2134d522f475Smrg } 2135d522f475Smrg } 2136d522f475Smrg 2137d522f475Smrg XftPatternDestroy(pat); 2138d522f475Smrg } 2139d522f475Smrg 2140d522f475Smrg CACHE_XFT(screen->renderFontNorm, norm); 2141d522f475Smrg CACHE_XFT(screen->renderFontBold, bold); 2142d522f475Smrg CACHE_XFT(screen->renderFontItal, ital); 2143d522f475Smrg 2144d522f475Smrg /* 2145d522f475Smrg * See xtermXftDrawString(). 2146d522f475Smrg */ 2147d522f475Smrg#if OPT_RENDERWIDE 2148d522f475Smrg if (norm != 0 && screen->wide_chars) { 2149d522f475Smrg int char_width = norm->max_advance_width * 2; 2150956cc18dSsnj#ifdef FC_ASPECT 2151956cc18dSsnj double aspect = ((xw->misc.face_wide_name 2152956cc18dSsnj || screen->renderFontNorm[fontnum].map.mixed) 2153956cc18dSsnj ? 1.0 2154956cc18dSsnj : 2.0); 2155956cc18dSsnj#endif 2156d522f475Smrg 215720d2c4d2Smrg face_name = getFaceName(xw, True); 2158d522f475Smrg TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n", 215920d2c4d2Smrg NonNull(face_name), 2160d522f475Smrg char_width)); 2161d522f475Smrg 2162d522f475Smrg#define WideXftPattern \ 2163d522f475Smrg XFT_FAMILY, XftTypeString, "mono", \ 2164d522f475Smrg XFT_SIZE, XftTypeDouble, face_size, \ 2165d522f475Smrg XFT_SPACING, XftTypeInteger, XFT_MONO 2166d522f475Smrg 216720d2c4d2Smrg if (face_name && (pat = XftNameParse(face_name)) != 0) { 2168956cc18dSsnj#define OPEN_XFT(tag) xtermOpenXft(xw, face_name, pat, tag) 2169d522f475Smrg XftPatternBuild(pat, 2170d522f475Smrg WideXftPattern, 2171d522f475Smrg XFT_CHAR_WIDTH, XftTypeInteger, char_width, 2172956cc18dSsnj#ifdef FC_ASPECT 2173956cc18dSsnj FC_ASPECT, XftTypeDouble, aspect, 2174956cc18dSsnj#endif 2175d522f475Smrg (void *) 0); 2176956cc18dSsnj wnorm = OPEN_XFT("wide"); 2177d522f475Smrg 2178d522f475Smrg if (wnorm != 0) { 2179d522f475Smrg XftPatternBuild(pat, 2180d522f475Smrg WideXftPattern, 2181d522f475Smrg BoldXftPattern(wnorm), 2182d522f475Smrg (void *) 0); 2183956cc18dSsnj wbold = OPEN_XFT("wide-bold"); 2184d522f475Smrg 2185d522f475Smrg#if OPT_ISO_COLORS 2186d522f475Smrg if (screen->italicULMode 2187d522f475Smrg && (pat = XftNameParse(face_name)) != 0) { 2188d522f475Smrg XftPatternBuild(pat, 2189d522f475Smrg WideXftPattern, 2190d522f475Smrg ItalXftPattern(wnorm), 2191d522f475Smrg (void *) 0); 2192956cc18dSsnj wital = OPEN_XFT("wide-italic"); 2193d522f475Smrg } 2194d522f475Smrg#endif 2195956cc18dSsnj#undef OPEN_XFT 2196d522f475Smrg } 2197d522f475Smrg XftPatternDestroy(pat); 2198d522f475Smrg } 2199d522f475Smrg 2200d522f475Smrg CACHE_XFT(screen->renderWideNorm, wnorm); 2201d522f475Smrg CACHE_XFT(screen->renderWideBold, wbold); 2202d522f475Smrg CACHE_XFT(screen->renderWideItal, wital); 2203d522f475Smrg } 2204d522f475Smrg#endif /* OPT_RENDERWIDE */ 2205d522f475Smrg } 2206d522f475Smrg if (norm == 0) { 22072eaa94a1Schristos TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum)); 22080bd37d32Smrg xw->work.render_font = False; 2209d522f475Smrg update_font_renderfont(); 2210d522f475Smrg /* now we will fall through into the bitmap fonts */ 2211d522f475Smrg } else { 2212d522f475Smrg setRenderFontsize(screen, win, norm, NULL); 2213d522f475Smrg setRenderFontsize(screen, win, bold, "bold"); 2214d522f475Smrg setRenderFontsize(screen, win, ital, "ital"); 221520d2c4d2Smrg#if OPT_BOX_CHARS 221620d2c4d2Smrg setupPackedFonts(xw); 221720d2c4d2Smrg 221820d2c4d2Smrg if (screen->force_packed) { 221920d2c4d2Smrg XTermXftFonts *use = &(screen->renderFontNorm[fontnum]); 22200bd37d32Smrg SetFontHeight(screen, win, use->font->ascent + use->font->descent); 22210bd37d32Smrg SetFontWidth(screen, win, use->map.min_width); 222220d2c4d2Smrg TRACE(("...packed TrueType font %dx%d vs %d\n", 222320d2c4d2Smrg win->f_height, 222420d2c4d2Smrg win->f_width, 222520d2c4d2Smrg use->map.max_width)); 222620d2c4d2Smrg } 222720d2c4d2Smrg#endif 222820d2c4d2Smrg DUMP_XFT(xw, &(screen->renderFontNorm[fontnum])); 2229d522f475Smrg } 2230d522f475Smrg } 2231d522f475Smrg /* 2232d522f475Smrg * Are we handling a bitmap font? 2233d522f475Smrg */ 2234492d43a5Smrg else 2235d522f475Smrg#endif /* OPT_RENDERFONT */ 2236d522f475Smrg { 223720d2c4d2Smrg if (is_double_width_font(font) && !(screen->fnt_prop)) { 22380bd37d32Smrg SetFontWidth(screen, win, font->min_bounds.width); 2239d522f475Smrg } else { 22400bd37d32Smrg SetFontWidth(screen, win, font->max_bounds.width); 2241d522f475Smrg } 22420bd37d32Smrg SetFontHeight(screen, win, font->ascent + font->descent); 2243d522f475Smrg win->f_ascent = font->ascent; 2244d522f475Smrg win->f_descent = font->descent; 2245d522f475Smrg } 2246d522f475Smrg i = 2 * screen->border + sbwidth; 2247d522f475Smrg j = 2 * screen->border; 2248d522f475Smrg width = MaxCols(screen) * win->f_width + i; 2249d522f475Smrg height = MaxRows(screen) * win->f_height + j; 2250956cc18dSsnj win->fullwidth = (Dimension) width; 2251956cc18dSsnj win->fullheight = (Dimension) height; 2252d522f475Smrg win->width = width - i; 2253d522f475Smrg win->height = height - j; 2254d522f475Smrg 2255d522f475Smrg TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n", 2256d522f475Smrg win->height, 2257d522f475Smrg win->width, 2258d522f475Smrg win->fullheight, 2259d522f475Smrg win->fullwidth, 2260d522f475Smrg win->f_height, 2261d522f475Smrg win->f_width, 2262d522f475Smrg win->f_ascent, 2263d522f475Smrg win->f_descent)); 226420d2c4d2Smrg 226520d2c4d2Smrg checkFontInfo(win->f_height, "height"); 226620d2c4d2Smrg checkFontInfo(win->f_width, "width"); 2267d522f475Smrg} 2268d522f475Smrg 2269d522f475Smrg/* save this information as a side-effect for double-sized characters */ 2270d522f475Smrgvoid 2271fa3f02f3SmrgxtermSaveFontInfo(TScreen *screen, XFontStruct * font) 2272d522f475Smrg{ 2273956cc18dSsnj screen->fnt_wide = (Dimension) (font->max_bounds.width); 2274956cc18dSsnj screen->fnt_high = (Dimension) (font->ascent + font->descent); 2275d522f475Smrg TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide)); 2276d522f475Smrg} 2277d522f475Smrg 2278d522f475Smrg/* 2279d522f475Smrg * After loading a new font, update the structures that use its size. 2280d522f475Smrg */ 2281d522f475Smrgvoid 2282d522f475SmrgxtermUpdateFontInfo(XtermWidget xw, Bool doresize) 2283d522f475Smrg{ 2284956cc18dSsnj TScreen *screen = TScreenOf(xw); 2285d522f475Smrg 2286d522f475Smrg int scrollbar_width; 2287d522f475Smrg VTwin *win = &(screen->fullVwin); 2288d522f475Smrg 2289d522f475Smrg scrollbar_width = (xw->misc.scrollbar 2290d522f475Smrg ? (screen->scrollWidget->core.width + 2291d522f475Smrg BorderWidth(screen->scrollWidget)) 2292d522f475Smrg : 0); 2293d522f475Smrg xtermComputeFontInfo(xw, win, screen->fnts[fNorm].fs, scrollbar_width); 2294d522f475Smrg xtermSaveFontInfo(screen, screen->fnts[fNorm].fs); 2295d522f475Smrg 2296d522f475Smrg if (doresize) { 2297d522f475Smrg if (VWindow(screen)) { 2298d522f475Smrg xtermClear(xw); 2299d522f475Smrg } 2300d522f475Smrg TRACE(("xtermUpdateFontInfo {{\n")); 2301d522f475Smrg DoResizeScreen(xw); /* set to the new natural size */ 2302d522f475Smrg ResizeScrollBar(xw); 2303d522f475Smrg Redraw(); 2304d522f475Smrg TRACE(("... }} xtermUpdateFontInfo\n")); 2305d522f475Smrg#ifdef SCROLLBAR_RIGHT 2306d522f475Smrg updateRightScrollbar(xw); 2307d522f475Smrg#endif 2308d522f475Smrg } 2309d522f475Smrg xtermSetCursorBox(screen); 2310d522f475Smrg} 2311d522f475Smrg 2312fa3f02f3Smrg#if OPT_BOX_CHARS || OPT_REPORT_FONTS 2313d522f475Smrg 2314d522f475Smrg/* 2315d522f475Smrg * Returns true if the given character is missing from the specified font. 2316d522f475Smrg */ 2317d522f475SmrgBool 2318956cc18dSsnjxtermMissingChar(unsigned ch, XTermFonts * font) 2319d522f475Smrg{ 2320956cc18dSsnj Bool result = False; 2321956cc18dSsnj XFontStruct *fs = font->fs; 2322fa3f02f3Smrg XCharStruct *pc = 0; 2323d522f475Smrg 2324956cc18dSsnj if (fs->max_byte1 == 0) { 2325d522f475Smrg#if OPT_WIDE_CHARS 2326fa3f02f3Smrg if (ch < 256) 2327956cc18dSsnj#endif 2328fa3f02f3Smrg { 2329fa3f02f3Smrg CI_GET_CHAR_INFO_1D(fs, E2A(ch), pc); 2330fa3f02f3Smrg } 2331956cc18dSsnj } 2332d522f475Smrg#if OPT_WIDE_CHARS 2333956cc18dSsnj else { 2334fa3f02f3Smrg unsigned row = (ch >> 8); 2335fa3f02f3Smrg unsigned col = (ch & 0xff); 2336fa3f02f3Smrg CI_GET_CHAR_INFO_2D(fs, row, col, pc); 2337956cc18dSsnj } 2338d522f475Smrg#endif 2339d522f475Smrg 2340fa3f02f3Smrg if (pc == 0 || CI_NONEXISTCHAR(pc)) { 2341956cc18dSsnj TRACE(("xtermMissingChar %#04x (!exists)\n", ch)); 2342956cc18dSsnj result = True; 2343d522f475Smrg } 2344fa3f02f3Smrg if (ch < KNOWN_MISSING) { 2345956cc18dSsnj font->known_missing[ch] = (Char) (result ? 2 : 1); 2346d522f475Smrg } 2347956cc18dSsnj return result; 2348d522f475Smrg} 2349fa3f02f3Smrg#endif 2350d522f475Smrg 2351fa3f02f3Smrg#if OPT_BOX_CHARS 2352d522f475Smrg/* 2353d522f475Smrg * The grid is arbitrary, enough resolution that nothing's lost in 2354d522f475Smrg * initialization. 2355d522f475Smrg */ 2356d522f475Smrg#define BOX_HIGH 60 2357d522f475Smrg#define BOX_WIDE 60 2358d522f475Smrg 2359d522f475Smrg#define MID_HIGH (BOX_HIGH/2) 2360d522f475Smrg#define MID_WIDE (BOX_WIDE/2) 2361d522f475Smrg 2362d522f475Smrg#define CHR_WIDE ((9*BOX_WIDE)/10) 2363d522f475Smrg#define CHR_HIGH ((9*BOX_HIGH)/10) 2364d522f475Smrg 2365d522f475Smrg/* 2366d522f475Smrg * ...since we'll scale the values anyway. 2367d522f475Smrg */ 2368e39b573cSmrg#define SCALED_X(n) ((int)(n) * (((int) font_width) - 1)) / (BOX_WIDE-1) 2369e39b573cSmrg#define SCALED_Y(n) ((int)(n) * (((int) font_height) - 1)) / (BOX_HIGH-1) 2370e39b573cSmrg#define SCALE_X(n) n = SCALED_X(n) 2371e39b573cSmrg#define SCALE_Y(n) n = SCALED_Y(n) 2372d522f475Smrg 2373d522f475Smrg#define SEG(x0,y0,x1,y1) x0,y0, x1,y1 2374d522f475Smrg 2375d522f475Smrg/* 2376d522f475Smrg * Draw the given graphic character, if it is simple enough (i.e., a 2377d522f475Smrg * line-drawing character). 2378d522f475Smrg */ 2379d522f475Smrgvoid 2380d522f475SmrgxtermDrawBoxChar(XtermWidget xw, 2381d522f475Smrg unsigned ch, 2382d522f475Smrg unsigned flags, 2383d522f475Smrg GC gc, 2384d522f475Smrg int x, 2385d522f475Smrg int y, 2386d522f475Smrg int cells) 2387d522f475Smrg{ 2388956cc18dSsnj TScreen *screen = TScreenOf(xw); 2389d522f475Smrg /* *INDENT-OFF* */ 2390d522f475Smrg static const short glyph_ht[] = { 2391d522f475Smrg SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,5*MID_HIGH/6), /* H */ 2392d522f475Smrg SEG(6*BOX_WIDE/10, 0, 6*BOX_WIDE/10,5*MID_HIGH/6), 2393d522f475Smrg SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12), 2394d522f475Smrg SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 2395d522f475Smrg SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 2396d522f475Smrg -1 2397d522f475Smrg }, glyph_ff[] = { 2398d522f475Smrg SEG(1*BOX_WIDE/10, 0, 6*BOX_WIDE/10, 0), /* F */ 2399d522f475Smrg SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12), 2400d522f475Smrg SEG(1*BOX_WIDE/10, 0, 0*BOX_WIDE/3, 5*MID_HIGH/6), 2401d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 2402d522f475Smrg SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 2403d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 2404d522f475Smrg -1 2405d522f475Smrg }, glyph_lf[] = { 2406d522f475Smrg SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,9*MID_HIGH/12), /* L */ 2407d522f475Smrg SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12), 2408d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 2409d522f475Smrg SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 2410d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 2411d522f475Smrg -1 2412d522f475Smrg }, glyph_nl[] = { 2413d522f475Smrg SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10, 0), /* N */ 2414d522f475Smrg SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/6, 5*MID_HIGH/6), 2415d522f475Smrg SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 2416d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), /* L */ 2417d522f475Smrg SEG(1*BOX_WIDE/3, CHR_HIGH, CHR_WIDE, CHR_HIGH), 2418d522f475Smrg -1 2419d522f475Smrg }, glyph_vt[] = { 2420d522f475Smrg SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/12,5*MID_HIGH/6), /* V */ 2421d522f475Smrg SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 2422d522f475Smrg SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 2423d522f475Smrg SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 2424d522f475Smrg -1 2425d522f475Smrg }, plus_or_minus[] = 2426d522f475Smrg { 2427d522f475Smrg SEG( 0, 5*BOX_HIGH/6, CHR_WIDE, 5*BOX_HIGH/6), 2428d522f475Smrg SEG( MID_WIDE, 2*BOX_HIGH/6, MID_WIDE, 4*BOX_HIGH/6), 2429d522f475Smrg SEG( 0, 3*BOX_HIGH/6, CHR_WIDE, 3*BOX_HIGH/6), 2430d522f475Smrg -1 2431d522f475Smrg }, lower_right_corner[] = 2432d522f475Smrg { 2433d522f475Smrg SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 2434d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, 0), 2435d522f475Smrg -1 2436d522f475Smrg }, upper_right_corner[] = 2437d522f475Smrg { 2438d522f475Smrg SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 2439d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 2440d522f475Smrg -1 2441d522f475Smrg }, upper_left_corner[] = 2442d522f475Smrg { 2443d522f475Smrg SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 2444d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 2445d522f475Smrg -1 2446d522f475Smrg }, lower_left_corner[] = 2447d522f475Smrg { 2448d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 2449d522f475Smrg SEG( MID_WIDE, MID_WIDE, BOX_WIDE, MID_HIGH), 2450d522f475Smrg -1 2451d522f475Smrg }, cross[] = 2452d522f475Smrg { 2453d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 2454d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 2455d522f475Smrg -1 2456d522f475Smrg }, scan_line_1[] = 2457d522f475Smrg { 2458d522f475Smrg SEG( 0, 0, BOX_WIDE, 0), 2459d522f475Smrg -1 2460d522f475Smrg }, scan_line_3[] = 2461d522f475Smrg { 2462d522f475Smrg SEG( 0, BOX_HIGH/4, BOX_WIDE, BOX_HIGH/4), 2463d522f475Smrg -1 2464d522f475Smrg }, scan_line_7[] = 2465d522f475Smrg { 2466d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 2467d522f475Smrg -1 2468d522f475Smrg }, scan_line_9[] = 2469d522f475Smrg { 2470d522f475Smrg SEG( 0, 3*BOX_HIGH/4, BOX_WIDE, 3*BOX_HIGH/4), 2471d522f475Smrg -1 2472d522f475Smrg }, horizontal_line[] = 2473d522f475Smrg { 2474d522f475Smrg SEG( 0, BOX_HIGH, BOX_WIDE, BOX_HIGH), 2475d522f475Smrg -1 2476d522f475Smrg }, left_tee[] = 2477d522f475Smrg { 2478d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 2479d522f475Smrg SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 2480d522f475Smrg -1 2481d522f475Smrg }, right_tee[] = 2482d522f475Smrg { 2483d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 2484d522f475Smrg SEG( MID_WIDE, MID_HIGH, 0, MID_HIGH), 2485d522f475Smrg -1 2486d522f475Smrg }, bottom_tee[] = 2487d522f475Smrg { 2488d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 2489d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 2490d522f475Smrg -1 2491d522f475Smrg }, top_tee[] = 2492d522f475Smrg { 2493d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 2494d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 2495d522f475Smrg -1 2496d522f475Smrg }, vertical_line[] = 2497d522f475Smrg { 2498d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 2499d522f475Smrg -1 2500d522f475Smrg }, less_than_or_equal[] = 2501d522f475Smrg { 2502d522f475Smrg SEG( CHR_WIDE, BOX_HIGH/3, 0, MID_HIGH), 2503d522f475Smrg SEG( CHR_WIDE, 2*BOX_HIGH/3, 0, MID_HIGH), 2504d522f475Smrg SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 2505d522f475Smrg -1 2506d522f475Smrg }, greater_than_or_equal[] = 2507d522f475Smrg { 2508d522f475Smrg SEG( 0, BOX_HIGH/3, CHR_WIDE, MID_HIGH), 2509d522f475Smrg SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, MID_HIGH), 2510d522f475Smrg SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 2511d522f475Smrg -1 2512d522f475Smrg }, greek_pi[] = 2513d522f475Smrg { 2514d522f475Smrg SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 2515d522f475Smrg SEG(5*CHR_WIDE/6, MID_HIGH, 5*CHR_WIDE/6, CHR_HIGH), 2516d522f475Smrg SEG(2*CHR_WIDE/6, MID_HIGH, 2*CHR_WIDE/6, CHR_HIGH), 2517d522f475Smrg -1 2518d522f475Smrg }, not_equal_to[] = 2519d522f475Smrg { 2520d522f475Smrg SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3, CHR_HIGH), 2521d522f475Smrg SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, 2*BOX_HIGH/3), 2522d522f475Smrg SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 2523d522f475Smrg -1 2524d522f475Smrg }; 2525d522f475Smrg /* *INDENT-ON* */ 2526d522f475Smrg 2527d522f475Smrg static const short *lines[] = 2528d522f475Smrg { 2529d522f475Smrg 0, /* 00 (unused) */ 2530d522f475Smrg 0, /* 01 diamond */ 2531d522f475Smrg 0, /* 02 box */ 2532d522f475Smrg glyph_ht, /* 03 HT */ 2533d522f475Smrg glyph_ff, /* 04 FF */ 2534d522f475Smrg 0, /* 05 CR */ 2535d522f475Smrg glyph_lf, /* 06 LF */ 2536d522f475Smrg 0, /* 07 degrees (small circle) */ 2537d522f475Smrg plus_or_minus, /* 08 */ 2538d522f475Smrg glyph_nl, /* 09 */ 2539d522f475Smrg glyph_vt, /* 0A */ 2540d522f475Smrg lower_right_corner, /* 0B */ 2541d522f475Smrg upper_right_corner, /* 0C */ 2542d522f475Smrg upper_left_corner, /* 0D */ 2543d522f475Smrg lower_left_corner, /* 0E */ 2544d522f475Smrg cross, /* 0F */ 2545d522f475Smrg scan_line_1, /* 10 */ 2546d522f475Smrg scan_line_3, /* 11 */ 2547d522f475Smrg scan_line_7, /* 12 */ 2548d522f475Smrg scan_line_9, /* 13 */ 2549d522f475Smrg horizontal_line, /* 14 */ 2550d522f475Smrg left_tee, /* 15 */ 2551d522f475Smrg right_tee, /* 16 */ 2552d522f475Smrg bottom_tee, /* 17 */ 2553d522f475Smrg top_tee, /* 18 */ 2554d522f475Smrg vertical_line, /* 19 */ 2555d522f475Smrg less_than_or_equal, /* 1A */ 2556d522f475Smrg greater_than_or_equal, /* 1B */ 2557d522f475Smrg greek_pi, /* 1C */ 2558d522f475Smrg not_equal_to, /* 1D */ 2559d522f475Smrg 0, /* 1E LB */ 2560d522f475Smrg 0, /* 1F bullet */ 2561d522f475Smrg }; 2562d522f475Smrg 2563d522f475Smrg GC gc2; 2564d522f475Smrg CgsEnum cgsId = (ch == 2) ? gcDots : gcLine; 2565d522f475Smrg VTwin *cgsWin = WhichVWin(screen); 2566d522f475Smrg const short *p; 2567956cc18dSsnj unsigned font_width = (unsigned) (((flags & DOUBLEWFONT) ? 2 : 1) * screen->fnt_wide); 2568956cc18dSsnj unsigned font_height = (unsigned) (((flags & DOUBLEHFONT) ? 2 : 1) * screen->fnt_high); 2569d522f475Smrg 2570d522f475Smrg if (cells > 1) 2571956cc18dSsnj font_width *= (unsigned) cells; 2572d522f475Smrg 2573d522f475Smrg#if OPT_WIDE_CHARS 2574d522f475Smrg /* 2575d522f475Smrg * Try to show line-drawing characters if we happen to be in UTF-8 2576d522f475Smrg * mode, but have gotten an old-style font. 2577d522f475Smrg */ 2578d522f475Smrg if (screen->utf8_mode 2579d522f475Smrg#if OPT_RENDERFONT 2580d522f475Smrg && !UsingRenderFont(xw) 2581d522f475Smrg#endif 2582d522f475Smrg && (ch > 127) 2583d522f475Smrg && (ch != UCS_REPL)) { 2584d522f475Smrg unsigned n; 2585d522f475Smrg for (n = 1; n < 32; n++) { 2586d522f475Smrg if (dec2ucs(n) == ch 258720d2c4d2Smrg && !((flags & BOLD) 258820d2c4d2Smrg ? IsXtermMissingChar(screen, n, &screen->fnts[fBold]) 258920d2c4d2Smrg : IsXtermMissingChar(screen, n, &screen->fnts[fNorm]))) { 2590d522f475Smrg TRACE(("...use xterm-style linedrawing\n")); 2591d522f475Smrg ch = n; 2592d522f475Smrg break; 2593d522f475Smrg } 2594d522f475Smrg } 2595d522f475Smrg } 2596d522f475Smrg#endif 2597d522f475Smrg 2598d522f475Smrg TRACE(("DRAW_BOX(%d) cell %dx%d at %d,%d%s\n", 2599d522f475Smrg ch, font_height, font_width, y, x, 2600d522f475Smrg (ch >= (sizeof(lines) / sizeof(lines[0])) 2601d522f475Smrg ? "-BAD" 2602d522f475Smrg : ""))); 2603d522f475Smrg 2604d522f475Smrg if (cgsId == gcDots) { 2605d522f475Smrg setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc)); 2606d522f475Smrg setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc)); 2607d522f475Smrg setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 2608d522f475Smrg } else { 2609d522f475Smrg setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc)); 2610d522f475Smrg setCgsFore(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 2611d522f475Smrg setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 2612d522f475Smrg } 2613d522f475Smrg gc2 = getCgsGC(xw, cgsWin, cgsId); 2614d522f475Smrg 2615d522f475Smrg if (!(flags & NOBACKGROUND)) { 26160bd37d32Smrg XFillRectangle(screen->display, VDrawable(screen), gc2, x, y, 2617d522f475Smrg font_width, 2618d522f475Smrg font_height); 2619d522f475Smrg } 2620d522f475Smrg 2621d522f475Smrg setCgsFont(xw, cgsWin, cgsId, getCgsFont(xw, cgsWin, gc)); 2622d522f475Smrg setCgsFore(xw, cgsWin, cgsId, getCgsFore(xw, cgsWin, gc)); 2623d522f475Smrg setCgsBack(xw, cgsWin, cgsId, getCgsBack(xw, cgsWin, gc)); 2624d522f475Smrg gc2 = getCgsGC(xw, cgsWin, cgsId); 2625d522f475Smrg 2626d522f475Smrg XSetLineAttributes(screen->display, gc2, 2627d522f475Smrg (flags & BOLD) 2628d522f475Smrg ? ((font_height > 12) 2629d522f475Smrg ? font_height / 12 2630d522f475Smrg : 1) 2631d522f475Smrg : ((font_height > 16) 2632d522f475Smrg ? font_height / 16 2633d522f475Smrg : 1), 2634d522f475Smrg LineSolid, 2635d522f475Smrg CapProjecting, 2636d522f475Smrg JoinMiter); 2637d522f475Smrg 2638d522f475Smrg if (ch == 1) { /* diamond */ 2639d522f475Smrg XPoint points[5]; 2640d522f475Smrg int npoints = 5, n; 2641d522f475Smrg 2642d522f475Smrg points[0].x = MID_WIDE; 2643d522f475Smrg points[0].y = BOX_HIGH / 4; 2644d522f475Smrg 2645d522f475Smrg points[1].x = 8 * BOX_WIDE / 8; 2646d522f475Smrg points[1].y = MID_HIGH; 2647d522f475Smrg 2648d522f475Smrg points[2].x = points[0].x; 2649d522f475Smrg points[2].y = 3 * BOX_HIGH / 4; 2650d522f475Smrg 2651d522f475Smrg points[3].x = 0 * BOX_WIDE / 8; 2652d522f475Smrg points[3].y = points[1].y; 2653d522f475Smrg 2654d522f475Smrg points[4].x = points[0].x; 2655d522f475Smrg points[4].y = points[0].y; 2656d522f475Smrg 2657d522f475Smrg for (n = 0; n < npoints; ++n) { 2658e39b573cSmrg points[n].x = (short) SCALED_X(points[n].x); 2659e39b573cSmrg points[n].y = (short) SCALED_Y(points[n].y); 2660e39b573cSmrg points[n].x = (short) (points[n].x + x); 2661e39b573cSmrg points[n].y = (short) (points[n].y + y); 2662d522f475Smrg } 2663d522f475Smrg 2664d522f475Smrg XFillPolygon(screen->display, 26650bd37d32Smrg VDrawable(screen), gc2, 2666d522f475Smrg points, npoints, 2667d522f475Smrg Convex, CoordModeOrigin); 2668d522f475Smrg } else if (ch == 7) { /* degrees */ 2669d522f475Smrg unsigned width = (BOX_WIDE / 3); 2670956cc18dSsnj int x_coord = MID_WIDE - (int) (width / 2); 2671956cc18dSsnj int y_coord = MID_HIGH - (int) width; 2672d522f475Smrg 2673d522f475Smrg SCALE_X(x_coord); 2674d522f475Smrg SCALE_Y(y_coord); 2675e39b573cSmrg width = (unsigned) SCALED_X(width); 2676d522f475Smrg 2677d522f475Smrg XDrawArc(screen->display, 26780bd37d32Smrg VDrawable(screen), gc2, 2679d522f475Smrg x + x_coord, y + y_coord, width, width, 2680d522f475Smrg 0, 2681d522f475Smrg 360 * 64); 2682d522f475Smrg } else if (ch == 0x1f) { /* bullet */ 2683d522f475Smrg unsigned width = 7 * BOX_WIDE / 10; 2684956cc18dSsnj int x_coord = MID_WIDE - (int) (width / 3); 2685956cc18dSsnj int y_coord = MID_HIGH - (int) (width / 3); 2686d522f475Smrg 2687d522f475Smrg SCALE_X(x_coord); 2688d522f475Smrg SCALE_Y(y_coord); 2689e39b573cSmrg width = (unsigned) SCALED_X(width); 2690d522f475Smrg 2691d522f475Smrg XDrawArc(screen->display, 26920bd37d32Smrg VDrawable(screen), gc2, 2693d522f475Smrg x + x_coord, y + y_coord, width, width, 2694d522f475Smrg 0, 2695d522f475Smrg 360 * 64); 2696d522f475Smrg } else if (ch < (sizeof(lines) / sizeof(lines[0])) 2697d522f475Smrg && (p = lines[ch]) != 0) { 2698956cc18dSsnj int coord[4]; 2699d522f475Smrg int n = 0; 2700d522f475Smrg while (*p >= 0) { 2701d522f475Smrg coord[n++] = *p++; 2702d522f475Smrg if (n == 4) { 2703d522f475Smrg SCALE_X(coord[0]); 2704d522f475Smrg SCALE_Y(coord[1]); 2705d522f475Smrg SCALE_X(coord[2]); 2706d522f475Smrg SCALE_Y(coord[3]); 2707d522f475Smrg XDrawLine(screen->display, 27080bd37d32Smrg VDrawable(screen), gc2, 2709d522f475Smrg x + coord[0], y + coord[1], 2710d522f475Smrg x + coord[2], y + coord[3]); 2711d522f475Smrg n = 0; 2712d522f475Smrg } 2713d522f475Smrg } 2714d522f475Smrg } else if (screen->force_all_chars) { 2715d522f475Smrg /* bounding rectangle, for debugging */ 27160bd37d32Smrg XDrawRectangle(screen->display, VDrawable(screen), gc2, x, y, 2717d522f475Smrg font_width - 1, 2718d522f475Smrg font_height - 1); 2719d522f475Smrg } 2720d522f475Smrg} 2721fa3f02f3Smrg#endif /* OPT_BOX_CHARS */ 2722d522f475Smrg 2723d522f475Smrg#if OPT_RENDERFONT 2724d522f475Smrg 2725d522f475Smrg/* 2726d522f475Smrg * Check if the given character has a glyph known to Xft. 2727d522f475Smrg * 2728d522f475Smrg * see xc/lib/Xft/xftglyphs.c 2729d522f475Smrg */ 2730d522f475SmrgBool 2731d522f475SmrgxtermXftMissing(XtermWidget xw, XftFont * font, unsigned wc) 2732d522f475Smrg{ 2733d522f475Smrg Bool result = False; 2734d522f475Smrg 2735d522f475Smrg if (font != 0) { 2736956cc18dSsnj TScreen *screen = TScreenOf(xw); 2737956cc18dSsnj if (!XftGlyphExists(screen->display, font, wc)) { 2738d522f475Smrg#if OPT_WIDE_CHARS 2739d522f475Smrg TRACE(("xtermXftMissing %d (dec=%#x, ucs=%#x)\n", 2740d522f475Smrg wc, ucs2dec(wc), dec2ucs(wc))); 2741d522f475Smrg#else 2742d522f475Smrg TRACE(("xtermXftMissing %d\n", wc)); 2743d522f475Smrg#endif 2744d522f475Smrg result = True; 2745d522f475Smrg } 2746d522f475Smrg } 2747d522f475Smrg return result; 2748d522f475Smrg} 2749fa3f02f3Smrg#endif /* OPT_RENDERFONT */ 2750d522f475Smrg 2751d522f475Smrg#if OPT_WIDE_CHARS 2752d522f475Smrg#define MY_UCS(ucs,dec) case ucs: result = dec; break 2753d522f475Smrgunsigned 2754d522f475Smrgucs2dec(unsigned ch) 2755d522f475Smrg{ 2756d522f475Smrg unsigned result = ch; 2757d522f475Smrg if ((ch > 127) 2758d522f475Smrg && (ch != UCS_REPL)) { 2759d522f475Smrg switch (ch) { 2760d522f475Smrg MY_UCS(0x25ae, 0); /* black vertical rectangle */ 2761d522f475Smrg MY_UCS(0x25c6, 1); /* black diamond */ 2762d522f475Smrg MY_UCS(0x2592, 2); /* medium shade */ 2763d522f475Smrg MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 2764d522f475Smrg MY_UCS(0x240c, 4); /* symbol for form feed */ 2765d522f475Smrg MY_UCS(0x240d, 5); /* symbol for carriage return */ 2766d522f475Smrg MY_UCS(0x240a, 6); /* symbol for line feed */ 2767d522f475Smrg MY_UCS(0x00b0, 7); /* degree sign */ 2768d522f475Smrg MY_UCS(0x00b1, 8); /* plus-minus sign */ 2769d522f475Smrg MY_UCS(0x2424, 9); /* symbol for newline */ 2770d522f475Smrg MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 2771d522f475Smrg MY_UCS(0x2518, 11); /* box drawings light up and left */ 2772d522f475Smrg MY_UCS(0x2510, 12); /* box drawings light down and left */ 2773d522f475Smrg MY_UCS(0x250c, 13); /* box drawings light down and right */ 2774d522f475Smrg MY_UCS(0x2514, 14); /* box drawings light up and right */ 2775d522f475Smrg MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 2776d522f475Smrg MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 2777d522f475Smrg MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 2778d522f475Smrg MY_UCS(0x2500, 18); /* box drawings light horizontal */ 2779d522f475Smrg MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 2780d522f475Smrg MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 2781d522f475Smrg MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 2782d522f475Smrg MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 2783d522f475Smrg MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 2784d522f475Smrg MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 2785d522f475Smrg MY_UCS(0x2502, 25); /* box drawings light vertical */ 2786d522f475Smrg MY_UCS(0x2264, 26); /* less-than or equal to */ 2787d522f475Smrg MY_UCS(0x2265, 27); /* greater-than or equal to */ 2788d522f475Smrg MY_UCS(0x03c0, 28); /* greek small letter pi */ 2789d522f475Smrg MY_UCS(0x2260, 29); /* not equal to */ 2790d522f475Smrg MY_UCS(0x00a3, 30); /* pound sign */ 2791d522f475Smrg MY_UCS(0x00b7, 31); /* middle dot */ 2792d522f475Smrg } 2793d522f475Smrg } 2794d522f475Smrg return result; 2795d522f475Smrg} 2796d522f475Smrg 2797d522f475Smrg#undef MY_UCS 2798d522f475Smrg#define MY_UCS(ucs,dec) case dec: result = ucs; break 2799d522f475Smrg 2800d522f475Smrgunsigned 2801d522f475Smrgdec2ucs(unsigned ch) 2802d522f475Smrg{ 2803d522f475Smrg unsigned result = ch; 2804d522f475Smrg if (xtermIsDecGraphic(ch)) { 2805d522f475Smrg switch (ch) { 2806d522f475Smrg MY_UCS(0x25ae, 0); /* black vertical rectangle */ 2807d522f475Smrg MY_UCS(0x25c6, 1); /* black diamond */ 2808d522f475Smrg MY_UCS(0x2592, 2); /* medium shade */ 2809d522f475Smrg MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 2810d522f475Smrg MY_UCS(0x240c, 4); /* symbol for form feed */ 2811d522f475Smrg MY_UCS(0x240d, 5); /* symbol for carriage return */ 2812d522f475Smrg MY_UCS(0x240a, 6); /* symbol for line feed */ 2813d522f475Smrg MY_UCS(0x00b0, 7); /* degree sign */ 2814d522f475Smrg MY_UCS(0x00b1, 8); /* plus-minus sign */ 2815d522f475Smrg MY_UCS(0x2424, 9); /* symbol for newline */ 2816d522f475Smrg MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 2817d522f475Smrg MY_UCS(0x2518, 11); /* box drawings light up and left */ 2818d522f475Smrg MY_UCS(0x2510, 12); /* box drawings light down and left */ 2819d522f475Smrg MY_UCS(0x250c, 13); /* box drawings light down and right */ 2820d522f475Smrg MY_UCS(0x2514, 14); /* box drawings light up and right */ 2821d522f475Smrg MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 2822d522f475Smrg MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 2823d522f475Smrg MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 2824d522f475Smrg MY_UCS(0x2500, 18); /* box drawings light horizontal */ 2825d522f475Smrg MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 2826d522f475Smrg MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 2827d522f475Smrg MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 2828d522f475Smrg MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 2829d522f475Smrg MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 2830d522f475Smrg MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 2831d522f475Smrg MY_UCS(0x2502, 25); /* box drawings light vertical */ 2832d522f475Smrg MY_UCS(0x2264, 26); /* less-than or equal to */ 2833d522f475Smrg MY_UCS(0x2265, 27); /* greater-than or equal to */ 2834d522f475Smrg MY_UCS(0x03c0, 28); /* greek small letter pi */ 2835d522f475Smrg MY_UCS(0x2260, 29); /* not equal to */ 2836d522f475Smrg MY_UCS(0x00a3, 30); /* pound sign */ 2837d522f475Smrg MY_UCS(0x00b7, 31); /* middle dot */ 2838d522f475Smrg } 2839d522f475Smrg } 2840d522f475Smrg return result; 2841d522f475Smrg} 2842d522f475Smrg 2843d522f475Smrg#endif /* OPT_WIDE_CHARS */ 2844d522f475Smrg 2845b6fea0ceSmrg#if OPT_RENDERFONT || OPT_SHIFT_FONTS 28460bd37d32Smrgstatic int 2847d522f475SmrglookupOneFontSize(XtermWidget xw, int fontnum) 2848d522f475Smrg{ 2849d522f475Smrg TScreen *screen = TScreenOf(xw); 2850d522f475Smrg 2851d522f475Smrg if (screen->menu_font_sizes[fontnum] == 0) { 2852d522f475Smrg XTermFonts fnt; 2853d522f475Smrg 2854d522f475Smrg memset(&fnt, 0, sizeof(fnt)); 2855d522f475Smrg screen->menu_font_sizes[fontnum] = -1; 28560bd37d32Smrg if (xtermOpenFont(xw, 28570bd37d32Smrg screen->MenuFontName(fontnum), 28580bd37d32Smrg &fnt, 28590bd37d32Smrg ((fontnum <= fontMenu_lastBuiltin) 28600bd37d32Smrg ? fwAlways 28610bd37d32Smrg : fwResource), 28620bd37d32Smrg True)) { 286320d2c4d2Smrg if (fontnum <= fontMenu_lastBuiltin 28640bd37d32Smrg || strcmp(fnt.fn, DEFFONT)) { 286520d2c4d2Smrg screen->menu_font_sizes[fontnum] = FontSize(fnt.fs); 28660bd37d32Smrg if (screen->menu_font_sizes[fontnum] <= 0) 28670bd37d32Smrg screen->menu_font_sizes[fontnum] = -1; 28680bd37d32Smrg } 2869d522f475Smrg xtermCloseFont(xw, &fnt); 2870d522f475Smrg } 2871d522f475Smrg } 28720bd37d32Smrg return (screen->menu_font_sizes[fontnum] > 0); 2873d522f475Smrg} 2874d522f475Smrg 2875d522f475Smrg/* 2876d522f475Smrg * Cache the font-sizes so subsequent larger/smaller font actions will go fast. 2877d522f475Smrg */ 2878d522f475Smrgstatic void 2879d522f475SmrglookupFontSizes(XtermWidget xw) 2880d522f475Smrg{ 2881d522f475Smrg int n; 2882d522f475Smrg 2883d522f475Smrg for (n = 0; n < NMENUFONTS; n++) { 28840bd37d32Smrg (void) lookupOneFontSize(xw, n); 2885d522f475Smrg } 2886d522f475Smrg} 2887b6fea0ceSmrg#endif /* OPT_RENDERFONT || OPT_SHIFT_FONTS */ 2888d522f475Smrg 28892eaa94a1Schristos#if OPT_RENDERFONT 28900bd37d32Smrgstatic void 28910bd37d32SmrgfillInFaceSize(XtermWidget xw, int fontnum) 28920bd37d32Smrg{ 28930bd37d32Smrg TScreen *screen = TScreenOf(xw); 28940bd37d32Smrg float value; 28950bd37d32Smrg double face_size = xw->misc.face_size[fontnum]; 28960bd37d32Smrg 28970bd37d32Smrg if (face_size <= 0.0) { 28980bd37d32Smrg#if OPT_SHIFT_FONTS 28990bd37d32Smrg /* 29000bd37d32Smrg * If the user is switching font-sizes, make it follow by 29010bd37d32Smrg * default the same ratios to the default as the fixed fonts 29020bd37d32Smrg * would, for easy comparison. There will be some differences 29030bd37d32Smrg * since the fixed fonts have a variety of height/width ratios, 29040bd37d32Smrg * but this is simpler than adding another resource value - and 29050bd37d32Smrg * as noted above, the data for the fixed fonts are available. 29060bd37d32Smrg */ 29070bd37d32Smrg (void) lookupOneFontSize(xw, 0); 29080bd37d32Smrg if (fontnum == fontMenu_default) { 29090bd37d32Smrg sscanf(DEFFACESIZE, "%f", &value); 29100bd37d32Smrg face_size = value; 29110bd37d32Smrg } else if (lookupOneFontSize(xw, fontnum) 29120bd37d32Smrg && (screen->menu_font_sizes[0] 29130bd37d32Smrg != screen->menu_font_sizes[fontnum])) { 29140bd37d32Smrg double ratio; 29150bd37d32Smrg long num = screen->menu_font_sizes[fontnum]; 29160bd37d32Smrg long den = screen->menu_font_sizes[0]; 29170bd37d32Smrg 29180bd37d32Smrg if (den <= 0) 29190bd37d32Smrg den = 1; 29200bd37d32Smrg ratio = dimSquareRoot((double) num / (double) den); 29210bd37d32Smrg 29220bd37d32Smrg face_size = (ratio * xw->misc.face_size[0]); 29230bd37d32Smrg TRACE(("scaled[%d] using %3ld/%ld = %.2f -> %f\n", 29240bd37d32Smrg fontnum, num, den, ratio, face_size)); 29250bd37d32Smrg } else 29260bd37d32Smrg#endif 29270bd37d32Smrg { 29280bd37d32Smrg#define LikeBitmap(s) (((s) / 78.0) * xw->misc.face_size[fontMenu_default]) 29290bd37d32Smrg switch (fontnum) { 29300bd37d32Smrg case fontMenu_font1: 29310bd37d32Smrg face_size = LikeBitmap(2.0); 29320bd37d32Smrg break; 29330bd37d32Smrg case fontMenu_font2: 29340bd37d32Smrg face_size = LikeBitmap(35.0); 29350bd37d32Smrg break; 29360bd37d32Smrg case fontMenu_font3: 29370bd37d32Smrg face_size = LikeBitmap(60.0); 29380bd37d32Smrg break; 29390bd37d32Smrg default: 29400bd37d32Smrg sscanf(DEFFACESIZE, "%f", &value); 29410bd37d32Smrg face_size = value; 29420bd37d32Smrg break; 29430bd37d32Smrg case fontMenu_font4: 29440bd37d32Smrg face_size = LikeBitmap(90.0); 29450bd37d32Smrg break; 29460bd37d32Smrg case fontMenu_font5: 29470bd37d32Smrg face_size = LikeBitmap(135.0); 29480bd37d32Smrg break; 29490bd37d32Smrg case fontMenu_font6: 29500bd37d32Smrg face_size = LikeBitmap(200.0); 29510bd37d32Smrg break; 29520bd37d32Smrg } 29530bd37d32Smrg TRACE(("builtin[%d] -> %f\n", fontnum, face_size)); 29540bd37d32Smrg } 29550bd37d32Smrg xw->misc.face_size[fontnum] = (float) face_size; 29560bd37d32Smrg } 29570bd37d32Smrg} 29580bd37d32Smrg 29590bd37d32Smrg/* no selection or escape */ 29600bd37d32Smrg#define NMENU_RENDERFONTS (fontMenu_lastBuiltin + 1) 29610bd37d32Smrg 29620bd37d32Smrg/* 29630bd37d32Smrg * Workaround for breakage in font-packages - check if all of the bitmap font 29640bd37d32Smrg * sizes are the same, and if we're using TrueType fonts. 29650bd37d32Smrg */ 29662eaa94a1Schristosstatic Boolean 29672eaa94a1SchristosuseFaceSizes(XtermWidget xw) 29682eaa94a1Schristos{ 29692eaa94a1Schristos Boolean result = False; 29702eaa94a1Schristos int n; 29712eaa94a1Schristos 29720bd37d32Smrg TRACE(("useFaceSizes {{\n")); 29732eaa94a1Schristos if (UsingRenderFont(xw)) { 29740bd37d32Smrg Boolean nonzero = True; 29750bd37d32Smrg 29762eaa94a1Schristos for (n = 0; n < NMENU_RENDERFONTS; ++n) { 29772eaa94a1Schristos if (xw->misc.face_size[n] <= 0.0) { 29780bd37d32Smrg nonzero = False; 29792eaa94a1Schristos break; 29802eaa94a1Schristos } 29812eaa94a1Schristos } 29820bd37d32Smrg if (!nonzero) { 2983956cc18dSsnj Boolean broken_fonts = True; 2984956cc18dSsnj TScreen *screen = TScreenOf(xw); 29850bd37d32Smrg long first; 2986956cc18dSsnj 2987956cc18dSsnj lookupFontSizes(xw); 29880bd37d32Smrg first = screen->menu_font_sizes[0]; 2989956cc18dSsnj for (n = 0; n < NMENUFONTS; n++) { 2990956cc18dSsnj if (screen->menu_font_sizes[n] > 0 2991956cc18dSsnj && screen->menu_font_sizes[n] != first) { 2992956cc18dSsnj broken_fonts = False; 2993956cc18dSsnj break; 2994956cc18dSsnj } 2995956cc18dSsnj } 2996956cc18dSsnj 2997956cc18dSsnj if (broken_fonts) { 2998956cc18dSsnj 2999956cc18dSsnj TRACE(("bitmap fonts are broken - set faceSize resources\n")); 3000956cc18dSsnj for (n = 0; n < NMENUFONTS; n++) { 30010bd37d32Smrg fillInFaceSize(xw, n); 3002956cc18dSsnj } 3003956cc18dSsnj 3004956cc18dSsnj } 3005956cc18dSsnj } 30060bd37d32Smrg result = True; 30072eaa94a1Schristos } 30080bd37d32Smrg TRACE(("...}}useFaceSizes %d\n", result)); 30092eaa94a1Schristos return result; 30102eaa94a1Schristos} 30110bd37d32Smrg#endif /* OPT_RENDERFONT */ 30122eaa94a1Schristos 3013b6fea0ceSmrg#if OPT_SHIFT_FONTS 3014d522f475Smrg/* 3015d522f475Smrg * Find the index of a larger/smaller font (according to the sign of 'relative' 3016d522f475Smrg * and its magnitude), starting from the 'old' index. 3017d522f475Smrg */ 3018d522f475Smrgint 3019d522f475SmrglookupRelativeFontSize(XtermWidget xw, int old, int relative) 3020d522f475Smrg{ 3021d522f475Smrg TScreen *screen = TScreenOf(xw); 3022d522f475Smrg int n, m = -1; 3023d522f475Smrg 30242eaa94a1Schristos TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative)); 3025d522f475Smrg if (!IsIcon(screen)) { 30262eaa94a1Schristos#if OPT_RENDERFONT 30272eaa94a1Schristos if (useFaceSizes(xw)) { 30282eaa94a1Schristos TRACE(("...using FaceSize\n")); 30292eaa94a1Schristos if (relative != 0) { 30302eaa94a1Schristos for (n = 0; n < NMENU_RENDERFONTS; ++n) { 30310bd37d32Smrg fillInFaceSize(xw, n); 30322eaa94a1Schristos if (xw->misc.face_size[n] > 0 && 30332eaa94a1Schristos xw->misc.face_size[n] != xw->misc.face_size[old]) { 30342eaa94a1Schristos int cmp_0 = ((xw->misc.face_size[n] > 30352eaa94a1Schristos xw->misc.face_size[old]) 30362eaa94a1Schristos ? relative 30372eaa94a1Schristos : -relative); 30382eaa94a1Schristos int cmp_m = ((m < 0) 30392eaa94a1Schristos ? 1 30402eaa94a1Schristos : ((xw->misc.face_size[n] < 30412eaa94a1Schristos xw->misc.face_size[m]) 30422eaa94a1Schristos ? relative 30432eaa94a1Schristos : -relative)); 30442eaa94a1Schristos if (cmp_0 > 0 && cmp_m > 0) { 30452eaa94a1Schristos m = n; 30462eaa94a1Schristos } 3047d522f475Smrg } 3048d522f475Smrg } 3049d522f475Smrg } 30502eaa94a1Schristos } else 30512eaa94a1Schristos#endif 30522eaa94a1Schristos { 30532eaa94a1Schristos TRACE(("...using bitmap areas\n")); 30542eaa94a1Schristos lookupFontSizes(xw); 30552eaa94a1Schristos if (relative != 0) { 30562eaa94a1Schristos for (n = 0; n < NMENUFONTS; ++n) { 30572eaa94a1Schristos if (screen->menu_font_sizes[n] > 0 && 30582eaa94a1Schristos screen->menu_font_sizes[n] != 30592eaa94a1Schristos screen->menu_font_sizes[old]) { 30602eaa94a1Schristos int cmp_0 = ((screen->menu_font_sizes[n] > 30612eaa94a1Schristos screen->menu_font_sizes[old]) 30622eaa94a1Schristos ? relative 30632eaa94a1Schristos : -relative); 30642eaa94a1Schristos int cmp_m = ((m < 0) 30652eaa94a1Schristos ? 1 30662eaa94a1Schristos : ((screen->menu_font_sizes[n] < 30672eaa94a1Schristos screen->menu_font_sizes[m]) 30682eaa94a1Schristos ? relative 30692eaa94a1Schristos : -relative)); 30702eaa94a1Schristos if (cmp_0 > 0 && cmp_m > 0) { 30712eaa94a1Schristos m = n; 30722eaa94a1Schristos } 30732eaa94a1Schristos } 30742eaa94a1Schristos } 3075d522f475Smrg } 3076d522f475Smrg } 30772eaa94a1Schristos TRACE(("...new index %d\n", m)); 30782eaa94a1Schristos if (m >= 0) { 30792eaa94a1Schristos if (relative > 1) 30802eaa94a1Schristos m = lookupRelativeFontSize(xw, m, relative - 1); 30812eaa94a1Schristos else if (relative < -1) 30822eaa94a1Schristos m = lookupRelativeFontSize(xw, m, relative + 1); 30832eaa94a1Schristos } 3084d522f475Smrg } 3085d522f475Smrg return m; 3086d522f475Smrg} 3087d522f475Smrg 3088d522f475Smrg/* ARGSUSED */ 3089d522f475Smrgvoid 3090d522f475SmrgHandleLargerFont(Widget w GCC_UNUSED, 3091d522f475Smrg XEvent * event GCC_UNUSED, 3092fa3f02f3Smrg String *params GCC_UNUSED, 3093d522f475Smrg Cardinal *param_count GCC_UNUSED) 3094d522f475Smrg{ 3095956cc18dSsnj XtermWidget xw; 3096d522f475Smrg 309720d2c4d2Smrg TRACE(("Handle larger-vt-font for %p\n", (void *) w)); 3098956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 3099d522f475Smrg if (xw->misc.shift_fonts) { 3100956cc18dSsnj TScreen *screen = TScreenOf(xw); 3101d522f475Smrg int m; 3102d522f475Smrg 3103d522f475Smrg m = lookupRelativeFontSize(xw, screen->menu_font_number, 1); 3104d522f475Smrg if (m >= 0) { 3105d522f475Smrg SetVTFont(xw, m, True, NULL); 3106d522f475Smrg } else { 310720d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 3108d522f475Smrg } 3109d522f475Smrg } 3110d522f475Smrg } 3111d522f475Smrg} 3112d522f475Smrg 3113d522f475Smrg/* ARGSUSED */ 3114d522f475Smrgvoid 3115d522f475SmrgHandleSmallerFont(Widget w GCC_UNUSED, 3116d522f475Smrg XEvent * event GCC_UNUSED, 3117fa3f02f3Smrg String *params GCC_UNUSED, 3118d522f475Smrg Cardinal *param_count GCC_UNUSED) 3119d522f475Smrg{ 3120956cc18dSsnj XtermWidget xw; 3121d522f475Smrg 312220d2c4d2Smrg TRACE(("Handle smaller-vt-font for %p\n", (void *) w)); 3123956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 3124d522f475Smrg if (xw->misc.shift_fonts) { 3125956cc18dSsnj TScreen *screen = TScreenOf(xw); 3126d522f475Smrg int m; 3127d522f475Smrg 3128d522f475Smrg m = lookupRelativeFontSize(xw, screen->menu_font_number, -1); 3129d522f475Smrg if (m >= 0) { 3130d522f475Smrg SetVTFont(xw, m, True, NULL); 3131d522f475Smrg } else { 313220d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 3133d522f475Smrg } 3134d522f475Smrg } 3135d522f475Smrg } 3136d522f475Smrg} 3137b6fea0ceSmrg#endif /* OPT_SHIFT_FONTS */ 3138d522f475Smrg 3139d522f475Smrgint 3140d522f475SmrgxtermGetFont(const char *param) 3141d522f475Smrg{ 3142d522f475Smrg int fontnum; 3143d522f475Smrg 3144d522f475Smrg switch (param[0]) { 3145d522f475Smrg case 'd': 3146d522f475Smrg case 'D': 3147d522f475Smrg case '0': 3148d522f475Smrg fontnum = fontMenu_default; 3149d522f475Smrg break; 3150d522f475Smrg case '1': 3151d522f475Smrg fontnum = fontMenu_font1; 3152d522f475Smrg break; 3153d522f475Smrg case '2': 3154d522f475Smrg fontnum = fontMenu_font2; 3155d522f475Smrg break; 3156d522f475Smrg case '3': 3157d522f475Smrg fontnum = fontMenu_font3; 3158d522f475Smrg break; 3159d522f475Smrg case '4': 3160d522f475Smrg fontnum = fontMenu_font4; 3161d522f475Smrg break; 3162d522f475Smrg case '5': 3163d522f475Smrg fontnum = fontMenu_font5; 3164d522f475Smrg break; 3165d522f475Smrg case '6': 3166d522f475Smrg fontnum = fontMenu_font6; 3167d522f475Smrg break; 3168d522f475Smrg case 'e': 3169d522f475Smrg case 'E': 3170d522f475Smrg fontnum = fontMenu_fontescape; 3171d522f475Smrg break; 3172d522f475Smrg case 's': 3173d522f475Smrg case 'S': 3174d522f475Smrg fontnum = fontMenu_fontsel; 3175d522f475Smrg break; 3176d522f475Smrg default: 3177d522f475Smrg fontnum = -1; 3178d522f475Smrg break; 3179d522f475Smrg } 3180d522f475Smrg return fontnum; 3181d522f475Smrg} 3182d522f475Smrg 3183d522f475Smrg/* ARGSUSED */ 3184d522f475Smrgvoid 3185d522f475SmrgHandleSetFont(Widget w GCC_UNUSED, 3186d522f475Smrg XEvent * event GCC_UNUSED, 3187fa3f02f3Smrg String *params, 3188d522f475Smrg Cardinal *param_count) 3189d522f475Smrg{ 3190956cc18dSsnj XtermWidget xw; 3191956cc18dSsnj 3192956cc18dSsnj if ((xw = getXtermWidget(w)) != 0) { 3193d522f475Smrg int fontnum; 3194d522f475Smrg VTFontNames fonts; 3195d522f475Smrg 3196d522f475Smrg memset(&fonts, 0, sizeof(fonts)); 3197d522f475Smrg 3198d522f475Smrg if (*param_count == 0) { 3199d522f475Smrg fontnum = fontMenu_default; 3200d522f475Smrg } else { 3201d522f475Smrg Cardinal maxparams = 1; /* total number of params allowed */ 3202d522f475Smrg int result = xtermGetFont(params[0]); 3203d522f475Smrg 3204d522f475Smrg switch (result) { 3205d522f475Smrg case fontMenu_default: /* FALLTHRU */ 3206d522f475Smrg case fontMenu_font1: /* FALLTHRU */ 3207d522f475Smrg case fontMenu_font2: /* FALLTHRU */ 3208d522f475Smrg case fontMenu_font3: /* FALLTHRU */ 3209d522f475Smrg case fontMenu_font4: /* FALLTHRU */ 3210d522f475Smrg case fontMenu_font5: /* FALLTHRU */ 3211d522f475Smrg case fontMenu_font6: /* FALLTHRU */ 3212d522f475Smrg break; 3213d522f475Smrg case fontMenu_fontescape: 3214d522f475Smrg#if OPT_WIDE_CHARS 3215d522f475Smrg maxparams = 5; 3216d522f475Smrg#else 3217d522f475Smrg maxparams = 3; 3218d522f475Smrg#endif 3219d522f475Smrg break; 3220d522f475Smrg case fontMenu_fontsel: 3221d522f475Smrg maxparams = 2; 3222d522f475Smrg break; 3223d522f475Smrg default: 322420d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 3225d522f475Smrg return; 3226d522f475Smrg } 3227d522f475Smrg fontnum = result; 3228d522f475Smrg 3229d522f475Smrg if (*param_count > maxparams) { /* see if extra args given */ 323020d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 3231d522f475Smrg return; 3232d522f475Smrg } 3233d522f475Smrg switch (*param_count) { /* assign 'em */ 3234d522f475Smrg#if OPT_WIDE_CHARS 3235d522f475Smrg case 5: 3236d522f475Smrg fonts.f_wb = params[4]; 3237d522f475Smrg /* FALLTHRU */ 3238d522f475Smrg case 4: 3239d522f475Smrg fonts.f_w = params[3]; 3240d522f475Smrg /* FALLTHRU */ 3241d522f475Smrg#endif 3242d522f475Smrg case 3: 3243d522f475Smrg fonts.f_b = params[2]; 3244d522f475Smrg /* FALLTHRU */ 3245d522f475Smrg case 2: 3246d522f475Smrg fonts.f_n = params[1]; 3247d522f475Smrg break; 3248d522f475Smrg } 3249d522f475Smrg } 3250d522f475Smrg 3251956cc18dSsnj SetVTFont(xw, fontnum, True, &fonts); 3252d522f475Smrg } 3253d522f475Smrg} 3254d522f475Smrg 3255d522f475Smrgvoid 3256d522f475SmrgSetVTFont(XtermWidget xw, 3257d522f475Smrg int which, 3258d522f475Smrg Bool doresize, 3259d522f475Smrg const VTFontNames * fonts) 3260d522f475Smrg{ 3261956cc18dSsnj TScreen *screen = TScreenOf(xw); 3262d522f475Smrg 3263d522f475Smrg TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which, 3264d522f475Smrg (fonts && fonts->f_n) ? fonts->f_n : "<null>", 3265d522f475Smrg (fonts && fonts->f_b) ? fonts->f_b : "<null>")); 3266d522f475Smrg 3267d522f475Smrg if (IsIcon(screen)) { 326820d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 3269d522f475Smrg } else if (which >= 0 && which < NMENUFONTS) { 3270d522f475Smrg VTFontNames myfonts; 3271d522f475Smrg 3272d522f475Smrg memset(&myfonts, 0, sizeof(myfonts)); 3273d522f475Smrg if (fonts != 0) 3274d522f475Smrg myfonts = *fonts; 3275d522f475Smrg 3276d522f475Smrg if (which == fontMenu_fontsel) { /* go get the selection */ 3277d522f475Smrg FindFontSelection(xw, myfonts.f_n, False); 3278d522f475Smrg } else { 3279d522f475Smrg int oldFont = screen->menu_font_number; 3280d522f475Smrg 3281d522f475Smrg#define USE_CACHED(field, name) \ 3282d522f475Smrg if (myfonts.field == 0) { \ 3283492d43a5Smrg myfonts.field = x_strdup(screen->menu_font_names[which][name]); \ 3284d522f475Smrg TRACE(("set myfonts." #field " from menu_font_names[%d][" #name "] %s\n", \ 3285d522f475Smrg which, NonNull(myfonts.field))); \ 3286d522f475Smrg } else { \ 3287d522f475Smrg TRACE(("set myfonts." #field " reused\n")); \ 3288d522f475Smrg } 328920d2c4d2Smrg#define SAVE_FNAME(field, name) \ 329020d2c4d2Smrg if (myfonts.field != 0) { \ 329120d2c4d2Smrg if (screen->menu_font_names[which][name] == 0 \ 329220d2c4d2Smrg || strcmp(screen->menu_font_names[which][name], myfonts.field)) { \ 329320d2c4d2Smrg TRACE(("updating menu_font_names[%d][" #name "] to %s\n", \ 329420d2c4d2Smrg which, myfonts.field)); \ 329520d2c4d2Smrg screen->menu_font_names[which][name] = x_strdup(myfonts.field); \ 329620d2c4d2Smrg } \ 329720d2c4d2Smrg } 329820d2c4d2Smrg 3299d522f475Smrg USE_CACHED(f_n, fNorm); 3300d522f475Smrg USE_CACHED(f_b, fBold); 3301d522f475Smrg#if OPT_WIDE_CHARS 3302d522f475Smrg USE_CACHED(f_w, fWide); 3303d522f475Smrg USE_CACHED(f_wb, fWBold); 3304d522f475Smrg#endif 3305d522f475Smrg if (xtermLoadFont(xw, 3306d522f475Smrg &myfonts, 3307d522f475Smrg doresize, which)) { 330820d2c4d2Smrg /* 330920d2c4d2Smrg * If successful, save the data so that a subsequent query via 331020d2c4d2Smrg * OSC-50 will return the expected values. 331120d2c4d2Smrg */ 331220d2c4d2Smrg SAVE_FNAME(f_n, fNorm); 331320d2c4d2Smrg SAVE_FNAME(f_b, fBold); 331420d2c4d2Smrg#if OPT_WIDE_CHARS 331520d2c4d2Smrg SAVE_FNAME(f_w, fWide); 331620d2c4d2Smrg SAVE_FNAME(f_wb, fWBold); 331720d2c4d2Smrg#endif 3318d522f475Smrg } else { 3319d522f475Smrg xtermLoadFont(xw, 3320d522f475Smrg xtermFontName(screen->MenuFontName(oldFont)), 3321d522f475Smrg doresize, oldFont); 332220d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 3323d522f475Smrg } 3324d522f475Smrg } 332520d2c4d2Smrg } else { 332620d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 3327d522f475Smrg } 3328d522f475Smrg return; 3329d522f475Smrg} 3330