1 /* 2 * Copyright 2012 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files (the 6 * "Software"), to deal in the Software without restriction, including 7 * without limitation the rights to use, copy, modify, merge, publish, 8 * distribute, sublicense, and/or sell copies of the Software, and to 9 * permit persons to whom the Software is furnished to do so, subject to 10 * the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the 13 * next paragraph) shall be included in all copies or substantial 14 * portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 */ 25 26 #include "config.h" 27 #include "xcursor.h" 28 #include "wayland-cursor.h" 29 #include "wayland-client.h" 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <stdint.h> 33 #include <string.h> 34 #include <unistd.h> 35 #include <sys/mman.h> 36 #include <fcntl.h> 37 #include <errno.h> 38 39 #include "os-compatibility.h" 40 41 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) 42 43 struct shm_pool { 44 struct wl_shm_pool *pool; 45 int fd; 46 unsigned int size; 47 unsigned int used; 48 char *data; 49 }; 50 51 static struct shm_pool * 52 shm_pool_create(struct wl_shm *shm, int size) 53 { 54 struct shm_pool *pool; 55 56 pool = malloc(sizeof *pool); 57 if (!pool) 58 return NULL; 59 60 pool->fd = os_create_anonymous_file(size); 61 if (pool->fd < 0) 62 goto err_free; 63 64 pool->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, 65 pool->fd, 0); 66 67 if (pool->data == MAP_FAILED) 68 goto err_close; 69 70 pool->pool = wl_shm_create_pool(shm, pool->fd, size); 71 pool->size = size; 72 pool->used = 0; 73 74 return pool; 75 76 err_close: 77 close(pool->fd); 78 err_free: 79 free(pool); 80 return NULL; 81 } 82 83 static int 84 shm_pool_resize(struct shm_pool *pool, int size) 85 { 86 if (ftruncate(pool->fd, size) < 0) 87 return 0; 88 89 #ifdef HAVE_POSIX_FALLOCATE 90 errno = posix_fallocate(pool->fd, 0, size); 91 if (errno != 0) 92 return 0; 93 #endif 94 95 wl_shm_pool_resize(pool->pool, size); 96 97 munmap(pool->data, pool->size); 98 99 pool->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, 100 pool->fd, 0); 101 if (pool->data == (void *)-1) 102 return 0; 103 pool->size = size; 104 105 return 1; 106 } 107 108 static int 109 shm_pool_allocate(struct shm_pool *pool, int size) 110 { 111 int offset; 112 113 if (pool->used + size > pool->size) 114 if (!shm_pool_resize(pool, 2 * pool->size + size)) 115 return -1; 116 117 offset = pool->used; 118 pool->used += size; 119 120 return offset; 121 } 122 123 static void 124 shm_pool_destroy(struct shm_pool *pool) 125 { 126 munmap(pool->data, pool->size); 127 wl_shm_pool_destroy(pool->pool); 128 close(pool->fd); 129 free(pool); 130 } 131 132 133 struct wl_cursor_theme { 134 unsigned int cursor_count; 135 struct wl_cursor **cursors; 136 struct wl_shm *shm; 137 struct shm_pool *pool; 138 char *name; 139 int size; 140 }; 141 142 struct cursor_image { 143 struct wl_cursor_image image; 144 struct wl_cursor_theme *theme; 145 struct wl_buffer *buffer; 146 int offset; /* data offset of this image in the shm pool */ 147 }; 148 149 struct cursor { 150 struct wl_cursor cursor; 151 uint32_t total_delay; /* length of the animation in ms */ 152 }; 153 154 /** Get an shm buffer for a cursor image 155 * 156 * \param image The cursor image 157 * \return An shm buffer for the cursor image. The user should not destroy 158 * the returned buffer. 159 */ 160 WL_EXPORT struct wl_buffer * 161 wl_cursor_image_get_buffer(struct wl_cursor_image *_img) 162 { 163 struct cursor_image *image = (struct cursor_image *) _img; 164 struct wl_cursor_theme *theme = image->theme; 165 166 if (!image->buffer) { 167 image->buffer = 168 wl_shm_pool_create_buffer(theme->pool->pool, 169 image->offset, 170 _img->width, _img->height, 171 _img->width * 4, 172 WL_SHM_FORMAT_ARGB8888); 173 }; 174 175 return image->buffer; 176 } 177 178 static void 179 wl_cursor_image_destroy(struct wl_cursor_image *_img) 180 { 181 struct cursor_image *image = (struct cursor_image *) _img; 182 183 if (image->buffer) 184 wl_buffer_destroy(image->buffer); 185 186 free(image); 187 } 188 189 static void 190 wl_cursor_destroy(struct wl_cursor *cursor) 191 { 192 unsigned int i; 193 194 for (i = 0; i < cursor->image_count; i++) 195 wl_cursor_image_destroy(cursor->images[i]); 196 197 free(cursor->images); 198 free(cursor->name); 199 free(cursor); 200 } 201 202 #include "cursor-data.h" 203 204 static struct wl_cursor * 205 wl_cursor_create_from_data(struct cursor_metadata *metadata, 206 struct wl_cursor_theme *theme) 207 { 208 struct cursor *cursor; 209 struct cursor_image *image; 210 int size; 211 212 cursor = malloc(sizeof *cursor); 213 if (!cursor) 214 return NULL; 215 216 cursor->cursor.image_count = 1; 217 cursor->cursor.images = malloc(sizeof *cursor->cursor.images); 218 if (!cursor->cursor.images) 219 goto err_free_cursor; 220 221 cursor->cursor.name = strdup(metadata->name); 222 cursor->total_delay = 0; 223 224 image = malloc(sizeof *image); 225 if (!image) 226 goto err_free_images; 227 228 cursor->cursor.images[0] = (struct wl_cursor_image *) image; 229 image->theme = theme; 230 image->buffer = NULL; 231 image->image.width = metadata->width; 232 image->image.height = metadata->height; 233 image->image.hotspot_x = metadata->hotspot_x; 234 image->image.hotspot_y = metadata->hotspot_y; 235 image->image.delay = 0; 236 237 size = metadata->width * metadata->height * sizeof(uint32_t); 238 image->offset = shm_pool_allocate(theme->pool, size); 239 240 if (image->offset < 0) 241 goto err_free_image; 242 243 memcpy(theme->pool->data + image->offset, 244 cursor_data + metadata->offset, size); 245 246 return &cursor->cursor; 247 248 err_free_image: 249 free(image); 250 251 err_free_images: 252 free(cursor->cursor.name); 253 free(cursor->cursor.images); 254 255 err_free_cursor: 256 free(cursor); 257 return NULL; 258 } 259 260 static void 261 load_default_theme(struct wl_cursor_theme *theme) 262 { 263 uint32_t i; 264 265 free(theme->name); 266 theme->name = strdup("default"); 267 268 theme->cursor_count = ARRAY_LENGTH(cursor_metadata); 269 theme->cursors = malloc(theme->cursor_count * sizeof(*theme->cursors)); 270 271 if (theme->cursors == NULL) { 272 theme->cursor_count = 0; 273 return; 274 } 275 276 for (i = 0; i < theme->cursor_count; ++i) { 277 theme->cursors[i] = 278 wl_cursor_create_from_data(&cursor_metadata[i], theme); 279 280 if (theme->cursors[i] == NULL) 281 break; 282 } 283 theme->cursor_count = i; 284 } 285 286 static struct wl_cursor * 287 wl_cursor_create_from_xcursor_images(XcursorImages *images, 288 struct wl_cursor_theme *theme) 289 { 290 struct cursor *cursor; 291 struct cursor_image *image; 292 int i, size; 293 294 cursor = malloc(sizeof *cursor); 295 if (!cursor) 296 return NULL; 297 298 cursor->cursor.images = 299 malloc(images->nimage * sizeof cursor->cursor.images[0]); 300 if (!cursor->cursor.images) { 301 free(cursor); 302 return NULL; 303 } 304 305 cursor->cursor.name = strdup(images->name); 306 cursor->total_delay = 0; 307 308 for (i = 0; i < images->nimage; i++) { 309 image = malloc(sizeof *image); 310 if (image == NULL) 311 break; 312 313 image->theme = theme; 314 image->buffer = NULL; 315 316 image->image.width = images->images[i]->width; 317 image->image.height = images->images[i]->height; 318 image->image.hotspot_x = images->images[i]->xhot; 319 image->image.hotspot_y = images->images[i]->yhot; 320 image->image.delay = images->images[i]->delay; 321 322 size = image->image.width * image->image.height * 4; 323 image->offset = shm_pool_allocate(theme->pool, size); 324 if (image->offset < 0) { 325 free(image); 326 break; 327 } 328 329 /* copy pixels to shm pool */ 330 memcpy(theme->pool->data + image->offset, 331 images->images[i]->pixels, size); 332 cursor->total_delay += image->image.delay; 333 cursor->cursor.images[i] = (struct wl_cursor_image *) image; 334 } 335 cursor->cursor.image_count = i; 336 337 if (cursor->cursor.image_count == 0) { 338 free(cursor->cursor.name); 339 free(cursor->cursor.images); 340 free(cursor); 341 return NULL; 342 } 343 344 return &cursor->cursor; 345 } 346 347 static void 348 load_callback(XcursorImages *images, void *data) 349 { 350 struct wl_cursor_theme *theme = data; 351 struct wl_cursor *cursor; 352 353 if (wl_cursor_theme_get_cursor(theme, images->name)) { 354 XcursorImagesDestroy(images); 355 return; 356 } 357 358 cursor = wl_cursor_create_from_xcursor_images(images, theme); 359 360 if (cursor) { 361 theme->cursor_count++; 362 theme->cursors = 363 realloc(theme->cursors, 364 theme->cursor_count * sizeof theme->cursors[0]); 365 366 if (theme->cursors == NULL) { 367 theme->cursor_count--; 368 free(cursor); 369 } else { 370 theme->cursors[theme->cursor_count - 1] = cursor; 371 } 372 } 373 374 XcursorImagesDestroy(images); 375 } 376 377 /** Load a cursor theme to memory shared with the compositor 378 * 379 * \param name The name of the cursor theme to load. If %NULL, the default 380 * theme will be loaded. 381 * \param size Desired size of the cursor images. 382 * \param shm The compositor's shm interface. 383 * 384 * \return An object representing the theme that should be destroyed with 385 * wl_cursor_theme_destroy() or %NULL on error. If no theme with the given 386 * name exists, a default theme will be loaded. 387 */ 388 WL_EXPORT struct wl_cursor_theme * 389 wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm) 390 { 391 struct wl_cursor_theme *theme; 392 393 theme = malloc(sizeof *theme); 394 if (!theme) 395 return NULL; 396 397 if (!name) 398 name = "default"; 399 400 theme->name = strdup(name); 401 if (!theme->name) 402 goto out_error_name; 403 theme->size = size; 404 theme->cursor_count = 0; 405 theme->cursors = NULL; 406 407 theme->pool = shm_pool_create(shm, size * size * 4); 408 if (!theme->pool) 409 goto out_error_pool; 410 411 xcursor_load_theme(name, size, load_callback, theme); 412 413 if (theme->cursor_count == 0) 414 load_default_theme(theme); 415 416 return theme; 417 418 out_error_pool: 419 free(theme->name); 420 out_error_name: 421 free(theme); 422 return NULL; 423 } 424 425 /** Destroys a cursor theme object 426 * 427 * \param theme The cursor theme to be destroyed 428 */ 429 WL_EXPORT void 430 wl_cursor_theme_destroy(struct wl_cursor_theme *theme) 431 { 432 unsigned int i; 433 434 for (i = 0; i < theme->cursor_count; i++) 435 wl_cursor_destroy(theme->cursors[i]); 436 437 shm_pool_destroy(theme->pool); 438 439 free(theme->name); 440 free(theme->cursors); 441 free(theme); 442 } 443 444 /** Get the cursor for a given name from a cursor theme 445 * 446 * \param theme The cursor theme 447 * \param name Name of the desired cursor 448 * \return The theme's cursor of the given name or %NULL if there is no 449 * such cursor 450 */ 451 WL_EXPORT struct wl_cursor * 452 wl_cursor_theme_get_cursor(struct wl_cursor_theme *theme, 453 const char *name) 454 { 455 unsigned int i; 456 457 for (i = 0; i < theme->cursor_count; i++) { 458 if (strcmp(name, theme->cursors[i]->name) == 0) 459 return theme->cursors[i]; 460 } 461 462 return NULL; 463 } 464 465 /** Find the frame for a given elapsed time in a cursor animation 466 * as well as the time left until next cursor change. 467 * 468 * \param cursor The cursor 469 * \param time Elapsed time in ms since the beginning of the animation 470 * \param duration pointer to uint32_t to store time left for this image or 471 * zero if the cursor won't change. 472 * 473 * \return The index of the image that should be displayed for the 474 * given time in the cursor animation. 475 */ 476 WL_EXPORT int 477 wl_cursor_frame_and_duration(struct wl_cursor *_cursor, uint32_t time, 478 uint32_t *duration) 479 { 480 struct cursor *cursor = (struct cursor *) _cursor; 481 uint32_t t; 482 int i; 483 484 if (cursor->cursor.image_count == 1) { 485 if (duration) 486 *duration = 0; 487 return 0; 488 } 489 490 i = 0; 491 t = time % cursor->total_delay; 492 493 /* If there is a 0 delay in the image set then this 494 * loop breaks on it and we display that cursor until 495 * time % cursor->total_delay wraps again. 496 * Since a 0 delay is silly, and we've never actually 497 * seen one in a cursor file, we haven't bothered to 498 * "fix" this. 499 */ 500 while (t - cursor->cursor.images[i]->delay < t) 501 t -= cursor->cursor.images[i++]->delay; 502 503 if (!duration) 504 return i; 505 506 /* Make sure we don't accidentally tell the caller this is 507 * a static cursor image. 508 */ 509 if (t >= cursor->cursor.images[i]->delay) 510 *duration = 1; 511 else 512 *duration = cursor->cursor.images[i]->delay - t; 513 514 return i; 515 } 516 517 /** Find the frame for a given elapsed time in a cursor animation 518 * 519 * \param cursor The cursor 520 * \param time Elapsed time in ms since the beginning of the animation 521 * 522 * \return The index of the image that should be displayed for the 523 * given time in the cursor animation. 524 */ 525 WL_EXPORT int 526 wl_cursor_frame(struct wl_cursor *_cursor, uint32_t time) 527 { 528 return wl_cursor_frame_and_duration(_cursor, time, NULL); 529 } 530