mirror of OpenBSD xenocara tree github.com/openbsd/xenocara
openbsd
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at jcs 453 lines 12 kB view raw
1/* 2 * Copyright © 2024 Thomas E. Dickey 3 * Copyright © 2002 Keith Packard 4 * 5 * Permission to use, copy, modify, distribute, and sell this software and its 6 * documentation for any purpose is hereby granted without fee, provided that 7 * the above copyright notice appear in all copies and that both that 8 * copyright notice and this permission notice appear in supporting 9 * documentation, and that the name of Keith Packard not be used in 10 * advertising or publicity pertaining to distribution of the software without 11 * specific, written prior permission. Keith Packard makes no 12 * representations about the suitability of this software for any purpose. It 13 * is provided "as is" without express or implied warranty. 14 * 15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 21 * PERFORMANCE OF THIS SOFTWARE. 22 */ 23 24#include "xcursorint.h" 25#include <X11/Xlibint.h> 26#include <X11/Xatom.h> 27#include <stdlib.h> 28 29static XcursorBool 30_XcursorFontIsCursor (Display *dpy, Font font) 31{ 32 XcursorFontInfo *fi; 33 XcursorDisplayInfo *info; 34 XcursorBool ret; 35 XFontStruct *fs; 36 Atom cursor; 37 38 if (!dpy || !font) 39 return XcursorFalse; 40 41 if (font == dpy->cursor_font) 42 return XcursorTrue; 43 44 info = _XcursorGetDisplayInfo (dpy); 45 if (!info) 46 return XcursorFalse; 47 LockDisplay (dpy); 48 for (fi = info->fonts; fi; fi = fi->next) 49 if (fi->font == font) 50 { 51 ret = fi->is_cursor_font; 52 UnlockDisplay (dpy); 53 return ret; 54 } 55 UnlockDisplay (dpy); 56 ret = XcursorFalse; 57 fs = XQueryFont (dpy, font); 58 if (fs) 59 { 60 int n; 61 cursor = XInternAtom (dpy, "cursor", False); 62 for (n = 0; n < fs->n_properties; n++) 63 if (fs->properties[n].name == XA_FONT) 64 { 65 ret = (fs->properties[n].card32 == cursor); 66 break; 67 } 68 XFreeFontInfo (NULL, fs, 1); 69 } 70 fi = malloc (sizeof (XcursorFontInfo)); 71 if (fi) 72 { 73 fi->font = font; 74 fi->is_cursor_font = ret; 75 LockDisplay (dpy); 76 fi->next = info->fonts; 77 info->fonts = fi; 78 UnlockDisplay (dpy); 79 } 80 return ret; 81} 82 83Cursor 84XcursorTryShapeCursor (Display *dpy, 85 Font source_font, 86 Font mask_font, 87 unsigned int source_char, 88 unsigned int mask_char, 89 XColor _Xconst *foreground, 90 XColor _Xconst *background) 91{ 92 Cursor cursor = None; 93 94 enterFunc((T_CALLED(XcursorTryShapeCursor) "(%p, %lu, %lu, %u, %u, %p, %p)\n", 95 (void*)dpy, source_font, mask_font, 96 source_char, mask_char, 97 (const void*)foreground, 98 (const void*)background)); 99 100 if (!dpy || !source_font || !mask_font || !foreground || !background) 101 returnLong(None); 102 103 if (!XcursorSupportsARGB (dpy) && !XcursorGetThemeCore (dpy)) 104 returnLong(None); 105 106 if (source_font == mask_font && 107 _XcursorFontIsCursor (dpy, source_font) && 108 source_char + 1 == mask_char) 109 { 110 XcursorImages *images = _XcursorShapeLoadImages (dpy, source_char); 111 112 if (images) 113 { 114 cursor = XcursorImagesLoadCursor (dpy, images); 115 XcursorImagesDestroy (images); 116 } 117 } 118 returnLong(cursor); 119} 120 121void 122XcursorNoticeCreateBitmap (Display *dpy, 123 Pixmap pid, 124 unsigned int width, 125 unsigned int height) 126{ 127 XcursorDisplayInfo *info; 128 unsigned long oldest; 129 unsigned long now; 130 int i; 131 int replace = 0; 132 XcursorBitmapInfo *bmi; 133 134 enterFunc((T_CALLED(XcursorNoticeCreateBitmap) "(%p, %lu, %u, %u)\n", 135 (void*)dpy, pid, width, height)); 136 137 if (!dpy) 138 returnVoid(); 139 140 if (!XcursorSupportsARGB (dpy) && !XcursorGetThemeCore (dpy)) 141 returnVoid(); 142 143 if (width > MAX_BITMAP_CURSOR_SIZE || height > MAX_BITMAP_CURSOR_SIZE) 144 returnVoid(); 145 146 info = _XcursorGetDisplayInfo (dpy); 147 if (!info) 148 returnVoid(); 149 150 LockDisplay (dpy); 151 replace = 0; 152 now = dpy->request; 153 oldest = now; 154 for (i = 0; i < NUM_BITMAPS; i++) 155 { 156 if (!info->bitmaps[i].bitmap) 157 { 158 replace = i; 159 break; 160 } 161 if ((long) (now - info->bitmaps[i].sequence) > 162 (long) (now - oldest)) 163 { 164 replace = i; 165 oldest = info->bitmaps[i].sequence; 166 } 167 } 168 bmi = &info->bitmaps[replace]; 169 bmi->bitmap = pid; 170 bmi->sequence = now; 171 bmi->width = width; 172 bmi->height = height; 173 bmi->has_image = False; 174 UnlockDisplay (dpy); 175 176 returnVoid(); 177} 178 179static XcursorBitmapInfo * 180_XcursorGetBitmap (Display *dpy, Pixmap bitmap) 181{ 182 XcursorDisplayInfo *info; 183 int i; 184 185 if (!dpy || !bitmap) 186 return NULL; 187 188 info = _XcursorGetDisplayInfo (dpy); 189 190 if (!info) 191 return NULL; 192 LockDisplay (dpy); 193 for (i = 0; i < NUM_BITMAPS; i++) 194 if (info->bitmaps[i].bitmap == bitmap) 195 { 196 info->bitmaps[i].sequence = dpy->request; 197 UnlockDisplay (dpy); 198 return &info->bitmaps[i]; 199 } 200 UnlockDisplay (dpy); 201 return NULL; 202} 203 204static Bool 205_XcursorClientLSB (void) 206{ 207 int v = 1; 208 return *((char *) &v) == 1; 209} 210 211/* stolen from Xlib */ 212static unsigned char const _reverse_byte[0x100] = { 213 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 214 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 215 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 216 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 217 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 218 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 219 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 220 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 221 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 222 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 223 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 224 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 225 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 226 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 227 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 228 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 229 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 230 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 231 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 232 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 233 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 234 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 235 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 236 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 237 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 238 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 239 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 240 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 241 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 242 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 243 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 244 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff 245}; 246 247#define RotByte(t,i) (((t) << (i)) | ((t) >> (8 - (i)))) 248 249void 250XcursorImageHash (XImage *image, 251 unsigned char hash[XCURSOR_BITMAP_HASH_SIZE]) 252{ 253 int i; 254 int x, y; 255 unsigned char *line; 256 unsigned char t; 257 int low_addr; 258 Bool bit_swap; 259 260 enterFunc((T_CALLED(XcursorImageHash) "(%p, %p)\n", 261 (void*)image, (void*)hash)); 262 263 if (!image) 264 returnVoid(); 265 266 for (i = 0; i < XCURSOR_BITMAP_HASH_SIZE; i++) 267 hash[i] = 0; 268 /* 269 * Flip byte order on MSB machines where the bitmap_unit isn't 270 * in bytes 271 */ 272 low_addr = 0; 273 if (image->bitmap_unit != 8) 274 { 275 if (!_XcursorClientLSB()) 276 switch (image->bitmap_unit) { 277 case 16: 278 low_addr = 1; 279 break; 280 case 32: 281 low_addr = 3; 282 break; 283 } 284 } 285 /* 286 * Flip bit order on MSB images 287 */ 288 bit_swap = (image->bitmap_bit_order != LSBFirst); 289 290 line = (unsigned char *) image->data; 291 i = 0; 292 /* 293 * Compute the hash. Yes, it might be nice to use 294 * a stronger hash function, but MD5 and SHA1 are both 295 * a bit to expensive in time and space for this, 296 * and cursors are generally small enough that a weak 297 * hash is sufficient to distinguish among them. 298 */ 299 for (y = 0; y < image->height; y++) 300 { 301 for (x = 0; x < image->bytes_per_line; x++) 302 { 303 t = line[x^low_addr]; 304 if (bit_swap) 305 t = _reverse_byte[t]; 306 if (t) 307 hash[(i++) & (XCURSOR_BITMAP_HASH_SIZE - 1)] ^= (unsigned char) RotByte (t, y & 7); 308 } 309 line += image->bytes_per_line; 310 } 311 312 returnVoid(); 313} 314 315static Bool 316_XcursorLogDiscover (void) 317{ 318 static Bool been_here; 319 static Bool log; 320 321 if (!been_here) 322 { 323 been_here = True; 324 325 if (getenv ("XCURSOR_DISCOVER")) 326 log = True; 327 traceOpts((T_OPTION(XCURSOR_DISCOVER) ": %d\n", log)); 328 } 329 return log; 330} 331 332void 333XcursorNoticePutBitmap (Display *dpy, 334 Drawable draw, 335 XImage *image) 336{ 337 XcursorBitmapInfo *bmi; 338 339 enterFunc((T_CALLED(XcursorNoticePutBitmap ) "(%p, %lu, %p)\n", 340 (void*)dpy, draw, (void*)image)); 341 342 if (!dpy || !image) 343 returnVoid(); 344 345 if (!XcursorSupportsARGB (dpy) && !XcursorGetThemeCore (dpy)) 346 returnVoid(); 347 348 if (image->width > MAX_BITMAP_CURSOR_SIZE || 349 image->height > MAX_BITMAP_CURSOR_SIZE) 350 returnVoid(); 351 352 bmi = _XcursorGetBitmap (dpy, (Pixmap) draw); 353 if (!bmi) 354 returnVoid(); 355 /* 356 * Make sure the image fills the bitmap 357 */ 358 if (image->width != (int)bmi->width || image->height != (int)bmi->height) 359 { 360 bmi->bitmap = 0; 361 returnVoid(); 362 } 363 /* 364 * If multiple images are placed in the same bitmap, 365 * assume it's not going to be a cursor 366 */ 367 if (bmi->has_image) 368 { 369 bmi->bitmap = 0; 370 returnVoid(); 371 } 372 /* 373 * Make sure the image is valid 374 */ 375 if (image->bytes_per_line & ((image->bitmap_unit >> 3) - 1)) 376 { 377 bmi->bitmap = 0; 378 returnVoid(); 379 } 380 /* 381 * Hash the image 382 */ 383 XcursorImageHash (image, bmi->hash); 384 /* 385 * Display the hash value and the image if 386 * requested so that users can find out what 387 * cursor name is associated with each image 388 */ 389 if (_XcursorLogDiscover()) 390 { 391 int x, y; 392 int i; 393 XImage t = *image; 394 395 XInitImage (&t); 396 397 printf ("Cursor image name: "); 398 for (i = 0; i < XCURSOR_BITMAP_HASH_SIZE; i++) 399 printf ("%02x", bmi->hash[i]); 400 printf ("\n"); 401 for (y = 0; y < image->height; y++) 402 { 403 for (x = 0; x < image->width; x++) 404 putchar (XGetPixel (&t, x, y) ? '*' : ' '); 405 putchar ('\n'); 406 } 407 } 408 bmi->has_image = True; 409 returnVoid(); 410} 411 412Cursor 413XcursorTryShapeBitmapCursor (Display *dpy, 414 Pixmap source, 415 Pixmap mask, 416 XColor *foreground, 417 XColor *background, 418 unsigned int x, 419 unsigned int y) 420{ 421 XcursorBitmapInfo *bmi; 422 char name[8 * XCURSOR_BITMAP_HASH_SIZE]; 423 int i; 424 Cursor cursor; 425 426 (void) mask; /* UNUSED */ 427 (void) x; /* UNUSED */ 428 (void) y; /* UNUSED */ 429 430 enterFunc((T_CALLED(XcursorTryShapeBitmapCursor) 431 "(%p, %lu, %lu, %p, %p, %u, %u)\n", 432 (void*)dpy, 433 source, mask, 434 (void*)foreground, 435 (void*)background, 436 x, y)); 437 438 if (!dpy || !foreground || !background) 439 returnLong(None); 440 441 if (!XcursorSupportsARGB (dpy) && !XcursorGetThemeCore (dpy)) 442 returnLong(None); 443 444 bmi = _XcursorGetBitmap (dpy, source); 445 if (!bmi || !bmi->has_image) 446 returnLong(None); 447 for (i = 0; i < XCURSOR_BITMAP_HASH_SIZE; i++) 448 sprintf (name + 2 * i, "%02x", bmi->hash[i]); 449 cursor = XcursorLibraryLoadCursor (dpy, name); 450 if (_XcursorLogDiscover()) 451 printf ("Cursor hash %s returns 0x%x\n", name, (unsigned int) cursor); 452 returnLong(cursor); 453}