display.c revision c63293b5
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 int len; 220 221 len = strlen (v) + 1; 222 223 info->theme = malloc (len); 224 if (info->theme) 225 strcpy (info->theme, v); 226 227 info->theme_from_config = malloc (len); 228 if (info->theme_from_config) 229 strcpy (info->theme_from_config, v); 230 } 231 232 /* 233 * Get the desired dither 234 */ 235 info->dither = XcursorDitherThreshold; 236 v = getenv ("XCURSOR_DITHER"); 237 if (!v) 238 v = XGetDefault (dpy, "Xcursor", "dither"); 239 if (v) 240 { 241 if (!strcmp (v, "threshold")) 242 info->dither = XcursorDitherThreshold; 243 if (!strcmp (v, "median")) 244 info->dither = XcursorDitherMedian; 245 if (!strcmp (v, "ordered")) 246 info->dither = XcursorDitherOrdered; 247 if (!strcmp (v, "diffuse")) 248 info->dither = XcursorDitherDiffuse; 249 } 250 251 info->theme_core = False; 252 /* 253 * Find out if core cursors should 254 * be themed 255 */ 256 v = getenv ("XCURSOR_THEME_CORE"); 257 if (!v) 258 v = XGetDefault (dpy, "Xcursor", "theme_core"); 259 if (v) 260 { 261 i = _XcursorDefaultParseBool (v); 262 if (i >= 0) 263 info->theme_core = i; 264 } 265 266 info->fonts = NULL; 267 for (i = 0; i < NUM_BITMAPS; i++) 268 info->bitmaps[i].bitmap = None; 269 270 /* 271 * Link new info info list, making sure another 272 * thread hasn't inserted something into the list while 273 * this one was busy setting up the data 274 */ 275 _XLockMutex (_Xglobal_lock); 276 for (old = _XcursorDisplayInfo; old; old = old->next) 277 if (old->display == dpy) 278 break; 279 if (old) 280 { 281 _XcursorFreeDisplayInfo (info); 282 info = old; 283 } 284 else 285 { 286 info->next = _XcursorDisplayInfo; 287 _XcursorDisplayInfo = info; 288 } 289 _XUnlockMutex (_Xglobal_lock); 290 291 return info; 292} 293 294XcursorBool 295XcursorSupportsARGB (Display *dpy) 296{ 297 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 298 299 return info && info->has_render_cursor; 300} 301 302XcursorBool 303XcursorSupportsAnim (Display *dpy) 304{ 305 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 306 307 return info && info->has_anim_cursor; 308} 309 310XcursorBool 311XcursorSetDefaultSize (Display *dpy, int size) 312{ 313 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 314 315 if (!info) 316 return XcursorFalse; 317 info->size = size; 318 return XcursorTrue; 319} 320 321int 322XcursorGetDefaultSize (Display *dpy) 323{ 324 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 325 326 if (!info) 327 return 0; 328 return info->size; 329} 330 331XcursorBool 332XcursorSetTheme (Display *dpy, const char *theme) 333{ 334 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 335 char *copy; 336 337 if (!info) 338 return XcursorFalse; 339 340 if (!theme) 341 theme = info->theme_from_config; 342 343 if (theme) 344 { 345 copy = malloc (strlen (theme) + 1); 346 if (!copy) 347 return XcursorFalse; 348 strcpy (copy, theme); 349 } 350 else 351 copy = NULL; 352 if (info->theme) 353 free (info->theme); 354 info->theme = copy; 355 return XcursorTrue; 356} 357 358char * 359XcursorGetTheme (Display *dpy) 360{ 361 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 362 363 if (!info) 364 return NULL; 365 return info->theme; 366} 367 368XcursorBool 369XcursorGetThemeCore (Display *dpy) 370{ 371 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 372 373 if (!info) 374 return XcursorFalse; 375 return info->theme_core; 376 377} 378 379XcursorBool 380XcursorSetThemeCore (Display *dpy, XcursorBool theme_core) 381{ 382 XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy); 383 384 if (!info) 385 return XcursorFalse; 386 info->theme_core = theme_core; 387 return XcursorTrue; 388} 389