From 5f428c5aa9f3e66cd23e4e75d54506960bd5b66c 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 6244f11ee..060b6af3b 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); } /** @@ -334,6 +344,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 -- 2.20.1 From 54c5034f6dcdaf382a8355460710ced47c05d91e 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 9352f49e8..763ec96ee 100644 --- a/clutter/clutter/clutter-stage.c +++ b/clutter/clutter/clutter-stage.c @@ -3722,6 +3722,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 e8fbda84c..ddf08fde4 100644 --- a/clutter/clutter/clutter-stage.h +++ b/clutter/clutter/clutter-stage.h @@ -250,6 +250,9 @@ void clutter_stage_ensure_viewport (ClutterStage CLUTTER_AVAILABLE_IN_ALL void clutter_stage_ensure_redraw (ClutterStage *stage); +CLUTTER_AVAILABLE_IN_ALL +gboolean clutter_stage_is_redraw_queued (ClutterStage *stage); + #ifdef CLUTTER_ENABLE_EXPERIMENTAL_API CLUTTER_AVAILABLE_IN_1_14 void clutter_stage_set_sync_delay (ClutterStage *stage, -- 2.20.1 From 59e1c68143d9090e238198448fa400bb0776d38a 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 df43f977c..5a816e4df 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 fbf3c77c3..1d24de93a 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 d0f5a79d9..3ba59037f 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); -- 2.20.1 From 45100944033987a946672fda6de309aa41a6139f 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.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 | 6 ++++ 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 +++- 11 files changed, 92 insertions(+), 20 deletions(-) diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c index 888e51cd9..28f1cd92f 100644 --- a/src/backends/meta-backend.c +++ b/src/backends/meta-backend.c @@ -456,7 +456,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 5a816e4df..a6bed1b52 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 1d24de93a..98f160c88 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 3ba59037f..6a8f2d328 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 ac0a31a16..105a65098 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 97ee4bfcf..875ada01a 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 fd7930c4c..dcc280da6 100644 --- a/src/backends/meta-screen-cast-stream.h +++ b/src/backends/meta-screen-cast-stream.h @@ -26,8 +26,12 @@ #include #include "backends/meta-screen-cast-stream-src.h" +#include "backends/meta-screen-cast.h" + #include "meta-dbus-screen-cast.h" +typedef struct _MetaScreenCastSession MetaScreenCastSession; + #define META_TYPE_SCREEN_CAST_STREAM (meta_screen_cast_stream_get_type ()) G_DECLARE_DERIVABLE_TYPE (MetaScreenCastStream, meta_screen_cast_stream, META, SCREEN_CAST_STREAM, @@ -48,6 +52,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 1200a39ef..4c9227116 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 6726ef873..3799be98a 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 4a67683e7..ceea9cbe1 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 a4fb8dd45..7e32b67b7 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" @@ -35,6 +36,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 */ -- 2.20.1 From 0bda3f694c9ea14239dd002856302e7d3007ae1c 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 ceac7df57..ea93dc99e 100644 --- a/src/backends/meta-renderer.c +++ b/src/backends/meta-renderer.c @@ -94,6 +94,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 bf51b51ab..1c617214b 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 */ -- 2.20.1 From 1a928d060cccd344004a06dacc008ae0654e8f3e 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 73ca70118..d1b7185e8 100644 --- a/src/backends/meta-stage.c +++ b/src/backends/meta-stage.c @@ -30,7 +30,8 @@ #include "backends/meta-backend-private.h" #include "clutter/clutter-mutter.h" -struct _MetaOverlay { +struct _MetaOverlay +{ gboolean enabled; CoglPipeline *pipeline; -- 2.20.1 From 44655d12468c26bf6949e4b5137d324f9ec3b651 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 d1b7185e8..4ed56c04b 100644 --- a/src/backends/meta-stage.c +++ b/src/backends/meta-stage.c @@ -30,6 +30,15 @@ #include "backends/meta-backend-private.h" #include "clutter/clutter-mutter.h" +enum +{ + ACTORS_PAINTED, + + N_SIGNALS +}; + +static guint signals[N_SIGNALS]; + struct _MetaOverlay { gboolean enabled; @@ -141,6 +150,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 = priv->overlays; l; l = l->next) meta_overlay_paint (l->data); } @@ -180,6 +191,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 -- 2.20.1 From 6afa7372f3c8104fb5670130b1cd54980e9b6446 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 382d7d4a2..b240744a8 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 -- 2.20.1 From 2e03a842ce2447f9d070a410d1a80c2e77b480a5 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 | 21 +++++++ .../native/meta-cursor-renderer-native.c | 4 ++ 3 files changed, 87 insertions(+) diff --git a/src/backends/meta-cursor-renderer.c b/src/backends/meta-cursor-renderer.c index eb79737f1..0a456bee6 100644 --- a/src/backends/meta-cursor-renderer.c +++ b/src/backends/meta-cursor-renderer.c @@ -35,6 +35,9 @@ #include "meta-stage-private.h" +G_DEFINE_INTERFACE (MetaHwCursorInhibitor, meta_hw_cursor_inhibitor, + G_TYPE_OBJECT) + struct _MetaCursorRendererPrivate { float current_x; @@ -44,6 +47,8 @@ struct _MetaCursorRendererPrivate MetaOverlay *stage_overlay; gboolean handled_by_backend; guint post_paint_func_id; + + GList *hw_cursor_inhibitors; }; typedef struct _MetaCursorRendererPrivate MetaCursorRendererPrivate; @@ -55,6 +60,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) @@ -283,3 +303,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 830d16ef6..092f17f1e 100644 --- a/src/backends/meta-cursor-renderer.h +++ b/src/backends/meta-cursor-renderer.h @@ -30,6 +30,18 @@ #include #include "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); @@ -55,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 29800953b..3ff4e81fb 100644 --- a/src/backends/native/meta-cursor-renderer-native.c +++ b/src/backends/native/meta-cursor-renderer-native.c @@ -587,6 +587,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; -- 2.20.1 From 65eaf0c6a12ca48fc92fbe4492726cd145549924 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 --- configure.ac | 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 +- 12 files changed, 622 insertions(+), 57 deletions(-) diff --git a/configure.ac b/configure.ac index 2aa9c4352..449f3d693 100644 --- a/configure.ac +++ b/configure.ac @@ -245,7 +245,7 @@ AC_ARG_ENABLE(remote-desktop, enable_remote_desktop=no ) AS_IF([test "$enable_remote_desktop" = "yes"], [ - MUTTER_PC_MODULES="$MUTTER_PC_MODULES libpipewire-0.2 >= 0.2.2" + MUTTER_PC_MODULES="$MUTTER_PC_MODULES libpipewire-0.2 >= 0.2.5" AC_DEFINE([HAVE_REMOTE_DESKTOP],[1], [Defined if screen cast and remote desktop support is enabled]) ]) AM_CONDITIONAL([HAVE_REMOTE_DESKTOP],[test "$enable_remote_desktop" = "yes"]) diff --git a/src/backends/meta-screen-cast-monitor-stream-src.c b/src/backends/meta-screen-cast-monitor-stream-src.c index b240744a8..6be477989 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-screen-cast-monitor-stream.h" +#include "backends/meta-screen-cast-session.h" #include "backends/meta-logical-monitor.h" #include "backends/meta-monitor.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 a6bed1b52..33b9f026a 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 98f160c88..f8dc04181 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 6a8f2d328..45d403dca 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 673a4640b..9f97bf36d 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 f3b3fd779..f2f96f213 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 875ada01a..c14f8fd85 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 dcc280da6..28ca6f683 100644 --- a/src/backends/meta-screen-cast-stream.h +++ b/src/backends/meta-screen-cast-stream.h @@ -67,4 +67,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 c3f9cf5ca..32df9f127 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 7e32b67b7..cadb6a2fe 100644 --- a/src/backends/meta-screen-cast.h +++ b/src/backends/meta-screen-cast.h @@ -29,6 +29,13 @@ #include "backends/meta-dbus-session-watcher.h" #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 3cd02b6cb..953809727 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: -- 2.20.1 From 93c2b18337a8babe340775cd979ad540f0838ab3 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 060b6af3b..97e7f8cb4 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 -- 2.20.1 From 392205b1d0728ac1636df90144c0fe091bd45624 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 6be477989..1d6aea242 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 -- 2.20.1