screen-cast-cursor-side-channel.patch

This commit is contained in:
Ray Strode 2019-01-14 10:06:59 -05:00
parent efd7b8987f
commit e3a42dc873
26 changed files with 881 additions and 74 deletions

View File

@ -3722,6 +3722,17 @@ clutter_stage_ensure_redraw (ClutterStage *stage)
_clutter_master_clock_start_running (master_clock); _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: * clutter_stage_queue_redraw:
* @stage: the #ClutterStage * @stage: the #ClutterStage

View File

@ -250,6 +250,9 @@ void clutter_stage_ensure_viewport (ClutterStage
CLUTTER_AVAILABLE_IN_ALL CLUTTER_AVAILABLE_IN_ALL
void clutter_stage_ensure_redraw (ClutterStage *stage); void clutter_stage_ensure_redraw (ClutterStage *stage);
CLUTTER_AVAILABLE_IN_ALL
gboolean clutter_stage_is_redraw_queued (ClutterStage *stage);
#ifdef CLUTTER_ENABLE_EXPERIMENTAL_API #ifdef CLUTTER_ENABLE_EXPERIMENTAL_API
CLUTTER_AVAILABLE_IN_1_14 CLUTTER_AVAILABLE_IN_1_14
void clutter_stage_set_sync_delay (ClutterStage *stage, void clutter_stage_set_sync_delay (ClutterStage *stage,

View File

@ -245,7 +245,7 @@ AC_ARG_ENABLE(remote-desktop,
enable_remote_desktop=no enable_remote_desktop=no
) )
AS_IF([test "$enable_remote_desktop" = "yes"], [ 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]) 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"]) AM_CONDITIONAL([HAVE_REMOTE_DESKTOP],[test "$enable_remote_desktop" = "yes"])

View File

@ -456,7 +456,8 @@ meta_backend_real_post_init (MetaBackend *backend)
priv->remote_access_controller = priv->remote_access_controller =
g_object_new (META_TYPE_REMOTE_ACCESS_CONTROLLER, NULL); g_object_new (META_TYPE_REMOTE_ACCESS_CONTROLLER, NULL);
priv->dbus_session_watcher = g_object_new (META_TYPE_DBUS_SESSION_WATCHER, 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); priv->remote_desktop = meta_remote_desktop_new (priv->dbus_session_watcher);
#endif /* HAVE_REMOTE_DESKTOP */ #endif /* HAVE_REMOTE_DESKTOP */

View File

@ -35,6 +35,9 @@
#include "meta-stage-private.h" #include "meta-stage-private.h"
G_DEFINE_INTERFACE (MetaHwCursorInhibitor, meta_hw_cursor_inhibitor,
G_TYPE_OBJECT)
struct _MetaCursorRendererPrivate struct _MetaCursorRendererPrivate
{ {
float current_x; float current_x;
@ -44,6 +47,8 @@ struct _MetaCursorRendererPrivate
MetaOverlay *stage_overlay; MetaOverlay *stage_overlay;
gboolean handled_by_backend; gboolean handled_by_backend;
guint post_paint_func_id; guint post_paint_func_id;
GList *hw_cursor_inhibitors;
}; };
typedef struct _MetaCursorRendererPrivate MetaCursorRendererPrivate; 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); 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 void
meta_cursor_renderer_emit_painted (MetaCursorRenderer *renderer, meta_cursor_renderer_emit_painted (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite) MetaCursorSprite *cursor_sprite)
@ -283,3 +303,45 @@ meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer)
return priv->displayed_cursor; 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;
}

View File

@ -30,6 +30,18 @@
#include <meta/screen.h> #include <meta/screen.h>
#include "meta-cursor.h" #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 ()) #define META_TYPE_CURSOR_RENDERER (meta_cursor_renderer_get_type ())
G_DECLARE_DERIVABLE_TYPE (MetaCursorRenderer, meta_cursor_renderer, G_DECLARE_DERIVABLE_TYPE (MetaCursorRenderer, meta_cursor_renderer,
META, CURSOR_RENDERER, GObject); META, CURSOR_RENDERER, GObject);
@ -55,6 +67,15 @@ void meta_cursor_renderer_force_update (MetaCursorRenderer *renderer);
MetaCursorSprite * meta_cursor_renderer_get_cursor (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, ClutterRect meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite); MetaCursorSprite *cursor_sprite);

View File

@ -48,6 +48,7 @@ G_DEFINE_TYPE (MetaCursorTracker, meta_cursor_tracker, G_TYPE_OBJECT);
enum { enum {
CURSOR_CHANGED, CURSOR_CHANGED,
CURSOR_MOVED,
LAST_SIGNAL LAST_SIGNAL
}; };
@ -117,11 +118,15 @@ change_cursor_renderer (MetaCursorTracker *tracker)
static void static void
sync_cursor (MetaCursorTracker *tracker) sync_cursor (MetaCursorTracker *tracker)
{ {
if (update_displayed_cursor (tracker)) gboolean cursor_changed = FALSE;
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
cursor_changed = update_displayed_cursor (tracker);
if (update_effective_cursor (tracker)) if (update_effective_cursor (tracker))
change_cursor_renderer (tracker); change_cursor_renderer (tracker);
if (cursor_changed)
g_signal_emit (tracker, signals[CURSOR_CHANGED], 0);
} }
static void static void
@ -158,6 +163,15 @@ meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass)
0, 0,
NULL, NULL, NULL, NULL, NULL, NULL,
G_TYPE_NONE, 0); 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 ()); g_assert (meta_is_wayland_compositor ());
meta_cursor_renderer_set_position (cursor_renderer, new_x, new_y); 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 static void

View File

@ -94,6 +94,24 @@ meta_renderer_get_views (MetaRenderer *renderer)
return priv->views; 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 static void
meta_renderer_finalize (GObject *object) meta_renderer_finalize (GObject *object)
{ {

View File

@ -53,4 +53,7 @@ void meta_renderer_set_legacy_view (MetaRenderer *renderer,
GList * meta_renderer_get_views (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 */ #endif /* META_RENDERER_H */

View File

@ -24,23 +24,38 @@
#include "backends/meta-screen-cast-monitor-stream-src.h" #include "backends/meta-screen-cast-monitor-stream-src.h"
#include <spa/buffer/meta.h>
#include "backends/meta-backend-private.h" #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-monitor-stream.h"
#include "backends/meta-screen-cast-session.h"
#include "backends/meta-logical-monitor.h" #include "backends/meta-logical-monitor.h"
#include "backends/meta-monitor.h" #include "backends/meta-monitor.h"
#include "clutter/clutter.h" #include "clutter/clutter.h"
#include "clutter/clutter-mutter.h" #include "clutter/clutter-mutter.h"
#include "core/boxes-private.h"
struct _MetaScreenCastMonitorStreamSrc struct _MetaScreenCastMonitorStreamSrc
{ {
MetaScreenCastStreamSrc parent; 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, static void
meta_screen_cast_monitor_stream_src, hw_cursor_inhibitor_iface_init (MetaHwCursorInhibitorInterface *iface);
META_TYPE_SCREEN_CAST_STREAM_SRC)
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 * static ClutterStage *
get_stage (MetaScreenCastMonitorStreamSrc *monitor_src) get_stage (MetaScreenCastMonitorStreamSrc *monitor_src)
@ -102,18 +117,164 @@ stage_painted (ClutterActor *actor,
meta_screen_cast_stream_src_maybe_record_frame (src); 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 static void
meta_screen_cast_monitor_stream_src_enable (MetaScreenCastStreamSrc *src) meta_screen_cast_monitor_stream_src_enable (MetaScreenCastStreamSrc *src)
{ {
MetaScreenCastMonitorStreamSrc *monitor_src = MetaScreenCastMonitorStreamSrc *monitor_src =
META_SCREEN_CAST_MONITOR_STREAM_SRC (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; ClutterStage *stage;
MetaScreenCastStream *stream;
stream = meta_screen_cast_stream_src_get_stream (src);
stage = get_stage (monitor_src); stage = get_stage (monitor_src);
monitor_src->stage_painted_handler_id =
g_signal_connect_after (stage, "paint", switch (meta_screen_cast_stream_get_cursor_mode (stream))
G_CALLBACK (stage_painted), {
monitor_src); 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)); clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
} }
@ -122,14 +283,43 @@ meta_screen_cast_monitor_stream_src_disable (MetaScreenCastStreamSrc *src)
{ {
MetaScreenCastMonitorStreamSrc *monitor_src = MetaScreenCastMonitorStreamSrc *monitor_src =
META_SCREEN_CAST_MONITOR_STREAM_SRC (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; ClutterStage *stage;
stage = get_stage (monitor_src); 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, meta_screen_cast_monitor_stream_src_record_frame (MetaScreenCastStreamSrc *src,
uint8_t *data) uint8_t *data)
{ {
@ -140,9 +330,226 @@ meta_screen_cast_monitor_stream_src_record_frame (MetaScreenCastStreamSrc *src,
MetaLogicalMonitor *logical_monitor; MetaLogicalMonitor *logical_monitor;
stage = get_stage (monitor_src); stage = get_stage (monitor_src);
if (!clutter_stage_is_redraw_queued (stage))
return FALSE;
monitor = get_monitor (monitor_src); monitor = get_monitor (monitor_src);
logical_monitor = meta_monitor_get_logical_monitor (monitor); logical_monitor = meta_monitor_get_logical_monitor (monitor);
clutter_stage_capture_into (stage, FALSE, &logical_monitor->rect, data); 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 * MetaScreenCastMonitorStreamSrc *
@ -157,6 +564,7 @@ meta_screen_cast_monitor_stream_src_new (MetaScreenCastMonitorStream *monitor_s
static void static void
meta_screen_cast_monitor_stream_src_init (MetaScreenCastMonitorStreamSrc *monitor_src) meta_screen_cast_monitor_stream_src_init (MetaScreenCastMonitorStreamSrc *monitor_src)
{ {
monitor_src->cursor_bitmap_invalid = TRUE;
} }
static void 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->enable = meta_screen_cast_monitor_stream_src_enable;
src_class->disable = meta_screen_cast_monitor_stream_src_disable; src_class->disable = meta_screen_cast_monitor_stream_src_disable;
src_class->record_frame = meta_screen_cast_monitor_stream_src_record_frame; 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;
} }

View File

@ -105,12 +105,15 @@ meta_screen_cast_monitor_stream_get_monitor (MetaScreenCastMonitorStream *monito
} }
MetaScreenCastMonitorStream * MetaScreenCastMonitorStream *
meta_screen_cast_monitor_stream_new (GDBusConnection *connection, meta_screen_cast_monitor_stream_new (MetaScreenCastSession *session,
MetaMonitorManager *monitor_manager, GDBusConnection *connection,
MetaMonitor *monitor, MetaMonitor *monitor,
ClutterStage *stage, ClutterStage *stage,
GError **error) MetaScreenCastCursorMode cursor_mode,
GError **error)
{ {
MetaGpu *gpu = meta_monitor_get_gpu (monitor);
MetaMonitorManager *monitor_manager = meta_gpu_get_monitor_manager (gpu);
MetaScreenCastMonitorStream *monitor_stream; MetaScreenCastMonitorStream *monitor_stream;
if (!meta_monitor_is_active (monitor)) 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, monitor_stream = g_initable_new (META_TYPE_SCREEN_CAST_MONITOR_STREAM,
NULL, NULL,
error, error,
"session", session,
"connection", connection, "connection", connection,
"cursor-mode", cursor_mode,
"monitor", monitor, "monitor", monitor,
NULL); NULL);
if (!monitor_stream) if (!monitor_stream)

View File

@ -27,6 +27,7 @@
#include "backends/meta-monitor-manager-private.h" #include "backends/meta-monitor-manager-private.h"
#include "backends/meta-screen-cast-stream.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 ()) #define META_TYPE_SCREEN_CAST_MONITOR_STREAM (meta_screen_cast_monitor_stream_get_type ())
G_DECLARE_FINAL_TYPE (MetaScreenCastMonitorStream, G_DECLARE_FINAL_TYPE (MetaScreenCastMonitorStream,
@ -34,11 +35,12 @@ G_DECLARE_FINAL_TYPE (MetaScreenCastMonitorStream,
META, SCREEN_CAST_MONITOR_STREAM, META, SCREEN_CAST_MONITOR_STREAM,
MetaScreenCastStream) MetaScreenCastStream)
MetaScreenCastMonitorStream * meta_screen_cast_monitor_stream_new (GDBusConnection *connection, MetaScreenCastMonitorStream * meta_screen_cast_monitor_stream_new (MetaScreenCastSession *session,
MetaMonitorManager *monitor_manager, GDBusConnection *connection,
MetaMonitor *monitor, MetaMonitor *monitor,
ClutterStage *stage, ClutterStage *stage,
GError **error); MetaScreenCastCursorMode cursor_mode,
GError **error);
ClutterStage * meta_screen_cast_monitor_stream_get_stage (MetaScreenCastMonitorStream *monitor_stream); ClutterStage * meta_screen_cast_monitor_stream_get_stage (MetaScreenCastMonitorStream *monitor_stream);

View File

@ -38,6 +38,8 @@ struct _MetaScreenCastSession
{ {
MetaDBusScreenCastSessionSkeleton parent; MetaDBusScreenCastSessionSkeleton parent;
MetaScreenCast *screen_cast;
char *peer_name; char *peer_name;
MetaScreenCastSessionType session_type; MetaScreenCastSessionType session_type;
@ -159,6 +161,12 @@ meta_screen_cast_session_get_stream (MetaScreenCastSession *session,
return NULL; return NULL;
} }
MetaScreenCast *
meta_screen_cast_session_get_screen_cast (MetaScreenCastSession *session)
{
return session->screen_cast;
}
char * char *
meta_screen_cast_session_get_object_path (MetaScreenCastSession *session) meta_screen_cast_session_get_object_path (MetaScreenCastSession *session)
{ {
@ -254,6 +262,20 @@ on_stream_closed (MetaScreenCastStream *stream,
meta_screen_cast_session_close (session); 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 static gboolean
handle_record_monitor (MetaDBusScreenCastSession *skeleton, handle_record_monitor (MetaDBusScreenCastSession *skeleton,
GDBusMethodInvocation *invocation, GDBusMethodInvocation *invocation,
@ -267,6 +289,7 @@ handle_record_monitor (MetaDBusScreenCastSession *skeleton,
MetaMonitorManager *monitor_manager = MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend); meta_backend_get_monitor_manager (backend);
MetaMonitor *monitor; MetaMonitor *monitor;
MetaScreenCastCursorMode cursor_mode;
ClutterStage *stage; ClutterStage *stage;
GError *error = NULL; GError *error = NULL;
MetaScreenCastMonitorStream *monitor_stream; MetaScreenCastMonitorStream *monitor_stream;
@ -298,12 +321,28 @@ handle_record_monitor (MetaDBusScreenCastSession *skeleton,
return TRUE; 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)); 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,
monitor_manager, connection,
monitor, monitor,
stage, stage,
cursor_mode,
&error); &error);
if (!monitor_stream) if (!monitor_stream)
{ {
@ -382,7 +421,8 @@ handle_record_window (MetaDBusScreenCastSession *skeleton,
interface_skeleton = G_DBUS_INTERFACE_SKELETON (skeleton); interface_skeleton = G_DBUS_INTERFACE_SKELETON (skeleton);
connection = g_dbus_interface_skeleton_get_connection (interface_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, window,
&error); &error);
if (!window_stream) if (!window_stream)
@ -442,6 +482,7 @@ meta_screen_cast_session_new (MetaScreenCast *screen_cast,
static unsigned int global_session_number = 0; static unsigned int global_session_number = 0;
session = g_object_new (META_TYPE_SCREEN_CAST_SESSION, NULL); session = g_object_new (META_TYPE_SCREEN_CAST_SESSION, NULL);
session->screen_cast = screen_cast;
session->session_type = session_type; session->session_type = session_type;
session->peer_name = g_strdup (peer_name); session->peer_name = g_strdup (peer_name);
session->object_path = session->object_path =

View File

@ -60,4 +60,6 @@ void meta_screen_cast_session_close (MetaScreenCastSession *session);
MetaScreenCastStream * meta_screen_cast_session_get_stream (MetaScreenCastSession *session, MetaScreenCastStream * meta_screen_cast_session_get_stream (MetaScreenCastSession *session,
const char *path); const char *path);
MetaScreenCast * meta_screen_cast_session_get_screen_cast (MetaScreenCastSession *session);
#endif /* META_SCREEN_CAST_SESSION_H */ #endif /* META_SCREEN_CAST_SESSION_H */

View File

@ -40,6 +40,10 @@
#define PRIVATE_OWNER_FROM_FIELD(TypeName, field_ptr, field_name) \ #define PRIVATE_OWNER_FROM_FIELD(TypeName, field_ptr, field_name) \
(TypeName *)((guint8 *)(field_ptr) - G_PRIVATE_OFFSET (TypeName, 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 enum
{ {
PROP_0, PROP_0,
@ -57,14 +61,6 @@ enum
static guint signals[N_SIGNALS]; 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 typedef struct _MetaPipeWireSource
{ {
GSource base; GSource base;
@ -133,14 +129,68 @@ meta_screen_cast_stream_src_get_videocrop (MetaScreenCastStreamSrc *src,
return FALSE; return FALSE;
} }
static void static gboolean
meta_screen_cast_stream_src_record_frame (MetaScreenCastStreamSrc *src, meta_screen_cast_stream_src_record_frame (MetaScreenCastStreamSrc *src,
uint8_t *data) uint8_t *data)
{ {
MetaScreenCastStreamSrcClass *klass = MetaScreenCastStreamSrcClass *klass =
META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src); 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 void
@ -151,7 +201,6 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src)
MetaRectangle crop_rect; MetaRectangle crop_rect;
struct pw_buffer *buffer; struct pw_buffer *buffer;
struct spa_buffer *spa_buffer; struct spa_buffer *spa_buffer;
struct spa_meta_video_crop *spa_meta_video_crop;
uint8_t *map = NULL; uint8_t *map = NULL;
uint8_t *data; uint8_t *data;
uint64_t now_us; uint64_t now_us;
@ -199,35 +248,45 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src)
return; return;
} }
meta_screen_cast_stream_src_record_frame (src, data); if (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_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; if (meta_screen_cast_stream_src_get_videocrop (src, &crop_rect))
spa_meta_video_crop->y = crop_rect.y; {
spa_meta_video_crop->width = crop_rect.width; spa_meta_video_crop->x = crop_rect.x;
spa_meta_video_crop->height = crop_rect.height; spa_meta_video_crop->y = crop_rect.y;
} spa_meta_video_crop->width = crop_rect.width;
else spa_meta_video_crop->height = crop_rect.height;
{ }
spa_meta_video_crop->x = 0; else
spa_meta_video_crop->y = 0; {
spa_meta_video_crop->width = priv->stream_width; spa_meta_video_crop->x = 0;
spa_meta_video_crop->height = priv->stream_height; 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; priv->last_frame_timestamp_us = now_us;
if (map) if (map)
munmap (map, spa_buffer->datas[0].maxsize + spa_buffer->datas[0].mapoffset); 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); pw_stream_queue_buffer (priv->pipewire_stream, buffer);
} }
@ -314,7 +373,7 @@ on_stream_format_changed (void *data,
uint8_t params_buffer[1024]; uint8_t params_buffer[1024];
int32_t width, height, stride, size; int32_t width, height, stride, size;
struct spa_pod_builder pod_builder; struct spa_pod_builder pod_builder;
const struct spa_pod *params[2]; const struct spa_pod *params[3];
const int bpp = 4; const int bpp = 4;
if (!format) 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.type, "I", pipewire_type->meta.VideoCrop,
":", pipewire_type->param_meta.size, "i", sizeof (struct spa_meta_video_crop)); ":", 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, pw_stream_finish_format (priv->pipewire_stream, 0,
params, G_N_ELEMENTS (params)); 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_media_subtype_map (map, &type->media_subtype);
spa_type_format_video_map (map, &type->format_video); spa_type_format_video_map (map, &type->format_video);
spa_type_video_format_map (map, &type->video_format); spa_type_video_format_map (map, &type->video_format);
type->meta_cursor = spa_type_map_get_id(map, SPA_TYPE_META__Cursor);
} }
static MetaPipeWireSource * static MetaPipeWireSource *

View File

@ -24,10 +24,26 @@
#define META_SCREEN_CAST_STREAM_SRC_H #define META_SCREEN_CAST_STREAM_SRC_H
#include <glib-object.h> #include <glib-object.h>
#include <spa/param/video/format-utils.h>
#include <spa/buffer/meta.h>
#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 "clutter/clutter.h"
#include "cogl/cogl.h"
#include "meta/boxes.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; typedef struct _MetaScreenCastStream MetaScreenCastStream;
#define META_TYPE_SCREEN_CAST_STREAM_SRC (meta_screen_cast_stream_src_get_type ()) #define META_TYPE_SCREEN_CAST_STREAM_SRC (meta_screen_cast_stream_src_get_type ())
@ -46,14 +62,18 @@ struct _MetaScreenCastStreamSrcClass
float *frame_rate); float *frame_rate);
void (* enable) (MetaScreenCastStreamSrc *src); void (* enable) (MetaScreenCastStreamSrc *src);
void (* disable) (MetaScreenCastStreamSrc *src); void (* disable) (MetaScreenCastStreamSrc *src);
void (* record_frame) (MetaScreenCastStreamSrc *src, gboolean (* record_frame) (MetaScreenCastStreamSrc *src,
uint8_t *data); uint8_t *data);
gboolean (* get_videocrop) (MetaScreenCastStreamSrc *src, gboolean (* get_videocrop) (MetaScreenCastStreamSrc *src,
MetaRectangle *crop_rect); 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); void meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src);
MetaScreenCastStream * meta_screen_cast_stream_src_get_stream (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 */ #endif /* META_SCREEN_CAST_STREAM_SRC_H */

View File

@ -24,13 +24,17 @@
#include "backends/meta-screen-cast-stream.h" #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" #define META_SCREEN_CAST_STREAM_DBUS_PATH "/org/gnome/Mutter/ScreenCast/Stream"
enum enum
{ {
PROP_0, PROP_0,
PROP_SESSION,
PROP_CONNECTION, PROP_CONNECTION,
PROP_CURSOR_MODE,
}; };
enum enum
@ -44,9 +48,13 @@ static guint signals[N_SIGNALS];
typedef struct _MetaScreenCastStreamPrivate typedef struct _MetaScreenCastStreamPrivate
{ {
MetaScreenCastSession *session;
GDBusConnection *connection; GDBusConnection *connection;
char *object_path; char *object_path;
MetaScreenCastCursorMode cursor_mode;
MetaScreenCastStreamSrc *src; MetaScreenCastStreamSrc *src;
} MetaScreenCastStreamPrivate; } MetaScreenCastStreamPrivate;
@ -97,6 +105,15 @@ on_stream_src_ready (MetaScreenCastStreamSrc *src,
meta_dbus_screen_cast_stream_emit_pipewire_stream_added (skeleton, node_id); 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 gboolean
meta_screen_cast_stream_start (MetaScreenCastStream *stream, meta_screen_cast_stream_start (MetaScreenCastStream *stream,
GError **error) GError **error)
@ -150,6 +167,15 @@ meta_screen_cast_stream_transform_position (MetaScreenCastStream *stream,
y); 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 static void
meta_screen_cast_stream_set_property (GObject *object, meta_screen_cast_stream_set_property (GObject *object,
guint prop_id, guint prop_id,
@ -162,9 +188,15 @@ meta_screen_cast_stream_set_property (GObject *object,
switch (prop_id) switch (prop_id)
{ {
case PROP_SESSION:
priv->session = g_value_get_object (value);
break;
case PROP_CONNECTION: case PROP_CONNECTION:
priv->connection = g_value_get_object (value); priv->connection = g_value_get_object (value);
break; break;
case PROP_CURSOR_MODE:
priv->cursor_mode = g_value_get_uint (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 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) switch (prop_id)
{ {
case PROP_SESSION:
g_value_set_object (value, priv->session);
break;
case PROP_CONNECTION: case PROP_CONNECTION:
g_value_set_object (value, priv->connection); g_value_set_object (value, priv->connection);
break; break;
case PROP_CURSOR_MODE:
g_value_set_uint (value, priv->cursor_mode);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 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->set_property = meta_screen_cast_stream_set_property;
object_class->get_property = meta_screen_cast_stream_get_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, g_object_class_install_property (object_class,
PROP_CONNECTION, PROP_CONNECTION,
g_param_spec_object ("connection", g_param_spec_object ("connection",
@ -266,6 +314,18 @@ meta_screen_cast_stream_class_init (MetaScreenCastStreamClass *klass)
G_PARAM_CONSTRUCT_ONLY | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS)); 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", signals[CLOSED] = g_signal_new ("closed",
G_TYPE_FROM_CLASS (klass), G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, G_SIGNAL_RUN_LAST,

View File

@ -26,8 +26,12 @@
#include <glib-object.h> #include <glib-object.h>
#include "backends/meta-screen-cast-stream-src.h" #include "backends/meta-screen-cast-stream-src.h"
#include "backends/meta-screen-cast.h"
#include "meta-dbus-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 ()) #define META_TYPE_SCREEN_CAST_STREAM (meta_screen_cast_stream_get_type ())
G_DECLARE_DERIVABLE_TYPE (MetaScreenCastStream, meta_screen_cast_stream, G_DECLARE_DERIVABLE_TYPE (MetaScreenCastStream, meta_screen_cast_stream,
META, SCREEN_CAST_STREAM, META, SCREEN_CAST_STREAM,
@ -48,6 +52,8 @@ struct _MetaScreenCastStreamClass
double *y); double *y);
}; };
MetaScreenCastSession * meta_screen_cast_stream_get_session (MetaScreenCastStream *stream);
gboolean meta_screen_cast_stream_start (MetaScreenCastStream *stream, gboolean meta_screen_cast_stream_start (MetaScreenCastStream *stream,
GError **error); GError **error);
@ -61,4 +67,6 @@ void meta_screen_cast_stream_transform_position (MetaScreenCastStream *stream,
double *x, double *x,
double *y); double *y);
MetaScreenCastCursorMode meta_screen_cast_stream_get_cursor_mode (MetaScreenCastStream *stream);
#endif /* META_SCREEN_CAST_STREAM_H */ #endif /* META_SCREEN_CAST_STREAM_H */

View File

@ -207,7 +207,7 @@ meta_screen_cast_window_stream_src_disable (MetaScreenCastStreamSrc *src)
meta_screen_cast_window_stream_src_stop (window_src); meta_screen_cast_window_stream_src_stop (window_src);
} }
static void static gboolean
meta_screen_cast_window_stream_src_record_frame (MetaScreenCastStreamSrc *src, meta_screen_cast_window_stream_src_record_frame (MetaScreenCastStreamSrc *src,
uint8_t *data) uint8_t *data)
{ {
@ -215,6 +215,8 @@ meta_screen_cast_window_stream_src_record_frame (MetaScreenCastStreamSrc *src,
META_SCREEN_CAST_WINDOW_STREAM_SRC (src); META_SCREEN_CAST_WINDOW_STREAM_SRC (src);
capture_into (window_src, data); capture_into (window_src, data);
return TRUE;
} }
MetaScreenCastWindowStreamSrc * MetaScreenCastWindowStreamSrc *

View File

@ -71,9 +71,10 @@ meta_screen_cast_window_stream_get_height (MetaScreenCastWindowStream *window_st
} }
MetaScreenCastWindowStream * MetaScreenCastWindowStream *
meta_screen_cast_window_stream_new (GDBusConnection *connection, meta_screen_cast_window_stream_new (MetaScreenCastSession *session,
MetaWindow *window, GDBusConnection *connection,
GError **error) MetaWindow *window,
GError **error)
{ {
MetaScreenCastWindowStream *window_stream; MetaScreenCastWindowStream *window_stream;
MetaLogicalMonitor *logical_monitor; 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, window_stream = g_initable_new (META_TYPE_SCREEN_CAST_WINDOW_STREAM,
NULL, NULL,
error, error,
"session", session,
"connection", connection, "connection", connection,
"window", window, "window", window,
NULL); NULL);

View File

@ -32,9 +32,10 @@ G_DECLARE_FINAL_TYPE (MetaScreenCastWindowStream,
META, SCREEN_CAST_WINDOW_STREAM, META, SCREEN_CAST_WINDOW_STREAM,
MetaScreenCastStream) MetaScreenCastStream)
MetaScreenCastWindowStream * meta_screen_cast_window_stream_new (GDBusConnection *connection, MetaScreenCastWindowStream * meta_screen_cast_window_stream_new (MetaScreenCastSession *session,
MetaWindow *window, GDBusConnection *connection,
GError **error); MetaWindow *window,
GError **error);
MetaWindow * meta_screen_cast_window_stream_get_window (MetaScreenCastWindowStream *window_stream); MetaWindow * meta_screen_cast_window_stream_get_window (MetaScreenCastWindowStream *window_stream);
int meta_screen_cast_window_stream_get_width (MetaScreenCastWindowStream *window_stream); int meta_screen_cast_window_stream_get_width (MetaScreenCastWindowStream *window_stream);

View File

@ -43,6 +43,7 @@ struct _MetaScreenCast
GList *sessions; GList *sessions;
MetaDbusSessionWatcher *session_watcher; MetaDbusSessionWatcher *session_watcher;
MetaBackend *backend;
}; };
static void static void
@ -62,12 +63,20 @@ meta_screen_cast_get_connection (MetaScreenCast *screen_cast)
return g_dbus_interface_skeleton_get_connection (interface_skeleton); return g_dbus_interface_skeleton_get_connection (interface_skeleton);
} }
MetaBackend *
meta_screen_cast_get_backend (MetaScreenCast *screen_cast)
{
return screen_cast->backend;
}
static gboolean static gboolean
register_remote_desktop_screen_cast_session (MetaScreenCastSession *session, register_remote_desktop_screen_cast_session (MetaScreenCastSession *session,
const char *remote_desktop_session_id, const char *remote_desktop_session_id,
GError **error) 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); MetaRemoteDesktop *remote_desktop = meta_backend_get_remote_desktop (backend);
MetaRemoteDesktopSession *remote_desktop_session; MetaRemoteDesktopSession *remote_desktop_session;
@ -244,11 +253,13 @@ meta_screen_cast_finalize (GObject *object)
} }
MetaScreenCast * MetaScreenCast *
meta_screen_cast_new (MetaDbusSessionWatcher *session_watcher) meta_screen_cast_new (MetaBackend *backend,
MetaDbusSessionWatcher *session_watcher)
{ {
MetaScreenCast *screen_cast; MetaScreenCast *screen_cast;
screen_cast = g_object_new (META_TYPE_SCREEN_CAST, NULL); screen_cast = g_object_new (META_TYPE_SCREEN_CAST, NULL);
screen_cast->backend = backend;
screen_cast->session_watcher = session_watcher; screen_cast->session_watcher = session_watcher;
return screen_cast; return screen_cast;

View File

@ -25,9 +25,17 @@
#include <glib-object.h> #include <glib-object.h>
#include "backends/meta-backend-private.h"
#include "backends/meta-dbus-session-watcher.h" #include "backends/meta-dbus-session-watcher.h"
#include "meta-dbus-screen-cast.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 ()) #define META_TYPE_SCREEN_CAST (meta_screen_cast_get_type ())
G_DECLARE_FINAL_TYPE (MetaScreenCast, meta_screen_cast, G_DECLARE_FINAL_TYPE (MetaScreenCast, meta_screen_cast,
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); 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 */ #endif /* META_SCREEN_CAST_H */

View File

@ -30,7 +30,17 @@
#include "backends/meta-backend-private.h" #include "backends/meta-backend-private.h"
#include "clutter/clutter-mutter.h" #include "clutter/clutter-mutter.h"
struct _MetaOverlay { enum
{
ACTORS_PAINTED,
N_SIGNALS
};
static guint signals[N_SIGNALS];
struct _MetaOverlay
{
gboolean enabled; gboolean enabled;
CoglPipeline *pipeline; CoglPipeline *pipeline;
@ -140,6 +150,8 @@ meta_stage_paint (ClutterActor *actor)
CLUTTER_ACTOR_CLASS (meta_stage_parent_class)->paint (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) for (l = priv->overlays; l; l = l->next)
meta_overlay_paint (l->data); meta_overlay_paint (l->data);
} }
@ -179,6 +191,13 @@ meta_stage_class_init (MetaStageClass *klass)
stage_class->activate = meta_stage_activate; stage_class->activate = meta_stage_activate;
stage_class->deactivate = meta_stage_deactivate; 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 static void

View File

@ -587,6 +587,10 @@ should_have_hw_cursor (MetaCursorRenderer *renderer,
if (!cursor_sprite) if (!cursor_sprite)
return FALSE; return FALSE;
if (meta_cursor_renderer_is_hw_cursors_inhibited (renderer,
cursor_sprite))
return FALSE;
for (l = gpus; l; l = l->next) for (l = gpus; l; l = l->next)
{ {
MetaGpuKms *gpu_kms = l->data; MetaGpuKms *gpu_kms = l->data;

View File

@ -71,7 +71,15 @@
Record a single monitor. 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
--> -->
<method name="RecordMonitor"> <method name="RecordMonitor">
<arg name="connector" type="s" direction="in" /> <arg name="connector" type="s" direction="in" />
@ -84,7 +92,7 @@
@properties: Properties used determining what window to select @properties: Properties used determining what window to select
@stream_path: Path to the new stream object @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: Available @properties include: