2021-02-01 04:57:35 -05:00
|
|
|
/*
|
|
|
|
* 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
|
2023-08-07 05:50:23 -04:00
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
2021-02-01 04:57:35 -05:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#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"
|
2023-08-29 14:34:05 -04:00
|
|
|
#include "backends/meta-monitor.h"
|
|
|
|
#include "backends/meta-output.h"
|
2021-02-01 04:57:35 -05:00
|
|
|
#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;
|
2022-04-29 10:05:50 -04:00
|
|
|
gulong prepare_frame_handler_id;
|
2021-02-01 04:57:35 -05:00
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2023-08-29 14:34:05 -04:00
|
|
|
MetaLogicalMonitor *
|
|
|
|
meta_screen_cast_virtual_stream_src_logical_monitor (MetaScreenCastVirtualStreamSrc *virtual_src)
|
|
|
|
{
|
|
|
|
MetaVirtualMonitor *virtual_monitor = virtual_src->virtual_monitor;
|
|
|
|
MetaOutput *output = meta_virtual_monitor_get_output (virtual_monitor);
|
|
|
|
MetaMonitor *monitor = meta_output_get_monitor (output);
|
|
|
|
|
|
|
|
return meta_monitor_get_logical_monitor (monitor);
|
|
|
|
}
|
|
|
|
|
2021-02-01 04:57:35 -05:00
|
|
|
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;
|
2023-02-03 14:33:57 -05:00
|
|
|
meta_screen_cast_stream_src_maybe_record_frame (src, flags, NULL);
|
2021-02-01 04:57:35 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2022-04-29 10:05:50 -04:00
|
|
|
pointer_position_invalidated (MetaCursorTracker *cursor_tracker,
|
|
|
|
MetaScreenCastStreamSrc *src)
|
2021-02-01 04:57:35 -05:00
|
|
|
{
|
2022-04-29 10:05:50 -04:00
|
|
|
ClutterStage *stage = stage_from_src (src);
|
|
|
|
|
|
|
|
clutter_stage_schedule_update (stage);
|
2021-02-01 04:57:35 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
cursor_changed (MetaCursorTracker *cursor_tracker,
|
|
|
|
MetaScreenCastVirtualStreamSrc *virtual_src)
|
|
|
|
{
|
|
|
|
virtual_src->cursor_bitmap_invalid = TRUE;
|
|
|
|
sync_cursor_state (virtual_src);
|
|
|
|
}
|
|
|
|
|
2022-04-29 10:05:50 -04:00
|
|
|
static void
|
|
|
|
on_prepare_frame (ClutterStage *stage,
|
|
|
|
ClutterStageView *stage_view,
|
2022-10-13 11:50:34 -04:00
|
|
|
ClutterFrame *frame,
|
2022-04-29 10:05:50 -04:00
|
|
|
MetaScreenCastVirtualStreamSrc *virtual_src)
|
|
|
|
{
|
|
|
|
sync_cursor_state (virtual_src);
|
|
|
|
}
|
|
|
|
|
2021-02-01 04:57:35 -05:00
|
|
|
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,
|
2023-01-24 09:59:17 -05:00
|
|
|
ClutterFrame *frame,
|
2021-02-01 04:57:35 -05:00
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (user_data);
|
|
|
|
MetaScreenCastRecordFlag flags;
|
2023-02-03 14:33:57 -05:00
|
|
|
const cairo_region_t *redraw_clip = NULL;
|
2021-02-01 04:57:35 -05:00
|
|
|
|
|
|
|
flags = META_SCREEN_CAST_RECORD_FLAG_NONE;
|
2023-02-03 14:33:57 -05:00
|
|
|
redraw_clip = clutter_paint_context_get_redraw_clip (paint_context);
|
|
|
|
meta_screen_cast_stream_src_maybe_record_frame (src, flags, redraw_clip);
|
2021-02-01 04:57:35 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
add_watch (MetaScreenCastVirtualStreamSrc *virtual_src)
|
|
|
|
{
|
|
|
|
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (virtual_src);
|
2022-09-16 11:44:35 -04:00
|
|
|
MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src);
|
2021-02-01 04:57:35 -05:00
|
|
|
MetaStage *meta_stage = META_STAGE (stage_from_src (src));
|
|
|
|
|
|
|
|
g_return_if_fail (!virtual_src->watch);
|
|
|
|
|
2022-09-16 11:44:35 -04:00
|
|
|
switch (meta_screen_cast_stream_get_cursor_mode (stream))
|
|
|
|
{
|
|
|
|
case META_SCREEN_CAST_CURSOR_MODE_METADATA:
|
|
|
|
case META_SCREEN_CAST_CURSOR_MODE_HIDDEN:
|
|
|
|
virtual_src->watch = meta_stage_watch_view (meta_stage,
|
|
|
|
view_from_src (src),
|
|
|
|
META_STAGE_WATCH_AFTER_ACTOR_PAINT,
|
|
|
|
actors_painted,
|
|
|
|
virtual_src);
|
|
|
|
break;
|
|
|
|
case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED:
|
|
|
|
virtual_src->watch = meta_stage_watch_view (meta_stage,
|
|
|
|
view_from_src (src),
|
|
|
|
META_STAGE_WATCH_AFTER_PAINT,
|
|
|
|
actors_painted,
|
|
|
|
virtual_src);
|
|
|
|
break;
|
|
|
|
}
|
2021-02-01 04:57:35 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2022-04-29 10:05:50 -04:00
|
|
|
ClutterStage *stage = stage_from_src (src);
|
2021-02-01 04:57:35 -05:00
|
|
|
|
|
|
|
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);
|
2022-04-29 10:05:50 -04:00
|
|
|
virtual_src->prepare_frame_handler_id =
|
|
|
|
g_signal_connect_after (stage, "prepare-frame",
|
|
|
|
G_CALLBACK (on_prepare_frame),
|
|
|
|
virtual_src);
|
2021-02-01 04:57:35 -05:00
|
|
|
G_GNUC_FALLTHROUGH;
|
|
|
|
case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED:
|
|
|
|
case META_SCREEN_CAST_CURSOR_MODE_HIDDEN:
|
|
|
|
add_watch (virtual_src);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-09-04 05:44:48 -04:00
|
|
|
meta_screen_cast_stream_notify_is_configured (stream);
|
|
|
|
|
2021-02-01 04:57:35 -05:00
|
|
|
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);
|
2022-04-29 10:05:50 -04:00
|
|
|
ClutterStage *stage = stage_from_src (src);
|
2021-02-01 04:57:35 -05:00
|
|
|
|
|
|
|
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);
|
2022-04-29 10:05:50 -04:00
|
|
|
g_clear_signal_handler (&virtual_src->prepare_frame_handler_id,
|
|
|
|
stage);
|
2021-02-01 04:57:35 -05:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
meta_screen_cast_virtual_stream_src_record_to_buffer (MetaScreenCastStreamSrc *src,
|
|
|
|
int width,
|
|
|
|
int height,
|
|
|
|
int stride,
|
|
|
|
uint8_t *data,
|
|
|
|
GError **error)
|
|
|
|
{
|
2022-09-16 16:03:53 -04:00
|
|
|
MetaScreenCastStream *stream;
|
|
|
|
ClutterPaintFlag paint_flags;
|
|
|
|
ClutterStageView *view;
|
2023-07-19 19:46:15 -04:00
|
|
|
MtkRectangle view_rect;
|
2022-09-16 16:03:53 -04:00
|
|
|
float scale;
|
|
|
|
|
|
|
|
stream = meta_screen_cast_stream_src_get_stream (src);
|
|
|
|
view = view_from_src (src);
|
|
|
|
scale = clutter_stage_view_get_scale (view);
|
|
|
|
clutter_stage_view_get_layout (view, &view_rect);
|
|
|
|
|
|
|
|
paint_flags = CLUTTER_PAINT_FLAG_CLEAR;
|
|
|
|
switch (meta_screen_cast_stream_get_cursor_mode (stream))
|
|
|
|
{
|
|
|
|
case META_SCREEN_CAST_CURSOR_MODE_METADATA:
|
|
|
|
case META_SCREEN_CAST_CURSOR_MODE_HIDDEN:
|
|
|
|
paint_flags |= CLUTTER_PAINT_FLAG_NO_CURSORS;
|
|
|
|
break;
|
|
|
|
case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED:
|
|
|
|
paint_flags |= CLUTTER_PAINT_FLAG_FORCE_CURSORS;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!clutter_stage_paint_to_buffer (stage_from_src (src),
|
|
|
|
&view_rect,
|
|
|
|
scale,
|
|
|
|
data,
|
|
|
|
stride,
|
|
|
|
CLUTTER_CAIRO_FORMAT_ARGB32,
|
|
|
|
paint_flags,
|
|
|
|
error))
|
|
|
|
return FALSE;
|
2021-02-01 04:57:35 -05:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2023-07-19 19:46:15 -04:00
|
|
|
MtkRectangle damage;
|
2021-02-01 04:57:35 -05:00
|
|
|
|
|
|
|
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);
|
2023-07-19 19:46:15 -04:00
|
|
|
MtkRectangle view_layout;
|
2021-02-01 04:57:35 -05:00
|
|
|
graphene_rect_t view_rect;
|
|
|
|
MetaCursorSprite *cursor_sprite;
|
|
|
|
|
|
|
|
clutter_stage_view_get_layout (stage_view, &view_layout);
|
2023-08-08 06:27:58 -04:00
|
|
|
view_rect = mtk_rectangle_to_graphene_rect (&view_layout);
|
2021-02-01 04:57:35 -05:00
|
|
|
|
|
|
|
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;
|
2023-07-19 19:46:15 -04:00
|
|
|
MtkRectangle view_layout;
|
2021-02-01 04:57:35 -05:00
|
|
|
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);
|
2023-08-08 06:27:58 -04:00
|
|
|
view_rect = mtk_rectangle_to_graphene_rect (&view_layout);
|
2021-02-01 04:57:35 -05:00
|
|
|
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;
|
2022-07-02 12:50:45 -04:00
|
|
|
MetaMonitorTransform transform;
|
2021-02-01 04:57:35 -05:00
|
|
|
|
|
|
|
cursor_scale = meta_cursor_sprite_get_texture_scale (cursor_sprite);
|
|
|
|
scale = view_scale * cursor_scale;
|
2022-07-02 12:50:45 -04:00
|
|
|
transform = meta_cursor_sprite_get_texture_transform (cursor_sprite);
|
|
|
|
|
2021-02-01 04:57:35 -05:00
|
|
|
meta_screen_cast_stream_src_set_cursor_sprite_metadata (src,
|
|
|
|
spa_meta_cursor,
|
|
|
|
cursor_sprite,
|
|
|
|
x, y,
|
2022-07-02 12:50:45 -04:00
|
|
|
scale,
|
|
|
|
transform);
|
2021-02-01 04:57:35 -05:00
|
|
|
}
|
|
|
|
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);
|
2022-02-03 05:45:18 -05:00
|
|
|
float refresh_rate;
|
2021-02-01 04:57:35 -05:00
|
|
|
|
|
|
|
if (mode_info->width == video_format->size.width &&
|
|
|
|
mode_info->height == video_format->size.height)
|
|
|
|
return;
|
|
|
|
|
2022-02-03 05:45:18 -05:00
|
|
|
refresh_rate = ((float) video_format->max_framerate.num /
|
|
|
|
video_format->max_framerate.denom);
|
|
|
|
meta_virtual_monitor_set_mode (virtual_monitor,
|
|
|
|
video_format->size.width,
|
|
|
|
video_format->size.height,
|
|
|
|
refresh_rate);
|
|
|
|
meta_monitor_manager_reload (monitor_manager);
|
|
|
|
return;
|
2021-02-01 04:57:35 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-02-03 05:45:18 -05:00
|
|
|
static void
|
|
|
|
meta_screen_cast_virtual_stream_src_dispose (GObject *object)
|
|
|
|
{
|
|
|
|
MetaScreenCastVirtualStreamSrc *virtual_src =
|
|
|
|
META_SCREEN_CAST_VIRTUAL_STREAM_SRC (object);
|
|
|
|
GObjectClass *parent_class =
|
|
|
|
G_OBJECT_CLASS (meta_screen_cast_virtual_stream_src_parent_class);
|
|
|
|
|
|
|
|
parent_class->dispose (object);
|
|
|
|
|
|
|
|
g_clear_object (&virtual_src->virtual_monitor);
|
|
|
|
}
|
|
|
|
|
2021-02-01 04:57:35 -05:00
|
|
|
static void
|
|
|
|
meta_screen_cast_virtual_stream_src_init (MetaScreenCastVirtualStreamSrc *virtual_src)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_screen_cast_virtual_stream_src_class_init (MetaScreenCastVirtualStreamSrcClass *klass)
|
|
|
|
{
|
2022-02-03 05:45:18 -05:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
2021-02-01 04:57:35 -05:00
|
|
|
MetaScreenCastStreamSrcClass *src_class =
|
|
|
|
META_SCREEN_CAST_STREAM_SRC_CLASS (klass);
|
|
|
|
|
2022-02-03 05:45:18 -05:00
|
|
|
object_class->dispose = meta_screen_cast_virtual_stream_src_dispose;
|
|
|
|
|
2021-02-01 04:57:35 -05:00
|
|
|
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;
|
|
|
|
}
|