| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532 |
- /*
- * Copyright © 2012 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
- #include "config.h"
- #include "xcursor.h"
- #include "wayland-cursor.h"
- #include "wayland-client.h"
- #include <limits.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/mman.h>
- #include <fcntl.h>
- #include <errno.h>
- #include "os-compatibility.h"
- #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
- struct shm_pool {
- struct wl_shm_pool *pool;
- int fd;
- unsigned int size;
- unsigned int used;
- char *data;
- };
- static struct shm_pool *
- shm_pool_create(struct wl_shm *shm, int size)
- {
- struct shm_pool *pool;
- pool = malloc(sizeof *pool);
- if (!pool)
- return NULL;
- pool->fd = os_create_anonymous_file(size);
- if (pool->fd < 0)
- goto err_free;
- pool->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
- pool->fd, 0);
- if (pool->data == MAP_FAILED)
- goto err_close;
- pool->pool = wl_shm_create_pool(shm, pool->fd, size);
- if (!pool->pool)
- goto err_unmap;
- pool->size = size;
- pool->used = 0;
- return pool;
- err_unmap:
- munmap(pool->data, size);
- err_close:
- close(pool->fd);
- err_free:
- free(pool);
- return NULL;
- }
- static int
- shm_pool_resize(struct shm_pool *pool, int size)
- {
- if (os_resize_anonymous_file(pool->fd, size) < 0)
- return 0;
- wl_shm_pool_resize(pool->pool, size);
- munmap(pool->data, pool->size);
- pool->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
- pool->fd, 0);
- if (pool->data == MAP_FAILED)
- return 0;
- pool->size = size;
- return 1;
- }
- static int
- shm_pool_allocate(struct shm_pool *pool, int size)
- {
- int offset;
- if (pool->used + size > pool->size)
- if (!shm_pool_resize(pool, 2 * pool->size + size))
- return -1;
- offset = pool->used;
- pool->used += size;
- return offset;
- }
- static void
- shm_pool_destroy(struct shm_pool *pool)
- {
- munmap(pool->data, pool->size);
- wl_shm_pool_destroy(pool->pool);
- close(pool->fd);
- free(pool);
- }
- struct wl_cursor_theme {
- unsigned int cursor_count;
- struct wl_cursor **cursors;
- struct wl_shm *shm;
- struct shm_pool *pool;
- int size;
- };
- struct cursor_image {
- struct wl_cursor_image image;
- struct wl_cursor_theme *theme;
- struct wl_buffer *buffer;
- int offset; /* data offset of this image in the shm pool */
- };
- struct cursor {
- struct wl_cursor cursor;
- uint32_t total_delay; /* length of the animation in ms */
- };
- /** Get an shm buffer for a cursor image
- *
- * \param image The cursor image
- * \return An shm buffer for the cursor image. The user should not destroy
- * the returned buffer.
- */
- WL_EXPORT struct wl_buffer *
- wl_cursor_image_get_buffer(struct wl_cursor_image *image)
- {
- struct cursor_image *img = (struct cursor_image *) image;
- struct wl_cursor_theme *theme = img->theme;
- if (!img->buffer) {
- img->buffer =
- wl_shm_pool_create_buffer(theme->pool->pool,
- img->offset,
- image->width, image->height,
- image->width * 4,
- WL_SHM_FORMAT_ARGB8888);
- };
- return img->buffer;
- }
- static void
- wl_cursor_image_destroy(struct wl_cursor_image *image)
- {
- struct cursor_image *img = (struct cursor_image *) image;
- if (img->buffer)
- wl_buffer_destroy(img->buffer);
- free(img);
- }
- static void
- wl_cursor_destroy(struct wl_cursor *cursor)
- {
- unsigned int i;
- for (i = 0; i < cursor->image_count; i++)
- wl_cursor_image_destroy(cursor->images[i]);
- free(cursor->images);
- free(cursor->name);
- free(cursor);
- }
- #include "cursor-data.h"
- static struct wl_cursor *
- wl_cursor_create_from_data(struct cursor_metadata *metadata,
- struct wl_cursor_theme *theme)
- {
- struct cursor *cursor;
- struct cursor_image *image;
- int size;
- cursor = malloc(sizeof *cursor);
- if (!cursor)
- return NULL;
- cursor->cursor.image_count = 1;
- cursor->cursor.images = malloc(sizeof *cursor->cursor.images);
- if (!cursor->cursor.images)
- goto err_free_cursor;
- cursor->cursor.name = strdup(metadata->name);
- cursor->total_delay = 0;
- image = malloc(sizeof *image);
- if (!image)
- goto err_free_images;
- cursor->cursor.images[0] = (struct wl_cursor_image *) image;
- image->theme = theme;
- image->buffer = NULL;
- image->image.width = metadata->width;
- image->image.height = metadata->height;
- image->image.hotspot_x = metadata->hotspot_x;
- image->image.hotspot_y = metadata->hotspot_y;
- image->image.delay = 0;
- size = metadata->width * metadata->height * sizeof(uint32_t);
- image->offset = shm_pool_allocate(theme->pool, size);
- if (image->offset < 0)
- goto err_free_image;
- memcpy(theme->pool->data + image->offset,
- cursor_data + metadata->offset, size);
- return &cursor->cursor;
- err_free_image:
- free(image);
- err_free_images:
- free(cursor->cursor.name);
- free(cursor->cursor.images);
- err_free_cursor:
- free(cursor);
- return NULL;
- }
- static void
- load_fallback_theme(struct wl_cursor_theme *theme)
- {
- uint32_t i;
- theme->cursor_count = ARRAY_LENGTH(cursor_metadata);
- theme->cursors = malloc(theme->cursor_count * sizeof(*theme->cursors));
- if (theme->cursors == NULL) {
- theme->cursor_count = 0;
- return;
- }
- for (i = 0; i < theme->cursor_count; ++i) {
- theme->cursors[i] =
- wl_cursor_create_from_data(&cursor_metadata[i], theme);
- if (theme->cursors[i] == NULL)
- break;
- }
- theme->cursor_count = i;
- }
- static struct wl_cursor *
- wl_cursor_create_from_xcursor_images(struct xcursor_images *images,
- struct wl_cursor_theme *theme)
- {
- struct cursor *cursor;
- struct cursor_image *image;
- size_t size;
- int i;
- cursor = malloc(sizeof *cursor);
- if (!cursor)
- return NULL;
- cursor->cursor.images =
- malloc(images->nimage * sizeof cursor->cursor.images[0]);
- if (!cursor->cursor.images) {
- free(cursor);
- return NULL;
- }
- cursor->cursor.name = strdup(images->name);
- cursor->total_delay = 0;
- for (i = 0; i < images->nimage; i++) {
- image = malloc(sizeof *image);
- if (image == NULL)
- break;
- image->theme = theme;
- image->buffer = NULL;
- image->image.width = images->images[i]->width;
- image->image.height = images->images[i]->height;
- image->image.hotspot_x = images->images[i]->xhot;
- image->image.hotspot_y = images->images[i]->yhot;
- image->image.delay = images->images[i]->delay;
- size = (size_t) image->image.width * image->image.height * 4;
- if (size > INT_MAX) {
- free(image);
- break;
- }
- image->offset = shm_pool_allocate(theme->pool, size);
- if (image->offset < 0) {
- free(image);
- break;
- }
- /* copy pixels to shm pool */
- memcpy(theme->pool->data + image->offset,
- images->images[i]->pixels, size);
- cursor->total_delay += image->image.delay;
- cursor->cursor.images[i] = (struct wl_cursor_image *) image;
- }
- cursor->cursor.image_count = i;
- if (cursor->cursor.image_count == 0) {
- free(cursor->cursor.name);
- free(cursor->cursor.images);
- free(cursor);
- return NULL;
- }
- return &cursor->cursor;
- }
- static void
- load_callback(struct xcursor_images *images, void *data)
- {
- struct wl_cursor_theme *theme = data;
- struct wl_cursor *cursor;
- struct wl_cursor **p;
- size_t s;
- if (wl_cursor_theme_get_cursor(theme, images->name)) {
- xcursor_images_destroy(images);
- return;
- }
- cursor = wl_cursor_create_from_xcursor_images(images, theme);
- if (cursor) {
- s = theme->cursor_count + 1;
- p = realloc(theme->cursors, s * sizeof theme->cursors[0]);
- if (p == NULL) {
- free(cursor);
- } else {
- theme->cursor_count = s;
- theme->cursors = p;
- theme->cursors[theme->cursor_count - 1] = cursor;
- }
- }
- xcursor_images_destroy(images);
- }
- /** Load a cursor theme to memory shared with the compositor
- *
- * \param name The name of the cursor theme to load. If %NULL, the default
- * theme will be loaded.
- * \param size Desired size of the cursor images.
- * \param shm The compositor's shm interface.
- *
- * \return An object representing the theme that should be destroyed with
- * wl_cursor_theme_destroy() or %NULL on error. If no theme with the given
- * name exists, a default theme will be loaded.
- */
- WL_EXPORT struct wl_cursor_theme *
- wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm)
- {
- struct wl_cursor_theme *theme;
- theme = malloc(sizeof *theme);
- if (!theme)
- return NULL;
- if (size < 0 || (size > 0 && INT_MAX / size / 4 < size))
- goto err;
- if (!name)
- name = "default";
- theme->size = size;
- theme->cursor_count = 0;
- theme->cursors = NULL;
- theme->pool = shm_pool_create(shm, size * size * 4);
- if (!theme->pool)
- goto err;
- xcursor_load_theme(name, size, load_callback, theme);
- if (theme->cursor_count == 0)
- xcursor_load_theme(NULL, size, load_callback, theme);
- if (theme->cursor_count == 0)
- load_fallback_theme(theme);
- return theme;
- err:
- free(theme);
- return NULL;
- }
- /** Destroys a cursor theme object
- *
- * \param theme The cursor theme to be destroyed
- */
- WL_EXPORT void
- wl_cursor_theme_destroy(struct wl_cursor_theme *theme)
- {
- unsigned int i;
- for (i = 0; i < theme->cursor_count; i++)
- wl_cursor_destroy(theme->cursors[i]);
- shm_pool_destroy(theme->pool);
- free(theme->cursors);
- free(theme);
- }
- /** Get the cursor for a given name from a cursor theme
- *
- * \param theme The cursor theme
- * \param name Name of the desired cursor
- * \return The theme's cursor of the given name or %NULL if there is no
- * such cursor
- */
- WL_EXPORT struct wl_cursor *
- wl_cursor_theme_get_cursor(struct wl_cursor_theme *theme,
- const char *name)
- {
- unsigned int i;
- for (i = 0; i < theme->cursor_count; i++) {
- if (strcmp(name, theme->cursors[i]->name) == 0)
- return theme->cursors[i];
- }
- return NULL;
- }
- /** Find the frame for a given elapsed time in a cursor animation
- * as well as the time left until next cursor change.
- *
- * \param cursor The cursor
- * \param time Elapsed time in ms since the beginning of the animation
- * \param duration pointer to uint32_t to store time left for this image or
- * zero if the cursor won't change.
- *
- * \return The index of the image that should be displayed for the
- * given time in the cursor animation.
- */
- WL_EXPORT int
- wl_cursor_frame_and_duration(struct wl_cursor *cursor, uint32_t time,
- uint32_t *duration)
- {
- struct cursor *cur = (struct cursor *) cursor;
- uint32_t t;
- int i;
- if (cur->cursor.image_count == 1 || cur->total_delay == 0) {
- if (duration)
- *duration = 0;
- return 0;
- }
- i = 0;
- t = time % cur->total_delay;
- /* If there is a 0 delay in the image set then this
- * loop breaks on it and we display that cursor until
- * time % cursor->total_delay wraps again.
- * Since a 0 delay is silly, and we've never actually
- * seen one in a cursor file, we haven't bothered to
- * "fix" this.
- */
- while (t - cur->cursor.images[i]->delay < t)
- t -= cur->cursor.images[i++]->delay;
- if (!duration)
- return i;
- /* Make sure we don't accidentally tell the caller this is
- * a static cursor image.
- */
- if (t >= cur->cursor.images[i]->delay)
- *duration = 1;
- else
- *duration = cur->cursor.images[i]->delay - t;
- return i;
- }
- /** Find the frame for a given elapsed time in a cursor animation
- *
- * \param cursor The cursor
- * \param time Elapsed time in ms since the beginning of the animation
- *
- * \return The index of the image that should be displayed for the
- * given time in the cursor animation.
- */
- WL_EXPORT int
- wl_cursor_frame(struct wl_cursor *cursor, uint32_t time)
- {
- return wl_cursor_frame_and_duration(cursor, time, NULL);
- }
|