diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e89e3f606578e4c05d2547dc273f386680925a66..19ce3c5207a909904463214ae2d85d2709a4c5ad 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -236,7 +236,7 @@ build-without-native-backend-and-wayland@x86_64: needs: - build-fedora-container@x86_64 script: - - meson . build -Dbuildtype=debugoptimized -Dnative_backend=false -Dudev=false -Dwayland=false -Dcore_tests=false --werror --prefix /usr + - meson . build -Dbuildtype=debugoptimized -Dnative_backend=false -Dudev=false -Dwayland=false -Dcore_tests=false -Dnative_tests=false --werror --prefix /usr - ninja -C build - ninja -C build install artifacts: @@ -254,7 +254,8 @@ build-without-native-backend-and-wayland@x86_64: MALLOC_CHECK_: "3" NO_AT_BRIDGE: "1" script: - - bash -x ./.gitlab-ci/run-tests.sh + - mkdir -m 700 $XDG_RUNTIME_DIR + - dbus-run-session -- bash -x ./.gitlab-ci/run-tests.sh artifacts: expire_in: 1 day reports: diff --git a/.gitlab-ci/run-tests.sh b/.gitlab-ci/run-tests.sh index 63726d11712f5126781c830bd87eb38842a02f96..b0a3d7dd146cab942fb2e8d6244f4c71d4291a41 100755 --- a/.gitlab-ci/run-tests.sh +++ b/.gitlab-ci/run-tests.sh @@ -1,17 +1,21 @@ #!/usr/bin/bash -set +e +set -e dconf update - -mkdir -m 700 $XDG_RUNTIME_DIR glib-compile-schemas $GSETTINGS_SCHEMA_DIR +# Disable audio support to not dead lock screen cast tests +rm -f /etc/pipewire/media-session.d/with-jack +rm -f /etc/pipewire/media-session.d/with-pulseaudio +pipewire & + +sleep 2 + export MUTTER_DEBUG_DUMMY_MODE_SPECS="800x600@10.0" -dbus-run-session -- \ - xvfb-run -s '+iglx -noreset' \ - meson test -C build --no-rebuild -t 10 --wrap catchsegv +xvfb-run -s '+iglx -noreset' \ + meson test -C build --no-rebuild -t 10 --wrap catchsegv exit_code=$? diff --git a/clutter/clutter/clutter-mutter.h b/clutter/clutter/clutter-mutter.h index 8f4e2390a012a177cbc1f23f10b51a38f491959d..88dee26587f5ef284e463eecb01e03c291b1c626 100644 --- a/clutter/clutter/clutter-mutter.h +++ b/clutter/clutter/clutter-mutter.h @@ -54,6 +54,13 @@ void clutter_stage_capture_into (ClutterStage *stage, cairo_rectangle_int_t *rect, uint8_t *data); +CLUTTER_EXPORT +void clutter_stage_capture_view_into (ClutterStage *stage, + ClutterStageView *view, + cairo_rectangle_int_t *rect, + uint8_t *data, + int stride); + CLUTTER_EXPORT void clutter_stage_clear_stage_views (ClutterStage *stage); diff --git a/clutter/clutter/clutter-stage-view-private.h b/clutter/clutter/clutter-stage-view-private.h index feee44e9e5ad1b4a8d8a43c088f2711662dc8f0e..345b595644be3dec6641ff14d3de2a7bb7679001 100644 --- a/clutter/clutter/clutter-stage-view-private.h +++ b/clutter/clutter/clutter-stage-view-private.h @@ -44,6 +44,7 @@ void clutter_stage_view_invalidate_projection (ClutterStageView *view); void clutter_stage_view_set_projection (ClutterStageView *view, const graphene_matrix_t *matrix); +CLUTTER_EXPORT void clutter_stage_view_add_redraw_clip (ClutterStageView *view, const cairo_rectangle_int_t *clip); @@ -63,6 +64,7 @@ void clutter_stage_view_transform_rect_to_onscreen (ClutterStageView int dst_height, cairo_rectangle_int_t *dst_rect); +CLUTTER_EXPORT void clutter_stage_view_schedule_update (ClutterStageView *view); void clutter_stage_view_notify_presented (ClutterStageView *view, diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c index 6e46187c59c047d756d13064964fdcd3a4b21c79..5b574b5e15e22e5b6c631afe6ffb87552789e144 100644 --- a/clutter/clutter/clutter-stage.c +++ b/clutter/clutter/clutter-stage.c @@ -175,11 +175,6 @@ static const ClutterColor default_stage_color = { 255, 255, 255, 255 }; static void free_queue_redraw_entry (QueueRedrawEntry *entry); static void free_pointer_device_entry (PointerDeviceEntry *entry); -static void capture_view_into (ClutterStage *stage, - ClutterStageView *view, - cairo_rectangle_int_t *rect, - uint8_t *data, - int stride); static void clutter_stage_update_view_perspective (ClutterStage *stage); static void clutter_stage_set_viewport (ClutterStage *stage, float width, @@ -3227,12 +3222,12 @@ clutter_stage_paint_to_buffer (ClutterStage *stage, return TRUE; } -static void -capture_view_into (ClutterStage *stage, - ClutterStageView *view, - cairo_rectangle_int_t *rect, - uint8_t *data, - int stride) +void +clutter_stage_capture_view_into (ClutterStage *stage, + ClutterStageView *view, + cairo_rectangle_int_t *rect, + uint8_t *data, + int stride) { CoglFramebuffer *framebuffer; ClutterBackend *backend; @@ -3247,6 +3242,11 @@ capture_view_into (ClutterStage *stage, framebuffer = clutter_stage_view_get_framebuffer (view); + clutter_stage_view_get_layout (view, &view_layout); + + if (!rect) + rect = &view_layout; + view_scale = clutter_stage_view_get_scale (view); texture_width = roundf (rect->width * view_scale); texture_height = roundf (rect->height * view_scale); @@ -3259,8 +3259,6 @@ capture_view_into (ClutterStage *stage, stride, data); - clutter_stage_view_get_layout (view, &view_layout); - cogl_framebuffer_read_pixels_into_bitmap (framebuffer, roundf ((rect->x - view_layout.x) * view_scale), roundf ((rect->y - view_layout.y) * view_scale), @@ -3300,10 +3298,12 @@ clutter_stage_capture_into (ClutterStage *stage, x_offset = capture_rect.x - rect->x; y_offset = capture_rect.y - rect->y; - capture_view_into (stage, view, - &capture_rect, - data + (x_offset * bpp) + (y_offset * stride), - stride); + clutter_stage_capture_view_into (stage, view, + &capture_rect, + (data + + (x_offset * bpp) + + (y_offset * stride)), + stride); } } diff --git a/meson.build b/meson.build index 4becf2b7d64fae17e85bf27343c1e11a850b3640..9dd8c5e2af0cf56c4bbf949a5c7e135958671590 100644 --- a/meson.build +++ b/meson.build @@ -262,6 +262,7 @@ have_tests = get_option('tests') have_core_tests = false have_cogl_tests = false have_clutter_tests = false +have_native_tests = false have_installed_tests = false if have_tests @@ -271,6 +272,15 @@ if have_tests error('Tests require Wayland to be enabled') endif endif + have_native_tests = get_option('native_tests') + if have_native_tests + if not have_native_backend + error('Native tests require the native backend') + endif + if not have_remote_desktop + error('Native tests require remote desktop') + endif + endif have_cogl_tests = get_option('cogl_tests') have_clutter_tests = get_option('clutter_tests') diff --git a/meson_options.txt b/meson_options.txt index a0fb616367756d48f0dfbfe05234983fed73a8aa..84e7dcc6c9cb2d7e154136a9024f1f0b89710ccd 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -117,6 +117,12 @@ option('core_tests', description: 'Enable mutter core tests' ) +option('native_tests', + type: 'boolean', + value: true, + description: 'Enable mutter native backend tests' +) + option('tests', type: 'boolean', value: true, diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h index 80df654bc679e4abc819e1188d3093488e5dd89a..0c328ffccde240f2594c77ddcf760f8ad9bd30ab 100644 --- a/src/backends/meta-backend-private.h +++ b/src/backends/meta-backend-private.h @@ -104,9 +104,14 @@ struct _MetaBackendClass MetaPointerConstraint *constraint); }; -void meta_init_backend (GType backend_gtype); +void meta_init_backend (GType backend_gtype, + unsigned int n_properties, + const char *names[], + const GValue *values); void meta_release_backend (void); +void meta_backend_prepare_shutdown (MetaBackend *backend); + #ifdef HAVE_WAYLAND MetaWaylandCompositor * meta_backend_get_wayland_compositor (MetaBackend *backend); diff --git a/src/backends/meta-backend-types.h b/src/backends/meta-backend-types.h index 146a8c3d7c3b1e6e38dce033342be5b8173bded0..eae62c02f244a1ccbfd7311368c81ea6d916101f 100644 --- a/src/backends/meta-backend-types.h +++ b/src/backends/meta-backend-types.h @@ -59,6 +59,9 @@ typedef struct _MetaScreenCastStream MetaScreenCastStream; typedef struct _MetaWaylandCompositor MetaWaylandCompositor; +typedef struct _MetaVirtualMonitor MetaVirtualMonitor; +typedef struct _MetaVirtualMonitorInfo MetaVirtualMonitorInfo; + #ifdef HAVE_REMOTE_DESKTOP typedef struct _MetaRemoteDesktop MetaRemoteDesktop; #endif diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c index 9e525957e0e7e3e3221cd9d47b183dbeb466f5d4..4eb0a8e7de599b2de6b334981455fc2755c71924 100644 --- a/src/backends/meta-backend.c +++ b/src/backends/meta-backend.c @@ -94,6 +94,7 @@ enum LAST_DEVICE_CHANGED, LID_IS_CLOSED_CHANGED, GPU_ADDED, + PREPARE_SHUTDOWN, N_SIGNALS }; @@ -455,6 +456,9 @@ on_device_added (ClutterSeat *seat, if (device_type == CLUTTER_TOUCHSCREEN_DEVICE) meta_cursor_tracker_set_pointer_visible (priv->cursor_tracker, FALSE); + else if (device_type == CLUTTER_POINTER_DEVICE && + !clutter_seat_has_touchscreen (seat)) + meta_cursor_tracker_set_pointer_visible (priv->cursor_tracker, TRUE); if (device_type == CLUTTER_TOUCHSCREEN_DEVICE || device_type == CLUTTER_TABLET_DEVICE || @@ -565,8 +569,26 @@ static void on_stage_shown_cb (MetaBackend *backend) { MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); + ClutterSeat *seat = clutter_backend_get_default_seat (priv->clutter_backend); + g_autoptr (GList) devices = NULL; + const GList *l; + + devices = clutter_seat_list_devices (seat); + for (l = devices; l; l = l->next) + { + ClutterInputDevice *device = l->data; + + if (clutter_input_device_get_device_mode (device) == + CLUTTER_INPUT_MODE_LOGICAL) + continue; + + if (clutter_input_device_get_device_type (device) != + CLUTTER_POINTER_DEVICE) + continue; - meta_cursor_tracker_set_pointer_visible (priv->cursor_tracker, TRUE); + meta_cursor_tracker_set_pointer_visible (priv->cursor_tracker, TRUE); + break; + } } static void @@ -869,6 +891,13 @@ meta_backend_class_init (MetaBackendClass *klass) 0, NULL, NULL, NULL, G_TYPE_NONE, 1, META_TYPE_GPU); + signals[PREPARE_SHUTDOWN] = + g_signal_new ("prepare-shutdown", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); mutter_stage_views = g_getenv ("MUTTER_STAGE_VIEWS"); stage_views_disabled = g_strcmp0 (mutter_stage_views, "0") == 0; @@ -1458,14 +1487,20 @@ meta_backend_get_clutter_backend (MetaBackend *backend) } void -meta_init_backend (GType backend_gtype) +meta_init_backend (GType backend_gtype, + unsigned int n_properties, + const char *names[], + const GValue *values) { MetaBackend *backend; GError *error = NULL; /* meta_backend_init() above install the backend globally so * so meta_get_backend() works even during initialization. */ - backend = g_object_new (backend_gtype, NULL); + backend = META_BACKEND (g_object_new_with_properties (backend_gtype, + n_properties, + names, + values)); if (!g_initable_init (G_INITABLE (backend), NULL, &error)) { g_warning ("Failed to create backend: %s", error->message); @@ -1479,6 +1514,12 @@ meta_release_backend (void) g_clear_object (&_backend); } +void +meta_backend_prepare_shutdown (MetaBackend *backend) +{ + g_signal_emit (backend, signals[PREPARE_SHUTDOWN], 0); +} + /** * meta_is_stage_views_enabled: * diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h index 70d61f823bd0bdf107c3afd1f54aa420314edb81..e191b50d0f6f8f94309a9e5f26d95afa5260bc23 100644 --- a/src/backends/meta-monitor-manager-private.h +++ b/src/backends/meta-monitor-manager-private.h @@ -261,6 +261,10 @@ struct _MetaMonitorManagerClass void (* set_output_ctm) (MetaOutput *output, const MetaOutputCtm *ctm); + + MetaVirtualMonitor * (* create_virtual_monitor) (MetaMonitorManager *manager, + const MetaVirtualMonitorInfo *info, + GError **error); }; META_EXPORT_TEST @@ -388,6 +392,12 @@ gboolean meta_monitor_manager_get_max_screen_size (MetaMonitorManager MetaLogicalMonitorLayoutMode meta_monitor_manager_get_default_layout_mode (MetaMonitorManager *manager); +META_EXPORT_TEST +MetaVirtualMonitor * meta_monitor_manager_create_virtual_monitor (MetaMonitorManager *manager, + const MetaVirtualMonitorInfo *info, + GError **error); + +META_EXPORT_TEST MetaMonitorConfigManager * meta_monitor_manager_get_config_manager (MetaMonitorManager *manager); @@ -424,4 +434,6 @@ void meta_monitor_manager_post_init (MetaMonitorManager *manager); MetaViewportInfo * meta_monitor_manager_get_viewports (MetaMonitorManager *manager); +GList * meta_monitor_manager_get_virtual_monitors (MetaMonitorManager *manager); + #endif /* META_MONITOR_MANAGER_PRIVATE_H */ diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c index 0fbdf566192fdcc1f8663d8ead396a434bea9779..005fa6791b52a0344699415a6e8de6119ad825f2 100644 --- a/src/backends/meta-monitor-manager.c +++ b/src/backends/meta-monitor-manager.c @@ -53,6 +53,7 @@ #include "backends/meta-monitor-config-manager.h" #include "backends/meta-orientation-manager.h" #include "backends/meta-output.h" +#include "backends/meta-virtual-monitor.h" #include "backends/x11/meta-monitor-manager-xrandr.h" #include "clutter/clutter.h" #include "core/main-private.h" @@ -101,6 +102,10 @@ typedef struct _MetaMonitorManagerPrivate { MetaPowerSave power_save_mode; gboolean initial_orient_change_done; + + GList *virtual_monitors; + + gboolean shutting_down; } MetaMonitorManagerPrivate; G_DEFINE_TYPE_WITH_PRIVATE (MetaMonitorManager, meta_monitor_manager, @@ -400,6 +405,16 @@ lid_is_closed_changed (MetaBackend *backend, meta_monitor_manager_lid_is_closed_changed (manager); } +static void +prepare_shutdown (MetaBackend *backend, + MetaMonitorManager *manager) +{ + MetaMonitorManagerPrivate *priv = + meta_monitor_manager_get_instance_private (manager); + + priv->shutting_down = TRUE; +} + /** * meta_monitor_manager_is_headless: * @manager: A #MetaMonitorManager object @@ -483,6 +498,60 @@ meta_monitor_manager_get_default_layout_mode (MetaMonitorManager *manager) return manager_class->get_default_layout_mode (manager); } +static void +on_virtual_monitor_destroyed (MetaVirtualMonitor *virtual_monitor, + MetaMonitorManager *manager) +{ + MetaMonitorManagerPrivate *priv = + meta_monitor_manager_get_instance_private (manager); + MetaOutput *output; + + output = meta_virtual_monitor_get_output (virtual_monitor); + g_message ("Removed virtual monitor %s", meta_output_get_name (output)); + priv->virtual_monitors = g_list_remove (priv->virtual_monitors, + virtual_monitor); + + if (!priv->shutting_down) + meta_monitor_manager_reload (manager); +} + +MetaVirtualMonitor * +meta_monitor_manager_create_virtual_monitor (MetaMonitorManager *manager, + const MetaVirtualMonitorInfo *info, + GError **error) +{ + MetaMonitorManagerPrivate *priv = + meta_monitor_manager_get_instance_private (manager); + MetaMonitorManagerClass *manager_class = + META_MONITOR_MANAGER_GET_CLASS (manager); + MetaVirtualMonitor *virtual_monitor; + MetaOutput *output; + + if (!manager_class->create_virtual_monitor) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "Backend doesn't support creating virtual monitors"); + return NULL; + } + + virtual_monitor = manager_class->create_virtual_monitor (manager, info, + error); + if (!virtual_monitor) + return NULL; + + g_signal_connect (virtual_monitor, "destroy", + G_CALLBACK (on_virtual_monitor_destroyed), + manager); + + priv->virtual_monitors = g_list_append (priv->virtual_monitors, + virtual_monitor); + + output = meta_virtual_monitor_get_output (virtual_monitor); + g_message ("Added virtual monitor %s", meta_output_get_name (output)); + + return virtual_monitor; +} + static void meta_monitor_manager_ensure_initial_config (MetaMonitorManager *manager) { @@ -896,6 +965,10 @@ meta_monitor_manager_constructed (GObject *object) G_CALLBACK (lid_is_closed_changed), manager, 0); + g_signal_connect (backend, "prepare-shutdown", + G_CALLBACK (prepare_shutdown), + manager); + manager->current_switch_config = META_MONITOR_SWITCH_CONFIG_UNKNOWN; initialize_dbus_interface (manager); @@ -905,9 +978,13 @@ static void meta_monitor_manager_finalize (GObject *object) { MetaMonitorManager *manager = META_MONITOR_MANAGER (object); + MetaMonitorManagerPrivate *priv = + meta_monitor_manager_get_instance_private (manager); g_list_free_full (manager->logical_monitors, g_object_unref); + g_warn_if_fail (!priv->virtual_monitors); + g_clear_signal_handler (&manager->experimental_features_changed_handler_id, manager->backend); @@ -2843,6 +2920,13 @@ meta_monitor_manager_get_power_save_mode (MetaMonitorManager *manager) return priv->power_save_mode; } +static void +destroy_monitor (MetaMonitor *monitor) +{ + g_object_run_dispose (G_OBJECT (monitor)); + g_object_unref (monitor); +} + static void rebuild_monitors (MetaMonitorManager *manager) { @@ -2851,7 +2935,7 @@ rebuild_monitors (MetaMonitorManager *manager) if (manager->monitors) { - g_list_free_full (manager->monitors, g_object_unref); + g_list_free_full (manager->monitors, (GDestroyNotify) destroy_monitor); manager->monitors = NULL; } @@ -2872,7 +2956,7 @@ rebuild_monitors (MetaMonitorManager *manager) { MetaMonitorTiled *monitor_tiled; - monitor_tiled = meta_monitor_tiled_new (gpu, manager, output); + monitor_tiled = meta_monitor_tiled_new (manager, output); manager->monitors = g_list_append (manager->monitors, monitor_tiled); } @@ -2881,12 +2965,24 @@ rebuild_monitors (MetaMonitorManager *manager) { MetaMonitorNormal *monitor_normal; - monitor_normal = meta_monitor_normal_new (gpu, manager, output); + monitor_normal = meta_monitor_normal_new (manager, output); manager->monitors = g_list_append (manager->monitors, monitor_normal); } } } + + for (l = meta_monitor_manager_get_virtual_monitors (manager); l; l = l->next) + { + MetaVirtualMonitor *virtual_monitor = l->data; + MetaOutput *output = meta_virtual_monitor_get_output (virtual_monitor); + MetaMonitorNormal *monitor_normal; + + monitor_normal = meta_monitor_normal_new (manager, output); + manager->monitors = g_list_append (manager->monitors, + monitor_normal); + + } } void @@ -3358,3 +3454,12 @@ meta_monitor_manager_get_viewports (MetaMonitorManager *manager) return info; } + +GList * +meta_monitor_manager_get_virtual_monitors (MetaMonitorManager *manager) +{ + MetaMonitorManagerPrivate *priv = + meta_monitor_manager_get_instance_private (manager); + + return priv->virtual_monitors; +} diff --git a/src/backends/meta-monitor.c b/src/backends/meta-monitor.c index 0be7994ad5501a5a8da88b2d27de03b845897406..e02f8ed4598cfd17bcedb8bb0922fd7c21e44528 100644 --- a/src/backends/meta-monitor.c +++ b/src/backends/meta-monitor.c @@ -55,7 +55,7 @@ typedef struct _MetaMonitorModeTiled typedef struct _MetaMonitorPrivate { - MetaGpu *gpu; + MetaBackend *backend; GList *outputs; GList *modes; @@ -288,12 +288,12 @@ meta_monitor_make_display_name (MetaMonitor *monitor, } } -MetaGpu * -meta_monitor_get_gpu (MetaMonitor *monitor) +MetaBackend * +meta_monitor_get_backend (MetaMonitor *monitor) { MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor); - return priv->gpu; + return priv->backend; } GList * @@ -486,6 +486,7 @@ meta_monitor_dispose (GObject *object) if (priv->outputs) { + g_list_foreach (priv->outputs, (GFunc) meta_output_unset_monitor, NULL); g_list_free_full (priv->outputs, g_object_unref); priv->outputs = NULL; } @@ -660,8 +661,7 @@ meta_monitor_normal_generate_modes (MetaMonitorNormal *monitor_normal) } MetaMonitorNormal * -meta_monitor_normal_new (MetaGpu *gpu, - MetaMonitorManager *monitor_manager, +meta_monitor_normal_new (MetaMonitorManager *monitor_manager, MetaOutput *output) { MetaMonitorNormal *monitor_normal; @@ -672,7 +672,7 @@ meta_monitor_normal_new (MetaGpu *gpu, monitor = META_MONITOR (monitor_normal); monitor_priv = meta_monitor_get_instance_private (monitor); - monitor_priv->gpu = gpu; + monitor_priv->backend = meta_monitor_manager_get_backend (monitor_manager); monitor_priv->outputs = g_list_append (NULL, g_object_ref (output)); meta_output_set_monitor (output, monitor); @@ -1348,8 +1348,7 @@ meta_monitor_tiled_generate_modes (MetaMonitorTiled *monitor_tiled) } MetaMonitorTiled * -meta_monitor_tiled_new (MetaGpu *gpu, - MetaMonitorManager *monitor_manager, +meta_monitor_tiled_new (MetaMonitorManager *monitor_manager, MetaOutput *output) { const MetaOutputInfo *output_info = meta_output_get_info (output); @@ -1361,13 +1360,13 @@ meta_monitor_tiled_new (MetaGpu *gpu, monitor = META_MONITOR (monitor_tiled); monitor_priv = meta_monitor_get_instance_private (monitor); - monitor_priv->gpu = gpu; + monitor_priv->backend = meta_monitor_manager_get_backend (monitor_manager); monitor_tiled->tile_group_id = output_info->tile_info.group_id; monitor_priv->winsys_id = meta_output_get_id (output); monitor_tiled->origin_output = output; - add_tiled_monitor_outputs (gpu, monitor_tiled); + add_tiled_monitor_outputs (meta_output_get_gpu (output), monitor_tiled); monitor_tiled->main_output = find_untiled_output (monitor_tiled); diff --git a/src/backends/meta-monitor.h b/src/backends/meta-monitor.h index c158b7c94097f48a45f61d6a1f4946ee63492e25..341657ae3ce56ce52ff95571c9a23ce6c8dd69b8 100644 --- a/src/backends/meta-monitor.h +++ b/src/backends/meta-monitor.h @@ -65,6 +65,7 @@ typedef enum _MetaMonitorScalesConstraint } MetaMonitorScalesConstraint; #define META_TYPE_MONITOR (meta_monitor_get_type ()) +META_EXPORT_TEST G_DECLARE_DERIVABLE_TYPE (MetaMonitor, meta_monitor, META, MONITOR, GObject) struct _MetaMonitorClass @@ -95,17 +96,15 @@ G_DECLARE_FINAL_TYPE (MetaMonitorTiled, meta_monitor_tiled, META, MONITOR_TILED, MetaMonitor) -MetaMonitorTiled * meta_monitor_tiled_new (MetaGpu *gpu, - MetaMonitorManager *monitor_manager, +MetaMonitorTiled * meta_monitor_tiled_new (MetaMonitorManager *monitor_manager, MetaOutput *output); -MetaMonitorNormal * meta_monitor_normal_new (MetaGpu *gpu, - MetaMonitorManager *monitor_manager, +MetaMonitorNormal * meta_monitor_normal_new (MetaMonitorManager *monitor_manager, MetaOutput *output); MetaMonitorSpec * meta_monitor_get_spec (MetaMonitor *monitor); -MetaGpu * meta_monitor_get_gpu (MetaMonitor *monitor); +MetaBackend * meta_monitor_get_backend (MetaMonitor *monitor); META_EXPORT_TEST gboolean meta_monitor_is_active (MetaMonitor *monitor); diff --git a/src/backends/meta-output.c b/src/backends/meta-output.c index c903110a6500123c4b5fe23042540f055e090f25..432697d6d9537c188526c857371335b98b7f8ff6 100644 --- a/src/backends/meta-output.c +++ b/src/backends/meta-output.c @@ -135,6 +135,16 @@ meta_output_set_monitor (MetaOutput *output, priv->monitor = monitor; } +void +meta_output_unset_monitor (MetaOutput *output) +{ + MetaOutputPrivate *priv = meta_output_get_instance_private (output); + + g_warn_if_fail (priv->monitor); + + priv->monitor = NULL; +} + const char * meta_output_get_name (MetaOutput *output) { diff --git a/src/backends/meta-output.h b/src/backends/meta-output.h index bed1996626ab875810f98c6da83d37953aa66a1b..b96c118d816434ab9d8d807144614f13b9fc96b3 100644 --- a/src/backends/meta-output.h +++ b/src/backends/meta-output.h @@ -39,7 +39,8 @@ struct _MetaTileInfo uint32_t tile_h; }; -/* This matches the values in drm_mode.h */ +/* The first 17 matches the values in drm_mode.h, the ones starting with + * 1000 do not. */ typedef enum { META_CONNECTOR_TYPE_Unknown = 0, @@ -59,6 +60,8 @@ typedef enum META_CONNECTOR_TYPE_eDP = 14, META_CONNECTOR_TYPE_VIRTUAL = 15, META_CONNECTOR_TYPE_DSI = 16, + + META_CONNECTOR_TYPE_META = 1000, } MetaConnectorType; typedef struct _MetaOutputInfo @@ -145,6 +148,8 @@ MetaMonitor * meta_output_get_monitor (MetaOutput *output); void meta_output_set_monitor (MetaOutput *output, MetaMonitor *monitor); +void meta_output_unset_monitor (MetaOutput *output); + const char * meta_output_get_name (MetaOutput *output); META_EXPORT_TEST diff --git a/src/backends/meta-remote-desktop-session.c b/src/backends/meta-remote-desktop-session.c index 4429c3567050d3bbad054d3097254e78b26b45b7..1f83ff709e703fa569c957319f21c14de3870e6d 100644 --- a/src/backends/meta-remote-desktop-session.c +++ b/src/backends/meta-remote-desktop-session.c @@ -678,11 +678,17 @@ handle_notify_pointer_motion_absolute (MetaDBusRemoteDesktopSession *skeleton, return TRUE; } - meta_screen_cast_stream_transform_position (stream, x, y, &abs_x, &abs_y); - - clutter_virtual_input_device_notify_absolute_motion (session->virtual_pointer, - CLUTTER_CURRENT_TIME, - abs_x, abs_y); + if (meta_screen_cast_stream_transform_position (stream, x, y, &abs_x, &abs_y)) + { + clutter_virtual_input_device_notify_absolute_motion (session->virtual_pointer, + CLUTTER_CURRENT_TIME, + abs_x, abs_y); + } + else + { + meta_topic (META_DEBUG_REMOTE_DESKTOP, + "Dropping early absolute pointer motion (%f, %f)", x, y); + } meta_dbus_remote_desktop_session_complete_notify_pointer_motion_absolute (skeleton, invocation); @@ -731,12 +737,18 @@ handle_notify_touch_down (MetaDBusRemoteDesktopSession *skeleton, return TRUE; } - meta_screen_cast_stream_transform_position (stream, x, y, &abs_x, &abs_y); - - clutter_virtual_input_device_notify_touch_down (session->virtual_touchscreen, - CLUTTER_CURRENT_TIME, - slot, - abs_x, abs_y); + if (meta_screen_cast_stream_transform_position (stream, x, y, &abs_x, &abs_y)) + { + clutter_virtual_input_device_notify_touch_down (session->virtual_touchscreen, + CLUTTER_CURRENT_TIME, + slot, + abs_x, abs_y); + } + else + { + meta_topic (META_DEBUG_REMOTE_DESKTOP, + "Dropping early touch down (%f, %f)", x, y); + } meta_dbus_remote_desktop_session_complete_notify_touch_down (skeleton, invocation); @@ -786,12 +798,18 @@ handle_notify_touch_motion (MetaDBusRemoteDesktopSession *skeleton, return TRUE; } - meta_screen_cast_stream_transform_position (stream, x, y, &abs_x, &abs_y); - - clutter_virtual_input_device_notify_touch_motion (session->virtual_touchscreen, - CLUTTER_CURRENT_TIME, - slot, - abs_x, abs_y); + if (meta_screen_cast_stream_transform_position (stream, x, y, &abs_x, &abs_y)) + { + clutter_virtual_input_device_notify_touch_motion (session->virtual_touchscreen, + CLUTTER_CURRENT_TIME, + slot, + abs_x, abs_y); + } + else + { + meta_topic (META_DEBUG_REMOTE_DESKTOP, + "Dropping early touch motion (%f, %f)", x, y); + } meta_dbus_remote_desktop_session_complete_notify_touch_motion (skeleton, invocation); diff --git a/src/backends/meta-screen-cast-area-stream-src.c b/src/backends/meta-screen-cast-area-stream-src.c index b7de04d7b6af0e28d798f4e7b553b40d3b273bb7..91251cc63b1c535766588d29d4ccccd56f2a34e2 100644 --- a/src/backends/meta-screen-cast-area-stream-src.c +++ b/src/backends/meta-screen-cast-area-stream-src.c @@ -83,7 +83,7 @@ get_backend (MetaScreenCastAreaStreamSrc *area_src) return meta_screen_cast_get_backend (screen_cast); } -static void +static gboolean meta_screen_cast_area_stream_src_get_specs (MetaScreenCastStreamSrc *src, int *width, int *height, @@ -100,6 +100,8 @@ meta_screen_cast_area_stream_src_get_specs (MetaScreenCastStreamSrc *src, *width = (int) roundf (area->width * scale); *height = (int) roundf (area->height * scale); *frame_rate = 60.0; + + return TRUE; } static gboolean diff --git a/src/backends/meta-screen-cast-area-stream.c b/src/backends/meta-screen-cast-area-stream.c index 9dd59fbfe6b0f97ba0897d20f0b4213ae135da5c..23d8c982800bf36ec35c1b7d9a20900eff382da1 100644 --- a/src/backends/meta-screen-cast-area-stream.c +++ b/src/backends/meta-screen-cast-area-stream.c @@ -148,7 +148,7 @@ meta_screen_cast_area_stream_set_parameters (MetaScreenCastStream *stream, area_stream->area.height)); } -static void +static gboolean meta_screen_cast_area_stream_transform_position (MetaScreenCastStream *stream, double stream_x, double stream_y, @@ -160,6 +160,8 @@ meta_screen_cast_area_stream_transform_position (MetaScreenCastStream *stream, *x = area_stream->area.x + (int) roundf (stream_x / area_stream->scale); *y = area_stream->area.y + (int) roundf (stream_y / area_stream->scale); + + return TRUE; } static void diff --git a/src/backends/meta-screen-cast-monitor-stream-src.c b/src/backends/meta-screen-cast-monitor-stream-src.c index 6753f176a770a9a5d93b35d50aa78bd59327f6e7..008cd6de7029ef7ad3b59e619222cae56ec09781 100644 --- a/src/backends/meta-screen-cast-monitor-stream-src.c +++ b/src/backends/meta-screen-cast-monitor-stream-src.c @@ -87,7 +87,7 @@ get_monitor (MetaScreenCastMonitorStreamSrc *monitor_src) return meta_screen_cast_monitor_stream_get_monitor (monitor_stream); } -static void +static gboolean meta_screen_cast_monitor_stream_src_get_specs (MetaScreenCastStreamSrc *src, int *width, int *height, @@ -112,6 +112,8 @@ meta_screen_cast_monitor_stream_src_get_specs (MetaScreenCastStreamSrc *src, *width = (int) roundf (logical_monitor->rect.width * scale); *height = (int) roundf (logical_monitor->rect.height * scale); *frame_rate = meta_monitor_mode_get_refresh_rate (mode); + + return TRUE; } static void diff --git a/src/backends/meta-screen-cast-monitor-stream.c b/src/backends/meta-screen-cast-monitor-stream.c index 9c138611caea45f16dff2562ea8bb6e8baef13d4..c7123a19b04d1cb50a5d5e13efbdb61c22408de6 100644 --- a/src/backends/meta-screen-cast-monitor-stream.c +++ b/src/backends/meta-screen-cast-monitor-stream.c @@ -113,8 +113,7 @@ meta_screen_cast_monitor_stream_new (MetaScreenCastSession *session, MetaScreenCastFlag flags, GError **error) { - MetaGpu *gpu = meta_monitor_get_gpu (monitor); - MetaBackend *backend = meta_gpu_get_backend (gpu); + MetaBackend *backend = meta_monitor_get_backend (monitor); MetaMonitorManager *monitor_manager = meta_backend_get_monitor_manager (backend); MetaScreenCastMonitorStream *monitor_stream; @@ -185,7 +184,7 @@ meta_screen_cast_monitor_stream_set_parameters (MetaScreenCastStream *stream, logical_monitor_layout.height)); } -static void +static gboolean meta_screen_cast_monitor_stream_transform_position (MetaScreenCastStream *stream, double stream_x, double stream_y, @@ -201,6 +200,8 @@ meta_screen_cast_monitor_stream_transform_position (MetaScreenCastStream *stream *x = logical_monitor_layout.x + stream_x; *y = logical_monitor_layout.y + stream_y; + + return TRUE; } static void diff --git a/src/backends/meta-screen-cast-session.c b/src/backends/meta-screen-cast-session.c index 10c37ee886cba62b4dc3404508a1197c0fce8032..3925738d47c6121cc3a638ea3b210c1270d10658 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-stream-src.c b/src/backends/meta-screen-cast-stream-src.c index 484a879b9899f4452a4cdccbb9b54a888c0ada4e..c3ede8aea8e5c693fb75593a49996a02ddffa9eb 100644 --- a/src/backends/meta-screen-cast-stream-src.c +++ b/src/backends/meta-screen-cast-stream-src.c @@ -47,6 +47,14 @@ (sizeof (struct spa_meta_cursor) + \ sizeof (struct spa_meta_bitmap) + width * height * 4) +#define DEFAULT_SIZE SPA_RECTANGLE (1280, 720) +#define MIN_SIZE SPA_RECTANGLE (1, 1) +#define MAX_SIZE SPA_RECTANGLE (16384, 16386) + +#define DEFAULT_FRAME_RATE SPA_FRACTION (60, 1) +#define MIN_FRAME_RATE SPA_FRACTION (1, 1) +#define MAX_FRAME_RATE SPA_FRACTION (1000, 1) + enum { PROP_0, @@ -107,7 +115,7 @@ G_DEFINE_TYPE_WITH_CODE (MetaScreenCastStreamSrc, meta_screen_cast_stream_src_init_initable_iface) G_ADD_PRIVATE (MetaScreenCastStreamSrc)) -static void +static gboolean meta_screen_cast_stream_src_get_specs (MetaScreenCastStreamSrc *src, int *width, int *height, @@ -116,7 +124,7 @@ meta_screen_cast_stream_src_get_specs (MetaScreenCastStreamSrc *src, MetaScreenCastStreamSrcClass *klass = META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src); - klass->get_specs (src, width, height, frame_rate); + return klass->get_specs (src, width, height, frame_rate); } static gboolean @@ -640,6 +648,17 @@ meta_screen_cast_stream_src_disable (MetaScreenCastStreamSrc *src) priv->is_enabled = FALSE; } +void +meta_screen_cast_stream_src_close (MetaScreenCastStreamSrc *src) +{ + MetaScreenCastStreamSrcPrivate *priv = + meta_screen_cast_stream_src_get_instance_private (src); + + if (meta_screen_cast_stream_src_is_enabled (src)) + meta_screen_cast_stream_src_disable (src); + priv->emit_closed_after_dispatch = TRUE; +} + static void on_stream_state_changed (void *data, enum pw_stream_state old, @@ -654,9 +673,7 @@ on_stream_state_changed (void *data, { case PW_STREAM_STATE_ERROR: g_warning ("pipewire stream error: %s", error_message); - if (meta_screen_cast_stream_src_is_enabled (src)) - meta_screen_cast_stream_src_disable (src); - priv->emit_closed_after_dispatch = TRUE; + meta_screen_cast_stream_src_close (src); break; case PW_STREAM_STATE_PAUSED: if (priv->node_id == SPA_ID_INVALID && priv->pipewire_stream) @@ -685,6 +702,8 @@ on_stream_param_changed (void *data, MetaScreenCastStreamSrc *src = data; MetaScreenCastStreamSrcPrivate *priv = meta_screen_cast_stream_src_get_instance_private (src); + MetaScreenCastStreamSrcClass *klass = + META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src); uint8_t params_buffer[1024]; int32_t width, height, stride, size; struct spa_pod_builder pod_builder; @@ -728,6 +747,9 @@ on_stream_param_changed (void *data, SPA_PARAM_META_size, SPA_POD_Int (CURSOR_META_SIZE (384, 384))); pw_stream_update_params (priv->pipewire_stream, params, G_N_ELEMENTS (params)); + + if (klass->notify_params_updated) + klass->notify_params_updated (src, &priv->video_format); } static void @@ -875,9 +897,6 @@ create_pipewire_stream (MetaScreenCastStreamSrc *src, int width; int height; float frame_rate; - MetaFraction frame_rate_fraction; - struct spa_fraction max_framerate; - struct spa_fraction min_framerate; const struct spa_pod *params[1]; int result; @@ -894,24 +913,49 @@ create_pipewire_stream (MetaScreenCastStreamSrc *src, return NULL; } - meta_screen_cast_stream_src_get_specs (src, &width, &height, &frame_rate); - frame_rate_fraction = meta_fraction_from_double (frame_rate); - - min_framerate = SPA_FRACTION (1, 1); - max_framerate = SPA_FRACTION (frame_rate_fraction.num, - frame_rate_fraction.denom); - - params[0] = spa_pod_builder_add_object ( - &pod_builder, - SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, - SPA_FORMAT_mediaType, SPA_POD_Id (SPA_MEDIA_TYPE_video), - SPA_FORMAT_mediaSubtype, SPA_POD_Id (SPA_MEDIA_SUBTYPE_raw), - SPA_FORMAT_VIDEO_format, SPA_POD_Id (SPA_VIDEO_FORMAT_BGRx), - SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle (&SPA_RECTANGLE (width, height)), - SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction (&SPA_FRACTION (0, 1)), - SPA_FORMAT_VIDEO_maxFramerate, SPA_POD_CHOICE_RANGE_Fraction (&max_framerate, - &min_framerate, - &max_framerate)); + if (meta_screen_cast_stream_src_get_specs (src, &width, &height, &frame_rate)) + { + MetaFraction frame_rate_fraction; + struct spa_fraction max_framerate; + struct spa_fraction min_framerate; + + frame_rate_fraction = meta_fraction_from_double (frame_rate); + + min_framerate = SPA_FRACTION (1, 1); + max_framerate = SPA_FRACTION (frame_rate_fraction.num, + frame_rate_fraction.denom); + + params[0] = spa_pod_builder_add_object ( + &pod_builder, + SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, + SPA_FORMAT_mediaType, SPA_POD_Id (SPA_MEDIA_TYPE_video), + SPA_FORMAT_mediaSubtype, SPA_POD_Id (SPA_MEDIA_SUBTYPE_raw), + SPA_FORMAT_VIDEO_format, SPA_POD_Id (SPA_VIDEO_FORMAT_BGRx), + SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle (&SPA_RECTANGLE (width, + height)), + SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction (&SPA_FRACTION (0, 1)), + SPA_FORMAT_VIDEO_maxFramerate, + SPA_POD_CHOICE_RANGE_Fraction (&max_framerate, + &min_framerate, + &max_framerate)); + } + else + { + params[0] = spa_pod_builder_add_object ( + &pod_builder, + SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, + SPA_FORMAT_mediaType, SPA_POD_Id (SPA_MEDIA_TYPE_video), + SPA_FORMAT_mediaSubtype, SPA_POD_Id (SPA_MEDIA_SUBTYPE_raw), + SPA_FORMAT_VIDEO_format, SPA_POD_Id (SPA_VIDEO_FORMAT_BGRx), + SPA_FORMAT_VIDEO_size, SPA_POD_CHOICE_RANGE_Rectangle (&DEFAULT_SIZE, + &MIN_SIZE, + &MAX_SIZE), + SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction (&SPA_FRACTION (0, 1)), + SPA_FORMAT_VIDEO_maxFramerate, + SPA_POD_CHOICE_RANGE_Fraction (&DEFAULT_FRAME_RATE, + &MIN_FRAME_RATE, + &MAX_FRAME_RATE)); + } pw_stream_add_listener (pipewire_stream, &priv->pipewire_stream_listener, @@ -942,17 +986,11 @@ on_core_error (void *data, const char *message) { MetaScreenCastStreamSrc *src = data; - MetaScreenCastStreamSrcPrivate *priv = - meta_screen_cast_stream_src_get_instance_private (src); g_warning ("pipewire remote error: id:%u %s", id, message); if (id == PW_ID_CORE && res == -EPIPE) - { - if (meta_screen_cast_stream_src_is_enabled (src)) - meta_screen_cast_stream_src_disable (src); - priv->emit_closed_after_dispatch = TRUE; - } + meta_screen_cast_stream_src_close (src); } static gboolean diff --git a/src/backends/meta-screen-cast-stream-src.h b/src/backends/meta-screen-cast-stream-src.h index 3eaebf62c5da006a7c5739264bb48d0cf04dbdca..456b5bd97805abc0fdb5ef934dc82ed3198dbf59 100644 --- a/src/backends/meta-screen-cast-stream-src.h +++ b/src/backends/meta-screen-cast-stream-src.h @@ -53,10 +53,10 @@ struct _MetaScreenCastStreamSrcClass { GObjectClass parent_class; - void (* get_specs) (MetaScreenCastStreamSrc *src, - int *width, - int *height, - float *frame_rate); + gboolean (* get_specs) (MetaScreenCastStreamSrc *src, + int *width, + int *height, + float *frame_rate); void (* enable) (MetaScreenCastStreamSrc *src); void (* disable) (MetaScreenCastStreamSrc *src); gboolean (* record_to_buffer) (MetaScreenCastStreamSrc *src, @@ -74,8 +74,13 @@ struct _MetaScreenCastStreamSrcClass MetaRectangle *crop_rect); void (* set_cursor_metadata) (MetaScreenCastStreamSrc *src, struct spa_meta_cursor *spa_meta_cursor); + + void (* notify_params_updated) (MetaScreenCastStreamSrc *src, + struct spa_video_info_raw *video_format); }; +void meta_screen_cast_stream_src_close (MetaScreenCastStreamSrc *src); + void meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src, MetaScreenCastRecordFlag flags); diff --git a/src/backends/meta-screen-cast-stream.c b/src/backends/meta-screen-cast-stream.c index fed1560fe4cd69332b26b16f56a7bfdac3de894e..b8ab5abd576721bdf4de5714b948ae9b7eb3e96e 100644 --- a/src/backends/meta-screen-cast-stream.c +++ b/src/backends/meta-screen-cast-stream.c @@ -177,18 +177,16 @@ meta_screen_cast_stream_get_src (MetaScreenCastStream *stream) return priv->src; } -void +gboolean meta_screen_cast_stream_transform_position (MetaScreenCastStream *stream, double stream_x, double stream_y, double *x, double *y) { - META_SCREEN_CAST_STREAM_GET_CLASS (stream)->transform_position (stream, - stream_x, - stream_y, - x, - y); + MetaScreenCastStreamClass *klass = META_SCREEN_CAST_STREAM_GET_CLASS (stream); + + return klass->transform_position (stream, stream_x, stream_y, x, y); } MetaScreenCastCursorMode diff --git a/src/backends/meta-screen-cast-stream.h b/src/backends/meta-screen-cast-stream.h index d121c15c1e43a016cc0115a4726021740b8bdbc8..3424def20c9deed96db687421671f447af9cc34f 100644 --- a/src/backends/meta-screen-cast-stream.h +++ b/src/backends/meta-screen-cast-stream.h @@ -43,11 +43,11 @@ struct _MetaScreenCastStreamClass GError **error); void (* set_parameters) (MetaScreenCastStream *stream, GVariantBuilder *parameters_builder); - void (* transform_position) (MetaScreenCastStream *stream, - double stream_x, - double stream_y, - double *x, - double *y); + gboolean (* transform_position) (MetaScreenCastStream *stream, + double stream_x, + double stream_y, + double *x, + double *y); }; MetaScreenCastSession * meta_screen_cast_stream_get_session (MetaScreenCastStream *stream); @@ -61,11 +61,11 @@ char * meta_screen_cast_stream_get_object_path (MetaScreenCastStream *stream); MetaScreenCastStreamSrc * meta_screen_cast_stream_get_src (MetaScreenCastStream *stream); -void meta_screen_cast_stream_transform_position (MetaScreenCastStream *stream, - double stream_x, - double stream_y, - double *x, - double *y); +gboolean meta_screen_cast_stream_transform_position (MetaScreenCastStream *stream, + double stream_x, + double stream_y, + double *x, + double *y); MetaScreenCastCursorMode meta_screen_cast_stream_get_cursor_mode (MetaScreenCastStream *stream); 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 0000000000000000000000000000000000000000..47a917da980b01c9866e7a4d16e68861c54af794 --- /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 0000000000000000000000000000000000000000..a891166bd75ade689a5d332f456debe9eb525ad0 --- /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 0000000000000000000000000000000000000000..34dd2a00cccee43a07b7d79ac8671dbaf436e930 --- /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 0000000000000000000000000000000000000000..422db5e26bc124a925f352e1c818f4bf7cda4edd --- /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-window-stream-src.c b/src/backends/meta-screen-cast-window-stream-src.c index 014a97c3247e2b49c75b9938969e44c0d7789e88..3fa932b4b17fa9a344aad959adc1dbd49879db5b 100644 --- a/src/backends/meta-screen-cast-window-stream-src.c +++ b/src/backends/meta-screen-cast-window-stream-src.c @@ -275,7 +275,7 @@ capture_into (MetaScreenCastWindowStreamSrc *window_src, return TRUE; } -static void +static gboolean meta_screen_cast_window_stream_src_get_specs (MetaScreenCastStreamSrc *src, int *width, int *height, @@ -287,6 +287,8 @@ meta_screen_cast_window_stream_src_get_specs (MetaScreenCastStreamSrc *src, *width = get_stream_width (window_src); *height = get_stream_height (window_src); *frame_rate = 60.0f; + + return TRUE; } static gboolean diff --git a/src/backends/meta-screen-cast-window-stream.c b/src/backends/meta-screen-cast-window-stream.c index 4c235d150edd21077eef89380e610679cdff72d8..6f42a446e8df1fd397424bf56a23453d23ebcc9b 100644 --- a/src/backends/meta-screen-cast-window-stream.c +++ b/src/backends/meta-screen-cast-window-stream.c @@ -128,7 +128,7 @@ meta_screen_cast_window_stream_set_parameters (MetaScreenCastStream *stream, window_stream->logical_height)); } -static void +static gboolean meta_screen_cast_window_stream_transform_position (MetaScreenCastStream *stream, double stream_x, double stream_y, @@ -145,6 +145,7 @@ meta_screen_cast_window_stream_transform_position (MetaScreenCastStream *stream, stream_y, x, y); + return TRUE; } static void diff --git a/src/backends/meta-screen-cast.h b/src/backends/meta-screen-cast.h index e2ea5a5e4601cd5bbac81264514cdfa870c06d0a..be297e28da5304eace472a079f8fe06446bdb7ac 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/backends/meta-stage-private.h b/src/backends/meta-stage-private.h index 03214218fdc8e51fc97bbf1ffcf0021fa31e3ff4..07534f6e39a3a4e96454e6a271aa37d0b5631922 100644 --- a/src/backends/meta-stage-private.h +++ b/src/backends/meta-stage-private.h @@ -21,6 +21,7 @@ #define META_STAGE_PRIVATE_H #include "backends/meta-cursor.h" +#include "core/util-private.h" #include "meta/boxes.h" #include "meta/meta-stage.h" #include "meta/types.h" @@ -62,12 +63,14 @@ gboolean meta_overlay_is_visible (MetaOverlay *overlay); void meta_stage_set_active (MetaStage *stage, gboolean is_active); +META_EXPORT_TEST MetaStageWatch * meta_stage_watch_view (MetaStage *stage, ClutterStageView *view, MetaStageWatchPhase watch_mode, MetaStageWatchFunc callback, gpointer user_data); +META_EXPORT_TEST void meta_stage_remove_watch (MetaStage *stage, MetaStageWatch *watch); diff --git a/src/backends/meta-virtual-monitor.c b/src/backends/meta-virtual-monitor.c new file mode 100644 index 0000000000000000000000000000000000000000..2bd95ffd7dbf44d69b330d72c5212f5950d60912 --- /dev/null +++ b/src/backends/meta-virtual-monitor.c @@ -0,0 +1,238 @@ +/* + * 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-virtual-monitor.h" + +#include "backends/meta-crtc.h" +#include "backends/meta-crtc-mode.h" +#include "backends/meta-output.h" + +enum +{ + DESTROY, + + N_SIGNALS +}; + +static guint signals[N_SIGNALS] = { 0 }; + +enum +{ + PROP_0, + + PROP_CRTC, + PROP_CRTC_MODE, + PROP_OUTPUT, + + N_PROPS +}; + +static GParamSpec *obj_props[N_PROPS]; + +typedef struct _MetaVirtualMonitorPrivate +{ + MetaCrtc *crtc; + MetaCrtcMode *crtc_mode; + MetaOutput *output; + + gboolean is_destroyed; +} MetaVirtualMonitorPrivate; + +G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaVirtualMonitor, meta_virtual_monitor, + G_TYPE_OBJECT) + +MetaVirtualMonitorInfo * +meta_virtual_monitor_info_new (int width, + int height, + float refresh_rate, + const char *vendor, + const char *product, + const char *serial) +{ + MetaVirtualMonitorInfo *info; + + info = g_new0 (MetaVirtualMonitorInfo, 1); + info->width = width; + info->height = height; + info->refresh_rate = refresh_rate; + info->vendor = g_strdup (vendor); + info->product = g_strdup (product); + info->serial = g_strdup (serial); + + return info; +} + +void +meta_virtual_monitor_info_free (MetaVirtualMonitorInfo *info) +{ + g_free (info->vendor); + g_free (info->product); + g_free (info->serial); + g_free (info); +} + +MetaCrtc * +meta_virtual_monitor_get_crtc (MetaVirtualMonitor *virtual_monitor) +{ + MetaVirtualMonitorPrivate *priv = + meta_virtual_monitor_get_instance_private (virtual_monitor); + + return priv->crtc; +} + +MetaCrtcMode * +meta_virtual_monitor_get_crtc_mode (MetaVirtualMonitor *virtual_monitor) +{ + MetaVirtualMonitorPrivate *priv = + meta_virtual_monitor_get_instance_private (virtual_monitor); + + return priv->crtc_mode; +} + +MetaOutput * +meta_virtual_monitor_get_output (MetaVirtualMonitor *virtual_monitor) +{ + MetaVirtualMonitorPrivate *priv = + meta_virtual_monitor_get_instance_private (virtual_monitor); + + return priv->output; +} + +static void +meta_virtual_monitor_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MetaVirtualMonitor *virtual_monitor = META_VIRTUAL_MONITOR (object); + MetaVirtualMonitorPrivate *priv = + meta_virtual_monitor_get_instance_private (virtual_monitor); + + switch (prop_id) + { + case PROP_CRTC: + priv->crtc = g_value_get_object (value); + break; + case PROP_CRTC_MODE: + priv->crtc_mode = g_value_get_object (value); + break; + case PROP_OUTPUT: + priv->output = g_value_get_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +meta_virtual_monitor_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MetaVirtualMonitor *virtual_monitor = META_VIRTUAL_MONITOR (object); + MetaVirtualMonitorPrivate *priv = + meta_virtual_monitor_get_instance_private (virtual_monitor); + + switch (prop_id) + { + case PROP_CRTC: + g_value_set_object (value, priv->crtc); + break; + case PROP_CRTC_MODE: + g_value_set_object (value, priv->crtc_mode); + break; + case PROP_OUTPUT: + g_value_set_object (value, priv->output); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +meta_virtual_monitor_dispose (GObject *object) +{ + MetaVirtualMonitor *virtual_monitor = META_VIRTUAL_MONITOR (object); + MetaVirtualMonitorPrivate *priv = + meta_virtual_monitor_get_instance_private (virtual_monitor); + + if (!priv->is_destroyed) + { + g_signal_emit (virtual_monitor, signals[DESTROY], 0); + priv->is_destroyed = TRUE; + } + + g_clear_object (&priv->crtc); + g_clear_object (&priv->crtc_mode); + g_clear_object (&priv->output); + + G_OBJECT_CLASS (meta_virtual_monitor_parent_class)->dispose (object); +} + +static void +meta_virtual_monitor_init (MetaVirtualMonitor *virtual_monitor) +{ +} + +static void +meta_virtual_monitor_class_init (MetaVirtualMonitorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = meta_virtual_monitor_set_property; + object_class->get_property = meta_virtual_monitor_get_property; + object_class->dispose = meta_virtual_monitor_dispose; + + obj_props[PROP_CRTC] = + g_param_spec_object ("crtc", + "crtc", + "The virtual CRTC", + META_TYPE_CRTC, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + obj_props[PROP_CRTC_MODE] = + g_param_spec_object ("crtc-mode", + "crtc-mode", + "The virtual CRTC mode", + META_TYPE_CRTC_MODE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + obj_props[PROP_OUTPUT] = + g_param_spec_object ("output", + "output", + "The virtual output", + META_TYPE_OUTPUT, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, N_PROPS, obj_props); + + signals[DESTROY] = + g_signal_new ("destroy", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); +} diff --git a/src/backends/meta-virtual-monitor.h b/src/backends/meta-virtual-monitor.h new file mode 100644 index 0000000000000000000000000000000000000000..2b733df9ccbfd49631ed6abb62ac33f137cba0f8 --- /dev/null +++ b/src/backends/meta-virtual-monitor.h @@ -0,0 +1,71 @@ +/* + * 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_VIRTUAL_MONITOR_H +#define META_VIRTUAL_MONITOR_H + +#include + +#include "backends/meta-backend-types.h" +#include "core/util-private.h" + +typedef struct _MetaVirtualMonitorInfo +{ + int width; + int height; + float refresh_rate; + + char *vendor; + char *product; + char *serial; +} MetaVirtualMonitorInfo; + +#define META_TYPE_VIRTUAL_MONITOR (meta_virtual_monitor_get_type ()) +G_DECLARE_DERIVABLE_TYPE (MetaVirtualMonitor, meta_virtual_monitor, + META, VIRTUAL_MONITOR, + GObject) + +struct _MetaVirtualMonitorClass +{ + GObjectClass parent_class; +}; + +META_EXPORT_TEST +MetaVirtualMonitorInfo * meta_virtual_monitor_info_new (int width, + int height, + float refresh_rate, + const char *vendor, + const char *product, + const char *serial); + +META_EXPORT_TEST +void meta_virtual_monitor_info_free (MetaVirtualMonitorInfo *info); + +MetaCrtc * meta_virtual_monitor_get_crtc (MetaVirtualMonitor *virtual_monitor); + +MetaCrtcMode * meta_virtual_monitor_get_crtc_mode (MetaVirtualMonitor *virtual_monitor); + +META_EXPORT_TEST +MetaOutput * meta_virtual_monitor_get_output (MetaVirtualMonitor *virtual_monitor); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaVirtualMonitorInfo, + meta_virtual_monitor_info_free) + +#endif /* META_VIRTUAL_MONITOR_H */ diff --git a/src/backends/native/meta-backend-native-types.h b/src/backends/native/meta-backend-native-types.h index 0668a84e4f1d642daa293835c36076f608fe0043..f16f6b1d0f8ee345c89a1694cdc4e3321bb55d78 100644 --- a/src/backends/native/meta-backend-native-types.h +++ b/src/backends/native/meta-backend-native-types.h @@ -27,5 +27,13 @@ typedef struct _MetaSeatImpl MetaSeatImpl; typedef struct _MetaKeymapNative MetaKeymapNative; typedef struct _MetaRendererNative MetaRendererNative; typedef struct _MetaGpuKms MetaGpuKms; +typedef struct _MetaCrtcVirtual MetaCrtcVirtual; +typedef struct _MetaCrtcModeVirtual MetaCrtcModeVirtual; + +typedef enum _MetaSeatNativeFlag +{ + META_SEAT_NATIVE_FLAG_NONE = 0, + META_SEAT_NATIVE_FLAG_NO_LIBINPUT = 1 << 0, +} MetaSeatNativeFlag; #endif /* META_BACKEND_NATIVE_TYPES_H */ diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c index bf270c3ffaf39689263987be4f98154bbf2df21b..f0c2fadaa61741fa40599470c9fec7e9a5447ae0 100644 --- a/src/backends/native/meta-backend-native.c +++ b/src/backends/native/meta-backend-native.c @@ -53,7 +53,7 @@ #include "backends/native/meta-kms.h" #include "backends/native/meta-kms-device.h" #include "backends/native/meta-launcher.h" -#include "backends/native/meta-monitor-manager-kms.h" +#include "backends/native/meta-monitor-manager-native.h" #include "backends/native/meta-renderer-native.h" #include "backends/native/meta-seat-native.h" #include "backends/native/meta-stage-native.h" @@ -65,6 +65,17 @@ #include "backends/meta-screen-cast.h" #endif +enum +{ + PROP_0, + + PROP_HEADLESS, + + N_PROPS +}; + +static GParamSpec *obj_props[N_PROPS]; + struct _MetaBackendNative { MetaBackend parent; @@ -73,6 +84,8 @@ struct _MetaBackendNative MetaUdev *udev; MetaKms *kms; + gboolean is_headless; + gulong udev_device_added_handler_id; }; @@ -131,6 +144,12 @@ maybe_disable_screen_cast_dma_bufs (MetaBackendNative *native) }; primary_gpu = meta_renderer_native_get_primary_gpu (renderer_native); + if (!primary_gpu) + { + g_message ("Disabling DMA buffer screen sharing (surfaceless)"); + goto disable_dma_bufs; + } + kms_device = meta_gpu_kms_get_kms_device (primary_gpu); driver_name = meta_kms_device_get_driver_name (kms_device); @@ -144,6 +163,7 @@ maybe_disable_screen_cast_dma_bufs (MetaBackendNative *native) g_message ("Disabling DMA buffer screen sharing for driver '%s'.", driver_name); +disable_dma_bufs: meta_screen_cast_disable_dma_bufs (screen_cast); } #endif /* HAVE_REMOTE_DESKTOP */ @@ -199,10 +219,12 @@ static MetaMonitorManager * meta_backend_native_create_monitor_manager (MetaBackend *backend, GError **error) { + MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); MetaMonitorManager *manager; - manager = g_initable_new (META_TYPE_MONITOR_MANAGER_KMS, NULL, error, + manager = g_initable_new (META_TYPE_MONITOR_MANAGER_NATIVE, NULL, error, "backend", backend, + "needs-outputs", !backend_native->is_headless, NULL); if (!manager) return NULL; @@ -317,7 +339,16 @@ meta_backend_native_lock_layout_group (MetaBackend *backend, const char * meta_backend_native_get_seat_id (MetaBackendNative *backend_native) { - return meta_launcher_get_seat_id (backend_native->launcher); + if (backend_native->is_headless) + return "seat0"; + else + return meta_launcher_get_seat_id (backend_native->launcher); +} + +gboolean +meta_backend_native_is_headless (MetaBackendNative *backend_native) +{ + return backend_native->is_headless; } static void @@ -449,7 +480,7 @@ init_gpus (MetaBackendNative *native, GList *l; devices = meta_udev_list_drm_devices (udev, error); - if (!devices) + if (*error) return FALSE; for (l = devices; l; l = l->next) @@ -474,7 +505,8 @@ init_gpus (MetaBackendNative *native, g_list_free_full (devices, g_object_unref); - if (g_list_length (meta_backend_get_gpus (backend)) == 0) + if (!native->is_headless && + g_list_length (meta_backend_get_gpus (backend)) == 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "No GPUs found"); @@ -492,6 +524,7 @@ meta_backend_native_initable_init (GInitable *initable, GError **error) { MetaBackendNative *native = META_BACKEND_NATIVE (initable); + MetaKmsFlags kms_flags; if (!meta_is_stage_views_enabled ()) { @@ -500,9 +533,12 @@ meta_backend_native_initable_init (GInitable *initable, return FALSE; } - native->launcher = meta_launcher_new (error); - if (!native->launcher) - return FALSE; + if (!native->is_headless) + { + native->launcher = meta_launcher_new (error); + if (!native->launcher) + return FALSE; + } #ifdef HAVE_WAYLAND meta_backend_init_wayland_display (META_BACKEND (native)); @@ -510,7 +546,11 @@ meta_backend_native_initable_init (GInitable *initable, native->udev = meta_udev_new (native); - native->kms = meta_kms_new (META_BACKEND (native), error); + kms_flags = META_KMS_FLAG_NONE; + if (native->is_headless) + kms_flags |= META_KMS_FLAG_NO_MODE_SETTING; + + native->kms = meta_kms_new (META_BACKEND (native), kms_flags, error); if (!native->kms) return FALSE; @@ -520,6 +560,25 @@ meta_backend_native_initable_init (GInitable *initable, return initable_parent_iface->init (initable, cancellable, error); } +static void +meta_backend_native_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MetaBackendNative *backend_native = META_BACKEND_NATIVE (object); + + switch (prop_id) + { + case PROP_HEADLESS: + backend_native->is_headless = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static void initable_iface_init (GInitableIface *initable_iface) { @@ -534,6 +593,7 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass) MetaBackendClass *backend_class = META_BACKEND_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->set_property = meta_backend_native_set_property; object_class->dispose = meta_backend_native_dispose; backend_class->create_clutter_backend = meta_backend_native_create_clutter_backend; @@ -554,6 +614,16 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass) backend_class->update_screen_size = meta_backend_native_update_screen_size; backend_class->set_pointer_constraint = meta_backend_native_set_pointer_constraint; + + obj_props[PROP_HEADLESS] = + g_param_spec_boolean ("headless", + "headless", + "Headless", + FALSE, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, N_PROPS, obj_props); } static void @@ -586,6 +656,13 @@ meta_activate_vt (int vt, GError **error) MetaBackendNative *native = META_BACKEND_NATIVE (backend); MetaLauncher *launcher = meta_backend_native_get_launcher (native); + if (native->is_headless) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Can't switch VT while headless"); + return FALSE; + } + return meta_launcher_activate_vt (launcher, vt, error); } @@ -595,8 +672,8 @@ meta_backend_native_pause (MetaBackendNative *native) MetaBackend *backend = META_BACKEND (native); MetaMonitorManager *monitor_manager = meta_backend_get_monitor_manager (backend); - MetaMonitorManagerKms *monitor_manager_kms = - META_MONITOR_MANAGER_KMS (monitor_manager); + MetaMonitorManagerNative *monitor_manager_native = + META_MONITOR_MANAGER_NATIVE (monitor_manager); ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); MetaSeatNative *seat = META_SEAT_NATIVE (clutter_backend_get_default_seat (clutter_backend)); @@ -610,7 +687,7 @@ meta_backend_native_pause (MetaBackendNative *native) disconnect_udev_device_added_handler (native); - meta_monitor_manager_kms_pause (monitor_manager_kms); + meta_monitor_manager_native_pause (monitor_manager_native); } void meta_backend_native_resume (MetaBackendNative *native) @@ -619,8 +696,8 @@ void meta_backend_native_resume (MetaBackendNative *native) ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); MetaMonitorManager *monitor_manager = meta_backend_get_monitor_manager (backend); - MetaMonitorManagerKms *monitor_manager_kms = - META_MONITOR_MANAGER_KMS (monitor_manager); + MetaMonitorManagerNative *monitor_manager_native = + META_MONITOR_MANAGER_NATIVE (monitor_manager); MetaIdleMonitor *idle_monitor; ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); MetaSeatNative *seat = @@ -631,7 +708,7 @@ void meta_backend_native_resume (MetaBackendNative *native) COGL_TRACE_BEGIN_SCOPED (MetaBackendNativeResume, "Backend (resume)"); - meta_monitor_manager_kms_resume (monitor_manager_kms); + meta_monitor_manager_native_resume (monitor_manager_native); meta_kms_resume (native->kms); connect_udev_device_added_handler (native); diff --git a/src/backends/native/meta-backend-native.h b/src/backends/native/meta-backend-native.h index b0d82d0161b9bcaee43f3f79eda9be37f7ed3bef..aad4c8413fe881dcb3f7b7d88a3055d1ebc878af 100644 --- a/src/backends/native/meta-backend-native.h +++ b/src/backends/native/meta-backend-native.h @@ -32,6 +32,7 @@ #include "backends/native/meta-udev.h" #define META_TYPE_BACKEND_NATIVE (meta_backend_native_get_type ()) +META_EXPORT_TEST G_DECLARE_FINAL_TYPE (MetaBackendNative, meta_backend_native, META, BACKEND_NATIVE, MetaBackend) @@ -49,4 +50,6 @@ MetaKms * meta_backend_native_get_kms (MetaBackendNative *native); const char * meta_backend_native_get_seat_id (MetaBackendNative *backend_native); +gboolean meta_backend_native_is_headless (MetaBackendNative *backend_native); + #endif /* META_BACKEND_NATIVE_H */ diff --git a/src/backends/native/meta-clutter-backend-native.c b/src/backends/native/meta-clutter-backend-native.c index 798f670c1877d11c2798f2aadf057cd60cbc56cc..46156d8988ae8444d3afa7096f113a160192970d 100644 --- a/src/backends/native/meta-clutter-backend-native.c +++ b/src/backends/native/meta-clutter-backend-native.c @@ -106,12 +106,19 @@ meta_clutter_backend_native_init_events (ClutterBackend *clutter_backend) MetaBackend *backend = meta_get_backend (); MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); const char *seat_id; + MetaSeatNativeFlag flags; seat_id = meta_backend_native_get_seat_id (backend_native); + if (meta_backend_native_is_headless (backend_native)) + flags = META_SEAT_NATIVE_FLAG_NO_LIBINPUT; + else + flags = META_SEAT_NATIVE_FLAG_NONE; + clutter_backend_native->main_seat = g_object_new (META_TYPE_SEAT_NATIVE, "backend", clutter_backend, "seat-id", seat_id, + "flags", flags, NULL); } diff --git a/src/backends/native/meta-crtc-kms.c b/src/backends/native/meta-crtc-kms.c index e1272f88c941eb54089b0ad9b0c2f708172c5016..f1bc79146af96ba83d1d4145043ee94ec4e37c32 100644 --- a/src/backends/native/meta-crtc-kms.c +++ b/src/backends/native/meta-crtc-kms.c @@ -34,13 +34,13 @@ #include "backends/native/meta-kms-plane.h" #include "backends/native/meta-kms-update.h" #include "backends/native/meta-kms.h" -#include "backends/native/meta-monitor-manager-kms.h" +#include "backends/native/meta-monitor-manager-native.h" #define ALL_TRANSFORMS_MASK ((1 << META_MONITOR_N_TRANSFORMS) - 1) struct _MetaCrtcKms { - MetaCrtc parent; + MetaCrtcNative parent; MetaKmsCrtc *kms_crtc; @@ -54,7 +54,7 @@ struct _MetaCrtcKms static GQuark kms_crtc_crtc_kms_quark; -G_DEFINE_TYPE (MetaCrtcKms, meta_crtc_kms, META_TYPE_CRTC) +G_DEFINE_TYPE (MetaCrtcKms, meta_crtc_kms, META_TYPE_CRTC_NATIVE) gpointer meta_crtc_kms_get_cursor_renderer_private (MetaCrtcKms *crtc_kms) @@ -74,9 +74,9 @@ meta_crtc_kms_set_cursor_renderer_private (MetaCrtcKms *crtc_kms, crtc_kms->cursor_renderer_private_destroy_notify = destroy_notify; } -gboolean -meta_crtc_kms_is_transform_handled (MetaCrtcKms *crtc_kms, - MetaMonitorTransform transform) +static gboolean +is_transform_handled (MetaCrtcKms *crtc_kms, + MetaMonitorTransform transform) { if (!crtc_kms->primary_plane) return FALSE; @@ -85,6 +85,15 @@ meta_crtc_kms_is_transform_handled (MetaCrtcKms *crtc_kms, transform); } +static gboolean +meta_crtc_kms_is_transform_handled (MetaCrtcNative *crtc_native, + MetaMonitorTransform transform) +{ + MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc_native); + + return is_transform_handled (crtc_kms, transform); +} + void meta_crtc_kms_apply_transform (MetaCrtcKms *crtc_kms, MetaKmsPlaneAssignment *kms_plane_assignment) @@ -96,9 +105,9 @@ meta_crtc_kms_apply_transform (MetaCrtcKms *crtc_kms, crtc_config = meta_crtc_get_config (crtc); hw_transform = crtc_config->transform; - if (!meta_crtc_kms_is_transform_handled (crtc_kms, hw_transform)) + if (!is_transform_handled (crtc_kms, hw_transform)) hw_transform = META_MONITOR_TRANSFORM_NORMAL; - if (!meta_crtc_kms_is_transform_handled (crtc_kms, hw_transform)) + if (!is_transform_handled (crtc_kms, hw_transform)) return; meta_kms_plane_update_set_rotation (crtc_kms->primary_plane, @@ -187,8 +196,8 @@ meta_crtc_kms_maybe_set_gamma (MetaCrtcKms *crtc_kms, MetaBackend *backend = meta_gpu_get_backend (gpu); MetaMonitorManager *monitor_manager = meta_backend_get_monitor_manager (backend); - MetaMonitorManagerKms *monitor_manager_kms = - META_MONITOR_MANAGER_KMS (monitor_manager); + MetaMonitorManagerNative *monitor_manager_native = + META_MONITOR_MANAGER_NATIVE (monitor_manager); MetaKms *kms = meta_kms_device_get_kms (kms_device); MetaKmsUpdate *kms_update; MetaKmsCrtcGamma *gamma; @@ -196,8 +205,8 @@ meta_crtc_kms_maybe_set_gamma (MetaCrtcKms *crtc_kms, if (crtc_kms->is_gamma_valid) return; - gamma = meta_monitor_manager_kms_get_cached_crtc_gamma (monitor_manager_kms, - crtc_kms); + gamma = meta_monitor_manager_native_get_cached_crtc_gamma (monitor_manager_native, + crtc_kms); if (!gamma) return; @@ -369,6 +378,9 @@ static void meta_crtc_kms_class_init (MetaCrtcKmsClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + MetaCrtcNativeClass *crtc_native_class = META_CRTC_NATIVE_CLASS (klass); object_class->dispose = meta_crtc_kms_dispose; + + crtc_native_class->is_transform_handled = meta_crtc_kms_is_transform_handled; } diff --git a/src/backends/native/meta-crtc-kms.h b/src/backends/native/meta-crtc-kms.h index 8c4df1fad0312220fbaa748a243a03380befafb7..f8d241bbb51409341acef36d435b67f6d42cdeef 100644 --- a/src/backends/native/meta-crtc-kms.h +++ b/src/backends/native/meta-crtc-kms.h @@ -28,6 +28,7 @@ #include "backends/meta-backend-types.h" #include "backends/meta-crtc.h" +#include "backends/native/meta-crtc-native.h" #include "backends/native/meta-drm-buffer.h" #include "backends/native/meta-gpu-kms.h" #include "backends/native/meta-kms-crtc.h" @@ -36,7 +37,7 @@ #define META_TYPE_CRTC_KMS (meta_crtc_kms_get_type ()) G_DECLARE_FINAL_TYPE (MetaCrtcKms, meta_crtc_kms, META, CRTC_KMS, - MetaCrtc) + MetaCrtcNative) gpointer meta_crtc_kms_get_cursor_renderer_private (MetaCrtcKms *crtc_kms); @@ -44,9 +45,6 @@ void meta_crtc_kms_set_cursor_renderer_private (MetaCrtcKms *crtc_kms, gpointer cursor_renderer_private, GDestroyNotify destroy_notify); -gboolean meta_crtc_kms_is_transform_handled (MetaCrtcKms *crtc_kms, - MetaMonitorTransform transform); - void meta_crtc_kms_apply_transform (MetaCrtcKms *crtc_kms, MetaKmsPlaneAssignment *kms_plane_assignment); diff --git a/src/backends/native/meta-crtc-mode-virtual.c b/src/backends/native/meta-crtc-mode-virtual.c new file mode 100644 index 0000000000000000000000000000000000000000..3bb883049e515c6f05291f003167cd9899632ff6 --- /dev/null +++ b/src/backends/native/meta-crtc-mode-virtual.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2021 Red Hat + * + * 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/native/meta-crtc-mode-virtual.h" + +#include "backends/meta-virtual-monitor.h" + +struct _MetaCrtcModeVirtual +{ + MetaCrtcMode parent; +}; + +#define META_CRTC_MODE_VIRTUAL_ID_BIT (((uint64_t) 1) << 63) + +G_DEFINE_TYPE (MetaCrtcModeVirtual, meta_crtc_mode_virtual, + META_TYPE_CRTC_MODE) + +MetaCrtcModeVirtual * +meta_crtc_mode_virtual_new (uint64_t id, + const MetaVirtualMonitorInfo *info) +{ + g_autoptr (MetaCrtcModeInfo) crtc_mode_info = NULL; + g_autofree char *crtc_mode_name = NULL; + MetaCrtcModeVirtual *mode_virtual; + + crtc_mode_info = meta_crtc_mode_info_new (); + crtc_mode_info->width = info->width; + crtc_mode_info->height = info->height; + crtc_mode_info->refresh_rate = info->refresh_rate; + + crtc_mode_name = g_strdup_printf ("%dx%d@%f", + info->width, + info->height, + info->refresh_rate); + mode_virtual = g_object_new (META_TYPE_CRTC_MODE_VIRTUAL, + "id", META_CRTC_MODE_VIRTUAL_ID_BIT | id, + "name", crtc_mode_name, + "info", crtc_mode_info, + NULL); + + return mode_virtual; +} + +static void +meta_crtc_mode_virtual_init (MetaCrtcModeVirtual *mode_virtual) +{ +} + +static void +meta_crtc_mode_virtual_class_init (MetaCrtcModeVirtualClass *klass) +{ +} diff --git a/src/backends/native/meta-crtc-mode-virtual.h b/src/backends/native/meta-crtc-mode-virtual.h new file mode 100644 index 0000000000000000000000000000000000000000..e3ddb289c9e468e44233e09ba0b3694980a79274 --- /dev/null +++ b/src/backends/native/meta-crtc-mode-virtual.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2021 Red Hat + * + * 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_CRTC_MODE_VIRTUAL_H +#define META_CRTC_MODE_VIRTUAL_H + +#include "backends/meta-backend-types.h" +#include "backends/meta-crtc-mode.h" + +#define META_TYPE_CRTC_MODE_VIRTUAL (meta_crtc_mode_virtual_get_type ()) +G_DECLARE_FINAL_TYPE (MetaCrtcModeVirtual, meta_crtc_mode_virtual, + META, CRTC_MODE_VIRTUAL, + MetaCrtcMode) + +MetaCrtcModeVirtual * meta_crtc_mode_virtual_new (uint64_t id, + const MetaVirtualMonitorInfo *info); + +#endif /* META_CRTC_MODE_VIRTUAL_H */ diff --git a/src/backends/native/meta-crtc-native.c b/src/backends/native/meta-crtc-native.c new file mode 100644 index 0000000000000000000000000000000000000000..5e5751780f098899e7ab47c7831f799daaf17963 --- /dev/null +++ b/src/backends/native/meta-crtc-native.c @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 Red Hat + * + * 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/native/meta-crtc-native.h" + +G_DEFINE_ABSTRACT_TYPE (MetaCrtcNative, meta_crtc_native, + META_TYPE_CRTC) + +gboolean +meta_crtc_native_is_transform_handled (MetaCrtcNative *crtc_native, + MetaMonitorTransform transform) +{ + MetaCrtcNativeClass *klass = META_CRTC_NATIVE_GET_CLASS (crtc_native); + + return klass->is_transform_handled (crtc_native, transform); +} + +static void +meta_crtc_native_init (MetaCrtcNative *crtc_native) +{ +} + +static void +meta_crtc_native_class_init (MetaCrtcNativeClass *klass) +{ +} diff --git a/src/backends/native/meta-crtc-native.h b/src/backends/native/meta-crtc-native.h new file mode 100644 index 0000000000000000000000000000000000000000..0c16e5895984d199b2805ff776ca69410e93bde7 --- /dev/null +++ b/src/backends/native/meta-crtc-native.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 Red Hat + * + * 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_CRTC_NATIVE_H +#define META_CRTC_NATIVE_H + +#include "backends/meta-crtc.h" + +#define META_TYPE_CRTC_NATIVE (meta_crtc_native_get_type ()) +G_DECLARE_DERIVABLE_TYPE (MetaCrtcNative, meta_crtc_native, + META, CRTC_NATIVE, + MetaCrtc) + +struct _MetaCrtcNativeClass +{ + MetaCrtcClass parent_class; + + gboolean (* is_transform_handled) (MetaCrtcNative *crtc_native, + MetaMonitorTransform monitor_transform); +}; + +gboolean meta_crtc_native_is_transform_handled (MetaCrtcNative *crtc_native, + MetaMonitorTransform transform); + +#endif /* META_CRTC_NATIVE_H */ diff --git a/src/backends/native/meta-crtc-virtual.c b/src/backends/native/meta-crtc-virtual.c new file mode 100644 index 0000000000000000000000000000000000000000..eee346a23350b76c60a2aeca766e51ef9e769308 --- /dev/null +++ b/src/backends/native/meta-crtc-virtual.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2021 Red Hat + * + * 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/native/meta-crtc-virtual.h" + +struct _MetaCrtcVirtual +{ + MetaCrtcNative parent; +}; + +#define META_CRTC_VIRTUAL_ID_BIT (((uint64_t) 1) << 63) + +G_DEFINE_TYPE (MetaCrtcVirtual, meta_crtc_virtual, META_TYPE_CRTC_NATIVE) + +MetaCrtcVirtual * +meta_crtc_virtual_new (uint64_t id) +{ + return g_object_new (META_TYPE_CRTC_VIRTUAL, + "id", META_CRTC_VIRTUAL_ID_BIT | id, + NULL); +} + +static gboolean +meta_crtc_virtual_is_transform_handled (MetaCrtcNative *crtc_native, + MetaMonitorTransform transform) +{ + return transform == META_MONITOR_TRANSFORM_NORMAL; +} + +static void +meta_crtc_virtual_init (MetaCrtcVirtual *crtc_virtual) +{ +} + +static void +meta_crtc_virtual_class_init (MetaCrtcVirtualClass *klass) +{ + MetaCrtcNativeClass *crtc_native_class = META_CRTC_NATIVE_CLASS (klass); + + crtc_native_class->is_transform_handled = + meta_crtc_virtual_is_transform_handled; +} diff --git a/src/backends/native/meta-crtc-virtual.h b/src/backends/native/meta-crtc-virtual.h new file mode 100644 index 0000000000000000000000000000000000000000..89b1bcc7a6ebcbccd68f5efe88325776464faca6 --- /dev/null +++ b/src/backends/native/meta-crtc-virtual.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 Red Hat + * + * 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_CRTC_VIRTUAL_H +#define META_CRTC_VIRTUAL_H + +#include "backends/native/meta-crtc-native.h" + +#define META_TYPE_CRTC_VIRTUAL (meta_crtc_virtual_get_type ()) +G_DECLARE_FINAL_TYPE (MetaCrtcVirtual, meta_crtc_virtual, + META, CRTC_VIRTUAL, + MetaCrtcNative) + +MetaCrtcVirtual * meta_crtc_virtual_new (uint64_t id); + +#endif /* META_CRTC_VIRTUAL_H */ diff --git a/src/backends/native/meta-cursor-renderer-native.c b/src/backends/native/meta-cursor-renderer-native.c index bb436b2c052bdbb78490b953650acefe902f4835..098ef24bdf2ef26fc4b5ee4c9fd57e84ac958316 100644 --- a/src/backends/native/meta-cursor-renderer-native.c +++ b/src/backends/native/meta-cursor-renderer-native.c @@ -542,6 +542,9 @@ meta_cursor_renderer_native_prepare_frame (MetaCursorRendererNative *cursor_rend META_POWER_SAVE_ON) return; + if (!meta_crtc_get_gpu (crtc)) + return; + crtc_cursor_data = ensure_crtc_cursor_data (META_CRTC_KMS (crtc)); if (!crtc_cursor_data->hw_state_invalidated && !crtc_cursor_data->needs_sync_position) @@ -849,6 +852,9 @@ should_have_hw_cursor (MetaCursorRenderer *renderer, float scale; GList *l; + if (!gpus) + return FALSE; + if (!cursor_sprite) return FALSE; @@ -985,10 +991,11 @@ calculate_cursor_sprite_gpus (MetaCursorRenderer *renderer, for (l_mon = monitors; l_mon; l_mon = l_mon->next) { MetaMonitor *monitor = l_mon->data; + MetaOutput *output = meta_monitor_get_main_output (monitor); MetaGpu *gpu; - gpu = meta_monitor_get_gpu (monitor); - if (!g_list_find (gpus, gpu)) + gpu = meta_output_get_gpu (output); + if (gpu && !g_list_find (gpus, gpu)) gpus = g_list_prepend (gpus, gpu); } } diff --git a/src/backends/native/meta-kms-connector.c b/src/backends/native/meta-kms-connector.c index 1ea4502845bf2f0c6de1a8e51f2d623916fd7136..0ad166176233c9a65fd4e73f672ef03dda28fe14 100644 --- a/src/backends/native/meta-kms-connector.c +++ b/src/backends/native/meta-kms-connector.c @@ -42,7 +42,7 @@ struct _MetaKmsConnector MetaKmsDevice *device; uint32_t id; - MetaConnectorType type; + uint32_t type; uint32_t type_id; char *name; @@ -76,7 +76,7 @@ meta_kms_connector_get_prop_name (MetaKmsConnector *connector, return connector->prop_table.props[prop].name; } -MetaConnectorType +uint32_t meta_kms_connector_get_connector_type (MetaKmsConnector *connector) { return connector->type; @@ -621,7 +621,7 @@ meta_kms_connector_new (MetaKmsImplDevice *impl_device, connector = g_object_new (META_TYPE_KMS_CONNECTOR, NULL); connector->device = meta_kms_impl_device_get_device (impl_device); connector->id = drm_connector->connector_id; - connector->type = (MetaConnectorType) drm_connector->connector_type; + connector->type = drm_connector->connector_type; connector->type_id = drm_connector->connector_type_id; connector->name = make_connector_name (drm_connector); diff --git a/src/backends/native/meta-kms-connector.h b/src/backends/native/meta-kms-connector.h index 50ffdd851efa2bd46d349410584a72763a0e78a9..a3a7136c5a5e04288767df877e0c7d08bad90b2e 100644 --- a/src/backends/native/meta-kms-connector.h +++ b/src/backends/native/meta-kms-connector.h @@ -61,7 +61,7 @@ typedef struct _MetaKmsConnectorState MetaKmsDevice * meta_kms_connector_get_device (MetaKmsConnector *connector); -MetaConnectorType meta_kms_connector_get_connector_type (MetaKmsConnector *connector); +uint32_t meta_kms_connector_get_connector_type (MetaKmsConnector *connector); uint32_t meta_kms_connector_get_id (MetaKmsConnector *connector); diff --git a/src/backends/native/meta-kms-device.c b/src/backends/native/meta-kms-device.c index b5b50d602c49132381449c6f6433057feca6bc21..c388096d5935246a1d310affe166179a47a0cbfb 100644 --- a/src/backends/native/meta-kms-device.c +++ b/src/backends/native/meta-kms-device.c @@ -23,10 +23,14 @@ #include "backends/native/meta-kms-device-private.h" #include "backends/native/meta-kms-device.h" +#include +#include +#include #include #include "backends/native/meta-backend-native.h" #include "backends/native/meta-kms-impl-device-atomic.h" +#include "backends/native/meta-kms-impl-device-dummy.h" #include "backends/native/meta-kms-impl-device-simple.h" #include "backends/native/meta-kms-impl-device.h" #include "backends/native/meta-kms-impl.h" @@ -227,6 +231,7 @@ typedef struct _CreateImplDeviceData MetaKmsDevice *device; int fd; const char *path; + MetaKmsDeviceFlag flags; MetaKmsImplDevice *out_impl_device; GList *out_crtcs; @@ -236,6 +241,7 @@ typedef struct _CreateImplDeviceData GList *out_fallback_modes; char *out_driver_name; char *out_driver_description; + char *out_path; } CreateImplDeviceData; static gboolean @@ -273,30 +279,24 @@ get_driver_info (int fd, } static MetaKmsImplDevice * -meta_create_kms_impl_device (MetaKmsDevice *device, - MetaKmsImpl *impl, - int fd, - const char *path, - GError **error) +meta_create_kms_impl_device (MetaKmsDevice *device, + MetaKmsImpl *impl, + int fd, + const char *path, + MetaKmsDeviceFlag flags, + GError **error) { GType impl_device_type; gboolean supports_atomic_mode_setting; - int ret; g_autofree char *driver_name = NULL; g_autofree char *driver_description = NULL; const char *atomic_kms_enable_env; + int impl_fd; + g_autofree char *impl_path = NULL; + MetaKmsImplDevice *impl_device; meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl)); - ret = drmSetClientCap (fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); - if (ret != 0) - { - g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret), - "Failed to activate universal planes: %s", - g_strerror (-ret)); - return NULL; - } - if (!get_driver_info (fd, &driver_name, &driver_description)) { driver_name = g_strdup ("unknown"); @@ -304,7 +304,36 @@ meta_create_kms_impl_device (MetaKmsDevice *device, } atomic_kms_enable_env = getenv ("MUTTER_DEBUG_ENABLE_ATOMIC_KMS"); - if (atomic_kms_enable_env) + + if (flags & META_KMS_DEVICE_FLAG_NO_MODE_SETTING) + { + g_autofree char *render_node_path = NULL; + + render_node_path = drmGetRenderDeviceNameFromFd (fd); + if (!render_node_path) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Couldn't find render node device for '%s' (%s)", + path, driver_name); + return NULL; + } + + impl_fd = open (render_node_path, O_RDWR | O_CLOEXEC, 0); + if (impl_fd == -1) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), + "Failed to open render node '%s': %s", + render_node_path, g_strerror (errno)); + return NULL; + } + + g_message ("Adding device '%s' (from '%s', %s) using no mode setting.", + render_node_path, path, driver_name); + + impl_path = g_steal_pointer (&render_node_path); + impl_device_type = META_TYPE_KMS_IMPL_DEVICE_DUMMY; + } + else if (atomic_kms_enable_env) { if (g_strcmp0 (atomic_kms_enable_env, "1") == 0) { @@ -326,6 +355,9 @@ meta_create_kms_impl_device (MetaKmsDevice *device, atomic_kms_enable_env); } + impl_fd = dup (fd); + impl_path = g_strdup (path); + g_message ("Mode setting implementation for '%s' (%s) forced (%s).", path, driver_name, impl_device_type == META_TYPE_KMS_IMPL_DEVICE_ATOMIC ? @@ -336,10 +368,14 @@ meta_create_kms_impl_device (MetaKmsDevice *device, g_message ("Adding device '%s' (%s) using non-atomic mode setting" " (using atomic mode setting not allowed).", path, driver_name); + impl_fd = dup (fd); + impl_path = g_strdup (path); impl_device_type = META_TYPE_KMS_IMPL_DEVICE_SIMPLE; } else { + int ret; + ret = drmSetClientCap (fd, DRM_CLIENT_CAP_ATOMIC, 1); if (ret == 0) supports_atomic_mode_setting = TRUE; @@ -358,16 +394,29 @@ meta_create_kms_impl_device (MetaKmsDevice *device, path, driver_name); impl_device_type = META_TYPE_KMS_IMPL_DEVICE_SIMPLE; } + + impl_fd = dup (fd); + impl_path = g_strdup (path); } - return g_initable_new (impl_device_type, NULL, error, - "device", device, - "impl", impl, - "fd", fd, - "path", path, - "driver-name", driver_name, - "driver-description", driver_description, - NULL); + impl_device = g_initable_new (impl_device_type, NULL, error, + "device", device, + "impl", impl, + "fd", impl_fd, + "path", impl_path, + "flags", flags, + "driver-name", driver_name, + "driver-description", driver_description, + NULL); + if (!impl_device) + { + close (impl_fd); + return NULL; + } + + close (fd); + + return impl_device; } static gpointer @@ -382,6 +431,7 @@ create_impl_device_in_impl (MetaKmsImpl *impl, impl, data->fd, data->path, + data->flags, error); if (!impl_device) return FALSE; @@ -399,6 +449,7 @@ create_impl_device_in_impl (MetaKmsImpl *impl, g_strdup (meta_kms_impl_device_get_driver_name (impl_device)); data->out_driver_description = g_strdup (meta_kms_impl_device_get_driver_description (impl_device)); + data->out_path = g_strdup (meta_kms_impl_device_get_path (impl_device)); return GINT_TO_POINTER (TRUE); } @@ -416,9 +467,22 @@ meta_kms_device_new (MetaKms *kms, CreateImplDeviceData data; int fd; - fd = meta_launcher_open_restricted (launcher, path, error); - if (fd == -1) - return NULL; + if (flags & META_KMS_DEVICE_FLAG_NO_MODE_SETTING) + { + fd = open (path, O_RDWR | O_CLOEXEC, 0); + if (fd == -1) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), + "Failed to open DRM device: %s", g_strerror (errno)); + return NULL; + } + } + else + { + fd = meta_launcher_open_restricted (launcher, path, error); + if (fd == -1) + return NULL; + } device = g_object_new (META_TYPE_KMS_DEVICE, NULL); device->kms = kms; @@ -427,11 +491,15 @@ meta_kms_device_new (MetaKms *kms, .device = device, .fd = fd, .path = path, + .flags = flags, }; if (!meta_kms_run_impl_task_sync (kms, create_impl_device_in_impl, &data, error)) { - meta_launcher_close_restricted (launcher, fd); + if (flags & META_KMS_DEVICE_FLAG_NO_MODE_SETTING) + close (fd); + else + meta_launcher_close_restricted (launcher, fd); g_object_unref (device); return NULL; } @@ -446,6 +514,8 @@ meta_kms_device_new (MetaKms *kms, device->fallback_modes = data.out_fallback_modes; device->driver_name = data.out_driver_name; device->driver_description = data.out_driver_description; + free (device->path); + device->path = data.out_path; return device; } @@ -503,7 +573,10 @@ meta_kms_device_finalize (GObject *object) } else { - meta_launcher_close_restricted (launcher, data.out_fd); + if (device->flags & META_KMS_DEVICE_FLAG_NO_MODE_SETTING) + close (data.out_fd); + else + meta_launcher_close_restricted (launcher, data.out_fd); } } G_OBJECT_CLASS (meta_kms_device_parent_class)->finalize (object); diff --git a/src/backends/native/meta-kms-impl-device-atomic.c b/src/backends/native/meta-kms-impl-device-atomic.c index a7c219ef3653ce1ff26e99018f0d7330a919a241..d2da354d375820f14ab8e4603c8bfa817eb349f2 100644 --- a/src/backends/native/meta-kms-impl-device-atomic.c +++ b/src/backends/native/meta-kms-impl-device-atomic.c @@ -44,8 +44,13 @@ struct _MetaKmsImplDeviceAtomic GHashTable *page_flip_datas; }; -G_DEFINE_TYPE (MetaKmsImplDeviceAtomic, meta_kms_impl_device_atomic, - META_TYPE_KMS_IMPL_DEVICE) +static void +initable_iface_init (GInitableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (MetaKmsImplDeviceAtomic, meta_kms_impl_device_atomic, + META_TYPE_KMS_IMPL_DEVICE, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, + initable_iface_init)) static uint32_t store_new_blob (MetaKmsImplDevice *impl_device, @@ -1006,6 +1011,16 @@ meta_kms_impl_device_atomic_finalize (GObject *object) G_OBJECT_CLASS (meta_kms_impl_device_atomic_parent_class)->finalize (object); } +static gboolean +meta_kms_impl_device_atomic_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (initable); + + return meta_kms_impl_device_init_mode_setting (impl_device, error); +} + static void meta_kms_impl_device_atomic_init (MetaKmsImplDeviceAtomic *impl_device_atomic) { @@ -1015,6 +1030,12 @@ meta_kms_impl_device_atomic_init (MetaKmsImplDeviceAtomic *impl_device_atomic) (GDestroyNotify) meta_kms_page_flip_data_unref); } +static void +initable_iface_init (GInitableIface *iface) +{ + iface->init = meta_kms_impl_device_atomic_initable_init; +} + static void meta_kms_impl_device_atomic_class_init (MetaKmsImplDeviceAtomicClass *klass) { diff --git a/src/backends/native/meta-kms-impl-device-dummy.c b/src/backends/native/meta-kms-impl-device-dummy.c new file mode 100644 index 0000000000000000000000000000000000000000..c1a0a44307f8158a6b1eebd4f4e78df4e9424965 --- /dev/null +++ b/src/backends/native/meta-kms-impl-device-dummy.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2021 Red Hat + * + * 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/native/meta-kms-impl-device-dummy.h" + +struct _MetaKmsImplDeviceDummy +{ + MetaKmsImplDevice parent; +}; + +static void +initable_iface_init (GInitableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (MetaKmsImplDeviceDummy, meta_kms_impl_device_dummy, + META_TYPE_KMS_IMPL_DEVICE, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, + initable_iface_init)) + +static void +meta_kms_impl_device_dummy_discard_pending_page_flips (MetaKmsImplDevice *impl) +{ +} + +static void +meta_kms_impl_device_dummy_init (MetaKmsImplDeviceDummy *impl_device_dummy) +{ +} + +static gboolean +meta_kms_impl_device_dummy_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + return TRUE; +} + +static void +initable_iface_init (GInitableIface *iface) +{ + iface->init = meta_kms_impl_device_dummy_initable_init; +} + +static void +meta_kms_impl_device_dummy_class_init (MetaKmsImplDeviceDummyClass *klass) +{ + MetaKmsImplDeviceClass *impl_device_class = + META_KMS_IMPL_DEVICE_CLASS (klass); + + impl_device_class->discard_pending_page_flips = + meta_kms_impl_device_dummy_discard_pending_page_flips; +} diff --git a/src/backends/native/meta-kms-impl-device-dummy.h b/src/backends/native/meta-kms-impl-device-dummy.h new file mode 100644 index 0000000000000000000000000000000000000000..9576939ad89090848d4213456665d23a4300c358 --- /dev/null +++ b/src/backends/native/meta-kms-impl-device-dummy.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2021 Red Hat + * + * 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_KMS_IMPL_DEVICE_DUMMY_H +#define META_KMS_IMPL_DEVICE_DUMMY_H + +#include "backends/native/meta-kms-impl-device.h" + +#define META_TYPE_KMS_IMPL_DEVICE_DUMMY (meta_kms_impl_device_dummy_get_type ()) +G_DECLARE_FINAL_TYPE (MetaKmsImplDeviceDummy, meta_kms_impl_device_dummy, + META, KMS_IMPL_DEVICE_DUMMY, + MetaKmsImplDevice) + +#endif /* META_KMS_IMPL_DEVICE_DUMMY_H */ diff --git a/src/backends/native/meta-kms-impl-device-simple.c b/src/backends/native/meta-kms-impl-device-simple.c index 99c09a687720ed95e4c25e2ea1174a2b1759f6fb..07f80c21f81c7b0e7ca83af4ccd5c685cb821d74 100644 --- a/src/backends/native/meta-kms-impl-device-simple.c +++ b/src/backends/native/meta-kms-impl-device-simple.c @@ -58,8 +58,6 @@ struct _MetaKmsImplDeviceSimple GHashTable *cached_mode_sets; }; -static GInitableIface *initable_parent_iface; - static void initable_iface_init (GInitableIface *iface); @@ -1507,7 +1505,7 @@ meta_kms_impl_device_simple_initable_init (GInitable *initable, MetaKmsDevice *device = meta_kms_impl_device_get_device (impl_device); GList *l; - if (!initable_parent_iface->init (initable, cancellable, error)) + if (!meta_kms_impl_device_init_mode_setting (impl_device, error)) return FALSE; impl_device_simple->cached_mode_sets = @@ -1546,8 +1544,6 @@ meta_kms_impl_device_simple_init (MetaKmsImplDeviceSimple *impl_device_simple) static void initable_iface_init (GInitableIface *iface) { - initable_parent_iface = g_type_interface_peek_parent (iface); - iface->init = meta_kms_impl_device_simple_initable_init; } diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c index b2f1c3f11190cd6d91b4604d8e1cc6eecbe741b1..d0247ef71f956838993ea5f65551231d2d2c6b6f 100644 --- a/src/backends/native/meta-kms-impl-device.c +++ b/src/backends/native/meta-kms-impl-device.c @@ -37,6 +37,7 @@ #include "backends/native/meta-kms-update.h" #include "meta-default-modes.h" +#include "meta-private-enum-types.h" enum { @@ -46,6 +47,7 @@ enum PROP_IMPL, PROP_FD, PROP_PATH, + PROP_FLAGS, PROP_DRIVER_NAME, PROP_DRIVER_DESCRIPTION, @@ -62,6 +64,7 @@ typedef struct _MetaKmsImplDevicePrivate int fd; GSource *fd_source; char *path; + MetaKmsDeviceFlag flags; char *driver_name; char *driver_description; @@ -75,14 +78,9 @@ typedef struct _MetaKmsImplDevicePrivate GList *fallback_modes; } MetaKmsImplDevicePrivate; -static void -initable_iface_init (GInitableIface *iface); - G_DEFINE_TYPE_WITH_CODE (MetaKmsImplDevice, meta_kms_impl_device, G_TYPE_OBJECT, - G_ADD_PRIVATE (MetaKmsImplDevice) - G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, - initable_iface_init)) + G_ADD_PRIVATE (MetaKmsImplDevice)) MetaKmsDevice * meta_kms_impl_device_get_device (MetaKmsImplDevice *impl_device) @@ -717,6 +715,9 @@ meta_kms_impl_device_get_property (GObject *object, case PROP_PATH: g_value_set_string (value, priv->path); break; + case PROP_FLAGS: + g_value_set_flags (value, priv->flags); + break; case PROP_DRIVER_NAME: g_value_set_string (value, priv->driver_name); break; @@ -753,6 +754,9 @@ meta_kms_impl_device_set_property (GObject *object, case PROP_PATH: priv->path = g_value_dup_string (value); break; + case PROP_FLAGS: + priv->flags = g_value_get_flags (value); + break; case PROP_DRIVER_NAME: priv->driver_name = g_value_dup_string (value); break; @@ -786,16 +790,24 @@ meta_kms_impl_device_finalize (GObject *object) G_OBJECT_CLASS (meta_kms_impl_device_parent_class)->finalize (object); } -static gboolean -meta_kms_impl_device_initable_init (GInitable *initable, - GCancellable *cancellable, - GError **error) +gboolean +meta_kms_impl_device_init_mode_setting (MetaKmsImplDevice *impl_device, + GError **error) { - MetaKmsImplDevice *impl_device = META_KMS_IMPL_DEVICE (initable); MetaKmsImplDevicePrivate *priv = meta_kms_impl_device_get_instance_private (impl_device); + int ret; drmModeRes *drm_resources; + ret = drmSetClientCap (priv->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); + if (ret != 0) + { + g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret), + "Failed to activate universal planes: %s", + g_strerror (-ret)); + return FALSE; + } + drm_resources = drmModeGetResources (priv->fd); if (!drm_resources) { @@ -829,12 +841,6 @@ meta_kms_impl_device_init (MetaKmsImplDevice *device) { } -static void -initable_iface_init (GInitableIface *initable_iface) -{ - initable_iface->init = meta_kms_impl_device_initable_init; -} - static void meta_kms_impl_device_class_init (MetaKmsImplDeviceClass *klass) { @@ -876,6 +882,15 @@ meta_kms_impl_device_class_init (MetaKmsImplDeviceClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_props[PROP_FLAGS] = + g_param_spec_flags ("flags", + "flags", + "KMS impl device flags", + META_TYPE_KMS_DEVICE_FLAG, + META_KMS_DEVICE_FLAG_NONE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); obj_props[PROP_DRIVER_NAME] = g_param_spec_string ("driver-name", "driver-name", diff --git a/src/backends/native/meta-kms-impl-device.h b/src/backends/native/meta-kms-impl-device.h index a3d31daebf6dbf8bbf0143b394dd64bd7ded2255..5b3585aa78d882f416c29bd7ff799d1999960b95 100644 --- a/src/backends/native/meta-kms-impl-device.h +++ b/src/backends/native/meta-kms-impl-device.h @@ -140,4 +140,7 @@ void meta_kms_impl_device_discard_pending_page_flips (MetaKmsImplDevice *impl_de int meta_kms_impl_device_close (MetaKmsImplDevice *impl_device); +gboolean meta_kms_impl_device_init_mode_setting (MetaKmsImplDevice *impl_device, + GError **error); + #endif /* META_KMS_IMPL_DEVICE_H */ diff --git a/src/backends/native/meta-kms-types.h b/src/backends/native/meta-kms-types.h index cf1adc44efd2aed8e23123fab8e51b93a2b18ba4..01db55a40299cf303ad653168cc321ecfd822d20 100644 --- a/src/backends/native/meta-kms-types.h +++ b/src/backends/native/meta-kms-types.h @@ -61,6 +61,7 @@ typedef enum _MetaKmsDeviceFlag META_KMS_DEVICE_FLAG_PLATFORM_DEVICE = 1 << 1, META_KMS_DEVICE_FLAG_REQUIRES_MODIFIERS = 1 << 2, META_KMS_DEVICE_FLAG_PREFERRED_PRIMARY = 1 << 3, + META_KMS_DEVICE_FLAG_NO_MODE_SETTING = 1 << 4, } MetaKmsDeviceFlag; typedef enum _MetaKmsPlaneType MetaKmsPlaneType; diff --git a/src/backends/native/meta-kms.c b/src/backends/native/meta-kms.c index ee77975bd46db5901b1f8381b46860e9c428415b..6514f89f6eaefa514b7fa4b60e38dba5a3a10f48 100644 --- a/src/backends/native/meta-kms.c +++ b/src/backends/native/meta-kms.c @@ -158,6 +158,8 @@ struct _MetaKms { GObject parent; + MetaKmsFlags flags; + MetaBackend *backend; gulong hotplug_handler_id; @@ -614,6 +616,9 @@ meta_kms_create_device (MetaKms *kms, { MetaKmsDevice *device; + if (kms->flags & META_KMS_FLAG_NO_MODE_SETTING) + flags |= META_KMS_DEVICE_FLAG_NO_MODE_SETTING; + device = meta_kms_device_new (kms, path, flags, error); if (!device) return NULL; @@ -624,14 +629,16 @@ meta_kms_create_device (MetaKms *kms, } MetaKms * -meta_kms_new (MetaBackend *backend, - GError **error) +meta_kms_new (MetaBackend *backend, + MetaKmsFlags flags, + GError **error) { MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); MetaUdev *udev = meta_backend_native_get_udev (backend_native); MetaKms *kms; kms = g_object_new (META_TYPE_KMS, NULL); + kms->flags = flags; kms->backend = backend; kms->impl = meta_kms_impl_new (kms); if (!kms->impl) @@ -640,8 +647,12 @@ meta_kms_new (MetaBackend *backend, return NULL; } - kms->hotplug_handler_id = - g_signal_connect (udev, "hotplug", G_CALLBACK (on_udev_hotplug), kms); + if (!(flags & META_KMS_FLAG_NO_MODE_SETTING)) + { + kms->hotplug_handler_id = + g_signal_connect (udev, "hotplug", G_CALLBACK (on_udev_hotplug), kms); + } + kms->removed_handler_id = g_signal_connect (udev, "device-removed", G_CALLBACK (on_udev_device_removed), kms); diff --git a/src/backends/native/meta-kms.h b/src/backends/native/meta-kms.h index 7bbd78e0c5e34fef6de1c72357267cd182ba51f8..27b4e3537ec6c9127c49f31cb0027935a09ae6f3 100644 --- a/src/backends/native/meta-kms.h +++ b/src/backends/native/meta-kms.h @@ -25,6 +25,12 @@ #include "backends/meta-backend-private.h" #include "backends/native/meta-kms-types.h" +typedef enum _MetaKmsFlags +{ + META_KMS_FLAG_NONE = 0, + META_KMS_FLAG_NO_MODE_SETTING = 1 << 0, +} MetaKmsFlags; + typedef enum _MetaKmsUpdateFlag { META_KMS_UPDATE_FLAG_NONE = 0, @@ -57,7 +63,8 @@ MetaKmsDevice * meta_kms_create_device (MetaKms *kms, MetaKmsDeviceFlag flags, GError **error); -MetaKms * meta_kms_new (MetaBackend *backend, - GError **error); +MetaKms * meta_kms_new (MetaBackend *backend, + MetaKmsFlags flags, + GError **error); #endif /* META_KMS_H */ diff --git a/src/backends/native/meta-monitor-manager-kms.c b/src/backends/native/meta-monitor-manager-native.c similarity index 59% rename from src/backends/native/meta-monitor-manager-kms.c rename to src/backends/native/meta-monitor-manager-native.c index 6b952035ad87975bb44f51c900dcff47f4785608..82cf0373eaf8db2cbb888d6677ffba9d400168f8 100644 --- a/src/backends/native/meta-monitor-manager-kms.c +++ b/src/backends/native/meta-monitor-manager-native.c @@ -23,11 +23,11 @@ */ /** - * SECTION:meta-monitor-manager-kms - * @title: MetaMonitorManagerKms + * SECTION:meta-monitor-manager-native + * @title: MetaMonitorManagerNative * @short_description: A subclass of #MetaMonitorManager using Linux DRM * - * #MetaMonitorManagerKms is a subclass of #MetaMonitorManager which + * #MetaMonitorManagerNative is a subclass of #MetaMonitorManager which * implements its functionality "natively": it uses the appropriate * functions of the Linux DRM kernel module and using a udev client. * @@ -36,7 +36,7 @@ #include "config.h" -#include "backends/native/meta-monitor-manager-kms.h" +#include "backends/native/meta-monitor-manager-native.h" #include #include @@ -59,44 +59,60 @@ #include "backends/native/meta-launcher.h" #include "backends/native/meta-output-kms.h" #include "backends/native/meta-renderer-native.h" +#include "backends/native/meta-virtual-monitor-native.h" #include "clutter/clutter.h" #include "meta/main.h" #include "meta/meta-x11-errors.h" -struct _MetaMonitorManagerKms +enum +{ + PROP_0, + + PROP_NEED_OUTPUTS, + + N_PROPS +}; + +static GParamSpec *obj_props[N_PROPS]; + +struct _MetaMonitorManagerNative { MetaMonitorManager parent_instance; gulong kms_resources_changed_handler_id; GHashTable *crtc_gamma_cache; + + gboolean needs_outputs; }; -struct _MetaMonitorManagerKmsClass +struct _MetaMonitorManagerNativeClass { MetaMonitorManagerClass parent_class; }; +#define VIRTUAL_OUTPUT_ID_BIT (((uint64_t) 1) << 63) + static void initable_iface_init (GInitableIface *initable_iface); -G_DEFINE_TYPE_WITH_CODE (MetaMonitorManagerKms, meta_monitor_manager_kms, +G_DEFINE_TYPE_WITH_CODE (MetaMonitorManagerNative, meta_monitor_manager_native, META_TYPE_MONITOR_MANAGER, G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)) static GBytes * -meta_monitor_manager_kms_read_edid (MetaMonitorManager *manager, - MetaOutput *output) +meta_monitor_manager_native_read_edid (MetaMonitorManager *manager, + MetaOutput *output) { - return meta_output_kms_read_edid (META_OUTPUT_KMS (output)); + return meta_output_native_read_edid (META_OUTPUT_NATIVE (output)); } static void -meta_monitor_manager_kms_read_current_state (MetaMonitorManager *manager) +meta_monitor_manager_native_read_current_state (MetaMonitorManager *manager) { MetaMonitorManagerClass *parent_class = - META_MONITOR_MANAGER_CLASS (meta_monitor_manager_kms_parent_class); + META_MONITOR_MANAGER_CLASS (meta_monitor_manager_native_parent_class); MetaPowerSave power_save_mode; power_save_mode = meta_monitor_manager_get_power_save_mode (manager); @@ -129,8 +145,8 @@ meta_power_save_to_dpms_state (MetaPowerSave power_save) } static void -meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager, - MetaPowerSave mode) +meta_monitor_manager_native_set_power_save_mode (MetaMonitorManager *manager, + MetaPowerSave mode) { MetaBackend *backend = meta_monitor_manager_get_backend (manager); MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); @@ -174,7 +190,7 @@ meta_monitor_manager_kms_set_power_save_mode (MetaMonitorManager *manager, } static void -meta_monitor_manager_kms_ensure_initial_config (MetaMonitorManager *manager) +meta_monitor_manager_native_ensure_initial_config (MetaMonitorManager *manager) { MetaMonitorsConfig *config; @@ -211,6 +227,16 @@ apply_crtc_assignments (MetaMonitorManager *manager, to_configure_crtcs = g_list_concat (to_configure_crtcs, crtcs); } + for (l = meta_monitor_manager_get_virtual_monitors (manager); l; l = l->next) + { + MetaVirtualMonitor *virtual_monitor = l->data; + MetaOutput *output = meta_virtual_monitor_get_output (virtual_monitor); + MetaCrtc *crtc = meta_virtual_monitor_get_crtc (virtual_monitor); + + to_configure_outputs = g_list_append (to_configure_outputs, output); + to_configure_crtcs = g_list_append (to_configure_crtcs, crtc); + } + for (i = 0; i < n_crtcs; i++) { MetaCrtcAssignment *crtc_assignment = crtcs[i]; @@ -286,10 +312,10 @@ update_screen_size (MetaMonitorManager *manager, } static gboolean -meta_monitor_manager_kms_apply_monitors_config (MetaMonitorManager *manager, - MetaMonitorsConfig *config, - MetaMonitorsConfigMethod method, - GError **error) +meta_monitor_manager_native_apply_monitors_config (MetaMonitorManager *manager, + MetaMonitorsConfig *config, + MetaMonitorsConfigMethod method, + GError **error) { GPtrArray *crtc_assignments; GPtrArray *output_assignments; @@ -339,16 +365,18 @@ meta_monitor_manager_kms_apply_monitors_config (MetaMonitorManager *manager } static void -meta_monitor_manager_kms_get_crtc_gamma (MetaMonitorManager *manager, - MetaCrtc *crtc, - gsize *size, - unsigned short **red, - unsigned short **green, - unsigned short **blue) +meta_monitor_manager_native_get_crtc_gamma (MetaMonitorManager *manager, + MetaCrtc *crtc, + gsize *size, + unsigned short **red, + unsigned short **green, + unsigned short **blue) { MetaKmsCrtc *kms_crtc; const MetaKmsCrtcState *crtc_state; + g_return_if_fail (META_IS_CRTC_KMS (crtc)); + kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc)); crtc_state = meta_kms_crtc_get_current_state (kms_crtc); @@ -422,32 +450,38 @@ generate_gamma_ramp_string (size_t size, } MetaKmsCrtcGamma * -meta_monitor_manager_kms_get_cached_crtc_gamma (MetaMonitorManagerKms *manager_kms, - MetaCrtcKms *crtc_kms) +meta_monitor_manager_native_get_cached_crtc_gamma (MetaMonitorManagerNative *manager_native, + MetaCrtcKms *crtc_kms) { uint64_t crtc_id; crtc_id = meta_crtc_get_id (META_CRTC (crtc_kms)); - return g_hash_table_lookup (manager_kms->crtc_gamma_cache, + return g_hash_table_lookup (manager_native->crtc_gamma_cache, GUINT_TO_POINTER (crtc_id)); } static void -meta_monitor_manager_kms_set_crtc_gamma (MetaMonitorManager *manager, - MetaCrtc *crtc, - gsize size, - unsigned short *red, - unsigned short *green, - unsigned short *blue) -{ - MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (manager); - MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc); - MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc)); +meta_monitor_manager_native_set_crtc_gamma (MetaMonitorManager *manager, + MetaCrtc *crtc, + gsize size, + unsigned short *red, + unsigned short *green, + unsigned short *blue) +{ + MetaMonitorManagerNative *manager_native = + META_MONITOR_MANAGER_NATIVE (manager); + MetaCrtcKms *crtc_kms; + MetaKmsCrtc *kms_crtc; g_autofree char *gamma_ramp_string = NULL; MetaBackend *backend = meta_monitor_manager_get_backend (manager); ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); - g_hash_table_replace (manager_kms->crtc_gamma_cache, + g_return_if_fail (META_IS_CRTC_KMS (crtc)); + + crtc_kms = META_CRTC_KMS (crtc); + kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc)); + + g_hash_table_replace (manager_native->crtc_gamma_cache, GUINT_TO_POINTER (meta_crtc_get_id (crtc)), meta_kms_crtc_gamma_new (kms_crtc, size, red, green, blue)); @@ -474,63 +508,64 @@ on_kms_resources_changed (MetaKms *kms, } static void -meta_monitor_manager_kms_connect_hotplug_handler (MetaMonitorManagerKms *manager_kms) +meta_monitor_manager_native_connect_hotplug_handler (MetaMonitorManagerNative *manager_native) { - MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms); + MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_native); MetaBackend *backend = meta_monitor_manager_get_backend (manager); MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); MetaKms *kms = meta_backend_native_get_kms (backend_native); - manager_kms->kms_resources_changed_handler_id = + manager_native->kms_resources_changed_handler_id = g_signal_connect (kms, "resources-changed", G_CALLBACK (on_kms_resources_changed), manager); } static void -meta_monitor_manager_kms_disconnect_hotplug_handler (MetaMonitorManagerKms *manager_kms) +meta_monitor_manager_native_disconnect_hotplug_handler (MetaMonitorManagerNative *manager_native) { - MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms); + MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_native); MetaBackend *backend = meta_monitor_manager_get_backend (manager); MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); MetaKms *kms = meta_backend_native_get_kms (backend_native); - g_clear_signal_handler (&manager_kms->kms_resources_changed_handler_id, kms); + g_clear_signal_handler (&manager_native->kms_resources_changed_handler_id, kms); } void -meta_monitor_manager_kms_pause (MetaMonitorManagerKms *manager_kms) +meta_monitor_manager_native_pause (MetaMonitorManagerNative *manager_native) { - meta_monitor_manager_kms_disconnect_hotplug_handler (manager_kms); + meta_monitor_manager_native_disconnect_hotplug_handler (manager_native); } void -meta_monitor_manager_kms_resume (MetaMonitorManagerKms *manager_kms) +meta_monitor_manager_native_resume (MetaMonitorManagerNative *manager_native) { - meta_monitor_manager_kms_connect_hotplug_handler (manager_kms); + meta_monitor_manager_native_connect_hotplug_handler (manager_native); } static gboolean -meta_monitor_manager_kms_is_transform_handled (MetaMonitorManager *manager, - MetaCrtc *crtc, - MetaMonitorTransform transform) +meta_monitor_manager_native_is_transform_handled (MetaMonitorManager *manager, + MetaCrtc *crtc, + MetaMonitorTransform transform) { - return meta_crtc_kms_is_transform_handled (META_CRTC_KMS (crtc), transform); + return meta_crtc_native_is_transform_handled (META_CRTC_NATIVE (crtc), + transform); } static float -meta_monitor_manager_kms_calculate_monitor_mode_scale (MetaMonitorManager *manager, - MetaMonitor *monitor, - MetaMonitorMode *monitor_mode) +meta_monitor_manager_native_calculate_monitor_mode_scale (MetaMonitorManager *manager, + MetaMonitor *monitor, + MetaMonitorMode *monitor_mode) { return meta_monitor_calculate_mode_scale (monitor, monitor_mode); } static float * -meta_monitor_manager_kms_calculate_supported_scales (MetaMonitorManager *manager, - MetaLogicalMonitorLayoutMode layout_mode, - MetaMonitor *monitor, - MetaMonitorMode *monitor_mode, - int *n_supported_scales) +meta_monitor_manager_native_calculate_supported_scales (MetaMonitorManager *manager, + MetaLogicalMonitorLayoutMode layout_mode, + MetaMonitor *monitor, + MetaMonitorMode *monitor_mode, + int *n_supported_scales) { MetaMonitorScalesConstraint constraints = META_MONITOR_SCALES_CONSTRAINT_NONE; @@ -550,7 +585,7 @@ meta_monitor_manager_kms_calculate_supported_scales (MetaMonitorManager } static MetaMonitorManagerCapability -meta_monitor_manager_kms_get_capabilities (MetaMonitorManager *manager) +meta_monitor_manager_native_get_capabilities (MetaMonitorManager *manager) { MetaBackend *backend = meta_monitor_manager_get_backend (manager); MetaSettings *settings = meta_backend_get_settings (backend); @@ -566,15 +601,15 @@ meta_monitor_manager_kms_get_capabilities (MetaMonitorManager *manager) } static gboolean -meta_monitor_manager_kms_get_max_screen_size (MetaMonitorManager *manager, - int *max_width, - int *max_height) +meta_monitor_manager_native_get_max_screen_size (MetaMonitorManager *manager, + int *max_width, + int *max_height) { return FALSE; } static MetaLogicalMonitorLayoutMode -meta_monitor_manager_kms_get_default_layout_mode (MetaMonitorManager *manager) +meta_monitor_manager_native_get_default_layout_mode (MetaMonitorManager *manager) { MetaBackend *backend = meta_monitor_manager_get_backend (manager); MetaSettings *settings = meta_backend_get_settings (backend); @@ -587,29 +622,100 @@ meta_monitor_manager_kms_get_default_layout_mode (MetaMonitorManager *manager) return META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL; } +static MetaVirtualMonitorNative * +find_virtual_monitor (MetaMonitorManagerNative *manager_native, + uint64_t id) +{ + MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_native); + GList *l; + + for (l = meta_monitor_manager_get_virtual_monitors (manager); l; l = l->next) + { + MetaVirtualMonitorNative *virtual_monitor_native = l->data; + + if (meta_virtual_monitor_native_get_id (virtual_monitor_native) == id) + return virtual_monitor_native; + } + + return NULL; +} + +static uint64_t +allocate_virtual_monitor_id (MetaMonitorManagerNative *manager_native) +{ + uint64_t id; + + id = 0; + + while (TRUE) + { + if (!find_virtual_monitor (manager_native, id)) + return id; + + id++; + } +} + +static MetaVirtualMonitor * +meta_monitor_manager_native_create_virtual_monitor (MetaMonitorManager *manager, + const MetaVirtualMonitorInfo *info, + GError **error) +{ + MetaMonitorManagerNative *manager_native = + META_MONITOR_MANAGER_NATIVE (manager); + MetaVirtualMonitorNative *virtual_monitor_native; + uint64_t id; + + id = allocate_virtual_monitor_id (manager_native); + virtual_monitor_native = meta_virtual_monitor_native_new (id, info); + return META_VIRTUAL_MONITOR (virtual_monitor_native); +} + +static void +meta_monitor_manager_native_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MetaMonitorManagerNative *manager_native = + META_MONITOR_MANAGER_NATIVE (object); + + switch (prop_id) + { + case PROP_NEED_OUTPUTS: + manager_native->needs_outputs = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static void -meta_monitor_manager_kms_dispose (GObject *object) +meta_monitor_manager_native_dispose (GObject *object) { - MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (object); + MetaMonitorManagerNative *manager_native = + META_MONITOR_MANAGER_NATIVE (object); - g_clear_pointer (&manager_kms->crtc_gamma_cache, + g_clear_pointer (&manager_native->crtc_gamma_cache, g_hash_table_unref); - G_OBJECT_CLASS (meta_monitor_manager_kms_parent_class)->dispose (object); + G_OBJECT_CLASS (meta_monitor_manager_native_parent_class)->dispose (object); } static gboolean -meta_monitor_manager_kms_initable_init (GInitable *initable, - GCancellable *cancellable, - GError **error) +meta_monitor_manager_native_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) { - MetaMonitorManagerKms *manager_kms = META_MONITOR_MANAGER_KMS (initable); - MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_kms); + MetaMonitorManagerNative *manager_native = + META_MONITOR_MANAGER_NATIVE (initable); + MetaMonitorManager *manager = META_MONITOR_MANAGER (manager_native); MetaBackend *backend = meta_monitor_manager_get_backend (manager); gboolean can_have_outputs; GList *l; - meta_monitor_manager_kms_connect_hotplug_handler (manager_kms); + meta_monitor_manager_native_connect_hotplug_handler (manager_native); can_have_outputs = FALSE; for (l = meta_backend_get_gpus (backend); l; l = l->next) @@ -622,14 +728,15 @@ meta_monitor_manager_kms_initable_init (GInitable *initable, break; } } - if (!can_have_outputs) + + if (manager_native->needs_outputs && !can_have_outputs) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "No GPUs with outputs found"); return FALSE; } - manager_kms->crtc_gamma_cache = + manager_native->crtc_gamma_cache = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) meta_kms_crtc_gamma_free); @@ -640,33 +747,60 @@ meta_monitor_manager_kms_initable_init (GInitable *initable, static void initable_iface_init (GInitableIface *initable_iface) { - initable_iface->init = meta_monitor_manager_kms_initable_init; + initable_iface->init = meta_monitor_manager_native_initable_init; } static void -meta_monitor_manager_kms_init (MetaMonitorManagerKms *manager_kms) +meta_monitor_manager_native_init (MetaMonitorManagerNative *manager_native) { + manager_native->needs_outputs = TRUE; } static void -meta_monitor_manager_kms_class_init (MetaMonitorManagerKmsClass *klass) +meta_monitor_manager_native_class_init (MetaMonitorManagerNativeClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_CLASS (klass); - object_class->dispose = meta_monitor_manager_kms_dispose; - - manager_class->read_edid = meta_monitor_manager_kms_read_edid; - manager_class->read_current_state = meta_monitor_manager_kms_read_current_state; - manager_class->ensure_initial_config = meta_monitor_manager_kms_ensure_initial_config; - manager_class->apply_monitors_config = meta_monitor_manager_kms_apply_monitors_config; - manager_class->set_power_save_mode = meta_monitor_manager_kms_set_power_save_mode; - manager_class->get_crtc_gamma = meta_monitor_manager_kms_get_crtc_gamma; - manager_class->set_crtc_gamma = meta_monitor_manager_kms_set_crtc_gamma; - manager_class->is_transform_handled = meta_monitor_manager_kms_is_transform_handled; - manager_class->calculate_monitor_mode_scale = meta_monitor_manager_kms_calculate_monitor_mode_scale; - manager_class->calculate_supported_scales = meta_monitor_manager_kms_calculate_supported_scales; - manager_class->get_capabilities = meta_monitor_manager_kms_get_capabilities; - manager_class->get_max_screen_size = meta_monitor_manager_kms_get_max_screen_size; - manager_class->get_default_layout_mode = meta_monitor_manager_kms_get_default_layout_mode; + object_class->set_property = meta_monitor_manager_native_set_property; + object_class->dispose = meta_monitor_manager_native_dispose; + + manager_class->read_edid = + meta_monitor_manager_native_read_edid; + manager_class->read_current_state = + meta_monitor_manager_native_read_current_state; + manager_class->ensure_initial_config = + meta_monitor_manager_native_ensure_initial_config; + manager_class->apply_monitors_config = + meta_monitor_manager_native_apply_monitors_config; + manager_class->set_power_save_mode = + meta_monitor_manager_native_set_power_save_mode; + manager_class->get_crtc_gamma = + meta_monitor_manager_native_get_crtc_gamma; + manager_class->set_crtc_gamma = + meta_monitor_manager_native_set_crtc_gamma; + manager_class->is_transform_handled = + meta_monitor_manager_native_is_transform_handled; + manager_class->calculate_monitor_mode_scale = + meta_monitor_manager_native_calculate_monitor_mode_scale; + manager_class->calculate_supported_scales = + meta_monitor_manager_native_calculate_supported_scales; + manager_class->get_capabilities = + meta_monitor_manager_native_get_capabilities; + manager_class->get_max_screen_size = + meta_monitor_manager_native_get_max_screen_size; + manager_class->get_default_layout_mode = + meta_monitor_manager_native_get_default_layout_mode; + manager_class->create_virtual_monitor = + meta_monitor_manager_native_create_virtual_monitor; + + obj_props[PROP_NEED_OUTPUTS] = + g_param_spec_boolean ("needs-outputs", + "needs-outputs", + "Whether any outputs are needed for operation", + TRUE, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, N_PROPS, obj_props); } diff --git a/src/backends/native/meta-monitor-manager-kms.h b/src/backends/native/meta-monitor-manager-native.h similarity index 66% rename from src/backends/native/meta-monitor-manager-kms.h rename to src/backends/native/meta-monitor-manager-native.h index 3222d5a47f9a48e430369bc32e5e15e7f027086e..60f899734ad4c2a36f5ac80f541f2bd7a0995692 100644 --- a/src/backends/native/meta-monitor-manager-kms.h +++ b/src/backends/native/meta-monitor-manager-native.h @@ -20,8 +20,8 @@ * along with this program; if not, see . */ -#ifndef META_MONITOR_MANAGER_KMS_H -#define META_MONITOR_MANAGER_KMS_H +#ifndef META_MONITOR_MANAGER_NATIVE_H +#define META_MONITOR_MANAGER_NATIVE_H #include #include @@ -32,18 +32,18 @@ typedef struct _MetaGpuKms MetaGpuKms; -#define META_TYPE_MONITOR_MANAGER_KMS (meta_monitor_manager_kms_get_type ()) -G_DECLARE_FINAL_TYPE (MetaMonitorManagerKms, meta_monitor_manager_kms, - META, MONITOR_MANAGER_KMS, +#define META_TYPE_MONITOR_MANAGER_NATIVE (meta_monitor_manager_native_get_type ()) +G_DECLARE_FINAL_TYPE (MetaMonitorManagerNative, meta_monitor_manager_native, + META, MONITOR_MANAGER_NATIVE, MetaMonitorManager) -void meta_monitor_manager_kms_pause (MetaMonitorManagerKms *manager_kms); +void meta_monitor_manager_native_pause (MetaMonitorManagerNative *manager_native); -void meta_monitor_manager_kms_resume (MetaMonitorManagerKms *manager_kms); +void meta_monitor_manager_native_resume (MetaMonitorManagerNative *manager_native); uint64_t meta_power_save_to_dpms_state (MetaPowerSave power_save); -MetaKmsCrtcGamma * meta_monitor_manager_kms_get_cached_crtc_gamma (MetaMonitorManagerKms *manager_kms, - MetaCrtcKms *crtc_kms); +MetaKmsCrtcGamma * meta_monitor_manager_native_get_cached_crtc_gamma (MetaMonitorManagerNative *manager_native, + MetaCrtcKms *crtc_kms); -#endif /* META_MONITOR_MANAGER_KMS_H */ +#endif /* META_MONITOR_MANAGER_NATIVE_H */ diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c index 4290eeeca859484d8ae731e333811a29aa37728d..7c0fb51333cf43a20a2d5dfd9592a22b87c650a2 100644 --- a/src/backends/native/meta-onscreen-native.c +++ b/src/backends/native/meta-onscreen-native.c @@ -240,6 +240,9 @@ notify_view_crtc_presented (MetaRendererView *view, case META_RENDERER_NATIVE_MODE_GBM: meta_onscreen_native_swap_drm_fb (onscreen); break; + case META_RENDERER_NATIVE_MODE_SURFACELESS: + g_assert_not_reached (); + break; #ifdef HAVE_EGL_DEVICE case META_RENDERER_NATIVE_MODE_EGL_DEVICE: break; @@ -473,6 +476,9 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, meta_crtc_kms_assign_primary_plane (crtc_kms, buffer, kms_update); + break; + case META_RENDERER_NATIVE_MODE_SURFACELESS: + g_assert_not_reached (); break; #ifdef HAVE_EGL_DEVICE case META_RENDERER_NATIVE_MODE_EGL_DEVICE: @@ -511,6 +517,9 @@ meta_onscreen_native_set_crtc_mode (CoglOnscreen *onscreen, { case META_RENDERER_NATIVE_MODE_GBM: break; + case META_RENDERER_NATIVE_MODE_SURFACELESS: + g_assert_not_reached (); + break; #ifdef HAVE_EGL_DEVICE case META_RENDERER_NATIVE_MODE_EGL_DEVICE: { @@ -1050,6 +1059,9 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, onscreen_native->gbm.next_fb = META_DRM_BUFFER (buffer_gbm); + break; + case META_RENDERER_NATIVE_MODE_SURFACELESS: + g_assert_not_reached (); break; #ifdef HAVE_EGL_DEVICE case META_RENDERER_NATIVE_MODE_EGL_DEVICE: @@ -1117,6 +1129,9 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, return; } break; + case META_RENDERER_NATIVE_MODE_SURFACELESS: + g_assert_not_reached (); + break; #ifdef HAVE_EGL_DEVICE case META_RENDERER_NATIVE_MODE_EGL_DEVICE: if (meta_renderer_native_has_pending_mode_set (renderer_native)) @@ -1736,6 +1751,9 @@ meta_onscreen_native_allocate (CoglFramebuffer *framebuffer, onscreen_native->gbm.surface = gbm_surface; cogl_onscreen_egl_set_egl_surface (onscreen_egl, egl_surface); break; + case META_RENDERER_NATIVE_MODE_SURFACELESS: + g_assert_not_reached (); + break; #ifdef HAVE_EGL_DEVICE case META_RENDERER_NATIVE_MODE_EGL_DEVICE: render_kms_device = @@ -2091,6 +2109,9 @@ meta_onscreen_native_dispose (GObject *object) g_clear_pointer (&onscreen_native->gbm.surface, gbm_surface_destroy); break; + case META_RENDERER_NATIVE_MODE_SURFACELESS: + g_assert_not_reached (); + break; #ifdef HAVE_EGL_DEVICE case META_RENDERER_NATIVE_MODE_EGL_DEVICE: g_clear_object (&onscreen_native->egl.dumb_fb); diff --git a/src/backends/native/meta-output-kms.c b/src/backends/native/meta-output-kms.c index d9055bb3ffe5e01c6f4a9a54606ec5b25cddc623..024344a3cc38f2370b1708170665d251120d3e71 100644 --- a/src/backends/native/meta-output-kms.c +++ b/src/backends/native/meta-output-kms.c @@ -41,12 +41,12 @@ struct _MetaOutputKms { - MetaOutput parent; + MetaOutputNative parent; MetaKmsConnector *kms_connector; }; -G_DEFINE_TYPE (MetaOutputKms, meta_output_kms, META_TYPE_OUTPUT) +G_DEFINE_TYPE (MetaOutputKms, meta_output_kms, META_TYPE_OUTPUT_NATIVE) MetaKmsConnector * meta_output_kms_get_kms_connector (MetaOutputKms *output_kms) @@ -110,9 +110,10 @@ meta_output_kms_can_clone (MetaOutputKms *output_kms, other_output_kms->kms_connector); } -GBytes * -meta_output_kms_read_edid (MetaOutputKms *output_kms) +static GBytes * +meta_output_kms_read_edid (MetaOutputNative *output_native) { + MetaOutputKms *output_kms = META_OUTPUT_KMS (output_native); const MetaKmsConnectorState *connector_state; GBytes *edid_data; @@ -266,6 +267,14 @@ init_output_modes (MetaOutputInfo *output_info, return TRUE; } +static MetaConnectorType +meta_kms_connector_type_from_drm (uint32_t drm_connector_type) +{ + g_warn_if_fail (drm_connector_type < META_CONNECTOR_TYPE_META); + + return (MetaConnectorType) drm_connector_type; +} + MetaOutputKms * meta_output_kms_new (MetaGpuKms *gpu_kms, MetaKmsConnector *kms_connector, @@ -278,6 +287,7 @@ meta_output_kms_new (MetaGpuKms *gpu_kms, g_autoptr (MetaOutputInfo) output_info = NULL; MetaOutput *output; MetaOutputKms *output_kms; + uint32_t drm_connector_type; const MetaKmsConnectorState *connector_state; GArray *crtcs; GList *l; @@ -330,7 +340,9 @@ meta_output_kms_new (MetaGpuKms *gpu_kms, meta_output_info_parse_edid (output_info, connector_state->edid_data); - output_info->connector_type = meta_kms_connector_get_connector_type (kms_connector); + drm_connector_type = meta_kms_connector_get_connector_type (kms_connector); + output_info->connector_type = + meta_kms_connector_type_from_drm (drm_connector_type); output_info->tile_info = connector_state->tile_info; @@ -387,4 +399,7 @@ meta_output_kms_init (MetaOutputKms *output_kms) static void meta_output_kms_class_init (MetaOutputKmsClass *klass) { + MetaOutputNativeClass *output_native_class = META_OUTPUT_NATIVE_CLASS (klass); + + output_native_class->read_edid = meta_output_kms_read_edid; } diff --git a/src/backends/native/meta-output-kms.h b/src/backends/native/meta-output-kms.h index da7b0018548401386e925214f16c79aaf1947b96..52acc6032a02baeebc6caec21c5207c7dc9f416f 100644 --- a/src/backends/native/meta-output-kms.h +++ b/src/backends/native/meta-output-kms.h @@ -26,11 +26,12 @@ #include "backends/meta-output.h" #include "backends/native/meta-gpu-kms.h" #include "backends/native/meta-kms-types.h" +#include "backends/native/meta-output-native.h" #define META_TYPE_OUTPUT_KMS (meta_output_kms_get_type ()) G_DECLARE_FINAL_TYPE (MetaOutputKms, meta_output_kms, META, OUTPUT_KMS, - MetaOutput) + MetaOutputNative) void meta_output_kms_set_power_save_mode (MetaOutputKms *output_kms, uint64_t dpms_state, @@ -46,8 +47,6 @@ MetaKmsConnector * meta_output_kms_get_kms_connector (MetaOutputKms *output_kms) uint32_t meta_output_kms_get_connector_id (MetaOutputKms *output_kms); -GBytes * meta_output_kms_read_edid (MetaOutputKms *output_kms); - MetaOutputKms * meta_output_kms_new (MetaGpuKms *gpu_kms, MetaKmsConnector *kms_connector, MetaOutput *old_output, diff --git a/src/backends/native/meta-output-native.c b/src/backends/native/meta-output-native.c new file mode 100644 index 0000000000000000000000000000000000000000..f21b2ebc659ddb5831e8a6be1bc9585bbfd5ccd3 --- /dev/null +++ b/src/backends/native/meta-output-native.c @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2020 Red Hat + * + * 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/native/meta-output-native.h" + +G_DEFINE_ABSTRACT_TYPE (MetaOutputNative, meta_output_native, + META_TYPE_OUTPUT) + +GBytes * +meta_output_native_read_edid (MetaOutputNative *output_native) +{ + MetaOutputNativeClass *klass = META_OUTPUT_NATIVE_GET_CLASS (output_native); + + return klass->read_edid (output_native); +} + +static void +meta_output_native_init (MetaOutputNative *output_native) +{ +} + +static void +meta_output_native_class_init (MetaOutputNativeClass *klass) +{ +} diff --git a/src/backends/native/meta-output-native.h b/src/backends/native/meta-output-native.h new file mode 100644 index 0000000000000000000000000000000000000000..f0475ae3bd85ee408a7134099e47435aa7ac2905 --- /dev/null +++ b/src/backends/native/meta-output-native.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2020 Red Hat + * + * 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_OUTPUT_NATIVE_H +#define META_OUTPUT_NATIVE_H + +#include "backends/meta-output.h" + +#define META_TYPE_OUTPUT_NATIVE (meta_output_native_get_type ()) +G_DECLARE_DERIVABLE_TYPE (MetaOutputNative, meta_output_native, + META, OUTPUT_NATIVE, + MetaOutput) + +struct _MetaOutputNativeClass +{ + MetaOutputClass parent_class; + + GBytes * (* read_edid) (MetaOutputNative *output_native); +}; + +GBytes * meta_output_native_read_edid (MetaOutputNative *output_native); + +#endif /* META_OUTPUT_NATIVE_H */ diff --git a/src/backends/native/meta-output-virtual.c b/src/backends/native/meta-output-virtual.c new file mode 100644 index 0000000000000000000000000000000000000000..12efb333881f2bbb88257bb89b04b55c4d41a851 --- /dev/null +++ b/src/backends/native/meta-output-virtual.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2021 Red Hat + * + * 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/native/meta-output-virtual.h" + +#include "backends/native/meta-crtc-mode-virtual.h" +#include "backends/native/meta-crtc-virtual.h" +#include "backends/meta-virtual-monitor.h" + +struct _MetaOutputVirtual +{ + MetaOutputNative parent; +}; + +#define META_OUTPUT_VIRTUAL_ID_BIT (((uint64_t) 1) << 63) + +G_DEFINE_TYPE (MetaOutputVirtual, meta_output_virtual, META_TYPE_OUTPUT_NATIVE) + +MetaOutputVirtual * +meta_output_virtual_new (uint64_t id, + const MetaVirtualMonitorInfo *info, + MetaCrtcVirtual *crtc_virtual, + MetaCrtcModeVirtual *crtc_mode_virtual) +{ + g_autoptr (MetaOutputInfo) output_info = NULL; + + output_info = meta_output_info_new (); + output_info->name = g_strdup_printf ("Meta-%" G_GUINT64_FORMAT, id); + + output_info->n_possible_crtcs = 1; + output_info->possible_crtcs = g_new0 (MetaCrtc *, 1); + output_info->possible_crtcs[0] = META_CRTC (crtc_virtual); + + output_info->hotplug_mode_update = FALSE; + output_info->suggested_x = -1; + output_info->suggested_y = -1; + + output_info->connector_type = META_CONNECTOR_TYPE_META; + output_info->vendor = g_strdup (info->vendor); + output_info->product = g_strdup (info->product); + output_info->serial = g_strdup (info->serial); + + output_info->n_modes = 1; + output_info->modes = g_new0 (MetaCrtcMode *, 1); + output_info->modes[0] = META_CRTC_MODE (crtc_mode_virtual); + output_info->preferred_mode = output_info->modes[0]; + + return g_object_new (META_TYPE_OUTPUT_VIRTUAL, + "id", META_OUTPUT_VIRTUAL_ID_BIT | id, + "info", output_info, + NULL); +} + +static void +meta_output_virtual_init (MetaOutputVirtual *output_virtual) +{ +} + +static void +meta_output_virtual_class_init (MetaOutputVirtualClass *klass) +{ +} diff --git a/src/backends/native/meta-output-virtual.h b/src/backends/native/meta-output-virtual.h new file mode 100644 index 0000000000000000000000000000000000000000..b04579f0decf1418a30dcaa228ad95fc1bcb3f02 --- /dev/null +++ b/src/backends/native/meta-output-virtual.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 Red Hat + * + * 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_OUTPUT_VIRTUAL_H +#define META_OUTPUT_VIRTUAL_H + +#include "backends/native/meta-backend-native-types.h" +#include "backends/native/meta-output-native.h" + +#define META_TYPE_OUTPUT_VIRTUAL (meta_output_virtual_get_type ()) +G_DECLARE_FINAL_TYPE (MetaOutputVirtual, meta_output_virtual, + META, OUTPUT_VIRTUAL, + MetaOutputNative) + +MetaOutputVirtual * meta_output_virtual_new (uint64_t id, + const MetaVirtualMonitorInfo *info, + MetaCrtcVirtual *crtc_virtual, + MetaCrtcModeVirtual *crtc_mode_virtual); + +#endif /* META_OUTPUT_VIRTUAL_H */ diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index 0839904b46361860b9a98cc23c91d356d7904ef6..f48db9ab8bbf741f04cd65b0f136f7989ab6e7e6 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -50,6 +50,7 @@ #include "backends/meta-logical-monitor.h" #include "backends/native/meta-cogl-utils.h" #include "backends/native/meta-crtc-kms.h" +#include "backends/native/meta-crtc-virtual.h" #include "backends/native/meta-kms-device.h" #include "backends/native/meta-kms.h" #include "backends/native/meta-onscreen-native.h" @@ -205,13 +206,14 @@ meta_renderer_native_connect (CoglRenderer *cogl_renderer, GError **error) { CoglRendererEGL *cogl_renderer_egl; - MetaGpuKms *gpu_kms = cogl_renderer->custom_winsys_user_data; - MetaRendererNative *renderer_native = meta_renderer_native_from_gpu (gpu_kms); + MetaRendererNative *renderer_native = cogl_renderer->custom_winsys_user_data; + MetaGpuKms *gpu_kms; MetaRendererNativeGpuData *renderer_gpu_data; cogl_renderer->winsys = g_new0 (CoglRendererEGL, 1); cogl_renderer_egl = cogl_renderer->winsys; + gpu_kms = meta_renderer_native_get_primary_gpu (renderer_native); renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native, gpu_kms); @@ -245,6 +247,10 @@ meta_renderer_native_add_egl_config_attributes (CoglDisplay *cog attributes[i++] = EGL_SURFACE_TYPE; attributes[i++] = EGL_WINDOW_BIT; break; + case META_RENDERER_NATIVE_MODE_SURFACELESS: + attributes[i++] = EGL_SURFACE_TYPE; + attributes[i++] = EGL_PBUFFER_BIT; + break; #ifdef HAVE_EGL_DEVICE case META_RENDERER_NATIVE_MODE_EGL_DEVICE: attributes[i++] = EGL_SURFACE_TYPE; @@ -325,6 +331,9 @@ meta_renderer_native_choose_egl_config (CoglDisplay *cogl_display, GBM_FORMAT_XRGB8888, out_config, error); + case META_RENDERER_NATIVE_MODE_SURFACELESS: + *out_config = EGL_NO_CONFIG_KHR; + return TRUE; #ifdef HAVE_EGL_DEVICE case META_RENDERER_NATIVE_MODE_EGL_DEVICE: return meta_egl_choose_first_config (egl, @@ -777,10 +786,11 @@ meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer, return dmabuf_handle; } break; + case META_RENDERER_NATIVE_MODE_SURFACELESS: #ifdef HAVE_EGL_DEVICE case META_RENDERER_NATIVE_MODE_EGL_DEVICE: - break; #endif + break; } g_set_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, @@ -932,26 +942,17 @@ get_native_cogl_winsys_vtable (CoglRenderer *cogl_renderer) } static CoglRenderer * -create_cogl_renderer_for_gpu (MetaGpuKms *gpu_kms) +meta_renderer_native_create_cogl_renderer (MetaRenderer *renderer) { CoglRenderer *cogl_renderer; cogl_renderer = cogl_renderer_new (); cogl_renderer_set_custom_winsys (cogl_renderer, get_native_cogl_winsys_vtable, - gpu_kms); - + renderer); return cogl_renderer; } -static CoglRenderer * -meta_renderer_native_create_cogl_renderer (MetaRenderer *renderer) -{ - MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer); - - return create_cogl_renderer_for_gpu (renderer_native->primary_gpu_kms); -} - static MetaMonitorTransform calculate_view_transform (MetaMonitorManager *monitor_manager, MetaLogicalMonitor *logical_monitor, @@ -1021,13 +1022,11 @@ meta_renderer_native_create_view (MetaRenderer *renderer, CoglContext *cogl_context = cogl_context_from_renderer_native (renderer_native); CoglDisplay *cogl_display = cogl_context_get_display (cogl_context); - CoglDisplayEGL *cogl_display_egl; - CoglOnscreenEgl *onscreen_egl; const MetaCrtcConfig *crtc_config; const MetaCrtcModeInfo *crtc_mode_info; MetaMonitorTransform view_transform; - MetaOnscreenNative *onscreen_native; - CoglOffscreen *offscreen = NULL; + g_autoptr (CoglFramebuffer) framebuffer = NULL; + g_autoptr (CoglOffscreen) offscreen = NULL; gboolean use_shadowfb; float scale; int onscreen_width; @@ -1042,16 +1041,41 @@ meta_renderer_native_create_view (MetaRenderer *renderer, onscreen_width = crtc_mode_info->width; onscreen_height = crtc_mode_info->height; - onscreen_native = meta_onscreen_native_new (renderer_native, - renderer_native->primary_gpu_kms, - output, - crtc, - cogl_context, - onscreen_width, - onscreen_height); + if (META_IS_CRTC_KMS (crtc)) + { + MetaOnscreenNative *onscreen_native; + + onscreen_native = meta_onscreen_native_new (renderer_native, + renderer_native->primary_gpu_kms, + output, + crtc, + cogl_context, + onscreen_width, + onscreen_height); + + if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (onscreen_native), &error)) + g_error ("Failed to allocate onscreen framebuffer: %s", error->message); + + use_shadowfb = should_force_shadow_fb (renderer_native, + renderer_native->primary_gpu_kms); + framebuffer = COGL_FRAMEBUFFER (onscreen_native); + } + else + { + CoglOffscreen *virtual_onscreen; - if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (onscreen_native), &error)) - g_error ("Failed to allocate onscreen framebuffer: %s", error->message); + g_assert (META_IS_CRTC_VIRTUAL (crtc)); + + virtual_onscreen = meta_renderer_native_create_offscreen (renderer_native, + cogl_context, + onscreen_width, + onscreen_height, + &error); + if (!virtual_onscreen) + g_error ("Failed to allocate back buffer texture: %s", error->message); + use_shadowfb = FALSE; + framebuffer = COGL_FRAMEBUFFER (virtual_onscreen); + } view_transform = calculate_view_transform (monitor_manager, logical_monitor, @@ -1082,9 +1106,6 @@ meta_renderer_native_create_view (MetaRenderer *renderer, g_error ("Failed to allocate back buffer texture: %s", error->message); } - use_shadowfb = should_force_shadow_fb (renderer_native, - renderer_native->primary_gpu_kms); - if (meta_is_stage_views_scaled ()) scale = meta_logical_monitor_get_scale (logical_monitor); else @@ -1099,25 +1120,29 @@ meta_renderer_native_create_view (MetaRenderer *renderer, "layout", &view_layout, "crtc", crtc, "scale", scale, - "framebuffer", onscreen_native, + "framebuffer", framebuffer, "offscreen", offscreen, "use-shadowfb", use_shadowfb, "transform", view_transform, "refresh-rate", crtc_mode_info->refresh_rate, NULL); - g_clear_object (&offscreen); - g_object_unref (onscreen_native); - meta_onscreen_native_set_view (COGL_ONSCREEN (onscreen_native), view); - - /* Ensure we don't point to stale surfaces when creating the offscreen */ - cogl_display_egl = cogl_display->winsys; - onscreen_egl = COGL_ONSCREEN_EGL (onscreen_native); - egl_surface = cogl_onscreen_egl_get_egl_surface (onscreen_egl); - _cogl_winsys_egl_make_current (cogl_display, - egl_surface, - egl_surface, - cogl_display_egl->egl_context); + if (META_IS_ONSCREEN_NATIVE (framebuffer)) + { + CoglDisplayEGL *cogl_display_egl; + CoglOnscreenEgl *onscreen_egl; + + meta_onscreen_native_set_view (COGL_ONSCREEN (framebuffer), view); + + /* Ensure we don't point to stale surfaces when creating the offscreen */ + cogl_display_egl = cogl_display->winsys; + onscreen_egl = COGL_ONSCREEN_EGL (framebuffer); + egl_surface = cogl_onscreen_egl_get_egl_surface (onscreen_egl); + _cogl_winsys_egl_make_current (cogl_display, + egl_surface, + egl_surface, + cogl_display_egl->egl_context); + } return view; } @@ -1165,9 +1190,16 @@ meta_renderer_native_prepare_frame (MetaRendererNative *renderer_native, ClutterFrame *frame) { MetaCrtc *crtc = meta_renderer_view_get_crtc (view); - MetaCrtcKms *crtc_kms = META_CRTC_KMS (crtc); - MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc)); - MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc);; + MetaCrtcKms *crtc_kms; + MetaKmsCrtc *kms_crtc; + MetaKmsDevice *kms_device; + + if (!META_IS_CRTC_KMS (crtc)) + return; + + crtc_kms = META_CRTC_KMS (crtc); + kms_crtc = meta_crtc_kms_get_kms_crtc (META_CRTC_KMS (crtc)); + kms_device = meta_kms_crtc_get_device (kms_crtc); meta_crtc_kms_maybe_set_gamma (crtc_kms, kms_device); } @@ -1181,9 +1213,13 @@ meta_renderer_native_finish_frame (MetaRendererNative *renderer_native, { CoglFramebuffer *framebuffer = clutter_stage_view_get_onscreen (CLUTTER_STAGE_VIEW (view)); - CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer); - meta_onscreen_native_finish_frame (onscreen, frame); + if (COGL_IS_ONSCREEN (framebuffer)) + { + CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer); + + meta_onscreen_native_finish_frame (onscreen, frame); + } } } @@ -1208,6 +1244,7 @@ create_secondary_egl_config (MetaEgl *egl, switch (mode) { case META_RENDERER_NATIVE_MODE_GBM: + case META_RENDERER_NATIVE_MODE_SURFACELESS: return choose_egl_config_from_gbm_format (egl, egl_display, attributes, @@ -1361,7 +1398,7 @@ init_secondary_gpu_data (MetaRendererNativeGpuData *renderer_gpu_data) if (init_secondary_gpu_data_gpu (renderer_gpu_data, &error)) return; - g_warning ("Failed to initialize accelerated iGPU/dGPU framebuffer sharing: %s", + g_message ("Failed to initialize accelerated iGPU/dGPU framebuffer sharing: %s", error->message); g_error_free (error); @@ -1454,6 +1491,65 @@ create_renderer_gpu_data_gbm (MetaRendererNative *renderer_native, return renderer_gpu_data; } +static EGLDisplay +init_surfaceless_egl_display (MetaRendererNative *renderer_native, + GError **error) +{ + MetaEgl *egl = meta_renderer_native_get_egl (renderer_native); + EGLDisplay egl_display; + + if (!meta_egl_has_extensions (egl, EGL_NO_DISPLAY, NULL, + "EGL_MESA_platform_surfaceless", + NULL)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Missing EGL platform required for surfaceless context: " + "EGL_MESA_platform_surfaceless"); + return EGL_NO_DISPLAY; + } + + egl_display = meta_egl_get_platform_display (egl, + EGL_PLATFORM_SURFACELESS_MESA, + EGL_DEFAULT_DISPLAY, + NULL, error); + if (egl_display == EGL_NO_DISPLAY) + return EGL_NO_DISPLAY; + + if (!meta_egl_initialize (egl, egl_display, error)) + return EGL_NO_DISPLAY; + + if (!meta_egl_has_extensions (egl, egl_display, NULL, + "EGL_KHR_no_config_context", + NULL)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Missing EGL extension required for surfaceless context: " + "EGL_KHR_no_config_context"); + return EGL_NO_DISPLAY; + } + + return egl_display; +} + +static MetaRendererNativeGpuData * +create_renderer_gpu_data_surfaceless (MetaRendererNative *renderer_native, + GError **error) +{ + MetaRendererNativeGpuData *renderer_gpu_data; + EGLDisplay egl_display; + + egl_display = init_surfaceless_egl_display (renderer_native, error); + if (egl_display == EGL_NO_DISPLAY) + return NULL; + + renderer_gpu_data = meta_create_renderer_native_gpu_data (NULL); + renderer_gpu_data->renderer_native = renderer_native; + renderer_gpu_data->mode = META_RENDERER_NATIVE_MODE_SURFACELESS; + renderer_gpu_data->egl_display = egl_display; + + return renderer_gpu_data; +} + #ifdef HAVE_EGL_DEVICE static const char * get_drm_device_file (MetaEgl *egl, @@ -1656,6 +1752,9 @@ meta_renderer_native_create_renderer_gpu_data (MetaRendererNative *renderer_nat GError *egl_device_error = NULL; #endif + if (!gpu_kms) + return create_renderer_gpu_data_surfaceless (renderer_native, error); + #ifdef HAVE_EGL_DEVICE /* Try to initialize the EGLDevice backend first. Whenever we use a * non-NVIDIA GPU, the EGLDevice enumeration function won't find a match, and @@ -1883,22 +1982,30 @@ meta_renderer_native_initable_init (GInitable *initable, GList *l; gpus = meta_backend_get_gpus (backend); - for (l = gpus; l; l = l->next) + if (gpus) { - MetaGpuKms *gpu_kms = META_GPU_KMS (l->data); + for (l = gpus; l; l = l->next) + { + MetaGpuKms *gpu_kms = META_GPU_KMS (l->data); - if (!create_renderer_gpu_data (renderer_native, gpu_kms, error)) - return FALSE; - } + if (!create_renderer_gpu_data (renderer_native, gpu_kms, error)) + return FALSE; + } - renderer_native->primary_gpu_kms = choose_primary_gpu (backend, - renderer_native, - error); - if (!renderer_native->primary_gpu_kms) - return FALSE; + renderer_native->primary_gpu_kms = choose_primary_gpu (backend, + renderer_native, + error); + if (!renderer_native->primary_gpu_kms) + return FALSE; - if (meta_gpu_kms_requires_modifiers (renderer_native->primary_gpu_kms)) - renderer_native->use_modifiers = TRUE; + if (meta_gpu_kms_requires_modifiers (renderer_native->primary_gpu_kms)) + renderer_native->use_modifiers = TRUE; + } + else + { + if (!create_renderer_gpu_data (renderer_native, NULL, error)) + return FALSE; + } return TRUE; } diff --git a/src/backends/native/meta-renderer-native.h b/src/backends/native/meta-renderer-native.h index 661736e7cbdeb137010049616e0f1007a3e0fec6..9475e1857ff1cb595feb9404c0bc3312f5e1aee8 100644 --- a/src/backends/native/meta-renderer-native.h +++ b/src/backends/native/meta-renderer-native.h @@ -31,7 +31,7 @@ #include "backends/meta-renderer.h" #include "backends/native/meta-gpu-kms.h" -#include "backends/native/meta-monitor-manager-kms.h" +#include "backends/native/meta-monitor-manager-native.h" #define META_TYPE_RENDERER_NATIVE (meta_renderer_native_get_type ()) G_DECLARE_FINAL_TYPE (MetaRendererNative, meta_renderer_native, @@ -41,6 +41,7 @@ G_DECLARE_FINAL_TYPE (MetaRendererNative, meta_renderer_native, typedef enum _MetaRendererNativeMode { META_RENDERER_NATIVE_MODE_GBM, + META_RENDERER_NATIVE_MODE_SURFACELESS, #ifdef HAVE_EGL_DEVICE META_RENDERER_NATIVE_MODE_EGL_DEVICE #endif diff --git a/src/backends/native/meta-seat-impl.c b/src/backends/native/meta-seat-impl.c index 71da8f8fac3df60d514f2a4a248b0b2452a42ac6..a67698ce15f0c726c0727154a0877aeff02a6fdf 100644 --- a/src/backends/native/meta-seat-impl.c +++ b/src/backends/native/meta-seat-impl.c @@ -40,6 +40,8 @@ #include "clutter/clutter-mutter.h" #include "core/bell.h" +#include "meta-private-enum-types.h" + /* * Clutter makes the assumption that two core devices have ID's 2 and 3 (core * pointer and core keyboard). @@ -96,6 +98,7 @@ enum PROP_0, PROP_SEAT, PROP_SEAT_ID, + PROP_FLAGS, N_PROPS, }; @@ -259,9 +262,12 @@ keyboard_repeat (gpointer data) /* There might be events queued in libinput that could cancel the repeat timer. */ - dispatch_libinput (seat_impl); - if (!seat_impl->repeat_source) - return G_SOURCE_REMOVE; + if (seat_impl->libinput) + { + dispatch_libinput (seat_impl); + if (!seat_impl->repeat_source) + return G_SOURCE_REMOVE; + } g_return_val_if_fail (seat_impl->repeat_device != NULL, G_SOURCE_REMOVE); @@ -2654,50 +2660,71 @@ meta_seat_impl_set_keyboard_numlock_in_impl (MetaSeatImpl *seat_impl, seat_impl->xkb); } -static gpointer -input_thread (MetaSeatImpl *seat_impl) +static gboolean +init_libinput (MetaSeatImpl *seat_impl, + GError **error) { MetaEventSource *source; struct udev *udev; - struct xkb_keymap *xkb_keymap; - - g_main_context_push_thread_default (seat_impl->input_context); + struct libinput *libinput; udev = udev_new (); if (G_UNLIKELY (udev == NULL)) { g_warning ("Failed to create udev object"); seat_impl->input_thread_initialized = TRUE; - return NULL; + return FALSE; } - seat_impl->libinput = libinput_udev_create_context (&libinput_interface, - seat_impl, udev); - if (seat_impl->libinput == NULL) + libinput = libinput_udev_create_context (&libinput_interface, + seat_impl, udev); + udev_unref (udev); + + if (libinput == NULL) { - g_critical ("Failed to create the libinput object."); - seat_impl->input_thread_initialized = TRUE; - return NULL; + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Failed to create the libinput object."); + return FALSE; } - if (libinput_udev_assign_seat (seat_impl->libinput, seat_impl->seat_id) == -1) + if (libinput_udev_assign_seat (libinput, seat_impl->seat_id) == -1) { - g_critical ("Failed to assign a seat to the libinput object."); + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Failed to assign a seat to the libinput object."); libinput_unref (seat_impl->libinput); - seat_impl->libinput = NULL; - seat_impl->input_thread_initialized = TRUE; - return NULL; + return FALSE; } - udev_unref (udev); + seat_impl->libinput = libinput; + source = meta_event_source_new (seat_impl); + seat_impl->event_source = source; + + return TRUE; +} + +static gpointer +input_thread (MetaSeatImpl *seat_impl) +{ + struct xkb_keymap *xkb_keymap; + + g_main_context_push_thread_default (seat_impl->input_context); + + if (!(seat_impl->flags & META_SEAT_NATIVE_FLAG_NO_LIBINPUT)) + { + g_autoptr (GError) error = NULL; + + if (!init_libinput (seat_impl, &error)) + { + g_critical ("Failed to initialize seat: %s", error->message); + seat_impl->input_thread_initialized = TRUE; + return NULL; + } + } seat_impl->input_settings = meta_input_settings_native_new_in_impl (seat_impl); g_signal_connect_object (seat_impl->input_settings, "kbd-a11y-changed", G_CALLBACK (kbd_a11y_changed_cb), seat_impl, 0); - source = meta_event_source_new (seat_impl); - seat_impl->event_source = source; - seat_impl->keymap = g_object_new (META_TYPE_KEYMAP_NATIVE, NULL); xkb_keymap = meta_keymap_native_get_keyboard_map_in_impl (seat_impl->keymap); @@ -2804,6 +2831,9 @@ meta_seat_impl_set_property (GObject *object, case PROP_SEAT_ID: seat_impl->seat_id = g_value_dup_string (value); break; + case PROP_FLAGS: + seat_impl->flags = g_value_get_flags (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -3050,6 +3080,15 @@ meta_seat_impl_class_init (MetaSeatImplClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + props[PROP_FLAGS] = + g_param_spec_flags ("flags", + "Flags", + "Flags", + META_TYPE_SEAT_NATIVE_FLAG, + META_SEAT_NATIVE_FLAG_NONE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY); + signals[KBD_A11Y_FLAGS_CHANGED] = g_signal_new ("kbd-a11y-flags-changed", G_TYPE_FROM_CLASS (object_class), @@ -3462,13 +3501,15 @@ meta_seat_impl_set_viewports (MetaSeatImpl *seat_impl, } MetaSeatImpl * -meta_seat_impl_new (MetaSeatNative *seat_native, - const char *seat_id) +meta_seat_impl_new (MetaSeatNative *seat_native, + const char *seat_id, + MetaSeatNativeFlag flags) { return g_initable_new (META_TYPE_SEAT_IMPL, NULL, NULL, "seat", seat_native, "seat-id", seat_id, + "flags", flags, NULL); } diff --git a/src/backends/native/meta-seat-impl.h b/src/backends/native/meta-seat-impl.h index d49d1660f51dcdc749d1fd6f247b337cf2e914fc..eed122f6c508b35cd95372b7445de78998e50a66 100644 --- a/src/backends/native/meta-seat-impl.h +++ b/src/backends/native/meta-seat-impl.h @@ -67,6 +67,7 @@ struct _MetaSeatImpl MetaSeatNative *seat_native; char *seat_id; + MetaSeatNativeFlag flags; MetaEventSource *event_source; struct libinput *libinput; GRWLock state_lock; @@ -126,8 +127,9 @@ struct _MetaSeatImpl G_DECLARE_FINAL_TYPE (MetaSeatImpl, meta_seat_impl, META, SEAT_IMPL, GObject) -MetaSeatImpl * meta_seat_impl_new (MetaSeatNative *seat_native, - const char *seat_id); +MetaSeatImpl * meta_seat_impl_new (MetaSeatNative *seat_native, + const char *seat_id, + MetaSeatNativeFlag flags); void meta_seat_impl_destroy (MetaSeatImpl *seat_impl); diff --git a/src/backends/native/meta-seat-native.c b/src/backends/native/meta-seat-native.c index c0bfe222332252725d06dccc4938b9a900f32851..133bf58fe10c8508c06c26038be0663426483ebe 100644 --- a/src/backends/native/meta-seat-native.c +++ b/src/backends/native/meta-seat-native.c @@ -37,10 +37,13 @@ #include "clutter/clutter-mutter.h" #include "core/bell.h" +#include "meta-private-enum-types.h" + enum { PROP_0, PROP_SEAT_ID, + PROP_FLAGS, N_PROPS, /* This property is overridden */ @@ -153,7 +156,7 @@ meta_seat_native_constructed (GObject *object) { MetaSeatNative *seat = META_SEAT_NATIVE (object); - seat->impl = meta_seat_impl_new (seat, seat->seat_id); + seat->impl = meta_seat_impl_new (seat, seat->seat_id, seat->flags); g_signal_connect (seat->impl, "kbd-a11y-flags-changed", G_CALLBACK (proxy_kbd_a11y_flags_changed), seat); g_signal_connect (seat->impl, "kbd-a11y-mods-state-changed", @@ -187,6 +190,9 @@ meta_seat_native_set_property (GObject *object, case PROP_SEAT_ID: seat_native->seat_id = g_value_dup_string (value); break; + case PROP_FLAGS: + seat_native->flags = g_value_get_flags (value); + break; case PROP_TOUCH_MODE: default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -209,6 +215,9 @@ meta_seat_native_get_property (GObject *object, case PROP_TOUCH_MODE: g_value_set_boolean (value, seat_native->touch_mode); break; + case PROP_FLAGS: + g_value_set_flags (value, seat_native->flags); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -393,6 +402,15 @@ meta_seat_native_class_init (MetaSeatNativeClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + props[PROP_FLAGS] = + g_param_spec_flags ("flags", + "Flags", + "Flags", + META_TYPE_SEAT_NATIVE_FLAG, + META_SEAT_NATIVE_FLAG_NONE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_properties (object_class, N_PROPS, props); g_object_class_override_property (object_class, PROP_TOUCH_MODE, diff --git a/src/backends/native/meta-seat-native.h b/src/backends/native/meta-seat-native.h index 7f94828d0e069ddf59d5f1d70554c8fca4f3b297..dca2679863a93c5240cb671512b2b808e45d45e3 100644 --- a/src/backends/native/meta-seat-native.h +++ b/src/backends/native/meta-seat-native.h @@ -44,6 +44,7 @@ struct _MetaSeatNative MetaSeatImpl *impl; char *seat_id; + MetaSeatNativeFlag flags; GList *devices; struct xkb_keymap *xkb_keymap; diff --git a/src/backends/native/meta-stage-native.c b/src/backends/native/meta-stage-native.c index efc45c3eee40522c0e4b4171e7546d4154549216..b56acd9d4655e27bc06404df9bd41b6b95ed1a39 100644 --- a/src/backends/native/meta-stage-native.c +++ b/src/backends/native/meta-stage-native.c @@ -27,6 +27,7 @@ #include "backends/native/meta-stage-native.h" #include "backends/meta-backend-private.h" +#include "backends/native/meta-crtc-virtual.h" #include "backends/native/meta-cursor-renderer-native.h" #include "backends/native/meta-renderer-native.h" #include "meta/meta-backend.h" @@ -45,6 +46,8 @@ struct _MetaStageNative int64_t presented_frame_counter_complete; }; +static ClutterStageWindowInterface *clutter_stage_window_parent_iface = NULL; + static void clutter_stage_window_iface_init (ClutterStageWindowInterface *iface); @@ -126,6 +129,24 @@ meta_stage_native_prepare_frame (ClutterStageWindow *stage_window, META_RENDERER_VIEW (stage_view)); } +static void +meta_stage_native_redraw_view (ClutterStageWindow *stage_window, + ClutterStageView *view, + ClutterFrame *frame) +{ + MetaCrtc *crtc; + + clutter_stage_window_parent_iface->redraw_view (stage_window, view, frame); + + crtc = meta_renderer_view_get_crtc (META_RENDERER_VIEW (view)); + if (META_IS_CRTC_VIRTUAL (crtc)) + { + g_warn_if_fail (!clutter_frame_has_result (frame)); + + clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_PENDING_PRESENTED); + } +} + static void meta_stage_native_finish_frame (ClutterStageWindow *stage_window, ClutterStageView *stage_view, @@ -137,6 +158,9 @@ meta_stage_native_finish_frame (ClutterStageWindow *stage_window, meta_renderer_native_finish_frame (META_RENDERER_NATIVE (renderer), META_RENDERER_VIEW (stage_view), frame); + + if (!clutter_frame_has_result (frame)) + clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_IDLE); } static void @@ -156,9 +180,12 @@ meta_stage_native_class_init (MetaStageNativeClass *klass) static void clutter_stage_window_iface_init (ClutterStageWindowInterface *iface) { + clutter_stage_window_parent_iface = g_type_interface_peek_parent (iface); + iface->can_clip_redraws = meta_stage_native_can_clip_redraws; iface->get_geometry = meta_stage_native_get_geometry; iface->get_views = meta_stage_native_get_views; iface->prepare_frame = meta_stage_native_prepare_frame; + iface->redraw_view = meta_stage_native_redraw_view; iface->finish_frame = meta_stage_native_finish_frame; } diff --git a/src/backends/native/meta-udev.c b/src/backends/native/meta-udev.c index 649c9df27e5d475c4616f4016e6fa7dbdf8908b3..9a6bfe03ba4ba94d39fbacb342a5fa1468c0e48a 100644 --- a/src/backends/native/meta-udev.c +++ b/src/backends/native/meta-udev.c @@ -159,11 +159,7 @@ meta_udev_list_drm_devices (MetaUdev *udev, devices = g_udev_enumerator_execute (enumerator); if (!devices) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - "No drm devices found"); - return FALSE; - } + return NULL; for (l = devices; l;) { @@ -179,13 +175,6 @@ meta_udev_list_drm_devices (MetaUdev *udev, l = l_next; } - if (!devices) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No DRM devices found"); - return NULL; - } - return devices; } diff --git a/src/backends/native/meta-virtual-monitor-native.c b/src/backends/native/meta-virtual-monitor-native.c new file mode 100644 index 0000000000000000000000000000000000000000..3f81f4180e11e8430c6537888c3af23894ff5756 --- /dev/null +++ b/src/backends/native/meta-virtual-monitor-native.c @@ -0,0 +1,80 @@ +/* + * 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/native/meta-virtual-monitor-native.h" + +#include "backends/native/meta-crtc-mode-virtual.h" +#include "backends/native/meta-crtc-virtual.h" +#include "backends/native/meta-output-virtual.h" + +struct _MetaVirtualMonitorNative +{ + MetaVirtualMonitor parent; + + uint64_t id; +}; + +#define VIRTUAL_OUTPUT_ID_BIT (((uint64_t) 1) << 63) + +G_DEFINE_TYPE (MetaVirtualMonitorNative, meta_virtual_monitor_native, + META_TYPE_VIRTUAL_MONITOR) + +uint64_t +meta_virtual_monitor_native_get_id (MetaVirtualMonitorNative *virtual_monitor_native) +{ + return virtual_monitor_native->id; +} + +MetaVirtualMonitorNative * +meta_virtual_monitor_native_new (uint64_t id, + const MetaVirtualMonitorInfo *info) +{ + MetaVirtualMonitorNative *virtual_monitor_native; + MetaCrtcVirtual *crtc_virtual; + MetaCrtcModeVirtual *crtc_mode_virtual; + MetaOutputVirtual *output_virtual; + + crtc_virtual = meta_crtc_virtual_new (id); + crtc_mode_virtual = meta_crtc_mode_virtual_new (id, info); + output_virtual = meta_output_virtual_new (id, info, + crtc_virtual, + crtc_mode_virtual); + + virtual_monitor_native = g_object_new (META_TYPE_VIRTUAL_MONITOR_NATIVE, + "crtc", crtc_virtual, + "crtc-mode", crtc_mode_virtual, + "output", output_virtual, + NULL); + virtual_monitor_native->id = id; + + return virtual_monitor_native; +} + +static void +meta_virtual_monitor_native_init (MetaVirtualMonitorNative *virtual_monitor_native) +{ +} + +static void +meta_virtual_monitor_native_class_init (MetaVirtualMonitorNativeClass *klass) +{ +} diff --git a/src/backends/native/meta-virtual-monitor-native.h b/src/backends/native/meta-virtual-monitor-native.h new file mode 100644 index 0000000000000000000000000000000000000000..d1a0ced6401e4de383903f6791c1663af8cfe05b --- /dev/null +++ b/src/backends/native/meta-virtual-monitor-native.h @@ -0,0 +1,45 @@ +/* + * 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_VIRTUAL_MONITOR_NATIVE_H +#define META_VIRTUAL_MONITOR_NATIVE_H + +#include + +#include "backends/meta-virtual-monitor.h" +#include "backends/meta-backend-types.h" + +#define META_TYPE_VIRTUAL_MONITOR_NATIVE (meta_virtual_monitor_native_get_type ()) +G_DECLARE_FINAL_TYPE (MetaVirtualMonitorNative, meta_virtual_monitor_native, + META, VIRTUAL_MONITOR_NATIVE, + MetaVirtualMonitor) + +uint64_t meta_virtual_monitor_native_get_id (MetaVirtualMonitorNative *virtual_monitor_native); + +MetaCrtcMode * meta_virtual_monitor_native_get_crtc_mode (MetaVirtualMonitorNative *virtual_monitor_native); + +MetaCrtc * meta_virtual_monitor_native_get_crtc (MetaVirtualMonitorNative *virtual_monitor_native); + +MetaOutput * meta_virtual_monitor_native_get_output (MetaVirtualMonitorNative *virtual_monitor_native); + +MetaVirtualMonitorNative * meta_virtual_monitor_native_new (uint64_t id, + const MetaVirtualMonitorInfo *info); + +#endif /* META_VIRTUAL_MONITOR_NATIVE_H */ diff --git a/src/compositor/plugins/default.c b/src/compositor/plugins/default.c index 1c73174d2fcecbd2d9045a91be74695a04e063c9..c89c84121f5479df7d81a270748dfb2b4cfa2e6d 100644 --- a/src/compositor/plugins/default.c +++ b/src/compositor/plugins/default.c @@ -338,6 +338,9 @@ on_monitors_changed (MetaMonitorManager *monitor_manager, MetaRectangle rect; ClutterActor *background_actor; MetaBackground *background; + uint8_t red; + uint8_t green; + uint8_t blue; ClutterColor color; meta_display_get_monitor_geometry (display, i, &rect); @@ -353,11 +356,11 @@ on_monitors_changed (MetaMonitorManager *monitor_manager, parsing the driconf XML, but it's nice if the colors are reproducible. */ - clutter_color_init (&color, - g_rand_int_range (rand, 0, 255), - g_rand_int_range (rand, 0, 255), - g_rand_int_range (rand, 0, 255), - 255); + + blue = g_rand_int_range (rand, 0, 255); + green = g_rand_int_range (rand, 0, 255); + red = g_rand_int_range (rand, 0, 255); + clutter_color_init (&color, red, green, blue, 255); background = meta_background_new (display); meta_background_set_color (background, &color); diff --git a/src/core/main-private.h b/src/core/main-private.h index d6d28facb3f950b41a3a2ca4062493663362d01b..7e6d6eba7f606140b90502d696b2f2e6e922a972 100644 --- a/src/core/main-private.h +++ b/src/core/main-private.h @@ -47,7 +47,9 @@ typedef enum _MetaDisplayPolicy META_EXPORT_TEST void meta_override_compositor_configuration (MetaCompositorType compositor_type, - GType backend_gtype); + GType backend_gtype, + const char *first_property_name, + ...); META_EXPORT_TEST MetaDisplayPolicy meta_get_x11_display_policy (void); diff --git a/src/core/main.c b/src/core/main.c index 4bcfd7a5de11d84759de54069910802d102c0849..6b26990c6a80cc4bcf9ac014aef2c7e6860e59d7 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -75,6 +76,8 @@ #endif #include "backends/meta-backend-private.h" +#include "backends/meta-monitor-manager-private.h" +#include "backends/meta-virtual-monitor.h" #include "backends/x11/cm/meta-backend-x11-cm.h" #include "backends/x11/meta-backend-x11.h" #include "clutter/clutter.h" @@ -139,6 +142,10 @@ static GMainLoop *meta_main_loop = NULL; static void prefs_changed_callback (MetaPreference pref, gpointer data); +#ifdef HAVE_NATIVE_BACKEND +static void release_virtual_monitors (void); +#endif + /** * meta_print_compilation_info: * @@ -208,9 +215,17 @@ static char *opt_wayland_display; #endif #ifdef HAVE_NATIVE_BACKEND static gboolean opt_display_server; +static gboolean opt_headless; #endif static gboolean opt_x11; +#ifdef HAVE_NATIVE_BACKEND +static gboolean opt_virtual_monitor_cb (const char *option_name, + const char *value, + gpointer data, + GError **error); +#endif + static GOptionEntry meta_options[] = { { "sm-disable", 0, 0, G_OPTION_ARG_NONE, @@ -279,6 +294,16 @@ static GOptionEntry meta_options[] = { &opt_display_server, N_("Run as a full display server, rather than nested") }, + { + "headless", 0, 0, G_OPTION_ARG_NONE, + &opt_headless, + N_("Run as a headless display server") + }, + { + "virtual-monitor", 0, 0, G_OPTION_ARG_CALLBACK, + &opt_virtual_monitor_cb, + N_("Add persistent virtual monitor (WxH or WxH@R)") + }, #endif { "x11", 0, 0, G_OPTION_ARG_NONE, @@ -337,6 +362,10 @@ static void meta_finalize (void) { MetaDisplay *display = meta_get_display (); + MetaBackend *backend = meta_get_backend (); + + if (backend) + meta_backend_prepare_shutdown (backend); if (display) meta_display_close (display, @@ -347,6 +376,10 @@ meta_finalize (void) meta_wayland_finalize (); #endif +#ifdef HAVE_NATIVE_BACKEND + release_virtual_monitors (); +#endif + meta_release_backend (); } @@ -447,6 +480,92 @@ check_for_wayland_session_type (void) } #endif +#ifdef HAVE_NATIVE_BACKEND +static GList *opt_virtual_monitor_infos = NULL; + +static GList *persistent_virtual_monitors = NULL; + +static gboolean +opt_virtual_monitor_cb (const char *option_name, + const char *value, + gpointer data, + GError **error) +{ + int width, height; + float refresh_rate = 60.0; + + if (sscanf (value, "%dx%d@%f", + &width, &height, &refresh_rate) == 3 || + sscanf (value, "%dx%d", + &width, &height) == 2) + { + g_autofree char *serial = NULL; + MetaVirtualMonitorInfo *virtual_monitor; + + serial = g_strdup_printf ("0x%.2x", + g_list_length (opt_virtual_monitor_infos)); + virtual_monitor = meta_virtual_monitor_info_new (width, + height, + refresh_rate, + "MetaVendor", + "MetaVirtualMonitor", + serial); + opt_virtual_monitor_infos = g_list_append (opt_virtual_monitor_infos, + virtual_monitor); + return TRUE; + } + else + { + return FALSE; + } +} + +static void +release_virtual_monitors (void) +{ + g_list_free_full (persistent_virtual_monitors, g_object_unref); + persistent_virtual_monitors = NULL; +} + +static void +add_persistent_virtual_monitors (void) +{ + MetaBackend *backend = meta_get_backend (); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + GList *l; + + for (l = opt_virtual_monitor_infos; l; l = l->next) + { + MetaVirtualMonitorInfo *info = l->data; + g_autoptr (GError) error = NULL; + MetaVirtualMonitor *virtual_monitor; + + virtual_monitor = + meta_monitor_manager_create_virtual_monitor (monitor_manager, + info, + &error); + if (!virtual_monitor) + { + g_warning ("Failed to add virtual monitor: %s", error->message); + meta_exit (META_EXIT_ERROR); + } + + persistent_virtual_monitors = g_list_append (persistent_virtual_monitors, + virtual_monitor); + } + + if (opt_virtual_monitor_infos) + { + g_list_free_full (opt_virtual_monitor_infos, + (GDestroyNotify) meta_virtual_monitor_info_free); + opt_virtual_monitor_infos = NULL; + + meta_monitor_manager_reload (monitor_manager); + } +} +#endif + /* * Determine the compositor configuration, i.e. whether to run as a Wayland * compositor, as well as what backend to use. @@ -468,14 +587,21 @@ check_for_wayland_session_type (void) * Wayland compositor, then the X11 Compositing Manager backend is used. */ static void -calculate_compositor_configuration (MetaCompositorType *compositor_type, - GType *backend_gtype) +calculate_compositor_configuration (MetaCompositorType *compositor_type, + GType *backend_gtype, + unsigned int *n_properties, + const char **prop_names[], + GValue *prop_values[]) { #ifdef HAVE_WAYLAND - gboolean run_as_wayland_compositor = opt_wayland && !opt_x11; + gboolean run_as_wayland_compositor = ((opt_wayland || + opt_display_server || + opt_headless) && + !opt_x11); #ifdef HAVE_NATIVE_BACKEND - if ((opt_wayland || opt_nested || opt_display_server) && opt_x11) + if ((opt_wayland || opt_nested || opt_display_server || opt_headless) && + opt_x11) #else if ((opt_wayland || opt_nested) && opt_x11) #endif @@ -485,7 +611,7 @@ calculate_compositor_configuration (MetaCompositorType *compositor_type, } #ifdef HAVE_NATIVE_BACKEND - if (opt_nested && opt_display_server) + if (opt_nested && (opt_display_server || opt_headless)) { meta_warning ("Can't run both as nested and as a display server"); meta_exit (META_EXIT_ERROR); @@ -507,6 +633,10 @@ calculate_compositor_configuration (MetaCompositorType *compositor_type, #endif /* HAVE_WAYLAND */ *compositor_type = META_COMPOSITOR_TYPE_X11; + *n_properties = 0; + *prop_names = NULL; + *prop_values = NULL; + #ifdef HAVE_WAYLAND if (opt_nested) { @@ -516,9 +646,25 @@ calculate_compositor_configuration (MetaCompositorType *compositor_type, #endif /* HAVE_WAYLAND */ #ifdef HAVE_NATIVE_BACKEND - if (opt_display_server) + if (opt_display_server || opt_headless) { *backend_gtype = META_TYPE_BACKEND_NATIVE; + if (opt_headless) + { + static const char *headless_prop_names[] = { + "headless", + }; + static GValue headless_prop_values[] = { + G_VALUE_INIT, + }; + + g_value_init (&headless_prop_values[0], G_TYPE_BOOLEAN); + g_value_set_boolean (&headless_prop_values[0], TRUE); + + *n_properties = G_N_ELEMENTS (headless_prop_values); + *prop_names = headless_prop_names; + *prop_values = headless_prop_values; + } return; } @@ -548,14 +694,61 @@ calculate_compositor_configuration (MetaCompositorType *compositor_type, static gboolean _compositor_configuration_overridden = FALSE; static MetaCompositorType _compositor_type_override; static GType _backend_gtype_override; +static GArray *_backend_property_names; +static GArray *_backend_property_values; void meta_override_compositor_configuration (MetaCompositorType compositor_type, - GType backend_gtype) + GType backend_gtype, + const char *first_property_name, + ...) { + va_list var_args; + GArray *names; + GArray *values; + GObjectClass *object_class; + const char *property_name; + + names = g_array_new (FALSE, FALSE, sizeof (const char *)); + values = g_array_new (FALSE, FALSE, sizeof (GValue)); + g_array_set_clear_func (values, (GDestroyNotify) g_value_unset); + + object_class = g_type_class_ref (backend_gtype); + + property_name = first_property_name; + + va_start (var_args, first_property_name); + + while (property_name) + { + GValue value = G_VALUE_INIT; + GParamSpec *pspec; + GType ptype; + char *error = NULL; + + pspec = g_object_class_find_property (object_class, + property_name); + g_assert (pspec); + + ptype = G_PARAM_SPEC_VALUE_TYPE (pspec); + G_VALUE_COLLECT_INIT (&value, ptype, var_args, 0, &error); + g_assert (!error); + + g_array_append_val (names, property_name); + g_array_append_val (values, value); + + property_name = va_arg (var_args, const char *); + } + + va_end (var_args); + + g_type_class_unref (object_class); + _compositor_configuration_overridden = TRUE; _compositor_type_override = compositor_type; _backend_gtype_override = backend_gtype; + _backend_property_names = names; + _backend_property_values = values; } /** @@ -572,6 +765,10 @@ meta_init (void) const char *debug_env; MetaCompositorType compositor_type; GType backend_gtype; + unsigned int n_properties; + const char **prop_names; + GValue *prop_values; + int i; #ifdef HAVE_SYS_PRCTL prctl (PR_SET_DUMPABLE, 1); @@ -610,10 +807,17 @@ meta_init (void) { compositor_type = _compositor_type_override; backend_gtype = _backend_gtype_override; + n_properties = _backend_property_names->len; + prop_names = (const char **) _backend_property_names->data; + prop_values = (GValue *) _backend_property_values->data; } else { - calculate_compositor_configuration (&compositor_type, &backend_gtype); + calculate_compositor_configuration (&compositor_type, + &backend_gtype, + &n_properties, + &prop_names, + &prop_values); } #ifdef HAVE_WAYLAND @@ -644,7 +848,20 @@ meta_init (void) if (!meta_is_wayland_compositor ()) meta_select_display (opt_display_name); - meta_init_backend (backend_gtype); + meta_init_backend (backend_gtype, n_properties, prop_names, prop_values); + + for (i = 0; i < n_properties; i++) + g_value_reset (&prop_values[i]); + + if (_backend_property_names) + { + g_array_free (_backend_property_names, TRUE); + g_array_free (_backend_property_values, TRUE); + } + +#ifdef HAVE_NATIVE_BACKEND + add_persistent_virtual_monitors (); +#endif meta_set_syncing (opt_sync || (g_getenv ("MUTTER_SYNC") != NULL)); @@ -817,7 +1034,8 @@ meta_test_init (void) int fd = g_mkstemp (display_name); meta_override_compositor_configuration (META_COMPOSITOR_TYPE_WAYLAND, - META_TYPE_BACKEND_X11_NESTED); + META_TYPE_BACKEND_X11_NESTED, + NULL); meta_wayland_override_display_name (display_name); meta_xwayland_override_display_number (512 + rand() % 512); meta_init (); diff --git a/src/core/workspace.c b/src/core/workspace.c index 32ee8da93abbedd5cc16130b1b0ced1415a3da01..321d3efb0ac25858685270cdac8a4e1eccff6061 100644 --- a/src/core/workspace.c +++ b/src/core/workspace.c @@ -887,7 +887,8 @@ ensure_work_areas_validated (MetaWorkspace *workspace) /* Lots of paranoia checks, forcing work_area_screen to be sane */ #define MIN_SANE_AREA 100 - if (work_area.width < MIN_SANE_AREA) + if (work_area.width < MIN_SANE_AREA && + work_area.width != display_rect.width) { meta_warning ("struts occupy an unusually large percentage of the screen; " "available remaining width = %d < %d", @@ -904,7 +905,8 @@ ensure_work_areas_validated (MetaWorkspace *workspace) work_area.width += 2*amount; } } - if (work_area.height < MIN_SANE_AREA) + if (work_area.height < MIN_SANE_AREA && + work_area.height != display_rect.height) { meta_warning ("struts occupy an unusually large percentage of the screen; " "available remaining height = %d < %d", diff --git a/src/meson.build b/src/meson.build index 7ed0bfca0a2c328c117fd545e235bb58bfb146f9..459a563152a6656b3daefc776c19c521524cee47 100644 --- a/src/meson.build +++ b/src/meson.build @@ -236,6 +236,8 @@ mutter_sources = [ 'backends/meta-stage-private.h', 'backends/meta-viewport-info.c', 'backends/meta-viewport-info.h', + 'backends/meta-virtual-monitor.c', + 'backends/meta-virtual-monitor.h', 'backends/x11/cm/meta-backend-x11-cm.c', 'backends/x11/cm/meta-backend-x11-cm.h', 'backends/x11/cm/meta-cursor-sprite-xfixes.c', @@ -478,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', @@ -645,8 +651,14 @@ if have_native_backend 'backends/native/meta-cogl-utils.h', 'backends/native/meta-crtc-kms.c', 'backends/native/meta-crtc-kms.h', + 'backends/native/meta-crtc-native.c', + 'backends/native/meta-crtc-native.h', 'backends/native/meta-crtc-mode-kms.c', 'backends/native/meta-crtc-mode-kms.h', + 'backends/native/meta-crtc-mode-virtual.c', + 'backends/native/meta-crtc-mode-virtual.h', + 'backends/native/meta-crtc-virtual.c', + 'backends/native/meta-crtc-virtual.h', 'backends/native/meta-cursor-renderer-native.c', 'backends/native/meta-cursor-renderer-native.h', 'backends/native/meta-drm-buffer-dumb.c', @@ -670,10 +682,14 @@ if have_native_backend 'backends/native/meta-keymap-native.h', 'backends/native/meta-launcher.c', 'backends/native/meta-launcher.h', - 'backends/native/meta-monitor-manager-kms.c', - 'backends/native/meta-monitor-manager-kms.h', + 'backends/native/meta-monitor-manager-native.c', + 'backends/native/meta-monitor-manager-native.h', 'backends/native/meta-output-kms.c', 'backends/native/meta-output-kms.h', + 'backends/native/meta-output-native.c', + 'backends/native/meta-output-native.h', + 'backends/native/meta-output-virtual.c', + 'backends/native/meta-output-virtual.h', 'backends/native/meta-kms-connector-private.h', 'backends/native/meta-kms-connector.c', 'backends/native/meta-kms-connector.h', @@ -685,6 +701,8 @@ if have_native_backend 'backends/native/meta-kms-device.h', 'backends/native/meta-kms-impl-device-atomic.c', 'backends/native/meta-kms-impl-device-atomic.h', + 'backends/native/meta-kms-impl-device-dummy.c', + 'backends/native/meta-kms-impl-device-dummy.h', 'backends/native/meta-kms-impl-device-simple.c', 'backends/native/meta-kms-impl-device-simple.h', 'backends/native/meta-kms-impl-device.c', @@ -726,6 +744,8 @@ if have_native_backend 'backends/native/meta-udev.h', 'backends/native/meta-virtual-input-device-native.c', 'backends/native/meta-virtual-input-device-native.h', + 'backends/native/meta-virtual-monitor-native.c', + 'backends/native/meta-virtual-monitor-native.h', 'backends/native/meta-xkb-utils.c', 'backends/native/meta-xkb-utils.h', 'compositor/meta-compositor-native.c', @@ -740,13 +760,26 @@ if have_wayland_eglstream ] endif -mutter_built_sources = [] +mutter_private_enum_sources = [] if have_remote_desktop + mutter_private_enum_sources += [ + 'backends/meta-screen-cast.h', + ] +endif + +if have_native_backend + mutter_private_enum_sources += [ + 'backends/native/meta-backend-native-types.h', + 'backends/native/meta-kms-types.h', + ] +endif + +mutter_built_sources = [] + +if mutter_private_enum_sources.length() > 0 mutter_private_enum_types = gnome.mkenums('meta-private-enum-types', - sources: [ - 'backends/meta-screen-cast.h', - ], + sources: mutter_private_enum_sources, c_template: 'meta-private-enum-types.c.in', h_template: 'meta-private-enum-types.h.in', ) diff --git a/src/org.gnome.Mutter.ScreenCast.xml b/src/org.gnome.Mutter.ScreenCast.xml index 07ab402eb454b3004976cfec68a419515905290f..d9f1f4435d9384e4aed70174949c2ccbdef09662 100644 --- a/src/org.gnome.Mutter.ScreenCast.xml +++ b/src/org.gnome.Mutter.ScreenCast.xml @@ -153,6 +153,35 @@ + + + + + +