kathenas / rpms / mutter

Forked from rpms/mutter 5 years ago
Clone

Blame SOURCES/screen-cast-cursor-side-channel.patch

776610
From 5f428c5aa9f3e66cd23e4e75d54506960bd5b66c Mon Sep 17 00:00:00 2001
776610
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
776610
Date: Wed, 12 Dec 2018 11:27:16 +0100
776610
Subject: [PATCH 01/12] cursor-tracker: Add 'cursor-moved' signal
776610
776610
https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
776610
---
776610
 src/backends/meta-cursor-tracker.c | 12 ++++++++++++
776610
 1 file changed, 12 insertions(+)
776610
776610
diff --git a/src/backends/meta-cursor-tracker.c b/src/backends/meta-cursor-tracker.c
776610
index 6244f11ee..060b6af3b 100644
776610
--- a/src/backends/meta-cursor-tracker.c
776610
+++ b/src/backends/meta-cursor-tracker.c
776610
@@ -48,6 +48,7 @@ G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT);
776610
 
776610
 enum {
776610
   CURSOR_CHANGED,
776610
+  CURSOR_MOVED,
776610
   LAST_SIGNAL
776610
 };
776610
 
776610
@@ -158,6 +159,15 @@ meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass)
776610
                                           0,
776610
                                           NULL, NULL, NULL,
776610
                                           G_TYPE_NONE, 0);
776610
+
776610
+  signals[CURSOR_MOVED] = g_signal_new ("cursor-moved",
776610
+                                        G_TYPE_FROM_CLASS (klass),
776610
+                                        G_SIGNAL_RUN_LAST,
776610
+                                        0,
776610
+                                        NULL, NULL, NULL,
776610
+                                        G_TYPE_NONE, 2,
776610
+                                        G_TYPE_FLOAT,
776610
+                                        G_TYPE_FLOAT);
776610
 }
776610
 
776610
 /**
776610
@@ -334,6 +344,8 @@ meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
776610
   g_assert (meta_is_wayland_compositor ());
776610
 
776610
   meta_cursor_renderer_set_position (cursor_renderer, new_x, new_y);
776610
+
776610
+  g_signal_emit (tracker, signals[CURSOR_MOVED], 0, new_x, new_y);
776610
 }
776610
 
776610
 static void
776610
-- 
776610
2.20.1
776610
776610
776610
From 54c5034f6dcdaf382a8355460710ced47c05d91e Mon Sep 17 00:00:00 2001
776610
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
776610
Date: Fri, 21 Dec 2018 17:28:33 +0100
776610
Subject: [PATCH 02/12] clutter/stage: Add clutter_stage_is_redraw_queued() API
776610
776610
This will be used by the screen casting code to check whether it should
776610
wait for a frame before reading cursor state, or send only the cursor
776610
update, if no redraw is queued.
776610
776610
https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
776610
---
776610
 clutter/clutter/clutter-stage.c | 11 +++++++++++
776610
 clutter/clutter/clutter-stage.h |  3 +++
776610
 2 files changed, 14 insertions(+)
776610
776610
diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c
776610
index 9352f49e8..763ec96ee 100644
776610
--- a/clutter/clutter/clutter-stage.c
776610
+++ b/clutter/clutter/clutter-stage.c
776610
@@ -3722,6 +3722,17 @@ clutter_stage_ensure_redraw (ClutterStage *stage)
776610
   _clutter_master_clock_start_running (master_clock);
776610
 }
776610
 
776610
+/**
776610
+ * clutter_stage_is_redraw_queued: (skip)
776610
+ */
776610
+gboolean
776610
+clutter_stage_is_redraw_queued (ClutterStage *stage)
776610
+{
776610
+  ClutterStagePrivate *priv = stage->priv;
776610
+
776610
+  return priv->redraw_pending;
776610
+}
776610
+
776610
 /**
776610
  * clutter_stage_queue_redraw:
776610
  * @stage: the #ClutterStage
776610
diff --git a/clutter/clutter/clutter-stage.h b/clutter/clutter/clutter-stage.h
776610
index e8fbda84c..ddf08fde4 100644
776610
--- a/clutter/clutter/clutter-stage.h
776610
+++ b/clutter/clutter/clutter-stage.h
776610
@@ -250,6 +250,9 @@ void            clutter_stage_ensure_viewport                   (ClutterStage
776610
 CLUTTER_AVAILABLE_IN_ALL
776610
 void            clutter_stage_ensure_redraw                     (ClutterStage          *stage);
776610
 
776610
+CLUTTER_AVAILABLE_IN_ALL
776610
+gboolean        clutter_stage_is_redraw_queued                  (ClutterStage          *stage);
776610
+
776610
 #ifdef CLUTTER_ENABLE_EXPERIMENTAL_API
776610
 CLUTTER_AVAILABLE_IN_1_14
776610
 void            clutter_stage_set_sync_delay                    (ClutterStage          *stage,
776610
-- 
776610
2.20.1
776610
776610
776610
From 59e1c68143d9090e238198448fa400bb0776d38a Mon Sep 17 00:00:00 2001
776610
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
776610
Date: Wed, 12 Dec 2018 11:32:11 +0100
776610
Subject: [PATCH 03/12] screen-cast-monitor-stream: Don't pass monitor manager
776610
 when creating
776610
776610
It can be fetched indirectly from the monitor already.
776610
776610
https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
776610
---
776610
 src/backends/meta-screen-cast-monitor-stream.c | 11 ++++++-----
776610
 src/backends/meta-screen-cast-monitor-stream.h |  9 ++++-----
776610
 src/backends/meta-screen-cast-session.c        |  1 -
776610
 3 files changed, 10 insertions(+), 11 deletions(-)
776610
776610
diff --git a/src/backends/meta-screen-cast-monitor-stream.c b/src/backends/meta-screen-cast-monitor-stream.c
776610
index df43f977c..5a816e4df 100644
776610
--- a/src/backends/meta-screen-cast-monitor-stream.c
776610
+++ b/src/backends/meta-screen-cast-monitor-stream.c
776610
@@ -105,12 +105,13 @@ meta_screen_cast_monitor_stream_get_monitor (MetaScreenCastMonitorStream *monito
776610
 }
776610
 
776610
 MetaScreenCastMonitorStream *
776610
-meta_screen_cast_monitor_stream_new (GDBusConnection     *connection,
776610
-                                     MetaMonitorManager  *monitor_manager,
776610
-                                     MetaMonitor         *monitor,
776610
-                                     ClutterStage        *stage,
776610
-                                     GError             **error)
776610
+meta_screen_cast_monitor_stream_new (GDBusConnection  *connection,
776610
+                                     MetaMonitor      *monitor,
776610
+                                     ClutterStage     *stage,
776610
+                                     GError          **error)
776610
 {
776610
+  MetaGpu *gpu = meta_monitor_get_gpu (monitor);
776610
+  MetaMonitorManager *monitor_manager = meta_gpu_get_monitor_manager (gpu);
776610
   MetaScreenCastMonitorStream *monitor_stream;
776610
 
776610
   if (!meta_monitor_is_active (monitor))
776610
diff --git a/src/backends/meta-screen-cast-monitor-stream.h b/src/backends/meta-screen-cast-monitor-stream.h
776610
index fbf3c77c3..1d24de93a 100644
776610
--- a/src/backends/meta-screen-cast-monitor-stream.h
776610
+++ b/src/backends/meta-screen-cast-monitor-stream.h
776610
@@ -34,11 +34,10 @@ G_DECLARE_FINAL_TYPE (MetaScreenCastMonitorStream,
776610
                       META, SCREEN_CAST_MONITOR_STREAM,
776610
                       MetaScreenCastStream)
776610
 
776610
-MetaScreenCastMonitorStream * meta_screen_cast_monitor_stream_new (GDBusConnection    *connection,
776610
-								   MetaMonitorManager *monitor_manager,
776610
-                                                                   MetaMonitor        *monitor,
776610
-                                                                   ClutterStage       *stage,
776610
-                                                                   GError            **error);
776610
+MetaScreenCastMonitorStream * meta_screen_cast_monitor_stream_new (GDBusConnection  *connection,
776610
+                                                                   MetaMonitor      *monitor,
776610
+                                                                   ClutterStage     *stage,
776610
+                                                                   GError          **error);
776610
 
776610
 ClutterStage * meta_screen_cast_monitor_stream_get_stage (MetaScreenCastMonitorStream *monitor_stream);
776610
 
776610
diff --git a/src/backends/meta-screen-cast-session.c b/src/backends/meta-screen-cast-session.c
776610
index d0f5a79d9..3ba59037f 100644
776610
--- a/src/backends/meta-screen-cast-session.c
776610
+++ b/src/backends/meta-screen-cast-session.c
776610
@@ -301,7 +301,6 @@ handle_record_monitor (MetaDBusScreenCastSession *skeleton,
776610
   stage = CLUTTER_STAGE (meta_backend_get_stage (backend));
776610
 
776610
   monitor_stream = meta_screen_cast_monitor_stream_new (connection,
776610
-                                                        monitor_manager,
776610
                                                         monitor,
776610
                                                         stage,
776610
                                                         &error);
776610
-- 
776610
2.20.1
776610
776610
776610
From 45100944033987a946672fda6de309aa41a6139f Mon Sep 17 00:00:00 2001
776610
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
776610
Date: Wed, 12 Dec 2018 11:35:58 +0100
776610
Subject: [PATCH 04/12] screen-cast: Add getters to fetch object owners
776610
776610
MetaBackend owns MetaScreenCast which owns MetaScreenCastSession which
776610
owns MetaScreenCastStream. Make it possible to fetch objects in the
776610
oppositev direction too.
776610
776610
https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
776610
---
776610
 src/backends/meta-backend.c                   |  3 +-
776610
 .../meta-screen-cast-monitor-stream.c         | 10 ++++---
776610
 .../meta-screen-cast-monitor-stream.h         | 10 ++++---
776610
 src/backends/meta-screen-cast-session.c       | 15 ++++++++--
776610
 src/backends/meta-screen-cast-session.h       |  2 ++
776610
 src/backends/meta-screen-cast-stream.c        | 30 +++++++++++++++++++
776610
 src/backends/meta-screen-cast-stream.h        |  6 ++++
776610
 src/backends/meta-screen-cast-window-stream.c |  8 +++--
776610
 src/backends/meta-screen-cast-window-stream.h |  7 +++--
776610
 src/backends/meta-screen-cast.c               | 15 ++++++++--
776610
 src/backends/meta-screen-cast.h               |  6 +++-
776610
 11 files changed, 92 insertions(+), 20 deletions(-)
776610
776610
diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c
776610
index 888e51cd9..28f1cd92f 100644
776610
--- a/src/backends/meta-backend.c
776610
+++ b/src/backends/meta-backend.c
776610
@@ -456,7 +456,8 @@ meta_backend_real_post_init (MetaBackend *backend)
776610
   priv->remote_access_controller =
776610
     g_object_new (META_TYPE_REMOTE_ACCESS_CONTROLLER, NULL);
776610
   priv->dbus_session_watcher = g_object_new (META_TYPE_DBUS_SESSION_WATCHER, NULL);
776610
-  priv->screen_cast = meta_screen_cast_new (priv->dbus_session_watcher);
776610
+  priv->screen_cast = meta_screen_cast_new (backend,
776610
+                                            priv->dbus_session_watcher);
776610
   priv->remote_desktop = meta_remote_desktop_new (priv->dbus_session_watcher);
776610
 #endif /* HAVE_REMOTE_DESKTOP */
776610
 
776610
diff --git a/src/backends/meta-screen-cast-monitor-stream.c b/src/backends/meta-screen-cast-monitor-stream.c
776610
index 5a816e4df..a6bed1b52 100644
776610
--- a/src/backends/meta-screen-cast-monitor-stream.c
776610
+++ b/src/backends/meta-screen-cast-monitor-stream.c
776610
@@ -105,10 +105,11 @@ meta_screen_cast_monitor_stream_get_monitor (MetaScreenCastMonitorStream *monito
776610
 }
776610
 
776610
 MetaScreenCastMonitorStream *
776610
-meta_screen_cast_monitor_stream_new (GDBusConnection  *connection,
776610
-                                     MetaMonitor      *monitor,
776610
-                                     ClutterStage     *stage,
776610
-                                     GError          **error)
776610
+meta_screen_cast_monitor_stream_new (MetaScreenCastSession  *session,
776610
+                                     GDBusConnection        *connection,
776610
+                                     MetaMonitor            *monitor,
776610
+                                     ClutterStage           *stage,
776610
+                                     GError                **error)
776610
 {
776610
   MetaGpu *gpu = meta_monitor_get_gpu (monitor);
776610
   MetaMonitorManager *monitor_manager = meta_gpu_get_monitor_manager (gpu);
776610
@@ -123,6 +124,7 @@ meta_screen_cast_monitor_stream_new (GDBusConnection  *connection,
776610
   monitor_stream = g_initable_new (META_TYPE_SCREEN_CAST_MONITOR_STREAM,
776610
                                    NULL,
776610
                                    error,
776610
+                                   "session", session,
776610
                                    "connection", connection,
776610
                                    "monitor", monitor,
776610
                                    NULL);
776610
diff --git a/src/backends/meta-screen-cast-monitor-stream.h b/src/backends/meta-screen-cast-monitor-stream.h
776610
index 1d24de93a..98f160c88 100644
776610
--- a/src/backends/meta-screen-cast-monitor-stream.h
776610
+++ b/src/backends/meta-screen-cast-monitor-stream.h
776610
@@ -27,6 +27,7 @@
776610
 
776610
 #include "backends/meta-monitor-manager-private.h"
776610
 #include "backends/meta-screen-cast-stream.h"
776610
+#include "backends/meta-screen-cast.h"
776610
 
776610
 #define META_TYPE_SCREEN_CAST_MONITOR_STREAM (meta_screen_cast_monitor_stream_get_type ())
776610
 G_DECLARE_FINAL_TYPE (MetaScreenCastMonitorStream,
776610
@@ -34,10 +35,11 @@ G_DECLARE_FINAL_TYPE (MetaScreenCastMonitorStream,
776610
                       META, SCREEN_CAST_MONITOR_STREAM,
776610
                       MetaScreenCastStream)
776610
 
776610
-MetaScreenCastMonitorStream * meta_screen_cast_monitor_stream_new (GDBusConnection  *connection,
776610
-                                                                   MetaMonitor      *monitor,
776610
-                                                                   ClutterStage     *stage,
776610
-                                                                   GError          **error);
776610
+MetaScreenCastMonitorStream * meta_screen_cast_monitor_stream_new (MetaScreenCastSession  *session,
776610
+                                                                   GDBusConnection        *connection,
776610
+                                                                   MetaMonitor            *monitor,
776610
+                                                                   ClutterStage           *stage,
776610
+                                                                   GError                **error);
776610
 
776610
 ClutterStage * meta_screen_cast_monitor_stream_get_stage (MetaScreenCastMonitorStream *monitor_stream);
776610
 
776610
diff --git a/src/backends/meta-screen-cast-session.c b/src/backends/meta-screen-cast-session.c
776610
index 3ba59037f..6a8f2d328 100644
776610
--- a/src/backends/meta-screen-cast-session.c
776610
+++ b/src/backends/meta-screen-cast-session.c
776610
@@ -38,6 +38,8 @@ struct _MetaScreenCastSession
776610
 {
776610
   MetaDBusScreenCastSessionSkeleton parent;
776610
 
776610
+  MetaScreenCast *screen_cast;
776610
+
776610
   char *peer_name;
776610
 
776610
   MetaScreenCastSessionType session_type;
776610
@@ -159,6 +161,12 @@ meta_screen_cast_session_get_stream (MetaScreenCastSession *session,
776610
   return NULL;
776610
 }
776610
 
776610
+MetaScreenCast *
776610
+meta_screen_cast_session_get_screen_cast (MetaScreenCastSession *session)
776610
+{
776610
+  return session->screen_cast;
776610
+}
776610
+
776610
 char *
776610
 meta_screen_cast_session_get_object_path (MetaScreenCastSession *session)
776610
 {
776610
@@ -300,7 +308,8 @@ handle_record_monitor (MetaDBusScreenCastSession *skeleton,
776610
 
776610
   stage = CLUTTER_STAGE (meta_backend_get_stage (backend));
776610
 
776610
-  monitor_stream = meta_screen_cast_monitor_stream_new (connection,
776610
+  monitor_stream = meta_screen_cast_monitor_stream_new (session,
776610
+                                                        connection,
776610
                                                         monitor,
776610
                                                         stage,
776610
                                                         &error);
776610
@@ -381,7 +390,8 @@ handle_record_window (MetaDBusScreenCastSession *skeleton,
776610
   interface_skeleton = G_DBUS_INTERFACE_SKELETON (skeleton);
776610
   connection = g_dbus_interface_skeleton_get_connection (interface_skeleton);
776610
 
776610
-  window_stream = meta_screen_cast_window_stream_new (connection,
776610
+  window_stream = meta_screen_cast_window_stream_new (session,
776610
+                                                      connection,
776610
                                                       window,
776610
                                                       &error);
776610
   if (!window_stream)
776610
@@ -441,6 +451,7 @@ meta_screen_cast_session_new (MetaScreenCast             *screen_cast,
776610
   static unsigned int global_session_number = 0;
776610
 
776610
   session = g_object_new (META_TYPE_SCREEN_CAST_SESSION, NULL);
776610
+  session->screen_cast = screen_cast;
776610
   session->session_type = session_type;
776610
   session->peer_name = g_strdup (peer_name);
776610
   session->object_path =
776610
diff --git a/src/backends/meta-screen-cast-session.h b/src/backends/meta-screen-cast-session.h
776610
index ac0a31a16..105a65098 100644
776610
--- a/src/backends/meta-screen-cast-session.h
776610
+++ b/src/backends/meta-screen-cast-session.h
776610
@@ -60,4 +60,6 @@ void meta_screen_cast_session_close (MetaScreenCastSession *session);
776610
 MetaScreenCastStream * meta_screen_cast_session_get_stream (MetaScreenCastSession *session,
776610
                                                             const char            *path);
776610
 
776610
+MetaScreenCast * meta_screen_cast_session_get_screen_cast (MetaScreenCastSession *session);
776610
+
776610
 #endif /* META_SCREEN_CAST_SESSION_H */
776610
diff --git a/src/backends/meta-screen-cast-stream.c b/src/backends/meta-screen-cast-stream.c
776610
index 97ee4bfcf..875ada01a 100644
776610
--- a/src/backends/meta-screen-cast-stream.c
776610
+++ b/src/backends/meta-screen-cast-stream.c
776610
@@ -24,12 +24,15 @@
776610
 
776610
 #include "backends/meta-screen-cast-stream.h"
776610
 
776610
+#include "backends/meta-screen-cast-session.h"
776610
+
776610
 #define META_SCREEN_CAST_STREAM_DBUS_PATH "/org/gnome/Mutter/ScreenCast/Stream"
776610
 
776610
 enum
776610
 {
776610
   PROP_0,
776610
 
776610
+  PROP_SESSION,
776610
   PROP_CONNECTION,
776610
 };
776610
 
776610
@@ -44,6 +47,8 @@ static guint signals[N_SIGNALS];
776610
 
776610
 typedef struct _MetaScreenCastStreamPrivate
776610
 {
776610
+  MetaScreenCastSession *session;
776610
+
776610
   GDBusConnection *connection;
776610
   char *object_path;
776610
 
776610
@@ -97,6 +102,15 @@ on_stream_src_ready (MetaScreenCastStreamSrc *src,
776610
   meta_dbus_screen_cast_stream_emit_pipewire_stream_added (skeleton, node_id);
776610
 }
776610
 
776610
+MetaScreenCastSession *
776610
+meta_screen_cast_stream_get_session (MetaScreenCastStream *stream)
776610
+{
776610
+  MetaScreenCastStreamPrivate *priv =
776610
+    meta_screen_cast_stream_get_instance_private (stream);
776610
+
776610
+  return priv->session;
776610
+}
776610
+
776610
 gboolean
776610
 meta_screen_cast_stream_start (MetaScreenCastStream  *stream,
776610
                                GError               **error)
776610
@@ -162,6 +176,9 @@ meta_screen_cast_stream_set_property (GObject      *object,
776610
 
776610
   switch (prop_id)
776610
     {
776610
+    case PROP_SESSION:
776610
+      priv->session = g_value_get_object (value);
776610
+      break;
776610
     case PROP_CONNECTION:
776610
       priv->connection = g_value_get_object (value);
776610
       break;
776610
@@ -182,6 +199,9 @@ meta_screen_cast_stream_get_property (GObject    *object,
776610
 
776610
   switch (prop_id)
776610
     {
776610
+    case PROP_SESSION:
776610
+      g_value_set_object (value, priv->session);
776610
+      break;
776610
     case PROP_CONNECTION:
776610
       g_value_set_object (value, priv->connection);
776610
       break;
776610
@@ -256,6 +276,16 @@ meta_screen_cast_stream_class_init (MetaScreenCastStreamClass *klass)
776610
   object_class->set_property = meta_screen_cast_stream_set_property;
776610
   object_class->get_property = meta_screen_cast_stream_get_property;
776610
 
776610
+  g_object_class_install_property (object_class,
776610
+                                   PROP_SESSION,
776610
+                                   g_param_spec_object ("session",
776610
+                                                        "session",
776610
+                                                        "MetaScreenSession",
776610
+                                                        META_TYPE_SCREEN_CAST_SESSION,
776610
+                                                        G_PARAM_READWRITE |
776610
+                                                        G_PARAM_CONSTRUCT_ONLY |
776610
+                                                        G_PARAM_STATIC_STRINGS));
776610
+
776610
   g_object_class_install_property (object_class,
776610
                                    PROP_CONNECTION,
776610
                                    g_param_spec_object ("connection",
776610
diff --git a/src/backends/meta-screen-cast-stream.h b/src/backends/meta-screen-cast-stream.h
776610
index fd7930c4c..dcc280da6 100644
776610
--- a/src/backends/meta-screen-cast-stream.h
776610
+++ b/src/backends/meta-screen-cast-stream.h
776610
@@ -26,8 +26,12 @@
776610
 #include <glib-object.h>
776610
 
776610
 #include "backends/meta-screen-cast-stream-src.h"
776610
+#include "backends/meta-screen-cast.h"
776610
+
776610
 #include "meta-dbus-screen-cast.h"
776610
 
776610
+typedef struct _MetaScreenCastSession MetaScreenCastSession;
776610
+
776610
 #define META_TYPE_SCREEN_CAST_STREAM (meta_screen_cast_stream_get_type ())
776610
 G_DECLARE_DERIVABLE_TYPE (MetaScreenCastStream, meta_screen_cast_stream,
776610
                           META, SCREEN_CAST_STREAM,
776610
@@ -48,6 +52,8 @@ struct _MetaScreenCastStreamClass
776610
                                double               *y);
776610
 };
776610
 
776610
+MetaScreenCastSession * meta_screen_cast_stream_get_session (MetaScreenCastStream *stream);
776610
+
776610
 gboolean meta_screen_cast_stream_start (MetaScreenCastStream *stream,
776610
                                         GError              **error);
776610
 
776610
diff --git a/src/backends/meta-screen-cast-window-stream.c b/src/backends/meta-screen-cast-window-stream.c
776610
index 1200a39ef..4c9227116 100644
776610
--- a/src/backends/meta-screen-cast-window-stream.c
776610
+++ b/src/backends/meta-screen-cast-window-stream.c
776610
@@ -71,9 +71,10 @@ meta_screen_cast_window_stream_get_height (MetaScreenCastWindowStream *window_st
776610
 }
776610
 
776610
 MetaScreenCastWindowStream *
776610
-meta_screen_cast_window_stream_new (GDBusConnection  *connection,
776610
-                                    MetaWindow       *window,
776610
-                                    GError          **error)
776610
+meta_screen_cast_window_stream_new (MetaScreenCastSession  *session,
776610
+                                    GDBusConnection        *connection,
776610
+                                    MetaWindow             *window,
776610
+                                    GError                **error)
776610
 {
776610
   MetaScreenCastWindowStream *window_stream;
776610
   MetaLogicalMonitor *logical_monitor;
776610
@@ -90,6 +91,7 @@ meta_screen_cast_window_stream_new (GDBusConnection  *connection,
776610
   window_stream = g_initable_new (META_TYPE_SCREEN_CAST_WINDOW_STREAM,
776610
                                   NULL,
776610
                                   error,
776610
+                                  "session", session,
776610
                                   "connection", connection,
776610
                                   "window", window,
776610
                                   NULL);
776610
diff --git a/src/backends/meta-screen-cast-window-stream.h b/src/backends/meta-screen-cast-window-stream.h
776610
index 6726ef873..3799be98a 100644
776610
--- a/src/backends/meta-screen-cast-window-stream.h
776610
+++ b/src/backends/meta-screen-cast-window-stream.h
776610
@@ -32,9 +32,10 @@ G_DECLARE_FINAL_TYPE (MetaScreenCastWindowStream,
776610
                       META, SCREEN_CAST_WINDOW_STREAM,
776610
                       MetaScreenCastStream)
776610
 
776610
-MetaScreenCastWindowStream * meta_screen_cast_window_stream_new (GDBusConnection  *connection,
776610
-                                                                 MetaWindow       *window,
776610
-                                                                 GError          **error);
776610
+MetaScreenCastWindowStream * meta_screen_cast_window_stream_new (MetaScreenCastSession  *session,
776610
+                                                                 GDBusConnection        *connection,
776610
+                                                                 MetaWindow             *window,
776610
+                                                                 GError                **error);
776610
 
776610
 MetaWindow  * meta_screen_cast_window_stream_get_window (MetaScreenCastWindowStream *window_stream);
776610
 int           meta_screen_cast_window_stream_get_width  (MetaScreenCastWindowStream *window_stream);
776610
diff --git a/src/backends/meta-screen-cast.c b/src/backends/meta-screen-cast.c
776610
index 4a67683e7..ceea9cbe1 100644
776610
--- a/src/backends/meta-screen-cast.c
776610
+++ b/src/backends/meta-screen-cast.c
776610
@@ -43,6 +43,7 @@ struct _MetaScreenCast
776610
   GList *sessions;
776610
 
776610
   MetaDbusSessionWatcher *session_watcher;
776610
+  MetaBackend *backend;
776610
 };
776610
 
776610
 static void
776610
@@ -62,12 +63,20 @@ meta_screen_cast_get_connection (MetaScreenCast *screen_cast)
776610
   return g_dbus_interface_skeleton_get_connection (interface_skeleton);
776610
 }
776610
 
776610
+MetaBackend *
776610
+meta_screen_cast_get_backend (MetaScreenCast *screen_cast)
776610
+{
776610
+  return screen_cast->backend;
776610
+}
776610
+
776610
 static gboolean
776610
 register_remote_desktop_screen_cast_session (MetaScreenCastSession  *session,
776610
                                              const char             *remote_desktop_session_id,
776610
                                              GError                **error)
776610
 {
776610
-  MetaBackend *backend = meta_get_backend ();
776610
+  MetaScreenCast *screen_cast =
776610
+    meta_screen_cast_session_get_screen_cast (session);
776610
+  MetaBackend *backend = meta_screen_cast_get_backend (screen_cast);
776610
   MetaRemoteDesktop *remote_desktop = meta_backend_get_remote_desktop (backend);
776610
   MetaRemoteDesktopSession *remote_desktop_session;
776610
 
776610
@@ -244,11 +253,13 @@ meta_screen_cast_finalize (GObject *object)
776610
 }
776610
 
776610
 MetaScreenCast *
776610
-meta_screen_cast_new (MetaDbusSessionWatcher *session_watcher)
776610
+meta_screen_cast_new (MetaBackend            *backend,
776610
+                      MetaDbusSessionWatcher *session_watcher)
776610
 {
776610
   MetaScreenCast *screen_cast;
776610
 
776610
   screen_cast = g_object_new (META_TYPE_SCREEN_CAST, NULL);
776610
+  screen_cast->backend = backend;
776610
   screen_cast->session_watcher = session_watcher;
776610
 
776610
   return screen_cast;
776610
diff --git a/src/backends/meta-screen-cast.h b/src/backends/meta-screen-cast.h
776610
index a4fb8dd45..7e32b67b7 100644
776610
--- a/src/backends/meta-screen-cast.h
776610
+++ b/src/backends/meta-screen-cast.h
776610
@@ -25,6 +25,7 @@
776610
 
776610
 #include <glib-object.h>
776610
 
776610
+#include "backends/meta-backend-private.h"
776610
 #include "backends/meta-dbus-session-watcher.h"
776610
 #include "meta-dbus-screen-cast.h"
776610
 
776610
@@ -35,6 +36,9 @@ G_DECLARE_FINAL_TYPE (MetaScreenCast, meta_screen_cast,
776610
 
776610
 GDBusConnection * meta_screen_cast_get_connection (MetaScreenCast *screen_cast);
776610
 
776610
-MetaScreenCast * meta_screen_cast_new (MetaDbusSessionWatcher *session_watcher);
776610
+MetaBackend * meta_screen_cast_get_backend (MetaScreenCast *screen_cast);
776610
+
776610
+MetaScreenCast * meta_screen_cast_new (MetaBackend            *backend,
776610
+                                       MetaDbusSessionWatcher *session_watcher);
776610
 
776610
 #endif /* META_SCREEN_CAST_H */
776610
-- 
776610
2.20.1
776610
776610
776610
From 0bda3f694c9ea14239dd002856302e7d3007ae1c Mon Sep 17 00:00:00 2001
776610
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
776610
Date: Wed, 12 Dec 2018 11:37:13 +0100
776610
Subject: [PATCH 05/12] renderer: Add API to get view from logical monitor
776610
776610
Will be used to get the view scale for a logical monitor, which is
776610
necessary for passing cursor sprites via PipeWire.
776610
776610
https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
776610
---
776610
 src/backends/meta-renderer.c | 18 ++++++++++++++++++
776610
 src/backends/meta-renderer.h |  3 +++
776610
 2 files changed, 21 insertions(+)
776610
776610
diff --git a/src/backends/meta-renderer.c b/src/backends/meta-renderer.c
776610
index ceac7df57..ea93dc99e 100644
776610
--- a/src/backends/meta-renderer.c
776610
+++ b/src/backends/meta-renderer.c
776610
@@ -94,6 +94,24 @@ meta_renderer_get_views (MetaRenderer *renderer)
776610
   return priv->views;
776610
 }
776610
 
776610
+MetaRendererView *
776610
+meta_renderer_get_view_from_logical_monitor (MetaRenderer       *renderer,
776610
+                                             MetaLogicalMonitor *logical_monitor)
776610
+{
776610
+  GList *l;
776610
+
776610
+  for (l = meta_renderer_get_views (renderer); l; l = l->next)
776610
+    {
776610
+      MetaRendererView *view = l->data;
776610
+
776610
+      if (meta_renderer_view_get_logical_monitor (view) ==
776610
+          logical_monitor)
776610
+        return view;
776610
+    }
776610
+
776610
+  return NULL;
776610
+}
776610
+
776610
 static void
776610
 meta_renderer_finalize (GObject *object)
776610
 {
776610
diff --git a/src/backends/meta-renderer.h b/src/backends/meta-renderer.h
776610
index bf51b51ab..1c617214b 100644
776610
--- a/src/backends/meta-renderer.h
776610
+++ b/src/backends/meta-renderer.h
776610
@@ -53,4 +53,7 @@ void meta_renderer_set_legacy_view (MetaRenderer     *renderer,
776610
 
776610
 GList * meta_renderer_get_views (MetaRenderer *renderer);
776610
 
776610
+MetaRendererView * meta_renderer_get_view_from_logical_monitor (MetaRenderer       *renderer,
776610
+                                                                MetaLogicalMonitor *logical_monitor);
776610
+
776610
 #endif /* META_RENDERER_H */
776610
-- 
776610
2.20.1
776610
776610
776610
From 1a928d060cccd344004a06dacc008ae0654e8f3e Mon Sep 17 00:00:00 2001
776610
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
776610
Date: Wed, 12 Dec 2018 11:39:00 +0100
776610
Subject: [PATCH 06/12] backends/stage: Fix minor style issue
776610
776610
https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
776610
---
776610
 src/backends/meta-stage.c | 3 ++-
776610
 1 file changed, 2 insertions(+), 1 deletion(-)
776610
776610
diff --git a/src/backends/meta-stage.c b/src/backends/meta-stage.c
776610
index 73ca70118..d1b7185e8 100644
776610
--- a/src/backends/meta-stage.c
776610
+++ b/src/backends/meta-stage.c
776610
@@ -30,7 +30,8 @@
776610
 #include "backends/meta-backend-private.h"
776610
 #include "clutter/clutter-mutter.h"
776610
 
776610
-struct _MetaOverlay {
776610
+struct _MetaOverlay
776610
+{
776610
   gboolean enabled;
776610
 
776610
   CoglPipeline *pipeline;
776610
-- 
776610
2.20.1
776610
776610
776610
From 44655d12468c26bf6949e4b5137d324f9ec3b651 Mon Sep 17 00:00:00 2001
776610
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
776610
Date: Wed, 12 Dec 2018 11:39:18 +0100
776610
Subject: [PATCH 07/12] backends/stage: Emit signal between painting actors and
776610
 overlays
776610
776610
Will be used by screen casting for embedding the cursor separately, or
776610
not including at all.
776610
776610
https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
776610
---
776610
 src/backends/meta-stage.c | 18 ++++++++++++++++++
776610
 1 file changed, 18 insertions(+)
776610
776610
diff --git a/src/backends/meta-stage.c b/src/backends/meta-stage.c
776610
index d1b7185e8..4ed56c04b 100644
776610
--- a/src/backends/meta-stage.c
776610
+++ b/src/backends/meta-stage.c
776610
@@ -30,6 +30,15 @@
776610
 #include "backends/meta-backend-private.h"
776610
 #include "clutter/clutter-mutter.h"
776610
 
776610
+enum
776610
+{
776610
+  ACTORS_PAINTED,
776610
+
776610
+  N_SIGNALS
776610
+};
776610
+
776610
+static guint signals[N_SIGNALS];
776610
+
776610
 struct _MetaOverlay
776610
 {
776610
   gboolean enabled;
776610
@@ -141,6 +150,8 @@ meta_stage_paint (ClutterActor *actor)
776610
 
776610
   CLUTTER_ACTOR_CLASS (meta_stage_parent_class)->paint (actor);
776610
 
776610
+  g_signal_emit (stage, signals[ACTORS_PAINTED], 0);
776610
+
776610
   for (l = priv->overlays; l; l = l->next)
776610
     meta_overlay_paint (l->data);
776610
 }
776610
@@ -180,6 +191,13 @@ meta_stage_class_init (MetaStageClass *klass)
776610
 
776610
   stage_class->activate = meta_stage_activate;
776610
   stage_class->deactivate = meta_stage_deactivate;
776610
+
776610
+  signals[ACTORS_PAINTED] = g_signal_new ("actors-painted",
776610
+                                          G_TYPE_FROM_CLASS (klass),
776610
+                                          G_SIGNAL_RUN_LAST,
776610
+                                          0,
776610
+                                          NULL, NULL, NULL,
776610
+                                          G_TYPE_NONE, 0);
776610
 }
776610
 
776610
 static void
776610
-- 
776610
2.20.1
776610
776610
776610
From 6afa7372f3c8104fb5670130b1cd54980e9b6446 Mon Sep 17 00:00:00 2001
776610
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
776610
Date: Wed, 12 Dec 2018 15:29:21 +0100
776610
Subject: [PATCH 08/12] screen-cast/monitor-stream-src: Copy content before
776610
 cursor is drawn
776610
776610
To get a consistent behaviour no matter whether HW cursors are in use or
776610
not, make sure to copy the framebuffer content before the stage overlays
776610
(cursor sprite textures) are painted.
776610
776610
https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
776610
---
776610
 src/backends/meta-screen-cast-monitor-stream-src.c | 10 +++++-----
776610
 1 file changed, 5 insertions(+), 5 deletions(-)
776610
776610
diff --git a/src/backends/meta-screen-cast-monitor-stream-src.c b/src/backends/meta-screen-cast-monitor-stream-src.c
776610
index 382d7d4a2..b240744a8 100644
776610
--- a/src/backends/meta-screen-cast-monitor-stream-src.c
776610
+++ b/src/backends/meta-screen-cast-monitor-stream-src.c
776610
@@ -35,7 +35,7 @@ struct _MetaScreenCastMonitorStreamSrc
776610
 {
776610
   MetaScreenCastStreamSrc parent;
776610
 
776610
-  gulong stage_painted_handler_id;
776610
+  gulong actors_painted_handler_id;
776610
 };
776610
 
776610
 G_DEFINE_TYPE (MetaScreenCastMonitorStreamSrc,
776610
@@ -110,8 +110,8 @@ meta_screen_cast_monitor_stream_src_enable (MetaScreenCastStreamSrc *src)
776610
   ClutterStage *stage;
776610
 
776610
   stage = get_stage (monitor_src);
776610
-  monitor_src->stage_painted_handler_id =
776610
-    g_signal_connect_after (stage, "paint",
776610
+  monitor_src->actors_painted_handler_id =
776610
+    g_signal_connect_after (stage, "actors-painted",
776610
                             G_CALLBACK (stage_painted),
776610
                             monitor_src);
776610
   clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
776610
@@ -125,8 +125,8 @@ meta_screen_cast_monitor_stream_src_disable (MetaScreenCastStreamSrc *src)
776610
   ClutterStage *stage;
776610
 
776610
   stage = get_stage (monitor_src);
776610
-  g_signal_handler_disconnect (stage, monitor_src->stage_painted_handler_id);
776610
-  monitor_src->stage_painted_handler_id = 0;
776610
+  g_signal_handler_disconnect (stage, monitor_src->actors_painted_handler_id);
776610
+  monitor_src->actors_painted_handler_id = 0;
776610
 }
776610
 
776610
 static void
776610
-- 
776610
2.20.1
776610
776610
776610
From 2e03a842ce2447f9d070a410d1a80c2e77b480a5 Mon Sep 17 00:00:00 2001
776610
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
776610
Date: Thu, 13 Sep 2018 11:28:51 +0200
776610
Subject: [PATCH 09/12] cursor-renderer: Add API to allow inhibiting HW cursor
776610
776610
There may be reasons to temporarly inhibit the HW cursor under certain
776610
circumstances. Allow adding such inhibitations by adding API to the
776610
cursor renderer to allow API users to add generic inhibitors with
776610
whatever logic is deemed necessary.
776610
776610
https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
776610
---
776610
 src/backends/meta-cursor-renderer.c           | 62 +++++++++++++++++++
776610
 src/backends/meta-cursor-renderer.h           | 21 +++++++
776610
 .../native/meta-cursor-renderer-native.c      |  4 ++
776610
 3 files changed, 87 insertions(+)
776610
776610
diff --git a/src/backends/meta-cursor-renderer.c b/src/backends/meta-cursor-renderer.c
776610
index eb79737f1..0a456bee6 100644
776610
--- a/src/backends/meta-cursor-renderer.c
776610
+++ b/src/backends/meta-cursor-renderer.c
776610
@@ -35,6 +35,9 @@
776610
 
776610
 #include "meta-stage-private.h"
776610
 
776610
+G_DEFINE_INTERFACE (MetaHwCursorInhibitor, meta_hw_cursor_inhibitor,
776610
+                    G_TYPE_OBJECT)
776610
+
776610
 struct _MetaCursorRendererPrivate
776610
 {
776610
   float current_x;
776610
@@ -44,6 +47,8 @@ struct _MetaCursorRendererPrivate
776610
   MetaOverlay *stage_overlay;
776610
   gboolean handled_by_backend;
776610
   guint post_paint_func_id;
776610
+
776610
+  GList *hw_cursor_inhibitors;
776610
 };
776610
 typedef struct _MetaCursorRendererPrivate MetaCursorRendererPrivate;
776610
 
776610
@@ -55,6 +60,21 @@ static guint signals[LAST_SIGNAL];
776610
 
776610
 G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRenderer, meta_cursor_renderer, G_TYPE_OBJECT);
776610
 
776610
+static gboolean
776610
+meta_hw_cursor_inhibitor_is_cursor_sprite_inhibited (MetaHwCursorInhibitor *inhibitor,
776610
+                                                     MetaCursorSprite      *cursor_sprite)
776610
+{
776610
+  MetaHwCursorInhibitorInterface *iface =
776610
+    META_HW_CURSOR_INHIBITOR_GET_IFACE (inhibitor);
776610
+
776610
+  return iface->is_cursor_sprite_inhibited (inhibitor, cursor_sprite);
776610
+}
776610
+
776610
+static void
776610
+meta_hw_cursor_inhibitor_default_init (MetaHwCursorInhibitorInterface *iface)
776610
+{
776610
+}
776610
+
776610
 void
776610
 meta_cursor_renderer_emit_painted (MetaCursorRenderer *renderer,
776610
                                    MetaCursorSprite   *cursor_sprite)
776610
@@ -283,3 +303,45 @@ meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer)
776610
 
776610
   return priv->displayed_cursor;
776610
 }
776610
+
776610
+void
776610
+meta_cursor_renderer_add_hw_cursor_inhibitor (MetaCursorRenderer    *renderer,
776610
+                                              MetaHwCursorInhibitor *inhibitor)
776610
+{
776610
+  MetaCursorRendererPrivate *priv =
776610
+    meta_cursor_renderer_get_instance_private (renderer);
776610
+
776610
+  priv->hw_cursor_inhibitors = g_list_prepend (priv->hw_cursor_inhibitors,
776610
+                                               inhibitor);
776610
+}
776610
+
776610
+void
776610
+meta_cursor_renderer_remove_hw_cursor_inhibitor (MetaCursorRenderer    *renderer,
776610
+                                                 MetaHwCursorInhibitor *inhibitor)
776610
+{
776610
+  MetaCursorRendererPrivate *priv =
776610
+    meta_cursor_renderer_get_instance_private (renderer);
776610
+
776610
+  priv->hw_cursor_inhibitors = g_list_remove (priv->hw_cursor_inhibitors,
776610
+                                              inhibitor);
776610
+}
776610
+
776610
+gboolean
776610
+meta_cursor_renderer_is_hw_cursors_inhibited (MetaCursorRenderer *renderer,
776610
+                                              MetaCursorSprite   *cursor_sprite)
776610
+{
776610
+  MetaCursorRendererPrivate *priv =
776610
+    meta_cursor_renderer_get_instance_private (renderer);
776610
+  GList *l;
776610
+
776610
+  for (l = priv->hw_cursor_inhibitors; l; l = l->next)
776610
+    {
776610
+      MetaHwCursorInhibitor *inhibitor = l->data;
776610
+
776610
+      if (meta_hw_cursor_inhibitor_is_cursor_sprite_inhibited (inhibitor,
776610
+                                                               cursor_sprite))
776610
+        return TRUE;
776610
+    }
776610
+
776610
+  return FALSE;
776610
+}
776610
diff --git a/src/backends/meta-cursor-renderer.h b/src/backends/meta-cursor-renderer.h
776610
index 830d16ef6..092f17f1e 100644
776610
--- a/src/backends/meta-cursor-renderer.h
776610
+++ b/src/backends/meta-cursor-renderer.h
776610
@@ -30,6 +30,18 @@
776610
 #include <meta/screen.h>
776610
 #include "meta-cursor.h"
776610
 
776610
+#define META_TYPE_HW_CURSOR_INHIBITOR (meta_hw_cursor_inhibitor_get_type ())
776610
+G_DECLARE_INTERFACE (MetaHwCursorInhibitor, meta_hw_cursor_inhibitor,
776610
+                     META, HW_CURSOR_INHIBITOR, GObject)
776610
+
776610
+struct _MetaHwCursorInhibitorInterface
776610
+{
776610
+  GTypeInterface parent_iface;
776610
+
776610
+  gboolean (* is_cursor_sprite_inhibited) (MetaHwCursorInhibitor *inhibitor,
776610
+                                           MetaCursorSprite      *cursor_sprite);
776610
+};
776610
+
776610
 #define META_TYPE_CURSOR_RENDERER (meta_cursor_renderer_get_type ())
776610
 G_DECLARE_DERIVABLE_TYPE (MetaCursorRenderer, meta_cursor_renderer,
776610
                           META, CURSOR_RENDERER, GObject);
776610
@@ -55,6 +67,15 @@ void meta_cursor_renderer_force_update (MetaCursorRenderer *renderer);
776610
 
776610
 MetaCursorSprite * meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer);
776610
 
776610
+void meta_cursor_renderer_add_hw_cursor_inhibitor (MetaCursorRenderer    *renderer,
776610
+                                                   MetaHwCursorInhibitor *inhibitor);
776610
+
776610
+void meta_cursor_renderer_remove_hw_cursor_inhibitor (MetaCursorRenderer    *renderer,
776610
+                                                      MetaHwCursorInhibitor *inhibitor);
776610
+
776610
+gboolean meta_cursor_renderer_is_hw_cursors_inhibited (MetaCursorRenderer *renderer,
776610
+                                                       MetaCursorSprite   *cursor_sprite);
776610
+
776610
 ClutterRect meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer,
776610
                                                  MetaCursorSprite   *cursor_sprite);
776610
 
776610
diff --git a/src/backends/native/meta-cursor-renderer-native.c b/src/backends/native/meta-cursor-renderer-native.c
776610
index 29800953b..3ff4e81fb 100644
776610
--- a/src/backends/native/meta-cursor-renderer-native.c
776610
+++ b/src/backends/native/meta-cursor-renderer-native.c
776610
@@ -587,6 +587,10 @@ should_have_hw_cursor (MetaCursorRenderer *renderer,
776610
   if (!cursor_sprite)
776610
     return FALSE;
776610
 
776610
+  if (meta_cursor_renderer_is_hw_cursors_inhibited (renderer,
776610
+                                                    cursor_sprite))
776610
+    return FALSE;
776610
+
776610
   for (l = gpus; l; l = l->next)
776610
     {
776610
       MetaGpuKms *gpu_kms = l->data;
776610
-- 
776610
2.20.1
776610
776610
776610
From 65eaf0c6a12ca48fc92fbe4492726cd145549924 Mon Sep 17 00:00:00 2001
776610
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
776610
Date: Fri, 14 Dec 2018 17:47:57 +0100
776610
Subject: [PATCH 10/12] screen-cast: Add 'cursor-mode' to allow decoupled
776610
 cursor updates
776610
776610
The 'cursor-mode', which currently is limited to RecordMonitor(), allows
776610
the user to either do screen casts where the cursor is hidden, embedded
776610
in the framebuffer, or sent as PipeWire stream metadata.
776610
776610
The latter allows the user to get cursor updates sent, including the
776610
cursor sprite, without requiring a stage paint each frame. Currently
776610
this is done by using the cursor sprite texture, and either reading
776610
directly from, or drawing to an offscreen framebuffer which is read from
776610
instead, in case the texture is scaled.
776610
776610
https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
776610
---
776610
 configure.ac                                  |   2 +-
776610
 .../meta-screen-cast-monitor-stream-src.c     | 416 +++++++++++++++++-
776610
 .../meta-screen-cast-monitor-stream.c         |  12 +-
776610
 .../meta-screen-cast-monitor-stream.h         |  11 +-
776610
 src/backends/meta-screen-cast-session.c       |  31 ++
776610
 src/backends/meta-screen-cast-stream-src.c    | 128 ++++--
776610
 src/backends/meta-screen-cast-stream-src.h    |  24 +-
776610
 src/backends/meta-screen-cast-stream.c        |  30 ++
776610
 src/backends/meta-screen-cast-stream.h        |   2 +
776610
 .../meta-screen-cast-window-stream-src.c      |   4 +-
776610
 src/backends/meta-screen-cast.h               |   7 +
776610
 src/org.gnome.Mutter.ScreenCast.xml           |  12 +-
776610
 12 files changed, 622 insertions(+), 57 deletions(-)
776610
776610
diff --git a/configure.ac b/configure.ac
776610
index 2aa9c4352..449f3d693 100644
776610
--- a/configure.ac
776610
+++ b/configure.ac
776610
@@ -245,7 +245,7 @@ AC_ARG_ENABLE(remote-desktop,
776610
   enable_remote_desktop=no
776610
 )
776610
 AS_IF([test "$enable_remote_desktop" = "yes"], [
776610
-  MUTTER_PC_MODULES="$MUTTER_PC_MODULES libpipewire-0.2 >= 0.2.2"
776610
+  MUTTER_PC_MODULES="$MUTTER_PC_MODULES libpipewire-0.2 >= 0.2.5"
776610
   AC_DEFINE([HAVE_REMOTE_DESKTOP],[1], [Defined if screen cast and remote desktop support is enabled])
776610
 ])
776610
 AM_CONDITIONAL([HAVE_REMOTE_DESKTOP],[test "$enable_remote_desktop" = "yes"])
776610
diff --git a/src/backends/meta-screen-cast-monitor-stream-src.c b/src/backends/meta-screen-cast-monitor-stream-src.c
776610
index b240744a8..6be477989 100644
776610
--- a/src/backends/meta-screen-cast-monitor-stream-src.c
776610
+++ b/src/backends/meta-screen-cast-monitor-stream-src.c
776610
@@ -24,23 +24,36 @@
776610
 
776610
 #include "backends/meta-screen-cast-monitor-stream-src.h"
776610
 
776610
+#include <spa/buffer/meta.h>
776610
+
776610
 #include "backends/meta-backend-private.h"
776610
+#include "backends/meta-cursor-tracker-private.h"
776610
 #include "backends/meta-screen-cast-monitor-stream.h"
776610
+#include "backends/meta-screen-cast-session.h"
776610
 #include "backends/meta-logical-monitor.h"
776610
 #include "backends/meta-monitor.h"
776610
 #include "clutter/clutter.h"
776610
 #include "clutter/clutter-mutter.h"
776610
+#include "core/boxes-private.h"
776610
 
776610
 struct _MetaScreenCastMonitorStreamSrc
776610
 {
776610
   MetaScreenCastStreamSrc parent;
776610
 
776610
   gulong actors_painted_handler_id;
776610
+  gulong paint_handler_id;
776610
+  gulong cursor_moved_handler_id;
776610
+  gulong cursor_changed_handler_id;
776610
 };
776610
 
776610
-G_DEFINE_TYPE (MetaScreenCastMonitorStreamSrc,
776610
-               meta_screen_cast_monitor_stream_src,
776610
-               META_TYPE_SCREEN_CAST_STREAM_SRC)
776610
+static void
776610
+hw_cursor_inhibitor_iface_init (MetaHwCursorInhibitorInterface *iface);
776610
+
776610
+G_DEFINE_TYPE_WITH_CODE (MetaScreenCastMonitorStreamSrc,
776610
+                         meta_screen_cast_monitor_stream_src,
776610
+                         META_TYPE_SCREEN_CAST_STREAM_SRC,
776610
+                         G_IMPLEMENT_INTERFACE (META_TYPE_HW_CURSOR_INHIBITOR,
776610
+                                                hw_cursor_inhibitor_iface_init))
776610
 
776610
 static ClutterStage *
776610
 get_stage (MetaScreenCastMonitorStreamSrc *monitor_src)
776610
@@ -102,18 +115,163 @@ stage_painted (ClutterActor                   *actor,
776610
   meta_screen_cast_stream_src_maybe_record_frame (src);
776610
 }
776610
 
776610
+static MetaBackend *
776610
+get_backend (MetaScreenCastMonitorStreamSrc *monitor_src)
776610
+{
776610
+  MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (monitor_src);
776610
+  MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src);
776610
+  MetaScreenCastSession *session = meta_screen_cast_stream_get_session (stream);
776610
+  MetaScreenCast *screen_cast =
776610
+    meta_screen_cast_session_get_screen_cast (session);
776610
+
776610
+  return meta_screen_cast_get_backend (screen_cast);
776610
+}
776610
+
776610
+static gboolean
776610
+is_cursor_in_stream (MetaScreenCastMonitorStreamSrc *monitor_src)
776610
+{
776610
+  MetaBackend *backend = get_backend (monitor_src);
776610
+  MetaCursorRenderer *cursor_renderer =
776610
+    meta_backend_get_cursor_renderer (backend);
776610
+  MetaMonitor *monitor;
776610
+  MetaLogicalMonitor *logical_monitor;
776610
+  MetaRectangle logical_monitor_layout;
776610
+  ClutterRect logical_monitor_rect;
776610
+  MetaCursorSprite *cursor_sprite;
776610
+
776610
+  monitor = get_monitor (monitor_src);
776610
+  logical_monitor = meta_monitor_get_logical_monitor (monitor);
776610
+  logical_monitor_layout = meta_logical_monitor_get_layout (logical_monitor);
776610
+  logical_monitor_rect =
776610
+    meta_rectangle_to_clutter_rect (&logical_monitor_layout);
776610
+
776610
+  cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer);
776610
+  if (cursor_sprite)
776610
+    {
776610
+      ClutterRect cursor_rect;
776610
+
776610
+      cursor_rect = meta_cursor_renderer_calculate_rect (cursor_renderer,
776610
+                                                         cursor_sprite);
776610
+      return clutter_rect_intersection (&cursor_rect,
776610
+                                        &logical_monitor_rect,
776610
+                                        NULL);
776610
+    }
776610
+  else
776610
+    {
776610
+      ClutterPoint cursor_position;
776610
+
776610
+      cursor_position = meta_cursor_renderer_get_position (cursor_renderer);
776610
+      return clutter_rect_contains_point (&logical_monitor_rect,
776610
+                                          &cursor_position);
776610
+    }
776610
+}
776610
+
776610
+static void
776610
+sync_cursor_state (MetaScreenCastMonitorStreamSrc *monitor_src)
776610
+{
776610
+  MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (monitor_src);
776610
+  ClutterStage *stage = get_stage (monitor_src);
776610
+
776610
+  if (!is_cursor_in_stream (monitor_src))
776610
+    return;
776610
+
776610
+  if (clutter_stage_is_redraw_queued (stage))
776610
+    return;
776610
+
776610
+  meta_screen_cast_stream_src_maybe_record_frame (src);
776610
+}
776610
+
776610
+static void
776610
+cursor_moved (MetaCursorTracker              *cursor_tracker,
776610
+              float                           x,
776610
+              float                           y,
776610
+              MetaScreenCastMonitorStreamSrc *monitor_src)
776610
+{
776610
+  sync_cursor_state (monitor_src);
776610
+}
776610
+
776610
+static void
776610
+cursor_changed (MetaCursorTracker              *cursor_tracker,
776610
+                MetaScreenCastMonitorStreamSrc *monitor_src)
776610
+{
776610
+  sync_cursor_state (monitor_src);
776610
+}
776610
+
776610
+static MetaCursorRenderer *
776610
+get_cursor_renderer (MetaScreenCastMonitorStreamSrc *monitor_src)
776610
+{
776610
+  MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (monitor_src);
776610
+  MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src);
776610
+  MetaScreenCastSession *session = meta_screen_cast_stream_get_session (stream);
776610
+  MetaScreenCast *screen_cast =
776610
+    meta_screen_cast_session_get_screen_cast (session);
776610
+  MetaBackend *backend = meta_screen_cast_get_backend (screen_cast);
776610
+
776610
+  return meta_backend_get_cursor_renderer (backend);
776610
+}
776610
+
776610
+static void
776610
+inhibit_hw_cursor (MetaScreenCastMonitorStreamSrc *monitor_src)
776610
+{
776610
+  MetaCursorRenderer *cursor_renderer;
776610
+  MetaHwCursorInhibitor *inhibitor;
776610
+
776610
+  cursor_renderer = get_cursor_renderer (monitor_src);
776610
+  inhibitor = META_HW_CURSOR_INHIBITOR (monitor_src);
776610
+  meta_cursor_renderer_add_hw_cursor_inhibitor (cursor_renderer, inhibitor);
776610
+}
776610
+
776610
+static void
776610
+uninhibit_hw_cursor (MetaScreenCastMonitorStreamSrc *monitor_src)
776610
+{
776610
+  MetaCursorRenderer *cursor_renderer;
776610
+  MetaHwCursorInhibitor *inhibitor;
776610
+
776610
+  cursor_renderer = get_cursor_renderer (monitor_src);
776610
+  inhibitor = META_HW_CURSOR_INHIBITOR (monitor_src);
776610
+  meta_cursor_renderer_remove_hw_cursor_inhibitor (cursor_renderer, inhibitor);
776610
+}
776610
+
776610
 static void
776610
 meta_screen_cast_monitor_stream_src_enable (MetaScreenCastStreamSrc *src)
776610
 {
776610
   MetaScreenCastMonitorStreamSrc *monitor_src =
776610
     META_SCREEN_CAST_MONITOR_STREAM_SRC (src);
776610
+  MetaBackend *backend = get_backend (monitor_src);
776610
+  MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
776610
   ClutterStage *stage;
776610
+  MetaScreenCastStream *stream;
776610
 
776610
+  stream = meta_screen_cast_stream_src_get_stream (src);
776610
   stage = get_stage (monitor_src);
776610
-  monitor_src->actors_painted_handler_id =
776610
-    g_signal_connect_after (stage, "actors-painted",
776610
-                            G_CALLBACK (stage_painted),
776610
-                            monitor_src);
776610
+
776610
+  switch (meta_screen_cast_stream_get_cursor_mode (stream))
776610
+    {
776610
+    case META_SCREEN_CAST_CURSOR_MODE_METADATA:
776610
+      monitor_src->cursor_moved_handler_id =
776610
+        g_signal_connect_after (cursor_tracker, "cursor-moved",
776610
+                                G_CALLBACK (cursor_moved),
776610
+                                monitor_src);
776610
+      monitor_src->cursor_changed_handler_id =
776610
+        g_signal_connect_after (cursor_tracker, "cursor-changed",
776610
+                                G_CALLBACK (cursor_changed),
776610
+                                monitor_src);
776610
+      /* Intentional fall-through */
776610
+    case META_SCREEN_CAST_CURSOR_MODE_HIDDEN:
776610
+      monitor_src->actors_painted_handler_id =
776610
+        g_signal_connect (stage, "actors-painted",
776610
+                          G_CALLBACK (stage_painted),
776610
+                          monitor_src);
776610
+      break;
776610
+    case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED:
776610
+      inhibit_hw_cursor (monitor_src);
776610
+      monitor_src->paint_handler_id =
776610
+        g_signal_connect_after (stage, "paint",
776610
+                                G_CALLBACK (stage_painted),
776610
+                                monitor_src);
776610
+      break;
776610
+    }
776610
+
776610
   clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
776610
 }
776610
 
776610
@@ -122,14 +280,43 @@ meta_screen_cast_monitor_stream_src_disable (MetaScreenCastStreamSrc *src)
776610
 {
776610
   MetaScreenCastMonitorStreamSrc *monitor_src =
776610
     META_SCREEN_CAST_MONITOR_STREAM_SRC (src);
776610
+  MetaBackend *backend = get_backend (monitor_src);
776610
+  MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
776610
   ClutterStage *stage;
776610
 
776610
   stage = get_stage (monitor_src);
776610
-  g_signal_handler_disconnect (stage, monitor_src->actors_painted_handler_id);
776610
-  monitor_src->actors_painted_handler_id = 0;
776610
+
776610
+  if (monitor_src->actors_painted_handler_id)
776610
+    {
776610
+      g_signal_handler_disconnect (stage,
776610
+                                   monitor_src->actors_painted_handler_id);
776610
+      monitor_src->actors_painted_handler_id = 0;
776610
+    }
776610
+
776610
+  if (monitor_src->paint_handler_id)
776610
+    {
776610
+      g_signal_handler_disconnect (stage,
776610
+                                   monitor_src->paint_handler_id);
776610
+      monitor_src->paint_handler_id = 0;
776610
+      uninhibit_hw_cursor (monitor_src);
776610
+    }
776610
+
776610
+  if (monitor_src->cursor_moved_handler_id)
776610
+    {
776610
+      g_signal_handler_disconnect (cursor_tracker,
776610
+                                   monitor_src->cursor_moved_handler_id);
776610
+      monitor_src->cursor_moved_handler_id = 0;
776610
+    }
776610
+
776610
+  if (monitor_src->cursor_changed_handler_id)
776610
+    {
776610
+      g_signal_handler_disconnect (cursor_tracker,
776610
+                                   monitor_src->cursor_changed_handler_id);
776610
+      monitor_src->cursor_changed_handler_id = 0;
776610
+    }
776610
 }
776610
 
776610
-static void
776610
+static gboolean
776610
 meta_screen_cast_monitor_stream_src_record_frame (MetaScreenCastStreamSrc *src,
776610
                                                   uint8_t                 *data)
776610
 {
776610
@@ -140,9 +327,216 @@ meta_screen_cast_monitor_stream_src_record_frame (MetaScreenCastStreamSrc *src,
776610
   MetaLogicalMonitor *logical_monitor;
776610
 
776610
   stage = get_stage (monitor_src);
776610
+  if (!clutter_stage_is_redraw_queued (stage))
776610
+    return FALSE;
776610
+
776610
   monitor = get_monitor (monitor_src);
776610
   logical_monitor = meta_monitor_get_logical_monitor (monitor);
776610
   clutter_stage_capture_into (stage, FALSE, &logical_monitor->rect, data);
776610
+
776610
+  return TRUE;
776610
+}
776610
+
776610
+static gboolean
776610
+draw_cursor_sprite_via_offscreen (MetaScreenCastMonitorStreamSrc  *monitor_src,
776610
+                                  CoglTexture                     *cursor_texture,
776610
+                                  int                              bitmap_width,
776610
+                                  int                              bitmap_height,
776610
+                                  uint32_t                        *bitmap_data,
776610
+                                  GError                         **error)
776610
+{
776610
+  MetaBackend *backend = get_backend (monitor_src);
776610
+  ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
776610
+  CoglContext *cogl_context =
776610
+    clutter_backend_get_cogl_context (clutter_backend);
776610
+  CoglTexture2D *bitmap_texture;
776610
+  CoglOffscreen *offscreen;
776610
+  CoglFramebuffer *fb;
776610
+  CoglPipeline *pipeline;
776610
+  CoglColor clear_color;
776610
+
776610
+  bitmap_texture = cogl_texture_2d_new_with_size (cogl_context,
776610
+                                                  bitmap_width, bitmap_height);
776610
+  cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (bitmap_texture),
776610
+                                          FALSE);
776610
+  if (!cogl_texture_allocate (COGL_TEXTURE (bitmap_texture), error))
776610
+    {
776610
+      cogl_object_unref (bitmap_texture);
776610
+      return FALSE;
776610
+    }
776610
+
776610
+  offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (bitmap_texture));
776610
+  fb = COGL_FRAMEBUFFER (offscreen);
776610
+  cogl_object_unref (bitmap_texture);
776610
+  if (!cogl_framebuffer_allocate (fb, error))
776610
+    {
776610
+      cogl_object_unref (fb);
776610
+      return FALSE;
776610
+    }
776610
+
776610
+  pipeline = cogl_pipeline_new (cogl_context);
776610
+  cogl_pipeline_set_layer_texture (pipeline, 0, cursor_texture);
776610
+  cogl_pipeline_set_layer_filters (pipeline, 0,
776610
+                                   COGL_PIPELINE_FILTER_LINEAR,
776610
+                                   COGL_PIPELINE_FILTER_LINEAR);
776610
+  cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0);
776610
+  cogl_framebuffer_clear (fb, COGL_BUFFER_BIT_COLOR, &clear_color);
776610
+  cogl_framebuffer_draw_rectangle (fb, pipeline,
776610
+                                   -1, 1, 1, -1);
776610
+  cogl_object_unref (pipeline);
776610
+
776610
+  cogl_framebuffer_read_pixels (fb,
776610
+                                0, 0,
776610
+                                bitmap_width, bitmap_height,
776610
+                                COGL_PIXEL_FORMAT_RGBA_8888_PRE,
776610
+                                (uint8_t *) bitmap_data);
776610
+  cogl_object_unref (fb);
776610
+
776610
+  return TRUE;
776610
+}
776610
+
776610
+static void
776610
+meta_screen_cast_monitor_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *src,
776610
+                                                         struct spa_meta_cursor  *spa_meta_cursor)
776610
+{
776610
+  MetaScreenCastMonitorStreamSrc *monitor_src =
776610
+    META_SCREEN_CAST_MONITOR_STREAM_SRC (src);
776610
+  MetaBackend *backend = get_backend (monitor_src);
776610
+  MetaCursorRenderer *cursor_renderer =
776610
+    meta_backend_get_cursor_renderer (backend);
776610
+  MetaRenderer *renderer = meta_backend_get_renderer (backend);
776610
+  MetaSpaType *spa_type = meta_screen_cast_stream_src_get_spa_type (src);
776610
+  GError *error = NULL;
776610
+  MetaCursorSprite *cursor_sprite;
776610
+  CoglTexture *cursor_texture;
776610
+  MetaMonitor *monitor;
776610
+  MetaLogicalMonitor *logical_monitor;
776610
+  MetaRectangle logical_monitor_layout;
776610
+  ClutterRect logical_monitor_rect;
776610
+  MetaRendererView *view;
776610
+  float view_scale;
776610
+  ClutterPoint cursor_position;
776610
+  struct spa_meta_bitmap *spa_meta_bitmap;
776610
+
776610
+  cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer);
776610
+  if (cursor_sprite)
776610
+    cursor_texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite);
776610
+  else
776610
+    cursor_texture = NULL;
776610
+
776610
+  if (!is_cursor_in_stream (monitor_src))
776610
+    {
776610
+      spa_meta_cursor->id = 0;
776610
+      return;
776610
+    }
776610
+
776610
+  monitor = get_monitor (monitor_src);
776610
+  logical_monitor = meta_monitor_get_logical_monitor (monitor);
776610
+  logical_monitor_layout = meta_logical_monitor_get_layout (logical_monitor);
776610
+  logical_monitor_rect =
776610
+    meta_rectangle_to_clutter_rect (&logical_monitor_layout);
776610
+
776610
+  view = meta_renderer_get_view_from_logical_monitor (renderer,
776610
+                                                      logical_monitor);
776610
+  if (view)
776610
+    view_scale = clutter_stage_view_get_scale (CLUTTER_STAGE_VIEW (view));
776610
+  else
776610
+    view_scale = 1.0;
776610
+
776610
+  cursor_position = meta_cursor_renderer_get_position (cursor_renderer);
776610
+  cursor_position.x -= logical_monitor_rect.origin.x;
776610
+  cursor_position.y -= logical_monitor_rect.origin.y;
776610
+  cursor_position.x *= view_scale;
776610
+  cursor_position.y *= view_scale;
776610
+
776610
+  spa_meta_cursor->id = 1;
776610
+  spa_meta_cursor->position.x = (int32_t) roundf (cursor_position.x);
776610
+  spa_meta_cursor->position.y = (int32_t) roundf (cursor_position.y);
776610
+  spa_meta_cursor->bitmap_offset = sizeof (struct spa_meta_cursor);
776610
+
776610
+  spa_meta_bitmap = SPA_MEMBER (spa_meta_cursor,
776610
+                                spa_meta_cursor->bitmap_offset,
776610
+                                struct spa_meta_bitmap);
776610
+  spa_meta_bitmap->format = spa_type->video_format.RGBA;
776610
+  spa_meta_bitmap->offset = sizeof (struct spa_meta_bitmap);
776610
+
776610
+  if (cursor_texture)
776610
+    {
776610
+      float cursor_scale;
776610
+      float bitmap_scale;
776610
+      int hotspot_x, hotspot_y;
776610
+      int texture_width, texture_height;
776610
+      int bitmap_width, bitmap_height;
776610
+      uint32_t *bitmap_data;
776610
+
776610
+      cursor_scale = meta_cursor_sprite_get_texture_scale (cursor_sprite);
776610
+      bitmap_scale = view_scale * cursor_scale;
776610
+
776610
+      meta_cursor_sprite_get_hotspot (cursor_sprite, &hotspot_x, &hotspot_y);
776610
+      spa_meta_cursor->hotspot.x = (int32_t) roundf (hotspot_x * bitmap_scale);
776610
+      spa_meta_cursor->hotspot.y = (int32_t) roundf (hotspot_y * bitmap_scale);
776610
+
776610
+      texture_width = cogl_texture_get_width (cursor_texture);
776610
+      texture_height = cogl_texture_get_height (cursor_texture);
776610
+      bitmap_width = texture_width * bitmap_scale;
776610
+      bitmap_height = texture_height * bitmap_scale;
776610
+
776610
+      spa_meta_bitmap->size.width = bitmap_width;
776610
+      spa_meta_bitmap->size.height = bitmap_height;
776610
+      spa_meta_bitmap->stride = bitmap_width * 4;
776610
+
776610
+      bitmap_data = SPA_MEMBER (spa_meta_bitmap,
776610
+                                spa_meta_bitmap->offset,
776610
+                                uint32_t);
776610
+
776610
+      if (texture_width == bitmap_width &&
776610
+          texture_height == bitmap_height)
776610
+        {
776610
+          cogl_texture_get_data (cursor_texture,
776610
+                                 COGL_PIXEL_FORMAT_RGBA_8888_PRE,
776610
+                                 texture_width * 4,
776610
+                                 (uint8_t *) bitmap_data);
776610
+        }
776610
+      else
776610
+        {
776610
+          if (!draw_cursor_sprite_via_offscreen (monitor_src,
776610
+                                                 cursor_texture,
776610
+                                                 bitmap_width,
776610
+                                                 bitmap_height,
776610
+                                                 bitmap_data,
776610
+                                                 &error))
776610
+            {
776610
+              g_warning ("Failed to draw cursor via offscreen: %s",
776610
+                         error->message);
776610
+              g_error_free (error);
776610
+              spa_meta_cursor->id = 0;
776610
+            }
776610
+        }
776610
+    }
776610
+  else
776610
+    {
776610
+      spa_meta_cursor->hotspot.x = 0;
776610
+      spa_meta_cursor->hotspot.y = 0;
776610
+
776610
+      *spa_meta_bitmap = (struct spa_meta_bitmap) { 0 };
776610
+    }
776610
+}
776610
+
776610
+static gboolean
776610
+meta_screen_cast_monitor_stream_src_is_cursor_sprite_inhibited (MetaHwCursorInhibitor *inhibitor,
776610
+                                                                MetaCursorSprite      *cursor_sprite)
776610
+{
776610
+  MetaScreenCastMonitorStreamSrc *monitor_src =
776610
+    META_SCREEN_CAST_MONITOR_STREAM_SRC (inhibitor);
776610
+
776610
+  return is_cursor_in_stream (monitor_src);
776610
+}
776610
+
776610
+static void
776610
+hw_cursor_inhibitor_iface_init (MetaHwCursorInhibitorInterface *iface)
776610
+{
776610
+  iface->is_cursor_sprite_inhibited =
776610
+    meta_screen_cast_monitor_stream_src_is_cursor_sprite_inhibited;
776610
 }
776610
 
776610
 MetaScreenCastMonitorStreamSrc *
776610
@@ -169,4 +563,6 @@ meta_screen_cast_monitor_stream_src_class_init (MetaScreenCastMonitorStreamSrcCl
776610
   src_class->enable = meta_screen_cast_monitor_stream_src_enable;
776610
   src_class->disable = meta_screen_cast_monitor_stream_src_disable;
776610
   src_class->record_frame = meta_screen_cast_monitor_stream_src_record_frame;
776610
+  src_class->set_cursor_metadata =
776610
+    meta_screen_cast_monitor_stream_src_set_cursor_metadata;
776610
 }
776610
diff --git a/src/backends/meta-screen-cast-monitor-stream.c b/src/backends/meta-screen-cast-monitor-stream.c
776610
index a6bed1b52..33b9f026a 100644
776610
--- a/src/backends/meta-screen-cast-monitor-stream.c
776610
+++ b/src/backends/meta-screen-cast-monitor-stream.c
776610
@@ -105,11 +105,12 @@ meta_screen_cast_monitor_stream_get_monitor (MetaScreenCastMonitorStream *monito
776610
 }
776610
 
776610
 MetaScreenCastMonitorStream *
776610
-meta_screen_cast_monitor_stream_new (MetaScreenCastSession  *session,
776610
-                                     GDBusConnection        *connection,
776610
-                                     MetaMonitor            *monitor,
776610
-                                     ClutterStage           *stage,
776610
-                                     GError                **error)
776610
+meta_screen_cast_monitor_stream_new (MetaScreenCastSession     *session,
776610
+                                     GDBusConnection           *connection,
776610
+                                     MetaMonitor               *monitor,
776610
+                                     ClutterStage              *stage,
776610
+                                     MetaScreenCastCursorMode   cursor_mode,
776610
+                                     GError                   **error)
776610
 {
776610
   MetaGpu *gpu = meta_monitor_get_gpu (monitor);
776610
   MetaMonitorManager *monitor_manager = meta_gpu_get_monitor_manager (gpu);
776610
@@ -126,6 +127,7 @@ meta_screen_cast_monitor_stream_new (MetaScreenCastSession  *session,
776610
                                    error,
776610
                                    "session", session,
776610
                                    "connection", connection,
776610
+                                   "cursor-mode", cursor_mode,
776610
                                    "monitor", monitor,
776610
                                    NULL);
776610
   if (!monitor_stream)
776610
diff --git a/src/backends/meta-screen-cast-monitor-stream.h b/src/backends/meta-screen-cast-monitor-stream.h
776610
index 98f160c88..f8dc04181 100644
776610
--- a/src/backends/meta-screen-cast-monitor-stream.h
776610
+++ b/src/backends/meta-screen-cast-monitor-stream.h
776610
@@ -35,11 +35,12 @@ G_DECLARE_FINAL_TYPE (MetaScreenCastMonitorStream,
776610
                       META, SCREEN_CAST_MONITOR_STREAM,
776610
                       MetaScreenCastStream)
776610
 
776610
-MetaScreenCastMonitorStream * meta_screen_cast_monitor_stream_new (MetaScreenCastSession  *session,
776610
-                                                                   GDBusConnection        *connection,
776610
-                                                                   MetaMonitor            *monitor,
776610
-                                                                   ClutterStage           *stage,
776610
-                                                                   GError                **error);
776610
+MetaScreenCastMonitorStream * meta_screen_cast_monitor_stream_new (MetaScreenCastSession     *session,
776610
+                                                                   GDBusConnection           *connection,
776610
+                                                                   MetaMonitor               *monitor,
776610
+                                                                   ClutterStage              *stage,
776610
+                                                                   MetaScreenCastCursorMode   cursor_mode,
776610
+                                                                   GError                   **error);
776610
 
776610
 ClutterStage * meta_screen_cast_monitor_stream_get_stage (MetaScreenCastMonitorStream *monitor_stream);
776610
 
776610
diff --git a/src/backends/meta-screen-cast-session.c b/src/backends/meta-screen-cast-session.c
776610
index 6a8f2d328..45d403dca 100644
776610
--- a/src/backends/meta-screen-cast-session.c
776610
+++ b/src/backends/meta-screen-cast-session.c
776610
@@ -262,6 +262,20 @@ on_stream_closed (MetaScreenCastStream  *stream,
776610
   meta_screen_cast_session_close (session);
776610
 }
776610
 
776610
+static gboolean
776610
+is_valid_cursor_mode (MetaScreenCastCursorMode cursor_mode)
776610
+{
776610
+  switch (cursor_mode)
776610
+    {
776610
+    case META_SCREEN_CAST_CURSOR_MODE_HIDDEN:
776610
+    case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED:
776610
+    case META_SCREEN_CAST_CURSOR_MODE_METADATA:
776610
+      return TRUE;
776610
+    }
776610
+
776610
+  return FALSE;
776610
+}
776610
+
776610
 static gboolean
776610
 handle_record_monitor (MetaDBusScreenCastSession *skeleton,
776610
                        GDBusMethodInvocation     *invocation,
776610
@@ -275,6 +289,7 @@ handle_record_monitor (MetaDBusScreenCastSession *skeleton,
776610
   MetaMonitorManager *monitor_manager =
776610
     meta_backend_get_monitor_manager (backend);
776610
   MetaMonitor *monitor;
776610
+  MetaScreenCastCursorMode cursor_mode;
776610
   ClutterStage *stage;
776610
   GError *error = NULL;
776610
   MetaScreenCastMonitorStream *monitor_stream;
776610
@@ -306,12 +321,28 @@ handle_record_monitor (MetaDBusScreenCastSession *skeleton,
776610
       return TRUE;
776610
     }
776610
 
776610
+  if (!g_variant_lookup (properties_variant, "cursor-mode", "u", &cursor_mode))
776610
+    {
776610
+      cursor_mode = META_SCREEN_CAST_CURSOR_MODE_HIDDEN;
776610
+    }
776610
+  else
776610
+    {
776610
+      if (!is_valid_cursor_mode (cursor_mode))
776610
+        {
776610
+          g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
776610
+                                                 G_DBUS_ERROR_FAILED,
776610
+                                                 "Unknown cursor mode");
776610
+          return TRUE;
776610
+        }
776610
+    }
776610
+
776610
   stage = CLUTTER_STAGE (meta_backend_get_stage (backend));
776610
 
776610
   monitor_stream = meta_screen_cast_monitor_stream_new (session,
776610
                                                         connection,
776610
                                                         monitor,
776610
                                                         stage,
776610
+                                                        cursor_mode,
776610
                                                         &error);
776610
   if (!monitor_stream)
776610
     {
776610
diff --git a/src/backends/meta-screen-cast-stream-src.c b/src/backends/meta-screen-cast-stream-src.c
776610
index 673a4640b..9f97bf36d 100644
776610
--- a/src/backends/meta-screen-cast-stream-src.c
776610
+++ b/src/backends/meta-screen-cast-stream-src.c
776610
@@ -40,6 +40,10 @@
776610
 #define PRIVATE_OWNER_FROM_FIELD(TypeName, field_ptr, field_name) \
776610
   (TypeName *)((guint8 *)(field_ptr) - G_PRIVATE_OFFSET (TypeName, field_name))
776610
 
776610
+#define CURSOR_META_SIZE(width, height) \
776610
+  (sizeof (struct spa_meta_cursor) + \
776610
+   sizeof (struct spa_meta_bitmap) + width * height * 4)
776610
+
776610
 enum
776610
 {
776610
   PROP_0,
776610
@@ -57,14 +61,6 @@ enum
776610
 
776610
 static guint signals[N_SIGNALS];
776610
 
776610
-typedef struct _MetaSpaType
776610
-{
776610
-  struct spa_type_media_type media_type;
776610
-  struct spa_type_media_subtype media_subtype;
776610
-  struct spa_type_format_video format_video;
776610
-  struct spa_type_video_format video_format;
776610
-} MetaSpaType;
776610
-
776610
 typedef struct _MetaPipeWireSource
776610
 {
776610
   GSource base;
776610
@@ -133,14 +129,68 @@ meta_screen_cast_stream_src_get_videocrop (MetaScreenCastStreamSrc *src,
776610
   return FALSE;
776610
 }
776610
 
776610
-static void
776610
+static gboolean
776610
 meta_screen_cast_stream_src_record_frame (MetaScreenCastStreamSrc *src,
776610
                                           uint8_t                 *data)
776610
 {
776610
   MetaScreenCastStreamSrcClass *klass =
776610
     META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src);
776610
 
776610
-  klass->record_frame (src, data);
776610
+  return klass->record_frame (src, data);
776610
+}
776610
+
776610
+static void
776610
+meta_screen_cast_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *src,
776610
+                                                 struct spa_meta_cursor  *spa_meta_cursor)
776610
+{
776610
+  MetaScreenCastStreamSrcClass *klass =
776610
+    META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src);
776610
+
776610
+  if (klass->set_cursor_metadata)
776610
+    klass->set_cursor_metadata (src, spa_meta_cursor);
776610
+}
776610
+
776610
+MetaSpaType *
776610
+meta_screen_cast_stream_src_get_spa_type (MetaScreenCastStreamSrc *src)
776610
+{
776610
+  MetaScreenCastStreamSrcPrivate *priv =
776610
+    meta_screen_cast_stream_src_get_instance_private (src);
776610
+
776610
+  return &priv->spa_type;
776610
+}
776610
+
776610
+static void
776610
+add_cursor_metadata (MetaScreenCastStreamSrc *src,
776610
+                     struct spa_buffer       *spa_buffer)
776610
+{
776610
+  MetaScreenCastStreamSrcPrivate *priv =
776610
+    meta_screen_cast_stream_src_get_instance_private (src);
776610
+  MetaSpaType *spa_type = &priv->spa_type;
776610
+  struct spa_meta_cursor *spa_meta_cursor;
776610
+
776610
+  spa_meta_cursor = spa_buffer_find_meta (spa_buffer, spa_type->meta_cursor);
776610
+  if (spa_meta_cursor)
776610
+    meta_screen_cast_stream_src_set_cursor_metadata (src, spa_meta_cursor);
776610
+}
776610
+
776610
+static void
776610
+maybe_record_cursor (MetaScreenCastStreamSrc *src,
776610
+                     struct spa_buffer       *spa_buffer,
776610
+                     uint8_t                 *data)
776610
+{
776610
+  MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src);
776610
+
776610
+  switch (meta_screen_cast_stream_get_cursor_mode (stream))
776610
+    {
776610
+    case META_SCREEN_CAST_CURSOR_MODE_HIDDEN:
776610
+    case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED:
776610
+      return;
776610
+    case META_SCREEN_CAST_CURSOR_MODE_METADATA:
776610
+      add_cursor_metadata (src, spa_buffer);
776610
+      return;
776610
+    }
776610
+
776610
+  g_assert_not_reached ();
776610
 }
776610
 
776610
 void
776610
@@ -151,7 +201,6 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src)
776610
   MetaRectangle crop_rect;
776610
   struct pw_buffer *buffer;
776610
   struct spa_buffer *spa_buffer;
776610
-  struct spa_meta_video_crop *spa_meta_video_crop;
776610
   uint8_t *map = NULL;
776610
   uint8_t *data;
776610
   uint64_t now_us;
776610
@@ -199,35 +248,45 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src)
776610
       return;
776610
     }
776610
 
776610
-  meta_screen_cast_stream_src_record_frame (src, data);
776610
-
776610
-  /* Update VideoCrop if needed */
776610
-  spa_meta_video_crop = spa_buffer_find_meta (spa_buffer, priv->pipewire_type->meta.VideoCrop);
776610
-  if (spa_meta_video_crop)
776610
+  if (meta_screen_cast_stream_src_record_frame (src, data))
776610
     {
776610
-      if (meta_screen_cast_stream_src_get_videocrop (src, &crop_rect))
776610
-        {
776610
-          spa_meta_video_crop->x = crop_rect.x;
776610
-          spa_meta_video_crop->y = crop_rect.y;
776610
-          spa_meta_video_crop->width = crop_rect.width;
776610
-          spa_meta_video_crop->height = crop_rect.height;
776610
-        }
776610
-      else
776610
+      struct spa_meta_video_crop *spa_meta_video_crop;
776610
+
776610
+      spa_buffer->datas[0].chunk->size = spa_buffer->datas[0].maxsize;
776610
+
776610
+      /* Update VideoCrop if needed */
776610
+      spa_meta_video_crop =
776610
+        spa_buffer_find_meta (spa_buffer, priv->pipewire_type->meta.VideoCrop);
776610
+      if (spa_meta_video_crop)
776610
         {
776610
-          spa_meta_video_crop->x = 0;
776610
-          spa_meta_video_crop->y = 0;
776610
-          spa_meta_video_crop->width = priv->stream_width;
776610
-          spa_meta_video_crop->height = priv->stream_height;
776610
+          if (meta_screen_cast_stream_src_get_videocrop (src, &crop_rect))
776610
+            {
776610
+              spa_meta_video_crop->x = crop_rect.x;
776610
+              spa_meta_video_crop->y = crop_rect.y;
776610
+              spa_meta_video_crop->width = crop_rect.width;
776610
+              spa_meta_video_crop->height = crop_rect.height;
776610
+            }
776610
+          else
776610
+            {
776610
+              spa_meta_video_crop->x = 0;
776610
+              spa_meta_video_crop->y = 0;
776610
+              spa_meta_video_crop->width = priv->stream_width;
776610
+              spa_meta_video_crop->height = priv->stream_height;
776610
+            }
776610
         }
776610
     }
776610
+  else
776610
+    {
776610
+      spa_buffer->datas[0].chunk->size = 0;
776610
+    }
776610
+
776610
+  maybe_record_cursor (src, spa_buffer, data);
776610
 
776610
   priv->last_frame_timestamp_us = now_us;
776610
 
776610
   if (map)
776610
     munmap (map, spa_buffer->datas[0].maxsize + spa_buffer->datas[0].mapoffset);
776610
 
776610
-  spa_buffer->datas[0].chunk->size = spa_buffer->datas[0].maxsize;
776610
-
776610
   pw_stream_queue_buffer (priv->pipewire_stream, buffer);
776610
 }
776610
 
776610
@@ -314,7 +373,7 @@ on_stream_format_changed (void                 *data,
776610
   uint8_t params_buffer[1024];
776610
   int32_t width, height, stride, size;
776610
   struct spa_pod_builder pod_builder;
776610
-  const struct spa_pod *params[2];
776610
+  const struct spa_pod *params[3];
776610
   const int bpp = 4;
776610
 
776610
   if (!format)
776610
@@ -348,6 +407,12 @@ on_stream_format_changed (void                 *data,
776610
     ":", pipewire_type->param_meta.type, "I", pipewire_type->meta.VideoCrop,
776610
     ":", pipewire_type->param_meta.size, "i", sizeof (struct spa_meta_video_crop));
776610
 
776610
+  params[2] = spa_pod_builder_object (
776610
+    &pod_builder,
776610
+    pipewire_type->param.idMeta, pipewire_type->param_meta.Meta,
776610
+    ":", pipewire_type->param_meta.type, "I", priv->spa_type.meta_cursor,
776610
+    ":", pipewire_type->param_meta.size, "i", CURSOR_META_SIZE (64, 64));
776610
+
776610
   pw_stream_finish_format (priv->pipewire_stream, 0,
776610
                            params, G_N_ELEMENTS (params));
776610
 }
776610
@@ -517,6 +582,7 @@ init_spa_type (MetaSpaType         *type,
776610
   spa_type_media_subtype_map (map, &type->media_subtype);
776610
   spa_type_format_video_map (map, &type->format_video);
776610
   spa_type_video_format_map (map, &type->video_format);
776610
+  type->meta_cursor = spa_type_map_get_id(map, SPA_TYPE_META__Cursor);
776610
 }
776610
 
776610
 static MetaPipeWireSource *
776610
diff --git a/src/backends/meta-screen-cast-stream-src.h b/src/backends/meta-screen-cast-stream-src.h
776610
index f3b3fd779..f2f96f213 100644
776610
--- a/src/backends/meta-screen-cast-stream-src.h
776610
+++ b/src/backends/meta-screen-cast-stream-src.h
776610
@@ -24,10 +24,26 @@
776610
 #define META_SCREEN_CAST_STREAM_SRC_H
776610
 
776610
 #include <glib-object.h>
776610
+#include <spa/param/video/format-utils.h>
776610
+#include <spa/buffer/meta.h>
776610
 
776610
+#include "backends/meta-backend-private.h"
776610
+#include "backends/meta-cursor-renderer.h"
776610
+#include "backends/meta-cursor.h"
776610
+#include "backends/meta-renderer.h"
776610
 #include "clutter/clutter.h"
776610
+#include "cogl/cogl.h"
776610
 #include "meta/boxes.h"
776610
 
776610
+typedef struct _MetaSpaType
776610
+{
776610
+  struct spa_type_media_type media_type;
776610
+  struct spa_type_media_subtype media_subtype;
776610
+  struct spa_type_format_video format_video;
776610
+  struct spa_type_video_format video_format;
776610
+  uint32_t meta_cursor;
776610
+} MetaSpaType;
776610
+
776610
 typedef struct _MetaScreenCastStream MetaScreenCastStream;
776610
 
776610
 #define META_TYPE_SCREEN_CAST_STREAM_SRC (meta_screen_cast_stream_src_get_type ())
776610
@@ -46,14 +62,18 @@ struct _MetaScreenCastStreamSrcClass
776610
                       float                   *frame_rate);
776610
   void (* enable) (MetaScreenCastStreamSrc *src);
776610
   void (* disable) (MetaScreenCastStreamSrc *src);
776610
-  void (* record_frame) (MetaScreenCastStreamSrc *src,
776610
-                         uint8_t                 *data);
776610
+  gboolean (* record_frame) (MetaScreenCastStreamSrc *src,
776610
+                             uint8_t                 *data);
776610
   gboolean (* get_videocrop) (MetaScreenCastStreamSrc *src,
776610
                               MetaRectangle           *crop_rect);
776610
+  void (* set_cursor_metadata) (MetaScreenCastStreamSrc *src,
776610
+                                struct spa_meta_cursor  *spa_meta_cursor);
776610
 };
776610
 
776610
 void meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src);
776610
 
776610
 MetaScreenCastStream * meta_screen_cast_stream_src_get_stream (MetaScreenCastStreamSrc *src);
776610
 
776610
+MetaSpaType * meta_screen_cast_stream_src_get_spa_type (MetaScreenCastStreamSrc *src);
776610
+
776610
 #endif /* META_SCREEN_CAST_STREAM_SRC_H */
776610
diff --git a/src/backends/meta-screen-cast-stream.c b/src/backends/meta-screen-cast-stream.c
776610
index 875ada01a..c14f8fd85 100644
776610
--- a/src/backends/meta-screen-cast-stream.c
776610
+++ b/src/backends/meta-screen-cast-stream.c
776610
@@ -34,6 +34,7 @@ enum
776610
 
776610
   PROP_SESSION,
776610
   PROP_CONNECTION,
776610
+  PROP_CURSOR_MODE,
776610
 };
776610
 
776610
 enum
776610
@@ -52,6 +53,8 @@ typedef struct _MetaScreenCastStreamPrivate
776610
   GDBusConnection *connection;
776610
   char *object_path;
776610
 
776610
+  MetaScreenCastCursorMode cursor_mode;
776610
+
776610
   MetaScreenCastStreamSrc *src;
776610
 } MetaScreenCastStreamPrivate;
776610
 
776610
@@ -164,6 +167,15 @@ meta_screen_cast_stream_transform_position (MetaScreenCastStream *stream,
776610
                                                                   y);
776610
 }
776610
 
776610
+MetaScreenCastCursorMode
776610
+meta_screen_cast_stream_get_cursor_mode (MetaScreenCastStream *stream)
776610
+{
776610
+  MetaScreenCastStreamPrivate *priv =
776610
+    meta_screen_cast_stream_get_instance_private (stream);
776610
+
776610
+  return priv->cursor_mode;
776610
+}
776610
+
776610
 static void
776610
 meta_screen_cast_stream_set_property (GObject      *object,
776610
                                       guint         prop_id,
776610
@@ -182,6 +194,9 @@ meta_screen_cast_stream_set_property (GObject      *object,
776610
     case PROP_CONNECTION:
776610
       priv->connection = g_value_get_object (value);
776610
       break;
776610
+    case PROP_CURSOR_MODE:
776610
+      priv->cursor_mode = g_value_get_uint (value);
776610
+      break;
776610
     default:
776610
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
776610
     }
776610
@@ -205,6 +220,9 @@ meta_screen_cast_stream_get_property (GObject    *object,
776610
     case PROP_CONNECTION:
776610
       g_value_set_object (value, priv->connection);
776610
       break;
776610
+    case PROP_CURSOR_MODE:
776610
+      g_value_set_uint (value, priv->cursor_mode);
776610
+      break;
776610
     default:
776610
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
776610
     }
776610
@@ -296,6 +314,18 @@ meta_screen_cast_stream_class_init (MetaScreenCastStreamClass *klass)
776610
                                                         G_PARAM_CONSTRUCT_ONLY |
776610
                                                         G_PARAM_STATIC_STRINGS));
776610
 
776610
+  g_object_class_install_property (object_class,
776610
+                                   PROP_CURSOR_MODE,
776610
+                                   g_param_spec_uint ("cursor-mode",
776610
+                                                      "cursor-mode",
776610
+                                                      "Cursor mode",
776610
+                                                      META_SCREEN_CAST_CURSOR_MODE_HIDDEN,
776610
+                                                      META_SCREEN_CAST_CURSOR_MODE_METADATA,
776610
+                                                      META_SCREEN_CAST_CURSOR_MODE_HIDDEN,
776610
+                                                      G_PARAM_READWRITE |
776610
+                                                      G_PARAM_CONSTRUCT_ONLY |
776610
+                                                      G_PARAM_STATIC_STRINGS));
776610
+
776610
   signals[CLOSED] = g_signal_new ("closed",
776610
                                   G_TYPE_FROM_CLASS (klass),
776610
                                   G_SIGNAL_RUN_LAST,
776610
diff --git a/src/backends/meta-screen-cast-stream.h b/src/backends/meta-screen-cast-stream.h
776610
index dcc280da6..28ca6f683 100644
776610
--- a/src/backends/meta-screen-cast-stream.h
776610
+++ b/src/backends/meta-screen-cast-stream.h
776610
@@ -67,4 +67,6 @@ void meta_screen_cast_stream_transform_position (MetaScreenCastStream *stream,
776610
                                                  double               *x,
776610
                                                  double               *y);
776610
 
776610
+MetaScreenCastCursorMode meta_screen_cast_stream_get_cursor_mode (MetaScreenCastStream *stream);
776610
+
776610
 #endif /* META_SCREEN_CAST_STREAM_H */
776610
diff --git a/src/backends/meta-screen-cast-window-stream-src.c b/src/backends/meta-screen-cast-window-stream-src.c
776610
index c3f9cf5ca..32df9f127 100644
776610
--- a/src/backends/meta-screen-cast-window-stream-src.c
776610
+++ b/src/backends/meta-screen-cast-window-stream-src.c
776610
@@ -207,7 +207,7 @@ meta_screen_cast_window_stream_src_disable (MetaScreenCastStreamSrc *src)
776610
   meta_screen_cast_window_stream_src_stop (window_src);
776610
 }
776610
 
776610
-static void
776610
+static gboolean
776610
 meta_screen_cast_window_stream_src_record_frame (MetaScreenCastStreamSrc *src,
776610
                                                  uint8_t                 *data)
776610
 {
776610
@@ -215,6 +215,8 @@ meta_screen_cast_window_stream_src_record_frame (MetaScreenCastStreamSrc *src,
776610
     META_SCREEN_CAST_WINDOW_STREAM_SRC (src);
776610
 
776610
   capture_into (window_src, data);
776610
+
776610
+  return TRUE;
776610
 }
776610
 
776610
 MetaScreenCastWindowStreamSrc *
776610
diff --git a/src/backends/meta-screen-cast.h b/src/backends/meta-screen-cast.h
776610
index 7e32b67b7..cadb6a2fe 100644
776610
--- a/src/backends/meta-screen-cast.h
776610
+++ b/src/backends/meta-screen-cast.h
776610
@@ -29,6 +29,13 @@
776610
 #include "backends/meta-dbus-session-watcher.h"
776610
 #include "meta-dbus-screen-cast.h"
776610
 
776610
+typedef enum _MetaScreenCastCursorMode
776610
+{
776610
+  META_SCREEN_CAST_CURSOR_MODE_HIDDEN = 0,
776610
+  META_SCREEN_CAST_CURSOR_MODE_EMBEDDED = 1,
776610
+  META_SCREEN_CAST_CURSOR_MODE_METADATA = 2,
776610
+} MetaScreenCastCursorMode;
776610
+
776610
 #define META_TYPE_SCREEN_CAST (meta_screen_cast_get_type ())
776610
 G_DECLARE_FINAL_TYPE (MetaScreenCast, meta_screen_cast,
776610
                       META, SCREEN_CAST,
776610
diff --git a/src/org.gnome.Mutter.ScreenCast.xml b/src/org.gnome.Mutter.ScreenCast.xml
776610
index 3cd02b6cb..953809727 100644
776610
--- a/src/org.gnome.Mutter.ScreenCast.xml
776610
+++ b/src/org.gnome.Mutter.ScreenCast.xml
776610
@@ -71,7 +71,15 @@
776610
 
776610
 	Record a single monitor.
776610
 
776610
-	Available @properties include: (none)
776610
+	Available @properties include:
776610
+
776610
+	* "cursor-mode" (u): Cursor mode. Default: 'hidden' (see below)
776610
+
776610
+	Available cursor mode values:
776610
+
776610
+	0: hidden - cursor is not included in the stream
776610
+	1: embedded - cursor is included in the framebuffer
776610
+	2: metadata - cursor is included as metadata in the PipeWire stream
776610
     -->
776610
     <method name="RecordMonitor">
776610
       <arg name="connector" type="s" direction="in" />
776610
@@ -84,7 +92,7 @@
776610
 	@properties: Properties used determining what window to select
776610
 	@stream_path: Path to the new stream object
776610
 
776610
-	Record a single window.
776610
+	Record a single window. The cursor will not be included.
776610
 
776610
 	Available @properties include:
776610
 
776610
-- 
776610
2.20.1
776610
776610
776610
From 93c2b18337a8babe340775cd979ad540f0838ab3 Mon Sep 17 00:00:00 2001
776610
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
776610
Date: Thu, 3 Jan 2019 16:40:42 +0100
776610
Subject: [PATCH 11/12] cursor-tracker: Emit `cursor-changed` after renderer
776610
 was updated
776610
776610
Otherwise the cursor retrieved via meta_cursor_renderer_get_cursor() is
776610
out of date.
776610
776610
https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
776610
---
776610
 src/backends/meta-cursor-tracker.c | 8 ++++++--
776610
 1 file changed, 6 insertions(+), 2 deletions(-)
776610
776610
diff --git a/src/backends/meta-cursor-tracker.c b/src/backends/meta-cursor-tracker.c
776610
index 060b6af3b..97e7f8cb4 100644
776610
--- a/src/backends/meta-cursor-tracker.c
776610
+++ b/src/backends/meta-cursor-tracker.c
776610
@@ -118,11 +118,15 @@ change_cursor_renderer (MetaCursorTracker *tracker)
776610
 static void
776610
 sync_cursor (MetaCursorTracker *tracker)
776610
 {
776610
-  if (update_displayed_cursor (tracker))
776610
-    g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
776610
+  gboolean cursor_changed = FALSE;
776610
+
776610
+  cursor_changed = update_displayed_cursor (tracker);
776610
 
776610
   if (update_effective_cursor (tracker))
776610
     change_cursor_renderer (tracker);
776610
+
776610
+  if (cursor_changed)
776610
+    g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
776610
 }
776610
 
776610
 static void
776610
-- 
776610
2.20.1
776610
776610
776610
From 392205b1d0728ac1636df90144c0fe091bd45624 Mon Sep 17 00:00:00 2001
776610
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
776610
Date: Thu, 3 Jan 2019 16:51:08 +0100
776610
Subject: [PATCH 12/12] screen-cast-monitor-stream-src: Only send cursor bitmap
776610
 when it changes
776610
776610
To avoid unnecessary pixel copying, only send the cursor bitmap when it
776610
changes. This also allows the receiver to know when the cursor bitmap
776610
actually changed.
776610
776610
https://gitlab.gnome.org/GNOME/mutter/merge_requests/357
776610
---
776610
 src/backends/meta-screen-cast-monitor-stream-src.c | 14 ++++++++++++++
776610
 1 file changed, 14 insertions(+)
776610
776610
diff --git a/src/backends/meta-screen-cast-monitor-stream-src.c b/src/backends/meta-screen-cast-monitor-stream-src.c
776610
index 6be477989..1d6aea242 100644
776610
--- a/src/backends/meta-screen-cast-monitor-stream-src.c
776610
+++ b/src/backends/meta-screen-cast-monitor-stream-src.c
776610
@@ -40,6 +40,8 @@ struct _MetaScreenCastMonitorStreamSrc
776610
 {
776610
   MetaScreenCastStreamSrc parent;
776610
 
776610
+  gboolean cursor_bitmap_invalid;
776610
+
776610
   gulong actors_painted_handler_id;
776610
   gulong paint_handler_id;
776610
   gulong cursor_moved_handler_id;
776610
@@ -194,6 +196,7 @@ static void
776610
 cursor_changed (MetaCursorTracker              *cursor_tracker,
776610
                 MetaScreenCastMonitorStreamSrc *monitor_src)
776610
 {
776610
+  monitor_src->cursor_bitmap_invalid = TRUE;
776610
   sync_cursor_state (monitor_src);
776610
 }
776610
 
776610
@@ -452,6 +455,16 @@ meta_screen_cast_monitor_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc
776610
   spa_meta_cursor->id = 1;
776610
   spa_meta_cursor->position.x = (int32_t) roundf (cursor_position.x);
776610
   spa_meta_cursor->position.y = (int32_t) roundf (cursor_position.y);
776610
+
776610
+  if (!monitor_src->cursor_bitmap_invalid)
776610
+    {
776610
+      spa_meta_cursor->hotspot.x = 0;
776610
+      spa_meta_cursor->hotspot.y = 0;
776610
+      spa_meta_cursor->bitmap_offset = 0;
776610
+      return;
776610
+    }
776610
+  monitor_src->cursor_bitmap_invalid = FALSE;
776610
+
776610
   spa_meta_cursor->bitmap_offset = sizeof (struct spa_meta_cursor);
776610
 
776610
   spa_meta_bitmap = SPA_MEMBER (spa_meta_cursor,
776610
@@ -551,6 +564,7 @@ meta_screen_cast_monitor_stream_src_new (MetaScreenCastMonitorStream  *monitor_s
776610
 static void
776610
 meta_screen_cast_monitor_stream_src_init (MetaScreenCastMonitorStreamSrc *monitor_src)
776610
 {
776610
+  monitor_src->cursor_bitmap_invalid = TRUE;
776610
 }
776610
 
776610
 static void
776610
-- 
776610
2.20.1
776610