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