[mutter/cherry-pick-f6db6cd2] monitor-config-manager: Handle multiple builtin panels gracefully




commit 5a4b9036df3f1a406e75eefe4a2b770472e49822
Author: Jonas Ådahl <jadahl gmail com>
Date:   Fri Nov 27 08:03:38 2020 +0000

    monitor-config-manager: Handle multiple builtin panels gracefully
    
    While multiple built-in panels isn't actually supported in any
    meaningful manner, if we would ever end up with such a situation, e.g.
    due to kernel bugs[0], we shouldn't crash when trying to set an
    'external only' without any external monitors.
    
    While we could handle this with more degraded functionality (e.g. don't
    support the 'switch' method of monitor configuration at all), handle it
    by simply not trying to switch to external-only when there are no,
    according to the kernel, external monitors available. This would e.g.
    still allow betwene 'mirror-all', and 'linear' switches.
    
    The crash itself was disguised as an arbitrary X11 BadValue error, due
    to mutter trying to resize the root window to 0x0, as the monitor
    configuration that was applied consisted of zero logical monitors, thus
    was effectively empty.
    
    [0] https://bugzilla.redhat.com/show_bug.cgi?id=1896904
    
    Related: https://bugzilla.redhat.com/show_bug.cgi?id=1899260
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1607>
    
    
    (cherry picked from commit f6db6cd2032a1c85c137935907fd9e5c756a5f06)

 src/backends/meta-monitor-config-manager.c |   3 +
 src/tests/monitor-unit-tests.c             | 146 +++++++++++++++++++++++++++++
 2 files changed, 149 insertions(+)
---
diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c
index b317aca0e0..1ef92c2d4d 100644
--- a/src/backends/meta-monitor-config-manager.c
+++ b/src/backends/meta-monitor-config-manager.c
@@ -1225,6 +1225,9 @@ create_for_switch_config_external (MetaMonitorConfigManager *config_manager)
       x += logical_monitor_config->layout.width;
     }
 
+  if (!logical_monitor_configs)
+    return NULL;
+
   monitors_config = meta_monitors_config_new (monitor_manager,
                                               logical_monitor_configs,
                                               layout_mode,
diff --git a/src/tests/monitor-unit-tests.c b/src/tests/monitor-unit-tests.c
index 6cce739971..f2a3da6a9c 100644
--- a/src/tests/monitor-unit-tests.c
+++ b/src/tests/monitor-unit-tests.c
@@ -2506,6 +2506,150 @@ meta_test_monitor_non_upright_panel (void)
   check_monitor_test_clients_state ();
 }
 
+static void
+meta_test_monitor_switch_external_without_external (void)
+{
+  MonitorTestCase test_case = {
+    .setup = {
+      .modes = {
+        {
+          .width = 1024,
+          .height = 768,
+          .refresh_rate = 60.0
+        }
+      },
+      .n_modes = 1,
+      .outputs = {
+        {
+          .crtc = 0,
+          .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 = TRUE
+        }
+      },
+      .n_outputs = 2,
+      .crtcs = {
+        {
+          .current_mode = 0
+        },
+        {
+          .current_mode = 0
+        }
+      },
+      .n_crtcs = 2
+    },
+
+    .expect = {
+      .monitors = {
+        {
+          .outputs = { 0 },
+          .n_outputs = 1,
+          .modes = {
+            {
+              .width = 1024,
+              .height = 768,
+              .refresh_rate = 60.0,
+              .crtc_modes = {
+                {
+                  .output = 0,
+                  .crtc_mode = 0
+                }
+              }
+            }
+          },
+          .n_modes = 1,
+          .current_mode = 0,
+          .width_mm = 222,
+          .height_mm = 125
+        },
+        {
+          .outputs = { 1 },
+          .n_outputs = 1,
+          .modes = {
+            {
+              .width = 1024,
+              .height = 768,
+              .refresh_rate = 60.0,
+              .crtc_modes = {
+                {
+                  .output = 1,
+                  .crtc_mode = 0
+                }
+              }
+            }
+          },
+          .n_modes = 1,
+          .current_mode = 0,
+          .width_mm = 222,
+          .height_mm = 125
+        }
+      },
+      .n_monitors = 2,
+      .logical_monitors = {
+        {
+          .monitors = { 0 },
+          .n_monitors = 1,
+          .layout = { .x = 0, .y = 0, .width = 1024, .height = 768 },
+          .scale = 1
+        },
+        {
+          .monitors = { 1 },
+          .n_monitors = 1,
+          .layout = { .x = 1024, .y = 0, .width = 1024, .height = 768 },
+          .scale = 1
+        }
+      },
+      .n_logical_monitors = 2,
+      .primary_logical_monitor = 0,
+      .n_outputs = 2,
+      .crtcs = {
+        {
+          .current_mode = 0,
+        },
+        {
+          .current_mode = 0,
+          .x = 1024,
+        },
+      },
+      .n_crtcs = 2,
+      .n_tiled_monitors = 0,
+      .screen_width = 2048,
+      .screen_height = 768
+    }
+  };
+  MetaMonitorTestSetup *test_setup;
+  MetaBackend *backend = meta_get_backend ();
+  MetaMonitorManager *monitor_manager =
+    meta_backend_get_monitor_manager (backend);
+
+  test_setup = create_monitor_test_setup (&test_case.setup,
+                                          MONITOR_TEST_FLAG_NO_STORED);
+  emulate_hotplug (test_setup);
+  check_monitor_configuration (&test_case.expect);
+
+  meta_monitor_manager_switch_config (monitor_manager,
+                                      META_MONITOR_SWITCH_CONFIG_EXTERNAL);
+  check_monitor_configuration (&test_case.expect);
+
+  check_monitor_test_clients_state ();
+}
+
 static void
 meta_test_monitor_custom_vertical_config (void)
 {
@@ -5656,6 +5800,8 @@ init_monitor_tests (void)
                     meta_test_monitor_preferred_non_first_mode);
   add_monitor_test ("/backends/monitor/non-upright-panel",
                     meta_test_monitor_non_upright_panel);
+  add_monitor_test ("/backends/monitor/switch-external-without-external",
+                    meta_test_monitor_switch_external_without_external);
 
   add_monitor_test ("/backends/monitor/custom/vertical-config",
                     meta_test_monitor_custom_vertical_config);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]