[mutter] orientation-manager: Use an idle to apply monitor orientation changes



commit 4fe75695675b5cac6401329535bde5278857e234
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date:   Fri May 1 16:32:46 2020 +0200

    orientation-manager: Use an idle to apply monitor orientation changes
    
    In X11 when we switch to another tty all the the signals are blocked (as
    the display fd is not replying back to polling, causing the main loop to
    stop), and they are all handled once we switch back to the tty.
    
    This is not a problem for most of external events, but in case of
    accelerometer changes, once we reactivate a mutter session we'll get
    them all together, causing lots of monitor reconfigurations leading to
    black screen for some seconds and most of the times to a wrong
    configuration being applied.
    
    To avoid this, batch all these events using an idle to only apply the
    last one we got in a loop.
    
    Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1217
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1233>

 src/backends/meta-orientation-manager.c    | 32 ++++++++++++++++++++++--
 src/tests/monitor-unit-tests.c             | 28 +++++++++++++++++++++
 src/tests/orientation-manager-unit-tests.c | 40 ++++++++++++++++++++++++++++++
 src/tests/orientation-manager-unit-tests.h |  4 +++
 4 files changed, 102 insertions(+), 2 deletions(-)
---
diff --git a/src/backends/meta-orientation-manager.c b/src/backends/meta-orientation-manager.c
index 52a1d1de60..7989aa84fc 100644
--- a/src/backends/meta-orientation-manager.c
+++ b/src/backends/meta-orientation-manager.c
@@ -52,6 +52,7 @@ struct _MetaOrientationManager
   GCancellable *cancellable;
 
   guint iio_watch_id;
+  guint sync_idle_id;
   GDBusProxy *iio_proxy;
   MetaOrientation prev_orientation;
   MetaOrientation curr_orientation;
@@ -135,13 +136,39 @@ sync_state (MetaOrientationManager *self)
   g_signal_emit (self, signals[ORIENTATION_CHANGED], 0);
 }
 
+static gboolean
+changed_idle (gpointer user_data)
+{
+  MetaOrientationManager *self = user_data;
+
+  self->sync_idle_id = 0;
+  sync_state (self);
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
+queue_sync_state (MetaOrientationManager *self)
+{
+  /* We need this idle to avoid triggering events happening while the session
+   * is not active (under X11), ideally this should be handled by stopping
+   * events if the session is not active, but we'll need a MetaLogind available
+   * in all the backends for having this working.
+   */
+
+  if (self->sync_idle_id)
+    return;
+
+  self->sync_idle_id = g_idle_add (changed_idle, self);
+}
+
 static void
 orientation_lock_changed (GSettings *settings,
                           gchar     *key,
                           gpointer   user_data)
 {
   MetaOrientationManager *self = user_data;
-  sync_state (self);
+  queue_sync_state (self);
 }
 
 static void
@@ -151,7 +178,7 @@ iio_properties_changed (GDBusProxy *proxy,
                         gpointer    user_data)
 {
   MetaOrientationManager *self = user_data;
-  sync_state (self);
+  queue_sync_state (self);
 }
 
 static void
@@ -288,6 +315,7 @@ meta_orientation_manager_finalize (GObject *object)
   g_clear_object (&self->cancellable);
 
   g_bus_unwatch_name (self->iio_watch_id);
+  g_clear_handle_id (&self->sync_idle_id, g_source_remove);
   g_clear_object (&self->iio_proxy);
 
   g_clear_object (&self->settings);
diff --git a/src/tests/monitor-unit-tests.c b/src/tests/monitor-unit-tests.c
index 73cff8c7fd..6b93db0aed 100644
--- a/src/tests/monitor-unit-tests.c
+++ b/src/tests/monitor-unit-tests.c
@@ -36,6 +36,7 @@
 #include "tests/monitor-test-utils.h"
 #include "tests/meta-test-utils.h"
 #include "tests/unit-tests.h"
+#include "tests/orientation-manager-unit-tests.h"
 #include "x11/meta-x11-display-private.h"
 
 static MonitorTestCase initial_test_case = {
@@ -3551,8 +3552,13 @@ typedef MetaSensorsProxyMock MetaSensorsProxyAutoResetMock;
 static void
 meta_sensors_proxy_reset (MetaSensorsProxyMock *proxy)
 {
+  MetaBackend *backend = meta_get_backend ();
+  MetaOrientationManager *orientation_manager =
+    meta_backend_get_orientation_manager (backend);
+
   meta_sensors_proxy_mock_set_orientation (proxy,
                                            META_ORIENTATION_NORMAL);
+  wait_for_orientation_changes (orientation_manager);
   g_object_unref (proxy);
 }
 G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaSensorsProxyAutoResetMock,
@@ -3875,6 +3881,7 @@ meta_test_monitor_orientation_initial_rotated (void)
   touch_device = meta_test_add_touch_device (backend);
   orientation = META_ORIENTATION_LEFT_UP;
   meta_sensors_proxy_mock_set_orientation (orientation_mock, orientation);
+  wait_for_orientation_changes (orientation_manager);
   g_assert_cmpuint (
     meta_orientation_manager_get_orientation (orientation_manager),
     ==,
@@ -3981,6 +3988,7 @@ meta_test_monitor_orientation_initial_rotated_no_touch_mode (void)
   orientation_mock = meta_sensors_proxy_mock_get ();
   orientation = META_ORIENTATION_LEFT_UP;
   meta_sensors_proxy_mock_set_orientation (orientation_mock, orientation);
+  wait_for_orientation_changes (orientation_manager);
   g_assert_cmpuint (
     meta_orientation_manager_get_orientation (orientation_manager),
     ==,
@@ -4097,6 +4105,7 @@ meta_test_monitor_orientation_initial_stored_rotated (void)
   touch_device = meta_test_add_touch_device (backend);
   orientation = META_ORIENTATION_RIGHT_UP;
   meta_sensors_proxy_mock_set_orientation (orientation_mock, orientation);
+  wait_for_orientation_changes (orientation_manager);
   g_assert_cmpuint (
     meta_orientation_manager_get_orientation (orientation_manager),
     ==,
@@ -4122,6 +4131,11 @@ meta_test_monitor_orientation_initial_stored_rotated (void)
 
   orientation = META_ORIENTATION_LEFT_UP;
   meta_sensors_proxy_mock_set_orientation (orientation_mock, orientation);
+  wait_for_orientation_changes (orientation_manager);
+  g_assert_cmpuint (
+    meta_orientation_manager_get_orientation (orientation_manager),
+    ==,
+    orientation);
 
   meta_backend_test_set_is_lid_closed (META_BACKEND_TEST (backend), FALSE);
   meta_monitor_manager_lid_is_closed_changed (monitor_manager);
@@ -4136,6 +4150,7 @@ meta_test_monitor_orientation_initial_stored_rotated (void)
 
   orientation = META_ORIENTATION_RIGHT_UP;
   meta_sensors_proxy_mock_set_orientation (orientation_mock, orientation);
+  wait_for_orientation_changes (orientation_manager);
   g_assert_cmpuint (
     meta_orientation_manager_get_orientation (orientation_manager),
     ==,
@@ -4247,6 +4262,7 @@ meta_test_monitor_orientation_initial_stored_rotated_no_touch (void)
   orientation_mock = meta_sensors_proxy_mock_get ();
   orientation = META_ORIENTATION_RIGHT_UP;
   meta_sensors_proxy_mock_set_orientation (orientation_mock, orientation);
+  wait_for_orientation_changes (orientation_manager);
   g_assert_cmpuint (
     meta_orientation_manager_get_orientation (orientation_manager),
     ==,
@@ -4390,6 +4406,7 @@ meta_test_monitor_orientation_changes (void)
       MetaMonitorsConfig *previous;
 
       meta_sensors_proxy_mock_set_orientation (orientation_mock, i);
+      wait_for_orientation_changes (orientation_manager);
       g_assert_cmpuint (
         meta_orientation_manager_get_orientation (orientation_manager),
         ==, i);
@@ -4418,6 +4435,7 @@ meta_test_monitor_orientation_changes (void)
 
   meta_sensors_proxy_mock_set_orientation (orientation_mock,
                                            META_ORIENTATION_NORMAL);
+  wait_for_orientation_changes (orientation_manager);
   META_TEST_LOG_CALL ("Checking configuration per orientation",
                       check_monitor_configuration_per_orientation (
                         &test_case.expect, 0, META_ORIENTATION_NORMAL,
@@ -4435,6 +4453,7 @@ meta_test_monitor_orientation_changes (void)
       MetaMonitorsConfig *previous;
 
       meta_sensors_proxy_mock_set_orientation (orientation_mock, i);
+      wait_for_orientation_changes (orientation_manager);
       g_assert_cmpuint (
         meta_orientation_manager_get_orientation (orientation_manager),
         ==, i);
@@ -4611,6 +4630,7 @@ meta_test_monitor_orientation_changes_with_hotplugging (void)
   for (i = META_N_ORIENTATIONS - 1; i > META_ORIENTATION_UNDEFINED; i--)
     {
       meta_sensors_proxy_mock_set_orientation (orientation_mock, i);
+      wait_for_orientation_changes (orientation_manager);
       g_assert_cmpuint (
         meta_orientation_manager_get_orientation (orientation_manager),
         ==, i);
@@ -4622,6 +4642,7 @@ meta_test_monitor_orientation_changes_with_hotplugging (void)
 
   meta_sensors_proxy_mock_set_orientation (orientation_mock,
                                            META_ORIENTATION_NORMAL);
+  wait_for_orientation_changes (orientation_manager);
   check_monitor_configuration (&test_case.expect);
 
   /* External monitor connected */
@@ -4642,6 +4663,7 @@ meta_test_monitor_orientation_changes_with_hotplugging (void)
   for (i = META_N_ORIENTATIONS - 1; i > META_ORIENTATION_UNDEFINED; i--)
     {
       meta_sensors_proxy_mock_set_orientation (orientation_mock, i);
+      wait_for_orientation_changes (orientation_manager);
       g_assert_cmpuint (
         meta_orientation_manager_get_orientation (orientation_manager),
         ==, i);
@@ -4653,6 +4675,7 @@ meta_test_monitor_orientation_changes_with_hotplugging (void)
 
   meta_sensors_proxy_mock_set_orientation (orientation_mock,
                                            META_ORIENTATION_NORMAL);
+  wait_for_orientation_changes (orientation_manager);
   check_monitor_configuration (&test_case.expect);
 
   /* Lid closed */
@@ -4672,11 +4695,13 @@ meta_test_monitor_orientation_changes_with_hotplugging (void)
   for (i = META_N_ORIENTATIONS - 1; i > META_ORIENTATION_UNDEFINED; i--)
     {
       meta_sensors_proxy_mock_set_orientation (orientation_mock, i);
+      wait_for_orientation_changes (orientation_manager);
       check_monitor_configuration (&test_case.expect);
     }
 
   meta_sensors_proxy_mock_set_orientation (orientation_mock,
                                            META_ORIENTATION_NORMAL);
+  wait_for_orientation_changes (orientation_manager);
 
   /*
    * The second part of this test emulate the following at each device rotation:
@@ -4719,6 +4744,7 @@ meta_test_monitor_orientation_changes_with_hotplugging (void)
 
       /* Change orientation */
       meta_sensors_proxy_mock_set_orientation (orientation_mock, i);
+      wait_for_orientation_changes (orientation_manager);
       check_monitor_configuration (&test_case.expect);
 
       /* Open the lid */
@@ -4734,6 +4760,7 @@ meta_test_monitor_orientation_changes_with_hotplugging (void)
       meta_backend_test_set_is_lid_closed (META_BACKEND_TEST (backend), FALSE);
       emulate_hotplug (test_setup);
 
+      wait_for_orientation_changes (orientation_manager);
       META_TEST_LOG_CALL ("Checking configuration per orientation",
                           check_monitor_configuration_per_orientation (
                             &test_case.expect, 0, i, 1024, 768));
@@ -4770,6 +4797,7 @@ meta_test_monitor_orientation_changes_with_hotplugging (void)
 
   meta_sensors_proxy_mock_set_orientation (orientation_mock,
                                            META_ORIENTATION_NORMAL);
+  wait_for_orientation_changes (orientation_manager);
 }
 
 static void
diff --git a/src/tests/orientation-manager-unit-tests.c b/src/tests/orientation-manager-unit-tests.c
index 74a861ab00..a936dccb7a 100644
--- a/src/tests/orientation-manager-unit-tests.c
+++ b/src/tests/orientation-manager-unit-tests.c
@@ -24,6 +24,44 @@
 
 #include "tests/meta-sensors-proxy-mock.h"
 
+static void
+on_orientation_changed (gpointer data)
+{
+  gboolean *changed = data;
+
+  *changed = TRUE;
+}
+
+static gboolean
+on_max_wait_timeout (gpointer data)
+{
+  guint *timeout_id = data;
+
+  *timeout_id = 0;
+
+  return G_SOURCE_REMOVE;
+}
+
+void
+wait_for_orientation_changes (MetaOrientationManager *orientation_manager)
+{
+  gboolean changed = FALSE;
+  gulong connection_id;
+  guint timeout_id;
+
+  timeout_id = g_timeout_add (300, on_max_wait_timeout, &timeout_id);
+  connection_id = g_signal_connect_swapped (orientation_manager,
+                                            "orientation-changed",
+                                            G_CALLBACK (on_orientation_changed),
+                                            &changed);
+
+  while (!changed && timeout_id)
+    g_main_context_iteration (NULL, TRUE);
+
+  g_clear_handle_id (&timeout_id, g_source_remove);
+  g_signal_handler_disconnect (orientation_manager, connection_id);
+}
+
 static void
 meta_test_orientation_manager_no_daemon (void)
 {
@@ -64,6 +102,7 @@ meta_test_orientation_manager_has_accelerometer (void)
   meta_sensors_proxy_mock_set_property (orientation_mock,
                                         "HasAccelerometer",
                                         g_variant_new_boolean (TRUE));
+  wait_for_orientation_changes (manager);
 
   g_debug ("Checking whether accelerometer is present");
   g_assert_true (meta_orientation_manager_has_accelerometer (manager));
@@ -104,6 +143,7 @@ meta_test_orientation_manager_accelerometer_orientations (void)
     {
       changed_called = FALSE;
       meta_sensors_proxy_mock_set_orientation (orientation_mock, i);
+      wait_for_orientation_changes (manager);
 
       g_debug ("Checking orientation %d", i);
       g_assert_cmpuint (meta_orientation_manager_get_orientation (manager),
diff --git a/src/tests/orientation-manager-unit-tests.h b/src/tests/orientation-manager-unit-tests.h
index 34b175f0ce..56eff09d1d 100644
--- a/src/tests/orientation-manager-unit-tests.h
+++ b/src/tests/orientation-manager-unit-tests.h
@@ -21,6 +21,10 @@
 #ifndef ORIENTATION_MANAGER_UNIT_TESTS_H
 #define ORIENTATION_MANAGER_UNIT_TESTS_H
 
+#include "backends/meta-orientation-manager.h"
+
 void init_orientation_manager_tests (void);
 
+void wait_for_orientation_changes (MetaOrientationManager *orientation_manager);
+
 #endif /* ORIENTATION_MANAGER_UNIT_TESTS_H */


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