xftdpy.c revision da9cf437
1/* 2 * Copyright © 2000 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that 7 * copyright notice and this permission notice appear in supporting 8 * documentation, and that the name of Keith Packard not be used in 9 * advertising or publicity pertaining to distribution of the software without 10 * specific, written prior permission. Keith Packard makes no 11 * representations about the suitability of this software for any purpose. It 12 * is provided "as is" without express or implied warranty. 13 * 14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20 * PERFORMANCE OF THIS SOFTWARE. 21 */ 22 23#include "xftint.h" 24 25_X_HIDDEN XftDisplayInfo *_XftDisplayInfo; 26 27static int 28_XftCloseDisplay (Display *dpy, XExtCodes *codes) 29{ 30 XftDisplayInfo *info, **prev; 31 32 info = _XftDisplayInfoGet (dpy, FcFalse); 33 if (!info) 34 return 0; 35 36 /* 37 * Get rid of any dangling unreferenced fonts 38 */ 39 info->max_unref_fonts = 0; 40 XftFontManageMemory (dpy); 41 42 /* 43 * Clean up the default values 44 */ 45 if (info->defaults) 46 FcPatternDestroy (info->defaults); 47 48 /* 49 * Unhook from the global list 50 */ 51 for (prev = &_XftDisplayInfo; (info = *prev); prev = &(*prev)->next) 52 if (info->display == dpy) 53 break; 54 *prev = info->next; 55 56 free (info); 57 return 0; 58} 59 60 61_X_HIDDEN XftDisplayInfo * 62_XftDisplayInfoGet (Display *dpy, FcBool createIfNecessary) 63{ 64 XftDisplayInfo *info, **prev; 65 XRenderPictFormat pf; 66 int i; 67 int event_base, error_base; 68 69 for (prev = &_XftDisplayInfo; (info = *prev); prev = &(*prev)->next) 70 { 71 if (info->display == dpy) 72 { 73 /* 74 * MRU the list 75 */ 76 if (prev != &_XftDisplayInfo) 77 { 78 *prev = info->next; 79 info->next = _XftDisplayInfo; 80 _XftDisplayInfo = info; 81 } 82 return info; 83 } 84 } 85 if (!createIfNecessary) 86 return NULL; 87 88 info = (XftDisplayInfo *) malloc (sizeof (XftDisplayInfo)); 89 if (!info) 90 goto bail0; 91 info->codes = XAddExtension (dpy); 92 if (!info->codes) 93 goto bail1; 94 (void) XESetCloseDisplay (dpy, info->codes->extension, _XftCloseDisplay); 95 96 info->display = dpy; 97 info->defaults = NULL; 98 info->solidFormat = NULL; 99 info->hasRender = (XRenderQueryExtension (dpy, &event_base, &error_base) && 100 (XRenderFindVisualFormat (dpy, DefaultVisual (dpy, DefaultScreen (dpy))) != NULL)); 101 info->use_free_glyphs = FcTrue; 102 if (info->hasRender) 103 { 104 int major, minor; 105 XRenderQueryVersion (dpy, &major, &minor); 106 if (major < 0 || (major == 0 && minor <= 2)) 107 info->use_free_glyphs = FcFalse; 108 109 pf.type = PictTypeDirect; 110 pf.depth = 32; 111 pf.direct.redMask = 0xff; 112 pf.direct.greenMask = 0xff; 113 pf.direct.blueMask = 0xff; 114 pf.direct.alphaMask = 0xff; 115 info->solidFormat = XRenderFindFormat (dpy, 116 (PictFormatType| 117 PictFormatDepth| 118 PictFormatRedMask| 119 PictFormatGreenMask| 120 PictFormatBlueMask| 121 PictFormatAlphaMask), 122 &pf, 123 0); 124 } 125 if (XftDebug () & XFT_DBG_RENDER) 126 { 127 Visual *visual = DefaultVisual (dpy, DefaultScreen (dpy)); 128 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual); 129 130 printf ("XftDisplayInfoGet Default visual 0x%x ", 131 (int) visual->visualid); 132 if (format) 133 { 134 if (format->type == PictTypeDirect) 135 { 136 printf ("format %d,%d,%d,%d\n", 137 format->direct.alpha, 138 format->direct.red, 139 format->direct.green, 140 format->direct.blue); 141 } 142 else 143 { 144 printf ("format indexed\n"); 145 } 146 } 147 else 148 printf ("No Render format for default visual\n"); 149 150 printf ("XftDisplayInfoGet initialized, hasRender set to \"%s\"\n", 151 info->hasRender ? "True" : "False"); 152 } 153 for (i = 0; i < XFT_NUM_SOLID_COLOR; i++) 154 { 155 info->colors[i].screen = -1; 156 info->colors[i].pict = 0; 157 } 158 info->fonts = NULL; 159 160 info->next = _XftDisplayInfo; 161 _XftDisplayInfo = info; 162 163 info->glyph_memory = 0; 164 info->max_glyph_memory = XftDefaultGetInteger (dpy, 165 XFT_MAX_GLYPH_MEMORY, 0, 166 XFT_DPY_MAX_GLYPH_MEMORY); 167 if (XftDebug () & XFT_DBG_CACHE) 168 printf ("global max cache memory %ld\n", info->max_glyph_memory); 169 170 171 info->num_unref_fonts = 0; 172 info->max_unref_fonts = XftDefaultGetInteger (dpy, 173 XFT_MAX_UNREF_FONTS, 0, 174 XFT_DPY_MAX_UNREF_FONTS); 175 if (XftDebug() & XFT_DBG_CACHE) 176 printf ("global max unref fonts %d\n", info->max_unref_fonts); 177 178 memset (info->fontHash, '\0', sizeof (XftFont *) * XFT_NUM_FONT_HASH); 179 return info; 180 181bail1: 182 free (info); 183bail0: 184 if (XftDebug () & XFT_DBG_RENDER) 185 { 186 printf ("XftDisplayInfoGet failed to initialize, Xft unhappy\n"); 187 } 188 return NULL; 189} 190 191/* 192 * Reduce memory usage in X server 193 */ 194 195static void 196_XftDisplayValidateMemory (XftDisplayInfo *info) 197{ 198 XftFont *public; 199 XftFontInt *font; 200 unsigned long glyph_memory; 201 202 glyph_memory = 0; 203 for (public = info->fonts; public; public = font->next) 204 { 205 font = (XftFontInt *) public; 206 glyph_memory += font->glyph_memory; 207 } 208 if (glyph_memory != info->glyph_memory) 209 printf ("Display glyph cache incorrect has %ld bytes, should have %ld\n", 210 info->glyph_memory, glyph_memory); 211} 212 213_X_HIDDEN void 214_XftDisplayManageMemory (Display *dpy) 215{ 216 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False); 217 unsigned long glyph_memory; 218 XftFont *public; 219 XftFontInt *font; 220 221 if (!info || !info->max_glyph_memory) 222 return; 223 if (XftDebug () & XFT_DBG_CACHE) 224 { 225 if (info->glyph_memory > info->max_glyph_memory) 226 printf ("Reduce global memory from %ld to %ld\n", 227 info->glyph_memory, info->max_glyph_memory); 228 _XftDisplayValidateMemory (info); 229 } 230 while (info->glyph_memory > info->max_glyph_memory) 231 { 232 glyph_memory = rand () % info->glyph_memory; 233 public = info->fonts; 234 while (public) 235 { 236 font = (XftFontInt *) public; 237 238 if (font->glyph_memory > glyph_memory) 239 { 240 _XftFontUncacheGlyph (dpy, public); 241 break; 242 } 243 public = font->next; 244 glyph_memory -= font->glyph_memory; 245 } 246 } 247 if (XftDebug () & XFT_DBG_CACHE) 248 _XftDisplayValidateMemory (info); 249} 250 251_X_EXPORT Bool 252XftDefaultHasRender (Display *dpy) 253{ 254 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True); 255 256 if (!info) 257 return False; 258 return info->hasRender; 259} 260 261_X_EXPORT Bool 262XftDefaultSet (Display *dpy, FcPattern *defaults) 263{ 264 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True); 265 266 if (!info) 267 return False; 268 if (info->defaults) 269 FcPatternDestroy (info->defaults); 270 info->defaults = defaults; 271 if (!info->max_glyph_memory) 272 info->max_glyph_memory = XFT_DPY_MAX_GLYPH_MEMORY; 273 info->max_glyph_memory = XftDefaultGetInteger (dpy, 274 XFT_MAX_GLYPH_MEMORY, 0, 275 info->max_glyph_memory); 276 if (!info->max_unref_fonts) 277 info->max_unref_fonts = XFT_DPY_MAX_UNREF_FONTS; 278 info->max_unref_fonts = XftDefaultGetInteger (dpy, 279 XFT_MAX_UNREF_FONTS, 0, 280 info->max_unref_fonts); 281 return True; 282} 283 284_X_HIDDEN int 285XftDefaultParseBool (const char *v) 286{ 287 char c0, c1; 288 289 c0 = *v; 290 if (isupper ((int)c0)) 291 c0 = tolower (c0); 292 if (c0 == 't' || c0 == 'y' || c0 == '1') 293 return 1; 294 if (c0 == 'f' || c0 == 'n' || c0 == '0') 295 return 0; 296 if (c0 == 'o') 297 { 298 c1 = v[1]; 299 if (isupper ((int)c1)) 300 c1 = tolower (c1); 301 if (c1 == 'n') 302 return 1; 303 if (c1 == 'f') 304 return 0; 305 } 306 return -1; 307} 308 309static Bool 310_XftDefaultInitBool (Display *dpy, FcPattern *pat, const char *option) 311{ 312 char *v; 313 int i; 314 315 v = XGetDefault (dpy, "Xft", option); 316 if (v && (i = XftDefaultParseBool (v)) >= 0) 317 return FcPatternAddBool (pat, option, i != 0); 318 return True; 319} 320 321static Bool 322_XftDefaultInitDouble (Display *dpy, FcPattern *pat, const char *option) 323{ 324 char *v, *e; 325 double d; 326 327 v = XGetDefault (dpy, "Xft", option); 328 if (v) 329 { 330 d = strtod (v, &e); 331 if (e != v) 332 return FcPatternAddDouble (pat, option, d); 333 } 334 return True; 335} 336 337static Bool 338_XftDefaultInitInteger (Display *dpy, FcPattern *pat, const char *option) 339{ 340 char *v, *e; 341 int i; 342 343 v = XGetDefault (dpy, "Xft", option); 344 if (v) 345 { 346 if (FcNameConstant ((FcChar8 *) v, &i)) 347 return FcPatternAddInteger (pat, option, i); 348 i = strtol (v, &e, 0); 349 if (e != v) 350 return FcPatternAddInteger (pat, option, i); 351 } 352 return True; 353} 354 355static FcPattern * 356_XftDefaultInit (Display *dpy) 357{ 358 FcPattern *pat; 359 360 pat = FcPatternCreate (); 361 if (!pat) 362 goto bail0; 363 364 if (!_XftDefaultInitDouble (dpy, pat, FC_SCALE)) 365 goto bail1; 366 if (!_XftDefaultInitDouble (dpy, pat, FC_DPI)) 367 goto bail1; 368 if (!_XftDefaultInitBool (dpy, pat, XFT_RENDER)) 369 goto bail1; 370 if (!_XftDefaultInitInteger (dpy, pat, FC_RGBA)) 371 goto bail1; 372 if (!_XftDefaultInitInteger (dpy, pat, FC_LCD_FILTER)) 373 goto bail1; 374 if (!_XftDefaultInitBool (dpy, pat, FC_ANTIALIAS)) 375 goto bail1; 376 if (!_XftDefaultInitBool (dpy, pat, FC_EMBOLDEN)) 377 goto bail1; 378 if (!_XftDefaultInitBool (dpy, pat, FC_AUTOHINT)) 379 goto bail1; 380 if (!_XftDefaultInitInteger (dpy, pat, FC_HINT_STYLE)) 381 goto bail1; 382 if (!_XftDefaultInitBool (dpy, pat, FC_HINTING)) 383 goto bail1; 384 if (!_XftDefaultInitBool (dpy, pat, FC_MINSPACE)) 385 goto bail1; 386 if (!_XftDefaultInitInteger (dpy, pat, XFT_MAX_GLYPH_MEMORY)) 387 goto bail1; 388 389 return pat; 390 391bail1: 392 FcPatternDestroy (pat); 393bail0: 394 return NULL; 395} 396 397static FcResult 398_XftDefaultGet (Display *dpy, const char *object, int screen, FcValue *v) 399{ 400 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True); 401 FcResult r; 402 403 if (!info) 404 return FcResultNoMatch; 405 406 if (!info->defaults) 407 { 408 info->defaults = _XftDefaultInit (dpy); 409 if (!info->defaults) 410 return FcResultNoMatch; 411 } 412 r = FcPatternGet (info->defaults, object, screen, v); 413 if (r == FcResultNoId && screen > 0) 414 r = FcPatternGet (info->defaults, object, 0, v); 415 return r; 416} 417 418_X_HIDDEN Bool 419XftDefaultGetBool (Display *dpy, const char *object, int screen, Bool def) 420{ 421 FcResult r; 422 FcValue v; 423 424 r = _XftDefaultGet (dpy, object, screen, &v); 425 if (r != FcResultMatch || v.type != FcTypeBool) 426 return def; 427 return v.u.b; 428} 429 430_X_HIDDEN int 431XftDefaultGetInteger (Display *dpy, const char *object, int screen, int def) 432{ 433 FcResult r; 434 FcValue v; 435 436 r = _XftDefaultGet (dpy, object, screen, &v); 437 if (r != FcResultMatch || v.type != FcTypeInteger) 438 return def; 439 return v.u.i; 440} 441 442_X_HIDDEN double 443XftDefaultGetDouble (Display *dpy, const char *object, int screen, double def) 444{ 445 FcResult r; 446 FcValue v; 447 448 r = _XftDefaultGet (dpy, object, screen, &v); 449 if (r != FcResultMatch || v.type != FcTypeDouble) 450 return def; 451 return v.u.d; 452} 453 454_X_EXPORT void 455XftDefaultSubstitute (Display *dpy, int screen, FcPattern *pattern) 456{ 457 FcValue v; 458 double dpi; 459 460 if (FcPatternGet (pattern, XFT_RENDER, 0, &v) == FcResultNoMatch) 461 { 462 FcPatternAddBool (pattern, XFT_RENDER, 463 XftDefaultGetBool (dpy, XFT_RENDER, screen, 464 XftDefaultHasRender (dpy))); 465 } 466 if (FcPatternGet (pattern, FC_ANTIALIAS, 0, &v) == FcResultNoMatch) 467 { 468 FcPatternAddBool (pattern, FC_ANTIALIAS, 469 XftDefaultGetBool (dpy, FC_ANTIALIAS, screen, 470 True)); 471 } 472 if (FcPatternGet (pattern, FC_EMBOLDEN, 0, &v) == FcResultNoMatch) 473 { 474 FcPatternAddBool (pattern, FC_EMBOLDEN, 475 XftDefaultGetBool (dpy, FC_EMBOLDEN, screen, 476 False)); 477 } 478 if (FcPatternGet (pattern, FC_HINTING, 0, &v) == FcResultNoMatch) 479 { 480 FcPatternAddBool (pattern, FC_HINTING, 481 XftDefaultGetBool (dpy, FC_HINTING, screen, 482 True)); 483 } 484 if (FcPatternGet (pattern, FC_HINT_STYLE, 0, &v) == FcResultNoMatch) 485 { 486 FcPatternAddInteger (pattern, FC_HINT_STYLE, 487 XftDefaultGetInteger (dpy, FC_HINT_STYLE, screen, 488 FC_HINT_FULL)); 489 } 490 if (FcPatternGet (pattern, FC_AUTOHINT, 0, &v) == FcResultNoMatch) 491 { 492 FcPatternAddBool (pattern, FC_AUTOHINT, 493 XftDefaultGetBool (dpy, FC_AUTOHINT, screen, 494 False)); 495 } 496 if (FcPatternGet (pattern, FC_RGBA, 0, &v) == FcResultNoMatch) 497 { 498 int subpixel = FC_RGBA_UNKNOWN; 499#if RENDER_MAJOR > 0 || RENDER_MINOR >= 6 500 if (XftDefaultHasRender (dpy)) 501 { 502 int render_order = XRenderQuerySubpixelOrder (dpy, screen); 503 switch (render_order) { 504 default: 505 case SubPixelUnknown: subpixel = FC_RGBA_UNKNOWN; break; 506 case SubPixelHorizontalRGB: subpixel = FC_RGBA_RGB; break; 507 case SubPixelHorizontalBGR: subpixel = FC_RGBA_BGR; break; 508 case SubPixelVerticalRGB: subpixel = FC_RGBA_VRGB; break; 509 case SubPixelVerticalBGR: subpixel = FC_RGBA_VBGR; break; 510 case SubPixelNone: subpixel = FC_RGBA_NONE; break; 511 } 512 } 513#endif 514 FcPatternAddInteger (pattern, FC_RGBA, 515 XftDefaultGetInteger (dpy, FC_RGBA, screen, 516 subpixel)); 517 } 518 if (FcPatternGet (pattern, FC_LCD_FILTER, 0, &v) == FcResultNoMatch) 519 { 520 FcPatternAddInteger (pattern, FC_LCD_FILTER, 521 XftDefaultGetInteger (dpy, FC_LCD_FILTER, screen, 522 FC_LCD_DEFAULT)); 523 } 524 if (FcPatternGet (pattern, FC_MINSPACE, 0, &v) == FcResultNoMatch) 525 { 526 FcPatternAddBool (pattern, FC_MINSPACE, 527 XftDefaultGetBool (dpy, FC_MINSPACE, screen, 528 False)); 529 } 530 if (FcPatternGet (pattern, FC_DPI, 0, &v) == FcResultNoMatch) 531 { 532 dpi = (((double) DisplayHeight (dpy, screen) * 25.4) / 533 (double) DisplayHeightMM (dpy, screen)); 534 FcPatternAddDouble (pattern, FC_DPI, 535 XftDefaultGetDouble (dpy, FC_DPI, screen, 536 dpi)); 537 } 538 if (FcPatternGet (pattern, FC_SCALE, 0, &v) == FcResultNoMatch) 539 { 540 FcPatternAddDouble (pattern, FC_SCALE, 541 XftDefaultGetDouble (dpy, FC_SCALE, screen, 1.0)); 542 } 543 if (FcPatternGet (pattern, XFT_MAX_GLYPH_MEMORY, 0, &v) == FcResultNoMatch) 544 { 545 FcPatternAddInteger (pattern, XFT_MAX_GLYPH_MEMORY, 546 XftDefaultGetInteger (dpy, XFT_MAX_GLYPH_MEMORY, 547 screen, 548 XFT_FONT_MAX_GLYPH_MEMORY)); 549 } 550 FcDefaultSubstitute (pattern); 551} 552 553