[mutter/wayland] cursor-tracker: Split the code that loads MetaCursorReferences out



commit 21425b583371774a2a6a636c8448fd5fbeac2b86
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Mon Mar 31 15:21:19 2014 -0400

    cursor-tracker: Split the code that loads MetaCursorReferences out
    
    The plan here is to move the usage of these interfaces to the consumer,
    and then slam the code into backends.

 src/core/meta-cursor-tracker-private.h |   52 +++++
 src/core/meta-cursor-tracker.c         |  371 --------------------------------
 src/core/meta-cursor.c                 |  331 ++++++++++++++++++++++++++++
 src/core/meta-cursor.h                 |   12 +
 4 files changed, 395 insertions(+), 371 deletions(-)
---
diff --git a/src/core/meta-cursor-tracker-private.h b/src/core/meta-cursor-tracker-private.h
index 835036a..62b32d3 100644
--- a/src/core/meta-cursor-tracker-private.h
+++ b/src/core/meta-cursor-tracker-private.h
@@ -25,6 +25,58 @@
 #include <meta/meta-cursor-tracker.h>
 #include <wayland-server.h>
 
+#include "meta-cursor.h"
+
+struct _MetaCursorTracker {
+  GObject parent_instance;
+
+  MetaScreen *screen;
+
+  gboolean is_showing;
+  gboolean has_hw_cursor;
+
+  /* The cursor tracker stores the cursor for the current grab
+   * operation, the cursor for the window with pointer focus, and
+   * the cursor for the root window, which contains either the
+   * default arrow cursor or the 'busy' hourglass if we're launching
+   * an app.
+   *
+   * We choose the first one available -- if there's a grab cursor,
+   * we choose that cursor, if there's window cursor, we choose that,
+   * otherwise we choose the root cursor.
+   *
+   * The displayed_cursor contains the chosen cursor.
+   */
+  MetaCursorReference *displayed_cursor;
+
+  MetaCursorReference *grab_cursor;
+
+  /* Wayland clients can set a NULL buffer as their cursor 
+   * explicitly, which means that we shouldn't display anything.
+   * So, we can't simply store a NULL in window_cursor to
+   * determine an unset window cursor; we need an extra boolean.
+   */
+  gboolean has_window_cursor;
+  MetaCursorReference *window_cursor;
+
+  MetaCursorReference *root_cursor;
+
+  MetaCursorReference *default_cursors[META_CURSOR_LAST];
+
+  int current_x, current_y;
+  MetaRectangle current_rect;
+  MetaRectangle previous_rect;
+  gboolean previous_is_valid;
+
+  CoglPipeline *pipeline;
+  int drm_fd;
+  struct gbm_device *gbm;
+};
+
+struct _MetaCursorTrackerClass {
+  GObjectClass parent_class;
+};
+
 gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
                                            XEvent            *xevent);
 
diff --git a/src/core/meta-cursor-tracker.c b/src/core/meta-cursor-tracker.c
index cc698fb..d038109 100644
--- a/src/core/meta-cursor-tracker.c
+++ b/src/core/meta-cursor-tracker.c
@@ -41,10 +41,6 @@
 #include <gdk/gdk.h>
 #include <gdk/gdkx.h>
 
-#include <X11/cursorfont.h>
-#include <X11/extensions/Xfixes.h>
-#include <X11/Xcursor/Xcursor.h>
-
 #include "meta-cursor-private.h"
 #include "meta-cursor-tracker-private.h"
 #include "screen-private.h"
@@ -52,56 +48,6 @@
 
 #include "wayland/meta-wayland-private.h"
 
-struct _MetaCursorTracker {
-  GObject parent_instance;
-
-  MetaScreen *screen;
-
-  gboolean is_showing;
-  gboolean has_hw_cursor;
-
-  /* The cursor tracker stores the cursor for the current grab
-   * operation, the cursor for the window with pointer focus, and
-   * the cursor for the root window, which contains either the
-   * default arrow cursor or the 'busy' hourglass if we're launching
-   * an app.
-   *
-   * We choose the first one available -- if there's a grab cursor,
-   * we choose that cursor, if there's window cursor, we choose that,
-   * otherwise we choose the root cursor.
-   *
-   * The displayed_cursor contains the chosen cursor.
-   */
-  MetaCursorReference *displayed_cursor;
-
-  MetaCursorReference *grab_cursor;
-
-  /* Wayland clients can set a NULL buffer as their cursor 
-   * explicitly, which means that we shouldn't display anything.
-   * So, we can't simply store a NULL in window_cursor to
-   * determine an unset window cursor; we need an extra boolean.
-   */
-  gboolean has_window_cursor;
-  MetaCursorReference *window_cursor;
-
-  MetaCursorReference *root_cursor;
-
-  MetaCursorReference *default_cursors[META_CURSOR_LAST];
-
-  int current_x, current_y;
-  MetaRectangle current_rect;
-  MetaRectangle previous_rect;
-  gboolean previous_is_valid;
-
-  CoglPipeline *pipeline;
-  int drm_fd;
-  struct gbm_device *gbm;
-};
-
-struct _MetaCursorTrackerClass {
-  GObjectClass parent_class;
-};
-
 G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT);
 
 enum {
@@ -117,323 +63,6 @@ static void meta_cursor_tracker_set_crtc_has_hw_cursor (MetaCursorTracker *track
 static void sync_cursor (MetaCursorTracker *tracker);
 
 static void
-translate_meta_cursor (MetaCursor   cursor,
-                       guint       *glyph_out,
-                       const char **name_out)
-{
-  guint glyph = XC_num_glyphs;
-  const char *name = NULL;
-
-  switch (cursor)
-    {
-    case META_CURSOR_DEFAULT:
-      glyph = XC_left_ptr;
-      break;
-    case META_CURSOR_NORTH_RESIZE:
-      glyph = XC_top_side;
-      break;
-    case META_CURSOR_SOUTH_RESIZE:
-      glyph = XC_bottom_side;
-      break;
-    case META_CURSOR_WEST_RESIZE:
-      glyph = XC_left_side;
-      break;
-    case META_CURSOR_EAST_RESIZE:
-      glyph = XC_right_side;
-      break;
-    case META_CURSOR_SE_RESIZE:
-      glyph = XC_bottom_right_corner;
-      break;
-    case META_CURSOR_SW_RESIZE:
-      glyph = XC_bottom_left_corner;
-      break;
-    case META_CURSOR_NE_RESIZE:
-      glyph = XC_top_right_corner;
-      break;
-    case META_CURSOR_NW_RESIZE:
-      glyph = XC_top_left_corner;
-      break;
-    case META_CURSOR_MOVE_OR_RESIZE_WINDOW:
-      glyph = XC_fleur;
-      break;
-    case META_CURSOR_BUSY:
-      glyph = XC_watch;
-      break;
-    case META_CURSOR_DND_IN_DRAG:
-      name = "dnd-none";
-      break;
-    case META_CURSOR_DND_MOVE:
-      name = "dnd-move";
-      break;
-    case META_CURSOR_DND_COPY:
-      name = "dnd-copy";
-      break;
-    case META_CURSOR_DND_UNSUPPORTED_TARGET:
-      name = "dnd-none";
-      break;
-    case META_CURSOR_POINTING_HAND:
-      glyph = XC_hand2;
-      break;
-    case META_CURSOR_CROSSHAIR:
-      glyph = XC_crosshair;
-      break;
-    case META_CURSOR_IBEAM:
-      glyph = XC_xterm;
-      break;
-
-    default:
-      g_assert_not_reached ();
-      glyph = 0; /* silence compiler */
-      break;
-    }
-
-  *glyph_out = glyph;
-  *name_out = name;
-}
-
-static Cursor
-load_cursor_on_server (MetaDisplay *display,
-                       MetaCursor   cursor)
-{
-  Cursor xcursor;
-  guint glyph;
-  const char *name;
-
-  translate_meta_cursor (cursor, &glyph, &name);
-
-  if (name != NULL)
-    xcursor = XcursorLibraryLoadCursor (display->xdisplay, name);
-  else
-    xcursor = XCreateFontCursor (display->xdisplay, glyph);
-
-  return xcursor;
-}
-
-Cursor
-meta_display_create_x_cursor (MetaDisplay *display,
-                              MetaCursor cursor)
-{
-  return load_cursor_on_server (display, cursor);
-}
-
-static XcursorImage *
-load_cursor_on_client (MetaDisplay *display,
-                       MetaCursor   cursor)
-{
-  XcursorImage *image;
-  guint glyph;
-  const char *name;
-  const char *theme = XcursorGetTheme (display->xdisplay);
-  int size = XcursorGetDefaultSize (display->xdisplay);
-
-  translate_meta_cursor (cursor, &glyph, &name);
-
-  if (name != NULL)
-    image = XcursorLibraryLoadImage (name, theme, size);
-  else
-    image = XcursorShapeLoadImage (glyph, theme, size);
-
-  return image;
-}
-
-static MetaCursorReference *
-meta_cursor_reference_from_theme (MetaCursorTracker  *tracker,
-                                  MetaCursor          cursor)
-{
-  XcursorImage *image;
-  int width, height, rowstride;
-  CoglPixelFormat cogl_format;
-  uint32_t gbm_format;
-  ClutterBackend *clutter_backend;
-  CoglContext *cogl_context;
-  MetaCursorReference *self;
-
-  image = load_cursor_on_client (tracker->screen->display, cursor);
-  if (!image)
-    return NULL;
-
-  width           = image->width;
-  height          = image->height;
-  rowstride       = width * 4;
-
-  gbm_format = GBM_FORMAT_ARGB8888;
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
-  cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
-#else
-  cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
-#endif
-
-  self = g_slice_new0 (MetaCursorReference);
-  self->ref_count = 1;
-  self->hot_x = image->xhot;
-  self->hot_y = image->yhot;
-
-  clutter_backend = clutter_get_default_backend ();
-  cogl_context = clutter_backend_get_cogl_context (clutter_backend);
-  self->texture = cogl_texture_2d_new_from_data (cogl_context,
-                                                 width, height,
-                                                 cogl_format,
-                                                 rowstride,
-                                                 (uint8_t*)image->pixels,
-                                                 NULL);
-
-  if (tracker->gbm)
-    {
-      if (width > 64 || height > 64)
-        {
-          meta_warning ("Invalid theme cursor size (must be at most 64x64)\n");
-          goto out;
-        }
-
-      if (gbm_device_is_format_supported (tracker->gbm, gbm_format,
-                                          GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE))
-        {
-          uint32_t buf[64 * 64];
-          int i;
-
-          self->bo = gbm_bo_create (tracker->gbm, 64, 64,
-                                    gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
-
-          memset (buf, 0, sizeof(buf));
-          for (i = 0; i < height; i++)
-            memcpy (buf + i * 64, image->pixels + i * width, width * 4);
-
-          gbm_bo_write (self->bo, buf, 64 * 64 * 4);
-        }
-      else
-        meta_warning ("HW cursor for format %d not supported\n", gbm_format);
-    }
-
- out:
-  XcursorImageDestroy (image);
-
-  return self;
-}
-
-static MetaCursorReference *
-meta_cursor_reference_from_buffer (MetaCursorTracker  *tracker,
-                                   struct wl_resource *buffer,
-                                   int                 hot_x,
-                                   int                 hot_y)
-{
-  ClutterBackend *backend;
-  CoglContext *cogl_context;
-  MetaCursorReference *self;
-  CoglPixelFormat cogl_format;
-  struct wl_shm_buffer *shm_buffer;
-  uint32_t gbm_format;
-
-  self = g_slice_new0 (MetaCursorReference);
-  self->ref_count = 1;
-  self->hot_x = hot_x;
-  self->hot_y = hot_y;
-
-  backend = clutter_get_default_backend ();
-  cogl_context = clutter_backend_get_cogl_context (backend);
-
-  shm_buffer = wl_shm_buffer_get (buffer);
-  if (shm_buffer)
-    {
-      int rowstride = wl_shm_buffer_get_stride (shm_buffer);
-      int width = wl_shm_buffer_get_width (shm_buffer);
-      int height = wl_shm_buffer_get_height (shm_buffer);
-
-      switch (wl_shm_buffer_get_format (shm_buffer))
-        {
-#if G_BYTE_ORDER == G_BIG_ENDIAN
-          case WL_SHM_FORMAT_ARGB8888:
-            cogl_format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
-            gbm_format = GBM_FORMAT_ARGB8888;
-            break;
-          case WL_SHM_FORMAT_XRGB8888:
-            cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
-            gbm_format = GBM_FORMAT_XRGB8888;
-            break;
-#else
-          case WL_SHM_FORMAT_ARGB8888:
-            cogl_format = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
-            gbm_format = GBM_FORMAT_ARGB8888;
-            break;
-          case WL_SHM_FORMAT_XRGB8888:
-            cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
-            gbm_format = GBM_FORMAT_XRGB8888;
-            break;
-#endif
-          default:
-            g_warn_if_reached ();
-            cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
-            gbm_format = GBM_FORMAT_ARGB8888;
-        }
-
-      self->texture = cogl_texture_2d_new_from_data (cogl_context,
-                                                     width, height,
-                                                     cogl_format,
-                                                     rowstride,
-                                                     wl_shm_buffer_get_data (shm_buffer),
-                                                     NULL);
-
-      if (width > 64 || height > 64)
-        {
-          meta_warning ("Invalid cursor size (must be at most 64x64), falling back to software (GL) 
cursors\n");
-          return self;
-        }
-
-      if (tracker->gbm)
-        {
-          if (gbm_device_is_format_supported (tracker->gbm, gbm_format,
-                                              GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE))
-            {
-              uint8_t *data;
-              uint8_t buf[4 * 64 * 64];
-              int i;
-
-              self->bo = gbm_bo_create (tracker->gbm, 64, 64,
-                                        gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
-
-              data = wl_shm_buffer_get_data (shm_buffer);
-              memset (buf, 0, sizeof(buf));
-              for (i = 0; i < height; i++)
-                memcpy (buf + i * 4 * 64, data + i * rowstride, 4 * width);
-
-              gbm_bo_write (self->bo, buf, 64 * 64 * 4);
-            }
-          else
-            meta_warning ("HW cursor for format %d not supported\n", gbm_format);
-        }
-    }
-  else
-    {
-      int width, height;
-
-      self->texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL);
-      width = cogl_texture_get_width (COGL_TEXTURE (self->texture));
-      height = cogl_texture_get_height (COGL_TEXTURE (self->texture));
-
-      /* HW cursors must be 64x64, but 64x64 is huge, and no cursor theme actually uses
-         that, so themed cursors must be padded with transparent pixels to fill the
-         overlay. This is trivial if we have CPU access to the data, but it's not
-         possible if the buffer is in GPU memory (and possibly tiled too), so if we
-         don't get the right size, we fallback to GL.
-      */
-      if (width != 64 || height != 64)
-        {
-          meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n");
-          return self;
-        }
-
-      if (tracker->gbm)
-        {
-          self->bo = gbm_bo_import (tracker->gbm, GBM_BO_IMPORT_WL_BUFFER,
-                                    buffer, GBM_BO_USE_CURSOR_64X64);
-          if (!self->bo)
-            meta_warning ("Importing HW cursor from wl_buffer failed\n");
-        }
-     }
-
-  return self;
-}
-
-static void
 meta_cursor_tracker_init (MetaCursorTracker *self)
 {
   /* (JS) Best (?) that can be assumed since XFixes doesn't provide a way of
diff --git a/src/core/meta-cursor.c b/src/core/meta-cursor.c
index 822fd11..5749054 100644
--- a/src/core/meta-cursor.c
+++ b/src/core/meta-cursor.c
@@ -23,6 +23,20 @@
 
 #include "meta-cursor-private.h"
 
+#include <meta/errors.h>
+
+#include "display-private.h"
+#include "screen-private.h"
+#include "meta-cursor-tracker-private.h" /* for tracker->gbm */
+
+#include <string.h>
+
+#include <X11/cursorfont.h>
+#include <X11/extensions/Xfixes.h>
+#include <X11/Xcursor/Xcursor.h>
+
+#include <cogl/cogl-wayland-server.h>
+
 MetaCursorReference *
 meta_cursor_reference_ref (MetaCursorReference *self)
 {
@@ -46,3 +60,320 @@ meta_cursor_reference_unref (MetaCursorReference *self)
       g_slice_free (MetaCursorReference, self);
     }
 }
+
+static void
+translate_meta_cursor (MetaCursor   cursor,
+                       guint       *glyph_out,
+                       const char **name_out)
+{
+  guint glyph = XC_num_glyphs;
+  const char *name = NULL;
+
+  switch (cursor)
+    {
+    case META_CURSOR_DEFAULT:
+      glyph = XC_left_ptr;
+      break;
+    case META_CURSOR_NORTH_RESIZE:
+      glyph = XC_top_side;
+      break;
+    case META_CURSOR_SOUTH_RESIZE:
+      glyph = XC_bottom_side;
+      break;
+    case META_CURSOR_WEST_RESIZE:
+      glyph = XC_left_side;
+      break;
+    case META_CURSOR_EAST_RESIZE:
+      glyph = XC_right_side;
+      break;
+    case META_CURSOR_SE_RESIZE:
+      glyph = XC_bottom_right_corner;
+      break;
+    case META_CURSOR_SW_RESIZE:
+      glyph = XC_bottom_left_corner;
+      break;
+    case META_CURSOR_NE_RESIZE:
+      glyph = XC_top_right_corner;
+      break;
+    case META_CURSOR_NW_RESIZE:
+      glyph = XC_top_left_corner;
+      break;
+    case META_CURSOR_MOVE_OR_RESIZE_WINDOW:
+      glyph = XC_fleur;
+      break;
+    case META_CURSOR_BUSY:
+      glyph = XC_watch;
+      break;
+    case META_CURSOR_DND_IN_DRAG:
+      name = "dnd-none";
+      break;
+    case META_CURSOR_DND_MOVE:
+      name = "dnd-move";
+      break;
+    case META_CURSOR_DND_COPY:
+      name = "dnd-copy";
+      break;
+    case META_CURSOR_DND_UNSUPPORTED_TARGET:
+      name = "dnd-none";
+      break;
+    case META_CURSOR_POINTING_HAND:
+      glyph = XC_hand2;
+      break;
+    case META_CURSOR_CROSSHAIR:
+      glyph = XC_crosshair;
+      break;
+    case META_CURSOR_IBEAM:
+      glyph = XC_xterm;
+      break;
+
+    default:
+      g_assert_not_reached ();
+      glyph = 0; /* silence compiler */
+      break;
+    }
+
+  *glyph_out = glyph;
+  *name_out = name;
+}
+
+static Cursor
+load_cursor_on_server (MetaDisplay *display,
+                       MetaCursor   cursor)
+{
+  Cursor xcursor;
+  guint glyph;
+  const char *name;
+
+  translate_meta_cursor (cursor, &glyph, &name);
+
+  if (name != NULL)
+    xcursor = XcursorLibraryLoadCursor (display->xdisplay, name);
+  else
+    xcursor = XCreateFontCursor (display->xdisplay, glyph);
+
+  return xcursor;
+}
+
+Cursor
+meta_display_create_x_cursor (MetaDisplay *display,
+                              MetaCursor cursor)
+{
+  return load_cursor_on_server (display, cursor);
+}
+
+static XcursorImage *
+load_cursor_on_client (MetaDisplay *display,
+                       MetaCursor   cursor)
+{
+  XcursorImage *image;
+  guint glyph;
+  const char *name;
+  const char *theme = XcursorGetTheme (display->xdisplay);
+  int size = XcursorGetDefaultSize (display->xdisplay);
+
+  translate_meta_cursor (cursor, &glyph, &name);
+
+  if (name != NULL)
+    image = XcursorLibraryLoadImage (name, theme, size);
+  else
+    image = XcursorShapeLoadImage (glyph, theme, size);
+
+  return image;
+}
+
+MetaCursorReference *
+meta_cursor_reference_from_theme (MetaCursorTracker  *tracker,
+                                  MetaCursor          cursor)
+{
+  XcursorImage *image;
+  int width, height, rowstride;
+  CoglPixelFormat cogl_format;
+  uint32_t gbm_format;
+  ClutterBackend *clutter_backend;
+  CoglContext *cogl_context;
+  MetaCursorReference *self;
+
+  image = load_cursor_on_client (tracker->screen->display, cursor);
+  if (!image)
+    return NULL;
+
+  width           = image->width;
+  height          = image->height;
+  rowstride       = width * 4;
+
+  gbm_format = GBM_FORMAT_ARGB8888;
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+  cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
+#else
+  cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
+#endif
+
+  self = g_slice_new0 (MetaCursorReference);
+  self->ref_count = 1;
+  self->hot_x = image->xhot;
+  self->hot_y = image->yhot;
+
+  clutter_backend = clutter_get_default_backend ();
+  cogl_context = clutter_backend_get_cogl_context (clutter_backend);
+  self->texture = cogl_texture_2d_new_from_data (cogl_context,
+                                                 width, height,
+                                                 cogl_format,
+                                                 rowstride,
+                                                 (uint8_t*)image->pixels,
+                                                 NULL);
+
+  if (tracker->gbm)
+    {
+      if (width > 64 || height > 64)
+        {
+          meta_warning ("Invalid theme cursor size (must be at most 64x64)\n");
+          goto out;
+        }
+
+      if (gbm_device_is_format_supported (tracker->gbm, gbm_format,
+                                          GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE))
+        {
+          uint32_t buf[64 * 64];
+          int i;
+
+          self->bo = gbm_bo_create (tracker->gbm, 64, 64,
+                                    gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
+
+          memset (buf, 0, sizeof(buf));
+          for (i = 0; i < height; i++)
+            memcpy (buf + i * 64, image->pixels + i * width, width * 4);
+
+          gbm_bo_write (self->bo, buf, 64 * 64 * 4);
+        }
+      else
+        meta_warning ("HW cursor for format %d not supported\n", gbm_format);
+    }
+
+ out:
+  XcursorImageDestroy (image);
+
+  return self;
+}
+
+MetaCursorReference *
+meta_cursor_reference_from_buffer (MetaCursorTracker  *tracker,
+                                   struct wl_resource *buffer,
+                                   int                 hot_x,
+                                   int                 hot_y)
+{
+  ClutterBackend *backend;
+  CoglContext *cogl_context;
+  MetaCursorReference *self;
+  CoglPixelFormat cogl_format;
+  struct wl_shm_buffer *shm_buffer;
+  uint32_t gbm_format;
+
+  self = g_slice_new0 (MetaCursorReference);
+  self->ref_count = 1;
+  self->hot_x = hot_x;
+  self->hot_y = hot_y;
+
+  backend = clutter_get_default_backend ();
+  cogl_context = clutter_backend_get_cogl_context (backend);
+
+  shm_buffer = wl_shm_buffer_get (buffer);
+  if (shm_buffer)
+    {
+      int rowstride = wl_shm_buffer_get_stride (shm_buffer);
+      int width = wl_shm_buffer_get_width (shm_buffer);
+      int height = wl_shm_buffer_get_height (shm_buffer);
+
+      switch (wl_shm_buffer_get_format (shm_buffer))
+        {
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+          case WL_SHM_FORMAT_ARGB8888:
+            cogl_format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
+            gbm_format = GBM_FORMAT_ARGB8888;
+            break;
+          case WL_SHM_FORMAT_XRGB8888:
+            cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
+            gbm_format = GBM_FORMAT_XRGB8888;
+            break;
+#else
+          case WL_SHM_FORMAT_ARGB8888:
+            cogl_format = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
+            gbm_format = GBM_FORMAT_ARGB8888;
+            break;
+          case WL_SHM_FORMAT_XRGB8888:
+            cogl_format = COGL_PIXEL_FORMAT_BGRA_8888;
+            gbm_format = GBM_FORMAT_XRGB8888;
+            break;
+#endif
+          default:
+            g_warn_if_reached ();
+            cogl_format = COGL_PIXEL_FORMAT_ARGB_8888;
+            gbm_format = GBM_FORMAT_ARGB8888;
+        }
+
+      self->texture = cogl_texture_2d_new_from_data (cogl_context,
+                                                     width, height,
+                                                     cogl_format,
+                                                     rowstride,
+                                                     wl_shm_buffer_get_data (shm_buffer),
+                                                     NULL);
+
+      if (width > 64 || height > 64)
+        {
+          meta_warning ("Invalid cursor size (must be at most 64x64), falling back to software (GL) 
cursors\n");
+          return self;
+        }
+
+      if (tracker->gbm)
+        {
+          if (gbm_device_is_format_supported (tracker->gbm, gbm_format,
+                                              GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE))
+            {
+              uint8_t *data;
+              uint8_t buf[4 * 64 * 64];
+              int i;
+
+              self->bo = gbm_bo_create (tracker->gbm, 64, 64,
+                                        gbm_format, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
+
+              data = wl_shm_buffer_get_data (shm_buffer);
+              memset (buf, 0, sizeof(buf));
+              for (i = 0; i < height; i++)
+                memcpy (buf + i * 4 * 64, data + i * rowstride, 4 * width);
+
+              gbm_bo_write (self->bo, buf, 64 * 64 * 4);
+            }
+          else
+            meta_warning ("HW cursor for format %d not supported\n", gbm_format);
+        }
+    }
+  else
+    {
+      int width, height;
+
+      self->texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL);
+      width = cogl_texture_get_width (COGL_TEXTURE (self->texture));
+      height = cogl_texture_get_height (COGL_TEXTURE (self->texture));
+
+      /* HW cursors must be 64x64, but 64x64 is huge, and no cursor theme actually uses
+         that, so themed cursors must be padded with transparent pixels to fill the
+         overlay. This is trivial if we have CPU access to the data, but it's not
+         possible if the buffer is in GPU memory (and possibly tiled too), so if we
+         don't get the right size, we fallback to GL.
+      */
+      if (width != 64 || height != 64)
+        {
+          meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n");
+          return self;
+        }
+
+      if (tracker->gbm)
+        {
+          self->bo = gbm_bo_import (tracker->gbm, GBM_BO_IMPORT_WL_BUFFER,
+                                    buffer, GBM_BO_USE_CURSOR_64X64);
+          if (!self->bo)
+            meta_warning ("Importing HW cursor from wl_buffer failed\n");
+        }
+     }
+
+  return self;
+}
diff --git a/src/core/meta-cursor.h b/src/core/meta-cursor.h
index 6d5bc3e..50ad086 100644
--- a/src/core/meta-cursor.h
+++ b/src/core/meta-cursor.h
@@ -27,4 +27,16 @@ typedef struct _MetaCursorReference MetaCursorReference;
 MetaCursorReference * meta_cursor_reference_ref (MetaCursorReference *cursor);
 void meta_cursor_reference_unref (MetaCursorReference *cursor);
 
+#include <meta/meta-cursor-tracker.h>
+#include <meta/common.h>
+#include <wayland-server.h>
+
+MetaCursorReference * meta_cursor_reference_from_theme  (MetaCursorTracker  *tracker,
+                                                         MetaCursor          cursor);
+
+MetaCursorReference * meta_cursor_reference_from_buffer (MetaCursorTracker  *tracker,
+                                                         struct wl_resource *buffer,
+                                                         int                 hot_x,
+                                                         int                 hot_y);
+
 #endif /* META_CURSOR_H */


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