xftdpy.c revision 0e0b1094
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 info->hasSolid = FcFalse; 110 if (major > 0 || (major == 0 && minor >= 10)) 111 info->hasSolid = FcTrue; 112 113 pf.type = PictTypeDirect; 114 pf.depth = 32; 115 pf.direct.redMask = 0xff; 116 pf.direct.greenMask = 0xff; 117 pf.direct.blueMask = 0xff; 118 pf.direct.alphaMask = 0xff; 119 info->solidFormat = XRenderFindFormat (dpy, 120 (PictFormatType| 121 PictFormatDepth| 122 PictFormatRedMask| 123 PictFormatGreenMask| 124 PictFormatBlueMask| 125 PictFormatAlphaMask), 126 &pf, 127 0); 128 } 129 if (XftDebug () & XFT_DBG_RENDER) 130 { 131 Visual *visual = DefaultVisual (dpy, DefaultScreen (dpy)); 132 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual); 133 134 printf ("XftDisplayInfoGet Default visual 0x%x ", 135 (int) visual->visualid); 136 if (format) 137 { 138 if (format->type == PictTypeDirect) 139 { 140 printf ("format %d,%d,%d,%d\n", 141 format->direct.alpha, 142 format->direct.red, 143 format->direct.green, 144 format->direct.blue); 145 } 146 else 147 { 148 printf ("format indexed\n"); 149 } 150 } 151 else 152 printf ("No Render format for default visual\n"); 153 154 printf ("XftDisplayInfoGet initialized, hasRender set to \"%s\"\n", 155 info->hasRender ? "True" : "False"); 156 } 157 for (i = 0; i < XFT_NUM_SOLID_COLOR; i++) 158 { 159 info->colors[i].screen = -1; 160 info->colors[i].pict = 0; 161 } 162 info->fonts = NULL; 163 164 info->next = _XftDisplayInfo; 165 _XftDisplayInfo = info; 166 167 info->glyph_memory = 0; 168 info->max_glyph_memory = (unsigned long)XftDefaultGetInteger (dpy, 169 XFT_MAX_GLYPH_MEMORY, 0, 170 XFT_DPY_MAX_GLYPH_MEMORY); 171 if (XftDebug () & XFT_DBG_CACHE) 172 printf ("global max cache memory %ld\n", info->max_glyph_memory); 173 174 175 info->num_unref_fonts = 0; 176 info->max_unref_fonts = XftDefaultGetInteger (dpy, 177 XFT_MAX_UNREF_FONTS, 0, 178 XFT_DPY_MAX_UNREF_FONTS); 179 if (XftDebug() & XFT_DBG_CACHE) 180 printf ("global max unref fonts %d\n", info->max_unref_fonts); 181 182 memset (info->fontHash, '\0', sizeof (XftFont *) * XFT_NUM_FONT_HASH); 183 return info; 184 185bail1: 186 free (info); 187bail0: 188 if (XftDebug () & XFT_DBG_RENDER) 189 { 190 printf ("XftDisplayInfoGet failed to initialize, Xft unhappy\n"); 191 } 192 return NULL; 193} 194 195/* 196 * Reduce memory usage in X server 197 */ 198 199static void 200_XftDisplayValidateMemory (XftDisplayInfo *info) 201{ 202 XftFont *public; 203 XftFontInt *font; 204 unsigned long glyph_memory; 205 206 glyph_memory = 0; 207 for (public = info->fonts; public; public = font->next) 208 { 209 font = (XftFontInt *) public; 210 glyph_memory += font->glyph_memory; 211 } 212 if (glyph_memory != info->glyph_memory) 213 printf ("Display glyph cache incorrect has %ld bytes, should have %ld\n", 214 info->glyph_memory, glyph_memory); 215} 216 217_X_HIDDEN void 218_XftDisplayManageMemory (Display *dpy) 219{ 220 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False); 221 unsigned long glyph_memory; 222 XftFont *public; 223 XftFontInt *font; 224 225 if (!info || !info->max_glyph_memory) 226 return; 227 if (XftDebug () & XFT_DBG_CACHE) 228 { 229 if (info->glyph_memory > info->max_glyph_memory) 230 printf ("Reduce global memory from %ld to %ld\n", 231 info->glyph_memory, info->max_glyph_memory); 232 _XftDisplayValidateMemory (info); 233 } 234 while (info->glyph_memory > info->max_glyph_memory) 235 { 236 glyph_memory = (unsigned long)rand () % info->glyph_memory; 237 public = info->fonts; 238 while (public) 239 { 240 font = (XftFontInt *) public; 241 242 if (font->glyph_memory > glyph_memory) 243 { 244 _XftFontUncacheGlyph (dpy, public); 245 break; 246 } 247 public = font->next; 248 glyph_memory -= font->glyph_memory; 249 } 250 } 251 if (XftDebug () & XFT_DBG_CACHE) 252 _XftDisplayValidateMemory (info); 253} 254 255_X_EXPORT Bool 256XftDefaultHasRender (Display *dpy) 257{ 258 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True); 259 260 if (!info) 261 return False; 262 return info->hasRender; 263} 264 265_X_EXPORT Bool 266XftDefaultSet (Display *dpy, FcPattern *defaults) 267{ 268 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True); 269 270 if (!info) 271 return False; 272 if (info->defaults) 273 FcPatternDestroy (info->defaults); 274 info->defaults = defaults; 275 if (!info->max_glyph_memory) 276 info->max_glyph_memory = XFT_DPY_MAX_GLYPH_MEMORY; 277 info->max_glyph_memory = (unsigned long)XftDefaultGetInteger (dpy, 278 XFT_MAX_GLYPH_MEMORY, 0, 279 (int)info->max_glyph_memory); 280 if (!info->max_unref_fonts) 281 info->max_unref_fonts = XFT_DPY_MAX_UNREF_FONTS; 282 info->max_unref_fonts = XftDefaultGetInteger (dpy, 283 XFT_MAX_UNREF_FONTS, 0, 284 info->max_unref_fonts); 285 return True; 286} 287 288_X_HIDDEN int 289XftDefaultParseBool (const char *v) 290{ 291 char c0, c1; 292 293 c0 = *v; 294 if (isupper ((int)c0)) 295 c0 = (char)tolower (c0); 296 if (c0 == 't' || c0 == 'y' || c0 == '1') 297 return 1; 298 if (c0 == 'f' || c0 == 'n' || c0 == '0') 299 return 0; 300 if (c0 == 'o') 301 { 302 c1 = v[1]; 303 if (isupper ((int)c1)) 304 c1 = (char)tolower (c1); 305 if (c1 == 'n') 306 return 1; 307 if (c1 == 'f') 308 return 0; 309 } 310 return -1; 311} 312 313static Bool 314_XftDefaultInitBool (Display *dpy, FcPattern *pat, const char *option) 315{ 316 char *v; 317 int i; 318 319 v = XGetDefault (dpy, "Xft", option); 320 if (v && (i = XftDefaultParseBool (v)) >= 0) 321 return FcPatternAddBool (pat, option, i != 0); 322 return True; 323} 324 325static Bool 326_XftDefaultInitDouble (Display *dpy, FcPattern *pat, const char *option) 327{ 328 char *v, *e; 329 double d; 330 331 v = XGetDefault (dpy, "Xft", option); 332 if (v) 333 { 334 d = strtod (v, &e); 335 if (e != v) 336 return FcPatternAddDouble (pat, option, d); 337 } 338 return True; 339} 340 341static Bool 342_XftDefaultInitInteger (Display *dpy, FcPattern *pat, const char *option) 343{ 344 char *v, *e; 345 int i; 346 347 v = XGetDefault (dpy, "Xft", option); 348 if (v) 349 { 350 if (FcNameConstant ((FcChar8 *) v, &i)) 351 return FcPatternAddInteger (pat, option, i); 352 i = (int)strtol (v, &e, 0); 353 if (e != v) 354 return FcPatternAddInteger (pat, option, i); 355 } 356 return True; 357} 358 359static FcPattern * 360_XftDefaultInit (Display *dpy) 361{ 362 FcPattern *pat; 363 364 pat = FcPatternCreate (); 365 if (!pat) 366 goto bail0; 367 368 if (!_XftDefaultInitDouble (dpy, pat, FC_SCALE)) 369 goto bail1; 370 if (!_XftDefaultInitDouble (dpy, pat, FC_DPI)) 371 goto bail1; 372 if (!_XftDefaultInitBool (dpy, pat, XFT_RENDER)) 373 goto bail1; 374 if (!_XftDefaultInitInteger (dpy, pat, FC_RGBA)) 375 goto bail1; 376 if (!_XftDefaultInitInteger (dpy, pat, FC_LCD_FILTER)) 377 goto bail1; 378 if (!_XftDefaultInitBool (dpy, pat, FC_ANTIALIAS)) 379 goto bail1; 380 if (!_XftDefaultInitBool (dpy, pat, FC_EMBOLDEN)) 381 goto bail1; 382 if (!_XftDefaultInitBool (dpy, pat, FC_AUTOHINT)) 383 goto bail1; 384 if (!_XftDefaultInitInteger (dpy, pat, FC_HINT_STYLE)) 385 goto bail1; 386 if (!_XftDefaultInitBool (dpy, pat, FC_HINTING)) 387 goto bail1; 388 if (!_XftDefaultInitBool (dpy, pat, FC_MINSPACE)) 389 goto bail1; 390 if (!_XftDefaultInitInteger (dpy, pat, XFT_MAX_GLYPH_MEMORY)) 391 goto bail1; 392 393 return pat; 394 395bail1: 396 FcPatternDestroy (pat); 397bail0: 398 return NULL; 399} 400 401static FcResult 402_XftDefaultGet (Display *dpy, const char *object, int screen, FcValue *v) 403{ 404 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True); 405 FcResult r; 406 407 if (!info) 408 return FcResultNoMatch; 409 410 if (!info->defaults) 411 { 412 info->defaults = _XftDefaultInit (dpy); 413 if (!info->defaults) 414 return FcResultNoMatch; 415 } 416 r = FcPatternGet (info->defaults, object, screen, v); 417 if (r == FcResultNoId && screen > 0) 418 r = FcPatternGet (info->defaults, object, 0, v); 419 return r; 420} 421 422_X_HIDDEN Bool 423XftDefaultGetBool (Display *dpy, const char *object, int screen, Bool def) 424{ 425 FcResult r; 426 FcValue v; 427 428 r = _XftDefaultGet (dpy, object, screen, &v); 429 if (r != FcResultMatch || v.type != FcTypeBool) 430 return def; 431 return v.u.b; 432} 433 434_X_HIDDEN int 435XftDefaultGetInteger (Display *dpy, const char *object, int screen, int def) 436{ 437 FcResult r; 438 FcValue v; 439 440 r = _XftDefaultGet (dpy, object, screen, &v); 441 if (r != FcResultMatch || v.type != FcTypeInteger) 442 return def; 443 return v.u.i; 444} 445 446_X_HIDDEN double 447XftDefaultGetDouble (Display *dpy, const char *object, int screen, double def) 448{ 449 FcResult r; 450 FcValue v; 451 452 r = _XftDefaultGet (dpy, object, screen, &v); 453 if (r != FcResultMatch || v.type != FcTypeDouble) 454 return def; 455 return v.u.d; 456} 457 458_X_EXPORT void 459XftDefaultSubstitute (Display *dpy, int screen, FcPattern *pattern) 460{ 461 FcValue v; 462 double dpi; 463 464 if (FcPatternGet (pattern, XFT_RENDER, 0, &v) == FcResultNoMatch) 465 { 466 FcPatternAddBool (pattern, XFT_RENDER, 467 XftDefaultGetBool (dpy, XFT_RENDER, screen, 468 XftDefaultHasRender (dpy))); 469 } 470 if (FcPatternGet (pattern, FC_ANTIALIAS, 0, &v) == FcResultNoMatch) 471 { 472 FcPatternAddBool (pattern, FC_ANTIALIAS, 473 XftDefaultGetBool (dpy, FC_ANTIALIAS, screen, 474 True)); 475 } 476 if (FcPatternGet (pattern, FC_EMBOLDEN, 0, &v) == FcResultNoMatch) 477 { 478 FcPatternAddBool (pattern, FC_EMBOLDEN, 479 XftDefaultGetBool (dpy, FC_EMBOLDEN, screen, 480 False)); 481 } 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 if (FcPatternGet (pattern, FC_HINT_STYLE, 0, &v) == FcResultNoMatch) 489 { 490 FcPatternAddInteger (pattern, FC_HINT_STYLE, 491 XftDefaultGetInteger (dpy, FC_HINT_STYLE, screen, 492 FC_HINT_FULL)); 493 } 494 if (FcPatternGet (pattern, FC_AUTOHINT, 0, &v) == FcResultNoMatch) 495 { 496 FcPatternAddBool (pattern, FC_AUTOHINT, 497 XftDefaultGetBool (dpy, FC_AUTOHINT, screen, 498 False)); 499 } 500 if (FcPatternGet (pattern, FC_RGBA, 0, &v) == FcResultNoMatch) 501 { 502 int subpixel = FC_RGBA_UNKNOWN; 503#if RENDER_MAJOR > 0 || RENDER_MINOR >= 6 504 if (XftDefaultHasRender (dpy)) 505 { 506 int render_order = XRenderQuerySubpixelOrder (dpy, screen); 507 switch (render_order) { 508 default: 509 case SubPixelUnknown: subpixel = FC_RGBA_UNKNOWN; break; 510 case SubPixelHorizontalRGB: subpixel = FC_RGBA_RGB; break; 511 case SubPixelHorizontalBGR: subpixel = FC_RGBA_BGR; break; 512 case SubPixelVerticalRGB: subpixel = FC_RGBA_VRGB; break; 513 case SubPixelVerticalBGR: subpixel = FC_RGBA_VBGR; break; 514 case SubPixelNone: subpixel = FC_RGBA_NONE; break; 515 } 516 } 517#endif 518 FcPatternAddInteger (pattern, FC_RGBA, 519 XftDefaultGetInteger (dpy, FC_RGBA, screen, 520 subpixel)); 521 } 522 if (FcPatternGet (pattern, FC_LCD_FILTER, 0, &v) == FcResultNoMatch) 523 { 524 FcPatternAddInteger (pattern, FC_LCD_FILTER, 525 XftDefaultGetInteger (dpy, FC_LCD_FILTER, screen, 526 FC_LCD_DEFAULT)); 527 } 528 if (FcPatternGet (pattern, FC_MINSPACE, 0, &v) == FcResultNoMatch) 529 { 530 FcPatternAddBool (pattern, FC_MINSPACE, 531 XftDefaultGetBool (dpy, FC_MINSPACE, screen, 532 False)); 533 } 534 if (FcPatternGet (pattern, FC_DPI, 0, &v) == FcResultNoMatch) 535 { 536 dpi = (((double) DisplayHeight (dpy, screen) * 25.4) / 537 (double) DisplayHeightMM (dpy, screen)); 538 FcPatternAddDouble (pattern, FC_DPI, 539 XftDefaultGetDouble (dpy, FC_DPI, screen, 540 dpi)); 541 } 542 if (FcPatternGet (pattern, FC_SCALE, 0, &v) == FcResultNoMatch) 543 { 544 FcPatternAddDouble (pattern, FC_SCALE, 545 XftDefaultGetDouble (dpy, FC_SCALE, screen, 1.0)); 546 } 547 if (FcPatternGet (pattern, XFT_MAX_GLYPH_MEMORY, 0, &v) == FcResultNoMatch) 548 { 549 FcPatternAddInteger (pattern, XFT_MAX_GLYPH_MEMORY, 550 XftDefaultGetInteger (dpy, XFT_MAX_GLYPH_MEMORY, 551 screen, 552 XFT_FONT_MAX_GLYPH_MEMORY)); 553 } 554 FcDefaultSubstitute (pattern); 555} 556 557