mirror of
https://github.com/brl/mutter.git
synced 2024-11-27 18:40:40 -05:00
613 lines
21 KiB
C
613 lines
21 KiB
C
|
/*
|
||
|
* 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;
|
||
|
}
|