monitor-manager: Apply switch-config in idle callback

Just as with restoring the previous monitor configuration in case the
user clicked "revert" in GNOME Shell's monitor configuration
confirmation dialog, we need to do switch configs in an idle callback as
well.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/2694
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2912>
This commit is contained in:
Jonas Ådahl 2023-03-14 17:28:24 +01:00 committed by Marge Bot
parent 5daddf0bc7
commit 214a7d393b
3 changed files with 173 additions and 13 deletions

View File

@ -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

View File

@ -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));

View File

@ -17,11 +17,16 @@
#include "config.h"
#include <linux/input-event-codes.h>
#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