diff --git a/data/dbus-interfaces/org.gnome.Mutter.DisplayConfig.xml b/data/dbus-interfaces/org.gnome.Mutter.DisplayConfig.xml index 8c1b951a7..cf9db4fd4 100644 --- a/data/dbus-interfaces/org.gnome.Mutter.DisplayConfig.xml +++ b/data/dbus-interfaces/org.gnome.Mutter.DisplayConfig.xml @@ -521,5 +521,12 @@ + + + diff --git a/src/backends/meta-monitor-manager.c b/src/backends/meta-monitor-manager.c index 921d1dcbb..eb5907469 100644 --- a/src/backends/meta-monitor-manager.c +++ b/src/backends/meta-monitor-manager.c @@ -1205,11 +1205,36 @@ update_night_light_supported (MetaMonitorManager *manager) night_light_supported); } +static void +update_has_external_monitor (MetaMonitorManager *monitor_manager) +{ + GList *l; + gboolean has_external_monitor = FALSE; + + for (l = meta_monitor_manager_get_monitors (monitor_manager); l; l = l->next) + { + MetaMonitor *monitor = l->data; + + if (meta_monitor_is_laptop_panel (monitor)) + continue; + + if (!meta_monitor_is_active (monitor)) + continue; + + has_external_monitor = TRUE; + break; + } + + meta_dbus_display_config_set_has_external_monitor (monitor_manager->display_config, + has_external_monitor); +} + static void meta_monitor_manager_notify_monitors_changed (MetaMonitorManager *manager) { meta_backend_monitors_changed (manager->backend); + update_has_external_monitor (manager); update_backlight (manager, TRUE); g_signal_emit (manager, signals[MONITORS_CHANGED_INTERNAL], 0); @@ -1247,6 +1272,7 @@ meta_monitor_manager_setup (MetaMonitorManager *manager) meta_monitor_manager_notify_monitors_changed (manager); + update_has_external_monitor (manager); update_backlight (manager, TRUE); manager->in_init = FALSE; diff --git a/src/backends/meta-monitor.h b/src/backends/meta-monitor.h index bd23d8f97..01836dc0e 100644 --- a/src/backends/meta-monitor.h +++ b/src/backends/meta-monitor.h @@ -124,6 +124,7 @@ gboolean meta_monitor_get_max_bpc (MetaMonitor *monitor, MetaOutputRGBRange meta_monitor_get_rgb_range (MetaMonitor *monitor); +META_EXPORT_TEST gboolean meta_monitor_is_laptop_panel (MetaMonitor *monitor); gboolean meta_monitor_is_virtual (MetaMonitor *monitor); diff --git a/src/tests/monitor-unit-tests.c b/src/tests/monitor-unit-tests.c index 2e0539fc1..a55e06055 100644 --- a/src/tests/monitor-unit-tests.c +++ b/src/tests/monitor-unit-tests.c @@ -4113,6 +4113,191 @@ meta_test_monitor_switch_config_remember_scale (void) check_monitor_test_clients_state (); } +static void +wait_for_boolean_property (GDBusProxy *proxy, + const char *property_name, + gboolean expected_value) +{ + g_debug ("Waiting for property '%s' to become %s on '%s'", + property_name, + expected_value ? "TRUE" : "FALSE", + g_dbus_proxy_get_interface_name (proxy)); + + while (TRUE) + { + g_autoptr (GVariant) value_variant = NULL; + + value_variant = g_dbus_proxy_get_cached_property (proxy, property_name); + g_assert_nonnull (value_variant); + + if (g_variant_get_boolean (value_variant) == expected_value) + break; + + g_main_context_iteration (NULL, TRUE); + } +} + +static void +proxy_ready_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GDBusProxy *proxy; + GDBusProxy **display_config_proxy_ptr = user_data; + g_autoptr (GError) error = NULL; + + proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + g_assert_nonnull (proxy); + g_assert_no_error (error); + + *display_config_proxy_ptr = proxy; +} + +static void +meta_test_monitor_has_external_monitor (void) +{ + MonitorTestCaseSetup test_case_setup = { + .modes = { + { + .width = 800, + .height = 600, + .refresh_rate = 60.0 + }, + }, + .n_modes = 1, + .outputs = { + { + .crtc = -1, + .modes = { 0 }, + .n_modes = 1, + .preferred_mode = 0, + .possible_crtcs = { 0 }, + .n_possible_crtcs = 1, + .width_mm = 222, + .height_mm = 125, + .is_laptop_panel = TRUE, + }, + { + .crtc = -1, + .modes = { 0 }, + .n_modes = 1, + .preferred_mode = 0, + .possible_crtcs = { 1 }, + .n_possible_crtcs = 1, + .width_mm = 222, + .height_mm = 125, + .is_laptop_panel = FALSE, + } + }, + .n_outputs = 2, + .crtcs = { + { + .current_mode = -1 + } + }, + .n_crtcs = 2 + }; + MetaBackend *backend = meta_context_get_backend (test_context); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + MetaMonitorTestSetup *test_setup; + GList *monitors; + MetaMonitor *first_monitor; + MetaMonitor *second_monitor; + g_autoptr (GDBusProxy) display_config_proxy = NULL; + g_autoptr (GError) error = NULL; + + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, + "org.gnome.Mutter.DisplayConfig", + "/org/gnome/Mutter/DisplayConfig", + "org.gnome.Mutter.DisplayConfig", + NULL, + proxy_ready_cb, + &display_config_proxy); + while (!display_config_proxy) + g_main_context_iteration (NULL, TRUE); + + g_debug ("Connecting one builtin and one external monitor"); + + test_setup = meta_create_monitor_test_setup (test_backend, + &test_case_setup, + MONITOR_TEST_FLAG_NO_STORED); + emulate_hotplug (test_setup); + + monitors = meta_monitor_manager_get_monitors (monitor_manager); + g_assert_cmpuint (g_list_length (monitors), ==, 2); + first_monitor = g_list_nth_data (monitors, 0); + second_monitor = g_list_nth_data (monitors, 1); + g_assert_true (meta_monitor_is_laptop_panel (first_monitor)); + g_assert_true (meta_monitor_is_active (first_monitor)); + g_assert_false (meta_monitor_is_laptop_panel (second_monitor)); + g_assert_true (meta_monitor_is_active (second_monitor)); + + wait_for_boolean_property (G_DBUS_PROXY (display_config_proxy), + "HasExternalMonitor", + TRUE); + + g_debug ("Disconnecting external monitor"); + + test_case_setup.n_outputs = 1; + test_setup = meta_create_monitor_test_setup (test_backend, + &test_case_setup, + MONITOR_TEST_FLAG_NO_STORED); + emulate_hotplug (test_setup); + + monitors = meta_monitor_manager_get_monitors (monitor_manager); + g_assert_cmpuint (g_list_length (monitors), ==, 1); + first_monitor = g_list_nth_data (monitors, 0); + g_assert_true (meta_monitor_is_laptop_panel (first_monitor)); + g_assert_true (meta_monitor_is_active (first_monitor)); + + wait_for_boolean_property (G_DBUS_PROXY (display_config_proxy), + "HasExternalMonitor", + FALSE); + + g_debug ("Reconnect external monitor."); + + test_case_setup.n_outputs = 2; + test_setup = meta_create_monitor_test_setup (test_backend, + &test_case_setup, + MONITOR_TEST_FLAG_NO_STORED); + emulate_hotplug (test_setup); + + monitors = meta_monitor_manager_get_monitors (monitor_manager); + g_assert_cmpuint (g_list_length (monitors), ==, 2); + first_monitor = g_list_nth_data (monitors, 0); + second_monitor = g_list_nth_data (monitors, 1); + g_assert_true (meta_monitor_is_laptop_panel (first_monitor)); + g_assert_true (meta_monitor_is_active (first_monitor)); + g_assert_false (meta_monitor_is_laptop_panel (second_monitor)); + g_assert_true (meta_monitor_is_active (second_monitor)); + + wait_for_boolean_property (G_DBUS_PROXY (display_config_proxy), + "HasExternalMonitor", + TRUE); + + g_debug ("Disable external monitor."); + + meta_monitor_manager_switch_config (monitor_manager, + META_MONITOR_SWITCH_CONFIG_BUILTIN); + while (g_main_context_iteration (NULL, FALSE)); + + monitors = meta_monitor_manager_get_monitors (monitor_manager); + g_assert_cmpuint (g_list_length (monitors), ==, 2); + first_monitor = g_list_nth_data (monitors, 0); + second_monitor = g_list_nth_data (monitors, 1); + g_assert_true (meta_monitor_is_laptop_panel (first_monitor)); + g_assert_true (meta_monitor_is_active (first_monitor)); + g_assert_false (meta_monitor_is_laptop_panel (second_monitor)); + g_assert_false (meta_monitor_is_active (second_monitor)); + + wait_for_boolean_property (G_DBUS_PROXY (display_config_proxy), + "HasExternalMonitor", + FALSE); +} + static void check_monitor_configuration_per_orientation (MonitorTestCase *test_case, unsigned int monitor_index, @@ -10153,6 +10338,9 @@ init_monitor_tests (void) add_monitor_test ("/backends/monitor/switch-config-remember-scale", meta_test_monitor_switch_config_remember_scale); + add_monitor_test ("/backends/monitor/has-external-monitor", + meta_test_monitor_has_external_monitor); + add_monitor_test ("/backends/monitor/orientation/is-managed", meta_test_monitor_orientation_is_managed); add_monitor_test ("/backends/monitor/orientation/initial-rotated",