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 *
shm_pool_create(struct wl_shm * shm,int size)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
shm_pool_resize(struct shm_pool * pool,int size)84 shm_pool_resize(struct shm_pool *pool, int size)
85 {
86 if (os_resize_anonymous_file(pool->fd, size) < 0)
87 return 0;
88
89 wl_shm_pool_resize(pool->pool, size);
90
91 munmap(pool->data, pool->size);
92
93 pool->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
94 pool->fd, 0);
95 if (pool->data == (void *)-1)
96 return 0;
97 pool->size = size;
98
99 return 1;
100 }
101
102 static int
shm_pool_allocate(struct shm_pool * pool,int size)103 shm_pool_allocate(struct shm_pool *pool, int size)
104 {
105 int offset;
106
107 if (pool->used + size > pool->size)
108 if (!shm_pool_resize(pool, 2 * pool->size + size))
109 return -1;
110
111 offset = pool->used;
112 pool->used += size;
113
114 return offset;
115 }
116
117 static void
shm_pool_destroy(struct shm_pool * pool)118 shm_pool_destroy(struct shm_pool *pool)
119 {
120 munmap(pool->data, pool->size);
121 wl_shm_pool_destroy(pool->pool);
122 close(pool->fd);
123 free(pool);
124 }
125
126
127 struct wl_cursor_theme {
128 unsigned int cursor_count;
129 struct wl_cursor **cursors;
130 struct wl_shm *shm;
131 struct shm_pool *pool;
132 char *name;
133 int size;
134 };
135
136 struct cursor_image {
137 struct wl_cursor_image image;
138 struct wl_cursor_theme *theme;
139 struct wl_buffer *buffer;
140 int offset; /* data offset of this image in the shm pool */
141 };
142
143 struct cursor {
144 struct wl_cursor cursor;
145 uint32_t total_delay; /* length of the animation in ms */
146 };
147
148 /** Get an shm buffer for a cursor image
149 *
150 * \param image The cursor image
151 * \return An shm buffer for the cursor image. The user should not destroy
152 * the returned buffer.
153 */
154 WL_EXPORT struct wl_buffer *
wl_cursor_image_get_buffer(struct wl_cursor_image * _img)155 wl_cursor_image_get_buffer(struct wl_cursor_image *_img)
156 {
157 struct cursor_image *image = (struct cursor_image *) _img;
158 struct wl_cursor_theme *theme = image->theme;
159
160 if (!image->buffer) {
161 image->buffer =
162 wl_shm_pool_create_buffer(theme->pool->pool,
163 image->offset,
164 _img->width, _img->height,
165 _img->width * 4,
166 WL_SHM_FORMAT_ARGB8888);
167 };
168
169 return image->buffer;
170 }
171
172 static void
wl_cursor_image_destroy(struct wl_cursor_image * _img)173 wl_cursor_image_destroy(struct wl_cursor_image *_img)
174 {
175 struct cursor_image *image = (struct cursor_image *) _img;
176
177 if (image->buffer)
178 wl_buffer_destroy(image->buffer);
179
180 free(image);
181 }
182
183 static void
wl_cursor_destroy(struct wl_cursor * cursor)184 wl_cursor_destroy(struct wl_cursor *cursor)
185 {
186 unsigned int i;
187
188 for (i = 0; i < cursor->image_count; i++)
189 wl_cursor_image_destroy(cursor->images[i]);
190
191 free(cursor->images);
192 free(cursor->name);
193 free(cursor);
194 }
195
196 #include "cursor-data.h"
197
198 static struct wl_cursor *
wl_cursor_create_from_data(struct cursor_metadata * metadata,struct wl_cursor_theme * theme)199 wl_cursor_create_from_data(struct cursor_metadata *metadata,
200 struct wl_cursor_theme *theme)
201 {
202 struct cursor *cursor;
203 struct cursor_image *image;
204 int size;
205
206 cursor = malloc(sizeof *cursor);
207 if (!cursor)
208 return NULL;
209
210 cursor->cursor.image_count = 1;
211 cursor->cursor.images = malloc(sizeof *cursor->cursor.images);
212 if (!cursor->cursor.images)
213 goto err_free_cursor;
214
215 cursor->cursor.name = strdup(metadata->name);
216 cursor->total_delay = 0;
217
218 image = malloc(sizeof *image);
219 if (!image)
220 goto err_free_images;
221
222 cursor->cursor.images[0] = (struct wl_cursor_image *) image;
223 image->theme = theme;
224 image->buffer = NULL;
225 image->image.width = metadata->width;
226 image->image.height = metadata->height;
227 image->image.hotspot_x = metadata->hotspot_x;
228 image->image.hotspot_y = metadata->hotspot_y;
229 image->image.delay = 0;
230
231 size = metadata->width * metadata->height * sizeof(uint32_t);
232 image->offset = shm_pool_allocate(theme->pool, size);
233
234 if (image->offset < 0)
235 goto err_free_image;
236
237 memcpy(theme->pool->data + image->offset,
238 cursor_data + metadata->offset, size);
239
240 return &cursor->cursor;
241
242 err_free_image:
243 free(image);
244
245 err_free_images:
246 free(cursor->cursor.name);
247 free(cursor->cursor.images);
248
249 err_free_cursor:
250 free(cursor);
251 return NULL;
252 }
253
254 static void
load_default_theme(struct wl_cursor_theme * theme)255 load_default_theme(struct wl_cursor_theme *theme)
256 {
257 uint32_t i;
258
259 free(theme->name);
260 theme->name = strdup("default");
261
262 theme->cursor_count = ARRAY_LENGTH(cursor_metadata);
263 theme->cursors = malloc(theme->cursor_count * sizeof(*theme->cursors));
264
265 if (theme->cursors == NULL) {
266 theme->cursor_count = 0;
267 return;
268 }
269
270 for (i = 0; i < theme->cursor_count; ++i) {
271 theme->cursors[i] =
272 wl_cursor_create_from_data(&cursor_metadata[i], theme);
273
274 if (theme->cursors[i] == NULL)
275 break;
276 }
277 theme->cursor_count = i;
278 }
279
280 static struct wl_cursor *
wl_cursor_create_from_xcursor_images(XcursorImages * images,struct wl_cursor_theme * theme)281 wl_cursor_create_from_xcursor_images(XcursorImages *images,
282 struct wl_cursor_theme *theme)
283 {
284 struct cursor *cursor;
285 struct cursor_image *image;
286 int i, size;
287
288 cursor = malloc(sizeof *cursor);
289 if (!cursor)
290 return NULL;
291
292 cursor->cursor.images =
293 malloc(images->nimage * sizeof cursor->cursor.images[0]);
294 if (!cursor->cursor.images) {
295 free(cursor);
296 return NULL;
297 }
298
299 cursor->cursor.name = strdup(images->name);
300 cursor->total_delay = 0;
301
302 for (i = 0; i < images->nimage; i++) {
303 image = malloc(sizeof *image);
304 if (image == NULL)
305 break;
306
307 image->theme = theme;
308 image->buffer = NULL;
309
310 image->image.width = images->images[i]->width;
311 image->image.height = images->images[i]->height;
312 image->image.hotspot_x = images->images[i]->xhot;
313 image->image.hotspot_y = images->images[i]->yhot;
314 image->image.delay = images->images[i]->delay;
315
316 size = image->image.width * image->image.height * 4;
317 image->offset = shm_pool_allocate(theme->pool, size);
318 if (image->offset < 0) {
319 free(image);
320 break;
321 }
322
323 /* copy pixels to shm pool */
324 memcpy(theme->pool->data + image->offset,
325 images->images[i]->pixels, size);
326 cursor->total_delay += image->image.delay;
327 cursor->cursor.images[i] = (struct wl_cursor_image *) image;
328 }
329 cursor->cursor.image_count = i;
330
331 if (cursor->cursor.image_count == 0) {
332 free(cursor->cursor.name);
333 free(cursor->cursor.images);
334 free(cursor);
335 return NULL;
336 }
337
338 return &cursor->cursor;
339 }
340
341 static void
load_callback(XcursorImages * images,void * data)342 load_callback(XcursorImages *images, void *data)
343 {
344 struct wl_cursor_theme *theme = data;
345 struct wl_cursor *cursor;
346
347 if (wl_cursor_theme_get_cursor(theme, images->name)) {
348 XcursorImagesDestroy(images);
349 return;
350 }
351
352 cursor = wl_cursor_create_from_xcursor_images(images, theme);
353
354 if (cursor) {
355 theme->cursor_count++;
356 theme->cursors =
357 realloc(theme->cursors,
358 theme->cursor_count * sizeof theme->cursors[0]);
359
360 if (theme->cursors == NULL) {
361 theme->cursor_count--;
362 free(cursor);
363 } else {
364 theme->cursors[theme->cursor_count - 1] = cursor;
365 }
366 }
367
368 XcursorImagesDestroy(images);
369 }
370
371 /** Load a cursor theme to memory shared with the compositor
372 *
373 * \param name The name of the cursor theme to load. If %NULL, the default
374 * theme will be loaded.
375 * \param size Desired size of the cursor images.
376 * \param shm The compositor's shm interface.
377 *
378 * \return An object representing the theme that should be destroyed with
379 * wl_cursor_theme_destroy() or %NULL on error. If no theme with the given
380 * name exists, a default theme will be loaded.
381 */
382 WL_EXPORT struct wl_cursor_theme *
wl_cursor_theme_load(const char * name,int size,struct wl_shm * shm)383 wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm)
384 {
385 struct wl_cursor_theme *theme;
386
387 theme = malloc(sizeof *theme);
388 if (!theme)
389 return NULL;
390
391 if (!name)
392 name = "default";
393
394 theme->name = strdup(name);
395 if (!theme->name)
396 goto out_error_name;
397 theme->size = size;
398 theme->cursor_count = 0;
399 theme->cursors = NULL;
400
401 theme->pool = shm_pool_create(shm, size * size * 4);
402 if (!theme->pool)
403 goto out_error_pool;
404
405 xcursor_load_theme(name, size, load_callback, theme);
406
407 if (theme->cursor_count == 0)
408 load_default_theme(theme);
409
410 return theme;
411
412 out_error_pool:
413 free(theme->name);
414 out_error_name:
415 free(theme);
416 return NULL;
417 }
418
419 /** Destroys a cursor theme object
420 *
421 * \param theme The cursor theme to be destroyed
422 */
423 WL_EXPORT void
wl_cursor_theme_destroy(struct wl_cursor_theme * theme)424 wl_cursor_theme_destroy(struct wl_cursor_theme *theme)
425 {
426 unsigned int i;
427
428 for (i = 0; i < theme->cursor_count; i++)
429 wl_cursor_destroy(theme->cursors[i]);
430
431 shm_pool_destroy(theme->pool);
432
433 free(theme->name);
434 free(theme->cursors);
435 free(theme);
436 }
437
438 /** Get the cursor for a given name from a cursor theme
439 *
440 * \param theme The cursor theme
441 * \param name Name of the desired cursor
442 * \return The theme's cursor of the given name or %NULL if there is no
443 * such cursor
444 */
445 WL_EXPORT struct wl_cursor *
wl_cursor_theme_get_cursor(struct wl_cursor_theme * theme,const char * name)446 wl_cursor_theme_get_cursor(struct wl_cursor_theme *theme,
447 const char *name)
448 {
449 unsigned int i;
450
451 for (i = 0; i < theme->cursor_count; i++) {
452 if (strcmp(name, theme->cursors[i]->name) == 0)
453 return theme->cursors[i];
454 }
455
456 return NULL;
457 }
458
459 /** Find the frame for a given elapsed time in a cursor animation
460 * as well as the time left until next cursor change.
461 *
462 * \param cursor The cursor
463 * \param time Elapsed time in ms since the beginning of the animation
464 * \param duration pointer to uint32_t to store time left for this image or
465 * zero if the cursor won't change.
466 *
467 * \return The index of the image that should be displayed for the
468 * given time in the cursor animation.
469 */
470 WL_EXPORT int
wl_cursor_frame_and_duration(struct wl_cursor * _cursor,uint32_t time,uint32_t * duration)471 wl_cursor_frame_and_duration(struct wl_cursor *_cursor, uint32_t time,
472 uint32_t *duration)
473 {
474 struct cursor *cursor = (struct cursor *) _cursor;
475 uint32_t t;
476 int i;
477
478 if (cursor->cursor.image_count == 1) {
479 if (duration)
480 *duration = 0;
481 return 0;
482 }
483
484 i = 0;
485 t = time % cursor->total_delay;
486
487 /* If there is a 0 delay in the image set then this
488 * loop breaks on it and we display that cursor until
489 * time % cursor->total_delay wraps again.
490 * Since a 0 delay is silly, and we've never actually
491 * seen one in a cursor file, we haven't bothered to
492 * "fix" this.
493 */
494 while (t - cursor->cursor.images[i]->delay < t)
495 t -= cursor->cursor.images[i++]->delay;
496
497 if (!duration)
498 return i;
499
500 /* Make sure we don't accidentally tell the caller this is
501 * a static cursor image.
502 */
503 if (t >= cursor->cursor.images[i]->delay)
504 *duration = 1;
505 else
506 *duration = cursor->cursor.images[i]->delay - t;
507
508 return i;
509 }
510
511 /** Find the frame for a given elapsed time in a cursor animation
512 *
513 * \param cursor The cursor
514 * \param time Elapsed time in ms since the beginning of the animation
515 *
516 * \return The index of the image that should be displayed for the
517 * given time in the cursor animation.
518 */
519 WL_EXPORT int
wl_cursor_frame(struct wl_cursor * _cursor,uint32_t time)520 wl_cursor_frame(struct wl_cursor *_cursor, uint32_t time)
521 {
522 return wl_cursor_frame_and_duration(_cursor, time, NULL);
523 }
524