diff --git a/src/backends/meta-screen-cast-session.c b/src/backends/meta-screen-cast-session.c index 10c37ee88..3925738d4 100644 --- a/src/backends/meta-screen-cast-session.c +++ b/src/backends/meta-screen-cast-session.c @@ -30,6 +30,7 @@ #include "backends/meta-screen-cast-area-stream.h" #include "backends/meta-screen-cast-monitor-stream.h" #include "backends/meta-screen-cast-stream.h" +#include "backends/meta-screen-cast-virtual-stream.h" #include "backends/meta-screen-cast-window-stream.h" #include "core/display-private.h" @@ -600,6 +601,83 @@ handle_record_area (MetaDBusScreenCastSession *skeleton, return TRUE; } +static gboolean +handle_record_virtual (MetaDBusScreenCastSession *skeleton, + GDBusMethodInvocation *invocation, + GVariant *properties_variant) +{ + MetaScreenCastSession *session = META_SCREEN_CAST_SESSION (skeleton); + GDBusInterfaceSkeleton *interface_skeleton; + GDBusConnection *connection; + MetaScreenCastCursorMode cursor_mode; + gboolean is_platform; + MetaScreenCastFlag flags; + g_autoptr (GError) error = NULL; + MetaScreenCastVirtualStream *virtual_stream; + MetaScreenCastStream *stream; + char *stream_path; + + if (!check_permission (session, invocation)) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_ACCESS_DENIED, + "Permission denied"); + 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; + } + } + + if (!g_variant_lookup (properties_variant, "is-platform", "b", &is_platform)) + is_platform = FALSE; + + interface_skeleton = G_DBUS_INTERFACE_SKELETON (skeleton); + connection = g_dbus_interface_skeleton_get_connection (interface_skeleton); + + flags = META_SCREEN_CAST_FLAG_NONE; + if (is_platform) + flags |= META_SCREEN_CAST_FLAG_IS_PLATFORM; + + virtual_stream = meta_screen_cast_virtual_stream_new (session, + connection, + cursor_mode, + flags, + &error); + if (!virtual_stream) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, + G_DBUS_ERROR_FAILED, + "Failed to record virtual: %s", + error->message); + return TRUE; + } + + stream = META_SCREEN_CAST_STREAM (virtual_stream); + stream_path = meta_screen_cast_stream_get_object_path (stream); + + session->streams = g_list_append (session->streams, stream); + + g_signal_connect (stream, "closed", G_CALLBACK (on_stream_closed), session); + + meta_dbus_screen_cast_session_complete_record_virtual (skeleton, + invocation, + stream_path); + + return TRUE; +} + static void meta_screen_cast_session_init_iface (MetaDBusScreenCastSessionIface *iface) { @@ -608,6 +686,7 @@ meta_screen_cast_session_init_iface (MetaDBusScreenCastSessionIface *iface) iface->handle_record_monitor = handle_record_monitor; iface->handle_record_window = handle_record_window; iface->handle_record_area = handle_record_area; + iface->handle_record_virtual = handle_record_virtual; } static void diff --git a/src/backends/meta-screen-cast-virtual-stream-src.c b/src/backends/meta-screen-cast-virtual-stream-src.c new file mode 100644 index 000000000..47a917da9 --- /dev/null +++ b/src/backends/meta-screen-cast-virtual-stream-src.c @@ -0,0 +1,612 @@ +/* + * Copyright (C) 2021 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + */ + +#include "config.h" + +#include "backends/meta-screen-cast-virtual-stream-src.h" + +#include "backends/meta-crtc-mode.h" +#include "backends/meta-cursor-tracker-private.h" +#include "backends/meta-screen-cast-session.h" +#include "backends/meta-stage-private.h" +#include "backends/meta-virtual-monitor.h" +#include "core/boxes-private.h" + +struct _MetaScreenCastVirtualStreamSrc +{ + MetaScreenCastStreamSrc parent; + + MetaVirtualMonitor *virtual_monitor; + + gboolean cursor_bitmap_invalid; + gboolean hw_cursor_inhibited; + + MetaStageWatch *watch; + + gulong position_invalidated_handler_id; + gulong cursor_changed_handler_id; + + gulong monitors_changed_handler_id; +}; + +static void +hw_cursor_inhibitor_iface_init (MetaHwCursorInhibitorInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (MetaScreenCastVirtualStreamSrc, + meta_screen_cast_virtual_stream_src, + META_TYPE_SCREEN_CAST_STREAM_SRC, + G_IMPLEMENT_INTERFACE (META_TYPE_HW_CURSOR_INHIBITOR, + hw_cursor_inhibitor_iface_init)) + +static gboolean +meta_screen_cast_virtual_stream_src_get_specs (MetaScreenCastStreamSrc *src, + int *width, + int *height, + float *frame_rate) +{ + return FALSE; +} + +static MetaBackend * +backend_from_src (MetaScreenCastStreamSrc *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 ClutterStageView * +view_from_src (MetaScreenCastStreamSrc *src) +{ + MetaScreenCastVirtualStreamSrc *virtual_src = + META_SCREEN_CAST_VIRTUAL_STREAM_SRC (src); + MetaVirtualMonitor *virtual_monitor = virtual_src->virtual_monitor; + MetaCrtc *crtc = meta_virtual_monitor_get_crtc (virtual_monitor); + MetaRenderer *renderer = meta_backend_get_renderer (backend_from_src (src)); + MetaRendererView *view = meta_renderer_get_view_for_crtc (renderer, crtc); + + return CLUTTER_STAGE_VIEW (view); +} + +static ClutterStage * +stage_from_src (MetaScreenCastStreamSrc *src) +{ + return CLUTTER_STAGE (meta_backend_get_stage (backend_from_src (src))); +} + +static gboolean +is_redraw_queued (MetaScreenCastVirtualStreamSrc *virtual_src) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (virtual_src); + + return clutter_stage_is_redraw_queued_on_view (stage_from_src (src), + view_from_src (src)); +} + +ClutterStageView * +meta_screen_cast_virtual_stream_src_get_view (MetaScreenCastVirtualStreamSrc *virtual_src) +{ + return view_from_src (META_SCREEN_CAST_STREAM_SRC (virtual_src)); +} + +static void +sync_cursor_state (MetaScreenCastVirtualStreamSrc *virtual_src) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (virtual_src); + MetaScreenCastRecordFlag flags; + + if (is_redraw_queued (virtual_src)) + return; + + if (meta_screen_cast_stream_src_pending_follow_up_frame (src)) + return; + + flags = META_SCREEN_CAST_RECORD_FLAG_CURSOR_ONLY; + meta_screen_cast_stream_src_maybe_record_frame (src, flags); +} + +static void +pointer_position_invalidated (MetaCursorTracker *cursor_tracker, + MetaScreenCastVirtualStreamSrc *virtual_src) +{ + sync_cursor_state (virtual_src); +} + +static void +cursor_changed (MetaCursorTracker *cursor_tracker, + MetaScreenCastVirtualStreamSrc *virtual_src) +{ + virtual_src->cursor_bitmap_invalid = TRUE; + sync_cursor_state (virtual_src); +} + +static void +inhibit_hw_cursor (MetaScreenCastVirtualStreamSrc *virtual_src) +{ + MetaHwCursorInhibitor *inhibitor; + MetaBackend *backend; + + g_return_if_fail (!virtual_src->hw_cursor_inhibited); + + backend = backend_from_src (META_SCREEN_CAST_STREAM_SRC (virtual_src)); + inhibitor = META_HW_CURSOR_INHIBITOR (virtual_src); + meta_backend_add_hw_cursor_inhibitor (backend, inhibitor); + + virtual_src->hw_cursor_inhibited = TRUE; +} + +static void +uninhibit_hw_cursor (MetaScreenCastVirtualStreamSrc *virtual_src) +{ + MetaHwCursorInhibitor *inhibitor; + MetaBackend *backend; + + g_return_if_fail (virtual_src->hw_cursor_inhibited); + + backend = backend_from_src (META_SCREEN_CAST_STREAM_SRC (virtual_src)); + inhibitor = META_HW_CURSOR_INHIBITOR (virtual_src); + meta_backend_remove_hw_cursor_inhibitor (backend, inhibitor); + + virtual_src->hw_cursor_inhibited = FALSE; +} + +static void +actors_painted (MetaStage *stage, + ClutterStageView *view, + ClutterPaintContext *paint_context, + gpointer user_data) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (user_data); + MetaScreenCastRecordFlag flags; + + flags = META_SCREEN_CAST_RECORD_FLAG_NONE; + meta_screen_cast_stream_src_maybe_record_frame (src, flags); +} + +static void +add_watch (MetaScreenCastVirtualStreamSrc *virtual_src) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (virtual_src); + MetaStage *meta_stage = META_STAGE (stage_from_src (src)); + + g_return_if_fail (!virtual_src->watch); + + virtual_src->watch = meta_stage_watch_view (meta_stage, + view_from_src (src), + META_STAGE_WATCH_AFTER_PAINT, + actors_painted, + virtual_src); +} + +static void +on_monitors_changed (MetaMonitorManager *monitor_manager, + MetaScreenCastVirtualStreamSrc *virtual_src) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (virtual_src); + MetaStage *stage = META_STAGE (stage_from_src (src)); + + meta_stage_remove_watch (stage, virtual_src->watch); + virtual_src->watch = NULL; + add_watch (virtual_src); +} + +static void +init_record_callbacks (MetaScreenCastVirtualStreamSrc *virtual_src) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (virtual_src); + MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src); + MetaBackend *backend = backend_from_src (src); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + MetaCursorTracker *cursor_tracker = + meta_backend_get_cursor_tracker (backend); + + switch (meta_screen_cast_stream_get_cursor_mode (stream)) + { + case META_SCREEN_CAST_CURSOR_MODE_METADATA: + virtual_src->position_invalidated_handler_id = + g_signal_connect_after (cursor_tracker, "position-invalidated", + G_CALLBACK (pointer_position_invalidated), + virtual_src); + virtual_src->cursor_changed_handler_id = + g_signal_connect_after (cursor_tracker, "cursor-changed", + G_CALLBACK (cursor_changed), + virtual_src); + G_GNUC_FALLTHROUGH; + case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED: + case META_SCREEN_CAST_CURSOR_MODE_HIDDEN: + add_watch (virtual_src); + break; + } + + if (meta_screen_cast_stream_get_cursor_mode (stream) == + META_SCREEN_CAST_CURSOR_MODE_EMBEDDED) + inhibit_hw_cursor (virtual_src); + + virtual_src->monitors_changed_handler_id = + g_signal_connect (monitor_manager, "monitors-changed-internal", + G_CALLBACK (on_monitors_changed), + virtual_src); +} + +static void +meta_screen_cast_virtual_stream_src_enable (MetaScreenCastStreamSrc *src) +{ + MetaScreenCastVirtualStreamSrc *virtual_src = + META_SCREEN_CAST_VIRTUAL_STREAM_SRC (src); + MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src); + MetaBackend *backend = backend_from_src (src); + MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend); + + switch (meta_screen_cast_stream_get_cursor_mode (stream)) + { + case META_SCREEN_CAST_CURSOR_MODE_METADATA: + case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED: + meta_cursor_tracker_track_position (cursor_tracker); + break; + case META_SCREEN_CAST_CURSOR_MODE_HIDDEN: + break; + } + + init_record_callbacks (virtual_src); + clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage_from_src (src)), + NULL); + clutter_stage_schedule_update (stage_from_src (src)); +} + +static void +meta_screen_cast_virtual_stream_src_disable (MetaScreenCastStreamSrc *src) +{ + MetaScreenCastVirtualStreamSrc *virtual_src = + META_SCREEN_CAST_VIRTUAL_STREAM_SRC (src); + MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src); + MetaBackend *backend = backend_from_src (src); + MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + + if (virtual_src->hw_cursor_inhibited) + uninhibit_hw_cursor (virtual_src); + + if (virtual_src->watch) + { + meta_stage_remove_watch (META_STAGE (stage_from_src (src)), + virtual_src->watch); + virtual_src->watch = NULL; + } + + g_clear_signal_handler (&virtual_src->position_invalidated_handler_id, + cursor_tracker); + g_clear_signal_handler (&virtual_src->cursor_changed_handler_id, + cursor_tracker); + + g_clear_signal_handler (&virtual_src->monitors_changed_handler_id, + monitor_manager); + + switch (meta_screen_cast_stream_get_cursor_mode (stream)) + { + case META_SCREEN_CAST_CURSOR_MODE_METADATA: + case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED: + meta_cursor_tracker_untrack_position (cursor_tracker); + break; + case META_SCREEN_CAST_CURSOR_MODE_HIDDEN: + break; + } + + g_clear_object (&virtual_src->virtual_monitor); +} + +static gboolean +meta_screen_cast_virtual_stream_src_record_to_buffer (MetaScreenCastStreamSrc *src, + int width, + int height, + int stride, + uint8_t *data, + GError **error) +{ + clutter_stage_capture_view_into (stage_from_src (src), + view_from_src (src), + NULL, + data, + stride); + + return TRUE; +} + +static gboolean +meta_screen_cast_virtual_stream_src_record_to_framebuffer (MetaScreenCastStreamSrc *src, + CoglFramebuffer *framebuffer, + GError **error) +{ + ClutterStageView *view; + CoglFramebuffer *view_framebuffer; + + view = view_from_src (src); + view_framebuffer = clutter_stage_view_get_framebuffer (view); + if (!cogl_blit_framebuffer (view_framebuffer, + framebuffer, + 0, 0, + 0, 0, + cogl_framebuffer_get_width (view_framebuffer), + cogl_framebuffer_get_height (view_framebuffer), + error)) + return FALSE; + + cogl_framebuffer_flush (framebuffer); + return TRUE; +} + +static void +meta_screen_cast_virtual_stream_record_follow_up (MetaScreenCastStreamSrc *src) +{ + MetaRectangle damage; + + clutter_stage_view_get_layout (view_from_src (src), &damage); + damage.width = 1; + damage.height = 1; + + clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage_from_src (src)), + &damage); +} + +static gboolean +is_cursor_in_stream (MetaScreenCastVirtualStreamSrc *virtual_src) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (virtual_src); + MetaBackend *backend = backend_from_src (src); + MetaCursorRenderer *cursor_renderer = + meta_backend_get_cursor_renderer (backend); + ClutterStageView *stage_view = view_from_src (src); + MetaRectangle view_layout; + graphene_rect_t view_rect; + MetaCursorSprite *cursor_sprite; + + clutter_stage_view_get_layout (stage_view, &view_layout); + view_rect = meta_rectangle_to_graphene_rect (&view_layout); + + cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer); + if (cursor_sprite) + { + graphene_rect_t cursor_rect; + + cursor_rect = meta_cursor_renderer_calculate_rect (cursor_renderer, + cursor_sprite); + return graphene_rect_intersection (&cursor_rect, &view_rect, NULL); + } + else + { + MetaCursorTracker *cursor_tracker = + meta_backend_get_cursor_tracker (backend); + graphene_point_t cursor_position; + + meta_cursor_tracker_get_pointer (cursor_tracker, &cursor_position, NULL); + return graphene_rect_contains_point (&view_rect, + &cursor_position); + } +} + +static void +meta_screen_cast_virtual_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *src, + struct spa_meta_cursor *spa_meta_cursor) +{ + MetaScreenCastVirtualStreamSrc *virtual_src = + META_SCREEN_CAST_VIRTUAL_STREAM_SRC (src); + MetaBackend *backend = backend_from_src (src); + MetaCursorRenderer *cursor_renderer = + meta_backend_get_cursor_renderer (backend); + MetaCursorTracker *cursor_tracker = + meta_backend_get_cursor_tracker (backend); + MetaCursorSprite *cursor_sprite; + ClutterStageView *stage_view; + MetaRectangle view_layout; + float view_scale; + graphene_rect_t view_rect; + graphene_point_t cursor_position; + int x, y; + + cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer); + + if (!meta_cursor_tracker_get_pointer_visible (cursor_tracker) || + !is_cursor_in_stream (virtual_src)) + { + meta_screen_cast_stream_src_unset_cursor_metadata (src, + spa_meta_cursor); + return; + } + + stage_view = view_from_src (src); + clutter_stage_view_get_layout (stage_view, &view_layout); + view_rect = meta_rectangle_to_graphene_rect (&view_layout); + view_scale = clutter_stage_view_get_scale (stage_view); + + meta_cursor_tracker_get_pointer (cursor_tracker, &cursor_position, NULL); + cursor_position.x -= view_rect.origin.x; + cursor_position.y -= view_rect.origin.y; + cursor_position.x *= view_scale; + cursor_position.y *= view_scale; + + x = (int) roundf (cursor_position.x); + y = (int) roundf (cursor_position.y); + + if (virtual_src->cursor_bitmap_invalid) + { + if (cursor_sprite) + { + float cursor_scale; + float scale; + + cursor_scale = meta_cursor_sprite_get_texture_scale (cursor_sprite); + scale = view_scale * cursor_scale; + meta_screen_cast_stream_src_set_cursor_sprite_metadata (src, + spa_meta_cursor, + cursor_sprite, + x, y, + scale); + } + else + { + meta_screen_cast_stream_src_set_empty_cursor_sprite_metadata (src, + spa_meta_cursor, + x, y); + } + + virtual_src->cursor_bitmap_invalid = FALSE; + } + else + { + meta_screen_cast_stream_src_set_cursor_position_metadata (src, + spa_meta_cursor, + x, y); + } +} + +static MetaVirtualMonitor * +create_virtual_monitor (MetaScreenCastVirtualStreamSrc *virtual_src, + struct spa_video_info_raw *video_format, + GError **error) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (virtual_src); + MetaBackend *backend = backend_from_src (src); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + static int virtual_monitor_src_seq = 0; + int width, height; + float refresh_rate; + g_autofree char *serial = NULL; + g_autoptr (MetaVirtualMonitorInfo) info = NULL; + + width = video_format->size.width; + height = video_format->size.height; + refresh_rate = ((float) video_format->max_framerate.num / + video_format->max_framerate.denom); + serial = g_strdup_printf ("0x%.6x", ++virtual_monitor_src_seq); + info = meta_virtual_monitor_info_new (width, height, refresh_rate, + "MetaVendor", + "Virtual remote monitor", + serial); + return meta_monitor_manager_create_virtual_monitor (monitor_manager, + info, + error); +} + +static void +ensure_virtual_monitor (MetaScreenCastVirtualStreamSrc *virtual_src, + struct spa_video_info_raw *video_format) +{ + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (virtual_src); + MetaBackend *backend = backend_from_src (src); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + g_autoptr (GError) error = NULL; + MetaVirtualMonitor *virtual_monitor; + + virtual_monitor = virtual_src->virtual_monitor; + if (virtual_monitor) + { + MetaCrtcMode *crtc_mode = + meta_virtual_monitor_get_crtc_mode (virtual_monitor); + const MetaCrtcModeInfo *mode_info = meta_crtc_mode_get_info (crtc_mode); + + if (mode_info->width == video_format->size.width && + mode_info->height == video_format->size.height) + return; + + g_clear_object (&virtual_src->virtual_monitor); + } + + virtual_monitor = create_virtual_monitor (virtual_src, video_format, &error); + if (!virtual_monitor) + { + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (virtual_src); + + g_warning ("Failed to create virtual monitor with size %dx%d: %s", + video_format->size.width, video_format->size.height, + error->message); + meta_screen_cast_stream_src_close (src); + return; + } + virtual_src->virtual_monitor = virtual_monitor; + + meta_monitor_manager_reload (monitor_manager); +} + +static void +meta_screen_cast_virtual_stream_src_notify_params_updated (MetaScreenCastStreamSrc *src, + struct spa_video_info_raw *video_format) +{ + MetaScreenCastVirtualStreamSrc *virtual_src = + META_SCREEN_CAST_VIRTUAL_STREAM_SRC (src); + + ensure_virtual_monitor (virtual_src, video_format); +} + +MetaScreenCastVirtualStreamSrc * +meta_screen_cast_virtual_stream_src_new (MetaScreenCastVirtualStream *virtual_stream, + GError **error) +{ + return g_initable_new (META_TYPE_SCREEN_CAST_VIRTUAL_STREAM_SRC, NULL, error, + "stream", virtual_stream, + NULL); +} + +static gboolean +meta_screen_cast_virtual_stream_src_is_cursor_inhibited (MetaHwCursorInhibitor *inhibitor) +{ + MetaScreenCastVirtualStreamSrc *virtual_src = + META_SCREEN_CAST_VIRTUAL_STREAM_SRC (inhibitor); + + return is_cursor_in_stream (virtual_src); +} + +static void +hw_cursor_inhibitor_iface_init (MetaHwCursorInhibitorInterface *iface) +{ + iface->is_cursor_inhibited = + meta_screen_cast_virtual_stream_src_is_cursor_inhibited; +} + +static void +meta_screen_cast_virtual_stream_src_init (MetaScreenCastVirtualStreamSrc *virtual_src) +{ +} + +static void +meta_screen_cast_virtual_stream_src_class_init (MetaScreenCastVirtualStreamSrcClass *klass) +{ + MetaScreenCastStreamSrcClass *src_class = + META_SCREEN_CAST_STREAM_SRC_CLASS (klass); + + src_class->get_specs = meta_screen_cast_virtual_stream_src_get_specs; + src_class->enable = meta_screen_cast_virtual_stream_src_enable; + src_class->disable = meta_screen_cast_virtual_stream_src_disable; + src_class->record_to_buffer = + meta_screen_cast_virtual_stream_src_record_to_buffer; + src_class->record_to_framebuffer = + meta_screen_cast_virtual_stream_src_record_to_framebuffer; + src_class->record_follow_up = + meta_screen_cast_virtual_stream_record_follow_up; + src_class->set_cursor_metadata = + meta_screen_cast_virtual_stream_src_set_cursor_metadata; + src_class->notify_params_updated = + meta_screen_cast_virtual_stream_src_notify_params_updated; +} diff --git a/src/backends/meta-screen-cast-virtual-stream-src.h b/src/backends/meta-screen-cast-virtual-stream-src.h new file mode 100644 index 000000000..a891166bd --- /dev/null +++ b/src/backends/meta-screen-cast-virtual-stream-src.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2021 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + */ + +#ifndef META_SCREEN_CAST_VIRTUAL_STREAM_SRC_H +#define META_SCREEN_CAST_VIRTUAL_STREAM_SRC_H + +#include "backends/meta-screen-cast-stream-src.h" +#include "backends/meta-screen-cast-virtual-stream.h" + +#define META_TYPE_SCREEN_CAST_VIRTUAL_STREAM_SRC (meta_screen_cast_virtual_stream_src_get_type ()) +G_DECLARE_FINAL_TYPE (MetaScreenCastVirtualStreamSrc, + meta_screen_cast_virtual_stream_src, + META, SCREEN_CAST_VIRTUAL_STREAM_SRC, + MetaScreenCastStreamSrc) + +MetaScreenCastVirtualStreamSrc * meta_screen_cast_virtual_stream_src_new (MetaScreenCastVirtualStream *virtual_stream, + GError **error); + +ClutterStageView * meta_screen_cast_virtual_stream_src_get_view (MetaScreenCastVirtualStreamSrc *virtual_src); + +#endif /* META_SCREEN_CAST_VIRTUAL_STREAM_SRC_H */ diff --git a/src/backends/meta-screen-cast-virtual-stream.c b/src/backends/meta-screen-cast-virtual-stream.c new file mode 100644 index 000000000..34dd2a00c --- /dev/null +++ b/src/backends/meta-screen-cast-virtual-stream.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2021 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + */ + +#include "config.h" + +#include "backends/meta-screen-cast-virtual-stream.h" + +#include "backends/meta-screen-cast-virtual-stream-src.h" +#include "backends/meta-virtual-monitor.h" + + +struct _MetaScreenCastVirtualStream +{ + MetaScreenCastStream parent; +}; + +G_DEFINE_TYPE (MetaScreenCastVirtualStream, + meta_screen_cast_virtual_stream, + META_TYPE_SCREEN_CAST_STREAM) + +MetaScreenCastVirtualStream * +meta_screen_cast_virtual_stream_new (MetaScreenCastSession *session, + GDBusConnection *connection, + MetaScreenCastCursorMode cursor_mode, + MetaScreenCastFlag flags, + GError **error) +{ + MetaScreenCastVirtualStream *virtual_stream; + + virtual_stream = g_initable_new (META_TYPE_SCREEN_CAST_VIRTUAL_STREAM, + NULL, + error, + "session", session, + "connection", connection, + "cursor-mode", cursor_mode, + "flags", flags, + NULL); + if (!virtual_stream) + return NULL; + + return virtual_stream; +} + +static MetaScreenCastStreamSrc * +meta_screen_cast_virtual_stream_create_src (MetaScreenCastStream *stream, + GError **error) +{ + MetaScreenCastVirtualStream *virtual_stream = + META_SCREEN_CAST_VIRTUAL_STREAM (stream); + MetaScreenCastVirtualStreamSrc *virtual_stream_src; + + virtual_stream_src = meta_screen_cast_virtual_stream_src_new (virtual_stream, + error); + if (!virtual_stream_src) + return NULL; + + return META_SCREEN_CAST_STREAM_SRC (virtual_stream_src); +} + +static void +meta_screen_cast_virtual_stream_set_parameters (MetaScreenCastStream *stream, + GVariantBuilder *parameters_builder) +{ +} + +static gboolean +meta_screen_cast_virtual_stream_transform_position (MetaScreenCastStream *stream, + double stream_x, + double stream_y, + double *x, + double *y) +{ + MetaScreenCastStreamSrc *src = meta_screen_cast_stream_get_src (stream); + MetaScreenCastVirtualStreamSrc *virtual_src = + META_SCREEN_CAST_VIRTUAL_STREAM_SRC (src); + ClutterStageView *view; + MetaRectangle view_layout; + + view = meta_screen_cast_virtual_stream_src_get_view (virtual_src); + if (!view) + return FALSE; + + clutter_stage_view_get_layout (view, &view_layout); + *x = stream_x + view_layout.x; + *y = stream_y + view_layout.y; + + return TRUE; +} + +static void +meta_screen_cast_virtual_stream_init (MetaScreenCastVirtualStream *virtual_stream) +{ +} + +static void +meta_screen_cast_virtual_stream_class_init (MetaScreenCastVirtualStreamClass *klass) +{ + MetaScreenCastStreamClass *stream_class = + META_SCREEN_CAST_STREAM_CLASS (klass); + + stream_class->create_src = meta_screen_cast_virtual_stream_create_src; + stream_class->set_parameters = meta_screen_cast_virtual_stream_set_parameters; + stream_class->transform_position = meta_screen_cast_virtual_stream_transform_position; +} diff --git a/src/backends/meta-screen-cast-virtual-stream.h b/src/backends/meta-screen-cast-virtual-stream.h new file mode 100644 index 000000000..422db5e26 --- /dev/null +++ b/src/backends/meta-screen-cast-virtual-stream.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2021 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + */ + +#ifndef META_SCREEN_CAST_VIRTUAL_STREAM_H +#define META_SCREEN_CAST_VIRTUAL_STREAM_H + +#include "backends/meta-screen-cast-stream.h" + +#define META_TYPE_SCREEN_CAST_VIRTUAL_STREAM (meta_screen_cast_virtual_stream_get_type ()) +G_DECLARE_FINAL_TYPE (MetaScreenCastVirtualStream, + meta_screen_cast_virtual_stream, + META, SCREEN_CAST_VIRTUAL_STREAM, + MetaScreenCastStream) + +MetaScreenCastVirtualStream * meta_screen_cast_virtual_stream_new (MetaScreenCastSession *session, + GDBusConnection *connection, + MetaScreenCastCursorMode cursor_mode, + MetaScreenCastFlag flags, + GError **error); + +MetaVirtualMonitor * meta_screen_cast_virtual_stream_get_virtual_monitor (MetaScreenCastVirtualStream *virtual_stream); + +#endif /* META_SCREEN_CAST_VIRTUAL_STREAM_H */ diff --git a/src/backends/meta-screen-cast.h b/src/backends/meta-screen-cast.h index e2ea5a5e4..be297e28d 100644 --- a/src/backends/meta-screen-cast.h +++ b/src/backends/meta-screen-cast.h @@ -41,6 +41,7 @@ typedef enum _MetaScreenCastFlag { META_SCREEN_CAST_FLAG_NONE = 0, META_SCREEN_CAST_FLAG_IS_RECORDING = 1 << 0, + META_SCREEN_CAST_FLAG_IS_PLATFORM = 1 << 1, } MetaScreenCastFlag; #define META_TYPE_SCREEN_CAST (meta_screen_cast_get_type ()) diff --git a/src/meson.build b/src/meson.build index fe3d1ccaf..459a56315 100644 --- a/src/meson.build +++ b/src/meson.build @@ -480,6 +480,10 @@ if have_remote_desktop 'backends/meta-screen-cast-monitor-stream.h', 'backends/meta-screen-cast-monitor-stream-src.c', 'backends/meta-screen-cast-monitor-stream-src.h', + 'backends/meta-screen-cast-virtual-stream-src.c', + 'backends/meta-screen-cast-virtual-stream-src.h', + 'backends/meta-screen-cast-virtual-stream.c', + 'backends/meta-screen-cast-virtual-stream.h', 'backends/meta-screen-cast-window-stream-src.c', 'backends/meta-screen-cast-window-stream-src.h', 'backends/meta-screen-cast-window-stream.c', diff --git a/src/org.gnome.Mutter.ScreenCast.xml b/src/org.gnome.Mutter.ScreenCast.xml index 07ab402eb..d9f1f4435 100644 --- a/src/org.gnome.Mutter.ScreenCast.xml +++ b/src/org.gnome.Mutter.ScreenCast.xml @@ -153,6 +153,35 @@ + + + + + +