display.c revision e169010a
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 free (info); 39} 40 41static int 42_XcursorCloseDisplay (Display *dpy, XExtCodes *codes) 43{ 44 XcursorDisplayInfo *info, **prev; 45 46 /* 47 * Unhook from the global list 48 */ 49 _XLockMutex (_Xglobal_lock); 50 for (prev = &_XcursorDisplayInfo; (info = *prev); prev = &(*prev)->next) 51 if (info->display == dpy) 52 { 53 *prev = info->next; 54 break; 55 } 56 _XUnlockMutex (_Xglobal_lock); 57 58 if (info) 59 _XcursorFreeDisplayInfo (info); 60 return 0; 61} 62 63static int 64_XcursorDefaultParseBool (char *v) 65{ 66 char c0, c1; 67 68 c0 = *v; 69 if (isupper ((int)c0)) 70 c0 = tolower (c0); 71 if (c0 == 't' || c0 == 'y' || c0 == '1') 72 return 1; 73 if (c0 == 'f' || c0 == 'n' || c0 == '0') 74 return 0; 75 if (c0 == 'o') 76 { 77 c1 = v[1]; 78 if (isupper ((int)c1)) 79 c1 = tolower (c1); 80 if (c1 == 'n') 81 return 1; 82 if (c1 == 'f') 83 return 0; 84 } 85 return -1; 86} 87 88XcursorDisplayInfo * 89_XcursorGetDisplayInfo (Display *dpy) 90{ 91 XcursorDisplayInfo *info, **prev, *old; 92 int event_base, error_base; 93 int major, minor; 94 char *v; 95 int i; 96 97 _XLockMutex (_Xglobal_lock); 98 for (prev = &_XcursorDisplayInfo; (info = *prev); prev = &(*prev)->next) 99 { 100 if (info->display == dpy) 101 { 102 /* 103 * MRU the list 104 */ 105 if (prev != &_XcursorDisplayInfo) 106 { 107 *prev = info->next; 108 info->next = _XcursorDisplayInfo; 109 _XcursorDisplayInfo = info; 110 } 111 break; 112 } 113 } 114 _XUnlockMutex (_Xglobal_lock); 115 if (info) 116 return info; 117 info = (XcursorDisplayInfo *) malloc (sizeof (XcursorDisplayInfo)); 118 if (!info) 119 return NULL; 120 info->next = NULL; 121 info->display = dpy; 122 123 info->codes = XAddExtension (dpy); 124 if (!info->codes) 125 { 126 free (info); 127 return NULL; 128 } 129 (void) XESetCloseDisplay (dpy, info->codes->extension, _XcursorCloseDisplay); 130 131 /* 132 * Check whether the display supports the Render CreateCursor request 133 */ 134 info->has_render_cursor = XcursorFalse; 135 info->has_anim_cursor = XcursorFalse; 136 if (XRenderQueryExtension (dpy, &event_base, &error_base) && 137 XRenderQueryVersion (dpy, &major, &minor)) 138 { 139 if (major > 0 || minor >= 5) 140 { 141 info->has_render_cursor = XcursorTrue; 142 v = getenv ("XCURSOR_CORE"); 143 if (!v) 144 v = XGetDefault (dpy, "Xcursor", "core"); 145 if (v && _XcursorDefaultParseBool (v) == 1) 146 info->has_render_cursor = XcursorFalse; 147 } 148 if (info->has_render_cursor && (major > 0 || minor >= 8)) 149 { 150 info->has_anim_cursor = XcursorTrue; 151 v = getenv ("XCURSOR_ANIM"); 152 if (!v) 153 v = XGetDefault (dpy, "Xcursor", "anim"); 154 if (v && _XcursorDefaultParseBool (v) == 0) 155 info->has_anim_cursor = XcursorFalse; 156 } 157 } 158 159 info->size = 0; 160 161 /* 162 * Get desired cursor size 163 */ 164 v = getenv ("XCURSOR_SIZE"); 165 if (!v) 166 v = XGetDefault (dpy, "Xcursor", "size"); 167 if (v) 168 info->size = atoi (v); 169 170 /* 171 * Use the Xft size to guess a size; make cursors 16 "points" tall 172 */ 173 if (info->size == 0) 174 { 175 int dpi = 0; 176 v = XGetDefault (dpy, "Xft", "dpi"); 177 if (v) 178 dpi = atoi (v); 179 if (dpi) 180 info->size = dpi * 16 / 72; 181 } 182 183 /* 184 * Use display size to guess a size 185 */ 186 if (info->size == 0) 187 { 188 int dim; 189 190 if (DisplayHeight (dpy, DefaultScreen (dpy)) < 191 DisplayWidth (dpy, DefaultScreen (dpy))) 192 dim = DisplayHeight (dpy, DefaultScreen (dpy)); 193 else 194 dim = DisplayWidth (dpy, DefaultScreen (dpy)); 195 /* 196 * 16 pixels on a display of dimension 768 197 */ 198 info->size = dim / 48; 199 } 200 201 info->theme = NULL; 202 info->theme_from_config = NULL; 203 204 /* 205 * Get the desired theme 206 */ 207 v = getenv ("XCURSOR_THEME"); 208 if (!v) 209 v = XGetDefault (dpy, "Xcursor", "theme"); 210 if (v) 211 { 212 int len; 213 214 len = strlen (v) + 1; 215 216 info->theme = malloc (len); 217 if (info->theme) 218 strcpy (info->theme, v); 219 220 info->theme_from_config = malloc (len); 221 if (info->theme_from_config) 222 strcpy (info->theme_from_config, 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 = malloc (strlen (theme) + 1); 339 if (!copy) 340 return XcursorFalse; 341 strcpy (copy, theme); 342 } 343 else 344 copy = NULL; 345 if (info->theme) 346 free (info->theme); 347 info->theme = copy; 348 return XcursorTrue; 349} 350 351char * 352XcursorGetTheme (Display *dpy) 353{ 354 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 355 356 if (!info) 357 return NULL; 358 return info->theme; 359} 360 361XcursorBool 362XcursorGetThemeCore (Display *dpy) 363{ 364 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 365 366 if (!info) 367 return XcursorFalse; 368 return info->theme_core; 369 370} 371 372XcursorBool 373XcursorSetThemeCore (Display *dpy, XcursorBool theme_core) 374{ 375 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 376 377 if (!info) 378 return XcursorFalse; 379 info->theme_core = theme_core; 380 return XcursorTrue; 381} 382