From 7d7e76506b8cd9c1b538f749998793ca174089e3 Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Thu, 16 Nov 2017 19:23:09 +0100
Subject: backends: Dissociate visibility from current cursor sprite

Just like X11/XFixes behaves, the current cursor is not affected
by its visibility, so it can be queried while invisible (possibly
to be replaced).

For this, keep an extra effective_cursor pointer that will be
either equal to displayed_cursor (maybe a bit of a misnomer now)
or NULL if the cursor is invisible. The MetaCursorRenderer
management is tied to the former, and the ::cursor-changed signal
emission to the latter.

https://bugzilla.gnome.org/show_bug.cgi?id=754806
---
 src/backends/meta-cursor-tracker-private.h |  1 +
 src/backends/meta-cursor-tracker.c         | 61 +++++++++++++++++++-----------
 2 files changed, 40 insertions(+), 22 deletions(-)

diff --git a/src/backends/meta-cursor-tracker-private.h b/src/backends/meta-cursor-tracker-private.h
index 3c19b43..2ec9468 100644
--- a/src/backends/meta-cursor-tracker-private.h
+++ b/src/backends/meta-cursor-tracker-private.h
@@ -32,6 +32,7 @@ struct _MetaCursorTracker {
 
   gboolean is_showing;
 
+  MetaCursorSprite *effective_cursor; /* May be NULL when hidden */
   MetaCursorSprite *displayed_cursor;
 
   /* Wayland clients can set a NULL buffer as their cursor
diff --git a/src/backends/meta-cursor-tracker.c b/src/backends/meta-cursor-tracker.c
index 59e242b..3cdab83 100644
--- a/src/backends/meta-cursor-tracker.c
+++ b/src/backends/meta-cursor-tracker.c
@@ -53,47 +53,57 @@ enum {
 
 static guint signals[LAST_SIGNAL];
 
-static MetaCursorSprite *
-get_displayed_cursor (MetaCursorTracker *tracker)
+static gboolean
+update_displayed_cursor (MetaCursorTracker *tracker)
 {
   MetaDisplay *display = meta_get_display ();
+  MetaCursorSprite *cursor = NULL;
 
-  if (!tracker->is_showing)
-    return NULL;
-
-  if (meta_display_windows_are_interactable (display))
+  if (display && meta_display_windows_are_interactable (display))
     {
       if (tracker->has_window_cursor)
-        return tracker->window_cursor;
+        cursor = tracker->window_cursor;
     }
 
-  return tracker->root_cursor;
+  if (!cursor)
+    cursor = tracker->root_cursor;
+
+  if (tracker->displayed_cursor == cursor)
+    return FALSE;
+
+  g_set_object (&tracker->displayed_cursor, cursor);
+  return TRUE;
+}
+
+static gboolean
+update_effective_cursor (MetaCursorTracker *tracker)
+{
+  MetaCursorSprite *cursor = NULL;
+
+  if (tracker->is_showing)
+    cursor = tracker->displayed_cursor;
+
+  return g_set_object (&tracker->effective_cursor, cursor);
 }
 
 static void
-update_displayed_cursor (MetaCursorTracker *tracker)
+change_cursor_renderer (MetaCursorTracker *tracker)
 {
   MetaBackend *backend = meta_get_backend ();
   MetaCursorRenderer *cursor_renderer =
     meta_backend_get_cursor_renderer (backend);
 
-  meta_cursor_renderer_set_cursor (cursor_renderer, tracker->displayed_cursor);
+  meta_cursor_renderer_set_cursor (cursor_renderer, tracker->effective_cursor);
 }
 
 static void
 sync_cursor (MetaCursorTracker *tracker)
 {
-  MetaCursorSprite *displayed_cursor = get_displayed_cursor (tracker);
-
-  if (tracker->displayed_cursor == displayed_cursor)
-    return;
-
-  g_clear_object (&tracker->displayed_cursor);
-  if (displayed_cursor)
-    tracker->displayed_cursor = g_object_ref (displayed_cursor);
+  if (update_displayed_cursor (tracker))
+    g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
 
-  update_displayed_cursor (tracker);
-  g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
+  if (update_effective_cursor (tracker))
+    change_cursor_renderer (tracker);
 }
 
 static void
@@ -107,6 +117,8 @@ meta_cursor_tracker_finalize (GObject *object)
 {
   MetaCursorTracker *self = META_CURSOR_TRACKER (object);
 
+  if (self->effective_cursor)
+    g_object_unref (self->effective_cursor);
   if (self->displayed_cursor)
     g_object_unref (self->displayed_cursor);
   if (self->root_cursor)
@@ -282,9 +294,14 @@ meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker)
     }
 
   if (cursor_sprite)
-    return meta_cursor_sprite_get_cogl_texture (cursor_sprite);
+    {
+      meta_cursor_sprite_realize_texture (cursor_sprite);
+      return meta_cursor_sprite_get_cogl_texture (cursor_sprite);
+    }
   else
-    return NULL;
+    {
+      return NULL;
+    }
 }
 
 /**
-- 
2.16.4


From 38c93bf755d7644ae1d019fab4de7d1bf2deb2d6 Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Thu, 16 Nov 2017 19:16:54 +0100
Subject: backends: Add MetaCursorSprite::texture-changed signal

As wayland implements the cursor role, it consists of a persistent
MetaCursorSprite that gets the backing texture changed. This is
inconvenient for the places using MetaCursorTracker to track cursor
changes, as they actually track MetaCursorSprites.

This signal will be used to trigger emission of
MetaCursorTracker::cursor-changed, which will make users able to
update accordingly.

https://bugzilla.gnome.org/show_bug.cgi?id=754806
---
 src/backends/meta-cursor.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/src/backends/meta-cursor.c b/src/backends/meta-cursor.c
index 256b0ca..ccd0ab0 100644
--- a/src/backends/meta-cursor.c
+++ b/src/backends/meta-cursor.c
@@ -37,6 +37,7 @@
 
 enum {
   PREPARE_AT,
+  TEXTURE_CHANGED,
 
   LAST_SIGNAL
 };
@@ -266,11 +267,18 @@ meta_cursor_sprite_set_texture (MetaCursorSprite *self,
                                 int               hot_x,
                                 int               hot_y)
 {
+  if (self->texture == COGL_TEXTURE_2D (texture) &&
+      self->hot_x == hot_x &&
+      self->hot_y == hot_y)
+    return;
+
   g_clear_pointer (&self->texture, cogl_object_unref);
   if (texture)
     self->texture = cogl_object_ref (texture);
   self->hot_x = hot_x;
   self->hot_y = hot_y;
+
+  g_signal_emit (self, signals[TEXTURE_CHANGED], 0);
 }
 
 void
@@ -365,4 +373,10 @@ meta_cursor_sprite_class_init (MetaCursorSpriteClass *klass)
                                       G_TYPE_NONE, 2,
                                       G_TYPE_INT,
                                       G_TYPE_INT);
+  signals[TEXTURE_CHANGED] = g_signal_new ("texture-changed",
+                                           G_TYPE_FROM_CLASS (object_class),
+                                           G_SIGNAL_RUN_LAST,
+                                           0,
+                                           NULL, NULL, NULL,
+                                           G_TYPE_NONE, 0);
 }
-- 
2.16.4


From c5470874ec79a02177d9d763d24056770371137b Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Thu, 16 Nov 2017 19:26:41 +0100
Subject: backends: Trigger MetaCursorTracker::cursor-changed on texture
 changes

So we allow gnome-shell's magnifier to update fake cursors while it's
turned on.

https://bugzilla.gnome.org/show_bug.cgi?id=754806
---
 src/backends/meta-cursor-tracker.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/backends/meta-cursor-tracker.c b/src/backends/meta-cursor-tracker.c
index 3cdab83..f1562a2 100644
--- a/src/backends/meta-cursor-tracker.c
+++ b/src/backends/meta-cursor-tracker.c
@@ -53,6 +53,13 @@ enum {
 
 static guint signals[LAST_SIGNAL];
 
+static void
+cursor_texture_updated (MetaCursorSprite  *cursor,
+                        MetaCursorTracker *tracker)
+{
+  g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
+}
+
 static gboolean
 update_displayed_cursor (MetaCursorTracker *tracker)
 {
@@ -71,7 +78,12 @@ update_displayed_cursor (MetaCursorTracker *tracker)
   if (tracker->displayed_cursor == cursor)
     return FALSE;
 
+  g_signal_handlers_disconnect_by_func (tracker->displayed_cursor,
+                                        cursor_texture_updated,
+                                        tracker);
   g_set_object (&tracker->displayed_cursor, cursor);
+  g_signal_connect (tracker->displayed_cursor, "texture-changed",
+                    G_CALLBACK (cursor_texture_updated), tracker);
   return TRUE;
 }
 
-- 
2.16.4


From 5bc87b11477b65f294869756e2d7e3ed9799d232 Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Fri, 17 Nov 2017 14:07:20 +0100
Subject: backends: Protect from reentrancy in
 meta_cursor_sprite_load_from_theme

This function is supposedly not failable, so just move the theme_dirty
flag clearing to the beginning of the function. Protects against cases
where requesting a cursor image may result in it being loaded and set
as a texture, which emits ::texture-changed, which may end up requesting
the cursor image again.

https://bugzilla.gnome.org/show_bug.cgi?id=754806
---
 src/backends/meta-cursor.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/backends/meta-cursor.c b/src/backends/meta-cursor.c
index ccd0ab0..beeee76 100644
--- a/src/backends/meta-cursor.c
+++ b/src/backends/meta-cursor.c
@@ -229,6 +229,8 @@ meta_cursor_sprite_load_from_theme (MetaCursorSprite *self)
 
   g_assert (self->cursor != META_CURSOR_NONE);
 
+  self->theme_dirty = FALSE;
+
   /* We might be reloading with a different scale. If so clear the old data. */
   if (self->xcursor_images)
     {
@@ -244,8 +246,6 @@ meta_cursor_sprite_load_from_theme (MetaCursorSprite *self)
 
   image = meta_cursor_sprite_get_current_frame_image (self);
   meta_cursor_sprite_load_from_xcursor_image (self, image);
-
-  self->theme_dirty = FALSE;
 }
 
 MetaCursorSprite *
-- 
2.16.4


From a32aa35e9431e654f2576ebbcf8bb70c815964b7 Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Mon, 20 Nov 2017 13:08:06 +0100
Subject: backends: Do not set up the root cursor on invisible window pointers

Commit b1a0bf891 broke the previous logic that we would only fallback
to the root cursor if 1) windows are not interactable or 2) no window
cursor is currently set (i.e. not hovering over any window). Now it
will set up the root cursor if it's NULL, which breaks clients
explicitly setting an invisible cursor. This commit restaurates the
previous behavior.

https://bugzilla.gnome.org/show_bug.cgi?id=754806
---
 src/backends/meta-cursor-tracker.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/src/backends/meta-cursor-tracker.c b/src/backends/meta-cursor-tracker.c
index f1562a2..b29a726 100644
--- a/src/backends/meta-cursor-tracker.c
+++ b/src/backends/meta-cursor-tracker.c
@@ -66,13 +66,10 @@ update_displayed_cursor (MetaCursorTracker *tracker)
   MetaDisplay *display = meta_get_display ();
   MetaCursorSprite *cursor = NULL;
 
-  if (display && meta_display_windows_are_interactable (display))
-    {
-      if (tracker->has_window_cursor)
-        cursor = tracker->window_cursor;
-    }
-
-  if (!cursor)
+  if (display && meta_display_windows_are_interactable (display) &&
+      tracker->has_window_cursor)
+    cursor = tracker->window_cursor;
+  else
     cursor = tracker->root_cursor;
 
   if (tracker->displayed_cursor == cursor)
-- 
2.16.4


From f8c5e1e78d66862ca303b10946479ef028437f1c Mon Sep 17 00:00:00 2001
From: Carlos Garnacho <carlosg@gnome.org>
Date: Mon, 20 Nov 2017 13:20:36 +0100
Subject: backends: Do NULL checks before disconnecting/connecting signals

The displayed cursor may be NULL.

https://bugzilla.gnome.org/show_bug.cgi?id=754806
---
 src/backends/meta-cursor-tracker.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/src/backends/meta-cursor-tracker.c b/src/backends/meta-cursor-tracker.c
index b29a726..74fa435 100644
--- a/src/backends/meta-cursor-tracker.c
+++ b/src/backends/meta-cursor-tracker.c
@@ -75,12 +75,21 @@ update_displayed_cursor (MetaCursorTracker *tracker)
   if (tracker->displayed_cursor == cursor)
     return FALSE;
 
-  g_signal_handlers_disconnect_by_func (tracker->displayed_cursor,
-                                        cursor_texture_updated,
-                                        tracker);
+  if (tracker->displayed_cursor)
+    {
+      g_signal_handlers_disconnect_by_func (tracker->displayed_cursor,
+                                            cursor_texture_updated,
+                                            tracker);
+    }
+
   g_set_object (&tracker->displayed_cursor, cursor);
-  g_signal_connect (tracker->displayed_cursor, "texture-changed",
-                    G_CALLBACK (cursor_texture_updated), tracker);
+
+  if (cursor)
+    {
+      g_signal_connect (cursor, "texture-changed",
+                        G_CALLBACK (cursor_texture_updated), tracker);
+    }
+
   return TRUE;
 }
 
-- 
2.16.4

