[clutter] wayland: Load a buffer from well known location for the cursor



commit e1434cebdb7b77ef39296eb80cb4b928a5267c2c
Author: Rob Bradford <rob linux intel com>
Date:   Tue Jan 10 16:40:59 2012 +0000

    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(+), 0 deletions(-)
---
diff --git a/clutter/wayland/clutter-backend-wayland.c b/clutter/wayland/clutter-backend-wayland.c
index 8aa51b2..365c073 100644
--- a/clutter/wayland/clutter-backend-wayland.c
+++ b/clutter/wayland/clutter-backend-wayland.c
@@ -32,6 +32,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <sys/mman.h>
 
 #include <errno.h>
 
@@ -48,12 +49,15 @@
 
 #include <wayland-client.h>
 
+#include <gdk-pixbuf/gdk-pixbuf.h>
 #include <cogl/cogl.h>
 
 #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 53dd2e0..fe8b2f4 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 */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]