summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGiovanni Campagna <gcampagn@redhat.com>2013-08-13 12:57:41 +0200
committerGiovanni Campagna <gcampagn@redhat.com>2013-08-19 16:09:53 +0200
commit2ae7454f36bb5b73732ac3a01244a5862e3e8f1c (patch)
treea98d87d8c277121d111e8f570969bd72b15d0f8f
parent4fd3c63da9b68b47ad74534e2fec18399657e03a (diff)
downloadmutter-2ae7454f36bb5b73732ac3a01244a5862e3e8f1c.tar.gz
Add MetaCursorTracker, a new helper for tracking the cursor sprite
Under X, we need to use XFixes to watch the cursor changing, while on wayland, we're in charge of setting and painting the cursor. MetaCursorTracker provides the abstraction layer for gnome-shell, which can thus drop ShellXFixesCursor. In the future, it may grow the ability to watch for pointer position too, especially if CursorEvents are added to the next version of XInput2, and thus it would also replace the PointerWatcher we use for gnome-shell's magnifier. https://bugzilla.gnome.org/show_bug.cgi?id=705911
-rw-r--r--src/Makefile.am3
-rw-r--r--src/core/display.c8
-rw-r--r--src/core/meta-cursor-tracker-private.h46
-rw-r--r--src/core/meta-cursor-tracker.c451
-rw-r--r--src/core/screen-private.h4
-rw-r--r--src/core/screen.c31
-rw-r--r--src/meta/meta-cursor-tracker.h49
-rw-r--r--src/meta/types.h1
-rw-r--r--src/wayland/meta-wayland-private.h2
-rw-r--r--src/wayland/meta-wayland-seat.c48
-rw-r--r--src/wayland/meta-wayland-stage.c187
-rw-r--r--src/wayland/meta-wayland-stage.h41
-rw-r--r--src/wayland/meta-wayland.c16
13 files changed, 626 insertions, 261 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 491e78445..8c1b393e1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -124,6 +124,8 @@ libmutter_la_SOURCES = \
core/keybindings.c \
core/keybindings-private.h \
core/main.c \
+ core/meta-cursor-tracker.c \
+ core/meta-cursor-tracker-private.h \
core/mutter-Xatomtype.h \
core/place.c \
core/place.h \
@@ -210,6 +212,7 @@ libmutterinclude_base_headers = \
meta/meta-background-actor.h \
meta/meta-background-group.h \
meta/meta-background.h \
+ meta/meta-cursor-tracker.h \
meta/meta-plugin.h \
meta/meta-shaped-texture.h \
meta/meta-shadow-factory.h \
diff --git a/src/core/display.c b/src/core/display.c
index c71b8c34a..316748d8a 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -2177,6 +2177,7 @@ meta_display_handle_event (MetaDisplay *display,
gboolean bypass_compositor;
gboolean filter_out_event;
XIEvent *input_event;
+ MetaScreen *screen;
#ifdef WITH_VERBOSE_MODE
if (dump_events)
@@ -2204,6 +2205,13 @@ meta_display_handle_event (MetaDisplay *display,
display->server_focus_serial);
}
+ screen = meta_display_screen_for_root (display, event->xany.window);
+ if (screen)
+ {
+ if (meta_screen_handle_xevent (screen, event))
+ return TRUE;
+ }
+
modified = event_get_modified_window (display, event);
input_event = get_input_event (display, event);
diff --git a/src/core/meta-cursor-tracker-private.h b/src/core/meta-cursor-tracker-private.h
new file mode 100644
index 000000000..773ac0020
--- /dev/null
+++ b/src/core/meta-cursor-tracker-private.h
@@ -0,0 +1,46 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/*
+ * Copyright 2013 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * Author: Giovanni Campagna <gcampagn@redhat.com>
+ */
+
+#ifndef META_CURSOR_TRACKER_PRIVATE_H
+#define META_CURSOR_TRACKER_PRIVATE_H
+
+#include <meta/meta-cursor-tracker.h>
+
+gboolean meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
+ XEvent *xevent);
+
+void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
+ MetaCursor cursor);
+void meta_cursor_tracker_revert_root (MetaCursorTracker *tracker);
+void meta_cursor_tracker_set_sprite (MetaCursorTracker *tracker,
+ CoglTexture2D *texture,
+ int hot_x,
+ int hot_y);
+
+void meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
+ int new_x,
+ int new_y);
+void meta_cursor_tracker_paint (MetaCursorTracker *tracker);
+void meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker,
+ ClutterActor *stage);
+#endif
diff --git a/src/core/meta-cursor-tracker.c b/src/core/meta-cursor-tracker.c
new file mode 100644
index 000000000..4a374d54d
--- /dev/null
+++ b/src/core/meta-cursor-tracker.c
@@ -0,0 +1,451 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/*
+ * Copyright 2013 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * Author: Giovanni Campagna <gcampagn@redhat.com>
+ */
+
+/**
+ * SECTION:cursor-tracker
+ * @title: MetaCursorTracker
+ * @short_description: Mutter cursor tracking helper
+ */
+
+#include <config.h>
+#include <meta/main.h>
+#include <meta/util.h>
+#include <meta/errors.h>
+
+#include <cogl/cogl.h>
+#include <clutter/clutter.h>
+
+#include <X11/extensions/Xfixes.h>
+
+#include "meta-cursor-tracker-private.h"
+#include "screen-private.h"
+#include "meta-wayland-private.h"
+
+#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X 7
+#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y 4
+
+struct _MetaCursorTracker {
+ GObject parent_instance;
+
+ MetaScreen *screen;
+
+ gboolean is_showing;
+
+ CoglTexture2D *sprite;
+ int hot_x, hot_y;
+
+ CoglTexture2D *root_cursor;
+ int root_hot_x, root_hot_y;
+
+ CoglTexture2D *default_cursor;
+
+ int current_x, current_y;
+ cairo_rectangle_int_t current_rect;
+ cairo_rectangle_int_t previous_rect;
+ gboolean previous_is_valid;
+
+ CoglPipeline *pipeline;
+};
+
+struct _MetaCursorTrackerClass {
+ GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT);
+
+enum {
+ CURSOR_CHANGED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static void
+meta_cursor_tracker_init (MetaCursorTracker *self)
+{
+ /* (JS) Best (?) that can be assumed since XFixes doesn't provide a way of
+ detecting if the system mouse cursor is showing or not.
+
+ On wayland we start with the cursor showing
+ */
+ self->is_showing = TRUE;
+}
+
+static void
+meta_cursor_tracker_finalize (GObject *object)
+{
+ MetaCursorTracker *self = META_CURSOR_TRACKER (object);
+
+ if (self->sprite)
+ cogl_object_unref (self->sprite);
+ if (self->root_cursor)
+ cogl_object_unref (self->root_cursor);
+ if (self->default_cursor)
+ cogl_object_unref (self->default_cursor);
+ if (self->pipeline)
+ cogl_object_unref (self->pipeline);
+
+ G_OBJECT_CLASS (meta_cursor_tracker_parent_class)->finalize (object);
+}
+
+static void
+meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = meta_cursor_tracker_finalize;
+
+ signals[CURSOR_CHANGED] = g_signal_new ("cursor-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
+}
+
+static MetaCursorTracker *
+make_wayland_cursor_tracker (MetaScreen *screen)
+{
+ MetaWaylandCompositor *compositor;
+ CoglContext *ctx;
+ MetaCursorTracker *self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL);
+ self->screen = screen;
+
+ ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
+ self->pipeline = cogl_pipeline_new (ctx);
+
+ compositor = meta_wayland_compositor_get_default ();
+ compositor->seat->cursor_tracker = self;
+
+ return self;
+}
+
+static MetaCursorTracker *
+make_x11_cursor_tracker (MetaScreen *screen)
+{
+ MetaCursorTracker *self = g_object_new (META_TYPE_CURSOR_TRACKER, NULL);
+ self->screen = screen;
+
+ XFixesSelectCursorInput (screen->display->xdisplay,
+ screen->xroot,
+ XFixesDisplayCursorNotifyMask);
+
+ return self;
+}
+
+/**
+ * meta_cursor_tracker_get_for_screen:
+ * @screen: the #MetaScreen
+ *
+ * Retrieves the cursor tracker object for @screen.
+ *
+ * Returns: (transfer none):
+ */
+MetaCursorTracker *
+meta_cursor_tracker_get_for_screen (MetaScreen *screen)
+{
+ MetaCursorTracker *self;
+
+ if (screen->cursor_tracker)
+ return screen->cursor_tracker;
+
+ if (meta_is_wayland_compositor ())
+ self = make_wayland_cursor_tracker (screen);
+ else
+ self = make_x11_cursor_tracker (screen);
+
+ screen->cursor_tracker = self;
+ return self;
+}
+
+gboolean
+meta_cursor_tracker_handle_xevent (MetaCursorTracker *tracker,
+ XEvent *xevent)
+{
+ XFixesCursorNotifyEvent *notify_event;
+
+ if (meta_is_wayland_compositor ())
+ return FALSE;
+
+ if (xevent->xany.type != tracker->screen->display->xfixes_event_base + XFixesCursorNotify)
+ return FALSE;
+
+ notify_event = (XFixesCursorNotifyEvent *)xevent;
+ if (notify_event->subtype != XFixesDisplayCursorNotify)
+ return FALSE;
+
+ g_clear_pointer (&tracker->sprite, cogl_object_unref);
+ g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
+
+ return TRUE;
+}
+
+static void
+ensure_xfixes_cursor (MetaCursorTracker *tracker)
+{
+ XFixesCursorImage *cursor_image;
+ CoglTexture2D *sprite;
+ guint8 *cursor_data;
+ gboolean free_cursor_data;
+ CoglContext *ctx;
+
+ if (tracker->sprite)
+ return;
+
+ cursor_image = XFixesGetCursorImage (tracker->screen->display->xdisplay);
+ if (!cursor_image)
+ return;
+
+ /* Like all X APIs, XFixesGetCursorImage() returns arrays of 32-bit
+ * quantities as arrays of long; we need to convert on 64 bit */
+ if (sizeof(long) == 4)
+ {
+ cursor_data = (guint8 *)cursor_image->pixels;
+ free_cursor_data = FALSE;
+ }
+ else
+ {
+ int i, j;
+ guint32 *cursor_words;
+ gulong *p;
+ guint32 *q;
+
+ cursor_words = g_new (guint32, cursor_image->width * cursor_image->height);
+ cursor_data = (guint8 *)cursor_words;
+
+ p = cursor_image->pixels;
+ q = cursor_words;
+ for (j = 0; j < cursor_image->height; j++)
+ for (i = 0; i < cursor_image->width; i++)
+ *(q++) = *(p++);
+
+ free_cursor_data = TRUE;
+ }
+
+ ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
+ sprite = cogl_texture_2d_new_from_data (ctx,
+ cursor_image->width,
+ cursor_image->height,
+ CLUTTER_CAIRO_FORMAT_ARGB32,
+ COGL_PIXEL_FORMAT_ANY,
+ cursor_image->width * 4, /* stride */
+ cursor_data,
+ NULL);
+
+ if (free_cursor_data)
+ g_free (cursor_data);
+
+ if (sprite != NULL)
+ {
+ tracker->sprite = sprite;
+ tracker->hot_x = cursor_image->xhot;
+ tracker->hot_y = cursor_image->yhot;
+ }
+ XFree (cursor_image);
+}
+
+/**
+ * meta_cursor_tracker_get_sprite:
+ *
+ * Returns: (transfer none):
+ */
+CoglTexture *
+meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker)
+{
+ g_return_val_if_fail (META_IS_CURSOR_TRACKER (tracker), NULL);
+
+ if (!meta_is_wayland_compositor ())
+ ensure_xfixes_cursor (tracker);
+
+ return COGL_TEXTURE (tracker->sprite);
+}
+
+/**
+ * meta_cursor_tracker_get_hot:
+ * @tracker:
+ * @x: (out):
+ * @y: (out):
+ *
+ */
+void
+meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
+ int *x,
+ int *y)
+{
+ g_return_if_fail (META_IS_CURSOR_TRACKER (tracker));
+
+ if (!meta_is_wayland_compositor ())
+ ensure_xfixes_cursor (tracker);
+
+ if (x)
+ *x = tracker->hot_x;
+ if (y)
+ *y = tracker->hot_y;
+}
+
+static void
+ensure_wayland_cursor (MetaCursorTracker *tracker)
+{
+ CoglBitmap *bitmap;
+ char *filename;
+
+ if (tracker->default_cursor)
+ return;
+
+ filename = g_build_filename (MUTTER_PKGDATADIR,
+ "cursors/left_ptr.png",
+ NULL);
+
+ bitmap = cogl_bitmap_new_from_file (filename, NULL);
+ tracker->default_cursor = cogl_texture_2d_new_from_bitmap (bitmap,
+ COGL_PIXEL_FORMAT_ANY,
+ NULL);
+
+ cogl_object_unref (bitmap);
+ g_free (filename);
+}
+
+void
+meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
+ MetaCursor cursor)
+{
+ Cursor xcursor;
+ MetaDisplay *display = tracker->screen->display;
+
+ /* First create a cursor for X11 applications that don't specify their own */
+ xcursor = meta_display_create_x_cursor (display, cursor);
+
+ XDefineCursor (display->xdisplay, tracker->screen->xroot, xcursor);
+ XFlush (display->xdisplay);
+ XFreeCursor (display->xdisplay, xcursor);
+
+ /* Now update the real root cursor */
+ if (meta_is_wayland_compositor ())
+ {
+ /* FIXME! We need to load all the other cursors too */
+ ensure_wayland_cursor (tracker);
+
+ g_clear_pointer (&tracker->root_cursor, cogl_object_unref);
+ tracker->root_cursor = cogl_object_ref (tracker->default_cursor);
+ tracker->root_hot_x = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X;
+ tracker->root_hot_y = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y;
+ }
+}
+
+void
+meta_cursor_tracker_revert_root (MetaCursorTracker *tracker)
+{
+ meta_cursor_tracker_set_sprite (tracker,
+ tracker->root_cursor,
+ tracker->root_hot_x,
+ tracker->root_hot_y);
+}
+
+void
+meta_cursor_tracker_set_sprite (MetaCursorTracker *tracker,
+ CoglTexture2D *sprite,
+ int hot_x,
+ int hot_y)
+{
+ g_assert (meta_is_wayland_compositor ());
+
+ g_clear_pointer (&tracker->sprite, cogl_object_unref);
+
+ if (sprite)
+ {
+ tracker->sprite = cogl_object_ref (sprite);
+ tracker->hot_x = hot_x;
+ tracker->hot_y = hot_y;
+ cogl_pipeline_set_layer_texture (tracker->pipeline, 0, COGL_TEXTURE (tracker->sprite));
+ }
+ else
+ cogl_pipeline_set_layer_texture (tracker->pipeline, 0, NULL);
+
+ g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
+
+ meta_cursor_tracker_update_position (tracker, tracker->current_x, tracker->current_y);
+}
+
+void
+meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
+ int new_x,
+ int new_y)
+{
+ g_assert (meta_is_wayland_compositor ());
+
+ tracker->current_x = new_x;
+ tracker->current_y = new_y;
+ tracker->current_rect.x = tracker->current_x - tracker->hot_x;
+ tracker->current_rect.y = tracker->current_y - tracker->hot_y;
+
+ if (tracker->sprite)
+ {
+ tracker->current_rect.width = cogl_texture_get_width (COGL_TEXTURE (tracker->sprite));
+ tracker->current_rect.height = cogl_texture_get_height (COGL_TEXTURE (tracker->sprite));
+ }
+ else
+ {
+ tracker->current_rect.width = 0;
+ tracker->current_rect.height = 0;
+ }
+}
+
+void
+meta_cursor_tracker_paint (MetaCursorTracker *tracker)
+{
+ g_assert (meta_is_wayland_compositor ());
+
+ if (tracker->sprite == NULL)
+ return;
+
+ /* FIXME: try to use a DRM cursor when possible */
+ cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (),
+ tracker->pipeline,
+ tracker->current_rect.x,
+ tracker->current_rect.y,
+ tracker->current_rect.x +
+ tracker->current_rect.width,
+ tracker->current_rect.y +
+ tracker->current_rect.height);
+
+ tracker->previous_rect = tracker->current_rect;
+ tracker->previous_is_valid = TRUE;
+}
+
+void
+meta_cursor_tracker_queue_redraw (MetaCursorTracker *tracker,
+ ClutterActor *stage)
+{
+ g_assert (meta_is_wayland_compositor ());
+
+ if (tracker->previous_is_valid)
+ {
+ clutter_actor_queue_redraw_with_clip (stage, &tracker->previous_rect);
+ tracker->previous_is_valid = FALSE;
+ }
+
+ if (tracker->sprite == NULL)
+ return;
+
+ clutter_actor_queue_redraw_with_clip (stage, &tracker->current_rect);
+}
diff --git a/src/core/screen-private.h b/src/core/screen-private.h
index 7e8a13318..6bb32f16d 100644
--- a/src/core/screen-private.h
+++ b/src/core/screen-private.h
@@ -93,6 +93,7 @@ struct _MetaScreen
MetaStack *stack;
MetaStackTracker *stack_tracker;
+ MetaCursorTracker *cursor_tracker;
MetaCursor current_cursor;
Window flash_window;
@@ -259,4 +260,7 @@ void meta_screen_set_active_workspace_hint (MetaScreen *screen);
Window meta_screen_create_guard_window (Display *xdisplay, MetaScreen *screen);
+gboolean meta_screen_handle_xevent (MetaScreen *screen,
+ XEvent *xevent);
+
#endif
diff --git a/src/core/screen.c b/src/core/screen.c
index 073a8af71..3706d94c0 100644
--- a/src/core/screen.c
+++ b/src/core/screen.c
@@ -48,6 +48,7 @@
#ifdef HAVE_WAYLAND
#include "meta-wayland-private.h"
#endif
+#include "meta-cursor-tracker-private.h"
#include <X11/extensions/Xinerama.h>
@@ -879,7 +880,8 @@ meta_screen_new (MetaDisplay *display,
screen->last_monitor_index = 0;
reload_monitor_infos (screen);
-
+
+ meta_cursor_tracker_get_for_screen (screen);
meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
/* Handle creating a no_focus_window for this screen */
@@ -1635,29 +1637,18 @@ void
meta_screen_set_cursor (MetaScreen *screen,
MetaCursor cursor)
{
- Cursor xcursor;
-
if (cursor == screen->current_cursor)
return;
screen->current_cursor = cursor;
-
- xcursor = meta_display_create_x_cursor (screen->display, cursor);
- XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
- XFlush (screen->display->xdisplay);
- XFreeCursor (screen->display->xdisplay, xcursor);
+ meta_cursor_tracker_set_root_cursor (screen->cursor_tracker, cursor);
}
void
meta_screen_update_cursor (MetaScreen *screen)
{
- Cursor xcursor;
-
- xcursor = meta_display_create_x_cursor (screen->display,
- screen->current_cursor);
- XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
- XFlush (screen->display->xdisplay);
- XFreeCursor (screen->display->xdisplay, xcursor);
+ meta_cursor_tracker_set_root_cursor (screen->cursor_tracker,
+ screen->current_cursor);
}
void
@@ -3869,3 +3860,13 @@ meta_screen_get_monitor_in_fullscreen (MetaScreen *screen,
/* We use -1 as a flag to mean "not known yet" for notification purposes */
return screen->monitor_infos[monitor].in_fullscreen == TRUE;
}
+
+gboolean
+meta_screen_handle_xevent (MetaScreen *screen,
+ XEvent *xevent)
+{
+ if (meta_cursor_tracker_handle_xevent (screen->cursor_tracker, xevent))
+ return TRUE;
+
+ return FALSE;
+}
diff --git a/src/meta/meta-cursor-tracker.h b/src/meta/meta-cursor-tracker.h
new file mode 100644
index 000000000..75199d666
--- /dev/null
+++ b/src/meta/meta-cursor-tracker.h
@@ -0,0 +1,49 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/*
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * Author: Giovanni Campagna <gcampagn@redhat.com>
+ */
+
+#ifndef META_CURSOR_TRACKER_H
+#define META_CURSOR_TRACKER_H
+
+#include <glib-object.h>
+#include <meta/types.h>
+#include <meta/workspace.h>
+
+#define META_TYPE_CURSOR_TRACKER (meta_cursor_tracker_get_type ())
+#define META_CURSOR_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_CURSOR_TRACKER, MetaCursorTracker))
+#define META_CURSOR_TRACKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_CURSOR_TRACKER, MetaCursorTrackerClass))
+#define META_IS_CURSOR_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_CURSOR_TRACKER))
+#define META_IS_CURSOR_TRACKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_CURSOR_TRACKER))
+#define META_CURSOR_TRACKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_CURSOR_TRACKER, MetaCursorTrackerClass))
+
+typedef struct _MetaCursorTrackerClass MetaCursorTrackerClass;
+
+GType meta_cursor_tracker_get_type (void);
+
+MetaCursorTracker *meta_cursor_tracker_get_for_screen (MetaScreen *screen);
+
+void meta_cursor_tracker_get_hot (MetaCursorTracker *tracker,
+ int *x,
+ int *y);
+CoglTexture *meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker);
+
+#endif
diff --git a/src/meta/types.h b/src/meta/types.h
index 25833207d..f13471146 100644
--- a/src/meta/types.h
+++ b/src/meta/types.h
@@ -38,5 +38,6 @@ typedef struct _MetaWorkspace MetaWorkspace;
*/
typedef struct _MetaGroup MetaGroup;
typedef struct _MetaKeyBinding MetaKeyBinding;
+typedef struct _MetaCursorTracker MetaCursorTracker;
#endif
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
index a859378c1..89c145d0c 100644
--- a/src/wayland/meta-wayland-private.h
+++ b/src/wayland/meta-wayland-private.h
@@ -28,6 +28,7 @@
#include <cairo.h>
#include "window-private.h"
+#include <meta/meta-cursor-tracker.h>
typedef struct _MetaWaylandCompositor MetaWaylandCompositor;
@@ -335,6 +336,7 @@ struct _MetaWaylandSeat
struct wl_display *display;
+ MetaCursorTracker *cursor_tracker;
MetaWaylandSurface *sprite;
int hotspot_x, hotspot_y;
struct wl_listener sprite_destroy_listener;
diff --git a/src/wayland/meta-wayland-seat.c b/src/wayland/meta-wayland-seat.c
index 0d2b729e5..3ea739919 100644
--- a/src/wayland/meta-wayland-seat.c
+++ b/src/wayland/meta-wayland-seat.c
@@ -36,6 +36,7 @@
#include "meta-window-actor-private.h"
#include "meta/meta-shaped-texture.h"
#include "meta-wayland-stage.h"
+#include "meta-cursor-tracker-private.h"
#define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int (10)
@@ -73,10 +74,14 @@ transform_stage_point_fixed (MetaWaylandSurface *surface,
static void
pointer_unmap_sprite (MetaWaylandSeat *seat)
{
- if (seat->current_stage)
+ if (seat->cursor_tracker)
{
- MetaWaylandStage *stage = META_WAYLAND_STAGE (seat->current_stage);
- meta_wayland_stage_set_invisible_cursor (stage);
+ meta_cursor_tracker_set_sprite (seat->cursor_tracker,
+ NULL, 0, 0);
+
+ if (seat->current_stage)
+ meta_cursor_tracker_queue_redraw (seat->cursor_tracker,
+ CLUTTER_ACTOR (seat->current_stage));
}
if (seat->sprite)
@@ -89,22 +94,29 @@ pointer_unmap_sprite (MetaWaylandSeat *seat)
void
meta_wayland_seat_update_sprite (MetaWaylandSeat *seat)
{
+ ClutterBackend *backend;
+ CoglContext *context;
+ struct wl_resource *buffer;
+ CoglTexture2D *texture;
+
+ if (seat->cursor_tracker == NULL)
+ return;
+
+ backend = clutter_get_default_backend ();
+ context = clutter_backend_get_cogl_context (backend);
+ buffer = seat->sprite->buffer_ref.buffer->resource;
+ texture = cogl_wayland_texture_2d_new_from_buffer (context, buffer, NULL);
+
+ meta_cursor_tracker_set_sprite (seat->cursor_tracker,
+ texture,
+ seat->hotspot_x,
+ seat->hotspot_y);
+
if (seat->current_stage)
- {
- MetaWaylandStage *stage = META_WAYLAND_STAGE (seat->current_stage);
- ClutterBackend *backend = clutter_get_default_backend ();
- CoglContext *context = clutter_backend_get_cogl_context (backend);
- struct wl_resource *buffer = seat->sprite->buffer_ref.buffer->resource;
- CoglTexture2D *texture =
- cogl_wayland_texture_2d_new_from_buffer (context, buffer, NULL);
-
- meta_wayland_stage_set_cursor_from_texture (stage,
- COGL_TEXTURE (texture),
- seat->hotspot_x,
- seat->hotspot_y);
-
- cogl_object_unref (texture);
- }
+ meta_cursor_tracker_queue_redraw (seat->cursor_tracker,
+ CLUTTER_ACTOR (seat->current_stage));
+
+ cogl_object_unref (texture);
}
static void
diff --git a/src/wayland/meta-wayland-stage.c b/src/wayland/meta-wayland-stage.c
index c3036084d..f7d28d419 100644
--- a/src/wayland/meta-wayland-stage.c
+++ b/src/wayland/meta-wayland-stage.c
@@ -28,157 +28,33 @@
#include "meta-wayland-stage.h"
#include "meta/meta-window-actor.h"
#include "meta/meta-shaped-texture.h"
-
-#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X 7
-#define META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y 4
+#include "meta-cursor-tracker-private.h"
G_DEFINE_TYPE (MetaWaylandStage, meta_wayland_stage, CLUTTER_TYPE_STAGE);
static void
-meta_wayland_stage_finalize (GObject *object)
-{
- MetaWaylandStage *self = (MetaWaylandStage *) object;
-
- cogl_object_unref (self->default_cursor_pipeline);
- cogl_object_unref (self->texture_cursor_pipeline);
-
- G_OBJECT_CLASS (meta_wayland_stage_parent_class)->finalize (object);
-}
-
-static void
-get_cursor_draw_position (MetaWaylandStage *self,
- cairo_rectangle_int_t *rect)
-{
- rect->x = self->cursor_x - self->cursor_hotspot_x;
- rect->y = self->cursor_y - self->cursor_hotspot_y;
- rect->width = self->cursor_width;
- rect->height = self->cursor_height;
-}
-
-static void
-draw_cursor_pipeline (MetaWaylandStage *self,
- CoglPipeline *pipeline)
-{
- cairo_rectangle_int_t rect;
-
- get_cursor_draw_position (self, &rect);
-
- cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (),
- pipeline,
- rect.x, rect.y,
- rect.x + rect.width,
- rect.y + rect.height);
-
- self->has_last_cursor_position = TRUE;
- self->last_cursor_position = rect;
-}
-
-static void
meta_wayland_stage_paint (ClutterActor *actor)
{
- MetaWaylandStage *self = META_WAYLAND_STAGE (actor);
+ MetaWaylandCompositor *compositor;
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 */
-
- switch (self->cursor_type)
- {
- case META_WAYLAND_STAGE_CURSOR_INVISIBLE:
- break;
-
- case META_WAYLAND_STAGE_CURSOR_DEFAULT:
- draw_cursor_pipeline (self, self->default_cursor_pipeline);
- break;
-
- case META_WAYLAND_STAGE_CURSOR_TEXTURE:
- draw_cursor_pipeline (self, self->texture_cursor_pipeline);
- break;
- }
-}
-
-static void
-update_cursor_position (MetaWaylandStage *self)
-{
- cairo_rectangle_int_t rect;
-
- if (self->has_last_cursor_position)
- {
- clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (self),
- &self->last_cursor_position);
- self->has_last_cursor_position = FALSE;
- }
-
- get_cursor_draw_position (self, &rect);
- if (rect.width != 0 && rect.height != 0)
- clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (self), &rect);
+ compositor = meta_wayland_compositor_get_default ();
+ if (compositor->seat->cursor_tracker)
+ meta_cursor_tracker_paint (compositor->seat->cursor_tracker);
}
static void
meta_wayland_stage_class_init (MetaWaylandStageClass *klass)
{
- GObjectClass *gobject_class = (GObjectClass *) klass;
ClutterActorClass *actor_class = (ClutterActorClass *) klass;
- gobject_class->finalize = meta_wayland_stage_finalize;
-
actor_class->paint = meta_wayland_stage_paint;
}
static void
-load_default_cursor_pipeline (MetaWaylandStage *self)
-{
- CoglContext *context =
- clutter_backend_get_cogl_context (clutter_get_default_backend ());
- CoglTexture *texture;
- CoglError *error = NULL;
- char *filename;
-
- filename = g_build_filename (MUTTER_DATADIR,
- "mutter/cursors/left_ptr.png",
- NULL);
-
- texture = cogl_texture_new_from_file (filename,
- COGL_TEXTURE_NONE,
- COGL_PIXEL_FORMAT_ANY,
- &error);
-
- g_free (filename);
-
- self->default_cursor_pipeline = cogl_pipeline_new (context);
- cogl_pipeline_set_layer_filters (self->default_cursor_pipeline,
- 0, /* layer */
- COGL_PIPELINE_FILTER_NEAREST,
- COGL_PIPELINE_FILTER_NEAREST);
-
- if (texture == NULL)
- {
- g_warning ("Failed to load default cursor: %s",
- error->message);
- cogl_error_free (error);
- }
- else
- {
- self->default_cursor_width = cogl_texture_get_width (texture);
- self->default_cursor_height = cogl_texture_get_height (texture);
-
- cogl_pipeline_set_layer_texture (self->default_cursor_pipeline,
- 0, /* layer */
- texture);
- cogl_object_unref (texture);
- }
-}
-
-static void
meta_wayland_stage_init (MetaWaylandStage *self)
{
- load_default_cursor_pipeline (self);
-
- self->texture_cursor_pipeline =
- cogl_pipeline_copy (self->default_cursor_pipeline);
-
- meta_wayland_stage_set_default_cursor (self);
}
ClutterActor *
@@ -188,56 +64,3 @@ meta_wayland_stage_new (void)
"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);
-}
-
-void
-meta_wayland_stage_set_cursor_from_texture (MetaWaylandStage *self,
- CoglTexture *texture,
- int hotspot_x,
- int hotspot_y)
-{
- CoglPipeline *pipeline;
-
- self->cursor_hotspot_x = hotspot_x;
- self->cursor_hotspot_y = hotspot_y;
- self->cursor_type = META_WAYLAND_STAGE_CURSOR_TEXTURE;
-
- pipeline = cogl_pipeline_copy (self->texture_cursor_pipeline);
- cogl_pipeline_set_layer_texture (pipeline, 0, texture);
- cogl_object_unref (self->texture_cursor_pipeline);
- self->texture_cursor_pipeline = pipeline;
-
- self->cursor_width = cogl_texture_get_width (texture);
- self->cursor_height = cogl_texture_get_height (texture);
-
- update_cursor_position (self);
-}
-
-void
-meta_wayland_stage_set_invisible_cursor (MetaWaylandStage *self)
-{
- self->cursor_type = META_WAYLAND_STAGE_CURSOR_INVISIBLE;
- self->cursor_width = 0;
- self->cursor_height = 0;
- update_cursor_position (self);
-}
-
-void
-meta_wayland_stage_set_default_cursor (MetaWaylandStage *self)
-{
- self->cursor_type = META_WAYLAND_STAGE_CURSOR_DEFAULT;
- self->cursor_hotspot_x = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_X;
- self->cursor_hotspot_y = META_WAYLAND_DEFAULT_CURSOR_HOTSPOT_Y;
- self->cursor_width = self->default_cursor_width;
- self->cursor_height = self->default_cursor_height;
- update_cursor_position (self);
-}
diff --git a/src/wayland/meta-wayland-stage.h b/src/wayland/meta-wayland-stage.h
index d25f2707f..c242fbd60 100644
--- a/src/wayland/meta-wayland-stage.h
+++ b/src/wayland/meta-wayland-stage.h
@@ -59,53 +59,12 @@ struct _MetaWaylandStageClass
struct _MetaWaylandStage
{
ClutterStage parent;
-
- /* A pipeline containing the cursor texture that will be used when
- the cursor is not over a surface */
- CoglPipeline *default_cursor_pipeline;
- int default_cursor_width;
- int default_cursor_height;
-
- CoglPipeline *texture_cursor_pipeline;
-
- int cursor_x;
- int cursor_y;
- int cursor_width;
- int cursor_height;
- int cursor_hotspot_x;
- int cursor_hotspot_y;
-
- enum
- {
- /* No cursor will be drawn */
- META_WAYLAND_STAGE_CURSOR_INVISIBLE,
- /* The cursor will be drawn from our default cursor image */
- META_WAYLAND_STAGE_CURSOR_DEFAULT,
- /* The cursor will be drawn using a custom texture */
- META_WAYLAND_STAGE_CURSOR_TEXTURE
- } cursor_type;
-
- gboolean has_last_cursor_position;
- cairo_rectangle_int_t last_cursor_position;
};
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_texture (MetaWaylandStage *self,
- CoglTexture *texture,
- 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 5b62e8967..600db9368 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -43,6 +43,7 @@
#include "meta-wayland-keyboard.h"
#include "meta-wayland-pointer.h"
#include "meta-wayland-data-device.h"
+#include "meta-cursor-tracker-private.h"
#include "display-private.h"
#include "window-private.h"
#include <meta/types.h>
@@ -1290,12 +1291,17 @@ event_cb (ClutterActor *stage,
}
}
- meta_wayland_stage_set_cursor_position (META_WAYLAND_STAGE (stage),
- wl_fixed_to_int (pointer->x),
- wl_fixed_to_int (pointer->y));
+ if (seat->cursor_tracker)
+ {
+ meta_cursor_tracker_update_position (seat->cursor_tracker,
+ wl_fixed_to_int (pointer->x),
+ wl_fixed_to_int (pointer->y));
+
+ if (pointer->current == NULL)
+ meta_cursor_tracker_revert_root (seat->cursor_tracker);
- if (pointer->current == NULL)
- meta_wayland_stage_set_default_cursor (META_WAYLAND_STAGE (stage));
+ meta_cursor_tracker_queue_redraw (seat->cursor_tracker, stage);
+ }
display = meta_get_display ();
if (!display)