window: use libXcursor for loading pointer images
authorAnder Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Thu, 3 May 2012 09:29:46 +0000 (12:29 +0300)
committerKristian Høgsberg <krh@bitplanet.net>
Thu, 3 May 2012 14:14:04 +0000 (10:14 -0400)
21 files changed:
clients/window.c
configure.ac
data/Makefile.am
data/bottom_left_corner.png [deleted file]
data/bottom_right_corner.png [deleted file]
data/bottom_side.png [deleted file]
data/dnd-copy.png [deleted file]
data/dnd-link.png [deleted file]
data/dnd-move.png [deleted file]
data/grabbing.png [deleted file]
data/hand1.png [deleted file]
data/hand2.png [deleted file]
data/left_ptr.png [deleted file]
data/left_side.png [deleted file]
data/right_side.png [deleted file]
data/sb_h_double_arrow.png [deleted file]
data/sb_v_double_arrow.png [deleted file]
data/top_left_corner.png [deleted file]
data/top_right_corner.png [deleted file]
data/top_side.png [deleted file]
data/xterm.png [deleted file]

index 54f57a3..2dcf421 100644 (file)
@@ -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)
+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_cursor_from_images(struct display *display, struct cursor *cursor,
+                         XcursorImages *images)
 {
-       if (check_size(rectangle) < 0)
-               return NULL;
+       int i;
+       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
-create_pointer_surfaces(struct display *display)
+create_cursors(struct display *display)
 {
        int i, count;
-       const int width = 32, height = 32;
-       struct rectangle rect;
+       struct cursor *cursor;
+       XcursorImages *images;
 
-       count = ARRAY_LENGTH(pointer_images);
-       display->pointer_surfaces =
-               malloc(count * sizeof *display->pointer_surfaces);
-       rect.width = width;
-       rect.height = height;
+       count = ARRAY_LENGTH(cursors);
+       display->cursors = malloc(count * sizeof *display->cursors);
        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);
+               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_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;
 
-       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);
index 6da7922..26c4283 100644 (file)
@@ -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"
index 39b62ff..ec2723a 100644 (file)
@@ -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                             \
diff --git a/data/bottom_left_corner.png b/data/bottom_left_corner.png
deleted file mode 100644 (file)
index 2d4370f..0000000
Binary files a/data/bottom_left_corner.png and /dev/null differ
diff --git a/data/bottom_right_corner.png b/data/bottom_right_corner.png
deleted file mode 100644 (file)
index 768e777..0000000
Binary files a/data/bottom_right_corner.png and /dev/null differ
diff --git a/data/bottom_side.png b/data/bottom_side.png
deleted file mode 100644 (file)
index ac7c70e..0000000
Binary files a/data/bottom_side.png and /dev/null differ
diff --git a/data/dnd-copy.png b/data/dnd-copy.png
deleted file mode 100644 (file)
index fd044ae..0000000
Binary files a/data/dnd-copy.png and /dev/null differ
diff --git a/data/dnd-link.png b/data/dnd-link.png
deleted file mode 100644 (file)
index 5183bf9..0000000
Binary files a/data/dnd-link.png and /dev/null differ
diff --git a/data/dnd-move.png b/data/dnd-move.png
deleted file mode 100644 (file)
index c3ccd6e..0000000
Binary files a/data/dnd-move.png and /dev/null differ
diff --git a/data/grabbing.png b/data/grabbing.png
deleted file mode 100644 (file)
index 0469459..0000000
Binary files a/data/grabbing.png and /dev/null differ
diff --git a/data/hand1.png b/data/hand1.png
deleted file mode 100644 (file)
index c13aa36..0000000
Binary files a/data/hand1.png and /dev/null differ
diff --git a/data/hand2.png b/data/hand2.png
deleted file mode 100644 (file)
index 016b9a6..0000000
Binary files a/data/hand2.png and /dev/null differ
diff --git a/data/left_ptr.png b/data/left_ptr.png
deleted file mode 100644 (file)
index c42ac55..0000000
Binary files a/data/left_ptr.png and /dev/null differ
diff --git a/data/left_side.png b/data/left_side.png
deleted file mode 100644 (file)
index 2e2fab5..0000000
Binary files a/data/left_side.png and /dev/null differ
diff --git a/data/right_side.png b/data/right_side.png
deleted file mode 100644 (file)
index d49b114..0000000
Binary files a/data/right_side.png and /dev/null differ
diff --git a/data/sb_h_double_arrow.png b/data/sb_h_double_arrow.png
deleted file mode 100644 (file)
index 8e55c0a..0000000
Binary files a/data/sb_h_double_arrow.png and /dev/null differ
diff --git a/data/sb_v_double_arrow.png b/data/sb_v_double_arrow.png
deleted file mode 100644 (file)
index 822f622..0000000
Binary files a/data/sb_v_double_arrow.png and /dev/null differ
diff --git a/data/top_left_corner.png b/data/top_left_corner.png
deleted file mode 100644 (file)
index 25c4e84..0000000
Binary files a/data/top_left_corner.png and /dev/null differ
diff --git a/data/top_right_corner.png b/data/top_right_corner.png
deleted file mode 100644 (file)
index fb7727c..0000000
Binary files a/data/top_right_corner.png and /dev/null differ
diff --git a/data/top_side.png b/data/top_side.png
deleted file mode 100644 (file)
index bf351f1..0000000
Binary files a/data/top_side.png and /dev/null differ
diff --git a/data/xterm.png b/data/xterm.png
deleted file mode 100644 (file)
index dc054c9..0000000
Binary files a/data/xterm.png and /dev/null differ