xftdpy.c revision 0d590c07
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 = NULL; 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 (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, 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, 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, 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 (!_XftDefaultInitBool (dpy, pat, FC_ANTIALIAS)) 373 goto bail1; 374#ifdef FC_EMBOLDEN 375 if (!_XftDefaultInitBool (dpy, pat, FC_EMBOLDEN)) 376 goto bail1; 377#endif 378 if (!_XftDefaultInitBool (dpy, pat, FC_AUTOHINT)) 379 goto bail1; 380#ifdef FC_HINT_STYLE 381 if (!_XftDefaultInitInteger (dpy, pat, FC_HINT_STYLE)) 382 goto bail1; 383#endif 384 if (!_XftDefaultInitBool (dpy, pat, FC_HINTING)) 385 goto bail1; 386 if (!_XftDefaultInitBool (dpy, pat, FC_MINSPACE)) 387 goto bail1; 388 if (!_XftDefaultInitInteger (dpy, pat, XFT_MAX_GLYPH_MEMORY)) 389 goto bail1; 390 391 return pat; 392 393bail1: 394 FcPatternDestroy (pat); 395bail0: 396 return NULL; 397} 398 399static FcResult 400_XftDefaultGet (Display *dpy, const char *object, int screen, FcValue *v) 401{ 402 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True); 403 FcResult r; 404 405 if (!info) 406 return FcResultNoMatch; 407 408 if (!info->defaults) 409 { 410 info->defaults = _XftDefaultInit (dpy); 411 if (!info->defaults) 412 return FcResultNoMatch; 413 } 414 r = FcPatternGet (info->defaults, object, screen, v); 415 if (r == FcResultNoId && screen > 0) 416 r = FcPatternGet (info->defaults, object, 0, v); 417 return r; 418} 419 420_X_HIDDEN Bool 421XftDefaultGetBool (Display *dpy, const char *object, int screen, Bool def) 422{ 423 FcResult r; 424 FcValue v; 425 426 r = _XftDefaultGet (dpy, object, screen, &v); 427 if (r != FcResultMatch || v.type != FcTypeBool) 428 return def; 429 return v.u.b; 430} 431 432_X_HIDDEN int 433XftDefaultGetInteger (Display *dpy, const char *object, int screen, int def) 434{ 435 FcResult r; 436 FcValue v; 437 438 r = _XftDefaultGet (dpy, object, screen, &v); 439 if (r != FcResultMatch || v.type != FcTypeInteger) 440 return def; 441 return v.u.i; 442} 443 444_X_HIDDEN double 445XftDefaultGetDouble (Display *dpy, const char *object, int screen, double def) 446{ 447 FcResult r; 448 FcValue v; 449 450 r = _XftDefaultGet (dpy, object, screen, &v); 451 if (r != FcResultMatch || v.type != FcTypeDouble) 452 return def; 453 return v.u.d; 454} 455 456_X_EXPORT void 457XftDefaultSubstitute (Display *dpy, int screen, FcPattern *pattern) 458{ 459 FcValue v; 460 double dpi; 461 462 if (FcPatternGet (pattern, XFT_RENDER, 0, &v) == FcResultNoMatch) 463 { 464 FcPatternAddBool (pattern, XFT_RENDER, 465 XftDefaultGetBool (dpy, XFT_RENDER, screen, 466 XftDefaultHasRender (dpy))); 467 } 468 if (FcPatternGet (pattern, FC_ANTIALIAS, 0, &v) == FcResultNoMatch) 469 { 470 FcPatternAddBool (pattern, FC_ANTIALIAS, 471 XftDefaultGetBool (dpy, FC_ANTIALIAS, screen, 472 True)); 473 } 474#ifdef FC_EMBOLDEN 475 if (FcPatternGet (pattern, FC_EMBOLDEN, 0, &v) == FcResultNoMatch) 476 { 477 FcPatternAddBool (pattern, FC_EMBOLDEN, 478 XftDefaultGetBool (dpy, FC_EMBOLDEN, screen, 479 False)); 480 } 481#endif 482 if (FcPatternGet (pattern, FC_HINTING, 0, &v) == FcResultNoMatch) 483 { 484 FcPatternAddBool (pattern, FC_HINTING, 485 XftDefaultGetBool (dpy, FC_HINTING, screen, 486 True)); 487 } 488#ifdef FC_HINT_STYLE 489 if (FcPatternGet (pattern, FC_HINT_STYLE, 0, &v) == FcResultNoMatch) 490 { 491 FcPatternAddInteger (pattern, FC_HINT_STYLE, 492 XftDefaultGetInteger (dpy, FC_HINT_STYLE, screen, 493 FC_HINT_FULL)); 494 } 495#endif 496 if (FcPatternGet (pattern, FC_AUTOHINT, 0, &v) == FcResultNoMatch) 497 { 498 FcPatternAddBool (pattern, FC_AUTOHINT, 499 XftDefaultGetBool (dpy, FC_AUTOHINT, screen, 500 False)); 501 } 502 if (FcPatternGet (pattern, FC_RGBA, 0, &v) == FcResultNoMatch) 503 { 504 int subpixel = FC_RGBA_UNKNOWN; 505#if RENDER_MAJOR > 0 || RENDER_MINOR >= 6 506 if (XftDefaultHasRender (dpy)) 507 { 508 int render_order = XRenderQuerySubpixelOrder (dpy, screen); 509 switch (render_order) { 510 default: 511 case SubPixelUnknown: subpixel = FC_RGBA_UNKNOWN; break; 512 case SubPixelHorizontalRGB: subpixel = FC_RGBA_RGB; break; 513 case SubPixelHorizontalBGR: subpixel = FC_RGBA_BGR; break; 514 case SubPixelVerticalRGB: subpixel = FC_RGBA_VRGB; break; 515 case SubPixelVerticalBGR: subpixel = FC_RGBA_VBGR; break; 516 case SubPixelNone: subpixel = FC_RGBA_NONE; break; 517 } 518 } 519#endif 520 FcPatternAddInteger (pattern, FC_RGBA, 521 XftDefaultGetInteger (dpy, FC_RGBA, screen, 522 subpixel)); 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