From 2b2d77dc3e3db3d44e221c2e7a889ca9bc6b119d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 12 Dec 2018 11:27:16 +0100 Subject: [PATCH 01/12] cursor-tracker: Add 'cursor-moved' signal https://gitlab.gnome.org/GNOME/mutter/merge_requests/357 --- src/backends/meta-cursor-tracker.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/backends/meta-cursor-tracker.c b/src/backends/meta-cursor-tracker.c index 1a35019353f..7ff0e7b0ce2 100644 --- a/src/backends/meta-cursor-tracker.c +++ b/src/backends/meta-cursor-tracker.c @@ -48,6 +48,7 @@ G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT); enum { CURSOR_CHANGED, + CURSOR_MOVED, LAST_SIGNAL }; @@ -158,6 +159,15 @@ meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass) 0, NULL, NULL, NULL, G_TYPE_NONE, 0); + + signals[CURSOR_MOVED] = g_signal_new ("cursor-moved", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 2, + G_TYPE_FLOAT, + G_TYPE_FLOAT); } /** @@ -342,6 +352,8 @@ meta_cursor_tracker_update_position (MetaCursorTracker *tracker, g_assert (meta_is_wayland_compositor ()); meta_cursor_renderer_set_position (cursor_renderer, new_x, new_y); + + g_signal_emit (tracker, signals[CURSOR_MOVED], 0, new_x, new_y); } static void -- GitLab From 50071303afd47cbb67e6738fc8c0acb767368c3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 21 Dec 2018 17:28:33 +0100 Subject: [PATCH 02/12] clutter/stage: Add clutter_stage_is_redraw_queued() API This will be used by the screen casting code to check whether it should wait for a frame before reading cursor state, or send only the cursor update, if no redraw is queued. https://gitlab.gnome.org/GNOME/mutter/merge_requests/357 --- clutter/clutter/clutter-stage.c | 11 +++++++++++ clutter/clutter/clutter-stage.h | 3 +++ 2 files changed, 14 insertions(+) diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c index d1107149e26..8dc7ebc4ecc 100644 --- a/clutter/clutter/clutter-stage.c +++ b/clutter/clutter/clutter-stage.c @@ -3731,6 +3731,17 @@ clutter_stage_ensure_redraw (ClutterStage *stage) _clutter_master_clock_start_running (master_clock); } +/** + * clutter_stage_is_redraw_queued: (skip) + */ +gboolean +clutter_stage_is_redraw_queued (ClutterStage *stage) +{ + ClutterStagePrivate *priv = stage->priv; + + return priv->redraw_pending; +} + /** * clutter_stage_queue_redraw: * @stage: the #ClutterStage diff --git a/clutter/clutter/clutter-stage.h b/clutter/clutter/clutter-stage.h index 643f8d7b371..ab1ab92fa4e 100644 --- a/clutter/clutter/clutter-stage.h +++ b/clutter/clutter/clutter-stage.h @@ -250,6 +250,9 @@ void clutter_stage_ensure_viewport (ClutterStage CLUTTER_EXPORT void clutter_stage_ensure_redraw (ClutterStage *stage); +CLUTTER_EXPORT +gboolean clutter_stage_is_redraw_queued (ClutterStage *stage); + #ifdef CLUTTER_ENABLE_EXPERIMENTAL_API CLUTTER_EXPORT void clutter_stage_set_sync_delay (ClutterStage *stage, -- GitLab From 08229a6f5d72683ec780edf5acf101ab0bed8867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 12 Dec 2018 11:32:11 +0100 Subject: [PATCH 03/12] screen-cast-monitor-stream: Don't pass monitor manager when creating It can be fetched indirectly from the monitor already. https://gitlab.gnome.org/GNOME/mutter/merge_requests/357 --- src/backends/meta-screen-cast-monitor-stream.c | 11 ++++++----- src/backends/meta-screen-cast-monitor-stream.h | 9 ++++----- src/backends/meta-screen-cast-session.c | 1 - 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/backends/meta-screen-cast-monitor-stream.c b/src/backends/meta-screen-cast-monitor-stream.c index df43f977c9a..5a816e4df7a 100644 --- a/src/backends/meta-screen-cast-monitor-stream.c +++ b/src/backends/meta-screen-cast-monitor-stream.c @@ -105,12 +105,13 @@ meta_screen_cast_monitor_stream_get_monitor (MetaScreenCastMonitorStream *monito } MetaScreenCastMonitorStream * -meta_screen_cast_monitor_stream_new (GDBusConnection *connection, - MetaMonitorManager *monitor_manager, - MetaMonitor *monitor, - ClutterStage *stage, - GError **error) +meta_screen_cast_monitor_stream_new (GDBusConnection *connection, + MetaMonitor *monitor, + ClutterStage *stage, + GError **error) { + MetaGpu *gpu = meta_monitor_get_gpu (monitor); + MetaMonitorManager *monitor_manager = meta_gpu_get_monitor_manager (gpu); MetaScreenCastMonitorStream *monitor_stream; if (!meta_monitor_is_active (monitor)) diff --git a/src/backends/meta-screen-cast-monitor-stream.h b/src/backends/meta-screen-cast-monitor-stream.h index fbf3c77c307..1d24de93a16 100644 --- a/src/backends/meta-screen-cast-monitor-stream.h +++ b/src/backends/meta-screen-cast-monitor-stream.h @@ -34,11 +34,10 @@ G_DECLARE_FINAL_TYPE (MetaScreenCastMonitorStream, META, SCREEN_CAST_MONITOR_STREAM, MetaScreenCastStream) -MetaScreenCastMonitorStream * meta_screen_cast_monitor_stream_new (GDBusConnection *connection, - MetaMonitorManager *monitor_manager, - MetaMonitor *monitor, - ClutterStage *stage, - GError **error); +MetaScreenCastMonitorStream * meta_screen_cast_monitor_stream_new (GDBusConnection *connection, + MetaMonitor *monitor, + ClutterStage *stage, + GError **error); ClutterStage * meta_screen_cast_monitor_stream_get_stage (MetaScreenCastMonitorStream *monitor_stream); diff --git a/src/backends/meta-screen-cast-session.c b/src/backends/meta-screen-cast-session.c index d0f5a79d919..3ba59037fb4 100644 --- a/src/backends/meta-screen-cast-session.c +++ b/src/backends/meta-screen-cast-session.c @@ -301,7 +301,6 @@ handle_record_monitor (MetaDBusScreenCastSession *skeleton, stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); monitor_stream = meta_screen_cast_monitor_stream_new (connection, - monitor_manager, monitor, stage, &error); -- GitLab From 0da0207eed385f82996a9c19c2b7f888de2c0bd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 12 Dec 2018 11:35:58 +0100 Subject: [PATCH 04/12] screen-cast: Add getters to fetch object owners MetaBackend owns MetaScreenCast which owns MetaScreenCastSession which owns MetaScreenCastStream. Make it possible to fetch objects in the oppositev direction too. https://gitlab.gnome.org/GNOME/mutter/merge_requests/357 --- src/backends/meta-backend-types.h | 4 +++ src/backends/meta-backend.c | 3 +- .../meta-screen-cast-monitor-stream.c | 10 ++++--- .../meta-screen-cast-monitor-stream.h | 10 ++++--- src/backends/meta-screen-cast-session.c | 15 ++++++++-- src/backends/meta-screen-cast-session.h | 2 ++ src/backends/meta-screen-cast-stream.c | 30 +++++++++++++++++++ src/backends/meta-screen-cast-stream.h | 4 +++ src/backends/meta-screen-cast-window-stream.c | 8 +++-- src/backends/meta-screen-cast-window-stream.h | 7 +++-- src/backends/meta-screen-cast.c | 15 ++++++++-- src/backends/meta-screen-cast.h | 6 +++- 12 files changed, 94 insertions(+), 20 deletions(-) diff --git a/src/backends/meta-backend-types.h b/src/backends/meta-backend-types.h index 66b6ae23849..eb982d73eb2 100644 --- a/src/backends/meta-backend-types.h +++ b/src/backends/meta-backend-types.h @@ -49,4 +49,8 @@ typedef struct _MetaTileInfo MetaTileInfo; typedef struct _MetaRenderer MetaRenderer; typedef struct _MetaRendererView MetaRendererView; +typedef struct _MetaScreenCast MetaScreenCast; +typedef struct _MetaScreenCastSession MetaScreenCastSession; +typedef struct _MetaScreenCastStream MetaScreenCastStream; + #endif /* META_BACKEND_TYPE_H */ diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c index 8987da1e3c7..c527114bee2 100644 --- a/src/backends/meta-backend.c +++ b/src/backends/meta-backend.c @@ -504,7 +504,8 @@ meta_backend_real_post_init (MetaBackend *backend) priv->remote_access_controller = g_object_new (META_TYPE_REMOTE_ACCESS_CONTROLLER, NULL); priv->dbus_session_watcher = g_object_new (META_TYPE_DBUS_SESSION_WATCHER, NULL); - priv->screen_cast = meta_screen_cast_new (priv->dbus_session_watcher); + priv->screen_cast = meta_screen_cast_new (backend, + priv->dbus_session_watcher); priv->remote_desktop = meta_remote_desktop_new (priv->dbus_session_watcher); #endif /* HAVE_REMOTE_DESKTOP */ diff --git a/src/backends/meta-screen-cast-monitor-stream.c b/src/backends/meta-screen-cast-monitor-stream.c index 5a816e4df7a..a6bed1b5224 100644 --- a/src/backends/meta-screen-cast-monitor-stream.c +++ b/src/backends/meta-screen-cast-monitor-stream.c @@ -105,10 +105,11 @@ meta_screen_cast_monitor_stream_get_monitor (MetaScreenCastMonitorStream *monito } MetaScreenCastMonitorStream * -meta_screen_cast_monitor_stream_new (GDBusConnection *connection, - MetaMonitor *monitor, - ClutterStage *stage, - GError **error) +meta_screen_cast_monitor_stream_new (MetaScreenCastSession *session, + GDBusConnection *connection, + MetaMonitor *monitor, + ClutterStage *stage, + GError **error) { MetaGpu *gpu = meta_monitor_get_gpu (monitor); MetaMonitorManager *monitor_manager = meta_gpu_get_monitor_manager (gpu); @@ -123,6 +124,7 @@ meta_screen_cast_monitor_stream_new (GDBusConnection *connection, monitor_stream = g_initable_new (META_TYPE_SCREEN_CAST_MONITOR_STREAM, NULL, error, + "session", session, "connection", connection, "monitor", monitor, NULL); diff --git a/src/backends/meta-screen-cast-monitor-stream.h b/src/backends/meta-screen-cast-monitor-stream.h index 1d24de93a16..98f160c8882 100644 --- a/src/backends/meta-screen-cast-monitor-stream.h +++ b/src/backends/meta-screen-cast-monitor-stream.h @@ -27,6 +27,7 @@ #include "backends/meta-monitor-manager-private.h" #include "backends/meta-screen-cast-stream.h" +#include "backends/meta-screen-cast.h" #define META_TYPE_SCREEN_CAST_MONITOR_STREAM (meta_screen_cast_monitor_stream_get_type ()) G_DECLARE_FINAL_TYPE (MetaScreenCastMonitorStream, @@ -34,10 +35,11 @@ G_DECLARE_FINAL_TYPE (MetaScreenCastMonitorStream, META, SCREEN_CAST_MONITOR_STREAM, MetaScreenCastStream) -MetaScreenCastMonitorStream * meta_screen_cast_monitor_stream_new (GDBusConnection *connection, - MetaMonitor *monitor, - ClutterStage *stage, - GError **error); +MetaScreenCastMonitorStream * meta_screen_cast_monitor_stream_new (MetaScreenCastSession *session, + GDBusConnection *connection, + MetaMonitor *monitor, + ClutterStage *stage, + GError **error); ClutterStage * meta_screen_cast_monitor_stream_get_stage (MetaScreenCastMonitorStream *monitor_stream); diff --git a/src/backends/meta-screen-cast-session.c b/src/backends/meta-screen-cast-session.c index 3ba59037fb4..6a8f2d3284d 100644 --- a/src/backends/meta-screen-cast-session.c +++ b/src/backends/meta-screen-cast-session.c @@ -38,6 +38,8 @@ struct _MetaScreenCastSession { MetaDBusScreenCastSessionSkeleton parent; + MetaScreenCast *screen_cast; + char *peer_name; MetaScreenCastSessionType session_type; @@ -159,6 +161,12 @@ meta_screen_cast_session_get_stream (MetaScreenCastSession *session, return NULL; } +MetaScreenCast * +meta_screen_cast_session_get_screen_cast (MetaScreenCastSession *session) +{ + return session->screen_cast; +} + char * meta_screen_cast_session_get_object_path (MetaScreenCastSession *session) { @@ -300,7 +308,8 @@ handle_record_monitor (MetaDBusScreenCastSession *skeleton, stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); - monitor_stream = meta_screen_cast_monitor_stream_new (connection, + monitor_stream = meta_screen_cast_monitor_stream_new (session, + connection, monitor, stage, &error); @@ -381,7 +390,8 @@ handle_record_window (MetaDBusScreenCastSession *skeleton, interface_skeleton = G_DBUS_INTERFACE_SKELETON (skeleton); connection = g_dbus_interface_skeleton_get_connection (interface_skeleton); - window_stream = meta_screen_cast_window_stream_new (connection, + window_stream = meta_screen_cast_window_stream_new (session, + connection, window, &error); if (!window_stream) @@ -441,6 +451,7 @@ meta_screen_cast_session_new (MetaScreenCast *screen_cast, static unsigned int global_session_number = 0; session = g_object_new (META_TYPE_SCREEN_CAST_SESSION, NULL); + session->screen_cast = screen_cast; session->session_type = session_type; session->peer_name = g_strdup (peer_name); session->object_path = diff --git a/src/backends/meta-screen-cast-session.h b/src/backends/meta-screen-cast-session.h index ac0a31a165b..105a6509895 100644 --- a/src/backends/meta-screen-cast-session.h +++ b/src/backends/meta-screen-cast-session.h @@ -60,4 +60,6 @@ void meta_screen_cast_session_close (MetaScreenCastSession *session); MetaScreenCastStream * meta_screen_cast_session_get_stream (MetaScreenCastSession *session, const char *path); +MetaScreenCast * meta_screen_cast_session_get_screen_cast (MetaScreenCastSession *session); + #endif /* META_SCREEN_CAST_SESSION_H */ diff --git a/src/backends/meta-screen-cast-stream.c b/src/backends/meta-screen-cast-stream.c index 97ee4bfcf37..875ada01aa8 100644 --- a/src/backends/meta-screen-cast-stream.c +++ b/src/backends/meta-screen-cast-stream.c @@ -24,12 +24,15 @@ #include "backends/meta-screen-cast-stream.h" +#include "backends/meta-screen-cast-session.h" + #define META_SCREEN_CAST_STREAM_DBUS_PATH "/org/gnome/Mutter/ScreenCast/Stream" enum { PROP_0, + PROP_SESSION, PROP_CONNECTION, }; @@ -44,6 +47,8 @@ static guint signals[N_SIGNALS]; typedef struct _MetaScreenCastStreamPrivate { + MetaScreenCastSession *session; + GDBusConnection *connection; char *object_path; @@ -97,6 +102,15 @@ on_stream_src_ready (MetaScreenCastStreamSrc *src, meta_dbus_screen_cast_stream_emit_pipewire_stream_added (skeleton, node_id); } +MetaScreenCastSession * +meta_screen_cast_stream_get_session (MetaScreenCastStream *stream) +{ + MetaScreenCastStreamPrivate *priv = + meta_screen_cast_stream_get_instance_private (stream); + + return priv->session; +} + gboolean meta_screen_cast_stream_start (MetaScreenCastStream *stream, GError **error) @@ -162,6 +176,9 @@ meta_screen_cast_stream_set_property (GObject *object, switch (prop_id) { + case PROP_SESSION: + priv->session = g_value_get_object (value); + break; case PROP_CONNECTION: priv->connection = g_value_get_object (value); break; @@ -182,6 +199,9 @@ meta_screen_cast_stream_get_property (GObject *object, switch (prop_id) { + case PROP_SESSION: + g_value_set_object (value, priv->session); + break; case PROP_CONNECTION: g_value_set_object (value, priv->connection); break; @@ -256,6 +276,16 @@ meta_screen_cast_stream_class_init (MetaScreenCastStreamClass *klass) object_class->set_property = meta_screen_cast_stream_set_property; object_class->get_property = meta_screen_cast_stream_get_property; + g_object_class_install_property (object_class, + PROP_SESSION, + g_param_spec_object ("session", + "session", + "MetaScreenSession", + META_TYPE_SCREEN_CAST_SESSION, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, PROP_CONNECTION, g_param_spec_object ("connection", diff --git a/src/backends/meta-screen-cast-stream.h b/src/backends/meta-screen-cast-stream.h index fd7930c4c29..d394dbb4dab 100644 --- a/src/backends/meta-screen-cast-stream.h +++ b/src/backends/meta-screen-cast-stream.h @@ -26,6 +26,8 @@ #include #include "backends/meta-screen-cast-stream-src.h" +#include "backends/meta-screen-cast.h" + #include "meta-dbus-screen-cast.h" #define META_TYPE_SCREEN_CAST_STREAM (meta_screen_cast_stream_get_type ()) @@ -48,6 +50,8 @@ struct _MetaScreenCastStreamClass double *y); }; +MetaScreenCastSession * meta_screen_cast_stream_get_session (MetaScreenCastStream *stream); + gboolean meta_screen_cast_stream_start (MetaScreenCastStream *stream, GError **error); diff --git a/src/backends/meta-screen-cast-window-stream.c b/src/backends/meta-screen-cast-window-stream.c index 1200a39eff5..4c922711645 100644 --- a/src/backends/meta-screen-cast-window-stream.c +++ b/src/backends/meta-screen-cast-window-stream.c @@ -71,9 +71,10 @@ meta_screen_cast_window_stream_get_height (MetaScreenCastWindowStream *window_st } MetaScreenCastWindowStream * -meta_screen_cast_window_stream_new (GDBusConnection *connection, - MetaWindow *window, - GError **error) +meta_screen_cast_window_stream_new (MetaScreenCastSession *session, + GDBusConnection *connection, + MetaWindow *window, + GError **error) { MetaScreenCastWindowStream *window_stream; MetaLogicalMonitor *logical_monitor; @@ -90,6 +91,7 @@ meta_screen_cast_window_stream_new (GDBusConnection *connection, window_stream = g_initable_new (META_TYPE_SCREEN_CAST_WINDOW_STREAM, NULL, error, + "session", session, "connection", connection, "window", window, NULL); diff --git a/src/backends/meta-screen-cast-window-stream.h b/src/backends/meta-screen-cast-window-stream.h index 6726ef87317..3799be98a2c 100644 --- a/src/backends/meta-screen-cast-window-stream.h +++ b/src/backends/meta-screen-cast-window-stream.h @@ -32,9 +32,10 @@ G_DECLARE_FINAL_TYPE (MetaScreenCastWindowStream, META, SCREEN_CAST_WINDOW_STREAM, MetaScreenCastStream) -MetaScreenCastWindowStream * meta_screen_cast_window_stream_new (GDBusConnection *connection, - MetaWindow *window, - GError **error); +MetaScreenCastWindowStream * meta_screen_cast_window_stream_new (MetaScreenCastSession *session, + GDBusConnection *connection, + MetaWindow *window, + GError **error); MetaWindow * meta_screen_cast_window_stream_get_window (MetaScreenCastWindowStream *window_stream); int meta_screen_cast_window_stream_get_width (MetaScreenCastWindowStream *window_stream); diff --git a/src/backends/meta-screen-cast.c b/src/backends/meta-screen-cast.c index bebef5b4ee6..ebf6c18b395 100644 --- a/src/backends/meta-screen-cast.c +++ b/src/backends/meta-screen-cast.c @@ -43,6 +43,7 @@ struct _MetaScreenCast GList *sessions; MetaDbusSessionWatcher *session_watcher; + MetaBackend *backend; }; static void @@ -62,12 +63,20 @@ meta_screen_cast_get_connection (MetaScreenCast *screen_cast) return g_dbus_interface_skeleton_get_connection (interface_skeleton); } +MetaBackend * +meta_screen_cast_get_backend (MetaScreenCast *screen_cast) +{ + return screen_cast->backend; +} + static gboolean register_remote_desktop_screen_cast_session (MetaScreenCastSession *session, const char *remote_desktop_session_id, GError **error) { - MetaBackend *backend = meta_get_backend (); + MetaScreenCast *screen_cast = + meta_screen_cast_session_get_screen_cast (session); + MetaBackend *backend = meta_screen_cast_get_backend (screen_cast); MetaRemoteDesktop *remote_desktop = meta_backend_get_remote_desktop (backend); MetaRemoteDesktopSession *remote_desktop_session; @@ -244,11 +253,13 @@ meta_screen_cast_finalize (GObject *object) } MetaScreenCast * -meta_screen_cast_new (MetaDbusSessionWatcher *session_watcher) +meta_screen_cast_new (MetaBackend *backend, + MetaDbusSessionWatcher *session_watcher) { MetaScreenCast *screen_cast; screen_cast = g_object_new (META_TYPE_SCREEN_CAST, NULL); + screen_cast->backend = backend; screen_cast->session_watcher = session_watcher; return screen_cast; diff --git a/src/backends/meta-screen-cast.h b/src/backends/meta-screen-cast.h index a28a0aa07af..a5450ae0ec9 100644 --- a/src/backends/meta-screen-cast.h +++ b/src/backends/meta-screen-cast.h @@ -25,6 +25,7 @@ #include +#include "backends/meta-backend-private.h" #include "backends/meta-dbus-session-watcher.h" #include "meta-dbus-screen-cast.h" @@ -36,6 +37,9 @@ G_DECLARE_FINAL_TYPE (MetaScreenCast, meta_screen_cast, GDBusConnection * meta_screen_cast_get_connection (MetaScreenCast *screen_cast); -MetaScreenCast * meta_screen_cast_new (MetaDbusSessionWatcher *session_watcher); +MetaBackend * meta_screen_cast_get_backend (MetaScreenCast *screen_cast); + +MetaScreenCast * meta_screen_cast_new (MetaBackend *backend, + MetaDbusSessionWatcher *session_watcher); #endif /* META_SCREEN_CAST_H */ -- GitLab From bd97b11414467166b1dffcd82dd4b15b5fc1abe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 12 Dec 2018 11:37:13 +0100 Subject: [PATCH 05/12] renderer: Add API to get view from logical monitor Will be used to get the view scale for a logical monitor, which is necessary for passing cursor sprites via PipeWire. https://gitlab.gnome.org/GNOME/mutter/merge_requests/357 --- src/backends/meta-renderer.c | 18 ++++++++++++++++++ src/backends/meta-renderer.h | 3 +++ 2 files changed, 21 insertions(+) diff --git a/src/backends/meta-renderer.c b/src/backends/meta-renderer.c index 85d3984edc9..28637437ba6 100644 --- a/src/backends/meta-renderer.c +++ b/src/backends/meta-renderer.c @@ -142,6 +142,24 @@ meta_renderer_get_views (MetaRenderer *renderer) return priv->views; } +MetaRendererView * +meta_renderer_get_view_from_logical_monitor (MetaRenderer *renderer, + MetaLogicalMonitor *logical_monitor) +{ + GList *l; + + for (l = meta_renderer_get_views (renderer); l; l = l->next) + { + MetaRendererView *view = l->data; + + if (meta_renderer_view_get_logical_monitor (view) == + logical_monitor) + return view; + } + + return NULL; +} + static void meta_renderer_finalize (GObject *object) { diff --git a/src/backends/meta-renderer.h b/src/backends/meta-renderer.h index ba91a2584cd..b6df4f17706 100644 --- a/src/backends/meta-renderer.h +++ b/src/backends/meta-renderer.h @@ -53,4 +53,7 @@ void meta_renderer_set_legacy_view (MetaRenderer *renderer, GList * meta_renderer_get_views (MetaRenderer *renderer); +MetaRendererView * meta_renderer_get_view_from_logical_monitor (MetaRenderer *renderer, + MetaLogicalMonitor *logical_monitor); + #endif /* META_RENDERER_H */ -- GitLab From 7ac20831344411f72f0ae54c689da571204a6614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 12 Dec 2018 11:39:00 +0100 Subject: [PATCH 06/12] backends/stage: Fix minor style issue https://gitlab.gnome.org/GNOME/mutter/merge_requests/357 --- src/backends/meta-stage.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/backends/meta-stage.c b/src/backends/meta-stage.c index 9b1dadab77e..2b6f8edc548 100644 --- a/src/backends/meta-stage.c +++ b/src/backends/meta-stage.c @@ -30,7 +30,8 @@ #include "meta/meta-monitor-manager.h" #include "meta/util.h" -struct _MetaOverlay { +struct _MetaOverlay +{ gboolean enabled; CoglPipeline *pipeline; -- GitLab From ed5c1f433b5821a4e5e88adfcd3e6ce12b83009b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 12 Dec 2018 11:39:18 +0100 Subject: [PATCH 07/12] backends/stage: Emit signal between painting actors and overlays Will be used by screen casting for embedding the cursor separately, or not including at all. https://gitlab.gnome.org/GNOME/mutter/merge_requests/357 --- src/backends/meta-stage.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/backends/meta-stage.c b/src/backends/meta-stage.c index 2b6f8edc548..c009f102233 100644 --- a/src/backends/meta-stage.c +++ b/src/backends/meta-stage.c @@ -30,6 +30,15 @@ #include "meta/meta-monitor-manager.h" #include "meta/util.h" +enum +{ + ACTORS_PAINTED, + + N_SIGNALS +}; + +static guint signals[N_SIGNALS]; + struct _MetaOverlay { gboolean enabled; @@ -142,6 +151,8 @@ meta_stage_paint (ClutterActor *actor) CLUTTER_ACTOR_CLASS (meta_stage_parent_class)->paint (actor); + g_signal_emit (stage, signals[ACTORS_PAINTED], 0); + for (l = stage->overlays; l; l = l->next) meta_overlay_paint (l->data); } @@ -179,6 +190,13 @@ meta_stage_class_init (MetaStageClass *klass) stage_class->activate = meta_stage_activate; stage_class->deactivate = meta_stage_deactivate; + + signals[ACTORS_PAINTED] = g_signal_new ("actors-painted", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); } static void -- GitLab From 328eff735294e39b4eaeafa9711d8d4d0c31e39f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 12 Dec 2018 15:29:21 +0100 Subject: [PATCH 08/12] screen-cast/monitor-stream-src: Copy content before cursor is drawn To get a consistent behaviour no matter whether HW cursors are in use or not, make sure to copy the framebuffer content before the stage overlays (cursor sprite textures) are painted. https://gitlab.gnome.org/GNOME/mutter/merge_requests/357 --- src/backends/meta-screen-cast-monitor-stream-src.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/backends/meta-screen-cast-monitor-stream-src.c b/src/backends/meta-screen-cast-monitor-stream-src.c index 1118daadd75..2aad3aa0cf7 100644 --- a/src/backends/meta-screen-cast-monitor-stream-src.c +++ b/src/backends/meta-screen-cast-monitor-stream-src.c @@ -35,7 +35,7 @@ struct _MetaScreenCastMonitorStreamSrc { MetaScreenCastStreamSrc parent; - gulong stage_painted_handler_id; + gulong actors_painted_handler_id; }; G_DEFINE_TYPE (MetaScreenCastMonitorStreamSrc, @@ -110,8 +110,8 @@ meta_screen_cast_monitor_stream_src_enable (MetaScreenCastStreamSrc *src) ClutterStage *stage; stage = get_stage (monitor_src); - monitor_src->stage_painted_handler_id = - g_signal_connect_after (stage, "paint", + monitor_src->actors_painted_handler_id = + g_signal_connect_after (stage, "actors-painted", G_CALLBACK (stage_painted), monitor_src); clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); @@ -125,8 +125,8 @@ meta_screen_cast_monitor_stream_src_disable (MetaScreenCastStreamSrc *src) ClutterStage *stage; stage = get_stage (monitor_src); - g_signal_handler_disconnect (stage, monitor_src->stage_painted_handler_id); - monitor_src->stage_painted_handler_id = 0; + g_signal_handler_disconnect (stage, monitor_src->actors_painted_handler_id); + monitor_src->actors_painted_handler_id = 0; } static void -- GitLab From 79d99cbe3feda7b609c67a3d1fc46c289ac23bfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 13 Sep 2018 11:28:51 +0200 Subject: [PATCH 09/12] cursor-renderer: Add API to allow inhibiting HW cursor There may be reasons to temporarly inhibit the HW cursor under certain circumstances. Allow adding such inhibitations by adding API to the cursor renderer to allow API users to add generic inhibitors with whatever logic is deemed necessary. https://gitlab.gnome.org/GNOME/mutter/merge_requests/357 --- src/backends/meta-cursor-renderer.c | 62 +++++++++++++++++++ src/backends/meta-cursor-renderer.h | 22 +++++++ .../native/meta-cursor-renderer-native.c | 4 ++ 3 files changed, 88 insertions(+) diff --git a/src/backends/meta-cursor-renderer.c b/src/backends/meta-cursor-renderer.c index 1f76206f84f..34a7f91d855 100644 --- a/src/backends/meta-cursor-renderer.c +++ b/src/backends/meta-cursor-renderer.c @@ -34,6 +34,9 @@ #include "meta/meta-backend.h" #include "meta/util.h" +G_DEFINE_INTERFACE (MetaHwCursorInhibitor, meta_hw_cursor_inhibitor, + G_TYPE_OBJECT) + struct _MetaCursorRendererPrivate { float current_x; @@ -43,6 +46,8 @@ struct _MetaCursorRendererPrivate MetaOverlay *stage_overlay; gboolean handled_by_backend; guint post_paint_func_id; + + GList *hw_cursor_inhibitors; }; typedef struct _MetaCursorRendererPrivate MetaCursorRendererPrivate; @@ -54,6 +59,21 @@ static guint signals[LAST_SIGNAL]; G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRenderer, meta_cursor_renderer, G_TYPE_OBJECT); +static gboolean +meta_hw_cursor_inhibitor_is_cursor_sprite_inhibited (MetaHwCursorInhibitor *inhibitor, + MetaCursorSprite *cursor_sprite) +{ + MetaHwCursorInhibitorInterface *iface = + META_HW_CURSOR_INHIBITOR_GET_IFACE (inhibitor); + + return iface->is_cursor_sprite_inhibited (inhibitor, cursor_sprite); +} + +static void +meta_hw_cursor_inhibitor_default_init (MetaHwCursorInhibitorInterface *iface) +{ +} + void meta_cursor_renderer_emit_painted (MetaCursorRenderer *renderer, MetaCursorSprite *cursor_sprite) @@ -282,3 +302,45 @@ meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer) return priv->displayed_cursor; } + +void +meta_cursor_renderer_add_hw_cursor_inhibitor (MetaCursorRenderer *renderer, + MetaHwCursorInhibitor *inhibitor) +{ + MetaCursorRendererPrivate *priv = + meta_cursor_renderer_get_instance_private (renderer); + + priv->hw_cursor_inhibitors = g_list_prepend (priv->hw_cursor_inhibitors, + inhibitor); +} + +void +meta_cursor_renderer_remove_hw_cursor_inhibitor (MetaCursorRenderer *renderer, + MetaHwCursorInhibitor *inhibitor) +{ + MetaCursorRendererPrivate *priv = + meta_cursor_renderer_get_instance_private (renderer); + + priv->hw_cursor_inhibitors = g_list_remove (priv->hw_cursor_inhibitors, + inhibitor); +} + +gboolean +meta_cursor_renderer_is_hw_cursors_inhibited (MetaCursorRenderer *renderer, + MetaCursorSprite *cursor_sprite) +{ + MetaCursorRendererPrivate *priv = + meta_cursor_renderer_get_instance_private (renderer); + GList *l; + + for (l = priv->hw_cursor_inhibitors; l; l = l->next) + { + MetaHwCursorInhibitor *inhibitor = l->data; + + if (meta_hw_cursor_inhibitor_is_cursor_sprite_inhibited (inhibitor, + cursor_sprite)) + return TRUE; + } + + return FALSE; +} diff --git a/src/backends/meta-cursor-renderer.h b/src/backends/meta-cursor-renderer.h index e1d5f8d4227..60f1dbe1585 100644 --- a/src/backends/meta-cursor-renderer.h +++ b/src/backends/meta-cursor-renderer.h @@ -27,8 +27,21 @@ #include +#include "backends/meta-backend-types.h" #include "backends/meta-cursor.h" +#define META_TYPE_HW_CURSOR_INHIBITOR (meta_hw_cursor_inhibitor_get_type ()) +G_DECLARE_INTERFACE (MetaHwCursorInhibitor, meta_hw_cursor_inhibitor, + META, HW_CURSOR_INHIBITOR, GObject) + +struct _MetaHwCursorInhibitorInterface +{ + GTypeInterface parent_iface; + + gboolean (* is_cursor_sprite_inhibited) (MetaHwCursorInhibitor *inhibitor, + MetaCursorSprite *cursor_sprite); +}; + #define META_TYPE_CURSOR_RENDERER (meta_cursor_renderer_get_type ()) G_DECLARE_DERIVABLE_TYPE (MetaCursorRenderer, meta_cursor_renderer, META, CURSOR_RENDERER, GObject); @@ -54,6 +67,15 @@ void meta_cursor_renderer_force_update (MetaCursorRenderer *renderer); MetaCursorSprite * meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer); +void meta_cursor_renderer_add_hw_cursor_inhibitor (MetaCursorRenderer *renderer, + MetaHwCursorInhibitor *inhibitor); + +void meta_cursor_renderer_remove_hw_cursor_inhibitor (MetaCursorRenderer *renderer, + MetaHwCursorInhibitor *inhibitor); + +gboolean meta_cursor_renderer_is_hw_cursors_inhibited (MetaCursorRenderer *renderer, + MetaCursorSprite *cursor_sprite); + ClutterRect meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer, MetaCursorSprite *cursor_sprite); diff --git a/src/backends/native/meta-cursor-renderer-native.c b/src/backends/native/meta-cursor-renderer-native.c index 4fd7b1736cc..d325483449d 100644 --- a/src/backends/native/meta-cursor-renderer-native.c +++ b/src/backends/native/meta-cursor-renderer-native.c @@ -586,6 +586,10 @@ should_have_hw_cursor (MetaCursorRenderer *renderer, if (!cursor_sprite) return FALSE; + if (meta_cursor_renderer_is_hw_cursors_inhibited (renderer, + cursor_sprite)) + return FALSE; + for (l = gpus; l; l = l->next) { MetaGpuKms *gpu_kms = l->data; -- GitLab From 4e402b397267169e578005cd89bb5bbdaf70853b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 14 Dec 2018 17:47:57 +0100 Subject: [PATCH 10/12] screen-cast: Add 'cursor-mode' to allow decoupled cursor updates The 'cursor-mode', which currently is limited to RecordMonitor(), allows the user to either do screen casts where the cursor is hidden, embedded in the framebuffer, or sent as PipeWire stream metadata. The latter allows the user to get cursor updates sent, including the cursor sprite, without requiring a stage paint each frame. Currently this is done by using the cursor sprite texture, and either reading directly from, or drawing to an offscreen framebuffer which is read from instead, in case the texture is scaled. https://gitlab.gnome.org/GNOME/mutter/merge_requests/357 --- .gitlab-ci/Dockerfile | 3 + meson.build | 2 +- .../meta-screen-cast-monitor-stream-src.c | 416 +++++++++++++++++- .../meta-screen-cast-monitor-stream.c | 12 +- .../meta-screen-cast-monitor-stream.h | 11 +- src/backends/meta-screen-cast-session.c | 31 ++ src/backends/meta-screen-cast-stream-src.c | 128 ++++-- src/backends/meta-screen-cast-stream-src.h | 24 +- src/backends/meta-screen-cast-stream.c | 30 ++ src/backends/meta-screen-cast-stream.h | 2 + .../meta-screen-cast-window-stream-src.c | 4 +- src/backends/meta-screen-cast.h | 7 + src/org.gnome.Mutter.ScreenCast.xml | 12 +- 13 files changed, 625 insertions(+), 57 deletions(-) diff --git a/.gitlab-ci/Dockerfile b/.gitlab-ci/Dockerfile index 29db895f9fc..43cafa1aea2 100644 --- a/.gitlab-ci/Dockerfile +++ b/.gitlab-ci/Dockerfile @@ -13,5 +13,8 @@ RUN dnf -y update && dnf -y upgrade && \ # Unpackaged versions dnf install -y https://copr-be.cloud.fedoraproject.org/results/jadahl/mutter-ci/fedora-29-x86_64/00836095-gsettings-desktop-schemas/gsettings-desktop-schemas-3.30.1-1.20181206git918efdd69be53.fc29.x86_64.rpm https://copr-be.cloud.fedoraproject.org/results/jadahl/mutter-ci/fedora-29-x86_64/00836095-gsettings-desktop-schemas/gsettings-desktop-schemas-devel-3.30.1-1.20181206git918efdd69be53.fc29.x86_64.rpm && \ + # Packages not yet in stable + dnf install -y https://kojipkgs.fedoraproject.org//packages/pipewire/0.2.5/1.fc29/x86_64/pipewire-0.2.5-1.fc29.x86_64.rpm https://kojipkgs.fedoraproject.org//packages/pipewire/0.2.5/1.fc29/x86_64/pipewire-devel-0.2.5-1.fc29.x86_64.rpm https://kojipkgs.fedoraproject.org//packages/pipewire/0.2.5/1.fc29/x86_64/pipewire-libs-0.2.5-1.fc29.x86_64.rpm && \ + dnf install -y intltool redhat-rpm-config make && \ dnf clean all diff --git a/meson.build b/meson.build index 8d8f4da7bab..be1b829a3b4 100644 --- a/meson.build +++ b/meson.build @@ -43,7 +43,7 @@ libinput_req = '>= 1.4' gbm_req = '>= 10.3' # screen cast version requirements -libpipewire_req = '>= 0.2.2' +libpipewire_req = '>= 0.2.5' gnome = import('gnome') pkg = import('pkgconfig') diff --git a/src/backends/meta-screen-cast-monitor-stream-src.c b/src/backends/meta-screen-cast-monitor-stream-src.c index 2aad3aa0cf7..50ed6c519d1 100644 --- a/src/backends/meta-screen-cast-monitor-stream-src.c +++ b/src/backends/meta-screen-cast-monitor-stream-src.c @@ -24,23 +24,36 @@ #include "backends/meta-screen-cast-monitor-stream-src.h" +#include + #include "backends/meta-backend-private.h" +#include "backends/meta-cursor-tracker-private.h" #include "backends/meta-logical-monitor.h" #include "backends/meta-monitor.h" #include "backends/meta-screen-cast-monitor-stream.h" +#include "backends/meta-screen-cast-session.h" #include "clutter/clutter.h" #include "clutter/clutter-mutter.h" +#include "core/boxes-private.h" struct _MetaScreenCastMonitorStreamSrc { MetaScreenCastStreamSrc parent; gulong actors_painted_handler_id; + gulong paint_handler_id; + gulong cursor_moved_handler_id; + gulong cursor_changed_handler_id; }; -G_DEFINE_TYPE (MetaScreenCastMonitorStreamSrc, - meta_screen_cast_monitor_stream_src, - META_TYPE_SCREEN_CAST_STREAM_SRC) +static void +hw_cursor_inhibitor_iface_init (MetaHwCursorInhibitorInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (MetaScreenCastMonitorStreamSrc, + meta_screen_cast_monitor_stream_src, + META_TYPE_SCREEN_CAST_STREAM_SRC, + G_IMPLEMENT_INTERFACE (META_TYPE_HW_CURSOR_INHIBITOR, + hw_cursor_inhibitor_iface_init)) static ClutterStage * get_stage (MetaScreenCastMonitorStreamSrc *monitor_src) @@ -102,18 +115,163 @@ stage_painted (ClutterActor *actor, meta_screen_cast_stream_src_maybe_record_frame (src); } +static MetaBackend * +get_backend (MetaScreenCastMonitorStreamSrc *monitor_src) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (monitor_src); + MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src); + MetaScreenCastSession *session = meta_screen_cast_stream_get_session (stream); + MetaScreenCast *screen_cast = + meta_screen_cast_session_get_screen_cast (session); + + return meta_screen_cast_get_backend (screen_cast); +} + +static gboolean +is_cursor_in_stream (MetaScreenCastMonitorStreamSrc *monitor_src) +{ + MetaBackend *backend = get_backend (monitor_src); + MetaCursorRenderer *cursor_renderer = + meta_backend_get_cursor_renderer (backend); + MetaMonitor *monitor; + MetaLogicalMonitor *logical_monitor; + MetaRectangle logical_monitor_layout; + ClutterRect logical_monitor_rect; + MetaCursorSprite *cursor_sprite; + + monitor = get_monitor (monitor_src); + logical_monitor = meta_monitor_get_logical_monitor (monitor); + logical_monitor_layout = meta_logical_monitor_get_layout (logical_monitor); + logical_monitor_rect = + meta_rectangle_to_clutter_rect (&logical_monitor_layout); + + cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer); + if (cursor_sprite) + { + ClutterRect cursor_rect; + + cursor_rect = meta_cursor_renderer_calculate_rect (cursor_renderer, + cursor_sprite); + return clutter_rect_intersection (&cursor_rect, + &logical_monitor_rect, + NULL); + } + else + { + ClutterPoint cursor_position; + + cursor_position = meta_cursor_renderer_get_position (cursor_renderer); + return clutter_rect_contains_point (&logical_monitor_rect, + &cursor_position); + } +} + +static void +sync_cursor_state (MetaScreenCastMonitorStreamSrc *monitor_src) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (monitor_src); + ClutterStage *stage = get_stage (monitor_src); + + if (!is_cursor_in_stream (monitor_src)) + return; + + if (clutter_stage_is_redraw_queued (stage)) + return; + + meta_screen_cast_stream_src_maybe_record_frame (src); +} + +static void +cursor_moved (MetaCursorTracker *cursor_tracker, + float x, + float y, + MetaScreenCastMonitorStreamSrc *monitor_src) +{ + sync_cursor_state (monitor_src); +} + +static void +cursor_changed (MetaCursorTracker *cursor_tracker, + MetaScreenCastMonitorStreamSrc *monitor_src) +{ + sync_cursor_state (monitor_src); +} + +static MetaCursorRenderer * +get_cursor_renderer (MetaScreenCastMonitorStreamSrc *monitor_src) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (monitor_src); + MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src); + MetaScreenCastSession *session = meta_screen_cast_stream_get_session (stream); + MetaScreenCast *screen_cast = + meta_screen_cast_session_get_screen_cast (session); + MetaBackend *backend = meta_screen_cast_get_backend (screen_cast); + + return meta_backend_get_cursor_renderer (backend); +} + +static void +inhibit_hw_cursor (MetaScreenCastMonitorStreamSrc *monitor_src) +{ + MetaCursorRenderer *cursor_renderer; + MetaHwCursorInhibitor *inhibitor; + + cursor_renderer = get_cursor_renderer (monitor_src); + inhibitor = META_HW_CURSOR_INHIBITOR (monitor_src); + meta_cursor_renderer_add_hw_cursor_inhibitor (cursor_renderer, inhibitor); +} + +static void +uninhibit_hw_cursor (MetaScreenCastMonitorStreamSrc *monitor_src) +{ + MetaCursorRenderer *cursor_renderer; + MetaHwCursorInhibitor *inhibitor; + + cursor_renderer = get_cursor_renderer (monitor_src); + inhibitor = META_HW_CURSOR_INHIBITOR (monitor_src); + meta_cursor_renderer_remove_hw_cursor_inhibitor (cursor_renderer, inhibitor); +} + static void meta_screen_cast_monitor_stream_src_enable (MetaScreenCastStreamSrc *src) { MetaScreenCastMonitorStreamSrc *monitor_src = META_SCREEN_CAST_MONITOR_STREAM_SRC (src); + MetaBackend *backend = get_backend (monitor_src); + MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend); ClutterStage *stage; + MetaScreenCastStream *stream; + stream = meta_screen_cast_stream_src_get_stream (src); stage = get_stage (monitor_src); - monitor_src->actors_painted_handler_id = - g_signal_connect_after (stage, "actors-painted", - G_CALLBACK (stage_painted), - monitor_src); + + switch (meta_screen_cast_stream_get_cursor_mode (stream)) + { + case META_SCREEN_CAST_CURSOR_MODE_METADATA: + monitor_src->cursor_moved_handler_id = + g_signal_connect_after (cursor_tracker, "cursor-moved", + G_CALLBACK (cursor_moved), + monitor_src); + monitor_src->cursor_changed_handler_id = + g_signal_connect_after (cursor_tracker, "cursor-changed", + G_CALLBACK (cursor_changed), + monitor_src); + /* Intentional fall-through */ + case META_SCREEN_CAST_CURSOR_MODE_HIDDEN: + monitor_src->actors_painted_handler_id = + g_signal_connect (stage, "actors-painted", + G_CALLBACK (stage_painted), + monitor_src); + break; + case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED: + inhibit_hw_cursor (monitor_src); + monitor_src->paint_handler_id = + g_signal_connect_after (stage, "paint", + G_CALLBACK (stage_painted), + monitor_src); + break; + } + clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); } @@ -122,14 +280,43 @@ meta_screen_cast_monitor_stream_src_disable (MetaScreenCastStreamSrc *src) { MetaScreenCastMonitorStreamSrc *monitor_src = META_SCREEN_CAST_MONITOR_STREAM_SRC (src); + MetaBackend *backend = get_backend (monitor_src); + MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend); ClutterStage *stage; stage = get_stage (monitor_src); - g_signal_handler_disconnect (stage, monitor_src->actors_painted_handler_id); - monitor_src->actors_painted_handler_id = 0; + + if (monitor_src->actors_painted_handler_id) + { + g_signal_handler_disconnect (stage, + monitor_src->actors_painted_handler_id); + monitor_src->actors_painted_handler_id = 0; + } + + if (monitor_src->paint_handler_id) + { + g_signal_handler_disconnect (stage, + monitor_src->paint_handler_id); + monitor_src->paint_handler_id = 0; + uninhibit_hw_cursor (monitor_src); + } + + if (monitor_src->cursor_moved_handler_id) + { + g_signal_handler_disconnect (cursor_tracker, + monitor_src->cursor_moved_handler_id); + monitor_src->cursor_moved_handler_id = 0; + } + + if (monitor_src->cursor_changed_handler_id) + { + g_signal_handler_disconnect (cursor_tracker, + monitor_src->cursor_changed_handler_id); + monitor_src->cursor_changed_handler_id = 0; + } } -static void +static gboolean meta_screen_cast_monitor_stream_src_record_frame (MetaScreenCastStreamSrc *src, uint8_t *data) { @@ -140,9 +327,216 @@ meta_screen_cast_monitor_stream_src_record_frame (MetaScreenCastStreamSrc *src, MetaLogicalMonitor *logical_monitor; stage = get_stage (monitor_src); + if (!clutter_stage_is_redraw_queued (stage)) + return FALSE; + monitor = get_monitor (monitor_src); logical_monitor = meta_monitor_get_logical_monitor (monitor); clutter_stage_capture_into (stage, FALSE, &logical_monitor->rect, data); + + return TRUE; +} + +static gboolean +draw_cursor_sprite_via_offscreen (MetaScreenCastMonitorStreamSrc *monitor_src, + CoglTexture *cursor_texture, + int bitmap_width, + int bitmap_height, + uint32_t *bitmap_data, + GError **error) +{ + MetaBackend *backend = get_backend (monitor_src); + ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); + CoglContext *cogl_context = + clutter_backend_get_cogl_context (clutter_backend); + CoglTexture2D *bitmap_texture; + CoglOffscreen *offscreen; + CoglFramebuffer *fb; + CoglPipeline *pipeline; + CoglColor clear_color; + + bitmap_texture = cogl_texture_2d_new_with_size (cogl_context, + bitmap_width, bitmap_height); + cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (bitmap_texture), + FALSE); + if (!cogl_texture_allocate (COGL_TEXTURE (bitmap_texture), error)) + { + cogl_object_unref (bitmap_texture); + return FALSE; + } + + offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (bitmap_texture)); + fb = COGL_FRAMEBUFFER (offscreen); + cogl_object_unref (bitmap_texture); + if (!cogl_framebuffer_allocate (fb, error)) + { + cogl_object_unref (fb); + return FALSE; + } + + pipeline = cogl_pipeline_new (cogl_context); + cogl_pipeline_set_layer_texture (pipeline, 0, cursor_texture); + cogl_pipeline_set_layer_filters (pipeline, 0, + COGL_PIPELINE_FILTER_LINEAR, + COGL_PIPELINE_FILTER_LINEAR); + cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0); + cogl_framebuffer_clear (fb, COGL_BUFFER_BIT_COLOR, &clear_color); + cogl_framebuffer_draw_rectangle (fb, pipeline, + -1, 1, 1, -1); + cogl_object_unref (pipeline); + + cogl_framebuffer_read_pixels (fb, + 0, 0, + bitmap_width, bitmap_height, + COGL_PIXEL_FORMAT_RGBA_8888_PRE, + (uint8_t *) bitmap_data); + cogl_object_unref (fb); + + return TRUE; +} + +static void +meta_screen_cast_monitor_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *src, + struct spa_meta_cursor *spa_meta_cursor) +{ + MetaScreenCastMonitorStreamSrc *monitor_src = + META_SCREEN_CAST_MONITOR_STREAM_SRC (src); + MetaBackend *backend = get_backend (monitor_src); + MetaCursorRenderer *cursor_renderer = + meta_backend_get_cursor_renderer (backend); + MetaRenderer *renderer = meta_backend_get_renderer (backend); + MetaSpaType *spa_type = meta_screen_cast_stream_src_get_spa_type (src); + GError *error = NULL; + MetaCursorSprite *cursor_sprite; + CoglTexture *cursor_texture; + MetaMonitor *monitor; + MetaLogicalMonitor *logical_monitor; + MetaRectangle logical_monitor_layout; + ClutterRect logical_monitor_rect; + MetaRendererView *view; + float view_scale; + ClutterPoint cursor_position; + struct spa_meta_bitmap *spa_meta_bitmap; + + cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer); + if (cursor_sprite) + cursor_texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite); + else + cursor_texture = NULL; + + if (!is_cursor_in_stream (monitor_src)) + { + spa_meta_cursor->id = 0; + return; + } + + monitor = get_monitor (monitor_src); + logical_monitor = meta_monitor_get_logical_monitor (monitor); + logical_monitor_layout = meta_logical_monitor_get_layout (logical_monitor); + logical_monitor_rect = + meta_rectangle_to_clutter_rect (&logical_monitor_layout); + + view = meta_renderer_get_view_from_logical_monitor (renderer, + logical_monitor); + if (view) + view_scale = clutter_stage_view_get_scale (CLUTTER_STAGE_VIEW (view)); + else + view_scale = 1.0; + + cursor_position = meta_cursor_renderer_get_position (cursor_renderer); + cursor_position.x -= logical_monitor_rect.origin.x; + cursor_position.y -= logical_monitor_rect.origin.y; + cursor_position.x *= view_scale; + cursor_position.y *= view_scale; + + spa_meta_cursor->id = 1; + spa_meta_cursor->position.x = (int32_t) roundf (cursor_position.x); + spa_meta_cursor->position.y = (int32_t) roundf (cursor_position.y); + spa_meta_cursor->bitmap_offset = sizeof (struct spa_meta_cursor); + + spa_meta_bitmap = SPA_MEMBER (spa_meta_cursor, + spa_meta_cursor->bitmap_offset, + struct spa_meta_bitmap); + spa_meta_bitmap->format = spa_type->video_format.RGBA; + spa_meta_bitmap->offset = sizeof (struct spa_meta_bitmap); + + if (cursor_texture) + { + float cursor_scale; + float bitmap_scale; + int hotspot_x, hotspot_y; + int texture_width, texture_height; + int bitmap_width, bitmap_height; + uint32_t *bitmap_data; + + cursor_scale = meta_cursor_sprite_get_texture_scale (cursor_sprite); + bitmap_scale = view_scale * cursor_scale; + + meta_cursor_sprite_get_hotspot (cursor_sprite, &hotspot_x, &hotspot_y); + spa_meta_cursor->hotspot.x = (int32_t) roundf (hotspot_x * bitmap_scale); + spa_meta_cursor->hotspot.y = (int32_t) roundf (hotspot_y * bitmap_scale); + + texture_width = cogl_texture_get_width (cursor_texture); + texture_height = cogl_texture_get_height (cursor_texture); + bitmap_width = texture_width * bitmap_scale; + bitmap_height = texture_height * bitmap_scale; + + spa_meta_bitmap->size.width = bitmap_width; + spa_meta_bitmap->size.height = bitmap_height; + spa_meta_bitmap->stride = bitmap_width * 4; + + bitmap_data = SPA_MEMBER (spa_meta_bitmap, + spa_meta_bitmap->offset, + uint32_t); + + if (texture_width == bitmap_width && + texture_height == bitmap_height) + { + cogl_texture_get_data (cursor_texture, + COGL_PIXEL_FORMAT_RGBA_8888_PRE, + texture_width * 4, + (uint8_t *) bitmap_data); + } + else + { + if (!draw_cursor_sprite_via_offscreen (monitor_src, + cursor_texture, + bitmap_width, + bitmap_height, + bitmap_data, + &error)) + { + g_warning ("Failed to draw cursor via offscreen: %s", + error->message); + g_error_free (error); + spa_meta_cursor->id = 0; + } + } + } + else + { + spa_meta_cursor->hotspot.x = 0; + spa_meta_cursor->hotspot.y = 0; + + *spa_meta_bitmap = (struct spa_meta_bitmap) { 0 }; + } +} + +static gboolean +meta_screen_cast_monitor_stream_src_is_cursor_sprite_inhibited (MetaHwCursorInhibitor *inhibitor, + MetaCursorSprite *cursor_sprite) +{ + MetaScreenCastMonitorStreamSrc *monitor_src = + META_SCREEN_CAST_MONITOR_STREAM_SRC (inhibitor); + + return is_cursor_in_stream (monitor_src); +} + +static void +hw_cursor_inhibitor_iface_init (MetaHwCursorInhibitorInterface *iface) +{ + iface->is_cursor_sprite_inhibited = + meta_screen_cast_monitor_stream_src_is_cursor_sprite_inhibited; } MetaScreenCastMonitorStreamSrc * @@ -169,4 +563,6 @@ meta_screen_cast_monitor_stream_src_class_init (MetaScreenCastMonitorStreamSrcCl src_class->enable = meta_screen_cast_monitor_stream_src_enable; src_class->disable = meta_screen_cast_monitor_stream_src_disable; src_class->record_frame = meta_screen_cast_monitor_stream_src_record_frame; + src_class->set_cursor_metadata = + meta_screen_cast_monitor_stream_src_set_cursor_metadata; } diff --git a/src/backends/meta-screen-cast-monitor-stream.c b/src/backends/meta-screen-cast-monitor-stream.c index a6bed1b5224..33b9f026a2a 100644 --- a/src/backends/meta-screen-cast-monitor-stream.c +++ b/src/backends/meta-screen-cast-monitor-stream.c @@ -105,11 +105,12 @@ meta_screen_cast_monitor_stream_get_monitor (MetaScreenCastMonitorStream *monito } MetaScreenCastMonitorStream * -meta_screen_cast_monitor_stream_new (MetaScreenCastSession *session, - GDBusConnection *connection, - MetaMonitor *monitor, - ClutterStage *stage, - GError **error) +meta_screen_cast_monitor_stream_new (MetaScreenCastSession *session, + GDBusConnection *connection, + MetaMonitor *monitor, + ClutterStage *stage, + MetaScreenCastCursorMode cursor_mode, + GError **error) { MetaGpu *gpu = meta_monitor_get_gpu (monitor); MetaMonitorManager *monitor_manager = meta_gpu_get_monitor_manager (gpu); @@ -126,6 +127,7 @@ meta_screen_cast_monitor_stream_new (MetaScreenCastSession *session, error, "session", session, "connection", connection, + "cursor-mode", cursor_mode, "monitor", monitor, NULL); if (!monitor_stream) diff --git a/src/backends/meta-screen-cast-monitor-stream.h b/src/backends/meta-screen-cast-monitor-stream.h index 98f160c8882..f8dc04181ad 100644 --- a/src/backends/meta-screen-cast-monitor-stream.h +++ b/src/backends/meta-screen-cast-monitor-stream.h @@ -35,11 +35,12 @@ G_DECLARE_FINAL_TYPE (MetaScreenCastMonitorStream, META, SCREEN_CAST_MONITOR_STREAM, MetaScreenCastStream) -MetaScreenCastMonitorStream * meta_screen_cast_monitor_stream_new (MetaScreenCastSession *session, - GDBusConnection *connection, - MetaMonitor *monitor, - ClutterStage *stage, - GError **error); +MetaScreenCastMonitorStream * meta_screen_cast_monitor_stream_new (MetaScreenCastSession *session, + GDBusConnection *connection, + MetaMonitor *monitor, + ClutterStage *stage, + MetaScreenCastCursorMode cursor_mode, + GError **error); ClutterStage * meta_screen_cast_monitor_stream_get_stage (MetaScreenCastMonitorStream *monitor_stream); diff --git a/src/backends/meta-screen-cast-session.c b/src/backends/meta-screen-cast-session.c index 6a8f2d3284d..45d403dca06 100644 --- a/src/backends/meta-screen-cast-session.c +++ b/src/backends/meta-screen-cast-session.c @@ -262,6 +262,20 @@ on_stream_closed (MetaScreenCastStream *stream, meta_screen_cast_session_close (session); } +static gboolean +is_valid_cursor_mode (MetaScreenCastCursorMode cursor_mode) +{ + switch (cursor_mode) + { + case META_SCREEN_CAST_CURSOR_MODE_HIDDEN: + case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED: + case META_SCREEN_CAST_CURSOR_MODE_METADATA: + return TRUE; + } + + return FALSE; +} + static gboolean handle_record_monitor (MetaDBusScreenCastSession *skeleton, GDBusMethodInvocation *invocation, @@ -275,6 +289,7 @@ handle_record_monitor (MetaDBusScreenCastSession *skeleton, MetaMonitorManager *monitor_manager = meta_backend_get_monitor_manager (backend); MetaMonitor *monitor; + MetaScreenCastCursorMode cursor_mode; ClutterStage *stage; GError *error = NULL; MetaScreenCastMonitorStream *monitor_stream; @@ -306,12 +321,28 @@ handle_record_monitor (MetaDBusScreenCastSession *skeleton, return TRUE; } + if (!g_variant_lookup (properties_variant, "cursor-mode", "u", &cursor_mode)) + { + cursor_mode = META_SCREEN_CAST_CURSOR_MODE_HIDDEN; + } + else + { + if (!is_valid_cursor_mode (cursor_mode)) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_FAILED, + "Unknown cursor mode"); + return TRUE; + } + } + stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); monitor_stream = meta_screen_cast_monitor_stream_new (session, connection, monitor, stage, + cursor_mode, &error); if (!monitor_stream) { diff --git a/src/backends/meta-screen-cast-stream-src.c b/src/backends/meta-screen-cast-stream-src.c index 04b84eb1df5..7e11bd06726 100644 --- a/src/backends/meta-screen-cast-stream-src.c +++ b/src/backends/meta-screen-cast-stream-src.c @@ -40,6 +40,10 @@ #define PRIVATE_OWNER_FROM_FIELD(TypeName, field_ptr, field_name) \ (TypeName *)((guint8 *)(field_ptr) - G_PRIVATE_OFFSET (TypeName, field_name)) +#define CURSOR_META_SIZE(width, height) \ + (sizeof (struct spa_meta_cursor) + \ + sizeof (struct spa_meta_bitmap) + width * height * 4) + enum { PROP_0, @@ -57,14 +61,6 @@ enum static guint signals[N_SIGNALS]; -typedef struct _MetaSpaType -{ - struct spa_type_media_type media_type; - struct spa_type_media_subtype media_subtype; - struct spa_type_format_video format_video; - struct spa_type_video_format video_format; -} MetaSpaType; - typedef struct _MetaPipeWireSource { GSource base; @@ -133,14 +129,68 @@ meta_screen_cast_stream_src_get_videocrop (MetaScreenCastStreamSrc *src, return FALSE; } -static void +static gboolean meta_screen_cast_stream_src_record_frame (MetaScreenCastStreamSrc *src, uint8_t *data) { MetaScreenCastStreamSrcClass *klass = META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src); - klass->record_frame (src, data); + return klass->record_frame (src, data); +} + +static void +meta_screen_cast_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *src, + struct spa_meta_cursor *spa_meta_cursor) +{ + MetaScreenCastStreamSrcClass *klass = + META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src); + + if (klass->set_cursor_metadata) + klass->set_cursor_metadata (src, spa_meta_cursor); +} + +MetaSpaType * +meta_screen_cast_stream_src_get_spa_type (MetaScreenCastStreamSrc *src) +{ + MetaScreenCastStreamSrcPrivate *priv = + meta_screen_cast_stream_src_get_instance_private (src); + + return &priv->spa_type; +} + +static void +add_cursor_metadata (MetaScreenCastStreamSrc *src, + struct spa_buffer *spa_buffer) +{ + MetaScreenCastStreamSrcPrivate *priv = + meta_screen_cast_stream_src_get_instance_private (src); + MetaSpaType *spa_type = &priv->spa_type; + struct spa_meta_cursor *spa_meta_cursor; + + spa_meta_cursor = spa_buffer_find_meta (spa_buffer, spa_type->meta_cursor); + if (spa_meta_cursor) + meta_screen_cast_stream_src_set_cursor_metadata (src, spa_meta_cursor); +} + +static void +maybe_record_cursor (MetaScreenCastStreamSrc *src, + struct spa_buffer *spa_buffer, + uint8_t *data) +{ + MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src); + + switch (meta_screen_cast_stream_get_cursor_mode (stream)) + { + case META_SCREEN_CAST_CURSOR_MODE_HIDDEN: + case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED: + return; + case META_SCREEN_CAST_CURSOR_MODE_METADATA: + add_cursor_metadata (src, spa_buffer); + return; + } + + g_assert_not_reached (); } void @@ -151,7 +201,6 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src) MetaRectangle crop_rect; struct pw_buffer *buffer; struct spa_buffer *spa_buffer; - struct spa_meta_video_crop *spa_meta_video_crop; uint8_t *map = NULL; uint8_t *data; uint64_t now_us; @@ -199,35 +248,45 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src) return; } - meta_screen_cast_stream_src_record_frame (src, data); - - /* Update VideoCrop if needed */ - spa_meta_video_crop = spa_buffer_find_meta (spa_buffer, priv->pipewire_type->meta.VideoCrop); - if (spa_meta_video_crop) + if (meta_screen_cast_stream_src_record_frame (src, data)) { - if (meta_screen_cast_stream_src_get_videocrop (src, &crop_rect)) - { - spa_meta_video_crop->x = crop_rect.x; - spa_meta_video_crop->y = crop_rect.y; - spa_meta_video_crop->width = crop_rect.width; - spa_meta_video_crop->height = crop_rect.height; - } - else + struct spa_meta_video_crop *spa_meta_video_crop; + + spa_buffer->datas[0].chunk->size = spa_buffer->datas[0].maxsize; + + /* Update VideoCrop if needed */ + spa_meta_video_crop = + spa_buffer_find_meta (spa_buffer, priv->pipewire_type->meta.VideoCrop); + if (spa_meta_video_crop) { - spa_meta_video_crop->x = 0; - spa_meta_video_crop->y = 0; - spa_meta_video_crop->width = priv->stream_width; - spa_meta_video_crop->height = priv->stream_height; + if (meta_screen_cast_stream_src_get_videocrop (src, &crop_rect)) + { + spa_meta_video_crop->x = crop_rect.x; + spa_meta_video_crop->y = crop_rect.y; + spa_meta_video_crop->width = crop_rect.width; + spa_meta_video_crop->height = crop_rect.height; + } + else + { + spa_meta_video_crop->x = 0; + spa_meta_video_crop->y = 0; + spa_meta_video_crop->width = priv->stream_width; + spa_meta_video_crop->height = priv->stream_height; + } } } + else + { + spa_buffer->datas[0].chunk->size = 0; + } + + maybe_record_cursor (src, spa_buffer, data); priv->last_frame_timestamp_us = now_us; if (map) munmap (map, spa_buffer->datas[0].maxsize + spa_buffer->datas[0].mapoffset); - spa_buffer->datas[0].chunk->size = spa_buffer->datas[0].maxsize; - pw_stream_queue_buffer (priv->pipewire_stream, buffer); } @@ -314,7 +373,7 @@ on_stream_format_changed (void *data, uint8_t params_buffer[1024]; int32_t width, height, stride, size; struct spa_pod_builder pod_builder; - const struct spa_pod *params[2]; + const struct spa_pod *params[3]; const int bpp = 4; if (!format) @@ -348,6 +407,12 @@ on_stream_format_changed (void *data, ":", pipewire_type->param_meta.type, "I", pipewire_type->meta.VideoCrop, ":", pipewire_type->param_meta.size, "i", sizeof (struct spa_meta_video_crop)); + params[2] = spa_pod_builder_object ( + &pod_builder, + pipewire_type->param.idMeta, pipewire_type->param_meta.Meta, + ":", pipewire_type->param_meta.type, "I", priv->spa_type.meta_cursor, + ":", pipewire_type->param_meta.size, "i", CURSOR_META_SIZE (64, 64)); + pw_stream_finish_format (priv->pipewire_stream, 0, params, G_N_ELEMENTS (params)); } @@ -517,6 +582,7 @@ init_spa_type (MetaSpaType *type, spa_type_media_subtype_map (map, &type->media_subtype); spa_type_format_video_map (map, &type->format_video); spa_type_video_format_map (map, &type->video_format); + type->meta_cursor = spa_type_map_get_id(map, SPA_TYPE_META__Cursor); } static MetaPipeWireSource * diff --git a/src/backends/meta-screen-cast-stream-src.h b/src/backends/meta-screen-cast-stream-src.h index f3b3fd77938..f2f96f2130f 100644 --- a/src/backends/meta-screen-cast-stream-src.h +++ b/src/backends/meta-screen-cast-stream-src.h @@ -24,10 +24,26 @@ #define META_SCREEN_CAST_STREAM_SRC_H #include +#include +#include +#include "backends/meta-backend-private.h" +#include "backends/meta-cursor-renderer.h" +#include "backends/meta-cursor.h" +#include "backends/meta-renderer.h" #include "clutter/clutter.h" +#include "cogl/cogl.h" #include "meta/boxes.h" +typedef struct _MetaSpaType +{ + struct spa_type_media_type media_type; + struct spa_type_media_subtype media_subtype; + struct spa_type_format_video format_video; + struct spa_type_video_format video_format; + uint32_t meta_cursor; +} MetaSpaType; + typedef struct _MetaScreenCastStream MetaScreenCastStream; #define META_TYPE_SCREEN_CAST_STREAM_SRC (meta_screen_cast_stream_src_get_type ()) @@ -46,14 +62,18 @@ struct _MetaScreenCastStreamSrcClass float *frame_rate); void (* enable) (MetaScreenCastStreamSrc *src); void (* disable) (MetaScreenCastStreamSrc *src); - void (* record_frame) (MetaScreenCastStreamSrc *src, - uint8_t *data); + gboolean (* record_frame) (MetaScreenCastStreamSrc *src, + uint8_t *data); gboolean (* get_videocrop) (MetaScreenCastStreamSrc *src, MetaRectangle *crop_rect); + void (* set_cursor_metadata) (MetaScreenCastStreamSrc *src, + struct spa_meta_cursor *spa_meta_cursor); }; void meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src); MetaScreenCastStream * meta_screen_cast_stream_src_get_stream (MetaScreenCastStreamSrc *src); +MetaSpaType * meta_screen_cast_stream_src_get_spa_type (MetaScreenCastStreamSrc *src); + #endif /* META_SCREEN_CAST_STREAM_SRC_H */ diff --git a/src/backends/meta-screen-cast-stream.c b/src/backends/meta-screen-cast-stream.c index 875ada01aa8..c14f8fd8512 100644 --- a/src/backends/meta-screen-cast-stream.c +++ b/src/backends/meta-screen-cast-stream.c @@ -34,6 +34,7 @@ enum PROP_SESSION, PROP_CONNECTION, + PROP_CURSOR_MODE, }; enum @@ -52,6 +53,8 @@ typedef struct _MetaScreenCastStreamPrivate GDBusConnection *connection; char *object_path; + MetaScreenCastCursorMode cursor_mode; + MetaScreenCastStreamSrc *src; } MetaScreenCastStreamPrivate; @@ -164,6 +167,15 @@ meta_screen_cast_stream_transform_position (MetaScreenCastStream *stream, y); } +MetaScreenCastCursorMode +meta_screen_cast_stream_get_cursor_mode (MetaScreenCastStream *stream) +{ + MetaScreenCastStreamPrivate *priv = + meta_screen_cast_stream_get_instance_private (stream); + + return priv->cursor_mode; +} + static void meta_screen_cast_stream_set_property (GObject *object, guint prop_id, @@ -182,6 +194,9 @@ meta_screen_cast_stream_set_property (GObject *object, case PROP_CONNECTION: priv->connection = g_value_get_object (value); break; + case PROP_CURSOR_MODE: + priv->cursor_mode = g_value_get_uint (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -205,6 +220,9 @@ meta_screen_cast_stream_get_property (GObject *object, case PROP_CONNECTION: g_value_set_object (value, priv->connection); break; + case PROP_CURSOR_MODE: + g_value_set_uint (value, priv->cursor_mode); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -296,6 +314,18 @@ meta_screen_cast_stream_class_init (MetaScreenCastStreamClass *klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, + PROP_CURSOR_MODE, + g_param_spec_uint ("cursor-mode", + "cursor-mode", + "Cursor mode", + META_SCREEN_CAST_CURSOR_MODE_HIDDEN, + META_SCREEN_CAST_CURSOR_MODE_METADATA, + META_SCREEN_CAST_CURSOR_MODE_HIDDEN, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + signals[CLOSED] = g_signal_new ("closed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, diff --git a/src/backends/meta-screen-cast-stream.h b/src/backends/meta-screen-cast-stream.h index d394dbb4dab..4fc10869d7a 100644 --- a/src/backends/meta-screen-cast-stream.h +++ b/src/backends/meta-screen-cast-stream.h @@ -65,4 +65,6 @@ void meta_screen_cast_stream_transform_position (MetaScreenCastStream *stream, double *x, double *y); +MetaScreenCastCursorMode meta_screen_cast_stream_get_cursor_mode (MetaScreenCastStream *stream); + #endif /* META_SCREEN_CAST_STREAM_H */ diff --git a/src/backends/meta-screen-cast-window-stream-src.c b/src/backends/meta-screen-cast-window-stream-src.c index c3f9cf5ca92..32df9f1275c 100644 --- a/src/backends/meta-screen-cast-window-stream-src.c +++ b/src/backends/meta-screen-cast-window-stream-src.c @@ -207,7 +207,7 @@ meta_screen_cast_window_stream_src_disable (MetaScreenCastStreamSrc *src) meta_screen_cast_window_stream_src_stop (window_src); } -static void +static gboolean meta_screen_cast_window_stream_src_record_frame (MetaScreenCastStreamSrc *src, uint8_t *data) { @@ -215,6 +215,8 @@ meta_screen_cast_window_stream_src_record_frame (MetaScreenCastStreamSrc *src, META_SCREEN_CAST_WINDOW_STREAM_SRC (src); capture_into (window_src, data); + + return TRUE; } MetaScreenCastWindowStreamSrc * diff --git a/src/backends/meta-screen-cast.h b/src/backends/meta-screen-cast.h index a5450ae0ec9..994c40c5358 100644 --- a/src/backends/meta-screen-cast.h +++ b/src/backends/meta-screen-cast.h @@ -30,6 +30,13 @@ #include "meta-dbus-screen-cast.h" +typedef enum _MetaScreenCastCursorMode +{ + META_SCREEN_CAST_CURSOR_MODE_HIDDEN = 0, + META_SCREEN_CAST_CURSOR_MODE_EMBEDDED = 1, + META_SCREEN_CAST_CURSOR_MODE_METADATA = 2, +} MetaScreenCastCursorMode; + #define META_TYPE_SCREEN_CAST (meta_screen_cast_get_type ()) G_DECLARE_FINAL_TYPE (MetaScreenCast, meta_screen_cast, META, SCREEN_CAST, diff --git a/src/org.gnome.Mutter.ScreenCast.xml b/src/org.gnome.Mutter.ScreenCast.xml index 3cd02b6cba2..953809727e0 100644 --- a/src/org.gnome.Mutter.ScreenCast.xml +++ b/src/org.gnome.Mutter.ScreenCast.xml @@ -71,7 +71,15 @@ Record a single monitor. - Available @properties include: (none) + Available @properties include: + + * "cursor-mode" (u): Cursor mode. Default: 'hidden' (see below) + + Available cursor mode values: + + 0: hidden - cursor is not included in the stream + 1: embedded - cursor is included in the framebuffer + 2: metadata - cursor is included as metadata in the PipeWire stream --> @@ -84,7 +92,7 @@ @properties: Properties used determining what window to select @stream_path: Path to the new stream object - Record a single window. + Record a single window. The cursor will not be included. Available @properties include: -- GitLab From c45d5f53ff0f96855319dce968b5082bcc5f37ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 3 Jan 2019 16:40:42 +0100 Subject: [PATCH 11/12] cursor-tracker: Emit `cursor-changed` after renderer was updated Otherwise the cursor retrieved via meta_cursor_renderer_get_cursor() is out of date. https://gitlab.gnome.org/GNOME/mutter/merge_requests/357 --- src/backends/meta-cursor-tracker.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/backends/meta-cursor-tracker.c b/src/backends/meta-cursor-tracker.c index 7ff0e7b0ce2..0d49327f45a 100644 --- a/src/backends/meta-cursor-tracker.c +++ b/src/backends/meta-cursor-tracker.c @@ -118,11 +118,15 @@ change_cursor_renderer (MetaCursorTracker *tracker) static void sync_cursor (MetaCursorTracker *tracker) { - if (update_displayed_cursor (tracker)) - g_signal_emit (tracker, signals[CURSOR_CHANGED], 0); + gboolean cursor_changed = FALSE; + + cursor_changed = update_displayed_cursor (tracker); if (update_effective_cursor (tracker)) change_cursor_renderer (tracker); + + if (cursor_changed) + g_signal_emit (tracker, signals[CURSOR_CHANGED], 0); } static void -- GitLab From 56d260cfb3f6a7b4d20aa73ce08da007883d9b7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 3 Jan 2019 16:51:08 +0100 Subject: [PATCH 12/12] screen-cast-monitor-stream-src: Only send cursor bitmap when it changes To avoid unnecessary pixel copying, only send the cursor bitmap when it changes. This also allows the receiver to know when the cursor bitmap actually changed. https://gitlab.gnome.org/GNOME/mutter/merge_requests/357 --- src/backends/meta-screen-cast-monitor-stream-src.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/backends/meta-screen-cast-monitor-stream-src.c b/src/backends/meta-screen-cast-monitor-stream-src.c index 50ed6c519d1..897b86ae64a 100644 --- a/src/backends/meta-screen-cast-monitor-stream-src.c +++ b/src/backends/meta-screen-cast-monitor-stream-src.c @@ -40,6 +40,8 @@ struct _MetaScreenCastMonitorStreamSrc { MetaScreenCastStreamSrc parent; + gboolean cursor_bitmap_invalid; + gulong actors_painted_handler_id; gulong paint_handler_id; gulong cursor_moved_handler_id; @@ -194,6 +196,7 @@ static void cursor_changed (MetaCursorTracker *cursor_tracker, MetaScreenCastMonitorStreamSrc *monitor_src) { + monitor_src->cursor_bitmap_invalid = TRUE; sync_cursor_state (monitor_src); } @@ -452,6 +455,16 @@ meta_screen_cast_monitor_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc spa_meta_cursor->id = 1; spa_meta_cursor->position.x = (int32_t) roundf (cursor_position.x); spa_meta_cursor->position.y = (int32_t) roundf (cursor_position.y); + + if (!monitor_src->cursor_bitmap_invalid) + { + spa_meta_cursor->hotspot.x = 0; + spa_meta_cursor->hotspot.y = 0; + spa_meta_cursor->bitmap_offset = 0; + return; + } + monitor_src->cursor_bitmap_invalid = FALSE; + spa_meta_cursor->bitmap_offset = sizeof (struct spa_meta_cursor); spa_meta_bitmap = SPA_MEMBER (spa_meta_cursor, @@ -551,6 +564,7 @@ meta_screen_cast_monitor_stream_src_new (MetaScreenCastMonitorStream *monitor_s static void meta_screen_cast_monitor_stream_src_init (MetaScreenCastMonitorStreamSrc *monitor_src) { + monitor_src->cursor_bitmap_invalid = TRUE; } static void -- GitLab