diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c index e6df87630..28cc457e7 100644 --- a/src/backends/meta-monitor-manager.c +++ b/src/backends/meta-monitor-manager.c @@ -116,6 +116,8 @@ typedef struct _MetaMonitorManagerPrivate gboolean has_builtin_panel; gboolean night_light_supported; const char *experimental_hdr; + + guint switch_config_handle_id; } MetaMonitorManagerPrivate; G_DEFINE_TYPE_WITH_PRIVATE (MetaMonitorManager, meta_monitor_manager, @@ -1356,6 +1358,8 @@ static void meta_monitor_manager_dispose (GObject *object) { MetaMonitorManager *manager = META_MONITOR_MANAGER (object); + MetaMonitorManagerPrivate *priv = + meta_monitor_manager_get_instance_private (manager); g_clear_handle_id (&manager->dbus_name_id, g_bus_unown_name); @@ -1364,6 +1368,7 @@ meta_monitor_manager_dispose (GObject *object) g_clear_handle_id (&manager->persistent_timeout_id, g_source_remove); g_clear_handle_id (&manager->restore_config_id, g_source_remove); + g_clear_handle_id (&priv->switch_config_handle_id, g_source_remove); G_OBJECT_CLASS (meta_monitor_manager_parent_class)->dispose (object); } @@ -3863,35 +3868,66 @@ meta_monitor_manager_rotate_monitor (MetaMonitorManager *manager) g_object_unref (config); } -void -meta_monitor_manager_switch_config (MetaMonitorManager *manager, - MetaMonitorSwitchConfigType config_type) +typedef struct { - GError *error = NULL; - MetaMonitorsConfig *config; + MetaMonitorManager *monitor_manager; + MetaMonitorSwitchConfigType config_type; +} SwitchConfigData; - g_return_if_fail (config_type != META_MONITOR_SWITCH_CONFIG_UNKNOWN); +static gboolean +switch_config_idle_cb (gpointer user_data) +{ + SwitchConfigData *data = user_data; + MetaMonitorManager *monitor_manager = data->monitor_manager; + MetaMonitorManagerPrivate *priv = + meta_monitor_manager_get_instance_private (monitor_manager); + MetaMonitorConfigManager *config_manager = monitor_manager->config_manager; + MetaMonitorsConfig *config; + g_autoptr (GError) error = NULL; + + priv->switch_config_handle_id = 0; config = - meta_monitor_config_manager_create_for_switch_config (manager->config_manager, - config_type); + meta_monitor_config_manager_create_for_switch_config (config_manager, + data->config_type); if (!config) - return; + return G_SOURCE_REMOVE; - if (!meta_monitor_manager_apply_monitors_config (manager, + if (!meta_monitor_manager_apply_monitors_config (monitor_manager, config, META_MONITORS_CONFIG_METHOD_TEMPORARY, &error)) { g_warning ("Failed to use switch monitor configuration: %s", error->message); - g_error_free (error); } else { - manager->current_switch_config = config_type; + monitor_manager->current_switch_config = data->config_type; } - g_object_unref (config); + + return G_SOURCE_REMOVE; +} + +void +meta_monitor_manager_switch_config (MetaMonitorManager *manager, + MetaMonitorSwitchConfigType config_type) +{ + MetaMonitorManagerPrivate *priv = + meta_monitor_manager_get_instance_private (manager); + SwitchConfigData *data; + + g_return_if_fail (config_type != META_MONITOR_SWITCH_CONFIG_UNKNOWN); + + data = g_new0 (SwitchConfigData, 1); + data->monitor_manager = manager; + data->config_type = config_type; + + g_clear_handle_id (&priv->switch_config_handle_id, g_source_remove); + priv->switch_config_handle_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, + switch_config_idle_cb, + data, + g_free); } gboolean diff --git a/src/tests/monitor-unit-tests.c b/src/tests/monitor-unit-tests.c index 5aedb7844..99355f6fe 100644 --- a/src/tests/monitor-unit-tests.c +++ b/src/tests/monitor-unit-tests.c @@ -3626,6 +3626,7 @@ meta_test_monitor_switch_external_without_external (void) meta_monitor_manager_switch_config (monitor_manager, META_MONITOR_SWITCH_CONFIG_EXTERNAL); + while (g_main_context_iteration (NULL, FALSE)); META_TEST_LOG_CALL ("Checking monitor configuration", meta_check_monitor_configuration (test_context, &test_case.expect)); @@ -3817,6 +3818,7 @@ meta_test_monitor_switch_config_remember_scale (void) meta_monitor_manager_switch_config (monitor_manager, META_MONITOR_SWITCH_CONFIG_BUILTIN); + while (g_main_context_iteration (NULL, FALSE)); META_TEST_LOG_CALL ("Checking monitor configuration", meta_check_monitor_configuration (test_context, &test_case.expect)); @@ -3837,6 +3839,7 @@ meta_test_monitor_switch_config_remember_scale (void) meta_monitor_manager_switch_config (monitor_manager, META_MONITOR_SWITCH_CONFIG_EXTERNAL); + while (g_main_context_iteration (NULL, FALSE)); META_TEST_LOG_CALL ("Checking monitor configuration", meta_check_monitor_configuration (test_context, &test_case.expect)); @@ -3856,6 +3859,7 @@ meta_test_monitor_switch_config_remember_scale (void) meta_monitor_manager_switch_config (monitor_manager, META_MONITOR_SWITCH_CONFIG_ALL_LINEAR); + while (g_main_context_iteration (NULL, FALSE)); META_TEST_LOG_CALL ("Checking monitor configuration", meta_check_monitor_configuration (test_context, &test_case.expect)); @@ -3874,6 +3878,7 @@ meta_test_monitor_switch_config_remember_scale (void) meta_monitor_manager_switch_config (monitor_manager, META_MONITOR_SWITCH_CONFIG_ALL_MIRROR); + while (g_main_context_iteration (NULL, FALSE)); META_TEST_LOG_CALL ("Checking monitor configuration", meta_check_monitor_configuration (test_context, &test_case.expect)); diff --git a/src/tests/native-kms-hotplug.c b/src/tests/native-kms-hotplug.c index 4a6f2e0aa..3c60aa10a 100644 --- a/src/tests/native-kms-hotplug.c +++ b/src/tests/native-kms-hotplug.c @@ -17,11 +17,16 @@ #include "config.h" +#include + +#include "backends/meta-logical-monitor.h" #include "backends/meta-monitor-manager-private.h" +#include "backends/meta-virtual-monitor.h" #include "backends/native/meta-backend-native.h" #include "backends/native/meta-udev.h" #include "meta-test/meta-context-test.h" #include "tests/drm-mock/drm-mock.h" +#include "tests/meta-test-utils.h" typedef enum _State { @@ -207,6 +212,118 @@ meta_test_disconnect_connect (void) g_signal_handler_disconnect (stage, presented_handler_id); } +static gboolean +on_key_release (ClutterActor *actor, + const ClutterEvent *event, + MetaMonitorManager *monitor_manager) +{ + if (clutter_event_get_key_symbol (event) == CLUTTER_KEY_a) + { + g_debug ("Switching config"); + meta_monitor_manager_switch_config (monitor_manager, + META_MONITOR_SWITCH_CONFIG_ALL_MIRROR); + } + + return TRUE; +} + +static void +on_monitors_changed (MetaMonitorManager *monitor_manager, + gboolean *monitors_changed) +{ + *monitors_changed = TRUE; +} + +static void +meta_test_switch_config (void) +{ + MetaBackend *backend = meta_context_get_backend (test_context); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + ClutterActor *stage = meta_backend_get_stage (backend); + ClutterSeat *seat = meta_backend_get_default_seat (backend); + g_autoptr (ClutterVirtualInputDevice) virtual_keyboard = NULL; + g_autoptr (MetaVirtualMonitor) virtual_monitor = NULL; + GList *logical_monitors; + MetaRectangle logical_monitor_layout; + gulong after_paint_handler_id; + gulong presented_handler_id; + gboolean monitors_changed; + g_autoptr (GError) error = NULL; + ClutterActor *actor; + State state; + + after_paint_handler_id = g_signal_connect (stage, "after-paint", + G_CALLBACK (on_after_paint), + &state); + presented_handler_id = g_signal_connect (stage, "presented", + G_CALLBACK (on_presented), + &state); + g_signal_connect (monitor_manager, "monitors-changed", + G_CALLBACK (on_monitors_changed), + &monitors_changed); + + logical_monitors = + meta_monitor_manager_get_logical_monitors (monitor_manager); + g_assert_cmpuint (g_list_length (logical_monitors), ==, 1); + logical_monitor_layout = + meta_logical_monitor_get_layout (logical_monitors->data); + + virtual_monitor = meta_create_test_monitor (test_context, + logical_monitor_layout.width, + logical_monitor_layout.height, + 60.0); + + actor = clutter_actor_new (); + g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor); + clutter_actor_insert_child_above (stage, + actor, + clutter_actor_get_first_child (stage)); + clutter_actor_set_size (actor, + logical_monitor_layout.width, + logical_monitor_layout.height); + clutter_actor_set_position (actor, 0, 0); + clutter_actor_set_reactive (actor, TRUE); + clutter_actor_show (actor); + clutter_actor_grab_key_focus (actor); + g_signal_connect (actor, "key-press-event", + G_CALLBACK (on_key_release), + monitor_manager); + + monitors_changed = FALSE; + g_signal_connect (monitor_manager, "monitors-changed", + G_CALLBACK (on_monitors_changed), + &monitors_changed); + + g_debug ("Sending virtual keyboard event"); + virtual_keyboard = + clutter_seat_create_virtual_device (seat, CLUTTER_KEYBOARD_DEVICE); + clutter_virtual_input_device_notify_key (virtual_keyboard, + CLUTTER_CURRENT_TIME, + KEY_A, + CLUTTER_KEY_STATE_PRESSED); + clutter_virtual_input_device_notify_key (virtual_keyboard, + CLUTTER_CURRENT_TIME, + KEY_A, + CLUTTER_KEY_STATE_RELEASED); + + g_debug ("Waiting for monitors changed"); + while (!monitors_changed) + g_main_context_iteration (NULL, TRUE); + + g_debug ("Waiting for being repainted"); + state = INIT; + clutter_actor_queue_redraw (stage); + while (state != PRESENTED) + g_main_context_iteration (NULL, TRUE); + + clutter_actor_destroy (actor); + g_assert_null (actor); + + g_signal_handler_disconnect (stage, after_paint_handler_id); + g_signal_handler_disconnect (stage, presented_handler_id); +} + static void init_tests (void) { @@ -214,6 +331,8 @@ init_tests (void) meta_test_reload); g_test_add_func ("/hotplug/disconnect-connect", meta_test_disconnect_connect); + g_test_add_func ("/hotplug/switch-config", + meta_test_switch_config); } int