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,
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-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-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/meta-cursor-tracker.c b/src/backends/meta-cursor-tracker.c
index 6244f11ee..97e7f8cb4 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
};
@@ -117,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
@@ -158,6 +163,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 +348,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
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 */
diff --git a/src/backends/meta-screen-cast-monitor-stream-src.c b/src/backends/meta-screen-cast-monitor-stream-src.c
index 382d7d4a2..1d6aea242 100644
--- a/src/backends/meta-screen-cast-monitor-stream-src.c
+++ b/src/backends/meta-screen-cast-monitor-stream-src.c
@@ -24,23 +24,38 @@
#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 stage_painted_handler_id;
+ gboolean cursor_bitmap_invalid;
+
+ 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 +117,164 @@ 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)
+{
+ monitor_src->cursor_bitmap_invalid = TRUE;
+ 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->stage_painted_handler_id =
- g_signal_connect_after (stage, "paint",
- 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 +283,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->stage_painted_handler_id);
- monitor_src->stage_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 +330,226 @@ 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);
+
+ 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,
+ 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 *
@@ -157,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
@@ -169,4 +577,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 df43f977c..33b9f026a 100644
--- a/src/backends/meta-screen-cast-monitor-stream.c
+++ b/src/backends/meta-screen-cast-monitor-stream.c
@@ -105,12 +105,15 @@ 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 (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);
MetaScreenCastMonitorStream *monitor_stream;
if (!meta_monitor_is_active (monitor))
@@ -122,7 +125,9 @@ 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,
+ "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 fbf3c77c3..f8dc04181 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,11 +35,12 @@ 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 (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 d0f5a79d9..45d403dca 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)
{
@@ -254,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,
@@ -267,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;
@@ -298,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 (connection,
- monitor_manager,
+ monitor_stream = meta_screen_cast_monitor_stream_new (session,
+ connection,
monitor,
stage,
+ cursor_mode,
&error);
if (!monitor_stream)
{
@@ -382,7 +421,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)
@@ -442,6 +482,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-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))
+ 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 = 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;
+ 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 97ee4bfcf..c14f8fd85 100644
--- a/src/backends/meta-screen-cast-stream.c
+++ b/src/backends/meta-screen-cast-stream.c
@@ -24,13 +24,17 @@
#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,
+ PROP_CURSOR_MODE,
};
enum
@@ -44,9 +48,13 @@ static guint signals[N_SIGNALS];
typedef struct _MetaScreenCastStreamPrivate
{
+ MetaScreenCastSession *session;
+
GDBusConnection *connection;
char *object_path;
+ MetaScreenCastCursorMode cursor_mode;
+
MetaScreenCastStreamSrc *src;
} MetaScreenCastStreamPrivate;
@@ -97,6 +105,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)
@@ -150,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,
@@ -162,9 +188,15 @@ 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;
+ case PROP_CURSOR_MODE:
+ priv->cursor_mode = g_value_get_uint (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -182,9 +214,15 @@ 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;
+ case PROP_CURSOR_MODE:
+ g_value_set_uint (value, priv->cursor_mode);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -256,6 +294,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",
@@ -266,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 fd7930c4c..28ca6f683 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);
@@ -61,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-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..cadb6a2fe 100644
--- a/src/backends/meta-screen-cast.h
+++ b/src/backends/meta-screen-cast.h
@@ -25,9 +25,17 @@
#include
+#include "backends/meta-backend-private.h"
#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,
@@ -35,6 +43,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 */
diff --git a/src/backends/meta-stage.c b/src/backends/meta-stage.c
index 73ca70118..4ed56c04b 100644
--- a/src/backends/meta-stage.c
+++ b/src/backends/meta-stage.c
@@ -30,7 +30,17 @@
#include "backends/meta-backend-private.h"
#include "clutter/clutter-mutter.h"
-struct _MetaOverlay {
+enum
+{
+ ACTORS_PAINTED,
+
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS];
+
+struct _MetaOverlay
+{
gboolean enabled;
CoglPipeline *pipeline;
@@ -140,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);
}
@@ -179,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
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;
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: