[mutter/wip/wayland-stacking: 7/13] wayland: Add an actor for the cursor
- From: Robert Bragg <rbragg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wip/wayland-stacking: 7/13] wayland: Add an actor for the cursor
- Date: Wed, 16 May 2012 19:00:16 +0000 (UTC)
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]