mirror of
https://gitlab.freedesktop.org/wayland/wayland.git
synced 2025-10-29 05:40:16 -04:00
Introduce libwayland-cursor, a cursor helper library
The purpose of this library is to be the equivalent of libXcursor in the X world. This library is compatible with X cursor themes and loads them directly into an shm pool making it easy for the clients to get buffer for each cursor image. The code for handling the X cursor theme was taken from libXcursor. The files cursor/xcursor.[ch] are a stripped down version of that library containing only the interfaces necessary for implementing the wayland counterpart.
This commit is contained in:
parent
ff0d745674
commit
775002c6c0
8 changed files with 1375 additions and 1 deletions
356
cursor/wayland-cursor.c
Normal file
356
cursor/wayland-cursor.c
Normal file
|
|
@ -0,0 +1,356 @@
|
|||
/*
|
||||
* Copyright © 2012 Intel Corporation
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "xcursor.h"
|
||||
#include "wayland-cursor.h"
|
||||
#include "wayland-client.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
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;
|
||||
char filename[] = "/tmp/wayland-shm-XXXXXX";
|
||||
|
||||
pool = malloc(sizeof *pool);
|
||||
if (!pool)
|
||||
return NULL;
|
||||
|
||||
pool->fd = mkstemp(filename);
|
||||
if (pool->fd < 0)
|
||||
return NULL;
|
||||
|
||||
if (ftruncate(pool->fd, size) < 0) {
|
||||
close(pool->fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pool->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
pool->fd, 0);
|
||||
unlink(filename);
|
||||
|
||||
if (pool->data == MAP_FAILED) {
|
||||
close(pool->fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pool->pool = wl_shm_create_pool(shm, pool->fd, size);
|
||||
pool->size = size;
|
||||
pool->used = 0;
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
static int
|
||||
shm_pool_resize(struct shm_pool *pool, int size)
|
||||
{
|
||||
if (ftruncate(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);
|
||||
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);
|
||||
free(pool);
|
||||
}
|
||||
|
||||
|
||||
static const char *cursor_names[] = {
|
||||
"bottom_left_corner",
|
||||
"bottom_right_corner",
|
||||
"bottom_side",
|
||||
"grabbing",
|
||||
"left_ptr",
|
||||
"left_side",
|
||||
"right_side",
|
||||
"top_left_corner",
|
||||
"top_right_corner",
|
||||
"top_side",
|
||||
"xterm",
|
||||
"hand1",
|
||||
};
|
||||
|
||||
struct wl_cursor_theme {
|
||||
unsigned int cursor_count;
|
||||
struct wl_cursor **cursors;
|
||||
struct wl_shm *shm;
|
||||
struct shm_pool *pool;
|
||||
char *name;
|
||||
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 */
|
||||
};
|
||||
|
||||
/** 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 *_img)
|
||||
{
|
||||
struct cursor_image *image = (struct cursor_image *) _img;
|
||||
struct wl_cursor_theme *theme = image->theme;
|
||||
|
||||
if (!image->buffer) {
|
||||
image->buffer =
|
||||
wl_shm_pool_create_buffer(theme->pool->pool,
|
||||
image->offset,
|
||||
_img->width, _img->height,
|
||||
_img->width * 4,
|
||||
WL_SHM_FORMAT_ARGB8888);
|
||||
};
|
||||
|
||||
return image->buffer;
|
||||
}
|
||||
|
||||
static void
|
||||
wl_cursor_image_destroy(struct wl_cursor_image *_img)
|
||||
{
|
||||
struct cursor_image *image = (struct cursor_image *) _img;
|
||||
|
||||
if (image->buffer)
|
||||
wl_buffer_destroy(image->buffer);
|
||||
|
||||
free(image);
|
||||
}
|
||||
|
||||
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->name);
|
||||
free(cursor);
|
||||
}
|
||||
|
||||
static struct wl_cursor *
|
||||
load_cursor(struct wl_cursor_theme *theme, const char *name)
|
||||
{
|
||||
XcursorImages *images;
|
||||
struct wl_cursor *cursor;
|
||||
struct cursor_image *image;
|
||||
int i, size;
|
||||
|
||||
images = XcursorLibraryLoadImages(name, theme->name, theme->size);
|
||||
if (!images)
|
||||
return NULL;
|
||||
|
||||
cursor = malloc(sizeof *cursor);
|
||||
if (!cursor) {
|
||||
XcursorImagesDestroy(images);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cursor->image_count = images->nimage;
|
||||
cursor->images = malloc(images->nimage * sizeof cursor->images[0]);
|
||||
if (!cursor->images) {
|
||||
XcursorImagesDestroy(images);
|
||||
free(cursor);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cursor->name = strdup(name);
|
||||
|
||||
for (i = 0; i < images->nimage; i++) {
|
||||
image = malloc(sizeof *image);
|
||||
cursor->images[i] = (struct wl_cursor_image *) image;
|
||||
|
||||
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;
|
||||
|
||||
/* copy pixels to shm pool */
|
||||
size = image->image.width * image->image.height * 4;
|
||||
image->offset = shm_pool_allocate(theme->pool, size);
|
||||
memcpy(theme->pool->data + image->offset,
|
||||
images->images[i]->pixels, size);
|
||||
}
|
||||
|
||||
XcursorImagesDestroy(images);
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
WL_EXPORT struct wl_cursor_theme *
|
||||
wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm)
|
||||
{
|
||||
struct wl_cursor_theme *theme;
|
||||
unsigned int i;
|
||||
|
||||
theme = malloc(sizeof *theme);
|
||||
if (!theme)
|
||||
return NULL;
|
||||
|
||||
if (!name)
|
||||
name = "default";
|
||||
|
||||
theme->name = strdup(name);
|
||||
theme->size = size;
|
||||
theme->cursor_count = ARRAY_LENGTH(cursor_names);
|
||||
|
||||
theme->cursors =
|
||||
malloc(theme->cursor_count * sizeof theme->cursors[0]);
|
||||
if (!theme->cursors) {
|
||||
free(theme);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
theme->pool =
|
||||
shm_pool_create(shm, theme->cursor_count * size * size * 4);
|
||||
|
||||
for (i = 0; i < theme->cursor_count; i++)
|
||||
theme->cursors[i] = load_cursor(theme, cursor_names[i]);
|
||||
|
||||
return theme;
|
||||
}
|
||||
|
||||
/** 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 type from a cursor theme
|
||||
*
|
||||
* \param theme The cursor theme
|
||||
* \patam type The desired cursor type
|
||||
* \return The theme's cursor of the given type or %NULL if there is no
|
||||
* such cursor
|
||||
*/
|
||||
WL_EXPORT struct wl_cursor *
|
||||
wl_cursor_theme_get_cursor(struct wl_cursor_theme *theme,
|
||||
enum wl_cursor_type type)
|
||||
{
|
||||
if (type < theme->cursor_count)
|
||||
return theme->cursors[type];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** 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_by_name(struct wl_cursor_theme *theme,
|
||||
const char *name)
|
||||
{
|
||||
unsigned int i;
|
||||
struct wl_cursor *cursor;
|
||||
|
||||
for (i = 0; i < theme->cursor_count; i++) {
|
||||
if (strcmp(name, theme->cursors[i]->name) == 0)
|
||||
return theme->cursors[i];
|
||||
}
|
||||
|
||||
cursor = load_cursor(theme, name);
|
||||
if (!cursor)
|
||||
return NULL;
|
||||
|
||||
theme->cursor_count++;
|
||||
theme->cursors =
|
||||
realloc(theme->cursors,
|
||||
theme->cursor_count * sizeof theme->cursors[0]);
|
||||
|
||||
theme->cursors[theme->cursor_count - 1] = cursor;
|
||||
|
||||
return cursor;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue