window: use libXcursor for loading pointer images
222
clients/window.c
|
@ -57,6 +57,7 @@
|
|||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <wayland-client.h>
|
||||
|
@ -64,6 +65,8 @@
|
|||
|
||||
#include "window.h"
|
||||
|
||||
struct cursor;
|
||||
|
||||
struct display {
|
||||
struct wl_display *display;
|
||||
struct wl_compositor *compositor;
|
||||
|
@ -91,7 +94,7 @@ struct display {
|
|||
cairo_surface_t *active_frame, *inactive_frame, *shadow;
|
||||
int frame_radius;
|
||||
struct xkb_desc *xkb;
|
||||
cairo_surface_t **pointer_surfaces;
|
||||
struct cursor *cursors;
|
||||
|
||||
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
|
||||
PFNEGLCREATEIMAGEKHRPROC create_image;
|
||||
|
@ -172,7 +175,7 @@ struct input {
|
|||
struct wl_input_device *input_device;
|
||||
struct window *pointer_focus;
|
||||
struct window *keyboard_focus;
|
||||
int current_pointer_image;
|
||||
int current_cursor;
|
||||
uint32_t modifiers;
|
||||
uint32_t pointer_enter_serial;
|
||||
int32_t sx, sy;
|
||||
|
@ -216,6 +219,18 @@ struct menu {
|
|||
menu_func_t func;
|
||||
};
|
||||
|
||||
struct cursor_image {
|
||||
cairo_surface_t *surface;
|
||||
int width, height;
|
||||
int hotspot_x, hotspot_y;
|
||||
int delay;
|
||||
};
|
||||
|
||||
struct cursor {
|
||||
int n_images;
|
||||
struct cursor_image *images;
|
||||
};
|
||||
|
||||
enum {
|
||||
POINTER_DEFAULT = 100,
|
||||
POINTER_UNSET
|
||||
|
@ -345,6 +360,14 @@ shm_surface_data_destroy(void *p)
|
|||
munmap(data->map, data->length);
|
||||
}
|
||||
|
||||
static void
|
||||
shm_surface_write(cairo_surface_t *surface, unsigned char *data, int count)
|
||||
{
|
||||
void *dest = cairo_image_surface_get_data(surface);
|
||||
|
||||
memcpy(dest, data, count);
|
||||
}
|
||||
|
||||
static struct wl_shm_pool *
|
||||
make_shm_pool(struct display *display, int size, void **data)
|
||||
{
|
||||
|
@ -432,35 +455,6 @@ display_create_shm_surface(struct display *display,
|
|||
return surface;
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
display_create_shm_surface_from_file(struct display *display,
|
||||
const char *filename,
|
||||
struct rectangle *rect)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
pixman_image_t *image;
|
||||
void *dest;
|
||||
int size;
|
||||
|
||||
image = load_image(filename);
|
||||
if (image == NULL)
|
||||
return NULL;
|
||||
|
||||
surface = display_create_shm_surface(display, rect, 0, NULL);
|
||||
if (surface == NULL) {
|
||||
pixman_image_unref(image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = pixman_image_get_stride(image) * pixman_image_get_height(image);
|
||||
dest = cairo_image_surface_get_data(surface);
|
||||
memcpy(dest, pixman_image_get_data(image), size);
|
||||
|
||||
pixman_image_unref(image);
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
static int
|
||||
check_size(struct rectangle *rect)
|
||||
{
|
||||
|
@ -490,70 +484,102 @@ display_create_surface(struct display *display,
|
|||
return display_create_shm_surface(display, rectangle, flags, NULL);
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
display_create_surface_from_file(struct display *display,
|
||||
const char *filename,
|
||||
struct rectangle *rectangle)
|
||||
{
|
||||
if (check_size(rectangle) < 0)
|
||||
return NULL;
|
||||
|
||||
return display_create_shm_surface_from_file(display, filename, rectangle);
|
||||
}
|
||||
static const struct {
|
||||
const char *filename;
|
||||
int hotspot_x, hotspot_y;
|
||||
} pointer_images[] = {
|
||||
{ DATADIR "/weston/bottom_left_corner.png", 6, 30 },
|
||||
{ DATADIR "/weston/bottom_right_corner.png", 28, 28 },
|
||||
{ DATADIR "/weston/bottom_side.png", 16, 20 },
|
||||
{ DATADIR "/weston/grabbing.png", 20, 17 },
|
||||
{ DATADIR "/weston/left_ptr.png", 10, 5 },
|
||||
{ DATADIR "/weston/left_side.png", 10, 20 },
|
||||
{ DATADIR "/weston/right_side.png", 30, 19 },
|
||||
{ DATADIR "/weston/top_left_corner.png", 8, 8 },
|
||||
{ DATADIR "/weston/top_right_corner.png", 26, 8 },
|
||||
{ DATADIR "/weston/top_side.png", 18, 8 },
|
||||
{ DATADIR "/weston/xterm.png", 15, 15 },
|
||||
{ DATADIR "/weston/hand1.png", 18, 11 }
|
||||
static const char *cursors[] = {
|
||||
"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",
|
||||
};
|
||||
|
||||
static void
|
||||
create_pointer_surfaces(struct display *display)
|
||||
create_cursor_from_images(struct display *display, struct cursor *cursor,
|
||||
XcursorImages *images)
|
||||
{
|
||||
int i, count;
|
||||
const int width = 32, height = 32;
|
||||
int i;
|
||||
struct rectangle rect;
|
||||
XcursorImage *image;
|
||||
|
||||
count = ARRAY_LENGTH(pointer_images);
|
||||
display->pointer_surfaces =
|
||||
malloc(count * sizeof *display->pointer_surfaces);
|
||||
rect.width = width;
|
||||
rect.height = height;
|
||||
for (i = 0; i < count; i++) {
|
||||
display->pointer_surfaces[i] =
|
||||
display_create_surface_from_file(display,
|
||||
pointer_images[i].filename,
|
||||
&rect);
|
||||
if (!display->pointer_surfaces[i]) {
|
||||
fprintf(stderr, "Error loading pointer image: %s\n",
|
||||
pointer_images[i].filename);
|
||||
}
|
||||
cursor->images = malloc(images->nimage * sizeof *cursor->images);
|
||||
cursor->n_images = images->nimage;
|
||||
|
||||
for (i = 0; i < images->nimage; i++) {
|
||||
image = images->images[i];
|
||||
|
||||
rect.width = image->width;
|
||||
rect.height = image->height;
|
||||
|
||||
cursor->images[i].surface =
|
||||
display_create_shm_surface(display, &rect, 0, NULL);
|
||||
|
||||
shm_surface_write(cursor->images[i].surface,
|
||||
(unsigned char *) image->pixels,
|
||||
image->width * image->height * sizeof image->pixels[0]);
|
||||
|
||||
cursor->images[i].width = image->width;
|
||||
cursor->images[i].height = image->height;
|
||||
cursor->images[i].hotspot_x = image->xhot;
|
||||
cursor->images[i].hotspot_y = image->yhot;
|
||||
cursor->images[i].delay = image->delay;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_pointer_surfaces(struct display *display)
|
||||
create_cursors(struct display *display)
|
||||
{
|
||||
int i, count;
|
||||
struct cursor *cursor;
|
||||
XcursorImages *images;
|
||||
|
||||
count = ARRAY_LENGTH(cursors);
|
||||
display->cursors = malloc(count * sizeof *display->cursors);
|
||||
for (i = 0; i < count; i++) {
|
||||
images = XcursorLibraryLoadImages(cursors[i], NULL, 32);
|
||||
|
||||
if (!images) {
|
||||
fprintf(stderr, "Error loading cursor: %s\n",
|
||||
cursors[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
cursor = &display->cursors[i];
|
||||
create_cursor_from_images(display, cursor, images);
|
||||
|
||||
XcursorImagesDestroy(images);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_cursor_images(struct cursor *cursor)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cursor->n_images; i++)
|
||||
if (cursor->images[i].surface)
|
||||
cairo_surface_destroy(cursor->images[i].surface);
|
||||
|
||||
free(cursor->images);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_cursors(struct display *display)
|
||||
{
|
||||
int i, count;
|
||||
|
||||
count = ARRAY_LENGTH(pointer_images);
|
||||
count = ARRAY_LENGTH(cursors);
|
||||
for (i = 0; i < count; ++i) {
|
||||
if (display->pointer_surfaces[i])
|
||||
cairo_surface_destroy(display->pointer_surfaces[i]);
|
||||
destroy_cursor_images(&display->cursors[i]);
|
||||
}
|
||||
free(display->pointer_surfaces);
|
||||
free(display->cursors);
|
||||
}
|
||||
|
||||
cairo_surface_t *
|
||||
|
@ -561,18 +587,17 @@ display_get_pointer_surface(struct display *display, int pointer,
|
|||
int *width, int *height,
|
||||
int *hotspot_x, int *hotspot_y)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
struct cursor *cursor = &display->cursors[pointer];
|
||||
cairo_surface_t *surface = cursor->images[0].surface;
|
||||
|
||||
/* FIXME returning information for the first image. Something better
|
||||
* is needed for animated cursors */
|
||||
|
||||
surface = display->pointer_surfaces[pointer];
|
||||
#if HAVE_CAIRO_EGL
|
||||
*width = cairo_gl_surface_get_width(surface);
|
||||
*height = cairo_gl_surface_get_height(surface);
|
||||
#else
|
||||
*width = cairo_image_surface_get_width(surface);
|
||||
*height = cairo_image_surface_get_height(surface);
|
||||
#endif
|
||||
*hotspot_x = pointer_images[pointer].hotspot_x;
|
||||
*hotspot_y = pointer_images[pointer].hotspot_y;
|
||||
|
||||
*hotspot_x = cursor->images[0].hotspot_x;
|
||||
*hotspot_y = cursor->images[0].hotspot_y;
|
||||
|
||||
return cairo_surface_reference(surface);
|
||||
}
|
||||
|
@ -1442,7 +1467,7 @@ input_remove_pointer_focus(struct input *input)
|
|||
input_set_focus_widget(input, NULL, 0, 0);
|
||||
|
||||
input->pointer_focus = NULL;
|
||||
input->current_pointer_image = POINTER_UNSET;
|
||||
input->current_cursor = POINTER_UNSET;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1773,21 +1798,20 @@ input_set_pointer_image(struct input *input, uint32_t time, int pointer)
|
|||
{
|
||||
struct display *display = input->display;
|
||||
struct wl_buffer *buffer;
|
||||
cairo_surface_t *surface;
|
||||
struct cursor_image *image;
|
||||
|
||||
if (pointer == input->current_pointer_image)
|
||||
if (pointer == input->current_cursor)
|
||||
return;
|
||||
|
||||
input->current_pointer_image = pointer;
|
||||
surface = display->pointer_surfaces[pointer];
|
||||
image = &display->cursors[pointer].images[0];
|
||||
|
||||
if (!surface)
|
||||
if (!image->surface)
|
||||
return;
|
||||
|
||||
buffer = display_get_buffer_for_surface(display, surface);
|
||||
input->current_cursor = pointer;
|
||||
buffer = display_get_buffer_for_surface(display, image->surface);
|
||||
wl_input_device_attach(input->input_device, time, buffer,
|
||||
pointer_images[pointer].hotspot_x,
|
||||
pointer_images[pointer].hotspot_y);
|
||||
image->hotspot_x, image->hotspot_y);
|
||||
}
|
||||
|
||||
struct wl_data_device *
|
||||
|
@ -2854,7 +2878,7 @@ display_create(int argc, char *argv[])
|
|||
d->create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
|
||||
d->destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
|
||||
|
||||
create_pointer_surfaces(d);
|
||||
create_cursors(d);
|
||||
|
||||
display_render_frame(d);
|
||||
|
||||
|
@ -2902,7 +2926,7 @@ display_destroy(struct display *display)
|
|||
cairo_surface_destroy(display->active_frame);
|
||||
cairo_surface_destroy(display->inactive_frame);
|
||||
cairo_surface_destroy(display->shadow);
|
||||
destroy_pointer_surfaces(display);
|
||||
destroy_cursors(display);
|
||||
|
||||
#ifdef HAVE_CAIRO_EGL
|
||||
fini_egl(display);
|
||||
|
|
|
@ -137,7 +137,7 @@ AM_CONDITIONAL(BUILD_CLIENTS, test x$enable_clients = xyes)
|
|||
if test x$enable_clients = xyes; then
|
||||
AC_DEFINE([BUILD_CLIENTS], [1], [Build the Wayland clients])
|
||||
|
||||
PKG_CHECK_MODULES(CLIENT, [wayland-client wayland-egl egl >= 7.10 cairo >= 1.10.0 xkbcommon])
|
||||
PKG_CHECK_MODULES(CLIENT, [wayland-client wayland-egl egl >= 7.10 cairo >= 1.10.0 xkbcommon xcursor])
|
||||
|
||||
CLIENT_CFLAGS="$CLIENT_CFLAGS $IMAGE_CFLAGS"
|
||||
CLIENT_LIBS="$CLIENT_LIBS $IMAGE_LIBS"
|
||||
|
|
|
@ -1,24 +1,6 @@
|
|||
westondatadir = $(datadir)/weston
|
||||
|
||||
dist_westondata_DATA = \
|
||||
bottom_left_corner.png \
|
||||
bottom_right_corner.png \
|
||||
bottom_side.png \
|
||||
dnd-copy.png \
|
||||
dnd-link.png \
|
||||
dnd-move.png \
|
||||
grabbing.png \
|
||||
hand1.png \
|
||||
hand2.png \
|
||||
left_ptr.png \
|
||||
left_side.png \
|
||||
right_side.png \
|
||||
sb_h_double_arrow.png \
|
||||
sb_v_double_arrow.png \
|
||||
top_left_corner.png \
|
||||
top_right_corner.png \
|
||||
top_side.png \
|
||||
xterm.png \
|
||||
wayland.svg \
|
||||
$(wayland_icon_png) \
|
||||
pattern.png \
|
||||
|
|
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 994 B |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1004 B |
BIN
data/hand1.png
Before Width: | Height: | Size: 1.1 KiB |
BIN
data/hand2.png
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
BIN
data/xterm.png
Before Width: | Height: | Size: 615 B |