display.c revision 9d0ccd10
1/* 2 * Copyright © 2002 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 "xcursorint.h" 24#include <X11/Xlibint.h> 25#include <ctype.h> 26 27static XcursorDisplayInfo *_XcursorDisplayInfo; 28 29static void 30_XcursorFreeDisplayInfo (XcursorDisplayInfo *info) 31{ 32 if (info->theme) 33 free (info->theme); 34 35 if (info->theme_from_config) 36 free (info->theme_from_config); 37 38 while (info->fonts) 39 { 40 XcursorFontInfo *fi = info->fonts; 41 info->fonts = fi->next; 42 free (fi); 43 } 44 45 free (info); 46} 47 48static int 49_XcursorCloseDisplay (Display *dpy, XExtCodes *codes) 50{ 51 XcursorDisplayInfo *info, **prev; 52 53 /* 54 * Unhook from the global list 55 */ 56 _XLockMutex (_Xglobal_lock); 57 for (prev = &_XcursorDisplayInfo; (info = *prev); prev = &(*prev)->next) 58 if (info->display == dpy) 59 { 60 *prev = info->next; 61 break; 62 } 63 _XUnlockMutex (_Xglobal_lock); 64 65 if (info) 66 _XcursorFreeDisplayInfo (info); 67 return 0; 68} 69 70static int 71_XcursorDefaultParseBool (char *v) 72{ 73 char c0, c1; 74 75 c0 = *v; 76 if (isupper ((int)c0)) 77 c0 = tolower (c0); 78 if (c0 == 't' || c0 == 'y' || c0 == '1') 79 return 1; 80 if (c0 == 'f' || c0 == 'n' || c0 == '0') 81 return 0; 82 if (c0 == 'o') 83 { 84 c1 = v[1]; 85 if (isupper ((int)c1)) 86 c1 = tolower (c1); 87 if (c1 == 'n') 88 return 1; 89 if (c1 == 'f') 90 return 0; 91 } 92 return -1; 93} 94 95XcursorDisplayInfo * 96_XcursorGetDisplayInfo (Display *dpy) 97{ 98 XcursorDisplayInfo *info, **prev, *old; 99 int event_base, error_base; 100 int major, minor; 101 char *v; 102 int i; 103 104 _XLockMutex (_Xglobal_lock); 105 for (prev = &_XcursorDisplayInfo; (info = *prev); prev = &(*prev)->next) 106 { 107 if (info->display == dpy) 108 { 109 /* 110 * MRU the list 111 */ 112 if (prev != &_XcursorDisplayInfo) 113 { 114 *prev = info->next; 115 info->next = _XcursorDisplayInfo; 116 _XcursorDisplayInfo = info; 117 } 118 break; 119 } 120 } 121 _XUnlockMutex (_Xglobal_lock); 122 if (info) 123 return info; 124 info = (XcursorDisplayInfo *) malloc (sizeof (XcursorDisplayInfo)); 125 if (!info) 126 return NULL; 127 info->next = NULL; 128 info->display = dpy; 129 130 info->codes = XAddExtension (dpy); 131 if (!info->codes) 132 { 133 free (info); 134 return NULL; 135 } 136 (void) XESetCloseDisplay (dpy, info->codes->extension, _XcursorCloseDisplay); 137 138 /* 139 * Check whether the display supports the Render CreateCursor request 140 */ 141 info->has_render_cursor = XcursorFalse; 142 info->has_anim_cursor = XcursorFalse; 143 if (XRenderQueryExtension (dpy, &event_base, &error_base) && 144 XRenderQueryVersion (dpy, &major, &minor)) 145 { 146 if (major > 0 || minor >= 5) 147 { 148 info->has_render_cursor = XcursorTrue; 149 v = getenv ("XCURSOR_CORE"); 150 if (!v) 151 v = XGetDefault (dpy, "Xcursor", "core"); 152 if (v && _XcursorDefaultParseBool (v) == 1) 153 info->has_render_cursor = XcursorFalse; 154 } 155 if (info->has_render_cursor && (major > 0 || minor >= 8)) 156 { 157 info->has_anim_cursor = XcursorTrue; 158 v = getenv ("XCURSOR_ANIM"); 159 if (!v) 160 v = XGetDefault (dpy, "Xcursor", "anim"); 161 if (v && _XcursorDefaultParseBool (v) == 0) 162 info->has_anim_cursor = XcursorFalse; 163 } 164 } 165 166 info->size = 0; 167 168 /* 169 * Get desired cursor size 170 */ 171 v = getenv ("XCURSOR_SIZE"); 172 if (!v) 173 v = XGetDefault (dpy, "Xcursor", "size"); 174 if (v) 175 info->size = atoi (v); 176 177 /* 178 * Use the Xft size to guess a size; make cursors 16 "points" tall 179 */ 180 if (info->size == 0) 181 { 182 int dpi = 0; 183 v = XGetDefault (dpy, "Xft", "dpi"); 184 if (v) 185 dpi = atoi (v); 186 if (dpi) 187 info->size = dpi * 16 / 72; 188 } 189 190 /* 191 * Use display size to guess a size 192 */ 193 if (info->size == 0) 194 { 195 int dim; 196 197 if (DisplayHeight (dpy, DefaultScreen (dpy)) < 198 DisplayWidth (dpy, DefaultScreen (dpy))) 199 dim = DisplayHeight (dpy, DefaultScreen (dpy)); 200 else 201 dim = DisplayWidth (dpy, DefaultScreen (dpy)); 202 /* 203 * 16 pixels on a display of dimension 768 204 */ 205 info->size = dim / 48; 206 } 207 208 info->theme = NULL; 209 info->theme_from_config = NULL; 210 211 /* 212 * Get the desired theme 213 */ 214 v = getenv ("XCURSOR_THEME"); 215 if (!v) 216 v = XGetDefault (dpy, "Xcursor", "theme"); 217 if (v) 218 { 219 info->theme = strdup (v); 220 info->theme_from_config = strdup (v); 221 } 222 223 /* 224 * Get the desired dither 225 */ 226 info->dither = XcursorDitherThreshold; 227 v = getenv ("XCURSOR_DITHER"); 228 if (!v) 229 v = XGetDefault (dpy, "Xcursor", "dither"); 230 if (v) 231 { 232 if (!strcmp (v, "threshold")) 233 info->dither = XcursorDitherThreshold; 234 if (!strcmp (v, "median")) 235 info->dither = XcursorDitherMedian; 236 if (!strcmp (v, "ordered")) 237 info->dither = XcursorDitherOrdered; 238 if (!strcmp (v, "diffuse")) 239 info->dither = XcursorDitherDiffuse; 240 } 241 242 info->theme_core = False; 243 /* 244 * Find out if core cursors should 245 * be themed 246 */ 247 v = getenv ("XCURSOR_THEME_CORE"); 248 if (!v) 249 v = XGetDefault (dpy, "Xcursor", "theme_core"); 250 if (v) 251 { 252 i = _XcursorDefaultParseBool (v); 253 if (i >= 0) 254 info->theme_core = i; 255 } 256 257 info->fonts = NULL; 258 for (i = 0; i < NUM_BITMAPS; i++) 259 info->bitmaps[i].bitmap = None; 260 261 /* 262 * Link new info info list, making sure another 263 * thread hasn't inserted something into the list while 264 * this one was busy setting up the data 265 */ 266 _XLockMutex (_Xglobal_lock); 267 for (old = _XcursorDisplayInfo; old; old = old->next) 268 if (old->display == dpy) 269 break; 270 if (old) 271 { 272 _XcursorFreeDisplayInfo (info); 273 info = old; 274 } 275 else 276 { 277 info->next = _XcursorDisplayInfo; 278 _XcursorDisplayInfo = info; 279 } 280 _XUnlockMutex (_Xglobal_lock); 281 282 return info; 283} 284 285XcursorBool 286XcursorSupportsARGB (Display *dpy) 287{ 288 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 289 290 return info && info->has_render_cursor; 291} 292 293XcursorBool 294XcursorSupportsAnim (Display *dpy) 295{ 296 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 297 298 return info && info->has_anim_cursor; 299} 300 301XcursorBool 302XcursorSetDefaultSize (Display *dpy, int size) 303{ 304 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 305 306 if (!info) 307 return XcursorFalse; 308 info->size = size; 309 return XcursorTrue; 310} 311 312int 313XcursorGetDefaultSize (Display *dpy) 314{ 315 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 316 317 if (!info) 318 return 0; 319 return info->size; 320} 321 322XcursorBool 323XcursorSetTheme (Display *dpy, const char *theme) 324{ 325 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 326 char *copy; 327 328 if (!info) 329 return XcursorFalse; 330 331 if (!theme) 332 theme = info->theme_from_config; 333 334 if (theme) 335 { 336 copy = strdup (theme); 337 if (!copy) 338 return XcursorFalse; 339 } 340 else 341 copy = NULL; 342 if (info->theme) 343 free (info->theme); 344 info->theme = copy; 345 return XcursorTrue; 346} 347 348char * 349XcursorGetTheme (Display *dpy) 350{ 351 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 352 353 if (!info) 354 return NULL; 355 return info->theme; 356} 357 358XcursorBool 359XcursorGetThemeCore (Display *dpy) 360{ 361 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 362 363 if (!info) 364 return XcursorFalse; 365 return info->theme_core; 366 367} 368 369XcursorBool 370XcursorSetThemeCore (Display *dpy, XcursorBool theme_core) 371{ 372 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 373 374 if (!info) 375 return XcursorFalse; 376 info->theme_core = theme_core; 377 return XcursorTrue; 378} 379