1190d7dceSmrg/* $XTermId: fontutils.c,v 1.787 2024/12/01 20:29:42 tom Exp $ */ 2d522f475Smrg 30bd37d32Smrg/* 4980988aeSmrg * Copyright 1998-2023,2024 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> 47980988aeSmrg#include <error.h> 48d522f475Smrg#include <menu.h> 49d522f475Smrg#include <xstrings.h> 50d522f475Smrg#include <xterm.h> 51d522f475Smrg 52d522f475Smrg#include <stdio.h> 53d522f475Smrg#include <ctype.h> 54d522f475Smrg 55d1603babSmrg#define USE_FC_COLOR 0 56d1603babSmrg#if OPT_RENDERFONT 57d1603babSmrg#if XftVersion > 20304 58d1603babSmrg#undef USE_FC_COLOR 59d1603babSmrg#define USE_FC_COLOR 1 60d1603babSmrg#endif 61d1603babSmrg#endif 62d1603babSmrg 63d1603babSmrg#define FcOK(func) (func == FcResultMatch) 64d1603babSmrg 65d4fba8b9Smrg#define NoFontWarning(data) (data)->warn = fwAlways 66d4fba8b9Smrg 670bd37d32Smrg#define SetFontWidth(screen,dst,src) (dst)->f_width = (src) 68d4fba8b9Smrg#define SetFontHeight(screen,dst,src) (dst)->f_height = dimRound((double)((screen)->scale_height * (float) (src))) 690bd37d32Smrg 70d522f475Smrg/* from X11/Xlibint.h - not all vendors install this file */ 71d522f475Smrg#define CI_NONEXISTCHAR(cs) (((cs)->width == 0) && \ 72d522f475Smrg (((cs)->rbearing|(cs)->lbearing| \ 73d522f475Smrg (cs)->ascent|(cs)->descent) == 0)) 74d522f475Smrg 75fa3f02f3Smrg#define CI_GET_CHAR_INFO_1D(fs,col,cs) \ 76d522f475Smrg{ \ 77190d7dceSmrg cs = NULL; \ 78d522f475Smrg if (col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \ 79d522f475Smrg if (fs->per_char == NULL) { \ 80d522f475Smrg cs = &fs->min_bounds; \ 81d522f475Smrg } else { \ 82d522f475Smrg cs = &fs->per_char[(col - fs->min_char_or_byte2)]; \ 83d522f475Smrg } \ 84190d7dceSmrg if (CI_NONEXISTCHAR(cs)) cs = NULL; \ 85d522f475Smrg } \ 86d522f475Smrg} 87d522f475Smrg 88fa3f02f3Smrg#define CI_GET_CHAR_INFO_2D(fs,row,col,cs) \ 89d522f475Smrg{ \ 90190d7dceSmrg cs = NULL; \ 91d522f475Smrg if (row >= fs->min_byte1 && row <= fs->max_byte1 && \ 92d522f475Smrg col >= fs->min_char_or_byte2 && col <= fs->max_char_or_byte2) { \ 93d522f475Smrg if (fs->per_char == NULL) { \ 94d522f475Smrg cs = &fs->min_bounds; \ 95d522f475Smrg } else { \ 96d522f475Smrg cs = &fs->per_char[((row - fs->min_byte1) * \ 97d522f475Smrg (fs->max_char_or_byte2 - \ 98d522f475Smrg fs->min_char_or_byte2 + 1)) + \ 99d522f475Smrg (col - fs->min_char_or_byte2)]; \ 100d522f475Smrg } \ 101190d7dceSmrg if (CI_NONEXISTCHAR(cs)) cs = NULL; \ 102d522f475Smrg } \ 103d522f475Smrg} 104d522f475Smrg 1059a64e1c5Smrg#define FREE_FNAME(field) \ 106190d7dceSmrg if (fonts == NULL || new_fnames.field != fonts->field) { \ 107d1603babSmrg FREE_STRING(new_fnames.field); \ 108190d7dceSmrg new_fnames.field = NULL; \ 1099a64e1c5Smrg } 1109a64e1c5Smrg 111d522f475Smrg/* 112d522f475Smrg * A structure to hold the relevant properties from a font 113d522f475Smrg * we need to make a well formed font name for it. 114d522f475Smrg */ 115d522f475Smrgtypedef struct { 116d522f475Smrg /* registry, foundry, family */ 1179a64e1c5Smrg const char *beginning; 118d522f475Smrg /* weight */ 1199a64e1c5Smrg const char *weight; 120d522f475Smrg /* slant */ 1219a64e1c5Smrg const char *slant; 122d522f475Smrg /* wideness */ 1239a64e1c5Smrg const char *wideness; 124d522f475Smrg /* add style */ 1259a64e1c5Smrg const char *add_style; 126d522f475Smrg int pixel_size; 1279a64e1c5Smrg const char *point_size; 128d522f475Smrg int res_x; 129d522f475Smrg int res_y; 1309a64e1c5Smrg const char *spacing; 131d522f475Smrg int average_width; 132d522f475Smrg /* charset registry, charset encoding */ 133d522f475Smrg char *end; 134d522f475Smrg} FontNameProperties; 135d522f475Smrg 136d4fba8b9Smrg#if OPT_WIDE_CHARS && (OPT_RENDERFONT || (OPT_TRACE > 1)) 137d4fba8b9Smrg#define MY_UCS(code,high,wide,name) { code, high, wide, #name } 138d4fba8b9Smrgstatic const struct { 139d4fba8b9Smrg unsigned code, high, wide; 140d4fba8b9Smrg const char *name; 141d4fba8b9Smrg} unicode_boxes[] = { 142d4fba8b9Smrg 143d4fba8b9Smrg MY_UCS(0x2500, 0, 1, box drawings light horizontal), 144d4fba8b9Smrg MY_UCS(0x2502, 1, 0, box drawings light vertical), 145d4fba8b9Smrg MY_UCS(0x250c, 2, 2, box drawings light down and right), 146d4fba8b9Smrg MY_UCS(0x2510, 2, 2, box drawings light down and left), 147d4fba8b9Smrg MY_UCS(0x2514, 2, 2, box drawings light up and right), 148d4fba8b9Smrg MY_UCS(0x2518, 2, 2, box drawings light up and left), 149d4fba8b9Smrg MY_UCS(0x251c, 1, 2, box drawings light vertical and right), 150d4fba8b9Smrg MY_UCS(0x2524, 1, 2, box drawings light vertical and left), 151d4fba8b9Smrg MY_UCS(0x252c, 2, 1, box drawings light down and horizontal), 152d4fba8b9Smrg MY_UCS(0x2534, 2, 1, box drawings light up and horizontal), 153d4fba8b9Smrg MY_UCS(0x253c, 1, 1, box drawings light vertical and horizontal), 154d4fba8b9Smrg { 155d4fba8b9Smrg 0, 0, 0, NULL 156d4fba8b9Smrg } 157d4fba8b9Smrg}; 158d4fba8b9Smrg 159d4fba8b9Smrg#undef MY_UCS 160d4fba8b9Smrg#endif /* OPT_WIDE_CHARS */ 161d4fba8b9Smrg 162dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 163dfb07bc7Smrgstatic Boolean merge_sublist(char ***, char **); 164dfb07bc7Smrg#endif 165dfb07bc7Smrg 166dfb07bc7Smrgstatic void save2FontList(XtermWidget, const char *, XtermFontNames *, 167d1603babSmrg VTFontEnum, const char *, Bool, Bool); 168dfb07bc7Smrg 1690bd37d32Smrg#if OPT_RENDERFONT 1700bd37d32Smrgstatic void fillInFaceSize(XtermWidget, int); 1710bd37d32Smrg#endif 1720bd37d32Smrg 173d1603babSmrg#if OPT_REPORT_FONTS && OPT_TRACE 174d1603babSmrgstatic void 175d1603babSmrgreport_fonts(const char *fmt, ...) 176d1603babSmrg{ 177d1603babSmrg va_list ap; 178d1603babSmrg va_start(ap, fmt); 179d1603babSmrg vfprintf(stdout, fmt, ap); 180d1603babSmrg va_end(ap); 181d1603babSmrg#if OPT_TRACE 182d1603babSmrg va_start(ap, fmt); 183d1603babSmrg TraceVA(fmt, ap); 184d1603babSmrg va_end(ap); 185d1603babSmrg#endif 186d1603babSmrg} 187d1603babSmrg 188d1603babSmrg#define ReportFonts report_fonts 189d1603babSmrg#else 190d1603babSmrg#define ReportFonts printf 191d522f475Smrg#endif 192d522f475Smrg 193d4fba8b9Smrg#if OPT_TRACE 194d4fba8b9Smrgstatic void 195d4fba8b9Smrgset_font_height(TScreen *screen, VTwin *win, int height) 196d4fba8b9Smrg{ 197d4fba8b9Smrg SetFontHeight(screen, win, height); 198d4fba8b9Smrg TRACE(("SetFontHeight %d\n", win->f_height)); 199d4fba8b9Smrg#undef SetFontHeight 200d4fba8b9Smrg#define SetFontHeight(screen, win, height) set_font_height(screen, win, height) 201d4fba8b9Smrg} 202d4fba8b9Smrg 203d4fba8b9Smrgstatic void 204d4fba8b9Smrgset_font_width(TScreen *screen, VTwin *win, int width) 205d4fba8b9Smrg{ 206d4fba8b9Smrg (void) screen; 207d4fba8b9Smrg SetFontWidth(screen, win, width); 208d4fba8b9Smrg TRACE(("SetFontWidth %d\n", win->f_width)); 209d4fba8b9Smrg#undef SetFontWidth 210c48a5815Smrg#define SetFontWidth(screen, win, width) set_font_width(screen, win, width) 211d4fba8b9Smrg} 212d4fba8b9Smrg#endif 213d4fba8b9Smrg 214fa3f02f3Smrg#if OPT_REPORT_FONTS || OPT_WIDE_CHARS 2152eaa94a1Schristosstatic unsigned 2169a64e1c5SmrgcountGlyphs(XFontStruct *fp) 217d522f475Smrg{ 218d522f475Smrg unsigned count = 0; 219d522f475Smrg 220190d7dceSmrg if (fp != NULL) { 221d522f475Smrg if (fp->min_byte1 == 0 && fp->max_byte1 == 0) { 222fa3f02f3Smrg count = fp->max_char_or_byte2 - fp->min_char_or_byte2 + 1; 223d522f475Smrg } else if (fp->min_char_or_byte2 < 256 224d522f475Smrg && fp->max_char_or_byte2 < 256) { 225d522f475Smrg unsigned first = (fp->min_byte1 << 8) + fp->min_char_or_byte2; 226d522f475Smrg unsigned last = (fp->max_byte1 << 8) + fp->max_char_or_byte2; 227d522f475Smrg count = last + 1 - first; 228d522f475Smrg } 229d522f475Smrg } 230d522f475Smrg return count; 231d522f475Smrg} 232fa3f02f3Smrg#endif 233d522f475Smrg 234fa3f02f3Smrg#if OPT_WIDE_CHARS 235d522f475Smrg/* 236d522f475Smrg * Verify that the wide-bold font is at least a bold font with roughly as many 237d522f475Smrg * glyphs as the wide font. The counts should be the same, but settle for 238d522f475Smrg * filtering out the worst of the font mismatches. 239d522f475Smrg */ 240d522f475Smrgstatic Bool 2419a64e1c5SmrgcompatibleWideCounts(XFontStruct *wfs, XFontStruct *wbfs) 242d522f475Smrg{ 243d522f475Smrg unsigned count_w = countGlyphs(wfs); 244d522f475Smrg unsigned count_wb = countGlyphs(wbfs); 245d522f475Smrg if (count_w <= 256 || 246d522f475Smrg count_wb <= 256 || 247d522f475Smrg ((count_w / 4) * 3) > count_wb) { 248d522f475Smrg TRACE(("...font server lied (count wide %u vs wide-bold %u)\n", 249d522f475Smrg count_w, count_wb)); 250d522f475Smrg return False; 251d522f475Smrg } 252d522f475Smrg return True; 253d522f475Smrg} 254d522f475Smrg#endif /* OPT_WIDE_CHARS */ 255d522f475Smrg 25620d2c4d2Smrg#if OPT_BOX_CHARS 25720d2c4d2Smrgstatic void 25820d2c4d2SmrgsetupPackedFonts(XtermWidget xw) 25920d2c4d2Smrg{ 26020d2c4d2Smrg TScreen *screen = TScreenOf(xw); 26120d2c4d2Smrg Bool value = False; 26220d2c4d2Smrg 26320d2c4d2Smrg#if OPT_RENDERFONT 2640bd37d32Smrg if (xw->work.render_font == True) { 265dfb07bc7Smrg int e; 26620d2c4d2Smrg 267dfb07bc7Smrg for (e = 0; e < fMAX; ++e) { 268dfb07bc7Smrg XTermXftFonts *data = getMyXftFont(xw, e, screen->menu_font_number); 269190d7dceSmrg if (data != NULL) { 270d1603babSmrg if (data->font_info.mixed) { 271dfb07bc7Smrg screen->allow_packing = True; 272dfb07bc7Smrg break; 273dfb07bc7Smrg } 274dfb07bc7Smrg } 275dfb07bc7Smrg } 27620d2c4d2Smrg } 27720d2c4d2Smrg#endif /* OPT_RENDERFONT */ 27820d2c4d2Smrg 27920d2c4d2Smrg value = screen->allow_packing; 28020d2c4d2Smrg 28120d2c4d2Smrg SetItemSensitivity(fontMenuEntries[fontMenu_font_packedfont].widget, value); 28220d2c4d2Smrg} 28320d2c4d2Smrg#endif 28420d2c4d2Smrg 285d4fba8b9Smrgtypedef struct _nameList { 286d4fba8b9Smrg struct _nameList *next; 287d4fba8b9Smrg char *name; 288d4fba8b9Smrg} NameList; 289d4fba8b9Smrg 290d4fba8b9Smrgstatic NameList *derived_fonts; 291d4fba8b9Smrg 292d4fba8b9Smrgstatic Boolean 293d4fba8b9Smrgis_derived_font_name(const char *name) 294d4fba8b9Smrg{ 295d4fba8b9Smrg Boolean result = False; 296d4fba8b9Smrg NameList *list; 297d4fba8b9Smrg if (!IsEmpty(name)) { 298190d7dceSmrg for (list = derived_fonts; list != NULL; list = list->next) { 299d4fba8b9Smrg if (!x_strcasecmp(name, list->name)) { 300d4fba8b9Smrg result = True; 301d4fba8b9Smrg break; 302d4fba8b9Smrg } 303d4fba8b9Smrg } 304d4fba8b9Smrg } 305d4fba8b9Smrg return result; 306d4fba8b9Smrg} 307d4fba8b9Smrg 308d4fba8b9Smrgvoid 309d4fba8b9SmrgxtermDerivedFont(const char *name) 310d4fba8b9Smrg{ 311d4fba8b9Smrg if (!IsEmpty(name) && !is_derived_font_name(name)) { 312d4fba8b9Smrg NameList *list = TypeCalloc(NameList); 313d4fba8b9Smrg list->name = x_strdup(name); 314d4fba8b9Smrg list->next = derived_fonts; 315d4fba8b9Smrg derived_fonts = list; 316d4fba8b9Smrg } 317d4fba8b9Smrg} 318d4fba8b9Smrg 319d522f475Smrg/* 320d522f475Smrg * Returns the fields from start to stop in a dash- separated string. This 3219a64e1c5Smrg * function will modify the source, putting '\0's in the appropriate place and 322d522f475Smrg * moving the beginning forward to after the '\0' 323d522f475Smrg * 324d522f475Smrg * This will NOT work for the last field (but we won't need it). 325d522f475Smrg */ 326d522f475Smrgstatic char * 327d522f475Smrgn_fields(char **source, int start, int stop) 328d522f475Smrg{ 329d522f475Smrg int i; 330d522f475Smrg char *str, *str1; 331d522f475Smrg 332d522f475Smrg /* 333d522f475Smrg * find the start-1th dash 334d522f475Smrg */ 3359a64e1c5Smrg for (i = start - 1, str = *source; i; i--, str++) { 336190d7dceSmrg if ((str = strchr(str, '-')) == NULL) 337190d7dceSmrg return NULL; 3389a64e1c5Smrg } 339d522f475Smrg 340d522f475Smrg /* 341d522f475Smrg * find the stopth dash 342d522f475Smrg */ 3439a64e1c5Smrg for (i = stop - start + 1, str1 = str; i; i--, str1++) { 344190d7dceSmrg if ((str1 = strchr(str1, '-')) == NULL) 345190d7dceSmrg return NULL; 3469a64e1c5Smrg } 347d522f475Smrg 348d522f475Smrg /* 349d522f475Smrg * put a \0 at the end of the fields 350d522f475Smrg */ 351d522f475Smrg *(str1 - 1) = '\0'; 352d522f475Smrg 353d522f475Smrg /* 354d522f475Smrg * move source forward 355d522f475Smrg */ 356d522f475Smrg *source = str1; 357d522f475Smrg 358d522f475Smrg return str; 359d522f475Smrg} 360d522f475Smrg 361956cc18dSsnjstatic Boolean 362956cc18dSsnjcheck_fontname(const char *name) 363956cc18dSsnj{ 364956cc18dSsnj Boolean result = True; 365956cc18dSsnj 366492d43a5Smrg if (IsEmpty(name)) { 367956cc18dSsnj TRACE(("fontname missing\n")); 368956cc18dSsnj result = False; 369956cc18dSsnj } 370956cc18dSsnj return result; 371956cc18dSsnj} 372956cc18dSsnj 373d522f475Smrg/* 374d522f475Smrg * Gets the font properties from a given font structure. We use the FONT name 375d522f475Smrg * to find them out, since that seems easier. 376d522f475Smrg * 377d522f475Smrg * Returns a pointer to a static FontNameProperties structure 378d522f475Smrg * or NULL on error. 379d522f475Smrg */ 380d522f475Smrgstatic FontNameProperties * 3819a64e1c5Smrgget_font_name_props(Display *dpy, XFontStruct *fs, char **result) 382d522f475Smrg{ 383d522f475Smrg static FontNameProperties props; 384d522f475Smrg static char *last_name; 385d522f475Smrg 386d4fba8b9Smrg Atom fontatom; 387d4fba8b9Smrg char *name; 388d522f475Smrg char *str; 389d522f475Smrg 390d4fba8b9Smrg if (fs == NULL) 391d4fba8b9Smrg return NULL; 392d4fba8b9Smrg 393d522f475Smrg /* 394d522f475Smrg * first get the full font name 395d522f475Smrg */ 396190d7dceSmrg name = NULL; 397980988aeSmrg fontatom = CachedInternAtom(dpy, "FONT"); 39820d2c4d2Smrg if (fontatom != 0) { 399037a25ddSmrg XFontProp *fp; 400037a25ddSmrg int i; 401037a25ddSmrg 40220d2c4d2Smrg for (i = 0, fp = fs->properties; i < fs->n_properties; i++, fp++) { 40320d2c4d2Smrg if (fp->name == fontatom) { 40420d2c4d2Smrg name = XGetAtomName(dpy, fp->card32); 40520d2c4d2Smrg break; 40620d2c4d2Smrg } 40720d2c4d2Smrg } 40820d2c4d2Smrg } 409d522f475Smrg 410190d7dceSmrg if (name == NULL) 411190d7dceSmrg return NULL; 412d522f475Smrg 413d522f475Smrg /* 414d522f475Smrg * XGetAtomName allocates memory - don't leak 415d522f475Smrg */ 416d4fba8b9Smrg XFree(last_name); 417d522f475Smrg last_name = name; 418d522f475Smrg 419190d7dceSmrg if (result != NULL) { 420956cc18dSsnj if (!check_fontname(name)) 421190d7dceSmrg return NULL; 422d4fba8b9Smrg free(*result); 4230bd37d32Smrg *result = x_strdup(name); 424d522f475Smrg } 425d522f475Smrg 426d522f475Smrg /* 427d522f475Smrg * Now split it up into parts and put them in 428d522f475Smrg * their places. Since we are using parts of 429d522f475Smrg * the original string, we must not free the Atom Name 430d522f475Smrg */ 431d522f475Smrg 432d522f475Smrg /* registry, foundry, family */ 433190d7dceSmrg if ((props.beginning = n_fields(&name, 1, 3)) == NULL) 434190d7dceSmrg return NULL; 435d522f475Smrg 436d522f475Smrg /* weight is the next */ 437190d7dceSmrg if ((props.weight = n_fields(&name, 1, 1)) == NULL) 438190d7dceSmrg return NULL; 439d522f475Smrg 440d522f475Smrg /* slant */ 441190d7dceSmrg if ((props.slant = n_fields(&name, 1, 1)) == NULL) 442190d7dceSmrg return NULL; 443d522f475Smrg 444d522f475Smrg /* width */ 445190d7dceSmrg if ((props.wideness = n_fields(&name, 1, 1)) == NULL) 446190d7dceSmrg return NULL; 447d522f475Smrg 448d522f475Smrg /* add style */ 449190d7dceSmrg if ((props.add_style = n_fields(&name, 1, 1)) == NULL) 450190d7dceSmrg return NULL; 451d522f475Smrg 452d522f475Smrg /* pixel size */ 453190d7dceSmrg if ((str = n_fields(&name, 1, 1)) == NULL) 454190d7dceSmrg return NULL; 455d522f475Smrg if ((props.pixel_size = atoi(str)) == 0) 456190d7dceSmrg return NULL; 457d522f475Smrg 458d522f475Smrg /* point size */ 459190d7dceSmrg if ((props.point_size = n_fields(&name, 1, 1)) == NULL) 460190d7dceSmrg return NULL; 461d522f475Smrg 462d522f475Smrg /* res_x */ 463190d7dceSmrg if ((str = n_fields(&name, 1, 1)) == NULL) 464190d7dceSmrg return NULL; 465d522f475Smrg if ((props.res_x = atoi(str)) == 0) 466190d7dceSmrg return NULL; 467d522f475Smrg 468d522f475Smrg /* res_y */ 469190d7dceSmrg if ((str = n_fields(&name, 1, 1)) == NULL) 470190d7dceSmrg return NULL; 471d522f475Smrg if ((props.res_y = atoi(str)) == 0) 472190d7dceSmrg return NULL; 473d522f475Smrg 474d522f475Smrg /* spacing */ 475190d7dceSmrg if ((props.spacing = n_fields(&name, 1, 1)) == NULL) 476190d7dceSmrg return NULL; 477d522f475Smrg 478d522f475Smrg /* average width */ 479190d7dceSmrg if ((str = n_fields(&name, 1, 1)) == NULL) 480190d7dceSmrg return NULL; 481d522f475Smrg if ((props.average_width = atoi(str)) == 0) 482190d7dceSmrg return NULL; 483d522f475Smrg 484d522f475Smrg /* the rest: charset registry and charset encoding */ 485d522f475Smrg props.end = name; 486d522f475Smrg 487d522f475Smrg return &props; 488d522f475Smrg} 489d522f475Smrg 490d522f475Smrg#define ALLOCHUNK(n) ((n | 127) + 1) 491d522f475Smrg 492d522f475Smrgstatic void 493956cc18dSsnjalloca_fontname(char **result, size_t next) 494d522f475Smrg{ 495190d7dceSmrg size_t last = (*result != NULL) ? strlen(*result) : 0; 496190d7dceSmrg size_t have = (*result != NULL) ? ALLOCHUNK(last) : 0; 497956cc18dSsnj size_t want = last + next + 2; 498d522f475Smrg 499d522f475Smrg if (want >= have) { 50050027b5bSmrg char *save = *result; 501d522f475Smrg want = ALLOCHUNK(want); 502d522f475Smrg if (last != 0) { 503d522f475Smrg *result = TypeRealloc(char, want, *result); 504190d7dceSmrg if (*result == NULL) 5059a64e1c5Smrg free(save); 506d522f475Smrg } else { 507190d7dceSmrg if ((*result = TypeMallocN(char, want)) != NULL) { 50850027b5bSmrg free(save); 509d522f475Smrg **result = '\0'; 51050027b5bSmrg } 511d522f475Smrg } 512d522f475Smrg } 513d522f475Smrg} 514d522f475Smrg 515d522f475Smrgstatic void 51620d2c4d2Smrgappend_fontname_str(char **result, const char *value) 517d522f475Smrg{ 518190d7dceSmrg if (value == NULL) 519d522f475Smrg value = "*"; 520d522f475Smrg alloca_fontname(result, strlen(value)); 521190d7dceSmrg if (*result != NULL) { 522d522f475Smrg if (**result != '\0') 523d522f475Smrg strcat(*result, "-"); 524d522f475Smrg strcat(*result, value); 525d522f475Smrg } 526d522f475Smrg} 527d522f475Smrg 528d522f475Smrgstatic void 529d522f475Smrgappend_fontname_num(char **result, int value) 530d522f475Smrg{ 531d522f475Smrg if (value < 0) { 532d522f475Smrg append_fontname_str(result, "*"); 533d522f475Smrg } else { 534d522f475Smrg char temp[100]; 535d522f475Smrg sprintf(temp, "%d", value); 536d522f475Smrg append_fontname_str(result, temp); 537d522f475Smrg } 538d522f475Smrg} 539d522f475Smrg 540d522f475Smrg/* 541d522f475Smrg * Take the given font props and try to make a well formed font name specifying 542d522f475Smrg * the same base font and size and everything, but with different weight/width 543d522f475Smrg * according to the parameters. The return value is allocated, should be freed 544d522f475Smrg * by the caller. 545d522f475Smrg */ 546d522f475Smrgstatic char * 5479a64e1c5Smrgderive_font_name(FontNameProperties *props, 54820d2c4d2Smrg const char *use_weight, 549d522f475Smrg int use_average_width, 55020d2c4d2Smrg const char *use_encoding) 551d522f475Smrg{ 552190d7dceSmrg char *result = NULL; 553d522f475Smrg 554d522f475Smrg append_fontname_str(&result, props->beginning); 555d522f475Smrg append_fontname_str(&result, use_weight); 556d522f475Smrg append_fontname_str(&result, props->slant); 557190d7dceSmrg append_fontname_str(&result, NULL); 558190d7dceSmrg append_fontname_str(&result, NULL); 559d522f475Smrg append_fontname_num(&result, props->pixel_size); 560d522f475Smrg append_fontname_str(&result, props->point_size); 561d522f475Smrg append_fontname_num(&result, props->res_x); 562d522f475Smrg append_fontname_num(&result, props->res_y); 563d522f475Smrg append_fontname_str(&result, props->spacing); 564d522f475Smrg append_fontname_num(&result, use_average_width); 565d522f475Smrg append_fontname_str(&result, use_encoding); 566d522f475Smrg 567d4fba8b9Smrg xtermDerivedFont(result); 568d522f475Smrg return result; 569d522f475Smrg} 570d522f475Smrg 571d522f475Smrgstatic char * 5729a64e1c5Smrgbold_font_name(FontNameProperties *props, int use_average_width) 573d522f475Smrg{ 574d522f475Smrg return derive_font_name(props, "bold", use_average_width, props->end); 575d522f475Smrg} 576d522f475Smrg 5779a64e1c5Smrg#if OPT_WIDE_ATTRS 5789a64e1c5Smrgstatic char * 579dfb07bc7Smrgitalic_font_name(FontNameProperties *props, const char *slant) 5809a64e1c5Smrg{ 5819a64e1c5Smrg FontNameProperties myprops = *props; 582dfb07bc7Smrg myprops.slant = slant; 583dfb07bc7Smrg return derive_font_name(&myprops, props->weight, myprops.average_width, props->end); 584dfb07bc7Smrg} 585dfb07bc7Smrg 586dfb07bc7Smrgstatic Boolean 587dfb07bc7Smrgopen_italic_font(XtermWidget xw, int n, FontNameProperties *fp, XTermFonts * data) 588dfb07bc7Smrg{ 589d1603babSmrg static const char *const slant[] = 590dfb07bc7Smrg { 591dfb07bc7Smrg "o", 592dfb07bc7Smrg "i" 593dfb07bc7Smrg }; 594dfb07bc7Smrg Cardinal pass; 595dfb07bc7Smrg Boolean result = False; 596dfb07bc7Smrg 597d4fba8b9Smrg NoFontWarning(data); 598dfb07bc7Smrg for (pass = 0; pass < XtNumber(slant); ++pass) { 599d4fba8b9Smrg char *name; 600190d7dceSmrg if ((name = italic_font_name(fp, slant[pass])) != NULL) { 601dfb07bc7Smrg TRACE(("open_italic_font %s %s\n", 602dfb07bc7Smrg whichFontEnum((VTFontEnum) n), name)); 603d1603babSmrg if (xtermOpenFont(xw, name, data, NULL, False)) { 604190d7dceSmrg result = (data->fs != NULL); 605dfb07bc7Smrg#if OPT_REPORT_FONTS 606dfb07bc7Smrg if (resource.reportFonts) { 607d1603babSmrg ReportFonts("opened italic version of %s:\n\t%s\n", 608d1603babSmrg whichFontEnum((VTFontEnum) n), 609d1603babSmrg name); 610dfb07bc7Smrg } 611dfb07bc7Smrg#endif 612dfb07bc7Smrg } 613dfb07bc7Smrg free(name); 614dfb07bc7Smrg if (result) 615dfb07bc7Smrg break; 616dfb07bc7Smrg } 617dfb07bc7Smrg } 618dfb07bc7Smrg#if OPT_TRACE 619dfb07bc7Smrg if (result) { 620dfb07bc7Smrg XFontStruct *fs = data->fs; 621190d7dceSmrg if (fs != NULL) { 622dfb07bc7Smrg TRACE(("...actual size %dx%d (ascent %d, descent %d)\n", 623dfb07bc7Smrg fs->ascent + 624dfb07bc7Smrg fs->descent, 625dfb07bc7Smrg fs->max_bounds.width, 626dfb07bc7Smrg fs->ascent, 627dfb07bc7Smrg fs->descent)); 628dfb07bc7Smrg } 629dfb07bc7Smrg } 630dfb07bc7Smrg#endif 631dfb07bc7Smrg return result; 6329a64e1c5Smrg} 6339a64e1c5Smrg#endif 6349a64e1c5Smrg 635d522f475Smrg#if OPT_WIDE_CHARS 636d522f475Smrg#define derive_wide_font(props, weight) \ 637d522f475Smrg derive_font_name(props, weight, props->average_width * 2, "ISO10646-1") 638d522f475Smrg 639d522f475Smrgstatic char * 6409a64e1c5Smrgwide_font_name(FontNameProperties *props) 641d522f475Smrg{ 642d522f475Smrg return derive_wide_font(props, "medium"); 643d522f475Smrg} 644d522f475Smrg 645d522f475Smrgstatic char * 6469a64e1c5Smrgwidebold_font_name(FontNameProperties *props) 647d522f475Smrg{ 648d522f475Smrg return derive_wide_font(props, "bold"); 649d522f475Smrg} 650d522f475Smrg#endif /* OPT_WIDE_CHARS */ 651d522f475Smrg 652d522f475Smrg#if OPT_DEC_CHRSET 653d522f475Smrg/* 654d522f475Smrg * Take the given font props and try to make a well formed font name specifying 655d522f475Smrg * the same base font but changed depending on the given attributes and chrset. 656d522f475Smrg * 657d522f475Smrg * For double width fonts, we just double the X-resolution, for double height 658d522f475Smrg * fonts we double the pixel-size and Y-resolution 659d522f475Smrg */ 660d522f475Smrgchar * 661d4fba8b9SmrgxtermSpecialFont(XTermDraw * params) 662d522f475Smrg{ 663d4fba8b9Smrg TScreen *screen = TScreenOf(params->xw); 664d522f475Smrg#if OPT_TRACE 665d522f475Smrg static char old_spacing[80]; 666d522f475Smrg static FontNameProperties old_props; 667d522f475Smrg#endif 668d522f475Smrg FontNameProperties *props; 669190d7dceSmrg char *result = NULL; 67020d2c4d2Smrg const char *weight; 671d522f475Smrg int pixel_size; 672d522f475Smrg int res_x; 673d522f475Smrg int res_y; 674d522f475Smrg 675dfb07bc7Smrg props = get_font_name_props(screen->display, 676190d7dceSmrg GetNormalFont(screen, fNorm)->fs, NULL); 677190d7dceSmrg if (props == NULL) 678d522f475Smrg return result; 679d522f475Smrg 680d522f475Smrg pixel_size = props->pixel_size; 681d522f475Smrg res_x = props->res_x; 682d522f475Smrg res_y = props->res_y; 683d4fba8b9Smrg if (params->attr_flags & BOLD) 684d522f475Smrg weight = "bold"; 685d522f475Smrg else 686d522f475Smrg weight = props->weight; 687d522f475Smrg 688d4fba8b9Smrg if (CSET_DOUBLE(params->this_chrset)) 689d522f475Smrg res_x *= 2; 690d522f475Smrg 691d4fba8b9Smrg if (params->this_chrset == CSET_DHL_TOP 692d4fba8b9Smrg || params->this_chrset == CSET_DHL_BOT) { 693d522f475Smrg res_y *= 2; 694d522f475Smrg pixel_size *= 2; 695d522f475Smrg } 696d522f475Smrg#if OPT_TRACE 697d522f475Smrg if (old_props.res_x != res_x 698d522f475Smrg || old_props.res_x != res_y 699d522f475Smrg || old_props.pixel_size != pixel_size 700d522f475Smrg || strcmp(old_props.spacing, props->spacing)) { 7019a64e1c5Smrg TRACE(("xtermSpecialFont(atts = %#x, draw = %#x, chrset = %#x)\n", 702d4fba8b9Smrg params->attr_flags, params->draw_flags, params->this_chrset)); 703d522f475Smrg TRACE(("res_x = %d\n", res_x)); 704d522f475Smrg TRACE(("res_y = %d\n", res_y)); 705d522f475Smrg TRACE(("point_size = %s\n", props->point_size)); 706d522f475Smrg TRACE(("pixel_size = %d\n", pixel_size)); 707d522f475Smrg TRACE(("spacing = %s\n", props->spacing)); 708d522f475Smrg old_props.res_x = res_x; 709037a25ddSmrg old_props.res_y = res_y; 710d522f475Smrg old_props.pixel_size = pixel_size; 7110bd37d32Smrg old_props.spacing = old_spacing; 7120bd37d32Smrg sprintf(old_spacing, "%.*s", (int) sizeof(old_spacing) - 2, props->spacing); 713d522f475Smrg } 714d522f475Smrg#endif 715d522f475Smrg 716d522f475Smrg append_fontname_str(&result, props->beginning); 717d522f475Smrg append_fontname_str(&result, weight); 718d522f475Smrg append_fontname_str(&result, props->slant); 719d522f475Smrg append_fontname_str(&result, props->wideness); 720d522f475Smrg append_fontname_str(&result, props->add_style); 721d522f475Smrg append_fontname_num(&result, pixel_size); 722d522f475Smrg append_fontname_str(&result, props->point_size); 723d4fba8b9Smrg append_fontname_num(&result, (params->draw_flags & NORESOLUTION) ? -1 : res_x); 724d4fba8b9Smrg append_fontname_num(&result, (params->draw_flags & NORESOLUTION) ? -1 : res_y); 725d522f475Smrg append_fontname_str(&result, props->spacing); 726190d7dceSmrg append_fontname_str(&result, NULL); 727d522f475Smrg append_fontname_str(&result, props->end); 728d522f475Smrg 729d4fba8b9Smrg xtermDerivedFont(result); 730d522f475Smrg return result; 731d522f475Smrg} 732d522f475Smrg#endif /* OPT_DEC_CHRSET */ 733d522f475Smrg 734d522f475Smrg/* 735d522f475Smrg * Case-independent comparison for font-names, including wildcards. 736d522f475Smrg * XLFD allows '?' as a wildcard, but we do not handle that (no one seems 737d522f475Smrg * to use it). 738d522f475Smrg */ 739d522f475Smrgstatic Bool 740492d43a5Smrgsame_font_name(const char *pattern, const char *match) 741d522f475Smrg{ 742956cc18dSsnj Bool result = False; 743956cc18dSsnj 744956cc18dSsnj if (pattern && match) { 745956cc18dSsnj while (*pattern && *match) { 746956cc18dSsnj if (*pattern == *match) { 747956cc18dSsnj pattern++; 748956cc18dSsnj match++; 749956cc18dSsnj } else if (*pattern == '*' || *match == '*') { 750956cc18dSsnj if (same_font_name(pattern + 1, match)) { 751956cc18dSsnj return True; 752956cc18dSsnj } else if (same_font_name(pattern, match + 1)) { 753956cc18dSsnj return True; 754956cc18dSsnj } else { 755956cc18dSsnj return False; 756956cc18dSsnj } 757d522f475Smrg } else { 758956cc18dSsnj int p = x_toupper(*pattern++); 759956cc18dSsnj int m = x_toupper(*match++); 760956cc18dSsnj if (p != m) 761956cc18dSsnj return False; 762d522f475Smrg } 763d522f475Smrg } 764956cc18dSsnj result = (*pattern == *match); /* both should be NUL */ 765d522f475Smrg } 766956cc18dSsnj return result; 767d522f475Smrg} 768d522f475Smrg 769d522f475Smrg/* 770d522f475Smrg * Double-check the fontname that we asked for versus what the font server 771d522f475Smrg * actually gave us. The larger fixed fonts do not always have a matching bold 772d522f475Smrg * font, and the font server may try to scale another font or otherwise 773d522f475Smrg * substitute a mismatched font. 774d522f475Smrg * 775d522f475Smrg * If we cannot get what we requested, we will fallback to the original 776d522f475Smrg * behavior, which simulates bold by overstriking each character at one pixel 777d522f475Smrg * offset. 778d522f475Smrg */ 779d522f475Smrgstatic int 7809a64e1c5Smrggot_bold_font(Display *dpy, XFontStruct *fs, String requested) 781d522f475Smrg{ 782190d7dceSmrg char *actual = NULL; 783d522f475Smrg int got; 784d522f475Smrg 785190d7dceSmrg if (get_font_name_props(dpy, fs, &actual) == NULL) 786d522f475Smrg got = 0; 787d522f475Smrg else 788d522f475Smrg got = same_font_name(requested, actual); 7890bd37d32Smrg free(actual); 790d522f475Smrg return got; 791d522f475Smrg} 792d522f475Smrg 7939a64e1c5Smrg/* 7949a64e1c5Smrg * Check normal/bold (or wide/wide-bold) font pairs to see if we will be able 7959a64e1c5Smrg * to check for missing glyphs in a comparable manner. 7969a64e1c5Smrg */ 7979a64e1c5Smrgstatic int 7989a64e1c5Smrgcomparable_metrics(XFontStruct *normal, XFontStruct *bold) 7999a64e1c5Smrg{ 8009a64e1c5Smrg#define DATA "comparable_metrics: " 8019a64e1c5Smrg int result = 0; 8029a64e1c5Smrg 803190d7dceSmrg if (normal == NULL || bold == NULL) { 804dfb07bc7Smrg ; 805dfb07bc7Smrg } else if (normal->all_chars_exist) { 8069a64e1c5Smrg if (bold->all_chars_exist) { 8079a64e1c5Smrg result = 1; 8089a64e1c5Smrg } else { 8099a64e1c5Smrg TRACE((DATA "all chars exist in normal font, but not in bold\n")); 8109a64e1c5Smrg } 811190d7dceSmrg } else if (normal->per_char != NULL) { 812190d7dceSmrg if (bold->per_char != NULL) { 8139a64e1c5Smrg result = 1; 8149a64e1c5Smrg } else { 8159a64e1c5Smrg TRACE((DATA "normal font has per-char metrics, but not bold\n")); 8169a64e1c5Smrg } 8179a64e1c5Smrg } else { 8189a64e1c5Smrg TRACE((DATA "normal font is not very good!\n")); 8199a64e1c5Smrg result = 1; /* give in (we're not going in reverse) */ 8209a64e1c5Smrg } 8219a64e1c5Smrg return result; 8229a64e1c5Smrg#undef DATA 8239a64e1c5Smrg} 8249a64e1c5Smrg 825d522f475Smrg/* 826d522f475Smrg * If the font server tries to adjust another font, it may not adjust it 827d522f475Smrg * properly. Check that the bounding boxes are compatible. Otherwise we'll 828d522f475Smrg * leave trash on the display when we mix normal and bold fonts. 829d522f475Smrg */ 830d522f475Smrgstatic int 8319a64e1c5Smrgsame_font_size(XtermWidget xw, XFontStruct *nfs, XFontStruct *bfs) 832d522f475Smrg{ 833956cc18dSsnj TScreen *screen = TScreenOf(xw); 834dfb07bc7Smrg int result = 0; 835dfb07bc7Smrg 836190d7dceSmrg if (nfs != NULL && bfs != NULL) { 837dfb07bc7Smrg TRACE(("same_font_size height %d/%d, min %d/%d max %d/%d\n", 838dfb07bc7Smrg nfs->ascent + nfs->descent, 839dfb07bc7Smrg bfs->ascent + bfs->descent, 840dfb07bc7Smrg nfs->min_bounds.width, bfs->min_bounds.width, 841dfb07bc7Smrg nfs->max_bounds.width, bfs->max_bounds.width)); 842dfb07bc7Smrg result = screen->free_bold_box 843dfb07bc7Smrg || ((nfs->ascent + nfs->descent) == (bfs->ascent + bfs->descent) 844dfb07bc7Smrg && (nfs->min_bounds.width == bfs->min_bounds.width 845dfb07bc7Smrg || nfs->min_bounds.width == bfs->min_bounds.width + 1) 846dfb07bc7Smrg && (nfs->max_bounds.width == bfs->max_bounds.width 847dfb07bc7Smrg || nfs->max_bounds.width == bfs->max_bounds.width + 1)); 848dfb07bc7Smrg } 849dfb07bc7Smrg return result; 850d522f475Smrg} 851d522f475Smrg 852d522f475Smrg/* 853d522f475Smrg * Check if the font looks like it has fixed width 854d522f475Smrg */ 855d522f475Smrgstatic int 8569a64e1c5Smrgis_fixed_font(XFontStruct *fs) 857d522f475Smrg{ 858d522f475Smrg if (fs) 859d522f475Smrg return (fs->min_bounds.width == fs->max_bounds.width); 860d522f475Smrg return 1; 861d522f475Smrg} 862d522f475Smrg 863d4fba8b9Smrgstatic int 864d4fba8b9Smrgdiffering_widths(XFontStruct *a, XFontStruct *b) 865d4fba8b9Smrg{ 866d4fba8b9Smrg int result = 0; 867d4fba8b9Smrg if (a != NULL && b != NULL && a->max_bounds.width != b->max_bounds.width) 868d4fba8b9Smrg result = 1; 869d4fba8b9Smrg return result; 870d4fba8b9Smrg} 871d4fba8b9Smrg 872d522f475Smrg/* 873d522f475Smrg * Check if the font looks like a double width font (i.e. contains 874d522f475Smrg * characters of width X and 2X 875d522f475Smrg */ 876d522f475Smrg#if OPT_WIDE_CHARS 877d522f475Smrgstatic int 8789a64e1c5Smrgis_double_width_font(XFontStruct *fs) 879d522f475Smrg{ 880d4fba8b9Smrg return (fs != NULL && ((2 * fs->min_bounds.width) == fs->max_bounds.width)); 881d522f475Smrg} 882d522f475Smrg#else 883d522f475Smrg#define is_double_width_font(fs) 0 884d522f475Smrg#endif 885d522f475Smrg 886d522f475Smrg#if OPT_WIDE_CHARS && OPT_RENDERFONT && defined(HAVE_TYPE_FCCHAR32) 887d522f475Smrg#define HALF_WIDTH_TEST_STRING "1234567890" 888d522f475Smrg 889d522f475Smrg/* '1234567890' in Chinese characters in UTF-8 */ 890d522f475Smrg#define FULL_WIDTH_TEST_STRING "\xe4\xb8\x80\xe4\xba\x8c\xe4\xb8\x89" \ 891d522f475Smrg "\xe5\x9b\x9b\xe4\xba\x94" \ 892d522f475Smrg "\xef\xa7\x91\xe4\xb8\x83\xe5\x85\xab" \ 893d522f475Smrg "\xe4\xb9\x9d\xef\xa6\xb2" 894d522f475Smrg 895d522f475Smrg/* '1234567890' in Korean script in UTF-8 */ 896d522f475Smrg#define FULL_WIDTH_TEST_STRING2 "\xec\x9d\xbc\xec\x9d\xb4\xec\x82\xbc" \ 897d522f475Smrg "\xec\x82\xac\xec\x98\xa4" \ 898d522f475Smrg "\xec\x9c\xa1\xec\xb9\xa0\xed\x8c\x94" \ 899d522f475Smrg "\xea\xb5\xac\xec\x98\x81" 900d522f475Smrg 901d522f475Smrg#define HALF_WIDTH_CHAR1 0x0031 /* '1' */ 902d522f475Smrg#define HALF_WIDTH_CHAR2 0x0057 /* 'W' */ 903d522f475Smrg#define FULL_WIDTH_CHAR1 0x4E00 /* CJK Ideograph 'number one' */ 904d522f475Smrg#define FULL_WIDTH_CHAR2 0xAC00 /* Korean script syllable 'Ka' */ 905d522f475Smrg 906d522f475Smrgstatic Bool 9079a64e1c5Smrgis_double_width_font_xft(Display *dpy, XftFont *font) 908d522f475Smrg{ 909d522f475Smrg XGlyphInfo gi1, gi2; 910d522f475Smrg FcChar32 c1 = HALF_WIDTH_CHAR1, c2 = HALF_WIDTH_CHAR2; 9110bd37d32Smrg String fwstr = FULL_WIDTH_TEST_STRING; 9120bd37d32Smrg String hwstr = HALF_WIDTH_TEST_STRING; 913d522f475Smrg 914d522f475Smrg /* Some Korean fonts don't have Chinese characters at all. */ 915d522f475Smrg if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR1)) { 916d522f475Smrg if (!XftCharExists(dpy, font, FULL_WIDTH_CHAR2)) 917d522f475Smrg return False; /* Not a CJK font */ 918d522f475Smrg else /* a Korean font without CJK Ideographs */ 919d522f475Smrg fwstr = FULL_WIDTH_TEST_STRING2; 920d522f475Smrg } 921d522f475Smrg 922d522f475Smrg XftTextExtents32(dpy, font, &c1, 1, &gi1); 923d522f475Smrg XftTextExtents32(dpy, font, &c2, 1, &gi2); 924d522f475Smrg if (gi1.xOff != gi2.xOff) /* Not a fixed-width font */ 925d522f475Smrg return False; 926d522f475Smrg 9270bd37d32Smrg XftTextExtentsUtf8(dpy, 9280bd37d32Smrg font, 9290bd37d32Smrg (_Xconst FcChar8 *) hwstr, 9300bd37d32Smrg (int) strlen(hwstr), 9310bd37d32Smrg &gi1); 9320bd37d32Smrg XftTextExtentsUtf8(dpy, 9330bd37d32Smrg font, 9340bd37d32Smrg (_Xconst FcChar8 *) fwstr, 9350bd37d32Smrg (int) strlen(fwstr), 9360bd37d32Smrg &gi2); 937d522f475Smrg 938d522f475Smrg /* 939d522f475Smrg * fontconfig and Xft prior to 2.2(?) set the width of half-width 940d522f475Smrg * characters identical to that of full-width character in CJK double-width 941d522f475Smrg * (bi-width / monospace) font even though the former is half as wide as 942d522f475Smrg * the latter. This was fixed sometime before the release of fontconfig 943d522f475Smrg * 2.2 in early 2003. See 944d522f475Smrg * http://bugzilla.mozilla.org/show_bug.cgi?id=196312 945d522f475Smrg * In the meantime, we have to check both possibilities. 946d522f475Smrg */ 947d522f475Smrg return ((2 * gi1.xOff == gi2.xOff) || (gi1.xOff == gi2.xOff)); 948d522f475Smrg} 949d522f475Smrg#else 950d522f475Smrg#define is_double_width_font_xft(dpy, xftfont) 0 951d522f475Smrg#endif 952d522f475Smrg 953190d7dceSmrg#define EmptyFont(fs) (fs != NULL \ 954d522f475Smrg && ((fs)->ascent + (fs)->descent == 0 \ 955d522f475Smrg || (fs)->max_bounds.width == 0)) 956d522f475Smrg 957d522f475Smrg#define FontSize(fs) (((fs)->ascent + (fs)->descent) \ 958d522f475Smrg * (fs)->max_bounds.width) 959d522f475Smrg 960d522f475Smrgconst VTFontNames * 96120d2c4d2SmrgxtermFontName(const char *normal) 962d522f475Smrg{ 963d522f475Smrg static VTFontNames data; 9649a64e1c5Smrg FREE_STRING(data.f_n); 965d522f475Smrg memset(&data, 0, sizeof(data)); 966dfb07bc7Smrg if (normal) 967dfb07bc7Smrg data.f_n = x_strdup(normal); 968dfb07bc7Smrg return &data; 969dfb07bc7Smrg} 970dfb07bc7Smrg 971dfb07bc7Smrgconst VTFontNames * 972dfb07bc7SmrgdefaultVTFontNames(XtermWidget xw) 973dfb07bc7Smrg{ 974dfb07bc7Smrg static VTFontNames data; 975dfb07bc7Smrg memset(&data, 0, sizeof(data)); 976dfb07bc7Smrg data.f_n = DefaultFontN(xw); 977dfb07bc7Smrg data.f_b = DefaultFontB(xw); 978dfb07bc7Smrg#if OPT_WIDE_CHARS 979dfb07bc7Smrg data.f_w = DefaultFontW(xw); 980dfb07bc7Smrg data.f_wb = DefaultFontWB(xw); 981dfb07bc7Smrg#endif 982d522f475Smrg return &data; 983d522f475Smrg} 984d522f475Smrg 985d522f475Smrgstatic void 986fa3f02f3Smrgcache_menu_font_name(TScreen *screen, int fontnum, int which, const char *name) 987d522f475Smrg{ 988190d7dceSmrg if (name != NULL) { 9899a64e1c5Smrg String last = screen->menu_font_names[fontnum][which]; 990190d7dceSmrg if (last != NULL) { 991d522f475Smrg if (strcmp(last, name)) { 9929a64e1c5Smrg FREE_STRING(last); 993d522f475Smrg TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name)); 994d522f475Smrg screen->menu_font_names[fontnum][which] = x_strdup(name); 995d522f475Smrg } 996d522f475Smrg } else { 997d522f475Smrg TRACE(("caching menu fontname %d.%d %s\n", fontnum, which, name)); 998d522f475Smrg screen->menu_font_names[fontnum][which] = x_strdup(name); 999d522f475Smrg } 1000d522f475Smrg } 1001d522f475Smrg} 1002d522f475Smrg 1003dfb07bc7Smrgstatic void 1004d4fba8b9SmrgcannotFont(XtermWidget xw, const char *who, const char *tag, const char *name) 1005dfb07bc7Smrg{ 1006d4fba8b9Smrg static NameList *reported; 1007d4fba8b9Smrg NameList *list; 1008dfb07bc7Smrg 1009dfb07bc7Smrg switch (xw->misc.fontWarnings) { 1010dfb07bc7Smrg case fwNever: 1011dfb07bc7Smrg return; 1012dfb07bc7Smrg case fwResource: 1013d4fba8b9Smrg if (is_derived_font_name(name)) 1014d4fba8b9Smrg return; 1015dfb07bc7Smrg break; 1016dfb07bc7Smrg case fwAlways: 1017dfb07bc7Smrg break; 1018dfb07bc7Smrg } 1019190d7dceSmrg for (list = reported; list != NULL; list = list->next) { 1020d4fba8b9Smrg if (!x_strcasecmp(name, list->name)) { 1021d4fba8b9Smrg return; 1022d4fba8b9Smrg } 1023d4fba8b9Smrg } 1024190d7dceSmrg if ((list = TypeMalloc(NameList)) != NULL) { 1025d4fba8b9Smrg list->name = x_strdup(name); 1026d4fba8b9Smrg list->next = reported; 1027d4fba8b9Smrg reported = list; 1028d4fba8b9Smrg } 1029d4fba8b9Smrg xtermWarning("cannot %s%s%s %sfont \"%s\"\n", 1030d4fba8b9Smrg who, *tag ? " " : "", tag, 1031d4fba8b9Smrg is_derived_font_name(name) ? "derived " : "", 1032d4fba8b9Smrg name); 1033dfb07bc7Smrg} 1034dfb07bc7Smrg 1035d4fba8b9Smrg#if OPT_RENDERFONT 1036d4fba8b9Smrgstatic void 1037d4fba8b9SmrgnoUsableXft(XtermWidget xw, const char *name) 1038d4fba8b9Smrg{ 1039d4fba8b9Smrg switch (xw->misc.fontWarnings) { 1040d4fba8b9Smrg case fwNever: 1041d4fba8b9Smrg return; 1042d4fba8b9Smrg case fwResource: 1043d4fba8b9Smrg /* these combinations of wide/bold/italic are all "derived" */ 1044d4fba8b9Smrg return; 1045d4fba8b9Smrg case fwAlways: 1046d4fba8b9Smrg break; 1047d4fba8b9Smrg } 1048d4fba8b9Smrg xtermWarning("did not find a usable %s TrueType font\n", name); 1049d4fba8b9Smrg} 1050d4fba8b9Smrg#endif 1051d4fba8b9Smrg 10528f44fb3bSmrgXFontStruct * 10538f44fb3bSmrgxtermLoadQueryFont(XtermWidget xw, const char *name) 10548f44fb3bSmrg{ 10558f44fb3bSmrg XFontStruct *result = NULL; 10568f44fb3bSmrg size_t have = strlen(name); 10578f44fb3bSmrg if (have == 0 || have > MAX_U_STRING) { 10588f44fb3bSmrg ; /* just ignore it */ 10598f44fb3bSmrg } else { 10608f44fb3bSmrg TScreen *screen = TScreenOf(xw); 10618f44fb3bSmrg result = XLoadQueryFont(screen->display, name); 10628f44fb3bSmrg } 10638f44fb3bSmrg return result; 10648f44fb3bSmrg} 10658f44fb3bSmrg 1066d522f475Smrg/* 1067d1603babSmrg * Open the given font and verify that it is non-empty. Return false on 1068d522f475Smrg * failure. 1069d522f475Smrg */ 1070d522f475SmrgBool 1071956cc18dSsnjxtermOpenFont(XtermWidget xw, 1072956cc18dSsnj const char *name, 1073956cc18dSsnj XTermFonts * result, 1074d1603babSmrg XTermFonts * current, 1075956cc18dSsnj Bool force) 1076d522f475Smrg{ 1077d522f475Smrg Bool code = False; 1078d522f475Smrg 1079d4fba8b9Smrg TRACE(("xtermOpenFont %d:%d '%s'\n", 1080d4fba8b9Smrg result->warn, xw->misc.fontWarnings, NonNull(name))); 1081d1603babSmrg 1082492d43a5Smrg if (!IsEmpty(name)) { 1083d1603babSmrg Bool existing = (current != NULL 1084d1603babSmrg && current->fs != NULL 1085d1603babSmrg && current->fn != NULL); 1086d1603babSmrg 1087190d7dceSmrg if ((result->fs = xtermLoadQueryFont(xw, name)) != NULL) { 1088956cc18dSsnj code = True; 1089956cc18dSsnj if (EmptyFont(result->fs)) { 1090dfb07bc7Smrg xtermCloseFont(xw, result); 1091956cc18dSsnj code = False; 1092956cc18dSsnj } else { 1093956cc18dSsnj result->fn = x_strdup(name); 1094956cc18dSsnj } 109520d2c4d2Smrg } else if (XmuCompareISOLatin1(name, DEFFONT) != 0) { 1096dfb07bc7Smrg if (result->warn <= xw->misc.fontWarnings 1097956cc18dSsnj#if OPT_RENDERFONT 1098956cc18dSsnj && !UsingRenderFont(xw) 1099956cc18dSsnj#endif 1100956cc18dSsnj ) { 1101dfb07bc7Smrg cannotFont(xw, "load", "", name); 1102956cc18dSsnj } else { 1103492d43a5Smrg TRACE(("xtermOpenFont: cannot load font '%s'\n", name)); 1104956cc18dSsnj } 1105d1603babSmrg if (existing) { 1106d1603babSmrg TRACE(("...continue using font '%s'\n", current->fn)); 1107d1603babSmrg result->fn = x_strdup(current->fn); 1108d1603babSmrg result->fs = current->fs; 1109d1603babSmrg } else if (force) { 1110d4fba8b9Smrg NoFontWarning(result); 1111d1603babSmrg code = xtermOpenFont(xw, DEFFONT, result, NULL, True); 1112956cc18dSsnj } 1113d522f475Smrg } 1114d522f475Smrg } 1115d4fba8b9Smrg NoFontWarning(result); 1116d522f475Smrg return code; 1117d522f475Smrg} 1118d522f475Smrg 1119d522f475Smrg/* 1120956cc18dSsnj * Close the font and free the font info. 1121d522f475Smrg */ 1122dfb07bc7Smrgvoid 1123d522f475SmrgxtermCloseFont(XtermWidget xw, XTermFonts * fnt) 1124d522f475Smrg{ 1125190d7dceSmrg if (fnt != NULL && fnt->fs != NULL) { 1126d522f475Smrg TScreen *screen = TScreenOf(xw); 1127d522f475Smrg 1128d522f475Smrg clrCgsFonts(xw, WhichVWin(screen), fnt); 1129d522f475Smrg XFreeFont(screen->display, fnt->fs); 1130d522f475Smrg xtermFreeFontInfo(fnt); 1131d522f475Smrg } 1132d522f475Smrg} 1133d522f475Smrg 1134037a25ddSmrg/* 1135037a25ddSmrg * Close and free the font (as well as any aliases). 1136037a25ddSmrg */ 1137037a25ddSmrgstatic void 1138037a25ddSmrgxtermCloseFont2(XtermWidget xw, XTermFonts * fnts, int which) 1139037a25ddSmrg{ 1140037a25ddSmrg XFontStruct *thisFont = fnts[which].fs; 1141037a25ddSmrg 1142190d7dceSmrg if (thisFont != NULL) { 1143037a25ddSmrg int k; 1144037a25ddSmrg 1145037a25ddSmrg xtermCloseFont(xw, &fnts[which]); 1146037a25ddSmrg for (k = 0; k < fMAX; ++k) { 1147037a25ddSmrg if (k != which) { 1148037a25ddSmrg if (thisFont == fnts[k].fs) { 1149037a25ddSmrg xtermFreeFontInfo(&fnts[k]); 1150037a25ddSmrg } 1151037a25ddSmrg } 1152037a25ddSmrg } 1153037a25ddSmrg } 1154037a25ddSmrg} 1155037a25ddSmrg 1156d522f475Smrg/* 1157d522f475Smrg * Close the listed fonts, noting that some may use copies of the pointer. 1158d522f475Smrg */ 1159d522f475Smrgvoid 1160d522f475SmrgxtermCloseFonts(XtermWidget xw, XTermFonts * fnts) 1161d522f475Smrg{ 1162037a25ddSmrg int j; 1163d522f475Smrg 1164d522f475Smrg for (j = 0; j < fMAX; ++j) { 1165037a25ddSmrg xtermCloseFont2(xw, fnts, j); 1166d522f475Smrg } 1167d522f475Smrg} 1168d522f475Smrg 1169d522f475Smrg/* 1170d522f475Smrg * Make a copy of the source, assuming the XFontStruct's to be unique, but 1171d522f475Smrg * ensuring that the names are reallocated to simplify freeing. 1172d522f475Smrg */ 1173d522f475Smrgvoid 1174d522f475SmrgxtermCopyFontInfo(XTermFonts * target, XTermFonts * source) 1175d522f475Smrg{ 1176d522f475Smrg xtermFreeFontInfo(target); 1177d522f475Smrg target->chrset = source->chrset; 1178d522f475Smrg target->flags = source->flags; 1179d522f475Smrg target->fn = x_strdup(source->fn); 1180d522f475Smrg target->fs = source->fs; 1181dfb07bc7Smrg target->warn = source->warn; 1182d522f475Smrg} 1183d522f475Smrg 1184d522f475Smrgvoid 1185d522f475SmrgxtermFreeFontInfo(XTermFonts * target) 1186d522f475Smrg{ 1187d522f475Smrg target->chrset = 0; 1188d522f475Smrg target->flags = 0; 1189d4fba8b9Smrg FreeAndNull(target->fn); 1190190d7dceSmrg target->fs = NULL; 1191d522f475Smrg} 1192d522f475Smrg 1193fa3f02f3Smrg#if OPT_REPORT_FONTS 1194fa3f02f3Smrgstatic void 1195fa3f02f3SmrgreportXCharStruct(const char *tag, XCharStruct * cs) 1196fa3f02f3Smrg{ 1197d1603babSmrg ReportFonts("\t\t%s:\n", tag); 1198d1603babSmrg ReportFonts("\t\t\tlbearing: %d\n", cs->lbearing); 1199d1603babSmrg ReportFonts("\t\t\trbearing: %d\n", cs->rbearing); 1200d1603babSmrg ReportFonts("\t\t\twidth: %d\n", cs->width); 1201d1603babSmrg ReportFonts("\t\t\tascent: %d\n", cs->ascent); 1202d1603babSmrg ReportFonts("\t\t\tdescent: %d\n", cs->descent); 1203fa3f02f3Smrg} 1204fa3f02f3Smrg 1205190d7dceSmrgstatic void 1206190d7dceSmrgfillXCharStruct(XCharStruct * cs, short value) 1207190d7dceSmrg{ 1208190d7dceSmrg cs->lbearing = value; 1209190d7dceSmrg cs->rbearing = value; 1210190d7dceSmrg cs->width = value; 1211190d7dceSmrg cs->ascent = value; 1212190d7dceSmrg cs->descent = value; 1213190d7dceSmrg} 1214190d7dceSmrg 1215190d7dceSmrg/* if the per-character data differs from the summary, that is a problem */ 1216190d7dceSmrgstatic void 1217190d7dceSmrgcompareXCharStruct(const char *tag, XCharStruct * actual, XCharStruct * expect) 1218190d7dceSmrg{ 1219190d7dceSmrg#define CompareXCharStruct(field) \ 1220190d7dceSmrg if (actual->field != expect->field) \ 1221190d7dceSmrg ReportFonts("\t\t%s %s differs: %d\n", tag, #field, actual->field) 1222190d7dceSmrg CompareXCharStruct(lbearing); 1223190d7dceSmrg CompareXCharStruct(rbearing); 1224190d7dceSmrg CompareXCharStruct(width); 1225190d7dceSmrg CompareXCharStruct(ascent); 1226190d7dceSmrg CompareXCharStruct(descent); 1227190d7dceSmrg} 1228190d7dceSmrg 1229190d7dceSmrgstatic void 1230190d7dceSmrgreportXPerChar(XFontStruct *fs) 1231190d7dceSmrg{ 1232190d7dceSmrg XCharStruct *cs = fs->per_char; 1233190d7dceSmrg 1234190d7dceSmrg if (cs != NULL) { 1235190d7dceSmrg XCharStruct min_bounds; 1236190d7dceSmrg XCharStruct max_bounds; 1237190d7dceSmrg int valid = 0; 1238190d7dceSmrg int total = 0; 1239190d7dceSmrg unsigned first_char = 0; 1240190d7dceSmrg unsigned last_char = 0; 1241190d7dceSmrg unsigned ch; 1242190d7dceSmrg 1243190d7dceSmrg if (fs->max_byte1 == 0) { 1244190d7dceSmrg first_char = fs->min_char_or_byte2; 1245190d7dceSmrg last_char = fs->max_char_or_byte2; 1246190d7dceSmrg } else { 1247190d7dceSmrg first_char = (fs->min_byte1 * 256) + fs->min_char_or_byte2; 1248190d7dceSmrg last_char = (fs->max_byte1 * 256) + fs->max_char_or_byte2; 1249190d7dceSmrg } 1250190d7dceSmrg 1251190d7dceSmrg fillXCharStruct(&max_bounds, -32768); 1252190d7dceSmrg fillXCharStruct(&min_bounds, 32767); 1253190d7dceSmrg TRACE2(("\t\tCells: %d..%d\n", first_char, last_char)); 1254190d7dceSmrg for (ch = first_char; ch < last_char; ++ch) { 1255190d7dceSmrg XCharStruct *item = cs + ch - first_char; 1256190d7dceSmrg ++total; 1257190d7dceSmrg if (!CI_NONEXISTCHAR(item)) { 1258190d7dceSmrg ++valid; 1259190d7dceSmrg#define MIN_BOUNDS(field) min_bounds.field = Min(min_bounds.field, item->field) 1260190d7dceSmrg MIN_BOUNDS(lbearing); 1261190d7dceSmrg MIN_BOUNDS(rbearing); 1262190d7dceSmrg MIN_BOUNDS(width); 1263190d7dceSmrg MIN_BOUNDS(ascent); 1264190d7dceSmrg MIN_BOUNDS(descent); 1265190d7dceSmrg#define MAX_BOUNDS(field) max_bounds.field = Max(max_bounds.field, item->field) 1266190d7dceSmrg MAX_BOUNDS(lbearing); 1267190d7dceSmrg MAX_BOUNDS(rbearing); 1268190d7dceSmrg MAX_BOUNDS(width); 1269190d7dceSmrg MAX_BOUNDS(ascent); 1270190d7dceSmrg MAX_BOUNDS(descent); 1271190d7dceSmrg TRACE2(("\t\t\t%d: cell [%d .. %d] wide %d high %d / %d\n", 1272190d7dceSmrg ch, 1273190d7dceSmrg item->lbearing, 1274190d7dceSmrg item->rbearing, 1275190d7dceSmrg item->width, 1276190d7dceSmrg item->ascent, 1277190d7dceSmrg item->descent)); 1278190d7dceSmrg } else { 1279190d7dceSmrg TRACE(("\t\t\t%d: cell missing\n", ch)); 1280190d7dceSmrg } 1281190d7dceSmrg } 1282190d7dceSmrg ReportFonts("\t\tPer-character: %d/%d\n", valid, total); 1283190d7dceSmrg compareXCharStruct("Max", &max_bounds, &(fs->max_bounds)); 1284190d7dceSmrg compareXCharStruct("Min", &min_bounds, &(fs->min_bounds)); 1285190d7dceSmrg } else { 1286190d7dceSmrg ReportFonts("\t\tPer-character: none\n"); 1287190d7dceSmrg } 1288190d7dceSmrg} 1289190d7dceSmrg 1290fa3f02f3Smrgstatic void 1291fa3f02f3SmrgreportOneVTFont(const char *tag, 1292fa3f02f3Smrg XTermFonts * fnt) 1293fa3f02f3Smrg{ 1294190d7dceSmrg if (!IsEmpty(fnt->fn) && fnt->fs != NULL) { 1295fa3f02f3Smrg XFontStruct *fs = fnt->fs; 1296fa3f02f3Smrg unsigned first_char = 0; 1297fa3f02f3Smrg unsigned last_char = 0; 1298fa3f02f3Smrg 1299fa3f02f3Smrg if (fs->max_byte1 == 0) { 1300fa3f02f3Smrg first_char = fs->min_char_or_byte2; 1301fa3f02f3Smrg last_char = fs->max_char_or_byte2; 1302fa3f02f3Smrg } else { 1303fa3f02f3Smrg first_char = (fs->min_byte1 * 256) + fs->min_char_or_byte2; 1304fa3f02f3Smrg last_char = (fs->max_byte1 * 256) + fs->max_char_or_byte2; 1305fa3f02f3Smrg } 1306fa3f02f3Smrg 1307d1603babSmrg ReportFonts("\t%s: %s\n", tag, NonNull(fnt->fn)); 1308d1603babSmrg ReportFonts("\t\tall chars: %s\n", (fs->all_chars_exist 1309d1603babSmrg ? "yes" 1310d1603babSmrg : "no")); 1311d1603babSmrg ReportFonts("\t\tdefault char: %u\n", fs->default_char); 1312d1603babSmrg ReportFonts("\t\tdirection: %u\n", fs->direction); 1313d1603babSmrg ReportFonts("\t\tascent: %d\n", fs->ascent); 1314d1603babSmrg ReportFonts("\t\tdescent: %d\n", fs->descent); 1315d1603babSmrg ReportFonts("\t\tfirst char: %u\n", first_char); 1316d1603babSmrg ReportFonts("\t\tlast char: %u\n", last_char); 1317d1603babSmrg ReportFonts("\t\tmaximum-chars: %u\n", countGlyphs(fs)); 13189a64e1c5Smrg if (FontLacksMetrics(fnt)) { 1319d1603babSmrg ReportFonts("\t\tmissing-chars: ?\n"); 1320d1603babSmrg ReportFonts("\t\tpresent-chars: ?\n"); 13219a64e1c5Smrg } else { 13229a64e1c5Smrg unsigned missing = 0; 1323037a25ddSmrg unsigned ch; 13249a64e1c5Smrg for (ch = first_char; ch <= last_char; ++ch) { 13259a64e1c5Smrg if (xtermMissingChar(ch, fnt)) { 13269a64e1c5Smrg ++missing; 13279a64e1c5Smrg } 13289a64e1c5Smrg } 1329d1603babSmrg ReportFonts("\t\tmissing-chars: %u\n", missing); 1330d1603babSmrg ReportFonts("\t\tpresent-chars: %u\n", countGlyphs(fs) - missing); 13319a64e1c5Smrg } 1332d1603babSmrg ReportFonts("\t\tmin_byte1: %u\n", fs->min_byte1); 1333d1603babSmrg ReportFonts("\t\tmax_byte1: %u\n", fs->max_byte1); 1334d1603babSmrg ReportFonts("\t\tproperties: %d\n", fs->n_properties); 1335fa3f02f3Smrg reportXCharStruct("min_bounds", &(fs->min_bounds)); 1336fa3f02f3Smrg reportXCharStruct("max_bounds", &(fs->max_bounds)); 1337190d7dceSmrg reportXPerChar(fs); 1338190d7dceSmrg /* TODO: report fs->properties */ 1339fa3f02f3Smrg } 1340fa3f02f3Smrg} 1341fa3f02f3Smrg 1342fa3f02f3Smrgstatic void 1343fa3f02f3SmrgreportVTFontInfo(XtermWidget xw, int fontnum) 1344fa3f02f3Smrg{ 1345fa3f02f3Smrg if (resource.reportFonts) { 1346fa3f02f3Smrg TScreen *screen = TScreenOf(xw); 1347fa3f02f3Smrg 1348fa3f02f3Smrg if (fontnum) { 1349d1603babSmrg ReportFonts("Loaded VTFonts(font%d)\n", fontnum); 1350fa3f02f3Smrg } else { 1351d1603babSmrg ReportFonts("Loaded VTFonts(default)\n"); 1352fa3f02f3Smrg } 1353dfb07bc7Smrg 1354190d7dceSmrg#define ReportOneVTFont(name) reportOneVTFont(#name, screen->fnts + name) 1355190d7dceSmrg ReportOneVTFont(fNorm); 1356190d7dceSmrg ReportOneVTFont(fBold); 1357fa3f02f3Smrg#if OPT_WIDE_CHARS 1358190d7dceSmrg ReportOneVTFont(fWide); 1359190d7dceSmrg ReportOneVTFont(fWBold); 1360fa3f02f3Smrg#endif 1361fa3f02f3Smrg } 1362fa3f02f3Smrg} 1363fa3f02f3Smrg#endif 1364fa3f02f3Smrg 13659a64e1c5Smrgvoid 1366d4fba8b9SmrgxtermUpdateFontGCs(XtermWidget xw, MyGetFont myfunc) 13679a64e1c5Smrg{ 13689a64e1c5Smrg TScreen *screen = TScreenOf(xw); 13699a64e1c5Smrg VTwin *win = WhichVWin(screen); 1370d4fba8b9Smrg Pixel new_normal = getXtermFG(xw, xw->flags, xw->cur_foreground); 1371d4fba8b9Smrg Pixel new_revers = getXtermBG(xw, xw->flags, xw->cur_background); 1372dfb07bc7Smrg 13739a64e1c5Smrg setCgsFore(xw, win, gcNorm, new_normal); 13749a64e1c5Smrg setCgsBack(xw, win, gcNorm, new_revers); 1375dfb07bc7Smrg setCgsFont(xw, win, gcNorm, myfunc(screen, fNorm)); 13769a64e1c5Smrg 13779a64e1c5Smrg copyCgs(xw, win, gcBold, gcNorm); 1378d4fba8b9Smrg setCgsFont2(xw, win, gcBold, myfunc(screen, fBold), fBold); 13799a64e1c5Smrg 13809a64e1c5Smrg setCgsFore(xw, win, gcNormReverse, new_revers); 13819a64e1c5Smrg setCgsBack(xw, win, gcNormReverse, new_normal); 1382dfb07bc7Smrg setCgsFont(xw, win, gcNormReverse, myfunc(screen, fNorm)); 13839a64e1c5Smrg 13849a64e1c5Smrg copyCgs(xw, win, gcBoldReverse, gcNormReverse); 1385d4fba8b9Smrg setCgsFont2(xw, win, gcBoldReverse, myfunc(screen, fBold), fBold); 13869a64e1c5Smrg 13879a64e1c5Smrg if_OPT_WIDE_CHARS(screen, { 1388dfb07bc7Smrg XTermFonts *wide_xx = myfunc(screen, fWide); 1389dfb07bc7Smrg XTermFonts *bold_xx = myfunc(screen, fWBold); 1390190d7dceSmrg if (wide_xx->fs != NULL 1391190d7dceSmrg && bold_xx->fs != NULL) { 13929a64e1c5Smrg setCgsFore(xw, win, gcWide, new_normal); 13939a64e1c5Smrg setCgsBack(xw, win, gcWide, new_revers); 1394dfb07bc7Smrg setCgsFont(xw, win, gcWide, wide_xx); 13959a64e1c5Smrg 13969a64e1c5Smrg copyCgs(xw, win, gcWBold, gcWide); 1397dfb07bc7Smrg setCgsFont(xw, win, gcWBold, bold_xx); 13989a64e1c5Smrg 13999a64e1c5Smrg setCgsFore(xw, win, gcWideReverse, new_revers); 14009a64e1c5Smrg setCgsBack(xw, win, gcWideReverse, new_normal); 1401dfb07bc7Smrg setCgsFont(xw, win, gcWideReverse, wide_xx); 14029a64e1c5Smrg 14039a64e1c5Smrg copyCgs(xw, win, gcWBoldReverse, gcWideReverse); 1404dfb07bc7Smrg setCgsFont(xw, win, gcWBoldReverse, bold_xx); 14059a64e1c5Smrg } 14069a64e1c5Smrg }); 14079a64e1c5Smrg} 14089a64e1c5Smrg 1409d4fba8b9Smrg#if OPT_WIDE_ATTRS 1410d4fba8b9Smrgunsigned 1411d4fba8b9SmrgxtermUpdateItalics(XtermWidget xw, unsigned new_attrs, unsigned old_attrs) 1412d4fba8b9Smrg{ 1413c48a5815Smrg TScreen *screen = TScreenOf(xw); 1414c48a5815Smrg 141550027b5bSmrg (void) screen; 1416c48a5815Smrg if (UseItalicFont(screen)) { 1417c48a5815Smrg if ((new_attrs & ATR_ITALIC) && !(old_attrs & ATR_ITALIC)) { 1418c48a5815Smrg xtermLoadItalics(xw); 1419c48a5815Smrg xtermUpdateFontGCs(xw, getItalicFont); 1420c48a5815Smrg } else if (!(new_attrs & ATR_ITALIC) && (old_attrs & ATR_ITALIC)) { 1421c48a5815Smrg xtermUpdateFontGCs(xw, getNormalFont); 1422c48a5815Smrg } 1423d4fba8b9Smrg } 1424d4fba8b9Smrg return new_attrs; 1425d4fba8b9Smrg} 1426d4fba8b9Smrg#endif 1427d4fba8b9Smrg 1428d4fba8b9Smrg#if OPT_TRACE && OPT_BOX_CHARS 14299a64e1c5Smrgstatic void 14309a64e1c5Smrgshow_font_misses(const char *name, XTermFonts * fp) 14319a64e1c5Smrg{ 1432190d7dceSmrg if (fp->fs != NULL) { 14339a64e1c5Smrg if (FontLacksMetrics(fp)) { 14349a64e1c5Smrg TRACE(("%s font lacks metrics\n", name)); 14359a64e1c5Smrg } else if (FontIsIncomplete(fp)) { 14369a64e1c5Smrg TRACE(("%s font is incomplete\n", name)); 14379a64e1c5Smrg } else { 14389a64e1c5Smrg TRACE(("%s font is complete\n", name)); 14399a64e1c5Smrg } 14409a64e1c5Smrg } else { 14419a64e1c5Smrg TRACE(("%s font is missing\n", name)); 14429a64e1c5Smrg } 14439a64e1c5Smrg} 14449a64e1c5Smrg#endif 14459a64e1c5Smrg 1446dfb07bc7Smrgstatic Bool 1447dfb07bc7SmrgloadNormFP(XtermWidget xw, 1448dfb07bc7Smrg char **nameOutP, 1449dfb07bc7Smrg XTermFonts * infoOut, 1450d1603babSmrg XTermFonts * current, 1451dfb07bc7Smrg int fontnum) 1452dfb07bc7Smrg{ 1453dfb07bc7Smrg Bool status = True; 1454dfb07bc7Smrg 1455dfb07bc7Smrg TRACE(("loadNormFP (%s)\n", NonNull(*nameOutP))); 1456dfb07bc7Smrg 1457dfb07bc7Smrg if (!xtermOpenFont(xw, 1458dfb07bc7Smrg *nameOutP, 1459dfb07bc7Smrg infoOut, 1460d1603babSmrg current, (fontnum == fontMenu_default))) { 1461dfb07bc7Smrg /* 1462dfb07bc7Smrg * If we are opening the default font, and it happens to be missing, 1463dfb07bc7Smrg * force that to the compiled-in default font, e.g., "fixed". If we 1464dfb07bc7Smrg * cannot open the font, disable it from the menu. 1465dfb07bc7Smrg */ 1466dfb07bc7Smrg if (fontnum != fontMenu_fontsel) { 1467dfb07bc7Smrg SetItemSensitivity(fontMenuEntries[fontnum].widget, False); 1468dfb07bc7Smrg } 1469dfb07bc7Smrg status = False; 1470dfb07bc7Smrg } 1471dfb07bc7Smrg return status; 1472dfb07bc7Smrg} 1473dfb07bc7Smrg 1474dfb07bc7Smrgstatic Bool 1475dfb07bc7SmrgloadBoldFP(XtermWidget xw, 1476dfb07bc7Smrg char **nameOutP, 1477dfb07bc7Smrg XTermFonts * infoOut, 1478dfb07bc7Smrg const char *nameRef, 1479dfb07bc7Smrg XTermFonts * infoRef, 1480dfb07bc7Smrg int fontnum) 1481dfb07bc7Smrg{ 1482dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 1483dfb07bc7Smrg Bool status = True; 1484dfb07bc7Smrg 1485dfb07bc7Smrg TRACE(("loadBoldFP (%s)\n", NonNull(*nameOutP))); 1486dfb07bc7Smrg 1487dfb07bc7Smrg if (!check_fontname(*nameOutP)) { 1488dfb07bc7Smrg FontNameProperties *fp; 1489dfb07bc7Smrg char *normal = x_strdup(nameRef); 1490dfb07bc7Smrg 1491dfb07bc7Smrg fp = get_font_name_props(screen->display, infoRef->fs, &normal); 1492190d7dceSmrg if (fp != NULL) { 1493d4fba8b9Smrg NoFontWarning(infoOut); 1494dfb07bc7Smrg *nameOutP = bold_font_name(fp, fp->average_width); 1495d1603babSmrg if (!xtermOpenFont(xw, *nameOutP, infoOut, NULL, False)) { 1496dfb07bc7Smrg free(*nameOutP); 1497dfb07bc7Smrg *nameOutP = bold_font_name(fp, -1); 1498d1603babSmrg xtermOpenFont(xw, *nameOutP, infoOut, NULL, False); 1499dfb07bc7Smrg } 1500dfb07bc7Smrg TRACE(("...derived bold '%s'\n", NonNull(*nameOutP))); 1501dfb07bc7Smrg } 1502190d7dceSmrg if (fp == NULL || infoOut->fs == NULL) { 1503dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1504dfb07bc7Smrg TRACE(("...cannot load a matching bold font\n")); 1505dfb07bc7Smrg } else if (comparable_metrics(infoRef->fs, infoOut->fs) 1506dfb07bc7Smrg && same_font_size(xw, infoRef->fs, infoOut->fs) 1507dfb07bc7Smrg && got_bold_font(screen->display, infoOut->fs, *nameOutP)) { 1508dfb07bc7Smrg TRACE(("...got a matching bold font\n")); 1509dfb07bc7Smrg cache_menu_font_name(screen, fontnum, fBold, *nameOutP); 1510dfb07bc7Smrg } else { 1511dfb07bc7Smrg xtermCloseFont2(xw, infoOut - fBold, fBold); 1512dfb07bc7Smrg *infoOut = *infoRef; 1513dfb07bc7Smrg TRACE(("...did not get a matching bold font\n")); 1514dfb07bc7Smrg } 1515dfb07bc7Smrg free(normal); 1516d1603babSmrg } else if (!xtermOpenFont(xw, *nameOutP, infoOut, NULL, False)) { 1517dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1518dfb07bc7Smrg TRACE(("...cannot load bold font '%s'\n", NonNull(*nameOutP))); 1519dfb07bc7Smrg } else { 1520dfb07bc7Smrg cache_menu_font_name(screen, fontnum, fBold, *nameOutP); 1521dfb07bc7Smrg } 1522dfb07bc7Smrg 1523dfb07bc7Smrg /* 1524dfb07bc7Smrg * Most of the time this call to load the font will succeed, even if 1525dfb07bc7Smrg * there is no wide font : the X server doubles the width of the 1526dfb07bc7Smrg * normal font, or similar. 1527dfb07bc7Smrg * 1528dfb07bc7Smrg * But if it did fail for some reason, then nevermind. 1529dfb07bc7Smrg */ 1530dfb07bc7Smrg if (EmptyFont(infoOut->fs)) 1531dfb07bc7Smrg status = False; /* can't use a 0-sized font */ 1532dfb07bc7Smrg 1533dfb07bc7Smrg if (!same_font_size(xw, infoRef->fs, infoOut->fs) 1534dfb07bc7Smrg && (is_fixed_font(infoRef->fs) && is_fixed_font(infoOut->fs))) { 1535dfb07bc7Smrg TRACE(("...ignoring mismatched normal/bold fonts\n")); 1536dfb07bc7Smrg xtermCloseFont2(xw, infoOut - fBold, fBold); 1537dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1538dfb07bc7Smrg } 1539dfb07bc7Smrg 1540dfb07bc7Smrg return status; 1541dfb07bc7Smrg} 1542dfb07bc7Smrg 1543dfb07bc7Smrg#if OPT_WIDE_CHARS 1544dfb07bc7Smrgstatic Bool 1545dfb07bc7SmrgloadWideFP(XtermWidget xw, 1546dfb07bc7Smrg char **nameOutP, 1547dfb07bc7Smrg XTermFonts * infoOut, 1548dfb07bc7Smrg const char *nameRef, 1549dfb07bc7Smrg XTermFonts * infoRef, 1550dfb07bc7Smrg int fontnum) 1551dfb07bc7Smrg{ 1552dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 1553dfb07bc7Smrg Bool status = True; 1554dfb07bc7Smrg 1555dfb07bc7Smrg TRACE(("loadWideFP (%s)\n", NonNull(*nameOutP))); 1556dfb07bc7Smrg 1557d4fba8b9Smrg if (!check_fontname(*nameOutP) 1558d4fba8b9Smrg && (screen->utf8_fonts && !is_double_width_font(infoRef->fs))) { 1559dfb07bc7Smrg char *normal = x_strdup(nameRef); 1560d4fba8b9Smrg FontNameProperties *fp = get_font_name_props(screen->display, 1561d4fba8b9Smrg infoRef->fs, &normal); 1562190d7dceSmrg if (fp != NULL) { 1563dfb07bc7Smrg *nameOutP = wide_font_name(fp); 1564d4fba8b9Smrg NoFontWarning(infoOut); 1565dfb07bc7Smrg } 1566dfb07bc7Smrg free(normal); 1567dfb07bc7Smrg } 1568dfb07bc7Smrg 1569dfb07bc7Smrg if (check_fontname(*nameOutP)) { 1570d1603babSmrg if (xtermOpenFont(xw, *nameOutP, infoOut, NULL, False) 1571d4fba8b9Smrg && is_derived_font_name(*nameOutP) 1572d4fba8b9Smrg && EmptyFont(infoOut->fs)) { 1573d4fba8b9Smrg xtermCloseFont2(xw, infoOut - fWide, fWide); 1574d4fba8b9Smrg } 1575190d7dceSmrg if (infoOut->fs == NULL) { 1576dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1577d4fba8b9Smrg } else { 1578d4fba8b9Smrg TRACE(("...%s wide %s\n", 1579d4fba8b9Smrg is_derived_font_name(*nameOutP) ? "derived" : "given", 1580d4fba8b9Smrg NonNull(*nameOutP))); 1581d4fba8b9Smrg cache_menu_font_name(screen, fontnum, fWide, *nameOutP); 1582dfb07bc7Smrg } 1583dfb07bc7Smrg } else { 1584dfb07bc7Smrg xtermCopyFontInfo(infoOut, infoRef); 1585dfb07bc7Smrg } 1586c48a5815Smrg#define MinWidthOf(fs) fs->min_bounds.width 1587c48a5815Smrg#define MaxWidthOf(fs) fs->max_bounds.width 1588c48a5815Smrg xw->work.force_wideFont = False; 1589c48a5815Smrg if (MaxWidthOf(infoOut->fs) != (2 * MaxWidthOf(infoRef->fs))) { 1590c48a5815Smrg TRACE(("...reference width %d\n", MaxWidthOf(infoRef->fs))); 1591c48a5815Smrg TRACE(("...?? double-width %d\n", 2 * MaxWidthOf(infoRef->fs))); 1592c48a5815Smrg TRACE(("...actual width %d\n", MaxWidthOf(infoOut->fs))); 1593c48a5815Smrg xw->work.force_wideFont = True; 1594c48a5815Smrg } 1595dfb07bc7Smrg return status; 1596dfb07bc7Smrg} 1597dfb07bc7Smrg 1598dfb07bc7Smrgstatic Bool 1599dfb07bc7SmrgloadWBoldFP(XtermWidget xw, 1600dfb07bc7Smrg char **nameOutP, 1601dfb07bc7Smrg XTermFonts * infoOut, 1602dfb07bc7Smrg const char *wideNameRef, XTermFonts * wideInfoRef, 1603dfb07bc7Smrg const char *boldNameRef, XTermFonts * boldInfoRef, 1604dfb07bc7Smrg int fontnum) 1605dfb07bc7Smrg{ 1606dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 1607dfb07bc7Smrg Bool status = True; 1608dfb07bc7Smrg char *bold = NULL; 1609dfb07bc7Smrg 1610dfb07bc7Smrg TRACE(("loadWBoldFP (%s)\n", NonNull(*nameOutP))); 1611dfb07bc7Smrg 1612dfb07bc7Smrg if (!check_fontname(*nameOutP)) { 1613dfb07bc7Smrg FontNameProperties *fp; 1614dfb07bc7Smrg fp = get_font_name_props(screen->display, boldInfoRef->fs, &bold); 1615190d7dceSmrg if (fp != NULL) { 1616dfb07bc7Smrg *nameOutP = widebold_font_name(fp); 1617d4fba8b9Smrg NoFontWarning(infoOut); 1618dfb07bc7Smrg } 1619dfb07bc7Smrg } 1620dfb07bc7Smrg 1621dfb07bc7Smrg if (check_fontname(*nameOutP)) { 1622dfb07bc7Smrg 1623d1603babSmrg if (xtermOpenFont(xw, *nameOutP, infoOut, NULL, False) 1624d4fba8b9Smrg && is_derived_font_name(*nameOutP) 1625dfb07bc7Smrg && !compatibleWideCounts(wideInfoRef->fs, infoOut->fs)) { 1626dfb07bc7Smrg xtermCloseFont2(xw, infoOut - fWBold, fWBold); 1627dfb07bc7Smrg } 1628dfb07bc7Smrg 1629190d7dceSmrg if (infoOut->fs == NULL) { 1630d4fba8b9Smrg if (is_derived_font_name(*nameOutP)) 1631dfb07bc7Smrg free(*nameOutP); 1632dfb07bc7Smrg if (IsEmpty(wideNameRef)) { 1633dfb07bc7Smrg *nameOutP = x_strdup(boldNameRef); 1634dfb07bc7Smrg xtermCopyFontInfo(infoOut, boldInfoRef); 1635dfb07bc7Smrg TRACE(("...cannot load wide-bold, use bold %s\n", 1636dfb07bc7Smrg NonNull(boldNameRef))); 1637dfb07bc7Smrg } else { 1638dfb07bc7Smrg *nameOutP = x_strdup(wideNameRef); 1639dfb07bc7Smrg xtermCopyFontInfo(infoOut, wideInfoRef); 1640dfb07bc7Smrg TRACE(("...cannot load wide-bold, use wide %s\n", 1641dfb07bc7Smrg NonNull(wideNameRef))); 1642dfb07bc7Smrg } 1643dfb07bc7Smrg } else { 1644dfb07bc7Smrg TRACE(("...%s wide/bold %s\n", 1645d4fba8b9Smrg is_derived_font_name(*nameOutP) ? "derived" : "given", 1646dfb07bc7Smrg NonNull(*nameOutP))); 1647dfb07bc7Smrg cache_menu_font_name(screen, fontnum, fWBold, *nameOutP); 1648dfb07bc7Smrg } 1649dfb07bc7Smrg } else if (is_double_width_font(boldInfoRef->fs)) { 1650dfb07bc7Smrg xtermCopyFontInfo(infoOut, boldInfoRef); 1651dfb07bc7Smrg TRACE(("...bold font is double-width, use it %s\n", NonNull(boldNameRef))); 1652dfb07bc7Smrg } else { 1653dfb07bc7Smrg xtermCopyFontInfo(infoOut, wideInfoRef); 1654dfb07bc7Smrg TRACE(("...cannot load wide bold font, use wide %s\n", NonNull(wideNameRef))); 1655dfb07bc7Smrg } 1656dfb07bc7Smrg 1657dfb07bc7Smrg free(bold); 1658dfb07bc7Smrg 1659dfb07bc7Smrg if (EmptyFont(infoOut->fs)) { 1660dfb07bc7Smrg status = False; /* can't use a 0-sized font */ 1661dfb07bc7Smrg } else { 1662dfb07bc7Smrg if ((!comparable_metrics(wideInfoRef->fs, infoOut->fs) 1663dfb07bc7Smrg || (!same_font_size(xw, wideInfoRef->fs, infoOut->fs) 1664dfb07bc7Smrg && is_fixed_font(wideInfoRef->fs) 1665dfb07bc7Smrg && is_fixed_font(infoOut->fs)))) { 1666dfb07bc7Smrg TRACE(("...ignoring mismatched normal/bold wide fonts\n")); 1667dfb07bc7Smrg xtermCloseFont2(xw, infoOut - fWBold, fWBold); 1668dfb07bc7Smrg xtermCopyFontInfo(infoOut, wideInfoRef); 1669dfb07bc7Smrg } 1670dfb07bc7Smrg } 1671dfb07bc7Smrg 1672dfb07bc7Smrg return status; 1673dfb07bc7Smrg} 1674dfb07bc7Smrg#endif 1675dfb07bc7Smrg 1676d1603babSmrg/* 1677d1603babSmrg * Load a given bitmap font, along with the bold/wide variants. 1678d1603babSmrg * Returns nonzero on success. 1679d1603babSmrg */ 1680d522f475Smrgint 1681d522f475SmrgxtermLoadFont(XtermWidget xw, 1682d522f475Smrg const VTFontNames * fonts, 1683d522f475Smrg Bool doresize, 1684d522f475Smrg int fontnum) 1685d522f475Smrg{ 1686956cc18dSsnj TScreen *screen = TScreenOf(xw); 1687d522f475Smrg VTwin *win = WhichVWin(screen); 1688d522f475Smrg 1689d1603babSmrg VTFontNames new_fnames; 1690d1603babSmrg XTermFonts new_fonts[fMAX]; 1691d1603babSmrg XTermFonts old_fonts[fMAX]; 1692d522f475Smrg char *tmpname = NULL; 1693956cc18dSsnj Boolean proportional = False; 1694d1603babSmrg Boolean recovered; 1695d1603babSmrg int code = 0; 1696d522f475Smrg 1697d1603babSmrg memset(&new_fnames, 0, sizeof(new_fnames)); 1698d1603babSmrg memset(new_fonts, 0, sizeof(new_fonts)); 1699d1603babSmrg memcpy(&old_fonts, screen->fnts, sizeof(old_fonts)); 1700d522f475Smrg 1701190d7dceSmrg if (fonts != NULL) 1702d1603babSmrg new_fnames = *fonts; 1703d1603babSmrg if (!check_fontname(new_fnames.f_n)) 1704d1603babSmrg return code; 1705d522f475Smrg 1706d522f475Smrg if (fontnum == fontMenu_fontescape 1707d1603babSmrg && new_fnames.f_n != screen->MenuFontName(fontnum)) { 1708190d7dceSmrg if ((tmpname = x_strdup(new_fnames.f_n)) == NULL) 1709d1603babSmrg return code; 1710d522f475Smrg } 1711d522f475Smrg 1712d1603babSmrg TRACE(("Begin Cgs - xtermLoadFont(%s)\n", new_fnames.f_n)); 1713d522f475Smrg releaseWindowGCs(xw, win); 1714d522f475Smrg 1715956cc18dSsnj#define DbgResource(name, field, index) \ 1716956cc18dSsnj TRACE(("xtermLoadFont #%d "name" %s%s\n", \ 1717956cc18dSsnj fontnum, \ 1718d1603babSmrg (new_fonts[index].warn == fwResource) ? "*" : " ", \ 1719d1603babSmrg NonNull(new_fnames.field))) 1720956cc18dSsnj DbgResource("normal", f_n, fNorm); 1721956cc18dSsnj DbgResource("bold ", f_b, fBold); 1722d522f475Smrg#if OPT_WIDE_CHARS 1723956cc18dSsnj DbgResource("wide ", f_w, fWide); 1724956cc18dSsnj DbgResource("w/bold", f_wb, fWBold); 1725d522f475Smrg#endif 1726d522f475Smrg 1727dfb07bc7Smrg if (!loadNormFP(xw, 1728d1603babSmrg &new_fnames.f_n, 1729d1603babSmrg &new_fonts[fNorm], 1730d1603babSmrg &old_fonts[fNorm], 1731dfb07bc7Smrg fontnum)) 1732d522f475Smrg goto bad; 1733d522f475Smrg 1734dfb07bc7Smrg if (!loadBoldFP(xw, 1735d1603babSmrg &new_fnames.f_b, 1736d1603babSmrg &new_fonts[fBold], 1737d1603babSmrg new_fnames.f_n, 1738d1603babSmrg &new_fonts[fNorm], 1739dfb07bc7Smrg fontnum)) 1740dfb07bc7Smrg goto bad; 1741d522f475Smrg 1742d522f475Smrg /* 1743d522f475Smrg * If there is no widefont specified, fake it by doubling AVERAGE_WIDTH 1744d522f475Smrg * of normal fonts XLFD, and asking for it. This plucks out 18x18ja 1745d522f475Smrg * and 12x13ja as the corresponding fonts for 9x18 and 6x13. 1746d522f475Smrg */ 1747d522f475Smrg if_OPT_WIDE_CHARS(screen, { 1748d522f475Smrg 1749dfb07bc7Smrg if (!loadWideFP(xw, 1750d1603babSmrg &new_fnames.f_w, 1751d1603babSmrg &new_fonts[fWide], 1752d1603babSmrg new_fnames.f_n, 1753d1603babSmrg &new_fonts[fNorm], 1754dfb07bc7Smrg fontnum)) 1755dfb07bc7Smrg goto bad; 1756dfb07bc7Smrg 1757dfb07bc7Smrg if (!loadWBoldFP(xw, 1758d1603babSmrg &new_fnames.f_wb, 1759d1603babSmrg &new_fonts[fWBold], 1760d1603babSmrg new_fnames.f_w, 1761d1603babSmrg &new_fonts[fWide], 1762d1603babSmrg new_fnames.f_b, 1763d1603babSmrg &new_fonts[fBold], 1764dfb07bc7Smrg fontnum)) 1765dfb07bc7Smrg goto bad; 1766d522f475Smrg 1767d522f475Smrg }); 1768d522f475Smrg 1769d522f475Smrg /* 1770d522f475Smrg * Normal/bold fonts should be the same width. Also, the min/max 1771d522f475Smrg * values should be the same. 1772d522f475Smrg */ 1773190d7dceSmrg if (new_fonts[fNorm].fs != NULL 1774190d7dceSmrg && new_fonts[fBold].fs != NULL 1775d1603babSmrg && (!is_fixed_font(new_fonts[fNorm].fs) 1776d1603babSmrg || !is_fixed_font(new_fonts[fBold].fs) 1777d1603babSmrg || differing_widths(new_fonts[fNorm].fs, new_fonts[fBold].fs))) { 1778d522f475Smrg TRACE(("Proportional font! normal %d/%d, bold %d/%d\n", 1779d1603babSmrg new_fonts[fNorm].fs->min_bounds.width, 1780d1603babSmrg new_fonts[fNorm].fs->max_bounds.width, 1781d1603babSmrg new_fonts[fBold].fs->min_bounds.width, 1782d1603babSmrg new_fonts[fBold].fs->max_bounds.width)); 1783d522f475Smrg proportional = True; 1784d522f475Smrg } 1785d522f475Smrg 1786d522f475Smrg if_OPT_WIDE_CHARS(screen, { 1787190d7dceSmrg if (new_fonts[fWide].fs != NULL 1788190d7dceSmrg && new_fonts[fWBold].fs != NULL 1789d1603babSmrg && (!is_fixed_font(new_fonts[fWide].fs) 1790d1603babSmrg || !is_fixed_font(new_fonts[fWBold].fs) 1791d1603babSmrg || differing_widths(new_fonts[fWide].fs, new_fonts[fWBold].fs))) { 1792d522f475Smrg TRACE(("Proportional font! wide %d/%d, wide bold %d/%d\n", 1793d1603babSmrg new_fonts[fWide].fs->min_bounds.width, 1794d1603babSmrg new_fonts[fWide].fs->max_bounds.width, 1795d1603babSmrg new_fonts[fWBold].fs->min_bounds.width, 1796d1603babSmrg new_fonts[fWBold].fs->max_bounds.width)); 1797d522f475Smrg proportional = True; 1798d522f475Smrg } 1799d522f475Smrg }); 1800d522f475Smrg 1801d522f475Smrg /* TODO : enforce that the width of the wide font is 2* the width 1802d522f475Smrg of the narrow font */ 1803d522f475Smrg 1804d522f475Smrg /* 1805d522f475Smrg * If we're switching fonts, free the old ones. Otherwise we'll leak 1806d522f475Smrg * the memory that is associated with the old fonts. The 1807d522f475Smrg * XLoadQueryFont call allocates a new XFontStruct. 1808d522f475Smrg */ 1809d522f475Smrg xtermCloseFonts(xw, screen->fnts); 18109a64e1c5Smrg#if OPT_WIDE_ATTRS 18119a64e1c5Smrg xtermCloseFonts(xw, screen->ifnts); 18129a64e1c5Smrg screen->ifnts_ok = False; 18139a64e1c5Smrg#endif 1814d522f475Smrg 1815d1603babSmrg xtermCopyFontInfo(GetNormalFont(screen, fNorm), &new_fonts[fNorm]); 1816d1603babSmrg xtermCopyFontInfo(GetNormalFont(screen, fBold), &new_fonts[fBold]); 1817d522f475Smrg#if OPT_WIDE_CHARS 1818d1603babSmrg xtermCopyFontInfo(GetNormalFont(screen, fWide), &new_fonts[fWide]); 1819d1603babSmrg if (new_fonts[fWBold].fs == NULL) 1820d1603babSmrg xtermCopyFontInfo(GetNormalFont(screen, fWide), &new_fonts[fWide]); 1821d1603babSmrg xtermCopyFontInfo(GetNormalFont(screen, fWBold), &new_fonts[fWBold]); 1822d522f475Smrg#endif 1823d522f475Smrg 1824d4fba8b9Smrg xtermUpdateFontGCs(xw, getNormalFont); 1825d522f475Smrg 182620d2c4d2Smrg#if OPT_BOX_CHARS 182720d2c4d2Smrg screen->allow_packing = proportional; 182820d2c4d2Smrg setupPackedFonts(xw); 182920d2c4d2Smrg#endif 183020d2c4d2Smrg screen->fnt_prop = (Boolean) (proportional && !(screen->force_packed)); 1831d4fba8b9Smrg screen->fnt_boxes = 1; 1832d522f475Smrg 1833d522f475Smrg#if OPT_BOX_CHARS 1834d522f475Smrg /* 18359a64e1c5Smrg * xterm uses character positions 1-31 of a font for the line-drawing 1836d522f475Smrg * characters. Check that they are all present. The null character 1837d522f475Smrg * (0) is special, and is not used. 1838d522f475Smrg */ 1839d522f475Smrg#if OPT_RENDERFONT 1840d522f475Smrg if (UsingRenderFont(xw)) { 1841d522f475Smrg /* 1842d522f475Smrg * FIXME: we shouldn't even be here if we're using Xft. 1843d522f475Smrg */ 1844d4fba8b9Smrg screen->fnt_boxes = 0; 1845d522f475Smrg TRACE(("assume Xft missing line-drawing chars\n")); 1846d522f475Smrg } else 1847d522f475Smrg#endif 1848d522f475Smrg { 1849d522f475Smrg unsigned ch; 1850d522f475Smrg 18519a64e1c5Smrg#if OPT_TRACE 1852d1603babSmrg#define TRACE_MISS(index) show_font_misses(#index, &new_fonts[index]) 18539a64e1c5Smrg TRACE_MISS(fNorm); 18549a64e1c5Smrg TRACE_MISS(fBold); 18559a64e1c5Smrg#if OPT_WIDE_CHARS 18569a64e1c5Smrg TRACE_MISS(fWide); 18579a64e1c5Smrg TRACE_MISS(fWBold); 18589a64e1c5Smrg#endif 18599a64e1c5Smrg#endif 1860fa3f02f3Smrg 1861d522f475Smrg#if OPT_WIDE_CHARS 1862d4fba8b9Smrg if (screen->utf8_mode || screen->unicode_font) { 1863d4fba8b9Smrg UIntSet(screen->fnt_boxes, 2); 1864d4fba8b9Smrg for (ch = 1; ch < 32; ch++) { 1865d4fba8b9Smrg unsigned n = dec2ucs(screen, ch); 1866980988aeSmrg if (!is_UCS_SPECIAL(n) 1867d4fba8b9Smrg && (n != ch) 1868d4fba8b9Smrg && (screen->fnt_boxes & 2)) { 1869d1603babSmrg if (xtermMissingChar(n, &new_fonts[fNorm]) || 1870d1603babSmrg xtermMissingChar(n, &new_fonts[fBold])) { 1871d4fba8b9Smrg UIntClr(screen->fnt_boxes, 2); 1872d4fba8b9Smrg TRACE(("missing graphics character #%d, U+%04X\n", 1873d4fba8b9Smrg ch, n)); 1874d4fba8b9Smrg break; 1875d4fba8b9Smrg } 1876d4fba8b9Smrg } 1877d522f475Smrg } 1878d4fba8b9Smrg } 1879d522f475Smrg#endif 1880d4fba8b9Smrg 1881d4fba8b9Smrg for (ch = 1; ch < 32; ch++) { 1882d1603babSmrg if (xtermMissingChar(ch, &new_fonts[fNorm])) { 1883d4fba8b9Smrg TRACE(("missing normal char #%d\n", ch)); 1884d4fba8b9Smrg UIntClr(screen->fnt_boxes, 1); 1885d522f475Smrg break; 1886d522f475Smrg } 1887d1603babSmrg if (xtermMissingChar(ch, &new_fonts[fBold])) { 1888d4fba8b9Smrg TRACE(("missing bold char #%d\n", ch)); 1889d4fba8b9Smrg UIntClr(screen->fnt_boxes, 1); 1890d522f475Smrg break; 1891d522f475Smrg } 1892d522f475Smrg } 1893d4fba8b9Smrg 1894d4fba8b9Smrg TRACE(("Will %suse internal line-drawing characters (mode %d)\n", 1895d4fba8b9Smrg screen->fnt_boxes ? "not " : "", 1896d4fba8b9Smrg screen->fnt_boxes)); 1897d522f475Smrg } 1898d522f475Smrg#endif 1899d522f475Smrg 1900d522f475Smrg if (screen->always_bold_mode) { 1901d522f475Smrg screen->enbolden = screen->bold_mode; 1902d522f475Smrg } else { 1903d522f475Smrg screen->enbolden = screen->bold_mode 1904d1603babSmrg && ((new_fonts[fNorm].fs == new_fonts[fBold].fs) 1905d1603babSmrg || same_font_name(new_fnames.f_n, new_fnames.f_b)); 1906d522f475Smrg } 1907d522f475Smrg TRACE(("Will %suse 1-pixel offset/overstrike to simulate bold\n", 1908d522f475Smrg screen->enbolden ? "" : "not ")); 1909d522f475Smrg 1910d522f475Smrg set_menu_font(False); 1911d522f475Smrg screen->menu_font_number = fontnum; 1912d522f475Smrg set_menu_font(True); 1913d522f475Smrg if (tmpname) { /* if setting escape or sel */ 1914d522f475Smrg if (screen->MenuFontName(fontnum)) 19159a64e1c5Smrg FREE_STRING(screen->MenuFontName(fontnum)); 1916d522f475Smrg screen->MenuFontName(fontnum) = tmpname; 1917d522f475Smrg if (fontnum == fontMenu_fontescape) { 191894644356Smrg update_font_escape(); 1919d522f475Smrg } 1920d522f475Smrg#if OPT_SHIFT_FONTS 1921d1603babSmrg screen->menu_font_sizes[fontnum] = FontSize(new_fonts[fNorm].fs); 1922d522f475Smrg#endif 1923d522f475Smrg } 1924d522f475Smrg set_cursor_gcs(xw); 1925d522f475Smrg xtermUpdateFontInfo(xw, doresize); 1926d522f475Smrg TRACE(("Success Cgs - xtermLoadFont\n")); 1927fa3f02f3Smrg#if OPT_REPORT_FONTS 1928fa3f02f3Smrg reportVTFontInfo(xw, fontnum); 19299a64e1c5Smrg#endif 19309a64e1c5Smrg FREE_FNAME(f_n); 19319a64e1c5Smrg FREE_FNAME(f_b); 19329a64e1c5Smrg#if OPT_WIDE_CHARS 19339a64e1c5Smrg FREE_FNAME(f_w); 19349a64e1c5Smrg FREE_FNAME(f_wb); 19359a64e1c5Smrg#endif 1936d1603babSmrg if (new_fonts[fNorm].fn == new_fonts[fBold].fn) { 1937d1603babSmrg free(new_fonts[fNorm].fn); 19389a64e1c5Smrg } else { 1939d1603babSmrg free(new_fonts[fNorm].fn); 1940d1603babSmrg free(new_fonts[fBold].fn); 19419a64e1c5Smrg } 19429a64e1c5Smrg#if OPT_WIDE_CHARS 1943d1603babSmrg free(new_fonts[fWide].fn); 1944d1603babSmrg free(new_fonts[fWBold].fn); 1945fa3f02f3Smrg#endif 1946dfb07bc7Smrg xtermSetWinSize(xw); 1947d522f475Smrg return 1; 1948d522f475Smrg 1949d522f475Smrg bad: 1950d1603babSmrg recovered = False; 1951d4fba8b9Smrg free(tmpname); 19520bd37d32Smrg 19530bd37d32Smrg#if OPT_RENDERFONT 195494644356Smrg if ((fontnum == fontMenu_fontsel) && (fontnum != screen->menu_font_number)) { 19559a64e1c5Smrg int old_fontnum = screen->menu_font_number; 19569a64e1c5Smrg#if OPT_TOOLBAR 19579a64e1c5Smrg SetItemSensitivity(fontMenuEntries[fontnum].widget, True); 19589a64e1c5Smrg#endif 19599a64e1c5Smrg Bell(xw, XkbBI_MinorError, 0); 1960d1603babSmrg new_fnames.f_n = screen->MenuFontName(old_fontnum); 1961d1603babSmrg if (xtermLoadFont(xw, &new_fnames, doresize, old_fontnum)) 1962d1603babSmrg recovered = True; 1963d1603babSmrg } else if (x_strcasecmp(new_fnames.f_n, DEFFONT) 1964d1603babSmrg && x_strcasecmp(new_fnames.f_n, old_fonts[fNorm].fn)) { 1965d1603babSmrg new_fnames.f_n = x_strdup(old_fonts[fNorm].fn); 1966d1603babSmrg TRACE(("...recovering from failed font-load\n")); 1967d1603babSmrg if (xtermLoadFont(xw, &new_fnames, doresize, fontnum)) { 1968d1603babSmrg recovered = True; 196994644356Smrg if (fontnum != fontMenu_fontsel) { 197094644356Smrg SetItemSensitivity(fontMenuEntries[fontnum].widget, 197194644356Smrg UsingRenderFont(xw)); 197294644356Smrg } 19730bd37d32Smrg TRACE(("...recovered size %dx%d\n", 19740bd37d32Smrg FontHeight(screen), 19750bd37d32Smrg FontWidth(screen))); 19760bd37d32Smrg } 19770bd37d32Smrg } 19780bd37d32Smrg#endif 1979d1603babSmrg if (!recovered) { 1980d1603babSmrg releaseWindowGCs(xw, win); 1981d1603babSmrg xtermCloseFonts(xw, new_fonts); 1982d1603babSmrg TRACE(("Fail Cgs - xtermLoadFont\n")); 1983d1603babSmrg code = 0; 1984d1603babSmrg } 1985d1603babSmrg return code; 1986d522f475Smrg} 1987d522f475Smrg 19889a64e1c5Smrg#if OPT_WIDE_ATTRS 19899a64e1c5Smrg/* 19909a64e1c5Smrg * (Attempt to) load matching italics for the current normal/bold/etc fonts. 19919a64e1c5Smrg * If the attempt fails for a given style, use the non-italic font. 19929a64e1c5Smrg */ 19939a64e1c5Smrgvoid 19949a64e1c5SmrgxtermLoadItalics(XtermWidget xw) 19959a64e1c5Smrg{ 19969a64e1c5Smrg TScreen *screen = TScreenOf(xw); 19979a64e1c5Smrg 1998c48a5815Smrg if (UseItalicFont(screen) && !screen->ifnts_ok) { 1999037a25ddSmrg int n; 2000dfb07bc7Smrg FontNameProperties *fp; 2001dfb07bc7Smrg XTermFonts *data; 2002037a25ddSmrg 20039a64e1c5Smrg screen->ifnts_ok = True; 20049a64e1c5Smrg for (n = 0; n < fMAX; ++n) { 2005dfb07bc7Smrg switch (n) { 2006dfb07bc7Smrg case fNorm: 2007dfb07bc7Smrg /* FALLTHRU */ 2008dfb07bc7Smrg case fBold: 2009dfb07bc7Smrg /* FALLTHRU */ 2010dfb07bc7Smrg#if OPT_WIDE_CHARS 2011dfb07bc7Smrg case fWide: 2012dfb07bc7Smrg /* FALLTHRU */ 2013dfb07bc7Smrg case fWBold: 2014dfb07bc7Smrg#endif 2015dfb07bc7Smrg /* FALLTHRU */ 2016dfb07bc7Smrg data = getItalicFont(screen, n); 2017037a25ddSmrg 2018dfb07bc7Smrg /* 2019dfb07bc7Smrg * FIXME - need to handle font-leaks 2020dfb07bc7Smrg */ 2021190d7dceSmrg data->fs = NULL; 2022190d7dceSmrg if (getNormalFont(screen, n)->fs != NULL && 2023dfb07bc7Smrg (fp = get_font_name_props(screen->display, 2024dfb07bc7Smrg getNormalFont(screen, n)->fs, 2025190d7dceSmrg NULL)) != NULL) { 2026dfb07bc7Smrg if (!open_italic_font(xw, n, fp, data)) { 2027dfb07bc7Smrg if (n > 0) { 2028dfb07bc7Smrg xtermCopyFontInfo(data, 2029dfb07bc7Smrg getItalicFont(screen, n - 1)); 2030dfb07bc7Smrg } else { 2031dfb07bc7Smrg xtermOpenFont(xw, 2032dfb07bc7Smrg getNormalFont(screen, n)->fn, 2033d1603babSmrg data, NULL, False); 20349a64e1c5Smrg } 20359a64e1c5Smrg } 20369a64e1c5Smrg } 2037dfb07bc7Smrg break; 20389a64e1c5Smrg } 20399a64e1c5Smrg } 20409a64e1c5Smrg } 20419a64e1c5Smrg} 20429a64e1c5Smrg#endif 20439a64e1c5Smrg 2044d522f475Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 2045d522f475Smrg/* 2046d522f475Smrg * Collect font-names that we can modify with the load-vt-fonts() action. 2047d522f475Smrg */ 2048dfb07bc7Smrg#define MERGE_SUBFONT(dst,src,name) \ 2049492d43a5Smrg if (IsEmpty(dst.name)) { \ 2050dfb07bc7Smrg TRACE(("MERGE_SUBFONT " #dst "." #name " merge \"%s\"\n", NonNull(src.name))); \ 20519a64e1c5Smrg dst.name = x_strdup(src.name); \ 2052d522f475Smrg } else { \ 2053dfb07bc7Smrg TRACE(("MERGE_SUBFONT " #dst "." #name " found \"%s\"\n", NonNull(dst.name))); \ 2054dfb07bc7Smrg } 2055dfb07bc7Smrg#define MERGE_SUBLIST(dst,src,name) \ 2056d1603babSmrg if (dst.fonts.x11.name == NULL) \ 2057d1603babSmrg dst.fonts.x11.name = TypeCalloc(char *); \ 2058dfb07bc7Smrg if (merge_sublist(&(dst.fonts.x11.name), src.fonts.x11.name)) { \ 2059dfb07bc7Smrg TRACE(("MERGE_SUBLIST " #dst "." #name " merge \"%s\"\n", src.fonts.x11.name[0])); \ 2060dfb07bc7Smrg } else { \ 2061dfb07bc7Smrg TRACE(("MERGE_SUBLIST " #dst "." #name " found \"%s\"\n", dst.fonts.x11.name[0])); \ 2062d522f475Smrg } 2063d522f475Smrg 2064dfb07bc7Smrg#define INFER_SUBFONT(dst,src,name) \ 2065e39b573cSmrg if (IsEmpty(dst.name)) { \ 2066e39b573cSmrg TRACE(("INFER_SUBFONT " #dst "." #name " will infer\n")); \ 2067e39b573cSmrg dst.name = x_strdup(""); \ 2068e39b573cSmrg } else { \ 2069dfb07bc7Smrg TRACE(("INFER_SUBFONT " #dst "." #name " found \"%s\"\n", NonNull(dst.name))); \ 2070e39b573cSmrg } 2071e39b573cSmrg 20729a64e1c5Smrg#define FREE_MENU_FONTS(dst) \ 20739a64e1c5Smrg TRACE(("FREE_MENU_FONTS " #dst "\n")); \ 20749a64e1c5Smrg for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \ 20759a64e1c5Smrg for (m = 0; m < fMAX; ++m) { \ 20769a64e1c5Smrg FREE_STRING(dst.menu_font_names[n][m]); \ 2077190d7dceSmrg dst.menu_font_names[n][m] = NULL; \ 20789a64e1c5Smrg } \ 20799a64e1c5Smrg } 20809a64e1c5Smrg 2081dfb07bc7Smrg#define COPY_MENU_FONTS(dst,src) \ 2082d522f475Smrg TRACE(("COPY_MENU_FONTS " #src " to " #dst "\n")); \ 2083d522f475Smrg for (n = fontMenu_default; n <= fontMenu_lastBuiltin; ++n) { \ 2084d522f475Smrg for (m = 0; m < fMAX; ++m) { \ 20859a64e1c5Smrg FREE_STRING(dst.menu_font_names[n][m]); \ 2086492d43a5Smrg dst.menu_font_names[n][m] = x_strdup(src.menu_font_names[n][m]); \ 2087d522f475Smrg } \ 208894644356Smrg TRACE((".. " #dst ".menu_fonts_names[%d] = %s\n", n, NonNull(dst.menu_font_names[n][fNorm]))); \ 2089e39b573cSmrg } 2090e39b573cSmrg 20919a64e1c5Smrg#define COPY_DEFAULT_FONTS(target, source) \ 2092dfb07bc7Smrg TRACE(("COPY_DEFAULT_FONTS " #source " to " #target "\n")); \ 20939a64e1c5Smrg xtermCopyVTFontNames(&target.default_font, &source.default_font) 20949a64e1c5Smrg 2095dfb07bc7Smrg#define COPY_X11_FONTLISTS(target, source) \ 2096dfb07bc7Smrg TRACE(("COPY_X11_FONTLISTS " #source " to " #target "\n")); \ 2097dfb07bc7Smrg xtermCopyFontLists(xw, &target.fonts.x11, &source.fonts.x11) 2098dfb07bc7Smrg 2099dfb07bc7Smrgstatic void 2100dfb07bc7SmrgxtermCopyVTFontNames(VTFontNames * target, VTFontNames * source) 2101dfb07bc7Smrg{ 2102dfb07bc7Smrg#define COPY_IT(name,field) \ 2103dfb07bc7Smrg TRACE((".. "#name" = %s\n", NonNull(source->field))); \ 2104dfb07bc7Smrg free(target->field); \ 2105dfb07bc7Smrg target->field = x_strdup(source->field) 2106dfb07bc7Smrg 2107dfb07bc7Smrg TRACE(("xtermCopyVTFontNames\n")); 2108dfb07bc7Smrg 2109dfb07bc7Smrg COPY_IT(font, f_n); 2110dfb07bc7Smrg COPY_IT(boldFont, f_b); 2111dfb07bc7Smrg 2112dfb07bc7Smrg#if OPT_WIDE_CHARS 2113dfb07bc7Smrg COPY_IT(wideFont, f_w); 2114dfb07bc7Smrg COPY_IT(wideBoldFont, f_wb); 2115dfb07bc7Smrg#endif 2116dfb07bc7Smrg#undef COPY_IT 2117dfb07bc7Smrg} 2118dfb07bc7Smrg 21199a64e1c5Smrgstatic void 2120dfb07bc7SmrgxtermCopyFontLists(XtermWidget xw, VTFontList * target, VTFontList * source) 21219a64e1c5Smrg{ 2122dfb07bc7Smrg#define COPY_IT(name,field) \ 2123dfb07bc7Smrg copyFontList(&(target->field), source->field); \ 2124dfb07bc7Smrg TRACE_ARGV(".. " #name, source->field) 2125dfb07bc7Smrg 2126dfb07bc7Smrg (void) xw; 2127dfb07bc7Smrg TRACE(("xtermCopyFontLists %s ->%s\n", 2128dfb07bc7Smrg whichFontList(xw, source), 2129dfb07bc7Smrg whichFontList(xw, target))); 2130dfb07bc7Smrg 2131dfb07bc7Smrg COPY_IT(font, list_n); 2132dfb07bc7Smrg COPY_IT(fontBold, list_b); 2133dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 2134dfb07bc7Smrg COPY_IT(fontItal, list_i); 2135d4fba8b9Smrg COPY_IT(fontBtal, list_bi); 2136dfb07bc7Smrg#endif 21379a64e1c5Smrg#if OPT_WIDE_CHARS 2138dfb07bc7Smrg COPY_IT(wideFont, list_w); 2139dfb07bc7Smrg COPY_IT(wideBoldFont, list_wb); 2140dfb07bc7Smrg COPY_IT(wideItalFont, list_wi); 2141d4fba8b9Smrg COPY_IT(wideBtalFont, list_wbi); 21429a64e1c5Smrg#endif 2143dfb07bc7Smrg#undef COPY_IT 21449a64e1c5Smrg} 21459a64e1c5Smrg 2146e39b573cSmrgvoid 2147e39b573cSmrgxtermSaveVTFonts(XtermWidget xw) 2148e39b573cSmrg{ 2149e39b573cSmrg TScreen *screen = TScreenOf(xw); 2150e39b573cSmrg Cardinal n, m; 2151e39b573cSmrg 2152e39b573cSmrg if (!screen->savedVTFonts) { 2153e39b573cSmrg 2154e39b573cSmrg screen->savedVTFonts = True; 2155e39b573cSmrg TRACE(("xtermSaveVTFonts saving original\n")); 21569a64e1c5Smrg COPY_DEFAULT_FONTS(screen->cacheVTFonts, xw->misc); 2157dfb07bc7Smrg COPY_X11_FONTLISTS(screen->cacheVTFonts, xw->work); 2158dfb07bc7Smrg COPY_MENU_FONTS(screen->cacheVTFonts, xw->screen); 2159e39b573cSmrg } 2160e39b573cSmrg} 2161e39b573cSmrg 2162e39b573cSmrg#define SAME_STRING(x,y) ((x) == (y) || ((x) && (y) && !strcmp(x, y))) 2163e39b573cSmrg#define SAME_MEMBER(n) SAME_STRING(a->n, b->n) 2164e39b573cSmrg 2165e39b573cSmrgstatic Boolean 2166e39b573cSmrgsameSubResources(SubResourceRec * a, SubResourceRec * b) 2167e39b573cSmrg{ 2168e39b573cSmrg Boolean result = True; 2169e39b573cSmrg 2170e39b573cSmrg if (!SAME_MEMBER(default_font.f_n) 2171e39b573cSmrg || !SAME_MEMBER(default_font.f_b) 21720bd37d32Smrg#if OPT_WIDE_CHARS 2173e39b573cSmrg || !SAME_MEMBER(default_font.f_w) 21740bd37d32Smrg || !SAME_MEMBER(default_font.f_wb) 21750bd37d32Smrg#endif 21760bd37d32Smrg ) { 2177e39b573cSmrg TRACE(("sameSubResources: default_font differs\n")); 2178e39b573cSmrg result = False; 2179e39b573cSmrg } else { 2180037a25ddSmrg int n; 2181037a25ddSmrg 2182e39b573cSmrg for (n = 0; n < NMENUFONTS; ++n) { 2183e39b573cSmrg if (!SAME_MEMBER(menu_font_names[n][fNorm])) { 2184e39b573cSmrg TRACE(("sameSubResources: menu_font_names[%d] differs\n", n)); 2185e39b573cSmrg result = False; 2186e39b573cSmrg break; 2187e39b573cSmrg } 2188d522f475Smrg } 2189e39b573cSmrg } 2190e39b573cSmrg 2191e39b573cSmrg return result; 2192e39b573cSmrg} 2193d522f475Smrg 2194d522f475Smrg/* 2195d522f475Smrg * Load the "VT" font names from the given subresource name/class. These 2196d522f475Smrg * correspond to the VT100 resources. 2197d522f475Smrg */ 2198d522f475Smrgstatic Bool 219920d2c4d2SmrgxtermLoadVTFonts(XtermWidget xw, String myName, String myClass) 2200d522f475Smrg{ 2201e39b573cSmrg SubResourceRec subresourceRec; 2202e39b573cSmrg SubResourceRec referenceRec; 2203d522f475Smrg 2204d522f475Smrg /* 2205d522f475Smrg * These are duplicates of the VT100 font resources, but with a special 2206d522f475Smrg * application/classname passed in to distinguish them. 2207d522f475Smrg */ 2208d522f475Smrg static XtResource font_resources[] = 2209d522f475Smrg { 2210d522f475Smrg Sres(XtNfont, XtCFont, default_font.f_n, DEFFONT), 2211d522f475Smrg Sres(XtNboldFont, XtCBoldFont, default_font.f_b, DEFBOLDFONT), 2212d522f475Smrg#if OPT_WIDE_CHARS 2213d522f475Smrg Sres(XtNwideFont, XtCWideFont, default_font.f_w, DEFWIDEFONT), 2214d522f475Smrg Sres(XtNwideBoldFont, XtCWideBoldFont, default_font.f_wb, DEFWIDEBOLDFONT), 2215d522f475Smrg#endif 2216d522f475Smrg Sres(XtNfont1, XtCFont1, MenuFontName(fontMenu_font1), NULL), 2217d522f475Smrg Sres(XtNfont2, XtCFont2, MenuFontName(fontMenu_font2), NULL), 2218d522f475Smrg Sres(XtNfont3, XtCFont3, MenuFontName(fontMenu_font3), NULL), 2219d522f475Smrg Sres(XtNfont4, XtCFont4, MenuFontName(fontMenu_font4), NULL), 2220d522f475Smrg Sres(XtNfont5, XtCFont5, MenuFontName(fontMenu_font5), NULL), 2221d522f475Smrg Sres(XtNfont6, XtCFont6, MenuFontName(fontMenu_font6), NULL), 2222d4fba8b9Smrg Sres(XtNfont7, XtCFont7, MenuFontName(fontMenu_font7), NULL), 2223d522f475Smrg }; 2224d522f475Smrg Cardinal n, m; 2225d522f475Smrg Bool status = True; 2226956cc18dSsnj TScreen *screen = TScreenOf(xw); 2227d522f475Smrg 2228e39b573cSmrg TRACE(("called xtermLoadVTFonts(name=%s, class=%s)\n", 2229e39b573cSmrg NonNull(myName), NonNull(myClass))); 2230d522f475Smrg 2231e39b573cSmrg xtermSaveVTFonts(xw); 2232d522f475Smrg 2233492d43a5Smrg if (IsEmpty(myName)) { 2234d522f475Smrg TRACE(("xtermLoadVTFonts restoring original\n")); 22359a64e1c5Smrg COPY_DEFAULT_FONTS(xw->misc, screen->cacheVTFonts); 2236dfb07bc7Smrg COPY_X11_FONTLISTS(xw->work, screen->cacheVTFonts); 22379a64e1c5Smrg FREE_MENU_FONTS(xw->screen); 2238dfb07bc7Smrg COPY_MENU_FONTS(xw->screen, screen->cacheVTFonts); 2239d522f475Smrg } else { 2240d522f475Smrg TRACE(("xtermLoadVTFonts(%s, %s)\n", myName, myClass)); 2241d522f475Smrg 2242e39b573cSmrg memset(&referenceRec, 0, sizeof(referenceRec)); 2243d522f475Smrg memset(&subresourceRec, 0, sizeof(subresourceRec)); 2244956cc18dSsnj XtGetSubresources((Widget) xw, (XtPointer) &subresourceRec, 2245d522f475Smrg myName, myClass, 2246d522f475Smrg font_resources, 2247d522f475Smrg (Cardinal) XtNumber(font_resources), 2248d522f475Smrg NULL, (Cardinal) 0); 2249d522f475Smrg 2250e39b573cSmrg /* 2251e39b573cSmrg * XtGetSubresources returns no status, so we compare the returned 2252e39b573cSmrg * data against a zero'd struct to see if any data is returned. 2253e39b573cSmrg */ 2254e39b573cSmrg if (memcmp(&referenceRec, &subresourceRec, sizeof(referenceRec)) 2255e39b573cSmrg && !sameSubResources(&(screen->cacheVTFonts), &subresourceRec)) { 2256e39b573cSmrg 2257e39b573cSmrg screen->mergedVTFonts = True; 2258d522f475Smrg 22599a64e1c5Smrg /* 22609a64e1c5Smrg * To make it simple, reallocate the strings returned by 22619a64e1c5Smrg * XtGetSubresources. We can free our own strings, but not theirs. 22629a64e1c5Smrg */ 22639a64e1c5Smrg ALLOC_STRING(subresourceRec.default_font.f_n); 22649a64e1c5Smrg ALLOC_STRING(subresourceRec.default_font.f_b); 22659a64e1c5Smrg#if OPT_WIDE_CHARS 22669a64e1c5Smrg ALLOC_STRING(subresourceRec.default_font.f_w); 22679a64e1c5Smrg ALLOC_STRING(subresourceRec.default_font.f_wb); 22689a64e1c5Smrg#endif 22699a64e1c5Smrg for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) { 22709a64e1c5Smrg ALLOC_STRING(subresourceRec.MenuFontName(n)); 22719a64e1c5Smrg } 22729a64e1c5Smrg 2273dfb07bc7Smrg /* 2274dfb07bc7Smrg * Now, save the string to a font-list for consistency 2275dfb07bc7Smrg */ 2276dfb07bc7Smrg#define ALLOC_SUBLIST(which,field) \ 2277d1603babSmrg if (subresourceRec.default_font.field != NULL) { \ 2278d1603babSmrg char *blob = x_strdup(subresourceRec.default_font.field); \ 2279d1603babSmrg char *base; \ 2280d1603babSmrg for (base = blob; ; base = NULL) { \ 2281d1603babSmrg char *item = strtok(base, ","); \ 2282d1603babSmrg if (item == NULL) \ 2283d1603babSmrg break; \ 2284d1603babSmrg save2FontList(xw, "cached", \ 2285d1603babSmrg &(subresourceRec.fonts), \ 2286d1603babSmrg which, \ 2287d1603babSmrg item, False, False); \ 2288d1603babSmrg } \ 2289d1603babSmrg free(blob); \ 2290d1603babSmrg } 2291dfb07bc7Smrg 2292dfb07bc7Smrg ALLOC_SUBLIST(fNorm, f_n); 2293dfb07bc7Smrg ALLOC_SUBLIST(fBold, f_b); 2294dfb07bc7Smrg#if OPT_WIDE_CHARS 2295dfb07bc7Smrg ALLOC_SUBLIST(fWide, f_w); 2296dfb07bc7Smrg ALLOC_SUBLIST(fWBold, f_wb); 2297dfb07bc7Smrg#endif 2298dfb07bc7Smrg 2299d522f475Smrg /* 2300d522f475Smrg * If a particular resource value was not found, use the original. 2301d522f475Smrg */ 2302dfb07bc7Smrg MERGE_SUBFONT(subresourceRec, xw->misc, default_font.f_n); 2303dfb07bc7Smrg INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_b); 2304dfb07bc7Smrg MERGE_SUBLIST(subresourceRec, xw->work, list_n); 2305dfb07bc7Smrg MERGE_SUBLIST(subresourceRec, xw->work, list_b); 2306d522f475Smrg#if OPT_WIDE_CHARS 2307dfb07bc7Smrg INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_w); 2308dfb07bc7Smrg INFER_SUBFONT(subresourceRec, xw->misc, default_font.f_wb); 2309dfb07bc7Smrg MERGE_SUBLIST(subresourceRec, xw->work, list_w); 2310dfb07bc7Smrg MERGE_SUBLIST(subresourceRec, xw->work, list_wb); 2311d522f475Smrg#endif 23129a64e1c5Smrg for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) { 2313dfb07bc7Smrg MERGE_SUBFONT(subresourceRec, xw->screen, MenuFontName(n)); 23149a64e1c5Smrg } 2315d522f475Smrg 2316d522f475Smrg /* 2317d522f475Smrg * Finally, copy the subresource data to the widget. 2318d522f475Smrg */ 23199a64e1c5Smrg COPY_DEFAULT_FONTS(xw->misc, subresourceRec); 2320dfb07bc7Smrg COPY_X11_FONTLISTS(xw->work, subresourceRec); 23219a64e1c5Smrg FREE_MENU_FONTS(xw->screen); 2322dfb07bc7Smrg COPY_MENU_FONTS(xw->screen, subresourceRec); 23239a64e1c5Smrg 23249a64e1c5Smrg FREE_STRING(screen->MenuFontName(fontMenu_default)); 23259a64e1c5Smrg FREE_STRING(screen->menu_font_names[0][fBold]); 2326dfb07bc7Smrg screen->MenuFontName(fontMenu_default) = x_strdup(DefaultFontN(xw)); 2327dfb07bc7Smrg screen->menu_font_names[0][fBold] = x_strdup(DefaultFontB(xw)); 2328d522f475Smrg#if OPT_WIDE_CHARS 23299a64e1c5Smrg FREE_STRING(screen->menu_font_names[0][fWide]); 23309a64e1c5Smrg FREE_STRING(screen->menu_font_names[0][fWBold]); 2331dfb07bc7Smrg screen->menu_font_names[0][fWide] = x_strdup(DefaultFontW(xw)); 2332dfb07bc7Smrg screen->menu_font_names[0][fWBold] = x_strdup(DefaultFontWB(xw)); 2333d522f475Smrg#endif 23349a64e1c5Smrg /* 23359a64e1c5Smrg * And remove our copies of strings. 23369a64e1c5Smrg */ 23379a64e1c5Smrg FREE_STRING(subresourceRec.default_font.f_n); 23389a64e1c5Smrg FREE_STRING(subresourceRec.default_font.f_b); 23399a64e1c5Smrg#if OPT_WIDE_CHARS 23409a64e1c5Smrg FREE_STRING(subresourceRec.default_font.f_w); 23419a64e1c5Smrg FREE_STRING(subresourceRec.default_font.f_wb); 23429a64e1c5Smrg#endif 23439a64e1c5Smrg for (n = fontMenu_font1; n <= fontMenu_lastBuiltin; ++n) { 23449a64e1c5Smrg FREE_STRING(subresourceRec.MenuFontName(n)); 23459a64e1c5Smrg } 2346d522f475Smrg } else { 2347d522f475Smrg TRACE(("...no resources found\n")); 2348d522f475Smrg status = False; 2349d522f475Smrg } 2350d522f475Smrg } 2351dfb07bc7Smrg TRACE((".. xtermLoadVTFonts: %d\n", status)); 2352d522f475Smrg return status; 2353d522f475Smrg} 2354d522f475Smrg 2355d522f475Smrg#if OPT_WIDE_CHARS 2356d522f475Smrgstatic Bool 23579a64e1c5SmrgisWideFont(XFontStruct *fp, const char *tag, Bool nullOk) 2358d522f475Smrg{ 2359d522f475Smrg Bool result = False; 2360d522f475Smrg 2361d522f475Smrg (void) tag; 2362d522f475Smrg if (okFont(fp)) { 2363d522f475Smrg unsigned count = countGlyphs(fp); 2364d522f475Smrg TRACE(("isWideFont(%s) found %d cells\n", tag, count)); 2365d522f475Smrg result = (count > 256) ? True : False; 2366d522f475Smrg } else { 2367d522f475Smrg result = nullOk; 2368d522f475Smrg } 2369d522f475Smrg return result; 2370d522f475Smrg} 2371d522f475Smrg 2372d522f475Smrg/* 2373d522f475Smrg * If the current fonts are not wide, load the UTF8 fonts. 2374d522f475Smrg * 2375d522f475Smrg * Called during initialization (for wide-character mode), the fonts have not 2376d522f475Smrg * been setup, so we pass nullOk=True to isWideFont(). 2377d522f475Smrg * 2378d522f475Smrg * Called after initialization, e.g., in response to the UTF-8 menu entry 2379d522f475Smrg * (starting from narrow character mode), it checks if the fonts are not wide. 2380d522f475Smrg */ 2381d522f475SmrgBool 2382d522f475SmrgxtermLoadWideFonts(XtermWidget xw, Bool nullOk) 2383d522f475Smrg{ 2384956cc18dSsnj TScreen *screen = TScreenOf(xw); 2385d522f475Smrg Bool result; 2386d522f475Smrg 2387d4fba8b9Smrg if (EmptyFont(GetNormalFont(screen, fWide)->fs)) { 2388d4fba8b9Smrg result = (isWideFont(GetNormalFont(screen, fNorm)->fs, "normal", nullOk) 2389d4fba8b9Smrg && isWideFont(GetNormalFont(screen, fBold)->fs, "bold", nullOk)); 2390d522f475Smrg } else { 2391d4fba8b9Smrg result = (isWideFont(GetNormalFont(screen, fWide)->fs, "wide", nullOk) 2392d4fba8b9Smrg && isWideFont(GetNormalFont(screen, fWBold)->fs, 2393dfb07bc7Smrg "wide-bold", nullOk)); 2394d522f475Smrg if (result && !screen->utf8_latin1) { 2395d4fba8b9Smrg result = (isWideFont(GetNormalFont(screen, fNorm)->fs, "normal", nullOk) 2396d4fba8b9Smrg && isWideFont(GetNormalFont(screen, fBold)->fs, 2397dfb07bc7Smrg "bold", nullOk)); 2398d522f475Smrg } 2399d522f475Smrg } 2400d522f475Smrg if (!result) { 2401d522f475Smrg TRACE(("current fonts are not all wide%s\n", nullOk ? " nullOk" : "")); 2402e39b573cSmrg result = xtermLoadVTFonts(xw, XtNutf8Fonts, XtCUtf8Fonts); 2403d522f475Smrg } 2404d522f475Smrg TRACE(("xtermLoadWideFonts:%d\n", result)); 2405d522f475Smrg return result; 2406d522f475Smrg} 2407d522f475Smrg#endif /* OPT_WIDE_CHARS */ 2408d522f475Smrg 2409d522f475Smrg/* 2410d522f475Smrg * Restore the default fonts, i.e., if we had switched to wide-fonts. 2411d522f475Smrg */ 2412d522f475SmrgBool 2413956cc18dSsnjxtermLoadDefaultFonts(XtermWidget xw) 2414d522f475Smrg{ 2415d522f475Smrg Bool result; 2416956cc18dSsnj result = xtermLoadVTFonts(xw, NULL, NULL); 2417d522f475Smrg TRACE(("xtermLoadDefaultFonts:%d\n", result)); 2418d522f475Smrg return result; 2419d522f475Smrg} 2420d522f475Smrg#endif /* OPT_LOAD_VTFONTS || OPT_WIDE_CHARS */ 2421d522f475Smrg 2422d522f475Smrg#if OPT_LOAD_VTFONTS 2423d522f475Smrgvoid 2424d522f475SmrgHandleLoadVTFonts(Widget w, 24259a64e1c5Smrg XEvent *event GCC_UNUSED, 2426d4fba8b9Smrg String *params, 2427d4fba8b9Smrg Cardinal *param_count) 2428d522f475Smrg{ 2429956cc18dSsnj XtermWidget xw; 2430956cc18dSsnj 2431190d7dceSmrg if ((xw = getXtermWidget(w)) != NULL) { 2432037a25ddSmrg static char empty[] = ""; /* appease strict compilers */ 2433037a25ddSmrg 2434956cc18dSsnj TScreen *screen = TScreenOf(xw); 2435492d43a5Smrg char name_buf[80]; 2436492d43a5Smrg String name = (String) ((*param_count > 0) ? params[0] : empty); 243794644356Smrg char *myName = MyStackAlloc(strlen(name) + 1, name_buf); 2438d522f475Smrg 2439d522f475Smrg TRACE(("HandleLoadVTFonts(%d)\n", *param_count)); 2440190d7dceSmrg if (myName != NULL) { 2441037a25ddSmrg char class_buf[80]; 244294644356Smrg String convert = (String) ((*param_count > 1) ? params[1] : myName); 244394644356Smrg char *myClass = MyStackAlloc(strlen(convert) + 1, class_buf); 244494644356Smrg 244594644356Smrg strcpy(myName, name); 2446190d7dceSmrg if (myClass != NULL) { 244794644356Smrg strcpy(myClass, convert); 244894644356Smrg if (*param_count == 1) 244994644356Smrg myClass[0] = x_toupper(myClass[0]); 245094644356Smrg 245194644356Smrg if (xtermLoadVTFonts(xw, myName, myClass)) { 2452037a25ddSmrg int n; 245394644356Smrg /* 245494644356Smrg * When switching fonts, try to preserve the font-menu 245594644356Smrg * selection, since it is less surprising to do that (if 245694644356Smrg * the font-switching can be undone) than to switch to 245794644356Smrg * "Default". 245894644356Smrg */ 245994644356Smrg int font_number = screen->menu_font_number; 246094644356Smrg if (font_number > fontMenu_lastBuiltin) 246194644356Smrg font_number = fontMenu_lastBuiltin; 246294644356Smrg for (n = 0; n < NMENUFONTS; ++n) { 246394644356Smrg screen->menu_font_sizes[n] = 0; 246494644356Smrg } 2465dfb07bc7Smrg if (font_number == fontMenu_default) { 2466dfb07bc7Smrg SetVTFont(xw, font_number, True, defaultVTFontNames(xw)); 2467dfb07bc7Smrg } else { 2468dfb07bc7Smrg SetVTFont(xw, font_number, True, NULL); 2469dfb07bc7Smrg } 247094644356Smrg } 247194644356Smrg MyStackFree(myClass, class_buf); 24729a64e1c5Smrg } 247394644356Smrg MyStackFree(myName, name_buf); 2474d522f475Smrg } 2475d522f475Smrg } 2476d522f475Smrg} 2477d522f475Smrg#endif /* OPT_LOAD_VTFONTS */ 2478d522f475Smrg 2479d522f475Smrg/* 2480d522f475Smrg * Set the limits for the box that outlines the cursor. 2481d522f475Smrg */ 2482d522f475Smrgvoid 2483fa3f02f3SmrgxtermSetCursorBox(TScreen *screen) 2484d522f475Smrg{ 2485d522f475Smrg static XPoint VTbox[NBOX]; 2486d522f475Smrg XPoint *vp; 24872eaa94a1Schristos int fw = FontWidth(screen) - 1; 24882eaa94a1Schristos int fh = FontHeight(screen) - 1; 2489d1603babSmrg int ww = isCursorBar(screen) ? fw / 8 : fw; 2490d1603babSmrg int hh = isCursorUnderline(screen) ? fh / 8 : fh; 2491d1603babSmrg if (ww < 2) 2492d1603babSmrg ww = 2; 2493d1603babSmrg if (hh < 2) 2494d1603babSmrg hh = 2; 2495d522f475Smrg 2496d522f475Smrg vp = &VTbox[1]; 24970bd37d32Smrg (vp++)->x = (short) ww; 24982eaa94a1Schristos (vp++)->y = (short) hh; 24990bd37d32Smrg (vp++)->x = (short) -ww; 25002eaa94a1Schristos vp->y = (short) -hh; 25012eaa94a1Schristos 2502d522f475Smrg screen->box = VTbox; 2503d522f475Smrg} 2504d522f475Smrg 2505d4fba8b9Smrg#if OPT_RENDERFONT 2506d4fba8b9Smrg 2507d1603babSmrg#define CACHE_XFT(data) if (XftFp(data) != NULL) {\ 2508d1603babSmrg int err = checkXftWidth(xw, data);\ 2509d4fba8b9Smrg TRACE(("Xft metrics %s[%d] = %d (%d,%d)%s advance %d, actual %d%s%s\n",\ 2510d1603babSmrg #data,\ 2511d4fba8b9Smrg fontnum,\ 2512d1603babSmrg XftFp(data)->height,\ 2513d1603babSmrg XftFp(data)->ascent,\ 2514d1603babSmrg XftFp(data)->descent,\ 2515d1603babSmrg ((XftFp(data)->ascent + XftFp(data)->descent) > XftFp(data)->height ? "*" : ""),\ 2516d1603babSmrg XftFp(data)->max_advance_width,\ 2517d1603babSmrg data->font_info.min_width,\ 2518d1603babSmrg data->font_info.mixed ? " mixed" : "",\ 2519d4fba8b9Smrg err ? " ERROR" : ""));\ 2520d4fba8b9Smrg if (err) {\ 2521d1603babSmrg xtermCloseXft(screen, data);\ 2522d1603babSmrg memset((data), 0, sizeof(*data));\ 2523d4fba8b9Smrg failed += err;\ 2524d4fba8b9Smrg }\ 2525d522f475Smrg } 2526d522f475Smrg 2527dfb07bc7Smrg#if OPT_REPORT_FONTS 252820d2c4d2Smrgstatic FcChar32 25299a64e1c5SmrgxtermXftFirstChar(XftFont *xft) 253020d2c4d2Smrg{ 253120d2c4d2Smrg FcChar32 map[FC_CHARSET_MAP_SIZE]; 253220d2c4d2Smrg FcChar32 next; 253320d2c4d2Smrg FcChar32 first; 253420d2c4d2Smrg int i; 253520d2c4d2Smrg 253620d2c4d2Smrg first = FcCharSetFirstPage(xft->charset, map, &next); 25379a64e1c5Smrg for (i = 0; i < FC_CHARSET_MAP_SIZE; i++) { 253820d2c4d2Smrg if (map[i]) { 253920d2c4d2Smrg FcChar32 bits = map[i]; 2540fa3f02f3Smrg first += (FcChar32) i *32; 254120d2c4d2Smrg while (!(bits & 0x1)) { 254220d2c4d2Smrg bits >>= 1; 254320d2c4d2Smrg first++; 254420d2c4d2Smrg } 254520d2c4d2Smrg break; 254620d2c4d2Smrg } 25479a64e1c5Smrg } 254820d2c4d2Smrg return first; 254920d2c4d2Smrg} 255020d2c4d2Smrg 255120d2c4d2Smrgstatic FcChar32 25529a64e1c5SmrgxtermXftLastChar(XftFont *xft) 255320d2c4d2Smrg{ 2554d1603babSmrg FcChar32 temp, last, next; 255520d2c4d2Smrg FcChar32 map[FC_CHARSET_MAP_SIZE]; 255620d2c4d2Smrg int i; 255720d2c4d2Smrg last = FcCharSetFirstPage(xft->charset, map, &next); 2558d1603babSmrg while ((temp = FcCharSetNextPage(xft->charset, map, &next)) != FC_CHARSET_DONE) 2559d1603babSmrg last = temp; 2560fa3f02f3Smrg last &= (FcChar32) ~ 0xff; 25619a64e1c5Smrg for (i = FC_CHARSET_MAP_SIZE - 1; i >= 0; i--) { 256220d2c4d2Smrg if (map[i]) { 256320d2c4d2Smrg FcChar32 bits = map[i]; 2564fa3f02f3Smrg last += (FcChar32) i *32 + 31; 256520d2c4d2Smrg while (!(bits & 0x80000000)) { 256620d2c4d2Smrg last--; 256720d2c4d2Smrg bits <<= 1; 256820d2c4d2Smrg } 256920d2c4d2Smrg break; 257020d2c4d2Smrg } 25719a64e1c5Smrg } 2572dfb07bc7Smrg return (FcChar32) last; 257320d2c4d2Smrg} 2574dfb07bc7Smrg#endif /* OPT_REPORT_FONTS */ 257520d2c4d2Smrg 2576d4fba8b9Smrg#if OPT_TRACE 2577d4fba8b9Smrg 2578d4fba8b9Smrg#if !OPT_WIDE_CHARS 2579d4fba8b9Smrgstatic Char * 2580d4fba8b9SmrgconvertToUTF8(Char *buffer, int c) 2581d4fba8b9Smrg{ 2582d4fba8b9Smrg buffer[0] = (Char) c; 2583d4fba8b9Smrg buffer[1] = 0; 2584d4fba8b9Smrg return buffer; 2585d4fba8b9Smrg} 2586d4fba8b9Smrg#endif 2587d4fba8b9Smrg 258820d2c4d2Smrgstatic void 25899a64e1c5SmrgdumpXft(XtermWidget xw, XTermXftFonts *data) 259020d2c4d2Smrg{ 2591d1603babSmrg XftFont *xft = XftFp(data); 259220d2c4d2Smrg TScreen *screen = TScreenOf(xw); 259320d2c4d2Smrg VTwin *win = WhichVWin(screen); 259420d2c4d2Smrg 259520d2c4d2Smrg FcChar32 c; 259620d2c4d2Smrg FcChar32 first = xtermXftFirstChar(xft); 259720d2c4d2Smrg FcChar32 last = xtermXftLastChar(xft); 2598d4fba8b9Smrg FcChar32 dump; 259920d2c4d2Smrg unsigned count = 0; 2600d4fba8b9Smrg unsigned too_high = 0; 2601d4fba8b9Smrg unsigned too_wide = 0; 2602d4fba8b9Smrg Boolean skip = False; 2603d4fba8b9Smrg 2604d4fba8b9Smrg TRACE(("dumpXft " TRACE_L "\n")); 2605d4fba8b9Smrg TRACE(("\tdata range U+%04X..U+%04X\n", first, last)); 2606d4fba8b9Smrg TRACE(("\tcode\tcells\tdimensions\n")); 2607d4fba8b9Smrg#if OPT_TRACE < 2 2608d4fba8b9Smrg dump = 255; 2609d4fba8b9Smrg#else 2610d4fba8b9Smrg dump = last; 2611d4fba8b9Smrg#endif 261220d2c4d2Smrg for (c = first; c <= last; ++c) { 261320d2c4d2Smrg if (FcCharSetHasChar(xft->charset, c)) { 2614c48a5815Smrg int width = CharWidth(screen, c); 261520d2c4d2Smrg XGlyphInfo extents; 2616d4fba8b9Smrg Boolean big_x; 2617d4fba8b9Smrg Boolean big_y; 261820d2c4d2Smrg 261920d2c4d2Smrg XftTextExtents32(XtDisplay(xw), xft, &c, 1, &extents); 2620d4fba8b9Smrg big_x = (extents.width > win->f_width); 2621d4fba8b9Smrg big_y = (extents.height > win->f_height); 2622d4fba8b9Smrg 2623d4fba8b9Smrg if (c <= dump) { 2624d4fba8b9Smrg Char buffer[80]; 2625d4fba8b9Smrg 2626d4fba8b9Smrg *convertToUTF8(buffer, c) = '\0'; 2627d4fba8b9Smrg TRACE(("%s%s\tU+%04X\t%d\t%.1f x %.1f\t%s\n", 2628d4fba8b9Smrg (big_y ? "y" : ""), 2629d4fba8b9Smrg (big_x ? "x" : ""), 2630d4fba8b9Smrg c, width, 2631d4fba8b9Smrg ((double) extents.height) / win->f_height, 2632d4fba8b9Smrg ((double) extents.width) / win->f_width, 2633d4fba8b9Smrg buffer)); 2634d4fba8b9Smrg } else if (!skip) { 2635d4fba8b9Smrg skip = True; 2636d4fba8b9Smrg TRACE(("\t...skipping\n")); 2637d4fba8b9Smrg } 2638d4fba8b9Smrg if (big_y) 2639d4fba8b9Smrg ++too_high; 2640d4fba8b9Smrg if (big_x) 2641d4fba8b9Smrg ++too_wide; 264220d2c4d2Smrg ++count; 264320d2c4d2Smrg } 264420d2c4d2Smrg } 2645d4fba8b9Smrg TRACE((TRACE_R " %u total, %u too-high, %u too-wide\n", count, too_high, too_wide)); 264620d2c4d2Smrg} 264720d2c4d2Smrg#define DUMP_XFT(xw, data) dumpXft(xw, data) 264820d2c4d2Smrg#else 264920d2c4d2Smrg#define DUMP_XFT(xw, data) /* nothing */ 265020d2c4d2Smrg#endif 265120d2c4d2Smrg 2652d4fba8b9Smrg/* 2653d4fba8b9Smrg * Check if this is a FC_COLOR font, which fontconfig misrepresents to "fix" a 2654d4fba8b9Smrg * problem with web browsers. As of 2018/12 (4 years later), Xft does not work 2655d4fba8b9Smrg * with that. Even with this workaround, fontconfig has at least one bug which 2656d4fba8b9Smrg * causes it to crash (Debian #917034). 2657d4fba8b9Smrg */ 2658d4fba8b9Smrg#ifdef FC_COLOR 2659d4fba8b9Smrg#define GetFcBool(pattern, what) \ 2660d1603babSmrg FcOK(FcPatternGetBool(pattern, what, 0, &fcbogus)) 2661d4fba8b9Smrg 2662d4fba8b9Smrgstatic Boolean 2663d4fba8b9SmrgisBogusXft(XftFont *font) 2664d4fba8b9Smrg{ 2665d4fba8b9Smrg Boolean result = False; 2666190d7dceSmrg if (font != NULL) { 2667d4fba8b9Smrg FcBool fcbogus; 2668d4fba8b9Smrg if (GetFcBool(font->pattern, FC_COLOR) && fcbogus) { 2669d4fba8b9Smrg TRACE(("...matched color-bitmap font\n")); 2670d1603babSmrg#if !USE_FC_COLOR 2671d4fba8b9Smrg result = True; 2672d1603babSmrg#endif 2673d4fba8b9Smrg } else if (GetFcBool(font->pattern, FC_OUTLINE) && !fcbogus) { 2674d4fba8b9Smrg TRACE(("...matched non-outline font\n")); 2675d4fba8b9Smrg /* This is legal for regular bitmap fonts - fontconfig attempts to 2676d4fba8b9Smrg * find a match - but problematic for misencoded color-bitmap fonts. 2677d4fba8b9Smrg */ 2678d4fba8b9Smrg } 2679d4fba8b9Smrg } 2680d4fba8b9Smrg return result; 2681d4fba8b9Smrg} 2682d4fba8b9Smrg#endif 2683d4fba8b9Smrg 2684d4fba8b9Smrg#if OPT_BOX_CHARS 2685956cc18dSsnjstatic void 2686d4fba8b9SmrgsetBrokenBoxChars(XtermWidget xw, Bool state) 2687d4fba8b9Smrg{ 2688d4fba8b9Smrg TRACE(("setBrokenBoxChars %s\n", BtoS(state))); 2689d4fba8b9Smrg term->work.broken_box_chars = (Boolean) state; 2690d4fba8b9Smrg TScreenOf(xw)->broken_box_chars = (Boolean) state; 2691d4fba8b9Smrg update_font_boxchars(); 2692d4fba8b9Smrg} 2693d4fba8b9Smrg 2694d4fba8b9Smrg#else 2695d4fba8b9Smrg#define setBrokenBoxChars(xw, state) /* nothing */ 2696d4fba8b9Smrg#endif 2697d4fba8b9Smrg 2698d4fba8b9Smrgstatic Boolean 2699d4fba8b9SmrgcheckedXftWidth(Display *dpy, 2700d4fba8b9Smrg XTermXftFonts *source, 2701d4fba8b9Smrg unsigned limit, 2702d4fba8b9Smrg Dimension *width, 2703d4fba8b9Smrg FcChar32 c) 2704d4fba8b9Smrg{ 2705d4fba8b9Smrg Boolean result = False; 2706d4fba8b9Smrg 2707d1603babSmrg if (FcCharSetHasChar(XftFp(source)->charset, c)) { 2708d4fba8b9Smrg XGlyphInfo extents; 2709d4fba8b9Smrg 2710d4fba8b9Smrg result = True; 2711d1603babSmrg XftTextExtents32(dpy, XftFp(source), &c, 1, &extents); 2712d4fba8b9Smrg if (*width < extents.width && extents.width <= limit) { 2713d4fba8b9Smrg *width = extents.width; 2714d4fba8b9Smrg } 2715d4fba8b9Smrg } 2716d4fba8b9Smrg return result; 2717d4fba8b9Smrg} 2718d4fba8b9Smrg 2719d1603babSmrg/* 2720d1603babSmrg * Check if the given character has a glyph known to Xft. This is likely to be 2721d1603babSmrg * slower than checking our cache. 2722d1603babSmrg * 2723d1603babSmrg * see xc/lib/Xft/xftglyphs.c 2724d1603babSmrg */ 2725d1603babSmrgstatic Bool 2726d1603babSmrgslowXftMissing(XtermWidget xw, XftFont *font, unsigned wc) 2727d1603babSmrg{ 2728d1603babSmrg TScreen *screen = TScreenOf(xw); 2729d1603babSmrg Bool result = False; 2730d1603babSmrg 2731d1603babSmrg if (font != NULL) { 2732d1603babSmrg if (XftCharIndex(screen->display, font, wc) == 0) 2733d1603babSmrg result = True; 2734d1603babSmrg } 2735d1603babSmrg return result; 2736d1603babSmrg} 2737d1603babSmrg 2738d4fba8b9Smrgstatic int 2739d1603babSmrgcheckXftWidth(XtermWidget xw, XTermXftFonts *data) 2740956cc18dSsnj{ 2741956cc18dSsnj FcChar32 c; 2742d1603babSmrg FcChar32 last = xtermXftLastChar(XftFp(data)); 2743d1603babSmrg Dimension limit = (Dimension) XftFp(data)->max_advance_width; 2744956cc18dSsnj Dimension width = 0; 2745d4fba8b9Smrg Dimension width2 = 0; 2746d4fba8b9Smrg int failed = 0; 2747d4fba8b9Smrg#if OPT_WIDE_CHARS 2748d4fba8b9Smrg Cardinal n; 2749d4fba8b9Smrg#endif 2750956cc18dSsnj 2751d1603babSmrg data->font_info.min_width = 0; 2752d1603babSmrg data->font_info.max_width = limit; 2753d4fba8b9Smrg 2754d4fba8b9Smrg#if OPT_WIDE_CHARS 2755d4fba8b9Smrg /* 2756d4fba8b9Smrg * Check if the line-drawing characters are all provided in the font. 2757d4fba8b9Smrg * If so, take that into account for the cell-widths. 2758d4fba8b9Smrg */ 2759d4fba8b9Smrg for (n = 0; n < XtNumber(unicode_boxes) - 1; ++n) { 2760d4fba8b9Smrg if (!checkedXftWidth(XtDisplay(xw), 2761d1603babSmrg data, 2762d4fba8b9Smrg limit, 2763d4fba8b9Smrg &width2, unicode_boxes[n].code)) { 2764d4fba8b9Smrg width2 = 0; 2765d4fba8b9Smrg TRACE(("font omits U+%04X line-drawing symbol\n", 2766d4fba8b9Smrg unicode_boxes[n].code)); 2767d4fba8b9Smrg break; 2768d4fba8b9Smrg } 2769d4fba8b9Smrg } 2770d4fba8b9Smrg#else 2771d4fba8b9Smrg (void) width2; 2772d4fba8b9Smrg#endif 2773d4fba8b9Smrg 2774d4fba8b9Smrg if (width2 > 0) { 2775d4fba8b9Smrg Dimension check = (Dimension) (limit + 1) / 2; 2776d4fba8b9Smrg TRACE(("font provides VT100-style line-drawing\n")); 2777d4fba8b9Smrg /* 2778d4fba8b9Smrg * The "VT100 line-drawing" characters happen to be all "ambiguous 2779d4fba8b9Smrg * width" in Unicode's scheme. That means that they could be twice as 2780d4fba8b9Smrg * wide as the Latin-1 characters. 2781d4fba8b9Smrg */ 2782d4fba8b9Smrg#define FC_ERR(n) (1.2 * (n)) 2783d4fba8b9Smrg if (width2 > FC_ERR(check)) { 2784d4fba8b9Smrg TRACE(("line-drawing characters appear to be double-width (ignore)\n")); 2785d4fba8b9Smrg setBrokenBoxChars(xw, True); 2786d4fba8b9Smrg } else if (width2 > width) { 2787d4fba8b9Smrg width = width2; 2788d4fba8b9Smrg } 2789d4fba8b9Smrg } else { 2790d4fba8b9Smrg TRACE(("font does NOT provide VT100-style line-drawing\n")); 2791d4fba8b9Smrg setBrokenBoxChars(xw, True); 2792d4fba8b9Smrg } 2793956cc18dSsnj 279420d2c4d2Smrg /* 2795d4fba8b9Smrg * For each printable code, ask what its width is. Given the maximum width 2796d4fba8b9Smrg * for those, we have a reasonable estimate of the single-column width. 279720d2c4d2Smrg * 279820d2c4d2Smrg * Ignore control characters - their extent information is misleading. 279920d2c4d2Smrg */ 2800956cc18dSsnj for (c = 32; c < 256; ++c) { 2801c48a5815Smrg if (CharWidth(TScreenOf(xw), c) <= 0) 280220d2c4d2Smrg continue; 2803d1603babSmrg if (FcCharSetHasChar(XftFp(data)->charset, c)) { 2804d4fba8b9Smrg (void) checkedXftWidth(XtDisplay(xw), 2805d1603babSmrg data, 2806d1603babSmrg data->font_info.max_width, 2807d4fba8b9Smrg &width, c); 2808d4fba8b9Smrg } 2809d4fba8b9Smrg } 2810956cc18dSsnj 2811d4fba8b9Smrg /* 2812d4fba8b9Smrg * Sometimes someone uses a symbol font which has no useful ASCII or 2813d4fba8b9Smrg * Latin-1 characters. Allow that, in case they did it intentionally. 2814d4fba8b9Smrg */ 2815d4fba8b9Smrg if (width == 0) { 2816d4fba8b9Smrg failed = 1; 2817d4fba8b9Smrg if (last >= 256) { 2818d1603babSmrg width = data->font_info.max_width; 2819956cc18dSsnj } 2820956cc18dSsnj } 2821d1603babSmrg data->font_info.min_width = width; 2822d1603babSmrg data->font_info.mixed = (data->font_info.max_width >= 2823d1603babSmrg (data->font_info.min_width + 1)); 2824d4fba8b9Smrg return failed; 2825956cc18dSsnj} 2826956cc18dSsnj 2827d1603babSmrg#if OPT_TRACE 2828d1603babSmrgstatic const char * 2829d1603babSmrgnameOfXftFont(XftFont *fp) 2830d1603babSmrg{ 2831d1603babSmrg static char *result; 2832d1603babSmrg char buffer[1024]; 2833d1603babSmrg FreeAndNull(result); 2834d1603babSmrg if (XftNameUnparse(fp->pattern, buffer, (int) sizeof(buffer))) { 2835d1603babSmrg char *target; 2836d1603babSmrg char *source = buffer; 2837190d7dceSmrg if ((target = strtok(source, ":")) != NULL) { 2838d1603babSmrg result = x_strdup(target); 2839d1603babSmrg } 2840d1603babSmrg } 2841d1603babSmrg return NonNull(result); 2842d1603babSmrg} 2843d1603babSmrg#endif 2844d1603babSmrg 2845dfb07bc7Smrg#if OPT_REPORT_FONTS 2846fa3f02f3Smrgstatic void 2847fa3f02f3SmrgreportXftFonts(XtermWidget xw, 2848d1603babSmrg XTermXftFonts *fontData, 2849d1603babSmrg int fontNum, 28509a64e1c5Smrg XftFont *fp, 2851fa3f02f3Smrg const char *name, 2852fa3f02f3Smrg const char *tag, 28539a64e1c5Smrg XftPattern *match) 2854fa3f02f3Smrg{ 2855fa3f02f3Smrg if (resource.reportFonts) { 2856fa3f02f3Smrg char buffer[1024]; 2857fa3f02f3Smrg FcChar32 first_char = xtermXftFirstChar(fp); 2858fa3f02f3Smrg FcChar32 last_char = xtermXftLastChar(fp); 2859fa3f02f3Smrg FcChar32 ch; 2860fa3f02f3Smrg unsigned missing = 0; 2861fa3f02f3Smrg 2862d1603babSmrg ReportFonts("Loaded XftFonts(%s[%s])\n", name, tag); 2863fa3f02f3Smrg 2864fa3f02f3Smrg for (ch = first_char; ch <= last_char; ++ch) { 2865d1603babSmrg if (xtermXftMissing(xw, fontData, fontNum, fp, ch)) { 2866fa3f02f3Smrg ++missing; 2867fa3f02f3Smrg } 2868fa3f02f3Smrg } 2869d1603babSmrg ReportFonts("\t\tfirst char: %u\n", first_char); 2870d1603babSmrg ReportFonts("\t\tlast char: %u\n", last_char); 2871d1603babSmrg ReportFonts("\t\tmissing-chars: %u\n", missing); 2872d1603babSmrg ReportFonts("\t\tpresent-chars: %u\n", ((last_char - first_char) 2873d1603babSmrg + 1 - missing)); 2874fa3f02f3Smrg 2875fa3f02f3Smrg if (XftNameUnparse(match, buffer, (int) sizeof(buffer))) { 2876fa3f02f3Smrg char *target; 2877fa3f02f3Smrg char *source = buffer; 2878190d7dceSmrg while ((target = strtok(source, ":")) != NULL) { 2879d1603babSmrg ReportFonts("\t%s\n", target); 2880190d7dceSmrg source = NULL; 2881fa3f02f3Smrg } 2882fa3f02f3Smrg } 2883d4fba8b9Smrg fflush(stdout); 2884fa3f02f3Smrg } 2885fa3f02f3Smrg} 2886d1603babSmrg 2887d1603babSmrgstatic void 2888d1603babSmrgreportXftFallbackFont(XtermWidget xw, 2889d1603babSmrg XTermXftFonts *fontData, 2890d1603babSmrg int fontNum, 2891d1603babSmrg XftFont *font, 2892d1603babSmrg XftPattern *match) 2893d1603babSmrg{ 2894d1603babSmrg if (resource.reportFonts) { 2895d1603babSmrg char tag[80]; 2896d1603babSmrg sprintf(tag, "%s#%d", 2897d1603babSmrg whichXftFonts(xw, fontData), 2898d1603babSmrg fontNum + 1); 2899d1603babSmrg reportXftFonts(xw, fontData, fontNum, font, "fallback", tag, match); 2900d1603babSmrg } 2901d1603babSmrg} 2902d1603babSmrg 2903dfb07bc7Smrg#else 2904d1603babSmrg#define reportXftFonts(xw, fontData, fontNum, result, name, tag, match) /* empty */ 2905d1603babSmrg#define reportXftFallbackFont(xw, fontData, fontNum, font, match) /* empty */ 2906dfb07bc7Smrg#endif /* OPT_REPORT_FONTS */ 2907fa3f02f3Smrg 2908d4fba8b9Smrg/* 2909d4fba8b9Smrg * Xft discards the pattern-match during open-pattern if the result happens to 2910d4fba8b9Smrg * match a currently-open file, but provides no clue to the caller when it does 2911d4fba8b9Smrg * this. That is, closing a font-file may leave the data in Xft's cache, while 2912d4fba8b9Smrg * opening a file may free the data used for the match. 2913d4fba8b9Smrg * 2914d4fba8b9Smrg * Because of this problem, we cannot reliably refer to the pattern-match data 2915d4fba8b9Smrg * if it may have been seen before. 2916d4fba8b9Smrg */ 2917d4fba8b9SmrgBoolean 2918d4fba8b9SmrgmaybeXftCache(XtermWidget xw, XftFont *font) 2919d4fba8b9Smrg{ 2920d4fba8b9Smrg Boolean result = False; 2921d1603babSmrg if (font != NULL) { 2922d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 2923d4fba8b9Smrg ListXftFonts *p; 2924d1603babSmrg for (p = screen->list_xft_fonts; p != NULL; p = p->next) { 2925d4fba8b9Smrg if (p->font == font) { 2926d4fba8b9Smrg result = True; 2927d4fba8b9Smrg break; 2928d4fba8b9Smrg } 2929d4fba8b9Smrg } 2930d4fba8b9Smrg if (!result) { 2931d4fba8b9Smrg p = TypeXtMalloc(ListXftFonts); 2932d1603babSmrg if (p != NULL) { 2933d4fba8b9Smrg p->font = font; 2934d4fba8b9Smrg p->next = screen->list_xft_fonts; 2935d4fba8b9Smrg screen->list_xft_fonts = p; 2936d4fba8b9Smrg } 2937d4fba8b9Smrg } 2938d4fba8b9Smrg } 2939d4fba8b9Smrg return result; 2940d4fba8b9Smrg} 2941d4fba8b9Smrg 2942d4fba8b9Smrg/* 2943d4fba8b9Smrg * Drop an entry from the cache, and close the font. 2944d4fba8b9Smrg */ 2945d4fba8b9Smrgvoid 2946d4fba8b9SmrgcloseCachedXft(TScreen *screen, XftFont *font) 2947d4fba8b9Smrg{ 2948190d7dceSmrg if (font != NULL) { 2949d4fba8b9Smrg ListXftFonts *p, *q; 2950d4fba8b9Smrg 2951190d7dceSmrg for (p = screen->list_xft_fonts, q = NULL; p != NULL; q = p, p = p->next) { 2952d4fba8b9Smrg if (p->font == font) { 2953d4fba8b9Smrg XftFontClose(screen->display, font); 2954190d7dceSmrg if (q != NULL) { 2955d4fba8b9Smrg q->next = p->next; 2956d4fba8b9Smrg } else { 2957d4fba8b9Smrg screen->list_xft_fonts = p->next; 2958d4fba8b9Smrg } 2959d4fba8b9Smrg free(p); 2960d4fba8b9Smrg break; 2961d4fba8b9Smrg } 2962d4fba8b9Smrg } 2963d4fba8b9Smrg } 2964d4fba8b9Smrg} 2965d4fba8b9Smrg 2966d1603babSmrgstatic void 2967d1603babSmrgxtermOpenXft(XtermWidget xw, 2968d1603babSmrg XTermXftFonts *fontData, 2969d1603babSmrg int fontNum, 2970d1603babSmrg const char *name, 2971d1603babSmrg XftPattern *pat, 2972d1603babSmrg const char *tag) 2973d522f475Smrg{ 2974956cc18dSsnj TScreen *screen = TScreenOf(xw); 2975956cc18dSsnj Display *dpy = screen->display; 2976d522f475Smrg XftResult status; 2977190d7dceSmrg XftFont *result = NULL; 2978d522f475Smrg 2979d4fba8b9Smrg TRACE(("xtermOpenXft(name=%s, tag=%s)\n", name, tag)); 2980190d7dceSmrg if (pat != NULL && (fontNum <= MaxXftCache)) { 2981d4fba8b9Smrg XftPattern *match; 2982d4fba8b9Smrg 2983d4fba8b9Smrg FcConfigSubstitute(NULL, pat, FcMatchPattern); 2984d4fba8b9Smrg XftDefaultSubstitute(dpy, DefaultScreen(dpy), pat); 2985d4fba8b9Smrg 2986d4fba8b9Smrg match = FcFontMatch(NULL, pat, &status); 2987190d7dceSmrg if (match != NULL) { 2988d4fba8b9Smrg Boolean maybeReopened = False; 2989d522f475Smrg result = XftFontOpenPattern(dpy, match); 2990d4fba8b9Smrg#ifdef FC_COLOR 2991d1603babSmrg if (result != NULL) { 2992d4fba8b9Smrg if (isBogusXft(result)) { 2993d4fba8b9Smrg XftFontClose(dpy, result); 2994d1603babSmrg result = NULL; 2995d4fba8b9Smrg maybeReopened = True; 2996d4fba8b9Smrg } 2997d4fba8b9Smrg } 2998d4fba8b9Smrg#endif 2999d1603babSmrg if (result != NULL) { 3000d522f475Smrg TRACE(("...matched %s font\n", tag)); 3001d1603babSmrg if (fontData->fs_size < fontNum) 3002d1603babSmrg fontData->fs_size = fontNum; 3003d1603babSmrg XftFpN(fontData, fontNum) = result; 3004d1603babSmrg XftIsN(fontData, fontNum) = xcOpened; 3005d4fba8b9Smrg if (!maybeXftCache(xw, result)) { 3006d1603babSmrg reportXftFonts(xw, fontData, fontNum, result, name, tag, match); 3007d4fba8b9Smrg } 3008d522f475Smrg } else { 3009d4fba8b9Smrg TRACE(("...could not open %s font\n", tag)); 3010d4fba8b9Smrg if (!maybeReopened) 3011d4fba8b9Smrg XftPatternDestroy(match); 3012956cc18dSsnj if (xw->misc.fontWarnings >= fwAlways) { 3013dfb07bc7Smrg cannotFont(xw, "open", tag, name); 3014956cc18dSsnj } 3015d522f475Smrg } 3016d522f475Smrg } else { 3017d522f475Smrg TRACE(("...did not match %s font\n", tag)); 3018956cc18dSsnj if (xw->misc.fontWarnings >= fwResource) { 3019dfb07bc7Smrg cannotFont(xw, "match", tag, name); 3020956cc18dSsnj } 3021d522f475Smrg } 3022d522f475Smrg } 3023d1603babSmrg if (result == NULL && (fontNum <= MaxXftCache)) { 3024d1603babSmrg XftFpN(fontData, fontNum) = NULL; 3025d1603babSmrg XftIsN(fontData, fontNum) = xcEmpty; 3026d1603babSmrg } 3027d522f475Smrg} 3028d522f475Smrg 3029d522f475Smrg#if OPT_SHIFT_FONTS 3030d522f475Smrg/* 3031d522f475Smrg * Don't make a dependency on the math library for a single function. 3032d522f475Smrg * (Newton Raphson). 3033d522f475Smrg */ 3034d522f475Smrgstatic double 30350bd37d32SmrgdimSquareRoot(double value) 3036d522f475Smrg{ 3037d522f475Smrg double result = 0.0; 3038d522f475Smrg if (value > 0.0) { 3039d522f475Smrg int n; 3040d522f475Smrg double older = value; 3041d522f475Smrg for (n = 0; n < 10; ++n) { 3042d522f475Smrg double delta = (older * older - value) / (2.0 * older); 3043d522f475Smrg double newer = older - delta; 3044d522f475Smrg older = newer; 3045d522f475Smrg result = newer; 3046d522f475Smrg if (delta > -0.001 && delta < 0.001) 3047d522f475Smrg break; 3048d522f475Smrg } 3049d522f475Smrg } 3050d522f475Smrg return result; 3051d522f475Smrg} 3052d522f475Smrg#endif 3053d522f475Smrg 3054d4fba8b9Smrg#ifdef DEBUG_XFT 3055d4fba8b9Smrgstatic void 3056d1603babSmrgtrace_xft_glyph(XtermWidget xw, XTermXftFonts *data, FT_Face face, int code, const char *name) 3057d4fba8b9Smrg{ 3058d1603babSmrg if (xtermXftMissing(xw, data, 0, XftFp(data), code)) { 3059d4fba8b9Smrg TRACE(("Xft glyph U+%04X missing :%s\n", code, name)); 3060d4fba8b9Smrg } else if (FT_Load_Char(face, code, FT_LOAD_RENDER) == 0) { 3061d4fba8b9Smrg FT_GlyphSlot g = face->glyph; 3062d4fba8b9Smrg TRACE(("Xft glyph U+%04X size(%3d,%3d) at(%3d,%3d) :%s\n", 3063d4fba8b9Smrg code, 3064d4fba8b9Smrg g->bitmap.rows, g->bitmap.width, 3065d4fba8b9Smrg g->bitmap_top, g->bitmap_left, 3066d4fba8b9Smrg name)); 3067d4fba8b9Smrg } 3068d4fba8b9Smrg} 3069d4fba8b9Smrg 3070d4fba8b9Smrg#if OPT_WIDE_CHARS 3071d4fba8b9Smrgstatic void 3072d1603babSmrgtrace_xft_line_drawing(XtermWidget xw, XTermXftFonts *data, FT_Face face) 3073d4fba8b9Smrg{ 3074d4fba8b9Smrg int n; 3075d4fba8b9Smrg for (n = 0; unicode_boxes[n].code != 0; ++n) { 3076d1603babSmrg trace_xft_glyph(xw, data, face, unicode_boxes[n].code, 3077d4fba8b9Smrg unicode_boxes[n].name); 3078d4fba8b9Smrg } 3079d4fba8b9Smrg} 3080d4fba8b9Smrg#else 3081d1603babSmrg#define trace_xft_line_drawing(xw, data, face) /* nothing */ 3082d4fba8b9Smrg#endif 3083d4fba8b9Smrg#endif /* DEBUG_XFT */ 3084d4fba8b9Smrg 3085d4fba8b9Smrg/* 3086d4fba8b9Smrg * Check if the line-drawing characters do not fill the bounding box. If so, 3087d4fba8b9Smrg * they're not useful. 3088d4fba8b9Smrg */ 3089d4fba8b9Smrg#if OPT_BOX_CHARS 3090d4fba8b9Smrgstatic void 3091d1603babSmrglinedrawing_gaps(XtermWidget xw, XTermXftFonts *data) 3092d4fba8b9Smrg{ 3093d4fba8b9Smrg Boolean broken; 3094d4fba8b9Smrg 3095d4fba8b9Smrg#if OPT_WIDE_CHARS 3096d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 3097d4fba8b9Smrg int n; 3098d4fba8b9Smrg FT_Face face; 3099d1603babSmrg face = XftLockFace(XftFp(data)); 3100d4fba8b9Smrg broken = False; 3101d4fba8b9Smrg for (n = 0; unicode_boxes[n].code; ++n) { 3102d4fba8b9Smrg unsigned code = unicode_boxes[n].code; 3103d4fba8b9Smrg 3104d1603babSmrg if (xtermXftMissing(xw, data, 0, XftFp(data), code)) { 3105d4fba8b9Smrg TRACE(("Xft glyph U+%04X is missing\n", code)); 3106d4fba8b9Smrg broken = True; 3107d4fba8b9Smrg break; 3108d4fba8b9Smrg } 3109d4fba8b9Smrg 3110d4fba8b9Smrg if (FT_Load_Char(face, code, FT_LOAD_RENDER) == 0) { 3111d4fba8b9Smrg FT_GlyphSlot g = face->glyph; 3112d4fba8b9Smrg TRACE(("Xft glyph U+%04X size(%3d,%3d) at(%3d,%3d) :%s\n", 3113d4fba8b9Smrg code, 3114d4fba8b9Smrg g->bitmap.rows, g->bitmap.width, 3115d4fba8b9Smrg g->bitmap_top, g->bitmap_left, 3116d4fba8b9Smrg unicode_boxes[n].name)); 3117d4fba8b9Smrg /* 3118d4fba8b9Smrg * While it is possible for badly-designed fonts to have line 3119d4fba8b9Smrg * drawing characters which do not meet, FreeType aggravates the 3120d4fba8b9Smrg * situation with its rounding. Check for an obvious case where 3121d4fba8b9Smrg * the weights at the ends of a vertical line do not add up. That 3122d4fba8b9Smrg * shows up as two under-weight rows at the beginning/end of the 3123d4fba8b9Smrg * bitmap. 3124d4fba8b9Smrg */ 3125d4fba8b9Smrg if (code == 0x2502) { 3126d4fba8b9Smrg unsigned r, c; 3127d4fba8b9Smrg unsigned mids = 0, ends = 0; 3128d1603babSmrg unsigned char *buffer = g->bitmap.buffer; 3129d4fba8b9Smrg 3130d4fba8b9Smrg switch (g->bitmap.pixel_mode) { 3131d4fba8b9Smrg case FT_PIXEL_MODE_MONO: 3132d4fba8b9Smrg /* FALLTHRU */ 3133d4fba8b9Smrg case FT_PIXEL_MODE_GRAY: 3134d4fba8b9Smrg for (r = 0; r < (unsigned) g->bitmap.rows; ++r) { 3135d4fba8b9Smrg unsigned k = r * (unsigned) g->bitmap.pitch; 3136d4fba8b9Smrg unsigned sum = 0; 3137d4fba8b9Smrg for (c = 0; c < (unsigned) g->bitmap.width; ++c) { 3138d4fba8b9Smrg unsigned xx = 0; 3139d4fba8b9Smrg switch (g->bitmap.pixel_mode) { 3140d4fba8b9Smrg case FT_PIXEL_MODE_MONO: 3141d1603babSmrg xx = (unsigned) ((buffer[k + (c / 8)] 3142d4fba8b9Smrg >> (c % 8)) & 1); 3143d4fba8b9Smrg break; 3144d4fba8b9Smrg case FT_PIXEL_MODE_GRAY: 3145d1603babSmrg xx = buffer[k + c]; 3146d4fba8b9Smrg break; 3147d4fba8b9Smrg } 3148d4fba8b9Smrg sum += xx; 3149d4fba8b9Smrg TRACE2((" %2x", xx)); 3150d4fba8b9Smrg } 3151d4fba8b9Smrg TRACE2((" = %u\n", sum)); 3152d4fba8b9Smrg if (r > 0 && (r + 1) < (unsigned) g->bitmap.rows) { 3153d4fba8b9Smrg mids = sum; 3154d4fba8b9Smrg } else { 3155d4fba8b9Smrg ends += sum; 3156d4fba8b9Smrg } 3157d4fba8b9Smrg } 3158d4fba8b9Smrg TRACE(("...compare middle %u vs ends %u\n", mids, ends)); 3159d4fba8b9Smrg if ((mids > ends) && (g->bitmap.rows < 16)) 3160d4fba8b9Smrg broken = True; 3161d4fba8b9Smrg break; 3162d4fba8b9Smrg default: 3163d4fba8b9Smrg TRACE(("FIXME pixel_mode %d not handled\n", 3164d4fba8b9Smrg g->bitmap.pixel_mode)); 3165d4fba8b9Smrg break; 3166d4fba8b9Smrg } 3167d4fba8b9Smrg if (broken) 3168d4fba8b9Smrg break; 3169d4fba8b9Smrg } 3170d4fba8b9Smrg /* 3171d4fba8b9Smrg * The factor of two accounts for line-drawing that goes through 3172d4fba8b9Smrg * the middle of a cell, possibly leaving half of the cell unused. 3173d4fba8b9Smrg * A horizontal line has to extend the full width of the cell. 3174d4fba8b9Smrg */ 3175d4fba8b9Smrg switch (unicode_boxes[n].high) { 3176d4fba8b9Smrg case 1: 3177d4fba8b9Smrg if ((unsigned) g->bitmap.rows < (unsigned) FontHeight(screen)) { 3178d4fba8b9Smrg TRACE(("...bitmap is shorter than full-cell (%u vs %u)\n", 3179d4fba8b9Smrg (unsigned) g->bitmap.rows, 3180d4fba8b9Smrg (unsigned) FontHeight(screen))); 3181d4fba8b9Smrg broken = True; 3182d4fba8b9Smrg } 3183d4fba8b9Smrg break; 3184d4fba8b9Smrg case 2: 3185d4fba8b9Smrg if ((unsigned) (g->bitmap.rows * 2) < (unsigned) FontHeight(screen)) { 3186d4fba8b9Smrg TRACE(("...bitmap is too short for half-cell (%u vs %u)\n", 3187d4fba8b9Smrg (unsigned) (g->bitmap.rows * 2), 3188d4fba8b9Smrg (unsigned) FontHeight(screen))); 3189d4fba8b9Smrg broken = True; 3190d4fba8b9Smrg } 3191d4fba8b9Smrg break; 3192d4fba8b9Smrg } 3193d4fba8b9Smrg switch (unicode_boxes[n].wide) { 3194d4fba8b9Smrg case 1: 3195d4fba8b9Smrg if ((unsigned) g->bitmap.width < (unsigned) FontWidth(screen)) { 3196d4fba8b9Smrg TRACE(("...bitmap is narrower than full-cell (%u vs %u)\n", 3197d4fba8b9Smrg (unsigned) g->bitmap.width, 3198d4fba8b9Smrg (unsigned) FontWidth(screen))); 3199d4fba8b9Smrg broken = True; 3200d4fba8b9Smrg } 3201d4fba8b9Smrg break; 3202d4fba8b9Smrg case 2: 3203d4fba8b9Smrg if ((unsigned) (g->bitmap.width * 2) < (unsigned) FontWidth(screen)) { 3204d4fba8b9Smrg TRACE(("...bitmap is too narrow for half-cell (%u vs %u)\n", 3205d4fba8b9Smrg (unsigned) (g->bitmap.width * 2), 3206d4fba8b9Smrg (unsigned) FontWidth(screen))); 3207d4fba8b9Smrg broken = True; 3208d4fba8b9Smrg } 3209d4fba8b9Smrg break; 3210d4fba8b9Smrg } 3211d4fba8b9Smrg if (broken) 3212d4fba8b9Smrg break; 3213d4fba8b9Smrg } 3214d4fba8b9Smrg } 3215d1603babSmrg XftUnlockFace(XftFp(data)); 3216d4fba8b9Smrg#else 3217d1603babSmrg (void) data; 3218d4fba8b9Smrg broken = True; 3219d4fba8b9Smrg#endif 3220d4fba8b9Smrg 3221d4fba8b9Smrg if (broken) { 3222d4fba8b9Smrg TRACE(("Xft line-drawing would not work\n")); 3223d4fba8b9Smrg setBrokenBoxChars(xw, True); 3224d4fba8b9Smrg } 3225d4fba8b9Smrg} 3226d4fba8b9Smrg#endif /* OPT_BOX_CHARS */ 3227d4fba8b9Smrg 3228d522f475Smrg/* 3229d522f475Smrg * Given the Xft font metrics, determine the actual font size. This is used 3230d522f475Smrg * for each font to ensure that normal, bold and italic fonts follow the same 3231d522f475Smrg * rule. 3232d522f475Smrg */ 3233d522f475Smrgstatic void 3234d1603babSmrgsetRenderFontsize(XtermWidget xw, VTwin *win, XTermXftFonts *data, const char *tag) 3235d522f475Smrg{ 3236d1603babSmrg XftFont *font = XftFp(data); 3237d1603babSmrg if (font != NULL) { 3238d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 3239d522f475Smrg int width, height, ascent, descent; 3240d4fba8b9Smrg#ifdef DEBUG_XFT 3241d4fba8b9Smrg int n; 3242d4fba8b9Smrg FT_Face face; 3243d4fba8b9Smrg FT_Size size; 3244d4fba8b9Smrg FT_Size_Metrics metrics; 3245d4fba8b9Smrg Boolean scalable; 3246d4fba8b9Smrg Boolean is_fixed; 3247d4fba8b9Smrg Boolean debug_xft = False; 3248d4fba8b9Smrg 3249d4fba8b9Smrg face = XftLockFace(font); 3250d4fba8b9Smrg size = face->size; 3251d4fba8b9Smrg metrics = size->metrics; 3252d4fba8b9Smrg is_fixed = FT_IS_FIXED_WIDTH(face); 3253d4fba8b9Smrg scalable = FT_IS_SCALABLE(face); 3254d1603babSmrg trace_xft_line_drawing(xw, data, face); 3255d4fba8b9Smrg for (n = 32; n < 127; ++n) { 3256d4fba8b9Smrg char name[80]; 3257d4fba8b9Smrg sprintf(name, "letter \"%c\"", n); 3258d1603babSmrg trace_xft_glyph(xw, data, face, n, name); 3259d4fba8b9Smrg } 3260d4fba8b9Smrg XftUnlockFace(font); 3261d4fba8b9Smrg 3262d4fba8b9Smrg /* freetype's inconsistent for this sign */ 3263d4fba8b9Smrg metrics.descender = -metrics.descender; 3264d4fba8b9Smrg 3265d4fba8b9Smrg#define TR_XFT "Xft metrics: " 3266d4fba8b9Smrg#define D_64(name) ((double)(metrics.name)/64.0) 3267d4fba8b9Smrg#define M_64(a,b) ((font->a * 64) != metrics.b) 3268d4fba8b9Smrg#define BOTH(a,b) D_64(b), M_64(a,b) ? "*" : "" 3269d4fba8b9Smrg 3270d4fba8b9Smrg debug_xft = (M_64(ascent, ascender) 3271d4fba8b9Smrg || M_64(descent, descender) 3272d4fba8b9Smrg || M_64(height, height) 3273d4fba8b9Smrg || M_64(max_advance_width, max_advance)); 3274d4fba8b9Smrg 3275d4fba8b9Smrg TRACE(("Xft font is %sscalable, %sfixed-width\n", 3276d4fba8b9Smrg is_fixed ? "" : "not ", 3277d4fba8b9Smrg scalable ? "" : "not ")); 3278d4fba8b9Smrg 3279d4fba8b9Smrg if (debug_xft) { 3280d4fba8b9Smrg TRACE(("Xft font size %d+%d vs %d by %d\n", 3281d4fba8b9Smrg font->ascent, 3282d4fba8b9Smrg font->descent, 3283d4fba8b9Smrg font->height, 3284d4fba8b9Smrg font->max_advance_width)); 3285d4fba8b9Smrg TRACE((TR_XFT "ascender %6.2f%s\n", BOTH(ascent, ascender))); 3286d4fba8b9Smrg TRACE((TR_XFT "descender %6.2f%s\n", BOTH(descent, descender))); 3287d4fba8b9Smrg TRACE((TR_XFT "height %6.2f%s\n", BOTH(height, height))); 3288d4fba8b9Smrg TRACE((TR_XFT "max_advance %6.2f%s\n", BOTH(max_advance_width, max_advance))); 3289d4fba8b9Smrg } else { 3290d4fba8b9Smrg TRACE((TR_XFT "matches font\n")); 3291d4fba8b9Smrg } 3292d4fba8b9Smrg#endif 3293d522f475Smrg 3294d522f475Smrg width = font->max_advance_width; 3295d522f475Smrg height = font->height; 3296d522f475Smrg ascent = font->ascent; 3297d522f475Smrg descent = font->descent; 3298d4fba8b9Smrg if (screen->force_xft_height && height < ascent + descent) { 3299d4fba8b9Smrg TRACE(("...height is less than ascent + descent (%u vs %u)\n", 3300d4fba8b9Smrg height, ascent + descent)); 3301d4fba8b9Smrg if ((ascent + descent) > (height + 1)) { 3302d4fba8b9Smrg /* this happens less than 10% of the time */ 3303d4fba8b9Smrg --ascent; 3304d4fba8b9Smrg --descent; 3305d4fba8b9Smrg TRACE(("...decrement both ascent and descent before retry\n")); 3306d4fba8b9Smrg } else if (ascent > descent) { 3307d4fba8b9Smrg /* this is the usual case */ 3308d4fba8b9Smrg --ascent; 3309d4fba8b9Smrg TRACE(("...decrement ascent before retry\n")); 3310d4fba8b9Smrg } else { 3311d4fba8b9Smrg /* this could happen, though rare... */ 3312d4fba8b9Smrg --descent; 3313d4fba8b9Smrg TRACE(("...decrement descent before retry\n")); 3314d4fba8b9Smrg } 3315d522f475Smrg height = ascent + descent; 3316d4fba8b9Smrg font->ascent = ascent; 3317d4fba8b9Smrg font->descent = descent; 3318d4fba8b9Smrg TRACE(("...updated height %d vs %d (ascent %d, descent %d)\n", 3319d4fba8b9Smrg height, ascent + descent, ascent, descent)); 3320d522f475Smrg } 3321d522f475Smrg if (is_double_width_font_xft(screen->display, font)) { 3322d4fba8b9Smrg TRACE(("...reduce width from %d to %d\n", width, width >> 1)); 3323d522f475Smrg width >>= 1; 3324d522f475Smrg } 3325190d7dceSmrg if (tag == NULL) { 33260bd37d32Smrg SetFontWidth(screen, win, width); 33270bd37d32Smrg SetFontHeight(screen, win, height); 3328d522f475Smrg win->f_ascent = ascent; 3329d522f475Smrg win->f_descent = descent; 3330d522f475Smrg TRACE(("setRenderFontsize result %dx%d (%d+%d)\n", 3331d522f475Smrg width, height, ascent, descent)); 3332d522f475Smrg } else if (win->f_width < width || 3333d522f475Smrg win->f_height < height || 3334d522f475Smrg win->f_ascent < ascent || 3335d522f475Smrg win->f_descent < descent) { 3336d522f475Smrg TRACE(("setRenderFontsize %s changed %dx%d (%d+%d) to %dx%d (%d+%d)\n", 3337d522f475Smrg tag, 3338d522f475Smrg win->f_width, win->f_height, win->f_ascent, win->f_descent, 3339d522f475Smrg width, height, ascent, descent)); 3340d522f475Smrg 33410bd37d32Smrg SetFontWidth(screen, win, width); 33420bd37d32Smrg SetFontHeight(screen, win, height); 3343d522f475Smrg win->f_ascent = ascent; 3344d522f475Smrg win->f_descent = descent; 3345d522f475Smrg } else { 3346d522f475Smrg TRACE(("setRenderFontsize %s unchanged\n", tag)); 3347d522f475Smrg } 3348d4fba8b9Smrg#if OPT_BOX_CHARS 3349190d7dceSmrg if (!screen->broken_box_chars && (tag == NULL)) { 3350d1603babSmrg linedrawing_gaps(xw, data); 3351d4fba8b9Smrg } 3352d4fba8b9Smrg#endif 3353d522f475Smrg } 3354d522f475Smrg} 3355d522f475Smrg#endif 3356d522f475Smrg 335720d2c4d2Smrgstatic void 3358d4fba8b9SmrgcheckFontInfo(int value, const char *tag, int failed) 335920d2c4d2Smrg{ 3360d4fba8b9Smrg if (value == 0 || failed) { 3361d4fba8b9Smrg if (value == 0) { 3362d4fba8b9Smrg xtermWarning("Selected font has no non-zero %s for ISO-8859-1 encoding\n", tag); 3363980988aeSmrg exit(ERROR_MISC); 3364d4fba8b9Smrg } else { 3365d4fba8b9Smrg xtermWarning("Selected font has no valid %s for ISO-8859-1 encoding\n", tag); 3366d4fba8b9Smrg } 336720d2c4d2Smrg } 336820d2c4d2Smrg} 336920d2c4d2Smrg 337020d2c4d2Smrg#if OPT_RENDERFONT 337120d2c4d2Smrgvoid 33729a64e1c5SmrgxtermCloseXft(TScreen *screen, XTermXftFonts *pub) 337320d2c4d2Smrg{ 3374d1603babSmrg if (XftFp(pub) != NULL) { 3375d1603babSmrg int n; 3376d4fba8b9Smrg 3377d4fba8b9Smrg if (pub->pattern) { 3378d4fba8b9Smrg XftPatternDestroy(pub->pattern); 3379d1603babSmrg pub->pattern = NULL; 3380d4fba8b9Smrg } 3381d4fba8b9Smrg if (pub->fontset) { 3382d4fba8b9Smrg XftFontSetDestroy(pub->fontset); 3383d1603babSmrg pub->fontset = NULL; 3384d4fba8b9Smrg } 3385d4fba8b9Smrg 3386d1603babSmrg for (n = 0; n <= pub->fs_size; ++n) { 3387d1603babSmrg if (XftFpN(pub, n) != NULL) { 3388d1603babSmrg closeCachedXft(screen, XftFpN(pub, n)); 3389d1603babSmrg XftFpN(pub, n) = NULL; 3390d1603babSmrg XftIsN(pub, n) = xcEmpty; 3391d4fba8b9Smrg } 3392d4fba8b9Smrg } 3393d1603babSmrg FreeAndNull(pub->font_map.per_font); 3394d1603babSmrg memset(pub, 0, sizeof(*pub)); 339520d2c4d2Smrg } 339620d2c4d2Smrg} 339720d2c4d2Smrg 339820d2c4d2Smrg/* 3399d4fba8b9Smrg * Get the faceName/faceNameDoublesize resource setting. 340020d2c4d2Smrg */ 3401492d43a5SmrgString 3402d4fba8b9SmrggetFaceName(XtermWidget xw, Bool wideName) 340320d2c4d2Smrg{ 340420d2c4d2Smrg#if OPT_RENDERWIDE 3405492d43a5Smrg String result = (wideName 3406dfb07bc7Smrg ? FirstItemOf(xw->work.fonts.xft.list_w) 3407dfb07bc7Smrg : CurrentXftFont(xw)); 340820d2c4d2Smrg#else 3409dfb07bc7Smrg String result = CurrentXftFont(xw); 3410d4fba8b9Smrg (void) wideName; 341120d2c4d2Smrg#endif 341220d2c4d2Smrg return x_nonempty(result); 341320d2c4d2Smrg} 341420d2c4d2Smrg 341520d2c4d2Smrg/* 341620d2c4d2Smrg * If we change the faceName, we'll have to re-acquire all of the fonts that 341720d2c4d2Smrg * are derived from it. 341820d2c4d2Smrg */ 341920d2c4d2Smrgvoid 342020d2c4d2SmrgsetFaceName(XtermWidget xw, const char *value) 342120d2c4d2Smrg{ 342220d2c4d2Smrg TScreen *screen = TScreenOf(xw); 3423190d7dceSmrg Boolean changed = (Boolean) ((CurrentXftFont(xw) == NULL) 3424dfb07bc7Smrg || strcmp(CurrentXftFont(xw), value)); 342520d2c4d2Smrg 34260bd37d32Smrg if (changed) { 3427037a25ddSmrg int n; 3428037a25ddSmrg 3429dfb07bc7Smrg CurrentXftFont(xw) = x_strdup(value); 34300bd37d32Smrg for (n = 0; n < NMENUFONTS; ++n) { 3431dfb07bc7Smrg int e; 34320bd37d32Smrg xw->misc.face_size[n] = -1.0; 3433dfb07bc7Smrg for (e = 0; e < fMAX; ++e) { 3434dfb07bc7Smrg xtermCloseXft(screen, getMyXftFont(xw, e, n)); 3435dfb07bc7Smrg } 34360bd37d32Smrg } 343720d2c4d2Smrg } 343820d2c4d2Smrg} 343920d2c4d2Smrg#endif 344020d2c4d2Smrg 3441d522f475Smrg/* 3442d522f475Smrg * Compute useful values for the font/window sizes 3443d522f475Smrg */ 3444d522f475Smrgvoid 3445d522f475SmrgxtermComputeFontInfo(XtermWidget xw, 34469a64e1c5Smrg VTwin *win, 34479a64e1c5Smrg XFontStruct *font, 3448d522f475Smrg int sbwidth) 3449d522f475Smrg{ 3450956cc18dSsnj TScreen *screen = TScreenOf(xw); 3451d522f475Smrg 3452d522f475Smrg int i, j, width, height; 3453492d43a5Smrg#if OPT_RENDERFONT 3454492d43a5Smrg int fontnum = screen->menu_font_number; 3455492d43a5Smrg#endif 3456d4fba8b9Smrg int failed = 0; 3457d522f475Smrg 3458d522f475Smrg#if OPT_RENDERFONT 3459d522f475Smrg /* 3460d522f475Smrg * xterm contains a lot of references to fonts, assuming they are fixed 3461d522f475Smrg * size. This chunk of code overrides the actual font-selection (see 3462d522f475Smrg * drawXtermText()), if the user has selected render-font. All of the 3463d522f475Smrg * font-loading for fixed-fonts still goes on whether or not this chunk 3464d522f475Smrg * overrides it. 3465d522f475Smrg */ 3466492d43a5Smrg if (UsingRenderFont(xw) && fontnum >= 0) { 3467492d43a5Smrg String face_name = getFaceName(xw, False); 3468d1603babSmrg XTermXftFonts *norm = &(screen->renderFontNorm[fontnum]); 3469d1603babSmrg XTermXftFonts *bold = &(screen->renderFontBold[fontnum]); 3470d1603babSmrg XTermXftFonts *ital = &(screen->renderFontItal[fontnum]); 3471d1603babSmrg XTermXftFonts *btal = &(screen->renderFontBtal[fontnum]); 3472d522f475Smrg#if OPT_RENDERWIDE 3473d1603babSmrg XTermXftFonts *wnorm = &(screen->renderWideNorm[fontnum]); 3474d1603babSmrg XTermXftFonts *wbold = &(screen->renderWideBold[fontnum]); 3475d1603babSmrg XTermXftFonts *wital = &(screen->renderWideItal[fontnum]); 3476d1603babSmrg XTermXftFonts *wbtal = &(screen->renderWideBtal[fontnum]); 3477d522f475Smrg#endif 3478d522f475Smrg 3479190d7dceSmrg if (XftFp(norm) == NULL && !IsEmpty(face_name)) { 3480d1603babSmrg Work *work = &(xw->work); 3481d522f475Smrg XftPattern *pat; 34820bd37d32Smrg double face_size; 3483d522f475Smrg 34840bd37d32Smrg TRACE(("xtermComputeFontInfo font %d: norm(face %s, size %.1f)\n", 3485492d43a5Smrg fontnum, face_name, 3486d522f475Smrg xw->misc.face_size[fontnum])); 3487d522f475Smrg 3488d1603babSmrg TRACE(("Using Xft %d\n", XftGetVersion())); 3489d4fba8b9Smrg TRACE(("Using FontConfig %d\n", FC_VERSION)); 3490d4fba8b9Smrg 3491d1603babSmrg if (work->xft_defaults == NULL) { 3492d1603babSmrg FcInit(); 3493d1603babSmrg work->xft_defaults = FcPatternCreate(); 3494d1603babSmrg XftDefaultSubstitute(screen->display, 3495d1603babSmrg XScreenNumberOfScreen(XtScreen(xw)), 3496d1603babSmrg work->xft_defaults); 3497d1603babSmrg if (screen->xft_max_glyph_memory > 0) { 3498d1603babSmrg FcPatternAddInteger(work->xft_defaults, 3499d1603babSmrg XFT_MAX_GLYPH_MEMORY, 3500d1603babSmrg screen->xft_max_glyph_memory); 3501d1603babSmrg } 3502d1603babSmrg if (screen->xft_max_unref_fonts > 0) { 3503d1603babSmrg FcPatternAddInteger(work->xft_defaults, 3504d1603babSmrg XFT_MAX_UNREF_FONTS, 3505d1603babSmrg screen->xft_max_unref_fonts); 3506d1603babSmrg } 3507d1603babSmrg#ifdef XFT_TRACK_MEM_USAGE 3508d1603babSmrg FcPatternAddBool(work->xft_defaults, 3509d1603babSmrg XFT_TRACK_MEM_USAGE, 3510d1603babSmrg screen->xft_track_mem_usage); 3511d1603babSmrg#endif 3512d1603babSmrg XftDefaultSet(screen->display, work->xft_defaults); 3513d1603babSmrg } 3514d1603babSmrg 35150bd37d32Smrg fillInFaceSize(xw, fontnum); 3516d4fba8b9Smrg face_size = (double) xw->misc.face_size[fontnum]; 3517d522f475Smrg 3518d522f475Smrg /* 3519d522f475Smrg * By observation (there is no documentation), XftPatternBuild is 3520d522f475Smrg * cumulative. Build the bold- and italic-patterns on top of the 3521d522f475Smrg * normal pattern. 3522d522f475Smrg */ 3523d4fba8b9Smrg#ifdef FC_COLOR 3524d1603babSmrg#if USE_FC_COLOR 3525d1603babSmrg#define NormXftPattern \ 3526d1603babSmrg XFT_FAMILY, XftTypeString, "mono", \ 3527d1603babSmrg FC_OUTLINE, XftTypeBool, FcTrue, \ 3528d1603babSmrg XFT_SIZE, XftTypeDouble, face_size 3529d1603babSmrg#else 3530d522f475Smrg#define NormXftPattern \ 3531d4fba8b9Smrg XFT_FAMILY, XftTypeString, "mono", \ 3532d4fba8b9Smrg FC_COLOR, XftTypeBool, FcFalse, \ 3533d4fba8b9Smrg FC_OUTLINE, XftTypeBool, FcTrue, \ 3534d4fba8b9Smrg XFT_SIZE, XftTypeDouble, face_size 3535d1603babSmrg#endif 3536d4fba8b9Smrg#else 3537d4fba8b9Smrg#define NormXftPattern \ 3538d4fba8b9Smrg XFT_FAMILY, XftTypeString, "mono", \ 3539d4fba8b9Smrg XFT_SIZE, XftTypeDouble, face_size 3540d4fba8b9Smrg#endif 3541d522f475Smrg 3542d522f475Smrg#define BoldXftPattern(norm) \ 3543d4fba8b9Smrg XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \ 3544d1603babSmrg XFT_CHAR_WIDTH, XftTypeInteger, XftFp(norm)->max_advance_width 3545d522f475Smrg 3546d522f475Smrg#define ItalXftPattern(norm) \ 3547d4fba8b9Smrg XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \ 3548d1603babSmrg XFT_CHAR_WIDTH, XftTypeInteger, XftFp(norm)->max_advance_width 3549d4fba8b9Smrg 3550d4fba8b9Smrg#define BtalXftPattern(norm) \ 3551d4fba8b9Smrg XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, \ 3552d4fba8b9Smrg XFT_SLANT, XftTypeInteger, XFT_SLANT_ITALIC, \ 3553d1603babSmrg XFT_CHAR_WIDTH, XftTypeInteger, XftFp(norm)->max_advance_width 3554d522f475Smrg 35559a64e1c5Smrg#if OPT_WIDE_ATTRS 35569a64e1c5Smrg#define HAVE_ITALICS 1 3557190d7dceSmrg#define FIND_ITALICS ((pat = XftNameParse(face_name)) != NULL) 35589a64e1c5Smrg#elif OPT_ISO_COLORS 35599a64e1c5Smrg#define HAVE_ITALICS 1 35609a64e1c5Smrg#define FIND_ITALICS (screen->italicULMode && (pat = XftNameParse(face_name)) != 0) 35619a64e1c5Smrg#else 35629a64e1c5Smrg#define HAVE_ITALICS 0 35639a64e1c5Smrg#endif 35649a64e1c5Smrg 3565d4fba8b9Smrg#if OPT_DEC_CHRSET 3566d4fba8b9Smrg freeall_DoubleFT(xw); 3567d4fba8b9Smrg#endif 3568190d7dceSmrg if ((pat = XftNameParse(face_name)) != NULL) { 3569d1603babSmrg#define OPEN_XFT(data, tag) xtermOpenXft(xw, data, 0, face_name, data->pattern, tag) 3570d1603babSmrg norm->pattern = XftPatternDuplicate(pat); 3571d1603babSmrg XftPatternBuild(norm->pattern, 3572d522f475Smrg NormXftPattern, 3573d522f475Smrg (void *) 0); 3574d4fba8b9Smrg OPEN_XFT(norm, "normal"); 3575d522f475Smrg 3576190d7dceSmrg if (XftFp(norm) != NULL) { 3577d1603babSmrg bold->pattern = XftPatternDuplicate(pat); 3578d1603babSmrg XftPatternBuild(bold->pattern, 3579d4fba8b9Smrg NormXftPattern, 3580d522f475Smrg BoldXftPattern(norm), 3581d522f475Smrg (void *) 0); 3582d4fba8b9Smrg OPEN_XFT(bold, "bold"); 3583d522f475Smrg 35849a64e1c5Smrg#if HAVE_ITALICS 35859a64e1c5Smrg if (FIND_ITALICS) { 3586d1603babSmrg ital->pattern = XftPatternDuplicate(pat); 3587d1603babSmrg XftPatternBuild(ital->pattern, 3588d522f475Smrg NormXftPattern, 3589d522f475Smrg ItalXftPattern(norm), 3590d522f475Smrg (void *) 0); 3591d4fba8b9Smrg OPEN_XFT(ital, "italic"); 3592d1603babSmrg btal->pattern = XftPatternDuplicate(pat); 3593d1603babSmrg XftPatternBuild(btal->pattern, 3594d4fba8b9Smrg NormXftPattern, 3595d4fba8b9Smrg BtalXftPattern(norm), 3596d4fba8b9Smrg (void *) 0); 3597d4fba8b9Smrg OPEN_XFT(btal, "bold-italic"); 3598d522f475Smrg } 35999a64e1c5Smrg#endif 3600d522f475Smrg 3601d522f475Smrg /* 3602d522f475Smrg * FIXME: just assume that the corresponding font has no 3603d522f475Smrg * graphics characters. 3604d522f475Smrg */ 3605d522f475Smrg if (screen->fnt_boxes) { 3606d4fba8b9Smrg screen->fnt_boxes = 0; 3607d1603babSmrg TRACE(("Xft opened - will not use internal line-drawing characters\n")); 3608d522f475Smrg } 3609d522f475Smrg } 3610d522f475Smrg 3611d1603babSmrg CACHE_XFT(norm); 3612d4fba8b9Smrg 3613d1603babSmrg CACHE_XFT(bold); 3614190d7dceSmrg if (XftFp(norm) != NULL && !XftFp(bold)) { 3615d4fba8b9Smrg noUsableXft(xw, "bold"); 3616d1603babSmrg XftPatternDestroy(bold->pattern); 3617d1603babSmrg bold->pattern = XftPatternDuplicate(pat); 3618d1603babSmrg XftPatternBuild(bold->pattern, 3619d4fba8b9Smrg NormXftPattern, 3620d4fba8b9Smrg (void *) 0); 3621d4fba8b9Smrg OPEN_XFT(bold, "bold"); 3622d4fba8b9Smrg failed = 0; 3623d1603babSmrg CACHE_XFT(bold); 3624d4fba8b9Smrg } 3625d4fba8b9Smrg#if HAVE_ITALICS 3626d1603babSmrg CACHE_XFT(ital); 3627190d7dceSmrg if (XftFp(norm) != NULL && !XftFp(ital)) { 3628d4fba8b9Smrg noUsableXft(xw, "italic"); 3629d1603babSmrg XftPatternDestroy(ital->pattern); 3630d1603babSmrg ital->pattern = XftPatternDuplicate(pat); 3631d1603babSmrg XftPatternBuild(ital->pattern, 3632d4fba8b9Smrg NormXftPattern, 3633d4fba8b9Smrg (void *) 0); 3634d4fba8b9Smrg OPEN_XFT(ital, "italics"); 3635d4fba8b9Smrg failed = 0; 3636d1603babSmrg CACHE_XFT(ital); 3637d4fba8b9Smrg } 3638d1603babSmrg CACHE_XFT(btal); 3639190d7dceSmrg if (XftFp(norm) != NULL && !XftFp(btal)) { 3640d4fba8b9Smrg noUsableXft(xw, "bold italic"); 3641d1603babSmrg XftPatternDestroy(btal->pattern); 3642d1603babSmrg btal->pattern = XftPatternDuplicate(pat); 3643d1603babSmrg XftPatternBuild(btal->pattern, 3644d4fba8b9Smrg NormXftPattern, 3645d4fba8b9Smrg (void *) 0); 3646d4fba8b9Smrg OPEN_XFT(btal, "bold-italics"); 3647d4fba8b9Smrg failed = 0; 3648d1603babSmrg CACHE_XFT(btal); 3649d4fba8b9Smrg } 3650d4fba8b9Smrg#endif 3651d522f475Smrg XftPatternDestroy(pat); 3652d4fba8b9Smrg } else { 3653d4fba8b9Smrg failed = 1; 3654d522f475Smrg } 3655d522f475Smrg 3656d522f475Smrg /* 3657d4fba8b9Smrg * See xtermXftDrawString(). A separate double-width font is nice 3658d4fba8b9Smrg * to have, but not essential. 3659d522f475Smrg */ 3660d522f475Smrg#if OPT_RENDERWIDE 3661190d7dceSmrg if (XftFp(norm) != NULL && screen->wide_chars) { 3662d1603babSmrg int char_width = XftFp(norm)->max_advance_width * 2; 3663dfb07bc7Smrg double aspect = ((FirstItemOf(xw->work.fonts.xft.list_w) 3664d1603babSmrg || screen->renderFontNorm[fontnum].font_info.mixed) 3665956cc18dSsnj ? 1.0 3666956cc18dSsnj : 2.0); 3667d522f475Smrg 366820d2c4d2Smrg face_name = getFaceName(xw, True); 3669d522f475Smrg TRACE(("xtermComputeFontInfo wide(face %s, char_width %d)\n", 367020d2c4d2Smrg NonNull(face_name), 3671d522f475Smrg char_width)); 3672d522f475Smrg 3673d522f475Smrg#define WideXftPattern \ 3674d4fba8b9Smrg XFT_FAMILY, XftTypeString, "mono", \ 3675d4fba8b9Smrg XFT_SIZE, XftTypeDouble, face_size, \ 3676d4fba8b9Smrg XFT_SPACING, XftTypeInteger, XFT_MONO, \ 3677d4fba8b9Smrg XFT_CHAR_WIDTH, XftTypeInteger, char_width, \ 3678d4fba8b9Smrg FC_ASPECT, XftTypeDouble, aspect 3679d4fba8b9Smrg 3680d4fba8b9Smrg if (!IsEmpty(face_name) && (pat = XftNameParse(face_name)) 3681190d7dceSmrg != NULL) { 3682d1603babSmrg wnorm->pattern = XftPatternDuplicate(pat); 3683d1603babSmrg XftPatternBuild(wnorm->pattern, 3684d522f475Smrg WideXftPattern, 3685d522f475Smrg (void *) 0); 3686d4fba8b9Smrg OPEN_XFT(wnorm, "wide"); 3687d522f475Smrg 3688190d7dceSmrg if (XftFp(wnorm) != NULL) { 3689d1603babSmrg wbold->pattern = XftPatternDuplicate(pat); 3690d1603babSmrg XftPatternBuild(wbold->pattern, 3691d522f475Smrg WideXftPattern, 3692d522f475Smrg BoldXftPattern(wnorm), 3693d522f475Smrg (void *) 0); 3694d4fba8b9Smrg OPEN_XFT(wbold, "wide-bold"); 3695d522f475Smrg 36969a64e1c5Smrg#if HAVE_ITALICS 36979a64e1c5Smrg if (FIND_ITALICS) { 3698d1603babSmrg wital->pattern = XftPatternDuplicate(pat); 3699d1603babSmrg XftPatternBuild(wital->pattern, 3700d522f475Smrg WideXftPattern, 3701d522f475Smrg ItalXftPattern(wnorm), 3702d522f475Smrg (void *) 0); 3703d4fba8b9Smrg OPEN_XFT(wital, "wide-italic"); 3704d4fba8b9Smrg } 3705d1603babSmrg CACHE_XFT(wbtal); 3706d1603babSmrg if (!XftFp(wbtal)) { 3707d4fba8b9Smrg noUsableXft(xw, "wide bold"); 3708d1603babSmrg XftPatternDestroy(wbtal->pattern); 3709d1603babSmrg wbtal->pattern = XftPatternDuplicate(pat); 3710d1603babSmrg XftPatternBuild(wbtal->pattern, 3711d4fba8b9Smrg WideXftPattern, 3712d4fba8b9Smrg (void *) 0); 3713d4fba8b9Smrg OPEN_XFT(wbtal, "wide-bold-italics"); 3714d4fba8b9Smrg failed = 0; 3715d1603babSmrg CACHE_XFT(wbtal); 3716d522f475Smrg } 3717d522f475Smrg#endif 3718d522f475Smrg } 3719d4fba8b9Smrg 3720d1603babSmrg CACHE_XFT(wnorm); 3721d4fba8b9Smrg 3722d1603babSmrg CACHE_XFT(wbold); 3723190d7dceSmrg if (XftFp(wnorm) != NULL && !XftFp(wbold)) { 3724d4fba8b9Smrg noUsableXft(xw, "wide-bold"); 3725d1603babSmrg XftPatternDestroy(wbold->pattern); 3726d1603babSmrg wbold->pattern = XftPatternDuplicate(pat); 3727d1603babSmrg XftPatternBuild(bold->pattern, 3728d4fba8b9Smrg WideXftPattern, 3729d4fba8b9Smrg (void *) 0); 3730d4fba8b9Smrg OPEN_XFT(wbold, "wide-bold"); 3731d4fba8b9Smrg failed = 0; 3732d1603babSmrg CACHE_XFT(bold); 3733d4fba8b9Smrg } 3734d4fba8b9Smrg 3735d1603babSmrg CACHE_XFT(wital); 3736190d7dceSmrg if (XftFp(wnorm) != NULL && !XftFp(wital)) { 3737d4fba8b9Smrg noUsableXft(xw, "wide-italic"); 3738d1603babSmrg XftPatternDestroy(wital->pattern); 3739d1603babSmrg wital->pattern = XftPatternDuplicate(pat); 3740d1603babSmrg XftPatternBuild(wital->pattern, 3741d4fba8b9Smrg WideXftPattern, 3742d4fba8b9Smrg (void *) 0); 3743d4fba8b9Smrg OPEN_XFT(wital, "wide-italic"); 3744d4fba8b9Smrg failed = 0; 3745d1603babSmrg CACHE_XFT(wital); 3746d4fba8b9Smrg } 3747d4fba8b9Smrg 3748d522f475Smrg XftPatternDestroy(pat); 3749d522f475Smrg } 3750d4fba8b9Smrg#undef OPEN_XFT 3751d522f475Smrg } 3752d522f475Smrg#endif /* OPT_RENDERWIDE */ 3753d522f475Smrg } 3754190d7dceSmrg if (XftFp(norm) == NULL) { 37552eaa94a1Schristos TRACE(("...no TrueType font found for number %d, disable menu entry\n", fontnum)); 37560bd37d32Smrg xw->work.render_font = False; 3757d522f475Smrg update_font_renderfont(); 3758d522f475Smrg /* now we will fall through into the bitmap fonts */ 3759d522f475Smrg } else { 3760d4fba8b9Smrg setBrokenBoxChars(xw, False); 3761d1603babSmrg setRenderFontsize(xw, win, norm, NULL); 3762d1603babSmrg setRenderFontsize(xw, win, bold, "bold"); 3763d1603babSmrg setRenderFontsize(xw, win, ital, "ital"); 3764d1603babSmrg setRenderFontsize(xw, win, btal, "btal"); 376520d2c4d2Smrg#if OPT_BOX_CHARS 376620d2c4d2Smrg setupPackedFonts(xw); 376720d2c4d2Smrg 376820d2c4d2Smrg if (screen->force_packed) { 376920d2c4d2Smrg XTermXftFonts *use = &(screen->renderFontNorm[fontnum]); 3770d1603babSmrg SetFontHeight(screen, win, XftFp(use)->ascent + XftFp(use)->descent); 3771d1603babSmrg SetFontWidth(screen, win, use->font_info.min_width); 377220d2c4d2Smrg TRACE(("...packed TrueType font %dx%d vs %d\n", 377320d2c4d2Smrg win->f_height, 377420d2c4d2Smrg win->f_width, 3775d1603babSmrg use->font_info.max_width)); 377620d2c4d2Smrg } 377720d2c4d2Smrg#endif 377820d2c4d2Smrg DUMP_XFT(xw, &(screen->renderFontNorm[fontnum])); 3779d522f475Smrg } 3780d522f475Smrg } 3781d522f475Smrg /* 3782d522f475Smrg * Are we handling a bitmap font? 3783d522f475Smrg */ 3784492d43a5Smrg else 3785d522f475Smrg#endif /* OPT_RENDERFONT */ 3786d522f475Smrg { 378720d2c4d2Smrg if (is_double_width_font(font) && !(screen->fnt_prop)) { 37880bd37d32Smrg SetFontWidth(screen, win, font->min_bounds.width); 3789d522f475Smrg } else { 37900bd37d32Smrg SetFontWidth(screen, win, font->max_bounds.width); 3791d522f475Smrg } 37920bd37d32Smrg SetFontHeight(screen, win, font->ascent + font->descent); 3793d522f475Smrg win->f_ascent = font->ascent; 3794d522f475Smrg win->f_descent = font->descent; 3795d522f475Smrg } 3796d522f475Smrg i = 2 * screen->border + sbwidth; 3797d522f475Smrg j = 2 * screen->border; 3798d522f475Smrg width = MaxCols(screen) * win->f_width + i; 3799d522f475Smrg height = MaxRows(screen) * win->f_height + j; 3800956cc18dSsnj win->fullwidth = (Dimension) width; 3801956cc18dSsnj win->fullheight = (Dimension) height; 3802d522f475Smrg win->width = width - i; 3803d522f475Smrg win->height = height - j; 3804d522f475Smrg 3805d522f475Smrg TRACE(("xtermComputeFontInfo window %dx%d (full %dx%d), fontsize %dx%d (asc %d, dsc %d)\n", 3806d522f475Smrg win->height, 3807d522f475Smrg win->width, 3808d522f475Smrg win->fullheight, 3809d522f475Smrg win->fullwidth, 3810d522f475Smrg win->f_height, 3811d522f475Smrg win->f_width, 3812d522f475Smrg win->f_ascent, 3813d522f475Smrg win->f_descent)); 381420d2c4d2Smrg 3815d4fba8b9Smrg checkFontInfo(win->f_height, "height", failed); 3816d4fba8b9Smrg checkFontInfo(win->f_width, "width", failed); 3817d522f475Smrg} 3818d522f475Smrg 3819d522f475Smrg/* save this information as a side-effect for double-sized characters */ 3820d4fba8b9Smrgstatic void 38219a64e1c5SmrgxtermSaveFontInfo(TScreen *screen, XFontStruct *font) 3822d522f475Smrg{ 3823956cc18dSsnj screen->fnt_wide = (Dimension) (font->max_bounds.width); 3824956cc18dSsnj screen->fnt_high = (Dimension) (font->ascent + font->descent); 3825d522f475Smrg TRACE(("xtermSaveFontInfo %dx%d\n", screen->fnt_high, screen->fnt_wide)); 3826d522f475Smrg} 3827d522f475Smrg 3828d522f475Smrg/* 3829d522f475Smrg * After loading a new font, update the structures that use its size. 3830d522f475Smrg */ 3831d522f475Smrgvoid 3832d522f475SmrgxtermUpdateFontInfo(XtermWidget xw, Bool doresize) 3833d522f475Smrg{ 3834956cc18dSsnj TScreen *screen = TScreenOf(xw); 3835d522f475Smrg 3836d522f475Smrg int scrollbar_width; 3837d522f475Smrg VTwin *win = &(screen->fullVwin); 3838d522f475Smrg 3839d4fba8b9Smrg#if USE_DOUBLE_BUFFER 3840d4fba8b9Smrg discardRenderDraw(TScreenOf(xw)); 3841d4fba8b9Smrg#endif /* USE_DOUBLE_BUFFER */ 3842d4fba8b9Smrg 3843d522f475Smrg scrollbar_width = (xw->misc.scrollbar 3844d522f475Smrg ? (screen->scrollWidget->core.width + 3845d522f475Smrg BorderWidth(screen->scrollWidget)) 3846d522f475Smrg : 0); 3847d4fba8b9Smrg xtermComputeFontInfo(xw, win, GetNormalFont(screen, fNorm)->fs, scrollbar_width); 3848d4fba8b9Smrg xtermSaveFontInfo(screen, GetNormalFont(screen, fNorm)->fs); 3849d522f475Smrg 3850d522f475Smrg if (doresize) { 3851d522f475Smrg if (VWindow(screen)) { 3852d522f475Smrg xtermClear(xw); 3853d522f475Smrg } 3854d4fba8b9Smrg TRACE(("xtermUpdateFontInfo " TRACE_L "\n")); 3855d522f475Smrg DoResizeScreen(xw); /* set to the new natural size */ 3856d522f475Smrg ResizeScrollBar(xw); 3857d522f475Smrg Redraw(); 3858d4fba8b9Smrg TRACE((TRACE_R " xtermUpdateFontInfo\n")); 3859d522f475Smrg#ifdef SCROLLBAR_RIGHT 3860d522f475Smrg updateRightScrollbar(xw); 3861d522f475Smrg#endif 3862d522f475Smrg } 3863d522f475Smrg xtermSetCursorBox(screen); 3864d522f475Smrg} 3865d522f475Smrg 3866fa3f02f3Smrg#if OPT_BOX_CHARS || OPT_REPORT_FONTS 3867d522f475Smrg 3868d522f475Smrg/* 3869d522f475Smrg * Returns true if the given character is missing from the specified font. 3870d522f475Smrg */ 3871d522f475SmrgBool 3872956cc18dSsnjxtermMissingChar(unsigned ch, XTermFonts * font) 3873d522f475Smrg{ 3874956cc18dSsnj Bool result = False; 3875956cc18dSsnj XFontStruct *fs = font->fs; 3876190d7dceSmrg XCharStruct *pc = NULL; 3877d522f475Smrg 3878d4fba8b9Smrg if (fs == NULL) { 3879d4fba8b9Smrg result = True; 3880d4fba8b9Smrg } else if (fs->max_byte1 == 0) { 3881d522f475Smrg#if OPT_WIDE_CHARS 3882fa3f02f3Smrg if (ch < 256) 3883956cc18dSsnj#endif 3884fa3f02f3Smrg { 3885190d7dceSmrg CI_GET_CHAR_INFO_1D(fs, ch, pc); 3886fa3f02f3Smrg } 3887956cc18dSsnj } 3888d522f475Smrg#if OPT_WIDE_CHARS 3889956cc18dSsnj else { 3890fa3f02f3Smrg unsigned row = (ch >> 8); 3891fa3f02f3Smrg unsigned col = (ch & 0xff); 3892fa3f02f3Smrg CI_GET_CHAR_INFO_2D(fs, row, col, pc); 3893956cc18dSsnj } 3894d522f475Smrg#endif 3895d522f475Smrg 3896190d7dceSmrg if (pc == NULL || CI_NONEXISTCHAR(pc)) { 3897c48a5815Smrg TRACE2(("xtermMissingChar %#04x (!exists)\n", ch)); 3898956cc18dSsnj result = True; 3899d522f475Smrg } 3900d1603babSmrg if (ch < MaxUChar) { 3901956cc18dSsnj font->known_missing[ch] = (Char) (result ? 2 : 1); 3902d522f475Smrg } 3903956cc18dSsnj return result; 3904d522f475Smrg} 3905fa3f02f3Smrg#endif 3906d522f475Smrg 3907980988aeSmrg#if OPT_BOX_CHARS || OPT_WIDE_CHARS 3908d522f475Smrg/* 3909d522f475Smrg * The grid is arbitrary, enough resolution that nothing's lost in 3910d522f475Smrg * initialization. 3911d522f475Smrg */ 3912d522f475Smrg#define BOX_HIGH 60 3913d522f475Smrg#define BOX_WIDE 60 3914d522f475Smrg 3915d522f475Smrg#define MID_HIGH (BOX_HIGH/2) 3916d522f475Smrg#define MID_WIDE (BOX_WIDE/2) 3917d522f475Smrg 3918d522f475Smrg#define CHR_WIDE ((9*BOX_WIDE)/10) 3919d522f475Smrg#define CHR_HIGH ((9*BOX_HIGH)/10) 3920d522f475Smrg 3921d522f475Smrg/* 3922d522f475Smrg * ...since we'll scale the values anyway. 3923d522f475Smrg */ 3924d4fba8b9Smrg#define Scale_XY(n,d,f) ((int)(n) * ((int)(f))) / (d) 3925d4fba8b9Smrg#define SCALED_X(n) Scale_XY(n, BOX_WIDE, font_width) 3926d4fba8b9Smrg#define SCALED_Y(n) Scale_XY(n, BOX_HIGH, font_height) 3927e39b573cSmrg#define SCALE_X(n) n = SCALED_X(n) 3928e39b573cSmrg#define SCALE_Y(n) n = SCALED_Y(n) 3929d522f475Smrg 3930d522f475Smrg#define SEG(x0,y0,x1,y1) x0,y0, x1,y1 3931d522f475Smrg 3932d522f475Smrg/* 3933d522f475Smrg * Draw the given graphic character, if it is simple enough (i.e., a 3934d522f475Smrg * line-drawing character). 3935d522f475Smrg */ 3936d522f475Smrgvoid 3937d4fba8b9SmrgxtermDrawBoxChar(XTermDraw * params, 3938d522f475Smrg unsigned ch, 3939d522f475Smrg GC gc, 3940d522f475Smrg int x, 3941d522f475Smrg int y, 3942d4fba8b9Smrg int cells, 3943d4fba8b9Smrg Bool xftords) 3944d522f475Smrg{ 3945d4fba8b9Smrg TScreen *screen = TScreenOf(params->xw); 3946d522f475Smrg /* *INDENT-OFF* */ 3947d522f475Smrg static const short glyph_ht[] = { 3948d522f475Smrg SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,5*MID_HIGH/6), /* H */ 3949d522f475Smrg SEG(6*BOX_WIDE/10, 0, 6*BOX_WIDE/10,5*MID_HIGH/6), 3950d522f475Smrg SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*BOX_WIDE/10,5*MID_HIGH/12), 3951d522f475Smrg SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 3952d522f475Smrg SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 3953d522f475Smrg -1 3954d522f475Smrg }, glyph_ff[] = { 3955d522f475Smrg SEG(1*BOX_WIDE/10, 0, 6*BOX_WIDE/10, 0), /* F */ 3956d522f475Smrg SEG(1*BOX_WIDE/10,5*MID_HIGH/12,6*CHR_WIDE/12,5*MID_HIGH/12), 3957d522f475Smrg SEG(1*BOX_WIDE/10, 0, 0*BOX_WIDE/3, 5*MID_HIGH/6), 3958d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 3959d522f475Smrg SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 3960d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 3961d522f475Smrg -1 3962d522f475Smrg }, glyph_lf[] = { 3963d522f475Smrg SEG(1*BOX_WIDE/10, 0, 1*BOX_WIDE/10,9*MID_HIGH/12), /* L */ 3964d522f475Smrg SEG(1*BOX_WIDE/10,9*MID_HIGH/12,6*BOX_WIDE/10,9*MID_HIGH/12), 3965d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, CHR_WIDE, MID_HIGH), /* F */ 3966d522f475Smrg SEG(1*BOX_WIDE/3, 8*MID_HIGH/6,10*CHR_WIDE/12,8*MID_HIGH/6), 3967d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), 3968d522f475Smrg -1 3969d522f475Smrg }, glyph_nl[] = { 3970d522f475Smrg SEG(1*BOX_WIDE/10,5*MID_HIGH/6, 1*BOX_WIDE/10, 0), /* N */ 3971d522f475Smrg SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/6, 5*MID_HIGH/6), 3972d522f475Smrg SEG(5*BOX_WIDE/6, 5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 3973d522f475Smrg SEG(1*BOX_WIDE/3, MID_HIGH, 1*BOX_WIDE/3, CHR_HIGH), /* L */ 3974d522f475Smrg SEG(1*BOX_WIDE/3, CHR_HIGH, CHR_WIDE, CHR_HIGH), 3975d522f475Smrg -1 3976d522f475Smrg }, glyph_vt[] = { 3977d522f475Smrg SEG(1*BOX_WIDE/10, 0, 5*BOX_WIDE/12,5*MID_HIGH/6), /* V */ 3978d522f475Smrg SEG(5*BOX_WIDE/12,5*MID_HIGH/6, 5*BOX_WIDE/6, 0), 3979d522f475Smrg SEG(2*BOX_WIDE/10, MID_HIGH, CHR_WIDE, MID_HIGH), /* T */ 3980d522f475Smrg SEG(6*BOX_WIDE/10, MID_HIGH, 6*BOX_WIDE/10, CHR_HIGH), 3981d522f475Smrg -1 3982d522f475Smrg }, plus_or_minus[] = 3983d522f475Smrg { 3984d522f475Smrg SEG( 0, 5*BOX_HIGH/6, CHR_WIDE, 5*BOX_HIGH/6), 3985d522f475Smrg SEG( MID_WIDE, 2*BOX_HIGH/6, MID_WIDE, 4*BOX_HIGH/6), 3986d522f475Smrg SEG( 0, 3*BOX_HIGH/6, CHR_WIDE, 3*BOX_HIGH/6), 3987d522f475Smrg -1 3988d522f475Smrg }, lower_right_corner[] = 3989d522f475Smrg { 3990d522f475Smrg SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 3991d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, 0), 3992d522f475Smrg -1 3993d522f475Smrg }, upper_right_corner[] = 3994d522f475Smrg { 3995d522f475Smrg SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 3996d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 3997d522f475Smrg -1 3998d522f475Smrg }, upper_left_corner[] = 3999d522f475Smrg { 4000d522f475Smrg SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 4001d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 4002d522f475Smrg -1 4003d522f475Smrg }, lower_left_corner[] = 4004d522f475Smrg { 4005d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 4006d522f475Smrg SEG( MID_WIDE, MID_WIDE, BOX_WIDE, MID_HIGH), 4007d522f475Smrg -1 4008d522f475Smrg }, cross[] = 4009d522f475Smrg { 4010d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 4011d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 4012d522f475Smrg -1 4013d522f475Smrg }, scan_line_1[] = 4014d522f475Smrg { 4015d522f475Smrg SEG( 0, 0, BOX_WIDE, 0), 4016d522f475Smrg -1 4017d522f475Smrg }, scan_line_3[] = 4018d522f475Smrg { 4019d522f475Smrg SEG( 0, BOX_HIGH/4, BOX_WIDE, BOX_HIGH/4), 4020d522f475Smrg -1 4021d522f475Smrg }, scan_line_7[] = 4022d522f475Smrg { 4023d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 4024d522f475Smrg -1 4025d522f475Smrg }, scan_line_9[] = 4026d522f475Smrg { 4027d522f475Smrg SEG( 0, 3*BOX_HIGH/4, BOX_WIDE, 3*BOX_HIGH/4), 4028d522f475Smrg -1 4029d522f475Smrg }, horizontal_line[] = 4030d522f475Smrg { 4031d522f475Smrg SEG( 0, BOX_HIGH, BOX_WIDE, BOX_HIGH), 4032d522f475Smrg -1 4033d522f475Smrg }, left_tee[] = 4034d522f475Smrg { 4035d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 4036d522f475Smrg SEG( MID_WIDE, MID_HIGH, BOX_WIDE, MID_HIGH), 4037d522f475Smrg -1 4038d522f475Smrg }, right_tee[] = 4039d522f475Smrg { 4040d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 4041d522f475Smrg SEG( MID_WIDE, MID_HIGH, 0, MID_HIGH), 4042d522f475Smrg -1 4043d522f475Smrg }, bottom_tee[] = 4044d522f475Smrg { 4045d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 4046d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, MID_HIGH), 4047d522f475Smrg -1 4048d522f475Smrg }, top_tee[] = 4049d522f475Smrg { 4050d522f475Smrg SEG( 0, MID_HIGH, BOX_WIDE, MID_HIGH), 4051d522f475Smrg SEG( MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 4052d522f475Smrg -1 4053d522f475Smrg }, vertical_line[] = 4054d522f475Smrg { 4055d522f475Smrg SEG( MID_WIDE, 0, MID_WIDE, BOX_HIGH), 4056d522f475Smrg -1 4057d522f475Smrg }, less_than_or_equal[] = 4058d522f475Smrg { 4059d522f475Smrg SEG( CHR_WIDE, BOX_HIGH/3, 0, MID_HIGH), 4060d522f475Smrg SEG( CHR_WIDE, 2*BOX_HIGH/3, 0, MID_HIGH), 4061d522f475Smrg SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 4062d522f475Smrg -1 4063d522f475Smrg }, greater_than_or_equal[] = 4064d522f475Smrg { 4065d522f475Smrg SEG( 0, BOX_HIGH/3, CHR_WIDE, MID_HIGH), 4066d522f475Smrg SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, MID_HIGH), 4067d522f475Smrg SEG( 0, 3*BOX_HIGH/4, CHR_WIDE, 3*BOX_HIGH/4), 4068d522f475Smrg -1 4069d522f475Smrg }, greek_pi[] = 4070d522f475Smrg { 4071d522f475Smrg SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 4072d522f475Smrg SEG(5*CHR_WIDE/6, MID_HIGH, 5*CHR_WIDE/6, CHR_HIGH), 4073d522f475Smrg SEG(2*CHR_WIDE/6, MID_HIGH, 2*CHR_WIDE/6, CHR_HIGH), 4074d522f475Smrg -1 4075d522f475Smrg }, not_equal_to[] = 4076d522f475Smrg { 4077d522f475Smrg SEG(2*BOX_WIDE/3, 1*BOX_HIGH/3, 1*BOX_WIDE/3, CHR_HIGH), 4078d522f475Smrg SEG( 0, 2*BOX_HIGH/3, CHR_WIDE, 2*BOX_HIGH/3), 4079d522f475Smrg SEG( 0, MID_HIGH, CHR_WIDE, MID_HIGH), 4080d522f475Smrg -1 4081980988aeSmrg }, sigma_1[] = 4082980988aeSmrg { 4083980988aeSmrg SEG(BOX_WIDE, MID_HIGH, BOX_WIDE/2, MID_HIGH), 4084980988aeSmrg SEG(BOX_WIDE/2, MID_HIGH, BOX_WIDE, BOX_HIGH), 4085980988aeSmrg -1 4086980988aeSmrg }, sigma_2[] = 4087980988aeSmrg { 4088980988aeSmrg SEG(BOX_WIDE, MID_HIGH, BOX_WIDE/2, MID_HIGH), 4089980988aeSmrg SEG(BOX_WIDE/2, MID_HIGH, BOX_WIDE, 0), 4090980988aeSmrg -1 4091980988aeSmrg }, sigma_3[] = 4092980988aeSmrg { 4093980988aeSmrg SEG( 0, 0, BOX_WIDE, BOX_HIGH), 4094980988aeSmrg -1 4095980988aeSmrg }, sigma_4[] = 4096980988aeSmrg { 4097980988aeSmrg SEG( 0, BOX_HIGH, BOX_WIDE, 0), 4098980988aeSmrg -1 4099980988aeSmrg }, sigma_5[] = 4100980988aeSmrg { 4101980988aeSmrg SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 4102980988aeSmrg SEG(MID_WIDE, MID_HIGH, MID_WIDE, BOX_HIGH), 4103980988aeSmrg -1 4104980988aeSmrg }, sigma_6[] = 4105980988aeSmrg { 4106980988aeSmrg SEG( 0, MID_HIGH, MID_WIDE, MID_HIGH), 4107980988aeSmrg SEG(MID_WIDE, MID_HIGH, MID_WIDE, 0), 4108980988aeSmrg -1 4109980988aeSmrg }, sigma_7[] = 4110980988aeSmrg { 4111980988aeSmrg SEG( 0, 0, MID_WIDE, MID_HIGH), 4112980988aeSmrg SEG( 0, BOX_HIGH, MID_WIDE, MID_HIGH), 4113980988aeSmrg -1 4114d522f475Smrg }; 4115d522f475Smrg 4116d4fba8b9Smrg static const struct { 4117d4fba8b9Smrg const int mode; /* 1=y, 2=x, 3=both */ 4118d1603babSmrg const short *const data; 4119d4fba8b9Smrg } lines[] = 4120d522f475Smrg { 4121190d7dceSmrg { 0, NULL }, /* 00 (unused) */ 4122190d7dceSmrg { 0, NULL }, /* 01 diamond */ 4123190d7dceSmrg { 0, NULL }, /* 02 box */ 4124d4fba8b9Smrg { 0, glyph_ht }, /* 03 HT */ 4125d4fba8b9Smrg { 0, glyph_ff }, /* 04 FF */ 4126190d7dceSmrg { 0, NULL }, /* 05 CR */ 4127d4fba8b9Smrg { 0, glyph_lf }, /* 06 LF */ 4128190d7dceSmrg { 0, NULL }, /* 07 degrees (small circle) */ 4129d4fba8b9Smrg { 3, plus_or_minus }, /* 08 */ 4130d4fba8b9Smrg { 0, glyph_nl }, /* 09 */ 4131d4fba8b9Smrg { 0, glyph_vt }, /* 0A */ 4132d4fba8b9Smrg { 3, lower_right_corner }, /* 0B */ 4133d4fba8b9Smrg { 3, upper_right_corner }, /* 0C */ 4134d4fba8b9Smrg { 3, upper_left_corner }, /* 0D */ 4135d4fba8b9Smrg { 3, lower_left_corner }, /* 0E */ 4136d4fba8b9Smrg { 3, cross }, /* 0F */ 4137d4fba8b9Smrg { 2, scan_line_1 }, /* 10 */ 4138d4fba8b9Smrg { 2, scan_line_3 }, /* 11 */ 4139d4fba8b9Smrg { 2, scan_line_7 }, /* 12 */ 4140d4fba8b9Smrg { 2, scan_line_9 }, /* 13 */ 4141d4fba8b9Smrg { 2, horizontal_line }, /* 14 */ 4142d4fba8b9Smrg { 3, left_tee }, /* 15 */ 4143d4fba8b9Smrg { 3, right_tee }, /* 16 */ 4144d4fba8b9Smrg { 3, bottom_tee }, /* 17 */ 4145d4fba8b9Smrg { 3, top_tee }, /* 18 */ 4146d4fba8b9Smrg { 1, vertical_line }, /* 19 */ 4147d4fba8b9Smrg { 0, less_than_or_equal }, /* 1A */ 4148d4fba8b9Smrg { 0, greater_than_or_equal }, /* 1B */ 4149d4fba8b9Smrg { 0, greek_pi }, /* 1C */ 4150d4fba8b9Smrg { 0, not_equal_to }, /* 1D */ 4151190d7dceSmrg { 0, NULL }, /* 1E LB */ 4152190d7dceSmrg { 0, NULL }, /* 1F bullet */ 4153190d7dceSmrg { 0, NULL }, /* 20 space */ 4154980988aeSmrg { 3, sigma_1 }, /* PUA(0) */ 4155980988aeSmrg { 3, sigma_2 }, /* PUA(1) */ 4156980988aeSmrg { 3, sigma_3 }, /* PUA(2) */ 4157980988aeSmrg { 3, sigma_4 }, /* PUA(3) */ 4158980988aeSmrg { 3, sigma_5 }, /* PUA(4) */ 4159980988aeSmrg { 3, sigma_6 }, /* PUA(5) */ 4160980988aeSmrg { 3, sigma_7 }, /* PUA(6) */ 4161d522f475Smrg }; 4162d4fba8b9Smrg /* *INDENT-ON* */ 4163d522f475Smrg 4164d522f475Smrg GC gc2; 4165d522f475Smrg CgsEnum cgsId = (ch == 2) ? gcDots : gcLine; 4166d522f475Smrg VTwin *cgsWin = WhichVWin(screen); 4167d522f475Smrg const short *p; 4168d4fba8b9Smrg unsigned font_width = (((params->draw_flags & DOUBLEWFONT) ? 2U : 1U) 4169d4fba8b9Smrg * screen->fnt_wide); 4170d4fba8b9Smrg unsigned font_height = (((params->draw_flags & DOUBLEHFONT) ? 2U : 1U) 4171d4fba8b9Smrg * screen->fnt_high); 4172d1603babSmrg unsigned thick; 4173d522f475Smrg 4174d522f475Smrg if (cells > 1) 4175956cc18dSsnj font_width *= (unsigned) cells; 4176d522f475Smrg 4177d522f475Smrg#if OPT_WIDE_CHARS 4178d522f475Smrg /* 4179d522f475Smrg * Try to show line-drawing characters if we happen to be in UTF-8 4180d522f475Smrg * mode, but have gotten an old-style font. 4181d522f475Smrg */ 4182d522f475Smrg if (screen->utf8_mode 4183d522f475Smrg#if OPT_RENDERFONT 4184d4fba8b9Smrg && !UsingRenderFont(params->xw) 4185d522f475Smrg#endif 4186d522f475Smrg && (ch > 127) 4187980988aeSmrg && !is_UCS_SPECIAL(ch)) { 4188d4fba8b9Smrg int which = (params->attr_flags & BOLD) ? fBold : fNorm; 4189d522f475Smrg unsigned n; 4190d522f475Smrg for (n = 1; n < 32; n++) { 4191190d7dceSmrg if (xtermMissingChar(n, XTermFontsRef(screen->fnts, which))) 4192d4fba8b9Smrg continue; 4193d4fba8b9Smrg if (dec2ucs(screen, n) != ch) 4194d4fba8b9Smrg continue; 4195d4fba8b9Smrg TRACE(("...use xterm-style linedrawing U+%04X ->%d\n", ch, n)); 4196d4fba8b9Smrg ch = n; 4197d4fba8b9Smrg break; 4198d522f475Smrg } 4199d522f475Smrg } 4200d522f475Smrg#endif 4201d522f475Smrg 4202d4fba8b9Smrg#if OPT_VT52_MODE 4203d4fba8b9Smrg if (!(screen->vtXX_level)) { 4204d4fba8b9Smrg switch (ch) { 4205d4fba8b9Smrg case 6: 4206d4fba8b9Smrg ch = 7; 4207d4fba8b9Smrg break; 4208d4fba8b9Smrg default: 4209d4fba8b9Smrg ch = 256; 4210d4fba8b9Smrg break; 4211d4fba8b9Smrg } 4212d4fba8b9Smrg } 4213d4fba8b9Smrg#endif 4214d4fba8b9Smrg 4215d4fba8b9Smrg /* 4216980988aeSmrg * Line-drawing characters display using the full (scaled) cellsize, while 4217d4fba8b9Smrg * other characters should be shifted to center them vertically. 4218d4fba8b9Smrg */ 4219d4fba8b9Smrg if (!xftords) { 4220d4fba8b9Smrg if ((ch < XtNumber(lines)) && (lines[ch].mode & 3) != 0) { 4221d4fba8b9Smrg font_height = (unsigned) ((float) font_height * screen->scale_height); 4222d4fba8b9Smrg } else { 4223d4fba8b9Smrg y += ScaleShift(screen); 4224d4fba8b9Smrg } 4225d4fba8b9Smrg } 4226d4fba8b9Smrg 4227980988aeSmrg if (xtermIsDecTechnical(ch)) { 4228980988aeSmrg ch -= XTERM_PUA; 4229980988aeSmrg ch += 33; 4230980988aeSmrg } 4231980988aeSmrg 4232d4fba8b9Smrg TRACE(("DRAW_BOX(%02X) cell %dx%d at %d,%d%s\n", 4233d522f475Smrg ch, font_height, font_width, y, x, 4234d4fba8b9Smrg ((ch >= XtNumber(lines)) 4235d522f475Smrg ? "-BAD" 4236d522f475Smrg : ""))); 4237d522f475Smrg 4238d522f475Smrg if (cgsId == gcDots) { 4239d4fba8b9Smrg setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc)); 4240d4fba8b9Smrg setCgsFore(params->xw, cgsWin, cgsId, getCgsFore(params->xw, cgsWin, gc)); 4241d4fba8b9Smrg setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 4242d522f475Smrg } else { 4243d4fba8b9Smrg setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc)); 4244d4fba8b9Smrg setCgsFore(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 4245d4fba8b9Smrg setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 4246d522f475Smrg } 4247d4fba8b9Smrg gc2 = getCgsGC(params->xw, cgsWin, cgsId); 4248d522f475Smrg 4249d4fba8b9Smrg if (!(params->draw_flags & NOBACKGROUND)) { 42500bd37d32Smrg XFillRectangle(screen->display, VDrawable(screen), gc2, x, y, 4251d522f475Smrg font_width, 4252d522f475Smrg font_height); 4253d522f475Smrg } 4254d522f475Smrg 4255d4fba8b9Smrg setCgsFont(params->xw, cgsWin, cgsId, getCgsFont(params->xw, cgsWin, gc)); 4256d4fba8b9Smrg setCgsFore(params->xw, cgsWin, cgsId, getCgsFore(params->xw, cgsWin, gc)); 4257d4fba8b9Smrg setCgsBack(params->xw, cgsWin, cgsId, getCgsBack(params->xw, cgsWin, gc)); 4258d4fba8b9Smrg gc2 = getCgsGC(params->xw, cgsWin, cgsId); 4259d522f475Smrg 4260d1603babSmrg thick = ((params->attr_flags & BOLD) 4261d1603babSmrg ? (Max((unsigned) screen->fnt_high / 12, 1)) 4262980988aeSmrg : (Max((unsigned) screen->fnt_high / 16, 1))); 4263980988aeSmrg setXtermLineAttributes(screen->display, gc2, 4264d1603babSmrg thick, 4265d1603babSmrg ((ch < XtNumber(lines)) 4266d1603babSmrg ? LineSolid 4267980988aeSmrg : LineOnOffDash)); 4268d522f475Smrg 4269980988aeSmrg if (ch == 32) { /* space! */ 4270980988aeSmrg ; /* boxing a missing space is pointless */ 4271980988aeSmrg } else if (ch == 1) { /* diamond */ 4272d522f475Smrg XPoint points[5]; 4273d522f475Smrg int npoints = 5, n; 4274d522f475Smrg 4275d522f475Smrg points[0].x = MID_WIDE; 4276d522f475Smrg points[0].y = BOX_HIGH / 4; 4277d522f475Smrg 4278d522f475Smrg points[1].x = 8 * BOX_WIDE / 8; 4279d522f475Smrg points[1].y = MID_HIGH; 4280d522f475Smrg 4281d522f475Smrg points[2].x = points[0].x; 4282d522f475Smrg points[2].y = 3 * BOX_HIGH / 4; 4283d522f475Smrg 4284d522f475Smrg points[3].x = 0 * BOX_WIDE / 8; 4285d522f475Smrg points[3].y = points[1].y; 4286d522f475Smrg 4287d522f475Smrg points[4].x = points[0].x; 4288d522f475Smrg points[4].y = points[0].y; 4289d522f475Smrg 4290d522f475Smrg for (n = 0; n < npoints; ++n) { 4291d4fba8b9Smrg points[n].x = (short) (SCALED_X(points[n].x)); 4292d4fba8b9Smrg points[n].y = (short) (SCALED_Y(points[n].y)); 4293e39b573cSmrg points[n].x = (short) (points[n].x + x); 4294e39b573cSmrg points[n].y = (short) (points[n].y + y); 4295d522f475Smrg } 4296d522f475Smrg 4297d522f475Smrg XFillPolygon(screen->display, 42980bd37d32Smrg VDrawable(screen), gc2, 4299d522f475Smrg points, npoints, 4300d522f475Smrg Convex, CoordModeOrigin); 4301d522f475Smrg } else if (ch == 7) { /* degrees */ 4302d522f475Smrg unsigned width = (BOX_WIDE / 3); 4303956cc18dSsnj int x_coord = MID_WIDE - (int) (width / 2); 4304956cc18dSsnj int y_coord = MID_HIGH - (int) width; 4305d522f475Smrg 4306d522f475Smrg SCALE_X(x_coord); 4307d522f475Smrg SCALE_Y(y_coord); 4308e39b573cSmrg width = (unsigned) SCALED_X(width); 4309d522f475Smrg 4310d522f475Smrg XDrawArc(screen->display, 43110bd37d32Smrg VDrawable(screen), gc2, 4312d522f475Smrg x + x_coord, y + y_coord, width, width, 4313d522f475Smrg 0, 4314d522f475Smrg 360 * 64); 4315d522f475Smrg } else if (ch == 0x1f) { /* bullet */ 4316d522f475Smrg unsigned width = 7 * BOX_WIDE / 10; 4317956cc18dSsnj int x_coord = MID_WIDE - (int) (width / 3); 4318956cc18dSsnj int y_coord = MID_HIGH - (int) (width / 3); 4319d522f475Smrg 4320d522f475Smrg SCALE_X(x_coord); 4321d522f475Smrg SCALE_Y(y_coord); 4322e39b573cSmrg width = (unsigned) SCALED_X(width); 4323d522f475Smrg 4324d522f475Smrg XDrawArc(screen->display, 43250bd37d32Smrg VDrawable(screen), gc2, 4326d522f475Smrg x + x_coord, y + y_coord, width, width, 4327d522f475Smrg 0, 4328d522f475Smrg 360 * 64); 4329d4fba8b9Smrg } else if (ch < XtNumber(lines) 4330190d7dceSmrg && (p = lines[ch].data) != NULL) { 4331956cc18dSsnj int coord[4]; 4332d522f475Smrg int n = 0; 4333d522f475Smrg while (*p >= 0) { 4334d522f475Smrg coord[n++] = *p++; 4335d522f475Smrg if (n == 4) { 4336d522f475Smrg SCALE_X(coord[0]); 4337d522f475Smrg SCALE_Y(coord[1]); 4338d522f475Smrg SCALE_X(coord[2]); 4339d522f475Smrg SCALE_Y(coord[3]); 4340d522f475Smrg XDrawLine(screen->display, 43410bd37d32Smrg VDrawable(screen), gc2, 4342d522f475Smrg x + coord[0], y + coord[1], 4343d522f475Smrg x + coord[2], y + coord[3]); 4344d522f475Smrg n = 0; 4345d522f475Smrg } 4346d522f475Smrg } 4347d522f475Smrg } else if (screen->force_all_chars) { 4348d522f475Smrg /* bounding rectangle, for debugging */ 4349d1603babSmrg if ((params->draw_flags & DOUBLEHFONT)) { 4350d1603babSmrg XRectangle clip; 4351d1603babSmrg 4352d1603babSmrg clip.x = 0; 4353d1603babSmrg clip.y = 0; 4354d1603babSmrg clip.width = (unsigned short) ((font_width - 1) + (unsigned) thick); 4355d1603babSmrg clip.height = (unsigned short) ((unsigned) FontHeight(screen) + thick); 4356d1603babSmrg 4357d1603babSmrg if ((params->draw_flags & DOUBLEFIRST)) { 4358d1603babSmrg y -= (2 * FontDescent(screen)); 4359d1603babSmrg clip.height = 4360d1603babSmrg (unsigned short) (clip.height 4361d1603babSmrg - ((unsigned short) FontDescent(screen))); 4362d1603babSmrg } else { 4363d1603babSmrg y -= FontHeight(screen); 4364d1603babSmrg y += FontDescent(screen); 4365d1603babSmrg clip.y = (short) FontHeight(screen); 4366d1603babSmrg } 4367d1603babSmrg XSetClipRectangles(screen->display, gc2, x, y, &clip, 1, Unsorted); 4368d1603babSmrg } 4369d1603babSmrg XDrawRectangle(screen->display, VDrawable(screen), gc2, 4370d1603babSmrg x + (int) thick, y + (int) thick, 4371d1603babSmrg font_width - (2 * thick), 4372d1603babSmrg font_height - (2 * thick)); 4373d1603babSmrg if ((params->draw_flags & DOUBLEHFONT)) { 4374d1603babSmrg XSetClipMask(screen->display, gc2, None); 4375d1603babSmrg } 4376d522f475Smrg } 4377980988aeSmrg resetXtermLineAttributes(screen->display, gc2); 4378d522f475Smrg} 4379980988aeSmrg#endif /* OPT_BOX_CHARS || OPT_WIDE_CHARS */ 4380d522f475Smrg 4381d522f475Smrg#if OPT_RENDERFONT 4382d1603babSmrgstatic int 4383d1603babSmrgcheckXftGlyph(XtermWidget xw, XftFont *font, unsigned wc) 4384d1603babSmrg{ 4385d1603babSmrg TScreen *screen = TScreenOf(xw); 4386d1603babSmrg int result = 0; 4387d1603babSmrg int expect; 4388d1603babSmrg 4389d1603babSmrg if ((expect = CharWidth(screen, wc)) > 0) { 4390d1603babSmrg XGlyphInfo gi; 4391d1603babSmrg int actual; 4392d1603babSmrg int limit = (100 + xw->misc.limit_fontwidth); 4393d1603babSmrg 4394d1603babSmrg XftTextExtents32(screen->display, font, &wc, 1, &gi); 4395d1603babSmrg /* 4396d1603babSmrg * Some (more than a few) fonts are sloppy; allow 10% outside 4397d1603babSmrg * the bounding box to accommodate them. 4398d1603babSmrg */ 4399d1603babSmrg actual = ((gi.xOff * 100) >= (limit * FontWidth(screen))) ? 2 : 1; 4400d1603babSmrg if (actual <= expect) { 4401d1603babSmrg /* allow double-cell if wcwidth agrees */ 4402d1603babSmrg result = 1; 4403d1603babSmrg } else { 4404d1603babSmrg /* 4405d1603babSmrg * Do not use this font for this specific character, but 4406d1603babSmrg * possibly other characters can be used. 4407d1603babSmrg */ 4408d1603babSmrg result = -1; 4409d1603babSmrg TRACE(("SKIP U+%04X %d vs %d (%d vs %d) %s\n", 4410d1603babSmrg wc, gi.xOff, FontWidth(screen), actual, expect, 4411d1603babSmrg nameOfXftFont(font))); 4412d1603babSmrg } 4413d1603babSmrg } else { 4414d1603babSmrg result = 1; 4415d1603babSmrg } 4416d1603babSmrg return result; 4417d1603babSmrg} 4418d1603babSmrg 4419d4fba8b9Smrg/* 4420d4fba8b9Smrg * Check if the glyph is defined in the given font, and (try to) filter out 4421d4fba8b9Smrg * cases where double-width glyphs are stuffed into a single-width outline. 4422d4fba8b9Smrg */ 4423d1603babSmrgstatic int 4424d1603babSmrgfoundXftGlyph(XtermWidget xw, XTermXftFonts *data, int fontNum, unsigned wc) 4425d4fba8b9Smrg{ 4426d1603babSmrg XftFont *font = XftFpN(data, fontNum); 4427d1603babSmrg int result = 0; 4428d4fba8b9Smrg 4429190d7dceSmrg if (font != NULL) { 4430d1603babSmrg if (!xtermXftMissing(xw, data, fontNum, font, wc)) { 4431d4fba8b9Smrg 4432d1603babSmrg if (XftIsN(data, fontNum) == xcBogus) { 4433d1603babSmrg ; 4434d1603babSmrg } else if (XftIsN(data, fontNum) == xcOpened) { 4435d1603babSmrg result = 1; 4436d4fba8b9Smrg } else { 4437d1603babSmrg result = checkXftGlyph(xw, font, wc); 4438d4fba8b9Smrg } 4439d4fba8b9Smrg } 4440d4fba8b9Smrg } 4441d4fba8b9Smrg return result; 4442d4fba8b9Smrg} 4443d4fba8b9Smrg 4444d4fba8b9Smrgstatic void 4445d1603babSmrgmarkXftOpened(XtermWidget xw, XTermXftFonts *which, int n, unsigned wc) 4446d4fba8b9Smrg{ 4447d1603babSmrg if (XftIsN(which, n) != xcOpened) { 4448d4fba8b9Smrg which->opened++; 4449d1603babSmrg XftIsN(which, n) = xcOpened; 4450d4fba8b9Smrg /* XFT_DEBUG=3 will show useful context for this */ 4451190d7dceSmrg if (getenv("XFT_DEBUG") != NULL) { 4452d1603babSmrg printf("%s: matched U+%04X in fontset #%d [%u:%u]\n", 4453d1603babSmrg ProgramName, 4454d4fba8b9Smrg wc, n + 1, 4455d4fba8b9Smrg which->opened, 4456d4fba8b9Smrg xw->work.max_fontsets); 4457d4fba8b9Smrg } 4458d4fba8b9Smrg } 4459d4fba8b9Smrg} 4460d4fba8b9Smrg 4461d1603babSmrgstatic char ** 4462190d7dceSmrgxftData2List(XtermWidget xw, const XTermXftFonts *fontData) 4463d1603babSmrg{ 4464d1603babSmrg TScreen *screen = TScreenOf(xw); 4465d1603babSmrg VTFontList *lists = &xw->work.fonts.xft; 4466d1603babSmrg char **result = NULL; 4467d1603babSmrg int n = screen->menu_font_number; 4468d1603babSmrg 4469d1603babSmrg if (fontData == &screen->renderFontNorm[n]) 4470d1603babSmrg result = lists->list_n; 4471d1603babSmrg else if (fontData == &screen->renderFontBold[n]) 4472d1603babSmrg result = lists->list_b; 4473d1603babSmrg else if (fontData == &screen->renderFontItal[n]) 4474d1603babSmrg result = lists->list_i; 4475d1603babSmrg else if (fontData == &screen->renderFontBtal[n]) 4476d1603babSmrg result = lists->list_bi; 4477d1603babSmrg#if OPT_RENDERWIDE 4478d1603babSmrg if (fontData == &screen->renderWideNorm[n]) 4479d1603babSmrg result = lists->list_w; 4480d1603babSmrg else if (fontData == &screen->renderWideBold[n]) 4481d1603babSmrg result = lists->list_wb; 4482d1603babSmrg else if (fontData == &screen->renderWideItal[n]) 4483d1603babSmrg result = lists->list_wi; 4484d1603babSmrg else if (fontData == &screen->renderWideBtal[n]) 4485d1603babSmrg result = lists->list_wbi; 4486d1603babSmrg#endif 4487d1603babSmrg return result; 4488d1603babSmrg} 4489d1603babSmrg 4490d1603babSmrgstatic FcPattern * 4491d1603babSmrgmergeXftStyle(XtermWidget xw, FcPattern * myPattern, XTermXftFonts *fontData) 4492d1603babSmrg{ 4493d1603babSmrg TScreen *screen = TScreenOf(xw); 4494d1603babSmrg Display *dpy = screen->display; 4495d1603babSmrg XftFont *given = XftFp(fontData); 4496d1603babSmrg XftResult mStatus; 4497d1603babSmrg int iValue; 4498d1603babSmrg double dValue; 4499d1603babSmrg 4500d1603babSmrg if (FcOK(FcPatternGetInteger(fontData->pattern, XFT_WEIGHT, 0, &iValue))) { 4501d1603babSmrg FcPatternAddInteger(myPattern, XFT_WEIGHT, iValue); 4502d1603babSmrg } 4503d1603babSmrg if (FcOK(FcPatternGetInteger(fontData->pattern, XFT_SLANT, 0, &iValue))) { 4504d1603babSmrg FcPatternAddInteger(myPattern, XFT_SLANT, iValue); 4505d1603babSmrg } 4506d1603babSmrg if (FcOK(FcPatternGetDouble(fontData->pattern, FC_ASPECT, 0, &dValue))) { 4507d1603babSmrg FcPatternAddDouble(myPattern, FC_ASPECT, dValue); 4508d1603babSmrg } 4509d1603babSmrg if (FcOK(FcPatternGetDouble(fontData->pattern, XFT_SIZE, 0, &dValue))) { 4510d1603babSmrg FcPatternAddDouble(myPattern, XFT_SIZE, dValue); 4511d1603babSmrg } 4512d1603babSmrg FcPatternAddBool(myPattern, FC_SCALABLE, FcTrue); 4513d1603babSmrg FcPatternAddInteger(myPattern, XFT_SPACING, XFT_MONO); 4514d1603babSmrg FcPatternAddInteger(myPattern, FC_CHAR_WIDTH, given->max_advance_width); 4515d1603babSmrg#ifdef FC_COLOR 4516d1603babSmrg#if !USE_FC_COLOR 4517d1603babSmrg FcPatternAddBool(myPattern, FC_COLOR, FcFalse); 4518d1603babSmrg#endif 4519d1603babSmrg FcPatternAddBool(myPattern, FC_OUTLINE, FcTrue); 4520d1603babSmrg#endif 4521d1603babSmrg 4522d1603babSmrg FcConfigSubstitute(NULL, myPattern, FcMatchPattern); 4523d1603babSmrg XftDefaultSubstitute(dpy, DefaultScreen(dpy), myPattern); 4524d1603babSmrg 4525d1603babSmrg return FcFontMatch(NULL, myPattern, &mStatus); 4526d1603babSmrg} 4527d1603babSmrg 4528d4fba8b9Smrg/* 4529d4fba8b9Smrg * Check if the given character has a glyph known to Xft. If it is missing, 4530d4fba8b9Smrg * try first to replace the font with a fallback that provides the glyph. 4531d1603babSmrg * 4532d1603babSmrg * Return -1 if nothing is found. Otherwise, return the index in the cache. 4533d4fba8b9Smrg */ 4534d1603babSmrgint 4535d1603babSmrgfindXftGlyph(XtermWidget xw, XTermXftFonts *fontData, unsigned wc) 4536d4fba8b9Smrg{ 4537d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 4538d1603babSmrg XftFont *given; 4539d1603babSmrg XftFont *actual = NULL; 4540d4fba8b9Smrg FcResult status; 4541d1603babSmrg int n; 4542d1603babSmrg int result = -1; 4543d1603babSmrg 4544d1603babSmrg /* sanity-check */ 4545d1603babSmrg if (fontData == NULL) 4546d1603babSmrg return result; 4547d1603babSmrg given = XftFp(fontData); 4548d4fba8b9Smrg 4549d4fba8b9Smrg /* if fontsets are not wanted, just leave */ 4550d4fba8b9Smrg if (xw->work.max_fontsets == 0) { 4551d1603babSmrg return result; 4552d4fba8b9Smrg } 4553d4fba8b9Smrg 4554d4fba8b9Smrg /* ignore codes in private use areas */ 4555d4fba8b9Smrg if ((wc >= 0xe000 && wc <= 0xf8ff) 4556d4fba8b9Smrg || (wc >= 0xf0000 && wc <= 0xffffd) 4557d4fba8b9Smrg || (wc >= 0x100000 && wc <= 0x10fffd)) { 4558d1603babSmrg return result; 4559d4fba8b9Smrg } 4560d4fba8b9Smrg /* the end of the BMP is reserved for non-characters */ 4561d4fba8b9Smrg if (wc >= 0xfff0 && wc <= 0xffff) { 4562d1603babSmrg return result; 4563d4fba8b9Smrg } 4564d4fba8b9Smrg 4565d1603babSmrg /* initialize on the first call */ 4566d1603babSmrg if (fontData->fontset == NULL && fontData->pattern != NULL) { 4567d1603babSmrg FcFontSet *sortedFonts; 4568d1603babSmrg FcPattern *myPattern; 4569d1603babSmrg int j; 4570d1603babSmrg char **my_list; 4571d4fba8b9Smrg 4572d1603babSmrg myPattern = FcPatternDuplicate(fontData->pattern); 4573d4fba8b9Smrg 4574d1603babSmrg FcPatternAddBool(myPattern, FC_SCALABLE, FcTrue); 4575d1603babSmrg FcPatternAddInteger(myPattern, FC_CHAR_WIDTH, given->max_advance_width); 4576d4fba8b9Smrg 4577d1603babSmrg FcConfigSubstitute(FcConfigGetCurrent(), 4578d1603babSmrg myPattern, 4579d1603babSmrg FcMatchPattern); 4580d1603babSmrg FcDefaultSubstitute(myPattern); 4581d4fba8b9Smrg 4582d1603babSmrg sortedFonts = FcFontSort(NULL, myPattern, FcTrue, NULL, &status); 4583d4fba8b9Smrg 4584d1603babSmrg fontData->fontset = FcFontSetCreate(); 4585d4fba8b9Smrg 4586190d7dceSmrg if (fontData->fontset == NULL 4587190d7dceSmrg || !sortedFonts 4588190d7dceSmrg || sortedFonts->nfont <= 0) { 4589d1603babSmrg xtermWarning("did not find any usable TrueType font\n"); 4590d1603babSmrg return 0; 4591d1603babSmrg } 4592d1603babSmrg 4593d1603babSmrg /* 4594d1603babSmrg * Check if there are additional fonts in the XtermFontNames.xft for 4595d1603babSmrg * this font-data. 4596d1603babSmrg */ 4597d1603babSmrg if ((my_list = xftData2List(xw, fontData)) != NULL 4598d1603babSmrg && *++my_list != NULL) { 4599d1603babSmrg for (j = 0; my_list[j] != NULL; ++j) { 4600d1603babSmrg FcPattern *extraPattern; 4601190d7dceSmrg if ((extraPattern = XftNameParse(my_list[j])) != NULL) { 4602d1603babSmrg FcPattern *match; 4603d1603babSmrg 4604d1603babSmrg match = mergeXftStyle(xw, extraPattern, fontData); 4605d1603babSmrg 4606d1603babSmrg if (match != NULL) { 4607d1603babSmrg FcFontSetAdd(fontData->fontset, match); 4608d1603babSmrg } 4609d1603babSmrg FcPatternDestroy(extraPattern); 4610d1603babSmrg } 4611d4fba8b9Smrg } 4612d1603babSmrg } 4613d1603babSmrg 4614d1603babSmrg for (j = 0; j < sortedFonts->nfont; j++) { 4615d1603babSmrg FcPattern *font_pattern; 4616d4fba8b9Smrg 4617d1603babSmrg font_pattern = FcFontRenderPrepare(FcConfigGetCurrent(), 4618d1603babSmrg myPattern, 4619d1603babSmrg sortedFonts->fonts[j]); 4620d1603babSmrg if (font_pattern) { 4621d1603babSmrg FcFontSetAdd(fontData->fontset, font_pattern); 4622d1603babSmrg } 4623d4fba8b9Smrg } 4624d1603babSmrg 4625d1603babSmrg FcFontSetSortDestroy(sortedFonts); 4626d1603babSmrg FcPatternDestroy(myPattern); 4627d1603babSmrg 4628d1603babSmrg fontData->fs_size = Min(MaxXftCache, fontData->fontset->nfont); 4629d1603babSmrg } 4630d1603babSmrg if (fontData->fontset != NULL && fontData->fs_size > 0) { 4631d1603babSmrg XftFont *check; 4632d1603babSmrg int empty = fontData->fs_size; 4633d1603babSmrg 4634d1603babSmrg for (n = 1; n <= fontData->fs_size; ++n) { 4635d1603babSmrg XTermXftState usage = XftIsN(fontData, n); 4636d1603babSmrg if (usage == xcEmpty) { 4637d1603babSmrg if (empty > n) 4638d1603babSmrg empty = n; 4639d1603babSmrg } else if (usage == xcOpened 4640d1603babSmrg || (usage == xcUnused 4641d1603babSmrg && (fontData->opened < xw->work.max_fontsets))) { 4642d1603babSmrg check = XftFpN(fontData, n); 4643d1603babSmrg if (foundXftGlyph(xw, fontData, (int) n, wc)) { 4644d1603babSmrg markXftOpened(xw, fontData, n, wc); 4645d1603babSmrg actual = check; 4646d1603babSmrg result = (int) n; 4647d1603babSmrg TRACE_FALLBACK(xw, "old", wc, result, actual); 4648d1603babSmrg break; 4649d4fba8b9Smrg } 4650d4fba8b9Smrg } 4651d1603babSmrg } 4652d4fba8b9Smrg 4653d1603babSmrg if ((actual == NULL) 4654d1603babSmrg && (empty <= fontData->fs_size) 4655d1603babSmrg && (fontData->opened < xw->work.max_fontsets)) { 4656d1603babSmrg FcPattern *myPattern = NULL; 4657d1603babSmrg FcPattern *myReport = NULL; 4658d1603babSmrg int defer = -1; 4659d1603babSmrg 4660d1603babSmrg if (empty == 0) /* should not happen */ 4661d1603babSmrg empty++; 4662d1603babSmrg 4663d1603babSmrg for (n = empty; n <= fontData->fs_size; ++n) { 4664d1603babSmrg int found; 4665d1603babSmrg int nn = n - 1; 4666d1603babSmrg 4667d1603babSmrg if (XftIsN(fontData, n) != xcEmpty) { 4668d1603babSmrg continue; 4669d1603babSmrg } 4670d1603babSmrg if (resource.reportFonts) { 4671d1603babSmrg if (myReport != NULL) 4672d1603babSmrg FcPatternDestroy(myReport); 4673d1603babSmrg myReport = FcPatternDuplicate(fontData->fontset->fonts[nn]); 4674d1603babSmrg } 4675d1603babSmrg myPattern = FcPatternDuplicate(fontData->fontset->fonts[nn]); 4676d1603babSmrg check = XftFontOpenPattern(screen->display, myPattern); 4677d1603babSmrg (void) maybeXftCache(xw, check); 4678d1603babSmrg XftFpN(fontData, n) = check; 4679d1603babSmrg if (check == NULL) { 4680d1603babSmrg ; /* shouldn't happen... */ 4681d1603babSmrg } else 4682d4fba8b9Smrg#ifdef FC_COLOR 4683d1603babSmrg if (isBogusXft(check)) { 4684d1603babSmrg XftIsN(fontData, n) = xcBogus; 4685d1603babSmrg } else 4686d4fba8b9Smrg#endif 4687d1603babSmrg if ((found = foundXftGlyph(xw, fontData, (int) n, wc)) 4688d1603babSmrg != 0) { 4689d1603babSmrg markXftOpened(xw, fontData, n, wc); 4690d1603babSmrg reportXftFallbackFont(xw, fontData, (int) n, check, myReport); 4691d1603babSmrg if (found < 0) { 4692d1603babSmrg if (defer < 0) { 4693d1603babSmrg defer = (int) n; 4694d1603babSmrg TRACE(("Deferring font choice #%d\n", n + 1)); 4695d1603babSmrg continue; 4696d1603babSmrg } else if (slowXftMissing(xw, check, wc)) { 4697d1603babSmrg TRACE(("Deferred, continuing #%d\n", n + 1)); 4698d1603babSmrg continue; 4699d1603babSmrg } 4700d1603babSmrg } else if (defer >= 0) { 4701d1603babSmrg defer = -1; 4702d1603babSmrg TRACE(("Deferred, replacing %d with %d\n", 4703d1603babSmrg defer + 1, n + 1)); 4704d1603babSmrg } 4705d1603babSmrg actual = check; 4706d1603babSmrg result = (int) n; 4707d1603babSmrg TRACE_FALLBACK(xw, "new", wc, result, actual); 4708d1603babSmrg break; 4709d1603babSmrg } else { 4710d1603babSmrg if (defer >= 0 4711980988aeSmrg && !slowXftMissing(xw, check, wc) 4712d1603babSmrg && checkXftGlyph(xw, check, wc)) { 4713d1603babSmrg XTermFontMap *font_map = &(fontData->font_map); 4714d1603babSmrg TRACE(("checkrecover2 %d\n", n)); 4715d1603babSmrg markXftOpened(xw, fontData, n, wc); 4716d1603babSmrg reportXftFallbackFont(xw, fontData, (int) n, check, myReport); 4717d1603babSmrg actual = check; 4718d1603babSmrg result = (int) n; 4719d1603babSmrg TRACE_FALLBACK(xw, "fix", wc, result, actual); 4720d1603babSmrg font_map->per_font[wc] = (XTfontNum) (result + 1); 4721d4fba8b9Smrg break; 4722d1603babSmrg } else { 4723d1603babSmrg /* 4724d1603babSmrg * The slot is opened, but we are not using it yet. 4725d1603babSmrg */ 4726d1603babSmrg XftIsN(fontData, n) = xcUnused; 4727d4fba8b9Smrg } 4728d4fba8b9Smrg } 4729d4fba8b9Smrg } 4730d1603babSmrg if (myReport != NULL) 4731d1603babSmrg FcPatternDestroy(myReport); 4732d4fba8b9Smrg } 4733d4fba8b9Smrg } 4734d4fba8b9Smrg return result; 4735d4fba8b9Smrg} 4736d522f475Smrg 4737d522f475Smrg/* 4738d4fba8b9Smrg * Check if the given character has a glyph known to Xft. If it is missing, 4739d4fba8b9Smrg * return true. 4740d522f475Smrg * 4741d522f475Smrg * see xc/lib/Xft/xftglyphs.c 4742d522f475Smrg */ 4743d522f475SmrgBool 4744d1603babSmrgxtermXftMissing(XtermWidget xw, 4745d1603babSmrg XTermXftFonts *data, 4746d1603babSmrg int fontNum, /* 0=primary, 1+ is fallback */ 4747d1603babSmrg XftFont *font, /* actual font if no data */ 4748d1603babSmrg unsigned wc) 4749d522f475Smrg{ 4750d1603babSmrg Bool result = True; 4751d522f475Smrg 4752d1603babSmrg (void) xw; 4753d1603babSmrg if (data != NULL && font != NULL) { 4754d1603babSmrg XTermFontMap *font_map = &(data->font_map); 4755d1603babSmrg /* 4756d1603babSmrg * Each fallback font has one chance to be scanned/cached. 4757d1603babSmrg * We record in per_font[] the index of the first font containing a 4758d1603babSmrg * given glyph. 4759d1603babSmrg */ 4760d1603babSmrg if (font_map->depth <= fontNum) { 4761d1603babSmrg FcChar32 last = (xtermXftLastChar(font) | 255) + 1; 4762d1603babSmrg FcChar32 base; 4763d1603babSmrg FcChar32 nextPage; 4764d1603babSmrg FcChar32 map[FC_CHARSET_MAP_SIZE]; 4765d1603babSmrg unsigned added = 0; 4766d1603babSmrg unsigned actual = 0; 4767d1603babSmrg 4768d1603babSmrg font_map->depth = (fontNum + 1); 4769d1603babSmrg /* allocate space */ 4770d1603babSmrg if (last > font_map->last_char) { 4771d1603babSmrg size_t need = (last * sizeof(XTfontNum)); 4772d1603babSmrg size_t c1st = (font_map->last_char * sizeof(XTfontNum)); 4773d1603babSmrg font_map->per_font = realloc(font_map->per_font, need); 4774d1603babSmrg memset(font_map->per_font + font_map->last_char, 0, (need - c1st)); 4775d1603babSmrg font_map->last_char = last; 4776d1603babSmrg } 4777d1603babSmrg 4778d1603babSmrg /* scan new font */ 4779d1603babSmrg base = FcCharSetFirstPage(font->charset, map, &nextPage); 4780d1603babSmrg do { 4781d1603babSmrg unsigned row; 4782d1603babSmrg unsigned col; 4783d1603babSmrg FcChar32 bits; 4784d1603babSmrg for (row = 0; row < FC_CHARSET_MAP_SIZE; ++row) { 4785d1603babSmrg bits = map[row]; 4786d1603babSmrg for (col = 0; col < 32; ++col) { 4787d1603babSmrg if ((bits & 1) != 0) { 4788d1603babSmrg actual++; 4789d1603babSmrg if (!font_map->per_font[base]) { 4790d1603babSmrg font_map->per_font[base] = (Char) font_map->depth; 4791d1603babSmrg ++added; 4792d1603babSmrg } 4793d1603babSmrg } 4794d1603babSmrg bits >>= 1; 4795d1603babSmrg ++base; 4796d1603babSmrg } 4797d1603babSmrg } 4798d1603babSmrg } while ((base = FcCharSetNextPage(font->charset, map, 4799d1603babSmrg &nextPage)) != FC_CHARSET_DONE); 4800d1603babSmrg (void) added; 4801d1603babSmrg (void) actual; 4802d1603babSmrg TRACE(("xtermXftMissing U+%04X #%-3d %6u added vs %6u of %6ld %s: %s\n", 4803d1603babSmrg wc, 4804d1603babSmrg font_map->depth, 4805d1603babSmrg added, actual, 4806d1603babSmrg font_map->last_char + 1, 4807d1603babSmrg whichXftFonts(xw, data), 4808d1603babSmrg nameOfXftFont(font))); 4809d1603babSmrg } 4810d1603babSmrg if (wc < font_map->last_char) { 4811d1603babSmrg result = (font_map->per_font[wc] != (fontNum + 1)); 4812d522f475Smrg } 4813d522f475Smrg } 4814d522f475Smrg return result; 4815d522f475Smrg} 4816fa3f02f3Smrg#endif /* OPT_RENDERFONT */ 4817d522f475Smrg 4818d522f475Smrg#if OPT_WIDE_CHARS 4819d522f475Smrg#define MY_UCS(ucs,dec) case ucs: result = dec; break 4820d522f475Smrgunsigned 4821d4fba8b9Smrgucs2dec(TScreen *screen, unsigned ch) 4822d522f475Smrg{ 4823d522f475Smrg unsigned result = ch; 4824d4fba8b9Smrg 4825d4fba8b9Smrg (void) screen; 4826d522f475Smrg if ((ch > 127) 4827980988aeSmrg && !is_UCS_SPECIAL(ch)) { 4828d4fba8b9Smrg#if OPT_VT52_MODE 4829190d7dceSmrg if (screen != NULL && !(screen->vtXX_level)) { 4830d4fba8b9Smrg /* 4831d4fba8b9Smrg * Intentionally empty: it would be possible to use the built-in 4832d4fba8b9Smrg * line-drawing fallback in xtermDrawBoxChar(), but for testing 4833d4fba8b9Smrg * ncurses, this is good enough. 4834d4fba8b9Smrg */ 4835d4fba8b9Smrg ; 4836d4fba8b9Smrg } else 4837d4fba8b9Smrg#endif 4838d4fba8b9Smrg switch (ch) { 4839d4fba8b9Smrg MY_UCS(0x25ae, 0); /* black vertical rectangle */ 4840d4fba8b9Smrg MY_UCS(0x25c6, 1); /* black diamond */ 4841d4fba8b9Smrg MY_UCS(0x2592, 2); /* medium shade */ 4842d4fba8b9Smrg MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 4843d4fba8b9Smrg MY_UCS(0x240c, 4); /* symbol for form feed */ 4844d4fba8b9Smrg MY_UCS(0x240d, 5); /* symbol for carriage return */ 4845d4fba8b9Smrg MY_UCS(0x240a, 6); /* symbol for line feed */ 4846d4fba8b9Smrg MY_UCS(0x00b0, 7); /* degree sign */ 4847d4fba8b9Smrg MY_UCS(0x00b1, 8); /* plus-minus sign */ 4848d4fba8b9Smrg MY_UCS(0x2424, 9); /* symbol for newline */ 4849d4fba8b9Smrg MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 4850d4fba8b9Smrg MY_UCS(0x2518, 11); /* box drawings light up and left */ 4851d4fba8b9Smrg MY_UCS(0x2510, 12); /* box drawings light down and left */ 4852d4fba8b9Smrg MY_UCS(0x250c, 13); /* box drawings light down and right */ 4853d4fba8b9Smrg MY_UCS(0x2514, 14); /* box drawings light up and right */ 4854d4fba8b9Smrg MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 4855d4fba8b9Smrg MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 4856d4fba8b9Smrg MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 4857d4fba8b9Smrg MY_UCS(0x2500, 18); /* box drawings light horizontal */ 4858d4fba8b9Smrg MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 4859d4fba8b9Smrg MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 4860d4fba8b9Smrg MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 4861d4fba8b9Smrg MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 4862d4fba8b9Smrg MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 4863d4fba8b9Smrg MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 4864d4fba8b9Smrg MY_UCS(0x2502, 25); /* box drawings light vertical */ 4865d4fba8b9Smrg MY_UCS(0x2264, 26); /* less-than or equal to */ 4866d4fba8b9Smrg MY_UCS(0x2265, 27); /* greater-than or equal to */ 4867d4fba8b9Smrg MY_UCS(0x03c0, 28); /* greek small letter pi */ 4868d4fba8b9Smrg MY_UCS(0x2260, 29); /* not equal to */ 4869d4fba8b9Smrg MY_UCS(0x00a3, 30); /* pound sign */ 4870d4fba8b9Smrg MY_UCS(0x00b7, 31); /* middle dot */ 4871d4fba8b9Smrg } 4872d522f475Smrg } 4873d522f475Smrg return result; 4874d522f475Smrg} 4875d522f475Smrg 4876d522f475Smrg#undef MY_UCS 4877d522f475Smrg#define MY_UCS(ucs,dec) case dec: result = ucs; break 4878d522f475Smrg 4879d522f475Smrgunsigned 4880d4fba8b9Smrgdec2ucs(TScreen *screen, unsigned ch) 4881d522f475Smrg{ 4882d522f475Smrg unsigned result = ch; 4883d4fba8b9Smrg 4884d4fba8b9Smrg (void) screen; 4885d522f475Smrg if (xtermIsDecGraphic(ch)) { 4886d4fba8b9Smrg#if OPT_VT52_MODE 4887190d7dceSmrg if (screen != NULL && !(screen->vtXX_level)) { 4888d4fba8b9Smrg switch (ch) { 4889d4fba8b9Smrg MY_UCS(0x0020, 0); /* nbsp, treat as blank */ 4890d4fba8b9Smrg MY_UCS(0x0020, 1); /* reserved, treat as blank */ 4891d4fba8b9Smrg MY_UCS(0x25ae, 2); /* black vertical rectangle */ 4892d4fba8b9Smrg MY_UCS(0x215f, 3); /* "1/" */ 4893d4fba8b9Smrg MY_UCS(0x0020, 4); /* "3/", not in Unicode, ignore */ 4894d4fba8b9Smrg MY_UCS(0x0020, 5); /* "5/", not in Unicode, ignore */ 4895d4fba8b9Smrg MY_UCS(0x0020, 6); /* "7/", not in Unicode, ignore */ 4896d4fba8b9Smrg MY_UCS(0x00b0, 7); /* degree sign */ 4897d4fba8b9Smrg MY_UCS(0x00b1, 8); /* plus-minus sign */ 4898d4fba8b9Smrg MY_UCS(0x2192, 9); /* right-arrow */ 4899d4fba8b9Smrg MY_UCS(0x2026, 10); /* ellipsis */ 4900d4fba8b9Smrg MY_UCS(0x00f7, 11); /* divide by */ 4901d4fba8b9Smrg MY_UCS(0x2193, 12); /* down arrow */ 4902d4fba8b9Smrg MY_UCS(0x23ba, 13); /* bar at scan 0 */ 4903d4fba8b9Smrg MY_UCS(0x23ba, 14); /* bar at scan 1 */ 4904d4fba8b9Smrg MY_UCS(0x23bb, 15); /* bar at scan 2 */ 4905d4fba8b9Smrg MY_UCS(0x23bb, 16); /* bar at scan 3 */ 4906d4fba8b9Smrg MY_UCS(0x23bc, 17); /* bar at scan 4 */ 4907d4fba8b9Smrg MY_UCS(0x23bc, 18); /* bar at scan 5 */ 4908d4fba8b9Smrg MY_UCS(0x23bd, 19); /* bar at scan 6 */ 4909d4fba8b9Smrg MY_UCS(0x23bd, 20); /* bar at scan 7 */ 4910d4fba8b9Smrg MY_UCS(0x2080, 21); /* subscript 0 */ 4911d4fba8b9Smrg MY_UCS(0x2081, 22); /* subscript 1 */ 4912d4fba8b9Smrg MY_UCS(0x2082, 23); /* subscript 2 */ 4913d4fba8b9Smrg MY_UCS(0x2083, 24); /* subscript 3 */ 4914d4fba8b9Smrg MY_UCS(0x2084, 25); /* subscript 4 */ 4915d4fba8b9Smrg MY_UCS(0x2085, 26); /* subscript 5 */ 4916d4fba8b9Smrg MY_UCS(0x2086, 27); /* subscript 6 */ 4917d4fba8b9Smrg MY_UCS(0x2087, 28); /* subscript 7 */ 4918d4fba8b9Smrg MY_UCS(0x2088, 29); /* subscript 8 */ 4919d4fba8b9Smrg MY_UCS(0x2089, 30); /* subscript 9 */ 4920d4fba8b9Smrg MY_UCS(0x00b6, 31); /* paragraph */ 4921d4fba8b9Smrg } 4922d4fba8b9Smrg } else 4923d4fba8b9Smrg#endif 4924d4fba8b9Smrg switch (ch) { 4925d4fba8b9Smrg MY_UCS(0x25ae, 0); /* black vertical rectangle */ 4926d4fba8b9Smrg MY_UCS(0x25c6, 1); /* black diamond */ 4927d4fba8b9Smrg MY_UCS(0x2592, 2); /* medium shade */ 4928d4fba8b9Smrg MY_UCS(0x2409, 3); /* symbol for horizontal tabulation */ 4929d4fba8b9Smrg MY_UCS(0x240c, 4); /* symbol for form feed */ 4930d4fba8b9Smrg MY_UCS(0x240d, 5); /* symbol for carriage return */ 4931d4fba8b9Smrg MY_UCS(0x240a, 6); /* symbol for line feed */ 4932d4fba8b9Smrg MY_UCS(0x00b0, 7); /* degree sign */ 4933d4fba8b9Smrg MY_UCS(0x00b1, 8); /* plus-minus sign */ 4934d4fba8b9Smrg MY_UCS(0x2424, 9); /* symbol for newline */ 4935d4fba8b9Smrg MY_UCS(0x240b, 10); /* symbol for vertical tabulation */ 4936d4fba8b9Smrg MY_UCS(0x2518, 11); /* box drawings light up and left */ 4937d4fba8b9Smrg MY_UCS(0x2510, 12); /* box drawings light down and left */ 4938d4fba8b9Smrg MY_UCS(0x250c, 13); /* box drawings light down and right */ 4939d4fba8b9Smrg MY_UCS(0x2514, 14); /* box drawings light up and right */ 4940d4fba8b9Smrg MY_UCS(0x253c, 15); /* box drawings light vertical and horizontal */ 4941d4fba8b9Smrg MY_UCS(0x23ba, 16); /* box drawings scan 1 */ 4942d4fba8b9Smrg MY_UCS(0x23bb, 17); /* box drawings scan 3 */ 4943d4fba8b9Smrg MY_UCS(0x2500, 18); /* box drawings light horizontal */ 4944d4fba8b9Smrg MY_UCS(0x23bc, 19); /* box drawings scan 7 */ 4945d4fba8b9Smrg MY_UCS(0x23bd, 20); /* box drawings scan 9 */ 4946d4fba8b9Smrg MY_UCS(0x251c, 21); /* box drawings light vertical and right */ 4947d4fba8b9Smrg MY_UCS(0x2524, 22); /* box drawings light vertical and left */ 4948d4fba8b9Smrg MY_UCS(0x2534, 23); /* box drawings light up and horizontal */ 4949d4fba8b9Smrg MY_UCS(0x252c, 24); /* box drawings light down and horizontal */ 4950d4fba8b9Smrg MY_UCS(0x2502, 25); /* box drawings light vertical */ 4951d4fba8b9Smrg MY_UCS(0x2264, 26); /* less-than or equal to */ 4952d4fba8b9Smrg MY_UCS(0x2265, 27); /* greater-than or equal to */ 4953d4fba8b9Smrg MY_UCS(0x03c0, 28); /* greek small letter pi */ 4954d4fba8b9Smrg MY_UCS(0x2260, 29); /* not equal to */ 4955d4fba8b9Smrg MY_UCS(0x00a3, 30); /* pound sign */ 4956d4fba8b9Smrg MY_UCS(0x00b7, 31); /* middle dot */ 4957d4fba8b9Smrg } 4958d522f475Smrg } 4959d522f475Smrg return result; 4960d522f475Smrg} 4961d522f475Smrg 4962d522f475Smrg#endif /* OPT_WIDE_CHARS */ 4963d522f475Smrg 4964b6fea0ceSmrg#if OPT_RENDERFONT || OPT_SHIFT_FONTS 49650bd37d32Smrgstatic int 4966d522f475SmrglookupOneFontSize(XtermWidget xw, int fontnum) 4967d522f475Smrg{ 4968d522f475Smrg TScreen *screen = TScreenOf(xw); 4969d522f475Smrg 4970d522f475Smrg if (screen->menu_font_sizes[fontnum] == 0) { 4971d522f475Smrg XTermFonts fnt; 4972d522f475Smrg 4973d522f475Smrg memset(&fnt, 0, sizeof(fnt)); 4974d522f475Smrg screen->menu_font_sizes[fontnum] = -1; 4975d1603babSmrg if (xtermOpenFont(xw, screen->MenuFontName(fontnum), &fnt, NULL, True)) { 497620d2c4d2Smrg if (fontnum <= fontMenu_lastBuiltin 49770bd37d32Smrg || strcmp(fnt.fn, DEFFONT)) { 497820d2c4d2Smrg screen->menu_font_sizes[fontnum] = FontSize(fnt.fs); 49790bd37d32Smrg if (screen->menu_font_sizes[fontnum] <= 0) 49800bd37d32Smrg screen->menu_font_sizes[fontnum] = -1; 49810bd37d32Smrg } 4982d522f475Smrg xtermCloseFont(xw, &fnt); 4983d522f475Smrg } 4984d522f475Smrg } 49850bd37d32Smrg return (screen->menu_font_sizes[fontnum] > 0); 4986d522f475Smrg} 4987d522f475Smrg 4988d522f475Smrg/* 4989d522f475Smrg * Cache the font-sizes so subsequent larger/smaller font actions will go fast. 4990d522f475Smrg */ 4991d522f475Smrgstatic void 4992d522f475SmrglookupFontSizes(XtermWidget xw) 4993d522f475Smrg{ 4994d522f475Smrg int n; 4995d522f475Smrg 4996d522f475Smrg for (n = 0; n < NMENUFONTS; n++) { 49970bd37d32Smrg (void) lookupOneFontSize(xw, n); 4998d522f475Smrg } 4999d522f475Smrg} 5000b6fea0ceSmrg#endif /* OPT_RENDERFONT || OPT_SHIFT_FONTS */ 5001d522f475Smrg 50022eaa94a1Schristos#if OPT_RENDERFONT 50039a64e1c5Smrgstatic double 50049a64e1c5SmrgdefaultFaceSize(void) 50059a64e1c5Smrg{ 50069a64e1c5Smrg double result; 50079a64e1c5Smrg float value; 50089a64e1c5Smrg 50099a64e1c5Smrg if (sscanf(DEFFACESIZE, "%f", &value) == 1) 5010d4fba8b9Smrg result = (double) value; 50119a64e1c5Smrg else 50129a64e1c5Smrg result = 14.0; 50139a64e1c5Smrg return result; 50149a64e1c5Smrg} 50159a64e1c5Smrg 50160bd37d32Smrgstatic void 50170bd37d32SmrgfillInFaceSize(XtermWidget xw, int fontnum) 50180bd37d32Smrg{ 50190bd37d32Smrg TScreen *screen = TScreenOf(xw); 5020d4fba8b9Smrg double face_size = (double) xw->misc.face_size[fontnum]; 50210bd37d32Smrg 50220bd37d32Smrg if (face_size <= 0.0) { 50230bd37d32Smrg#if OPT_SHIFT_FONTS 50240bd37d32Smrg /* 50250bd37d32Smrg * If the user is switching font-sizes, make it follow by 50260bd37d32Smrg * default the same ratios to the default as the fixed fonts 50270bd37d32Smrg * would, for easy comparison. There will be some differences 50280bd37d32Smrg * since the fixed fonts have a variety of height/width ratios, 50290bd37d32Smrg * but this is simpler than adding another resource value - and 50300bd37d32Smrg * as noted above, the data for the fixed fonts are available. 50310bd37d32Smrg */ 50320bd37d32Smrg (void) lookupOneFontSize(xw, 0); 50330bd37d32Smrg if (fontnum == fontMenu_default) { 50349a64e1c5Smrg face_size = defaultFaceSize(); 50350bd37d32Smrg } else if (lookupOneFontSize(xw, fontnum) 50360bd37d32Smrg && (screen->menu_font_sizes[0] 50370bd37d32Smrg != screen->menu_font_sizes[fontnum])) { 50380bd37d32Smrg double ratio; 50390bd37d32Smrg long num = screen->menu_font_sizes[fontnum]; 50400bd37d32Smrg long den = screen->menu_font_sizes[0]; 50410bd37d32Smrg 50420bd37d32Smrg if (den <= 0) 50430bd37d32Smrg den = 1; 50440bd37d32Smrg ratio = dimSquareRoot((double) num / (double) den); 50450bd37d32Smrg 5046d4fba8b9Smrg face_size = (ratio * (double) xw->misc.face_size[0]); 50470bd37d32Smrg TRACE(("scaled[%d] using %3ld/%ld = %.2f -> %f\n", 50480bd37d32Smrg fontnum, num, den, ratio, face_size)); 50490bd37d32Smrg } else 50500bd37d32Smrg#endif 50510bd37d32Smrg { 5052d4fba8b9Smrg#define LikeBitmap(s) (((s) / 78.0) * (double) xw->misc.face_size[fontMenu_default]) 50530bd37d32Smrg switch (fontnum) { 50540bd37d32Smrg case fontMenu_font1: 50550bd37d32Smrg face_size = LikeBitmap(2.0); 50560bd37d32Smrg break; 50570bd37d32Smrg case fontMenu_font2: 50580bd37d32Smrg face_size = LikeBitmap(35.0); 50590bd37d32Smrg break; 50600bd37d32Smrg case fontMenu_font3: 50610bd37d32Smrg face_size = LikeBitmap(60.0); 50620bd37d32Smrg break; 50630bd37d32Smrg default: 50649a64e1c5Smrg face_size = defaultFaceSize(); 50650bd37d32Smrg break; 50660bd37d32Smrg case fontMenu_font4: 50670bd37d32Smrg face_size = LikeBitmap(90.0); 50680bd37d32Smrg break; 50690bd37d32Smrg case fontMenu_font5: 50700bd37d32Smrg face_size = LikeBitmap(135.0); 50710bd37d32Smrg break; 50720bd37d32Smrg case fontMenu_font6: 50730bd37d32Smrg face_size = LikeBitmap(200.0); 50740bd37d32Smrg break; 5075d4fba8b9Smrg case fontMenu_font7: 5076d4fba8b9Smrg face_size = LikeBitmap(240.0); 5077d4fba8b9Smrg break; 50780bd37d32Smrg } 50790bd37d32Smrg TRACE(("builtin[%d] -> %f\n", fontnum, face_size)); 50800bd37d32Smrg } 50810bd37d32Smrg xw->misc.face_size[fontnum] = (float) face_size; 50820bd37d32Smrg } 50830bd37d32Smrg} 50840bd37d32Smrg 50850bd37d32Smrg/* no selection or escape */ 50860bd37d32Smrg#define NMENU_RENDERFONTS (fontMenu_lastBuiltin + 1) 50870bd37d32Smrg 50880bd37d32Smrg/* 50890bd37d32Smrg * Workaround for breakage in font-packages - check if all of the bitmap font 50900bd37d32Smrg * sizes are the same, and if we're using TrueType fonts. 50910bd37d32Smrg */ 50922eaa94a1Schristosstatic Boolean 50932eaa94a1SchristosuseFaceSizes(XtermWidget xw) 50942eaa94a1Schristos{ 50952eaa94a1Schristos Boolean result = False; 50962eaa94a1Schristos 5097d4fba8b9Smrg TRACE(("useFaceSizes " TRACE_L "\n")); 50982eaa94a1Schristos if (UsingRenderFont(xw)) { 50990bd37d32Smrg Boolean nonzero = True; 5100037a25ddSmrg int n; 51010bd37d32Smrg 51022eaa94a1Schristos for (n = 0; n < NMENU_RENDERFONTS; ++n) { 5103d4fba8b9Smrg if (xw->misc.face_size[n] <= 0.0f) { 51040bd37d32Smrg nonzero = False; 51052eaa94a1Schristos break; 51062eaa94a1Schristos } 51072eaa94a1Schristos } 51080bd37d32Smrg if (!nonzero) { 5109956cc18dSsnj Boolean broken_fonts = True; 5110956cc18dSsnj TScreen *screen = TScreenOf(xw); 51110bd37d32Smrg long first; 5112956cc18dSsnj 5113956cc18dSsnj lookupFontSizes(xw); 51140bd37d32Smrg first = screen->menu_font_sizes[0]; 5115956cc18dSsnj for (n = 0; n < NMENUFONTS; n++) { 5116956cc18dSsnj if (screen->menu_font_sizes[n] > 0 5117956cc18dSsnj && screen->menu_font_sizes[n] != first) { 5118956cc18dSsnj broken_fonts = False; 5119956cc18dSsnj break; 5120956cc18dSsnj } 5121956cc18dSsnj } 5122956cc18dSsnj 5123956cc18dSsnj if (broken_fonts) { 5124956cc18dSsnj 5125956cc18dSsnj TRACE(("bitmap fonts are broken - set faceSize resources\n")); 5126956cc18dSsnj for (n = 0; n < NMENUFONTS; n++) { 51270bd37d32Smrg fillInFaceSize(xw, n); 5128956cc18dSsnj } 5129956cc18dSsnj 5130956cc18dSsnj } 5131956cc18dSsnj } 51320bd37d32Smrg result = True; 51332eaa94a1Schristos } 5134d4fba8b9Smrg TRACE((TRACE_R " useFaceSizes %d\n", result)); 51352eaa94a1Schristos return result; 51362eaa94a1Schristos} 51370bd37d32Smrg#endif /* OPT_RENDERFONT */ 51382eaa94a1Schristos 5139b6fea0ceSmrg#if OPT_SHIFT_FONTS 5140d522f475Smrg/* 5141d522f475Smrg * Find the index of a larger/smaller font (according to the sign of 'relative' 5142d522f475Smrg * and its magnitude), starting from the 'old' index. 5143d522f475Smrg */ 5144d522f475Smrgint 5145d522f475SmrglookupRelativeFontSize(XtermWidget xw, int old, int relative) 5146d522f475Smrg{ 5147d522f475Smrg TScreen *screen = TScreenOf(xw); 5148037a25ddSmrg int m = -1; 5149d522f475Smrg 51502eaa94a1Schristos TRACE(("lookupRelativeFontSize(old=%d, relative=%d)\n", old, relative)); 5151d522f475Smrg if (!IsIcon(screen)) { 51522eaa94a1Schristos#if OPT_RENDERFONT 51532eaa94a1Schristos if (useFaceSizes(xw)) { 51542eaa94a1Schristos TRACE(("...using FaceSize\n")); 51552eaa94a1Schristos if (relative != 0) { 5156037a25ddSmrg int n; 51572eaa94a1Schristos for (n = 0; n < NMENU_RENDERFONTS; ++n) { 51580bd37d32Smrg fillInFaceSize(xw, n); 51592eaa94a1Schristos if (xw->misc.face_size[n] > 0 && 51602eaa94a1Schristos xw->misc.face_size[n] != xw->misc.face_size[old]) { 51612eaa94a1Schristos int cmp_0 = ((xw->misc.face_size[n] > 51622eaa94a1Schristos xw->misc.face_size[old]) 51632eaa94a1Schristos ? relative 51642eaa94a1Schristos : -relative); 51652eaa94a1Schristos int cmp_m = ((m < 0) 51662eaa94a1Schristos ? 1 51672eaa94a1Schristos : ((xw->misc.face_size[n] < 51682eaa94a1Schristos xw->misc.face_size[m]) 51692eaa94a1Schristos ? relative 51702eaa94a1Schristos : -relative)); 51712eaa94a1Schristos if (cmp_0 > 0 && cmp_m > 0) { 51722eaa94a1Schristos m = n; 51732eaa94a1Schristos } 5174d522f475Smrg } 5175d522f475Smrg } 5176d522f475Smrg } 51772eaa94a1Schristos } else 51782eaa94a1Schristos#endif 51792eaa94a1Schristos { 51802eaa94a1Schristos TRACE(("...using bitmap areas\n")); 51812eaa94a1Schristos lookupFontSizes(xw); 51822eaa94a1Schristos if (relative != 0) { 5183037a25ddSmrg int n; 51842eaa94a1Schristos for (n = 0; n < NMENUFONTS; ++n) { 51852eaa94a1Schristos if (screen->menu_font_sizes[n] > 0 && 51862eaa94a1Schristos screen->menu_font_sizes[n] != 51872eaa94a1Schristos screen->menu_font_sizes[old]) { 51882eaa94a1Schristos int cmp_0 = ((screen->menu_font_sizes[n] > 51892eaa94a1Schristos screen->menu_font_sizes[old]) 51902eaa94a1Schristos ? relative 51912eaa94a1Schristos : -relative); 51922eaa94a1Schristos int cmp_m = ((m < 0) 51932eaa94a1Schristos ? 1 51942eaa94a1Schristos : ((screen->menu_font_sizes[n] < 51952eaa94a1Schristos screen->menu_font_sizes[m]) 51962eaa94a1Schristos ? relative 51972eaa94a1Schristos : -relative)); 51982eaa94a1Schristos if (cmp_0 > 0 && cmp_m > 0) { 51992eaa94a1Schristos m = n; 52002eaa94a1Schristos } 52012eaa94a1Schristos } 52022eaa94a1Schristos } 5203d522f475Smrg } 5204d522f475Smrg } 52052eaa94a1Schristos TRACE(("...new index %d\n", m)); 52062eaa94a1Schristos if (m >= 0) { 52072eaa94a1Schristos if (relative > 1) 52082eaa94a1Schristos m = lookupRelativeFontSize(xw, m, relative - 1); 52092eaa94a1Schristos else if (relative < -1) 52102eaa94a1Schristos m = lookupRelativeFontSize(xw, m, relative + 1); 52112eaa94a1Schristos } 5212d522f475Smrg } 5213d522f475Smrg return m; 5214d522f475Smrg} 5215d522f475Smrg 5216d522f475Smrg/* ARGSUSED */ 5217d522f475Smrgvoid 5218d4fba8b9SmrgHandleLargerFont(Widget w, 52199a64e1c5Smrg XEvent *event GCC_UNUSED, 5220fa3f02f3Smrg String *params GCC_UNUSED, 5221d522f475Smrg Cardinal *param_count GCC_UNUSED) 5222d522f475Smrg{ 5223956cc18dSsnj XtermWidget xw; 5224d522f475Smrg 522520d2c4d2Smrg TRACE(("Handle larger-vt-font for %p\n", (void *) w)); 5226190d7dceSmrg if ((xw = getXtermWidget(w)) != NULL) { 5227d522f475Smrg if (xw->misc.shift_fonts) { 5228956cc18dSsnj TScreen *screen = TScreenOf(xw); 5229d522f475Smrg int m; 5230d522f475Smrg 5231d522f475Smrg m = lookupRelativeFontSize(xw, screen->menu_font_number, 1); 5232d522f475Smrg if (m >= 0) { 5233d522f475Smrg SetVTFont(xw, m, True, NULL); 5234d522f475Smrg } else { 523520d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 5236d522f475Smrg } 5237d522f475Smrg } 5238d522f475Smrg } 5239d522f475Smrg} 5240d522f475Smrg 5241d522f475Smrg/* ARGSUSED */ 5242d522f475Smrgvoid 5243d4fba8b9SmrgHandleSmallerFont(Widget w, 52449a64e1c5Smrg XEvent *event GCC_UNUSED, 5245fa3f02f3Smrg String *params GCC_UNUSED, 5246d522f475Smrg Cardinal *param_count GCC_UNUSED) 5247d522f475Smrg{ 5248956cc18dSsnj XtermWidget xw; 5249d522f475Smrg 525020d2c4d2Smrg TRACE(("Handle smaller-vt-font for %p\n", (void *) w)); 5251190d7dceSmrg if ((xw = getXtermWidget(w)) != NULL) { 5252d522f475Smrg if (xw->misc.shift_fonts) { 5253956cc18dSsnj TScreen *screen = TScreenOf(xw); 5254d522f475Smrg int m; 5255d522f475Smrg 5256d522f475Smrg m = lookupRelativeFontSize(xw, screen->menu_font_number, -1); 5257d522f475Smrg if (m >= 0) { 5258d522f475Smrg SetVTFont(xw, m, True, NULL); 5259d522f475Smrg } else { 526020d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 5261d522f475Smrg } 5262d522f475Smrg } 5263d522f475Smrg } 5264d522f475Smrg} 5265b6fea0ceSmrg#endif /* OPT_SHIFT_FONTS */ 5266d522f475Smrg 5267d522f475Smrgint 5268d522f475SmrgxtermGetFont(const char *param) 5269d522f475Smrg{ 5270d522f475Smrg int fontnum; 5271d522f475Smrg 5272d1603babSmrg if (param == NULL) 5273d1603babSmrg param = ""; 5274d1603babSmrg 5275d522f475Smrg switch (param[0]) { 5276d522f475Smrg case 'd': 5277d522f475Smrg case 'D': 5278d522f475Smrg case '0': 5279d522f475Smrg fontnum = fontMenu_default; 5280d522f475Smrg break; 5281d522f475Smrg case '1': 5282d522f475Smrg fontnum = fontMenu_font1; 5283d522f475Smrg break; 5284d522f475Smrg case '2': 5285d522f475Smrg fontnum = fontMenu_font2; 5286d522f475Smrg break; 5287d522f475Smrg case '3': 5288d522f475Smrg fontnum = fontMenu_font3; 5289d522f475Smrg break; 5290d522f475Smrg case '4': 5291d522f475Smrg fontnum = fontMenu_font4; 5292d522f475Smrg break; 5293d522f475Smrg case '5': 5294d522f475Smrg fontnum = fontMenu_font5; 5295d522f475Smrg break; 5296d522f475Smrg case '6': 5297d522f475Smrg fontnum = fontMenu_font6; 5298d522f475Smrg break; 5299d4fba8b9Smrg case '7': 5300d4fba8b9Smrg fontnum = fontMenu_font7; 5301d4fba8b9Smrg break; 5302d522f475Smrg case 'e': 5303d522f475Smrg case 'E': 5304d522f475Smrg fontnum = fontMenu_fontescape; 5305d522f475Smrg break; 5306d522f475Smrg case 's': 5307d522f475Smrg case 'S': 5308d522f475Smrg fontnum = fontMenu_fontsel; 5309d522f475Smrg break; 5310d522f475Smrg default: 5311d522f475Smrg fontnum = -1; 5312d522f475Smrg break; 5313d522f475Smrg } 5314d1603babSmrg TRACE(("xtermGetFont(%s) ->%d\n", param, fontnum)); 5315d522f475Smrg return fontnum; 5316d522f475Smrg} 5317d522f475Smrg 5318d522f475Smrg/* ARGSUSED */ 5319d522f475Smrgvoid 5320d4fba8b9SmrgHandleSetFont(Widget w, 53219a64e1c5Smrg XEvent *event GCC_UNUSED, 5322fa3f02f3Smrg String *params, 5323d522f475Smrg Cardinal *param_count) 5324d522f475Smrg{ 5325956cc18dSsnj XtermWidget xw; 5326956cc18dSsnj 5327190d7dceSmrg if ((xw = getXtermWidget(w)) != NULL) { 5328d522f475Smrg int fontnum; 5329d522f475Smrg VTFontNames fonts; 5330d522f475Smrg 5331d522f475Smrg memset(&fonts, 0, sizeof(fonts)); 5332d522f475Smrg 5333d522f475Smrg if (*param_count == 0) { 5334d522f475Smrg fontnum = fontMenu_default; 5335d522f475Smrg } else { 5336d522f475Smrg Cardinal maxparams = 1; /* total number of params allowed */ 5337d522f475Smrg int result = xtermGetFont(params[0]); 5338d522f475Smrg 5339d522f475Smrg switch (result) { 5340d522f475Smrg case fontMenu_default: /* FALLTHRU */ 5341d522f475Smrg case fontMenu_font1: /* FALLTHRU */ 5342d522f475Smrg case fontMenu_font2: /* FALLTHRU */ 5343d522f475Smrg case fontMenu_font3: /* FALLTHRU */ 5344d522f475Smrg case fontMenu_font4: /* FALLTHRU */ 5345d522f475Smrg case fontMenu_font5: /* FALLTHRU */ 5346d522f475Smrg case fontMenu_font6: /* FALLTHRU */ 5347d4fba8b9Smrg case fontMenu_font7: /* FALLTHRU */ 5348d522f475Smrg break; 5349d522f475Smrg case fontMenu_fontescape: 5350d522f475Smrg#if OPT_WIDE_CHARS 5351d522f475Smrg maxparams = 5; 5352d522f475Smrg#else 5353d522f475Smrg maxparams = 3; 5354d522f475Smrg#endif 5355d522f475Smrg break; 5356d522f475Smrg case fontMenu_fontsel: 5357d522f475Smrg maxparams = 2; 5358d522f475Smrg break; 5359d522f475Smrg default: 536020d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 5361d522f475Smrg return; 5362d522f475Smrg } 5363d522f475Smrg fontnum = result; 5364d522f475Smrg 5365d522f475Smrg if (*param_count > maxparams) { /* see if extra args given */ 536620d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 5367d522f475Smrg return; 5368d522f475Smrg } 5369d522f475Smrg switch (*param_count) { /* assign 'em */ 5370d522f475Smrg#if OPT_WIDE_CHARS 5371d522f475Smrg case 5: 5372dfb07bc7Smrg fonts.f_wb = x_strdup(params[4]); 5373d522f475Smrg /* FALLTHRU */ 5374d522f475Smrg case 4: 5375dfb07bc7Smrg fonts.f_w = x_strdup(params[3]); 5376d522f475Smrg#endif 5377dfb07bc7Smrg /* FALLTHRU */ 5378d522f475Smrg case 3: 5379dfb07bc7Smrg fonts.f_b = x_strdup(params[2]); 5380d522f475Smrg /* FALLTHRU */ 5381d522f475Smrg case 2: 5382dfb07bc7Smrg fonts.f_n = x_strdup(params[1]); 5383d522f475Smrg break; 5384d522f475Smrg } 5385d522f475Smrg } 5386d522f475Smrg 5387956cc18dSsnj SetVTFont(xw, fontnum, True, &fonts); 5388d522f475Smrg } 5389d522f475Smrg} 5390d522f475Smrg 5391d1603babSmrgBool 5392d522f475SmrgSetVTFont(XtermWidget xw, 5393d522f475Smrg int which, 5394d522f475Smrg Bool doresize, 5395d522f475Smrg const VTFontNames * fonts) 5396d522f475Smrg{ 5397956cc18dSsnj TScreen *screen = TScreenOf(xw); 5398d1603babSmrg Bool result = False; 5399d522f475Smrg 5400d522f475Smrg TRACE(("SetVTFont(which=%d, f_n=%s, f_b=%s)\n", which, 5401d522f475Smrg (fonts && fonts->f_n) ? fonts->f_n : "<null>", 5402d522f475Smrg (fonts && fonts->f_b) ? fonts->f_b : "<null>")); 5403d522f475Smrg 5404d522f475Smrg if (IsIcon(screen)) { 540520d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 5406d522f475Smrg } else if (which >= 0 && which < NMENUFONTS) { 5407d1603babSmrg VTFontNames new_fnames; 5408d522f475Smrg 5409d1603babSmrg memset(&new_fnames, 0, sizeof(new_fnames)); 5410190d7dceSmrg if (fonts != NULL) 5411d1603babSmrg new_fnames = *fonts; 5412d522f475Smrg 5413d522f475Smrg if (which == fontMenu_fontsel) { /* go get the selection */ 5414d1603babSmrg result = FindFontSelection(xw, new_fnames.f_n, False); 5415d522f475Smrg } else { 5416d522f475Smrg#define USE_CACHED(field, name) \ 5417d1603babSmrg if (new_fnames.field == NULL) { \ 5418d1603babSmrg new_fnames.field = x_strdup(screen->menu_font_names[which][name]); \ 5419d1603babSmrg TRACE(("set new_fnames." #field " from menu_font_names[%d][" #name "] %s\n", \ 5420d1603babSmrg which, NonNull(new_fnames.field))); \ 5421d522f475Smrg } else { \ 5422d1603babSmrg TRACE(("set new_fnames." #field " reused\n")); \ 5423d522f475Smrg } 542420d2c4d2Smrg#define SAVE_FNAME(field, name) \ 5425d1603babSmrg if (new_fnames.field != NULL \ 5426d1603babSmrg && (screen->menu_font_names[which][name] == NULL \ 5427d1603babSmrg || strcmp(screen->menu_font_names[which][name], new_fnames.field))) { \ 5428d1603babSmrg TRACE(("updating menu_font_names[%d][" #name "] to \"%s\"\n", \ 5429d1603babSmrg which, new_fnames.field)); \ 5430d1603babSmrg FREE_STRING(screen->menu_font_names[which][name]); \ 5431d1603babSmrg screen->menu_font_names[which][name] = x_strdup(new_fnames.field); \ 543220d2c4d2Smrg } 543320d2c4d2Smrg 5434d522f475Smrg USE_CACHED(f_n, fNorm); 5435d522f475Smrg USE_CACHED(f_b, fBold); 5436d522f475Smrg#if OPT_WIDE_CHARS 5437d522f475Smrg USE_CACHED(f_w, fWide); 5438d522f475Smrg USE_CACHED(f_wb, fWBold); 5439d522f475Smrg#endif 5440d522f475Smrg if (xtermLoadFont(xw, 5441d1603babSmrg &new_fnames, 5442d522f475Smrg doresize, which)) { 544320d2c4d2Smrg /* 544420d2c4d2Smrg * If successful, save the data so that a subsequent query via 544520d2c4d2Smrg * OSC-50 will return the expected values. 544620d2c4d2Smrg */ 544720d2c4d2Smrg SAVE_FNAME(f_n, fNorm); 544820d2c4d2Smrg SAVE_FNAME(f_b, fBold); 544920d2c4d2Smrg#if OPT_WIDE_CHARS 545020d2c4d2Smrg SAVE_FNAME(f_w, fWide); 545120d2c4d2Smrg SAVE_FNAME(f_wb, fWBold); 545220d2c4d2Smrg#endif 5453d1603babSmrg result = True; 5454d522f475Smrg } else { 545520d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 5456d522f475Smrg } 54579a64e1c5Smrg FREE_FNAME(f_n); 54589a64e1c5Smrg FREE_FNAME(f_b); 54599a64e1c5Smrg#if OPT_WIDE_CHARS 54609a64e1c5Smrg FREE_FNAME(f_w); 54619a64e1c5Smrg FREE_FNAME(f_wb); 54629a64e1c5Smrg#endif 5463d522f475Smrg } 546420d2c4d2Smrg } else { 546520d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 5466d522f475Smrg } 5467d1603babSmrg TRACE(("...SetVTFont: %d\n", result)); 5468d1603babSmrg return result; 5469d522f475Smrg} 5470dfb07bc7Smrg 5471dfb07bc7Smrg#if OPT_RENDERFONT 5472dfb07bc7Smrgstatic void 5473dfb07bc7SmrgtrimSizeFromFace(char *face_name, float *face_size) 5474dfb07bc7Smrg{ 5475dfb07bc7Smrg char *first = strstr(face_name, ":size="); 5476190d7dceSmrg if (first == NULL) { 5477dfb07bc7Smrg first = face_name; 5478dfb07bc7Smrg } else { 5479dfb07bc7Smrg first++; 5480dfb07bc7Smrg } 5481dfb07bc7Smrg if (!strncmp(first, "size=", (size_t) 5)) { 5482dfb07bc7Smrg char *last = strchr(first, ':'); 5483dfb07bc7Smrg char mark; 5484dfb07bc7Smrg float value; 5485dfb07bc7Smrg char extra; 5486dfb07bc7Smrg TRACE(("...before trimming, font = \"%s\"\n", face_name)); 5487190d7dceSmrg if (last == NULL) 5488dfb07bc7Smrg last = first + strlen(first); 5489dfb07bc7Smrg mark = *last; 5490dfb07bc7Smrg *last = '\0'; 5491dfb07bc7Smrg if (sscanf(first, "size=%g%c", &value, &extra) == 1) { 5492dfb07bc7Smrg TRACE(("...trimmed size from font: %g\n", value)); 5493190d7dceSmrg if (face_size != NULL) 5494dfb07bc7Smrg *face_size = value; 5495dfb07bc7Smrg } 5496dfb07bc7Smrg if (mark) { 5497dfb07bc7Smrg while ((*first++ = *++last) != '\0') { 5498dfb07bc7Smrg ; 5499dfb07bc7Smrg } 5500dfb07bc7Smrg } else { 5501dfb07bc7Smrg if (first != face_name) 5502dfb07bc7Smrg --first; 5503dfb07bc7Smrg *first = '\0'; 5504dfb07bc7Smrg } 5505dfb07bc7Smrg TRACE(("...after trimming, font = \"%s\"\n", face_name)); 5506dfb07bc7Smrg } 5507dfb07bc7Smrg} 5508dfb07bc7Smrg#endif 5509dfb07bc7Smrg 5510dfb07bc7Smrg/* 5511dfb07bc7Smrg * Save a font specification to the proper list. 5512dfb07bc7Smrg */ 5513dfb07bc7Smrgstatic void 5514dfb07bc7Smrgsave2FontList(XtermWidget xw, 5515dfb07bc7Smrg const char *name, 5516dfb07bc7Smrg XtermFontNames * fontnames, 5517dfb07bc7Smrg VTFontEnum which, 5518dfb07bc7Smrg const char *source, 5519d1603babSmrg Bool check, 5520dfb07bc7Smrg Bool ttf) 5521dfb07bc7Smrg{ 5522dfb07bc7Smrg char *value; 5523dfb07bc7Smrg size_t plen; 5524dfb07bc7Smrg Bool marked = False; 5525dfb07bc7Smrg Bool use_ttf = ttf; 5526dfb07bc7Smrg 5527dfb07bc7Smrg (void) xw; 5528dfb07bc7Smrg 5529190d7dceSmrg if (source == NULL) 5530dfb07bc7Smrg source = ""; 5531dfb07bc7Smrg while (isspace(CharOf(*source))) 5532dfb07bc7Smrg ++source; 5533dfb07bc7Smrg 5534dfb07bc7Smrg /* fontconfig patterns can contain ':' separators, but we'll treat 5535dfb07bc7Smrg * a leading prefix specially to denote whether the pattern might be 5536dfb07bc7Smrg * XLFD ("x" or "xlfd") versus Xft ("xft"). 5537dfb07bc7Smrg */ 5538dfb07bc7Smrg for (plen = 0; source[plen] != '\0'; ++plen) { 5539dfb07bc7Smrg if (source[plen] == ':') { 5540dfb07bc7Smrg marked = True; 5541dfb07bc7Smrg switch (plen) { 5542dfb07bc7Smrg case 0: 5543dfb07bc7Smrg ++plen; /* trim leading ':' */ 5544dfb07bc7Smrg break; 5545dfb07bc7Smrg case 1: 5546dfb07bc7Smrg if (!strncmp(source, "x", plen)) { 5547dfb07bc7Smrg ++plen; 5548dfb07bc7Smrg use_ttf = False; 5549dfb07bc7Smrg } else { 5550dfb07bc7Smrg marked = False; 5551dfb07bc7Smrg } 5552dfb07bc7Smrg break; 5553dfb07bc7Smrg case 3: 5554dfb07bc7Smrg if (!strncmp(source, "xft", plen)) { 5555dfb07bc7Smrg ++plen; 5556dfb07bc7Smrg use_ttf = True; 5557dfb07bc7Smrg } else { 5558dfb07bc7Smrg marked = False; 5559dfb07bc7Smrg } 5560dfb07bc7Smrg break; 5561dfb07bc7Smrg case 4: 5562dfb07bc7Smrg if (!strncmp(source, "xlfd", plen)) { 5563dfb07bc7Smrg ++plen; 5564dfb07bc7Smrg use_ttf = False; 5565dfb07bc7Smrg } else { 5566dfb07bc7Smrg marked = False; 5567dfb07bc7Smrg } 5568dfb07bc7Smrg break; 5569dfb07bc7Smrg default: 5570dfb07bc7Smrg marked = False; 5571dfb07bc7Smrg plen = 0; 5572dfb07bc7Smrg break; 5573dfb07bc7Smrg } 5574dfb07bc7Smrg break; 5575dfb07bc7Smrg } 5576dfb07bc7Smrg } 5577dfb07bc7Smrg if (!marked) 5578dfb07bc7Smrg plen = 0; 5579dfb07bc7Smrg value = x_strtrim(source + plen); 5580190d7dceSmrg if (value != NULL) { 5581dfb07bc7Smrg Bool success = False; 5582dfb07bc7Smrg#if OPT_RENDERFONT 5583dfb07bc7Smrg VTFontList *target = (use_ttf 5584dfb07bc7Smrg ? &(fontnames->xft) 5585dfb07bc7Smrg : &(fontnames->x11)); 5586dfb07bc7Smrg#else 5587dfb07bc7Smrg VTFontList *target = &(fontnames->x11); 5588dfb07bc7Smrg#endif 5589190d7dceSmrg char ***list = NULL; 5590190d7dceSmrg char **next = NULL; 5591dfb07bc7Smrg size_t count = 0; 5592dfb07bc7Smrg 5593dfb07bc7Smrg (void) use_ttf; 5594dfb07bc7Smrg switch (which) { 5595dfb07bc7Smrg case fNorm: 5596dfb07bc7Smrg list = &(target->list_n); 5597dfb07bc7Smrg break; 5598dfb07bc7Smrg case fBold: 5599dfb07bc7Smrg list = &(target->list_b); 5600dfb07bc7Smrg break; 5601dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5602dfb07bc7Smrg case fItal: 5603dfb07bc7Smrg list = &(target->list_i); 5604dfb07bc7Smrg break; 5605d4fba8b9Smrg case fBtal: 5606d4fba8b9Smrg list = &(target->list_bi); 5607d4fba8b9Smrg break; 5608dfb07bc7Smrg#endif 5609dfb07bc7Smrg#if OPT_WIDE_CHARS 5610dfb07bc7Smrg case fWide: 5611dfb07bc7Smrg list = &(target->list_w); 5612dfb07bc7Smrg break; 5613dfb07bc7Smrg case fWBold: 5614dfb07bc7Smrg list = &(target->list_wb); 5615dfb07bc7Smrg break; 5616dfb07bc7Smrg case fWItal: 5617dfb07bc7Smrg list = &(target->list_wi); 5618dfb07bc7Smrg break; 5619d4fba8b9Smrg case fWBtal: 5620d4fba8b9Smrg list = &(target->list_wbi); 5621d4fba8b9Smrg break; 5622dfb07bc7Smrg#endif 5623dfb07bc7Smrg case fMAX: 5624190d7dceSmrg list = NULL; 5625dfb07bc7Smrg break; 5626dfb07bc7Smrg } 5627dfb07bc7Smrg 5628190d7dceSmrg if (list != NULL) { 5629dfb07bc7Smrg success = True; 5630190d7dceSmrg if (*list != NULL) { 5631190d7dceSmrg while ((*list)[count] != NULL) { 5632dfb07bc7Smrg if (IsEmpty((*list)[count])) { 5633dfb07bc7Smrg TRACE(("... initial %s\n", value)); 5634dfb07bc7Smrg free((*list)[count]); 5635dfb07bc7Smrg break; 5636dfb07bc7Smrg } else if (!strcmp(value, (*list)[count])) { 5637dfb07bc7Smrg TRACE(("... duplicate %s\n", value)); 5638dfb07bc7Smrg success = False; 5639dfb07bc7Smrg break; 5640dfb07bc7Smrg } 5641dfb07bc7Smrg ++count; 5642dfb07bc7Smrg } 5643dfb07bc7Smrg } 5644dfb07bc7Smrg if (success) { 5645d1603babSmrg next = (char **) realloc(*list, sizeof(char *) * (count + 2)); 5646190d7dceSmrg if (next != NULL) { 5647dfb07bc7Smrg#if OPT_RENDERFONT 5648dfb07bc7Smrg if (use_ttf) { 5649dfb07bc7Smrg trimSizeFromFace(value, 5650dfb07bc7Smrg (count == 0 && which == fNorm) 5651dfb07bc7Smrg ? &(xw->misc.face_size[0]) 5652dfb07bc7Smrg : (float *) 0); 5653dfb07bc7Smrg } 5654dfb07bc7Smrg#endif 5655dfb07bc7Smrg next[count++] = value; 5656190d7dceSmrg next[count] = NULL; 5657dfb07bc7Smrg *list = next; 56588f44fb3bSmrg TRACE(("... saved \"%s\" \"%s\" %lu:\"%s\"\n", 5659dfb07bc7Smrg whichFontList(xw, target), 5660dfb07bc7Smrg whichFontList2(xw, *list), 5661dfb07bc7Smrg (unsigned long) count, 5662dfb07bc7Smrg value)); 5663dfb07bc7Smrg } else { 5664d1603babSmrg xtermWarning("realloc failure in save2FontList(%s)\n", name); 5665dfb07bc7Smrg freeFontList(list); 5666dfb07bc7Smrg success = False; 5667dfb07bc7Smrg } 5668dfb07bc7Smrg } 5669dfb07bc7Smrg } 5670dfb07bc7Smrg if (success) { 5671d4fba8b9Smrg#if (MAX_XFT_FONTS == MAX_XLFD_FONTS) 5672d4fba8b9Smrg size_t limit = MAX_XFT_FONTS; 5673d4fba8b9Smrg#else 5674dfb07bc7Smrg size_t limit = use_ttf ? MAX_XFT_FONTS : MAX_XLFD_FONTS; 5675d4fba8b9Smrg#endif 5676d4fba8b9Smrg if (count > limit && *x_skip_blanks(value)) { 5677d1603babSmrg if (check) { 5678d1603babSmrg xtermWarning("too many fonts for %s, ignoring %s\n", 5679d1603babSmrg whichFontEnum(which), 5680d1603babSmrg value); 5681d1603babSmrg } 5682dfb07bc7Smrg if (list && *list) { 5683dfb07bc7Smrg free((*list)[limit]); 5684190d7dceSmrg (*list)[limit] = NULL; 5685dfb07bc7Smrg } 5686dfb07bc7Smrg } 5687dfb07bc7Smrg } else { 5688dfb07bc7Smrg free(value); 5689dfb07bc7Smrg } 5690dfb07bc7Smrg } 5691dfb07bc7Smrg} 5692dfb07bc7Smrg 5693dfb07bc7Smrg/* 5694dfb07bc7Smrg * In principle, any of the font-name resources could be extended to be a list 5695dfb07bc7Smrg * of font-names. That would be bad for performance, but as a basis for an 5696dfb07bc7Smrg * extension, parse the font-name as a comma-separated list, creating/updating 5697dfb07bc7Smrg * an array of font-names. 5698dfb07bc7Smrg */ 5699dfb07bc7Smrgvoid 5700dfb07bc7SmrgallocFontList(XtermWidget xw, 5701dfb07bc7Smrg const char *name, 5702dfb07bc7Smrg XtermFontNames * target, 5703dfb07bc7Smrg VTFontEnum which, 5704dfb07bc7Smrg const char *source, 5705dfb07bc7Smrg Bool ttf) 5706dfb07bc7Smrg{ 5707dfb07bc7Smrg char *blob; 5708dfb07bc7Smrg 5709dfb07bc7Smrg blob = x_strdup(source); 5710190d7dceSmrg if (blob != NULL) { 5711dfb07bc7Smrg int n; 5712dfb07bc7Smrg int pass; 5713190d7dceSmrg char **list = NULL; 5714dfb07bc7Smrg 57158f44fb3bSmrg TRACE(("allocFontList %s name=\"%s\" source=\"%s\"\n", 57168f44fb3bSmrg whichFontEnum(which), name, blob)); 5717dfb07bc7Smrg 5718dfb07bc7Smrg for (pass = 0; pass < 2; ++pass) { 5719dfb07bc7Smrg unsigned count = 0; 5720dfb07bc7Smrg if (pass) 5721dfb07bc7Smrg list[0] = blob; 5722dfb07bc7Smrg for (n = 0; blob[n] != '\0'; ++n) { 5723dfb07bc7Smrg if (blob[n] == ',') { 5724dfb07bc7Smrg ++count; 5725dfb07bc7Smrg if (pass != 0) { 5726dfb07bc7Smrg blob[n] = '\0'; 5727dfb07bc7Smrg list[count] = blob + n + 1; 5728dfb07bc7Smrg } 5729dfb07bc7Smrg } 5730dfb07bc7Smrg } 5731dfb07bc7Smrg if (!pass) { 5732dfb07bc7Smrg if (count == 0 && *blob == '\0') 5733dfb07bc7Smrg break; 5734dfb07bc7Smrg list = TypeCallocN(char *, count + 2); 5735190d7dceSmrg if (list == NULL) 5736dfb07bc7Smrg break; 5737dfb07bc7Smrg } 5738dfb07bc7Smrg } 5739dfb07bc7Smrg if (list) { 5740190d7dceSmrg for (n = 0; list[n] != NULL; ++n) { 5741dfb07bc7Smrg if (*list[n]) { 5742d1603babSmrg save2FontList(xw, name, target, which, list[n], True, ttf); 5743dfb07bc7Smrg } 5744dfb07bc7Smrg } 5745dfb07bc7Smrg free(list); 5746dfb07bc7Smrg } 5747dfb07bc7Smrg } 5748dfb07bc7Smrg free(blob); 5749dfb07bc7Smrg} 5750dfb07bc7Smrg 5751dfb07bc7Smrgstatic void 5752dfb07bc7SmrginitFontList(XtermWidget xw, 5753dfb07bc7Smrg const char *name, 5754dfb07bc7Smrg XtermFontNames * target, 5755dfb07bc7Smrg Bool ttf) 5756dfb07bc7Smrg{ 5757dfb07bc7Smrg int which; 5758dfb07bc7Smrg 5759dfb07bc7Smrg TRACE(("initFontList(%s)\n", name)); 5760dfb07bc7Smrg for (which = 0; which < fMAX; ++which) { 5761d1603babSmrg save2FontList(xw, name, target, (VTFontEnum) which, "", False, ttf); 5762dfb07bc7Smrg } 5763dfb07bc7Smrg} 5764dfb07bc7Smrg 5765dfb07bc7Smrgvoid 5766dfb07bc7SmrginitFontLists(XtermWidget xw) 5767dfb07bc7Smrg{ 5768dfb07bc7Smrg TRACE(("initFontLists\n")); 5769dfb07bc7Smrg initFontList(xw, "x11 font", &(xw->work.fonts), False); 5770dfb07bc7Smrg#if OPT_RENDERFONT 5771dfb07bc7Smrg initFontList(xw, "xft font", &(xw->work.fonts), True); 5772dfb07bc7Smrg#endif 5773dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 5774dfb07bc7Smrg initFontList(xw, "cached font", 5775dfb07bc7Smrg &(xw->screen.cacheVTFonts.fonts), False); 5776dfb07bc7Smrg#endif 5777dfb07bc7Smrg} 5778dfb07bc7Smrg 5779dfb07bc7Smrgvoid 5780dfb07bc7SmrgcopyFontList(char ***targetp, char **source) 5781dfb07bc7Smrg{ 5782dfb07bc7Smrg freeFontList(targetp); 5783dfb07bc7Smrg 5784190d7dceSmrg if (source != NULL) { 5785dfb07bc7Smrg int pass; 5786dfb07bc7Smrg size_t count; 5787dfb07bc7Smrg 5788dfb07bc7Smrg for (pass = 0; pass < 2; ++pass) { 5789190d7dceSmrg for (count = 0; source[count] != NULL; ++count) { 5790dfb07bc7Smrg if (pass) 5791dfb07bc7Smrg (*targetp)[count] = x_strdup(source[count]); 5792dfb07bc7Smrg } 5793dfb07bc7Smrg if (!pass) { 5794dfb07bc7Smrg ++count; 5795dfb07bc7Smrg *targetp = TypeCallocN(char *, count); 5796dfb07bc7Smrg } 5797dfb07bc7Smrg } 5798dfb07bc7Smrg } else { 5799dfb07bc7Smrg *targetp = TypeCallocN(char *, 2); 5800dfb07bc7Smrg (*targetp)[0] = x_strdup(""); 5801dfb07bc7Smrg } 5802dfb07bc7Smrg} 5803dfb07bc7Smrg 5804dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 5805dfb07bc7Smrgstatic Boolean 5806dfb07bc7Smrgmerge_sublist(char ***targetp, char **source) 5807dfb07bc7Smrg{ 5808dfb07bc7Smrg Boolean result = False; 5809190d7dceSmrg if ((*targetp == NULL || IsEmpty(**targetp)) && !IsEmpty(*source)) { 5810dfb07bc7Smrg copyFontList(targetp, source); 5811dfb07bc7Smrg result = True; 5812dfb07bc7Smrg } 5813dfb07bc7Smrg return result; 5814dfb07bc7Smrg} 5815dfb07bc7Smrg#endif 5816dfb07bc7Smrg 5817dfb07bc7Smrgvoid 5818dfb07bc7SmrgfreeFontList(char ***targetp) 5819dfb07bc7Smrg{ 5820190d7dceSmrg if (targetp != NULL) { 5821dfb07bc7Smrg char **target = *targetp; 5822190d7dceSmrg if (target != NULL) { 5823dfb07bc7Smrg int n; 5824190d7dceSmrg for (n = 0; target[n] != NULL; ++n) { 5825dfb07bc7Smrg free(target[n]); 5826dfb07bc7Smrg } 5827dfb07bc7Smrg free(target); 5828190d7dceSmrg *targetp = NULL; 5829dfb07bc7Smrg } 5830dfb07bc7Smrg } 5831dfb07bc7Smrg} 5832dfb07bc7Smrg 5833dfb07bc7Smrgvoid 5834dfb07bc7SmrgfreeFontLists(VTFontList * lists) 5835dfb07bc7Smrg{ 5836dfb07bc7Smrg int which; 5837dfb07bc7Smrg 5838dfb07bc7Smrg TRACE(("freeFontLists\n")); 5839dfb07bc7Smrg for (which = 0; which < fMAX; ++which) { 5840190d7dceSmrg char ***target = NULL; 5841dfb07bc7Smrg switch (which) { 5842dfb07bc7Smrg case fNorm: 5843dfb07bc7Smrg target = &(lists->list_n); 5844dfb07bc7Smrg break; 5845dfb07bc7Smrg case fBold: 5846dfb07bc7Smrg target = &(lists->list_b); 5847dfb07bc7Smrg break; 5848dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5849dfb07bc7Smrg case fItal: 5850dfb07bc7Smrg target = &(lists->list_i); 5851dfb07bc7Smrg break; 5852d4fba8b9Smrg case fBtal: 5853d4fba8b9Smrg target = &(lists->list_bi); 5854d4fba8b9Smrg break; 5855dfb07bc7Smrg#endif 5856dfb07bc7Smrg#if OPT_WIDE_CHARS 5857dfb07bc7Smrg case fWide: 5858dfb07bc7Smrg target = &(lists->list_w); 5859dfb07bc7Smrg break; 5860dfb07bc7Smrg case fWBold: 5861dfb07bc7Smrg target = &(lists->list_wb); 5862dfb07bc7Smrg break; 5863dfb07bc7Smrg case fWItal: 5864dfb07bc7Smrg target = &(lists->list_wi); 5865dfb07bc7Smrg break; 5866d4fba8b9Smrg case fWBtal: 5867d4fba8b9Smrg target = &(lists->list_wbi); 5868d4fba8b9Smrg break; 5869dfb07bc7Smrg#endif 5870dfb07bc7Smrg default: 5871190d7dceSmrg target = NULL; 5872dfb07bc7Smrg break; 5873dfb07bc7Smrg } 5874dfb07bc7Smrg freeFontList(target); 5875dfb07bc7Smrg } 5876dfb07bc7Smrg} 5877dfb07bc7Smrg 5878dfb07bc7Smrg/* 5879dfb07bc7Smrg * Return a pointer to the XLFD font information for a given font class. 5880dfb07bc7Smrg * XXX make this allocate the font on demand. 5881dfb07bc7Smrg */ 5882dfb07bc7SmrgXTermFonts * 5883dfb07bc7SmrggetNormalFont(TScreen *screen, int which) 5884dfb07bc7Smrg{ 5885190d7dceSmrg XTermFonts *result = NULL; 5886dfb07bc7Smrg if (which >= 0 && which < fMAX) 5887d4fba8b9Smrg result = GetNormalFont(screen, which); 5888dfb07bc7Smrg return result; 5889dfb07bc7Smrg} 5890dfb07bc7Smrg 5891dfb07bc7Smrg#if OPT_DEC_CHRSET 5892dfb07bc7SmrgXTermFonts * 5893dfb07bc7SmrggetDoubleFont(TScreen *screen, int which) 5894dfb07bc7Smrg{ 5895190d7dceSmrg XTermFonts *result = NULL; 5896dfb07bc7Smrg if ((int) which >= 0 && which < NUM_CHRSET) 5897d4fba8b9Smrg result = GetDoubleFont(screen, which); 5898d4fba8b9Smrg return result; 5899d4fba8b9Smrg} 5900d4fba8b9Smrg 5901d4fba8b9Smrg#if OPT_RENDERFONT 5902d1603babSmrgvoid 5903d1603babSmrggetDoubleXftFont(XTermDraw * params, XTermXftFonts *data, unsigned chrset, unsigned attr_flags) 5904d4fba8b9Smrg{ 5905d4fba8b9Smrg XtermWidget xw = params->xw; 5906d4fba8b9Smrg TScreen *screen = TScreenOf(xw); 5907d4fba8b9Smrg XftPattern *top_pattern; 5908d4fba8b9Smrg int fontnum = screen->menu_font_number; 5909d4fba8b9Smrg const char *face_name = getFaceName(xw, False); 5910d4fba8b9Smrg 5911d4fba8b9Smrg if (chrset != CSET_SWL 5912190d7dceSmrg && (top_pattern = XftNameParse(face_name)) != NULL) { 5913d4fba8b9Smrg double face_size = (double) xw->misc.face_size[fontnum]; 5914d4fba8b9Smrg XftPattern *sub_pattern = XftPatternDuplicate(top_pattern); 5915d1603babSmrg const char *category = "doublesize"; 5916d4fba8b9Smrg 5917d4fba8b9Smrg switch (chrset) { 5918d4fba8b9Smrg case CSET_DHL_TOP: 5919d1603babSmrg category = "DHL_TOP"; 5920d1603babSmrg goto double_high; 5921d4fba8b9Smrg case CSET_DHL_BOT: 5922d1603babSmrg category = "DHL_BOT"; 5923d1603babSmrg double_high: 5924d4fba8b9Smrg face_size *= 2; 5925d4fba8b9Smrg XftPatternBuild(sub_pattern, 5926d4fba8b9Smrg NormXftPattern, 5927d4fba8b9Smrg (void *) 0); 5928d4fba8b9Smrg break; 5929d4fba8b9Smrg case CSET_DWL: 5930d1603babSmrg category = "DWL"; 5931d4fba8b9Smrg XftPatternBuild(sub_pattern, 5932d4fba8b9Smrg NormXftPattern, 5933d4fba8b9Smrg FC_ASPECT, XftTypeDouble, 2.0, 5934d4fba8b9Smrg (void *) 0); 5935d4fba8b9Smrg break; 5936d4fba8b9Smrg } 5937d4fba8b9Smrg if (attr_flags & BOLD) { 5938d4fba8b9Smrg XftPatternBuild(sub_pattern, 5939d4fba8b9Smrg XFT_WEIGHT, XftTypeInteger, XFT_WEIGHT_BOLD, 5940d4fba8b9Smrg (void *) 0); 5941d4fba8b9Smrg } 5942d1603babSmrg xtermOpenXft(xw, data, 0, face_name, sub_pattern, category); 5943d1603babSmrg data->pattern = sub_pattern; 5944d4fba8b9Smrg } 5945dfb07bc7Smrg} 5946dfb07bc7Smrg#endif 5947d4fba8b9Smrg#endif /* OPT_DEC_CHRSET */ 5948dfb07bc7Smrg 5949dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5950dfb07bc7SmrgXTermFonts * 5951dfb07bc7SmrggetItalicFont(TScreen *screen, int which) 5952dfb07bc7Smrg{ 5953190d7dceSmrg XTermFonts *result = NULL; 5954dfb07bc7Smrg#if OPT_WIDE_ATTRS 5955dfb07bc7Smrg if (which >= 0 && which < fMAX) 5956d4fba8b9Smrg result = GetItalicFont(screen, which); 5957dfb07bc7Smrg#else 5958dfb07bc7Smrg (void) screen; 5959dfb07bc7Smrg (void) which; 5960dfb07bc7Smrg#endif 5961dfb07bc7Smrg return result; 5962dfb07bc7Smrg} 5963dfb07bc7Smrg#endif 5964dfb07bc7Smrg 5965dfb07bc7Smrg#if OPT_RENDERFONT 5966dfb07bc7Smrg/* 5967dfb07bc7Smrg * This returns a pointer to everything known about a given Xft font. 5968dfb07bc7Smrg * XXX make this allocate the font on demand. 5969dfb07bc7Smrg */ 5970dfb07bc7SmrgXTermXftFonts * 5971dfb07bc7SmrggetMyXftFont(XtermWidget xw, int which, int fontnum) 5972dfb07bc7Smrg{ 5973dfb07bc7Smrg TScreen *screen = TScreenOf(xw); 5974190d7dceSmrg XTermXftFonts *result = NULL; 5975dfb07bc7Smrg if (fontnum >= 0 && fontnum < NMENUFONTS) { 5976dfb07bc7Smrg switch ((VTFontEnum) which) { 5977dfb07bc7Smrg case fNorm: 5978dfb07bc7Smrg result = &(screen->renderFontNorm[fontnum]); 5979dfb07bc7Smrg break; 5980dfb07bc7Smrg case fBold: 5981dfb07bc7Smrg result = &(screen->renderFontBold[fontnum]); 5982dfb07bc7Smrg break; 5983dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 5984dfb07bc7Smrg case fItal: 5985dfb07bc7Smrg result = &(screen->renderFontItal[fontnum]); 5986dfb07bc7Smrg break; 5987d4fba8b9Smrg case fBtal: 5988d4fba8b9Smrg result = &(screen->renderFontBtal[fontnum]); 5989d4fba8b9Smrg break; 5990dfb07bc7Smrg#endif 5991dfb07bc7Smrg#if OPT_WIDE_CHARS 5992dfb07bc7Smrg case fWide: 5993dfb07bc7Smrg result = &(screen->renderWideNorm[fontnum]); 5994dfb07bc7Smrg break; 5995dfb07bc7Smrg case fWBold: 5996dfb07bc7Smrg result = &(screen->renderWideBold[fontnum]); 5997dfb07bc7Smrg break; 5998dfb07bc7Smrg case fWItal: 5999dfb07bc7Smrg result = &(screen->renderWideItal[fontnum]); 6000dfb07bc7Smrg break; 6001d4fba8b9Smrg case fWBtal: 6002d4fba8b9Smrg result = &(screen->renderWideBtal[fontnum]); 6003d4fba8b9Smrg break; 6004dfb07bc7Smrg#endif 6005dfb07bc7Smrg case fMAX: 6006dfb07bc7Smrg break; 6007dfb07bc7Smrg } 6008dfb07bc7Smrg } 6009dfb07bc7Smrg return result; 6010dfb07bc7Smrg} 6011dfb07bc7Smrg 6012d1603babSmrgconst char * 6013190d7dceSmrgwhichXftFonts(XtermWidget xw, const XTermXftFonts *data) 6014d1603babSmrg{ 6015d1603babSmrg TScreen *screen = TScreenOf(xw); 6016d1603babSmrg const char *result = "?"; 6017d1603babSmrg#define CHECK(name) ((data >= &(screen->name[0])) && (data < &(screen->name[NMENUFONTS]))) result = #name 6018d1603babSmrg if CHECK 6019d1603babSmrg (renderFontNorm); 6020d1603babSmrg else if CHECK 6021d1603babSmrg (renderFontBold); 6022d1603babSmrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 6023d1603babSmrg else if CHECK 6024d1603babSmrg (renderFontItal); 6025d1603babSmrg else if CHECK 6026d1603babSmrg (renderFontBtal); 6027d1603babSmrg#endif 6028d1603babSmrg#if OPT_WIDE_CHARS 6029d1603babSmrg else if CHECK 6030d1603babSmrg (renderWideNorm); 6031d1603babSmrg else if CHECK 6032d1603babSmrg (renderWideBold); 6033d1603babSmrg else if CHECK 6034d1603babSmrg (renderWideItal); 6035d1603babSmrg else if CHECK 6036d1603babSmrg (renderWideBtal); 6037d1603babSmrg#endif 6038d1603babSmrg#if OPT_DEC_CHRSET 6039d1603babSmrg#if OPT_RENDERFONT 6040d1603babSmrg else { 6041d1603babSmrg int n; 6042d1603babSmrg for (n = 0; n < NUM_CHRSET; ++n) { 6043d1603babSmrg if (data == &screen->double_xft_fonts[n]) { 6044d1603babSmrg result = "double_xft_fonts"; 6045d1603babSmrg break; 6046d1603babSmrg } 6047d1603babSmrg } 6048d1603babSmrg } 6049d1603babSmrg#endif 6050d1603babSmrg#endif /* OPT_DEC_CHRSET */ 6051d1603babSmrg return result; 6052d1603babSmrg} 6053d1603babSmrg 6054dfb07bc7SmrgXftFont * 6055dfb07bc7SmrggetXftFont(XtermWidget xw, VTFontEnum which, int fontnum) 6056dfb07bc7Smrg{ 6057d4fba8b9Smrg XTermXftFonts *data = getMyXftFont(xw, (int) which, fontnum); 6058190d7dceSmrg XftFont *result = NULL; 6059190d7dceSmrg if (data != NULL) 6060d1603babSmrg result = XftFp(data); 6061dfb07bc7Smrg return result; 6062dfb07bc7Smrg} 6063dfb07bc7Smrg#endif 6064dfb07bc7Smrg 6065dfb07bc7Smrgconst char * 6066dfb07bc7SmrgwhichFontEnum(VTFontEnum value) 6067dfb07bc7Smrg{ 6068dfb07bc7Smrg const char *result = "?"; 6069dfb07bc7Smrg#define DATA(name) case name: result = #name; break 6070dfb07bc7Smrg switch (value) { 6071dfb07bc7Smrg DATA(fNorm); 6072dfb07bc7Smrg DATA(fBold); 6073dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 6074dfb07bc7Smrg DATA(fItal); 6075d4fba8b9Smrg DATA(fBtal); 6076dfb07bc7Smrg#endif 6077dfb07bc7Smrg#if OPT_WIDE_CHARS 6078dfb07bc7Smrg DATA(fWide); 6079dfb07bc7Smrg DATA(fWBold); 6080dfb07bc7Smrg DATA(fWItal); 6081d4fba8b9Smrg DATA(fWBtal); 6082dfb07bc7Smrg#endif 6083dfb07bc7Smrg DATA(fMAX); 6084dfb07bc7Smrg } 6085dfb07bc7Smrg#undef DATA 6086dfb07bc7Smrg return result; 6087dfb07bc7Smrg} 6088dfb07bc7Smrg 6089dfb07bc7Smrgconst char * 6090190d7dceSmrgwhichFontList(XtermWidget xw, const VTFontList * value) 6091dfb07bc7Smrg{ 6092dfb07bc7Smrg const char *result = "?"; 6093dfb07bc7Smrg if (value == &(xw->work.fonts.x11)) 6094dfb07bc7Smrg result = "x11_fontnames"; 6095dfb07bc7Smrg#if OPT_RENDERFONT 6096dfb07bc7Smrg else if (value == &(xw->work.fonts.xft)) 6097dfb07bc7Smrg result = "xft_fontnames"; 6098dfb07bc7Smrg#endif 6099dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 6100dfb07bc7Smrg else if (value == &(xw->screen.cacheVTFonts.fonts.x11)) 6101dfb07bc7Smrg result = "cached_fontnames"; 6102dfb07bc7Smrg#endif 6103dfb07bc7Smrg return result; 6104dfb07bc7Smrg} 6105dfb07bc7Smrg 6106dfb07bc7Smrgstatic const char * 6107dfb07bc7SmrgwhichFontList2s(VTFontList * list, char **value) 6108dfb07bc7Smrg{ 6109190d7dceSmrg const char *result = NULL; 6110dfb07bc7Smrg#define DATA(name) if (value == (list->name)) result = #name 6111dfb07bc7Smrg DATA(list_n); 6112dfb07bc7Smrg DATA(list_b); 6113dfb07bc7Smrg#if OPT_WIDE_ATTRS || OPT_RENDERWIDE 6114dfb07bc7Smrg DATA(list_i); 6115d4fba8b9Smrg DATA(list_bi); 6116dfb07bc7Smrg#endif 6117dfb07bc7Smrg#if OPT_WIDE_CHARS 6118dfb07bc7Smrg DATA(list_w); 6119dfb07bc7Smrg DATA(list_wb); 6120dfb07bc7Smrg DATA(list_wi); 6121d4fba8b9Smrg DATA(list_wbi); 6122dfb07bc7Smrg#endif 6123dfb07bc7Smrg#undef DATA 6124dfb07bc7Smrg return result; 6125dfb07bc7Smrg} 6126dfb07bc7Smrg 6127dfb07bc7Smrgconst char * 6128dfb07bc7SmrgwhichFontList2(XtermWidget xw, char **value) 6129dfb07bc7Smrg{ 6130190d7dceSmrg const char *result = NULL; 6131dfb07bc7Smrg#define DATA(name) (result = whichFontList2s(&(xw->name), value)) 6132190d7dceSmrg if (DATA(work.fonts.x11) == NULL) { 6133dfb07bc7Smrg#if OPT_RENDERFONT 6134190d7dceSmrg if (DATA(work.fonts.xft) == NULL) 6135dfb07bc7Smrg#endif 6136dfb07bc7Smrg#if OPT_LOAD_VTFONTS || OPT_WIDE_CHARS 6137190d7dceSmrg if (DATA(screen.cacheVTFonts.fonts.x11) == NULL) 6138dfb07bc7Smrg#endif 6139dfb07bc7Smrg result = "?"; 6140dfb07bc7Smrg } 6141dfb07bc7Smrg#undef DATA 6142dfb07bc7Smrg return result; 6143dfb07bc7Smrg} 6144