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