From e1434cebdb7b77ef39296eb80cb4b928a5267c2c Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Tue, 10 Jan 2012 16:40:59 +0000 Subject: [PATCH] wayland: Load a buffer from well known location for the cursor Semantic changes to Wayland means that we cannot rely on the compositor setting a pointer buffer for us if set it to nil. The first part of fixing this is to create an shm buffer containing the bytes for our cursor. The best way to do this currently is to load the cursor from the well known location where weston instals its cursor images. The code to implemente this was derivedlifted from the Wayland backend in GTK+. --- clutter/wayland/clutter-backend-wayland.c | 179 ++++++++++++++++++++++ clutter/wayland/clutter-backend-wayland.h | 3 + 2 files changed, 182 insertions(+) diff --git a/clutter/wayland/clutter-backend-wayland.c b/clutter/wayland/clutter-backend-wayland.c index 8aa51b235..365c073e1 100644 --- a/clutter/wayland/clutter-backend-wayland.c +++ b/clutter/wayland/clutter-backend-wayland.c @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -48,12 +49,15 @@ #include +#include #include #define clutter_backend_wayland_get_type _clutter_backend_wayland_get_type G_DEFINE_TYPE (ClutterBackendWayland, clutter_backend_wayland, CLUTTER_TYPE_BACKEND); +static void clutter_backend_wayland_load_cursor (ClutterBackendWayland *backend_wayland); + static void clutter_backend_wayland_dispose (GObject *gobject) { @@ -65,6 +69,12 @@ clutter_backend_wayland_dispose (GObject *gobject) backend_wayland->device_manager = NULL; } + if (backend_wayland->cursor_buffer) + { + wl_buffer_destroy (backend_wayland->cursor_buffer); + backend_wayland->cursor_buffer = NULL; + } + G_OBJECT_CLASS (clutter_backend_wayland_parent_class)->dispose (gobject); } @@ -142,6 +152,9 @@ clutter_backend_wayland_post_parse (ClutterBackend *backend, backend_wayland->wayland_shell)) wl_display_roundtrip (backend_wayland->wayland_display); + /* We need the shm object before we can create the cursor */ + clutter_backend_wayland_load_cursor (backend_wayland); + return TRUE; } @@ -212,6 +225,172 @@ clutter_backend_wayland_class_init (ClutterBackendWaylandClass *klass) backend_class->get_display = clutter_backend_wayland_get_display; } +/* + * clutter_backend_wayland_load_cursor and the two functions below were copied + * from GTK+ and adapted for clutter + */ +static void +set_pixbuf (GdkPixbuf *pixbuf, + unsigned char *map, + int width, + int height) +{ + int stride, i, n_channels; + unsigned char *pixels, *end, *argb_pixels, *s, *d; + + stride = gdk_pixbuf_get_rowstride (pixbuf); + pixels = gdk_pixbuf_get_pixels (pixbuf); + n_channels = gdk_pixbuf_get_n_channels (pixbuf); + argb_pixels = map; + +#define MULT(_d,c,a,t) \ + do { t = c * a + 0x7f; _d = ((t >> 8) + t) >> 8; } while (0) + + if (n_channels == 4) + { + for (i = 0; i < height; i++) + { + s = pixels + i * stride; + end = s + width * 4; + d = argb_pixels + i * width * 4; + while (s < end) + { + unsigned int t; + + MULT(d[0], s[2], s[3], t); + MULT(d[1], s[1], s[3], t); + MULT(d[2], s[0], s[3], t); + d[3] = s[3]; + s += 4; + d += 4; + } + } + } + else if (n_channels == 3) + { + for (i = 0; i < height; i++) + { + s = pixels + i * stride; + end = s + width * 3; + d = argb_pixels + i * width * 4; + while (s < end) + { + d[0] = s[2]; + d[1] = s[1]; + d[2] = s[0]; + d[3] = 0xff; + s += 3; + d += 4; + } + } + } +} + +static struct wl_buffer * +create_cursor (ClutterBackendWayland *backend_wayland, + GdkPixbuf *pixbuf) +{ + int stride, fd; + char *filename; + GError *error = NULL; + struct wl_buffer *buffer; + gint width, height; + gsize size; + unsigned char *map; + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + stride = width * 4; + size = stride * height; + + fd = g_file_open_tmp ("wayland-shm-XXXXXX", &filename, &error); + if (fd < 0) + { + g_critical (G_STRLOC ": Opening temporary file failed: %s", error->message); + g_error_free (error); + return NULL; + } + + unlink (filename); + g_free (filename); + + if (ftruncate (fd, size) < 0) + { + g_critical (G_STRLOC ": Setting the size of temporary file failed: %s", g_strerror (errno)); + close (fd); + return NULL; + } + + map = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + + if (map == MAP_FAILED) + { + g_critical (G_STRLOC ": Memory mapping file failed: %s", g_strerror (errno)); + close (fd); + return NULL; + } + + set_pixbuf (pixbuf, map, width, height); + + buffer = wl_shm_create_buffer (backend_wayland->wayland_shm, + fd, + width, + height, + stride, + WL_SHM_FORMAT_ARGB32); + + close(fd); + munmap (map, size); + + return buffer; +} + +static void +clutter_backend_wayland_load_cursor (ClutterBackendWayland *backend_wayland) +{ + const gchar * const *directories; + gint j; + GdkPixbuf *pixbuf = NULL; + GError *error = NULL; + + directories = g_get_system_data_dirs(); + + for (j = 0; directories[j] != NULL; j++) + { + gchar *filename; + filename = g_build_filename (directories[j], + "weston", + "left_ptr.png", + NULL); + if (g_file_test (filename, G_FILE_TEST_EXISTS)) + { + pixbuf = gdk_pixbuf_new_from_file (filename, &error); + + if (error != NULL) + { + g_warning ("Failed to load cursor: %s: %s", + filename, error->message); + g_error_free (error); + return; + } + break; + } + } + + if (!pixbuf) + return; + + backend_wayland->cursor_buffer = create_cursor (backend_wayland, pixbuf); + + if (backend_wayland->cursor_buffer) + { + backend_wayland->cursor_x = 15; + backend_wayland->cursor_y = 15; + } + + g_object_unref (pixbuf); +} + static void clutter_backend_wayland_init (ClutterBackendWayland *backend_wayland) { diff --git a/clutter/wayland/clutter-backend-wayland.h b/clutter/wayland/clutter-backend-wayland.h index 53dd2e0c9..fe8b2f442 100644 --- a/clutter/wayland/clutter-backend-wayland.h +++ b/clutter/wayland/clutter-backend-wayland.h @@ -56,6 +56,9 @@ struct _ClutterBackendWayland struct wl_compositor *wayland_compositor; struct wl_shell *wayland_shell; struct wl_shm *wayland_shm; + struct wl_buffer *cursor_buffer; + gint cursor_x, cursor_y; + GSource *wayland_source; /* event timer */