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