[mutter/wip/wayland-stacking: 7/13] wayland: Add an actor for the cursor



commit 79a92ef01fa739e6519bfe7a29e25291418aac29
Author: Neil Roberts <neil linux intel com>
Date:   Wed Jan 18 23:03:23 2012 +0000

    wayland: Add an actor for the cursor
    
    When running Mutter under Cogl's KMS backend no cursor will be
    provided so instead this makes it so the cursor will be painted as a
    ClutterTexture that gets moved in respose to mouse motion events. The
    painting is done in a subclass of ClutterStage so that we can
    guarantee that the actor will be painted on top of all other actors.
    
    This patch adds support for the attach method on the input device
    interface so that clients can change the cursor image.
    
    The attach method sets a buffer and a hotspot position to use for the
    cursor image. Mutter now just converts the buffer to a Cogl texture
    and sets it on the ClutterTexture for the cursor. The cursor reverts
    back to the default image whenever to the pointer focus is moved off
    of any surface.
    
    The image for the pointer is taken from X. It gets installed into
    a fixed data location for mutter.

 Makefile.am                             |    2 +-
 configure.in                            |    1 +
 data/Makefile.am                        |    7 +
 data/left_ptr.png                       |  Bin 0 -> 736 bytes
 src/Makefile.am                         |    4 +-
 src/wayland/meta-wayland-input-device.c |   20 +++
 src/wayland/meta-wayland-stage.c        |  240 +++++++++++++++++++++++++++++++
 src/wayland/meta-wayland-stage.h        |   93 ++++++++++++
 src/wayland/meta-wayland.c              |   10 ++-
 9 files changed, 374 insertions(+), 3 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index d9c9d31..bc1cd77 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,5 @@
 
-SUBDIRS=src po doc
+SUBDIRS=src data po doc
 
 EXTRA_DIST = HACKING MAINTAINERS rationales.txt
 
diff --git a/configure.in b/configure.in
index 22c3b6f..b582e74 100644
--- a/configure.in
+++ b/configure.in
@@ -511,6 +511,7 @@ src/libmutter.pc
 src/mutter-plugins.pc
 src/tools/Makefile
 src/compositor/plugins/Makefile
+data/Makefile
 po/Makefile.in
 ])
 
diff --git a/data/Makefile.am b/data/Makefile.am
new file mode 100644
index 0000000..0fbff45
--- /dev/null
+++ b/data/Makefile.am
@@ -0,0 +1,7 @@
+defaultcursordir = $(datadir)/mutter/cursors
+
+dist_defaultcursor_DATA =
+
+if HAVE_WAYLAND
+dist_defaultcursor_DATA += left_ptr.png
+endif
diff --git a/data/left_ptr.png b/data/left_ptr.png
new file mode 100644
index 0000000..d3818cc
Binary files /dev/null and b/data/left_ptr.png differ
diff --git a/src/Makefile.am b/src/Makefile.am
index 9982c08..f8733fb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -170,7 +170,9 @@ libmutter_la_SOURCES +=				\
 	wayland/meta-wayland.c			\
 	wayland/meta-wayland-private.h		\
 	wayland/meta-wayland-input-device.h	\
-	wayland/meta-wayland-input-device.c
+	wayland/meta-wayland-input-device.c	\
+	wayland/meta-wayland-stage.h		\
+	wayland/meta-wayland-stage.c
 endif
 
 libmutter_la_LDFLAGS = -no-undefined
diff --git a/src/wayland/meta-wayland-input-device.c b/src/wayland/meta-wayland-input-device.c
index adba30c..48beb03 100644
--- a/src/wayland/meta-wayland-input-device.c
+++ b/src/wayland/meta-wayland-input-device.c
@@ -28,6 +28,7 @@
 #include <string.h>
 #include <linux/input.h>
 #include "meta-wayland-input-device.h"
+#include "meta-wayland-stage.h"
 #include "meta-wayland-private.h"
 
 struct _MetaWaylandInputDevice
@@ -45,6 +46,25 @@ input_device_attach (struct wl_client *client,
                      int32_t hotspot_x,
                      int32_t hotspot_y)
 {
+  MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
+  MetaWaylandStage *stage = META_WAYLAND_STAGE (compositor->stage);
+  MetaWaylandInputDevice *device = resource->data;
+  struct wl_input_device *input_device = (struct wl_input_device *) device;
+
+  if (time < input_device->pointer_focus_time)
+    return;
+  if (input_device->pointer_focus == NULL)
+    return;
+  if (input_device->pointer_focus->resource.client != client)
+    return;
+
+  if (buffer_resource)
+    meta_wayland_stage_set_cursor_from_buffer (stage,
+                                               buffer_resource->data,
+                                               hotspot_x,
+                                               hotspot_y);
+  else
+    meta_wayland_stage_set_invisible_cursor (stage);
 }
 
 const static struct wl_input_device_interface
diff --git a/src/wayland/meta-wayland-stage.c b/src/wayland/meta-wayland-stage.c
new file mode 100644
index 0000000..25553b8
--- /dev/null
+++ b/src/wayland/meta-wayland-stage.c
@@ -0,0 +1,240 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#define COGL_ENABLE_EXPERIMENTAL_2_0_API
+#define CLUTTER_ENABLE_EXPERIMENTAL_API
+#include <clutter/clutter.h>
+
+#include <cogl/cogl-wayland-server.h>
+
+#include "meta-wayland-stage.h"
+
+#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X 7
+#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y 4
+
+G_DEFINE_TYPE (MetaWaylandStage, meta_wayland_stage, CLUTTER_TYPE_STAGE);
+
+static void
+meta_wayland_stage_dispose (GObject *object)
+{
+  MetaWaylandStage *self = (MetaWaylandStage *) object;
+
+  if (self->cursor_texture)
+    {
+      clutter_actor_destroy (self->cursor_texture);
+      self->cursor_texture = NULL;
+    }
+
+  G_OBJECT_CLASS (meta_wayland_stage_parent_class)->dispose (object);
+}
+
+static void
+meta_wayland_stage_finalize (GObject *object)
+{
+  MetaWaylandStage *self = (MetaWaylandStage *) object;
+
+  if (self->default_cursor_image)
+    cogl_object_unref (self->default_cursor_image);
+
+  G_OBJECT_CLASS (meta_wayland_stage_parent_class)->finalize (object);
+}
+
+static void
+meta_wayland_stage_paint (ClutterActor *actor)
+{
+  MetaWaylandStage *self = META_WAYLAND_STAGE (actor);
+
+  CLUTTER_ACTOR_CLASS (meta_wayland_stage_parent_class)->paint (actor);
+
+  /* Make sure the cursor is always painted on top of all of the other
+     actors */
+  clutter_actor_paint (self->cursor_texture);
+}
+
+static void
+update_cursor_position (MetaWaylandStage *self)
+{
+  clutter_actor_set_position (self->cursor_texture,
+                              self->cursor_x - self->cursor_hotspot_x,
+                              self->cursor_y - self->cursor_hotspot_y);
+}
+
+static void
+meta_wayland_stage_allocate (ClutterActor           *actor,
+                             const ClutterActorBox  *allocation,
+                             ClutterAllocationFlags  flags)
+{
+  MetaWaylandStage *self = META_WAYLAND_STAGE (actor);
+
+  CLUTTER_ACTOR_CLASS (meta_wayland_stage_parent_class)->allocate (actor,
+                                                                   allocation,
+                                                                   flags);
+
+  if (self->cursor_texture)
+    clutter_actor_allocate_preferred_size (self->cursor_texture, flags);
+}
+
+static void
+meta_wayland_stage_class_init (MetaWaylandStageClass *klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  ClutterActorClass *actor_class = (ClutterActorClass *) klass;
+
+  gobject_class->dispose = meta_wayland_stage_dispose;
+  gobject_class->finalize = meta_wayland_stage_finalize;
+
+  actor_class->paint = meta_wayland_stage_paint;
+  actor_class->allocate = meta_wayland_stage_allocate;
+}
+
+static CoglTexture *
+load_default_cursor_image (void)
+{
+  CoglTexture *ret;
+  GError *error = NULL;
+  char *filename;
+
+  filename = g_build_filename (MUTTER_DATADIR,
+                               "mutter/cursors/left_ptr.png",
+                               NULL);
+
+  ret = cogl_texture_new_from_file (filename,
+                                    COGL_TEXTURE_NONE,
+                                    COGL_PIXEL_FORMAT_ANY,
+                                    &error);
+  if (ret == NULL)
+    {
+      g_warning ("Failed to load default cursor: %s",
+                 error->message);
+      g_clear_error (&error);
+    }
+
+  g_free (filename);
+
+  return ret;
+}
+
+static void
+meta_wayland_stage_init (MetaWaylandStage *self)
+{
+  self->cursor_texture = clutter_texture_new ();
+
+  /* We don't want to add this as a container child so that we can
+     paint it manually above all of the other actors */
+  clutter_actor_set_parent (self->cursor_texture, CLUTTER_ACTOR (self));
+
+  self->default_cursor_image = load_default_cursor_image ();
+
+  meta_wayland_stage_set_default_cursor (self);
+}
+
+ClutterActor *
+meta_wayland_stage_new (void)
+{
+  return g_object_new (META_WAYLAND_TYPE_STAGE,
+                       "cursor-visible", FALSE,
+                       NULL);
+}
+
+void
+meta_wayland_stage_set_cursor_position (MetaWaylandStage *self,
+                                        int               x,
+                                        int               y)
+{
+  self->cursor_x = x;
+  self->cursor_y = y;
+  update_cursor_position (self);
+}
+
+static void
+meta_wayland_stage_set_cursor_from_texture (MetaWaylandStage *self,
+                                            CoglTexture      *texture,
+                                            int               hotspot_x,
+                                            int               hotspot_y)
+{
+  ClutterTexture *cursor_texture =
+    CLUTTER_TEXTURE (self->cursor_texture);
+
+  self->cursor_hotspot_x = hotspot_x;
+  self->cursor_hotspot_y = hotspot_y;
+
+  clutter_texture_set_cogl_texture (cursor_texture, texture);
+
+  clutter_actor_show (self->cursor_texture);
+
+  update_cursor_position (self);
+}
+
+void
+meta_wayland_stage_set_invisible_cursor (MetaWaylandStage *self)
+{
+  ClutterTexture *cursor_texture =
+    CLUTTER_TEXTURE (self->cursor_texture);
+
+  clutter_texture_set_cogl_texture (cursor_texture,
+                                    self->default_cursor_image);
+  clutter_actor_hide (self->cursor_texture);
+}
+
+void
+meta_wayland_stage_set_default_cursor (MetaWaylandStage *self)
+{
+  int hotspot_x = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X;
+  int hotspot_y = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y;
+
+  meta_wayland_stage_set_cursor_from_texture (self,
+                                              self->default_cursor_image,
+                                              hotspot_x,
+                                              hotspot_y);
+}
+
+void
+meta_wayland_stage_set_cursor_from_buffer (MetaWaylandStage *self,
+                                           struct wl_buffer *buffer,
+                                           int               hotspot_x,
+                                           int               hotspot_y)
+{
+  ClutterBackend *backend = clutter_get_default_backend ();
+  CoglContext *context = clutter_backend_get_cogl_context (backend);
+  CoglTexture *texture;
+  GError *error = NULL;
+
+  texture = COGL_TEXTURE (cogl_wayland_texture_2d_new_from_buffer (context,
+                                                                   buffer,
+                                                                   &error));
+
+  if (texture == NULL)
+    {
+      g_warning ("%s", error->message);
+      meta_wayland_stage_set_invisible_cursor (self);
+    }
+  else
+    {
+      meta_wayland_stage_set_cursor_from_texture (self,
+                                                  texture,
+                                                  hotspot_x,
+                                                  hotspot_y);
+
+      cogl_object_unref (texture);
+    }
+}
diff --git a/src/wayland/meta-wayland-stage.h b/src/wayland/meta-wayland-stage.h
new file mode 100644
index 0000000..46539ca
--- /dev/null
+++ b/src/wayland/meta-wayland-stage.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef META_WAYLAND_STAGE_H
+#define META_WAYLAND_STAGE_H
+
+#include <clutter/clutter.h>
+#include <wayland-server.h>
+
+G_BEGIN_DECLS
+
+#define META_WAYLAND_TYPE_STAGE                                         \
+  (meta_wayland_stage_get_type())
+#define META_WAYLAND_STAGE(obj)                                         \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj),                                   \
+                               META_WAYLAND_TYPE_STAGE,                 \
+                               MetaWaylandStage))
+#define META_WAYLAND_STAGE_CLASS(klass)                                 \
+  (G_TYPE_CHECK_CLASS_CAST ((klass),                                    \
+                            META_WAYLAND_TYPE_STAGE,                    \
+                            MetaWaylandStageClass))
+#define META_WAYLAND_IS_STAGE(obj)                                      \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj),                                   \
+                               META_WAYLAND_TYPE_STAGE))
+#define META_WAYLAND_IS_STAGE_CLASS(klass)                              \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass),                                    \
+                            META_WAYLAND_TYPE_STAGE))
+#define META_WAYLAND_STAGE_GET_CLASS(obj)                               \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj),                                    \
+                              META_WAYLAND_STAGE,                       \
+                              MetaWaylandStageClass))
+
+typedef struct _MetaWaylandStage      MetaWaylandStage;
+typedef struct _MetaWaylandStageClass MetaWaylandStageClass;
+
+struct _MetaWaylandStageClass
+{
+  ClutterStageClass parent_class;
+};
+
+struct _MetaWaylandStage
+{
+  ClutterStage parent;
+
+  /* The cursor image that will be used when the cursor is not over a
+     surface */
+  CoglTexture *default_cursor_image;
+
+  int cursor_x;
+  int cursor_y;
+
+  ClutterActor *cursor_texture;
+  int cursor_hotspot_x;
+  int cursor_hotspot_y;
+};
+
+GType             meta_wayland_stage_get_type               (void) G_GNUC_CONST;
+
+ClutterActor     *meta_wayland_stage_new                    (void);
+
+void              meta_wayland_stage_set_cursor_position    (MetaWaylandStage *stage,
+                                                             int               x,
+                                                             int               y);
+
+void              meta_wayland_stage_set_default_cursor     (MetaWaylandStage *self);
+
+void              meta_wayland_stage_set_cursor_from_buffer (MetaWaylandStage *self,
+                                                             struct wl_buffer *buffer,
+                                                             int               hotspot_x,
+                                                             int               hotspot_y);
+
+void              meta_wayland_stage_set_invisible_cursor   (MetaWaylandStage *self);
+
+
+G_END_DECLS
+
+#endif /* META_WAYLAND_STAGE_H */
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index 1a043be..f459b6a 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -43,6 +43,7 @@
 #include "xserver-server-protocol.h"
 
 #include "meta-wayland-private.h"
+#include "meta-wayland-stage.h"
 #include "meta-window-actor-private.h"
 #include "display-private.h"
 #include "window-private.h"
@@ -1181,6 +1182,13 @@ event_cb (ClutterActor *stage,
 
   meta_wayland_input_device_handle_event (compositor->input_device, event);
 
+  meta_wayland_stage_set_cursor_position (META_WAYLAND_STAGE (stage),
+                                          device->x,
+                                          device->y);
+
+  if (device->pointer_focus == NULL)
+    meta_wayland_stage_set_default_cursor (META_WAYLAND_STAGE (stage));
+
   display = meta_get_display ();
   if (!display)
     return FALSE;
@@ -1314,7 +1322,7 @@ meta_wayland_init (void)
   if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
     g_error ("Failed to initialize Clutter");
 
-  compositor->stage = clutter_stage_new ();
+  compositor->stage = meta_wayland_stage_new ();
   clutter_stage_set_user_resizable (CLUTTER_STAGE (compositor->stage), FALSE);
   g_signal_connect_after (compositor->stage, "paint",
                           G_CALLBACK (paint_finished_cb), compositor);



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