[PATCH] window: use libXcursor for loading pointer images

Kristian Høgsberg krh at bitplanet.net
Thu May 3 08:43:41 PDT 2012


On Thu, May 3, 2012 at 5:29 AM, Ander Conselvan de Oliveira
<ander.conselvan.de.oliveira at intel.com> wrote:
> ---
> This is the code I have for using libXcursor. It would be good to make
> it use a single wl_shm_pool, but as long as no animated cursors are
> loaded, the number of pools created is the same as before.

Thanks Ander, committed.  Using a big pool for all cursors would be
nice.  We now also have a hard dependency on libX11 in weston through
libXcursor - something we need to figure out how to deal with.

Kristian

>  clients/window.c |  180 ++++++++++++++++++++++++++++++++++++-----------------
>  configure.ac     |    2 +-
>  2 files changed, 123 insertions(+), 59 deletions(-)
>
> diff --git a/clients/window.c b/clients/window.c
> index 54f57a3..0cc2e28 100644
> --- a/clients/window.c
> +++ b/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)
>  {
> @@ -500,60 +523,103 @@ display_create_surface_from_file(struct display *display,
>
>        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 }
> +
> +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;
> +
> +       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;
> +       }
>
> -       count = ARRAY_LENGTH(pointer_images);
> -       display->pointer_surfaces =
> -               malloc(count * sizeof *display->pointer_surfaces);
> -       rect.width = width;
> -       rect.height = height;
> +}
> +
> +static void
> +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++) {
> -               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 +627,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 +1507,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 +1838,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 +2918,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 +2966,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);
> diff --git a/configure.ac b/configure.ac
> index 6da7922..26c4283 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -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.7.4.1
>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel


More information about the wayland-devel mailing list