window: use libXcursor for loading pointer images

dev
Ander Conselvan de Oliveira 13 years ago committed by Kristian Høgsberg
parent d51624f915
commit 1493d2ae1c
  1. 214
      clients/window.c
  2. 2
      configure.ac
  3. 18
      data/Makefile.am
  4. BIN
      data/bottom_left_corner.png
  5. BIN
      data/bottom_right_corner.png
  6. BIN
      data/bottom_side.png
  7. BIN
      data/dnd-copy.png
  8. BIN
      data/dnd-link.png
  9. BIN
      data/dnd-move.png
  10. BIN
      data/grabbing.png
  11. BIN
      data/hand1.png
  12. BIN
      data/hand2.png
  13. BIN
      data/left_ptr.png
  14. BIN
      data/left_side.png
  15. BIN
      data/right_side.png
  16. BIN
      data/sb_h_double_arrow.png
  17. BIN
      data/sb_v_double_arrow.png
  18. BIN
      data/top_left_corner.png
  19. BIN
      data/top_right_corner.png
  20. BIN
      data/top_side.png
  21. BIN
      data/xterm.png

@ -57,6 +57,7 @@
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#include <X11/X.h> #include <X11/X.h>
#include <X11/Xcursor/Xcursor.h>
#include <linux/input.h> #include <linux/input.h>
#include <wayland-client.h> #include <wayland-client.h>
@ -64,6 +65,8 @@
#include "window.h" #include "window.h"
struct cursor;
struct display { struct display {
struct wl_display *display; struct wl_display *display;
struct wl_compositor *compositor; struct wl_compositor *compositor;
@ -91,7 +94,7 @@ struct display {
cairo_surface_t *active_frame, *inactive_frame, *shadow; cairo_surface_t *active_frame, *inactive_frame, *shadow;
int frame_radius; int frame_radius;
struct xkb_desc *xkb; struct xkb_desc *xkb;
cairo_surface_t **pointer_surfaces; struct cursor *cursors;
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d; PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
PFNEGLCREATEIMAGEKHRPROC create_image; PFNEGLCREATEIMAGEKHRPROC create_image;
@ -172,7 +175,7 @@ struct input {
struct wl_input_device *input_device; struct wl_input_device *input_device;
struct window *pointer_focus; struct window *pointer_focus;
struct window *keyboard_focus; struct window *keyboard_focus;
int current_pointer_image; int current_cursor;
uint32_t modifiers; uint32_t modifiers;
uint32_t pointer_enter_serial; uint32_t pointer_enter_serial;
int32_t sx, sy; int32_t sx, sy;
@ -216,6 +219,18 @@ struct menu {
menu_func_t func; 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 { enum {
POINTER_DEFAULT = 100, POINTER_DEFAULT = 100,
POINTER_UNSET POINTER_UNSET
@ -345,6 +360,14 @@ shm_surface_data_destroy(void *p)
munmap(data->map, data->length); 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 * static struct wl_shm_pool *
make_shm_pool(struct display *display, int size, void **data) make_shm_pool(struct display *display, int size, void **data)
{ {
@ -432,35 +455,6 @@ display_create_shm_surface(struct display *display,
return surface; 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 static int
check_size(struct rectangle *rect) check_size(struct rectangle *rect)
{ {
@ -490,70 +484,102 @@ display_create_surface(struct display *display,
return display_create_shm_surface(display, rectangle, flags, NULL); return display_create_shm_surface(display, rectangle, flags, NULL);
} }
static cairo_surface_t * static const char *cursors[] = {
display_create_surface_from_file(struct display *display, "bottom_left_corner",
const char *filename, "bottom_right_corner",
struct rectangle *rectangle) "bottom_side",
"grabbing",
"left_ptr",
"left_side",
"right_side",
"top_left_corner",
"top_right_corner",
"top_side",
"xterm",
"hand1",
};
static void
create_cursor_from_images(struct display *display, struct cursor *cursor,
XcursorImages *images)
{ {
if (check_size(rectangle) < 0) int i;
return NULL; struct rectangle rect;
XcursorImage *image;
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;
}
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 void static void
create_pointer_surfaces(struct display *display) create_cursors(struct display *display)
{ {
int i, count; int i, count;
const int width = 32, height = 32; struct cursor *cursor;
struct rectangle rect; XcursorImages *images;
count = ARRAY_LENGTH(pointer_images); count = ARRAY_LENGTH(cursors);
display->pointer_surfaces = display->cursors = malloc(count * sizeof *display->cursors);
malloc(count * sizeof *display->pointer_surfaces);
rect.width = width;
rect.height = height;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
display->pointer_surfaces[i] = images = XcursorLibraryLoadImages(cursors[i], NULL, 32);
display_create_surface_from_file(display,
pointer_images[i].filename, if (!images) {
&rect); fprintf(stderr, "Error loading cursor: %s\n",
if (!display->pointer_surfaces[i]) { cursors[i]);
fprintf(stderr, "Error loading pointer image: %s\n", continue;
pointer_images[i].filename);
} }
cursor = &display->cursors[i];
create_cursor_from_images(display, cursor, images);
XcursorImagesDestroy(images);
} }
} }
static void static void
destroy_pointer_surfaces(struct display *display) 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; int i, count;
count = ARRAY_LENGTH(pointer_images); count = ARRAY_LENGTH(cursors);
for (i = 0; i < count; ++i) { for (i = 0; i < count; ++i) {
if (display->pointer_surfaces[i]) destroy_cursor_images(&display->cursors[i]);
cairo_surface_destroy(display->pointer_surfaces[i]);
} }
free(display->pointer_surfaces); free(display->cursors);
} }
cairo_surface_t * cairo_surface_t *
@ -561,18 +587,17 @@ display_get_pointer_surface(struct display *display, int pointer,
int *width, int *height, int *width, int *height,
int *hotspot_x, int *hotspot_y) 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); *width = cairo_image_surface_get_width(surface);
*height = cairo_image_surface_get_height(surface); *height = cairo_image_surface_get_height(surface);
#endif
*hotspot_x = pointer_images[pointer].hotspot_x; *hotspot_x = cursor->images[0].hotspot_x;
*hotspot_y = pointer_images[pointer].hotspot_y; *hotspot_y = cursor->images[0].hotspot_y;
return cairo_surface_reference(surface); 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_set_focus_widget(input, NULL, 0, 0);
input->pointer_focus = NULL; input->pointer_focus = NULL;
input->current_pointer_image = POINTER_UNSET; input->current_cursor = POINTER_UNSET;
} }
static void static void
@ -1773,21 +1798,20 @@ input_set_pointer_image(struct input *input, uint32_t time, int pointer)
{ {
struct display *display = input->display; struct display *display = input->display;
struct wl_buffer *buffer; struct wl_buffer *buffer;
cairo_surface_t *surface; struct cursor_image *image;
if (pointer == input->current_pointer_image) if (pointer == input->current_cursor)
return; return;
input->current_pointer_image = pointer; image = &display->cursors[pointer].images[0];
surface = display->pointer_surfaces[pointer];
if (!surface) if (!image->surface)
return; 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, wl_input_device_attach(input->input_device, time, buffer,
pointer_images[pointer].hotspot_x, image->hotspot_x, image->hotspot_y);
pointer_images[pointer].hotspot_y);
} }
struct wl_data_device * struct wl_data_device *
@ -2854,7 +2878,7 @@ display_create(int argc, char *argv[])
d->create_image = (void *) eglGetProcAddress("eglCreateImageKHR"); d->create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
d->destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR"); d->destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
create_pointer_surfaces(d); create_cursors(d);
display_render_frame(d); display_render_frame(d);
@ -2902,7 +2926,7 @@ display_destroy(struct display *display)
cairo_surface_destroy(display->active_frame); cairo_surface_destroy(display->active_frame);
cairo_surface_destroy(display->inactive_frame); cairo_surface_destroy(display->inactive_frame);
cairo_surface_destroy(display->shadow); cairo_surface_destroy(display->shadow);
destroy_pointer_surfaces(display); destroy_cursors(display);
#ifdef HAVE_CAIRO_EGL #ifdef HAVE_CAIRO_EGL
fini_egl(display); fini_egl(display);

@ -137,7 +137,7 @@ AM_CONDITIONAL(BUILD_CLIENTS, test x$enable_clients = xyes)
if test x$enable_clients = xyes; then if test x$enable_clients = xyes; then
AC_DEFINE([BUILD_CLIENTS], [1], [Build the Wayland clients]) 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_CFLAGS="$CLIENT_CFLAGS $IMAGE_CFLAGS"
CLIENT_LIBS="$CLIENT_LIBS $IMAGE_LIBS" CLIENT_LIBS="$CLIENT_LIBS $IMAGE_LIBS"

@ -1,24 +1,6 @@
westondatadir = $(datadir)/weston westondatadir = $(datadir)/weston
dist_westondata_DATA = \ 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.svg \
$(wayland_icon_png) \ $(wayland_icon_png) \
pattern.png \ pattern.png \

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 994 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1004 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 615 B

Loading…
Cancel
Save