From d5f397977efcf67ec3c38832a5c123ccb3c4eb83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Mon, 4 May 2020 22:47:34 +0200 Subject: [PATCH] monitor-unit-tests: Add tests with dynamic orientation changes Verify monitors disposition when we have rotation changes coming from MetaOrientationManager, using our mock dbus implementation. Part-of: --- src/backends/meta-backend-private.h | 2 + src/backends/meta-monitor-manager-private.h | 1 + src/tests/meta-backend-test.c | 94 ++ src/tests/meta-backend-test.h | 11 + src/tests/monitor-unit-tests.c | 1294 +++++++++++++++++++ 5 files changed, 1402 insertions(+) diff --git a/src/backends/meta-backend-private.h b/src/backends/meta-backend-private.h index 81104e2d0..555239157 100644 --- a/src/backends/meta-backend-private.h +++ b/src/backends/meta-backend-private.h @@ -112,6 +112,7 @@ void meta_backend_destroy (MetaBackend *backend); void meta_backend_prepare_shutdown (MetaBackend *backend); +META_EXPORT_TEST ClutterBackend * meta_backend_get_clutter_backend (MetaBackend *backend); ClutterSeat * meta_backend_get_default_seat (MetaBackend *bakcend); @@ -123,6 +124,7 @@ MetaIdleManager * meta_backend_get_idle_manager (MetaBackend *backend); META_EXPORT_TEST MetaMonitorManager * meta_backend_get_monitor_manager (MetaBackend *backend); +META_EXPORT_TEST MetaOrientationManager * meta_backend_get_orientation_manager (MetaBackend *backend); MetaCursorTracker * meta_backend_get_cursor_tracker (MetaBackend *backend); MetaCursorRenderer * meta_backend_get_cursor_renderer_for_device (MetaBackend *backend, diff --git a/src/backends/meta-monitor-manager-private.h b/src/backends/meta-monitor-manager-private.h index a05a7231e..dd12ab050 100644 --- a/src/backends/meta-monitor-manager-private.h +++ b/src/backends/meta-monitor-manager-private.h @@ -305,6 +305,7 @@ MetaLogicalMonitor *meta_monitor_manager_get_logical_monitor_neighbor (MetaMonit MetaMonitor * meta_monitor_manager_get_primary_monitor (MetaMonitorManager *manager); +META_EXPORT_TEST MetaMonitor * meta_monitor_manager_get_laptop_panel (MetaMonitorManager *manager); MetaMonitor * meta_monitor_manager_get_monitor_from_spec (MetaMonitorManager *manager, diff --git a/src/tests/meta-backend-test.c b/src/tests/meta-backend-test.c index 0bc30d04d..576990386 100644 --- a/src/tests/meta-backend-test.c +++ b/src/tests/meta-backend-test.c @@ -81,6 +81,100 @@ meta_backend_test_create_monitor_manager (MetaBackend *backend, NULL); } +ClutterInputDevice * +meta_backend_test_add_test_device (MetaBackendTest *backend_test, + const char *name, + ClutterInputDeviceType device_type, + int n_buttons) +{ + g_autoptr (GList) devices = NULL; + MetaBackend *backend = META_BACKEND (backend_test); + ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); + ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend); + ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); + ClutterInputDevice *device; + ClutterEvent *event; + const char *product_id; + bool has_cursor = TRUE; + + switch (device_type) + { + case CLUTTER_POINTER_DEVICE: + product_id = "MetaTestPointer"; + break; + case CLUTTER_KEYBOARD_DEVICE: + product_id = "MetaTestKeyboard"; + has_cursor = FALSE; + break; + case CLUTTER_EXTENSION_DEVICE: + product_id = "MetaTestExtension"; + has_cursor = FALSE; + break; + case CLUTTER_JOYSTICK_DEVICE: + product_id = "MetaTestJoystick"; + break; + case CLUTTER_TABLET_DEVICE: + product_id = "MetaTestTablet"; + break; + case CLUTTER_TOUCHPAD_DEVICE: + product_id = "MetaTestTouchpad"; + break; + case CLUTTER_TOUCHSCREEN_DEVICE: + product_id = "MetaTestTouchscreen"; + break; + case CLUTTER_PEN_DEVICE: + product_id = "MetaTestPen"; + break; + case CLUTTER_ERASER_DEVICE: + product_id = "MetaTestEraser"; + break; + case CLUTTER_CURSOR_DEVICE: + product_id = "MetaTestCursor"; + break; + case CLUTTER_PAD_DEVICE: + product_id = "MetaTestPad"; + has_cursor = FALSE; + break; + + default: + g_assert_not_reached (); + } + + device = g_object_new (CLUTTER_TYPE_INPUT_DEVICE, + "name", name, + "device-type", CLUTTER_TOUCHSCREEN_DEVICE, + "seat", seat, + "has-cursor", has_cursor, + "backend", clutter_backend, + "vendor-id", "MetaTest", + "product-id", product_id, + "n-buttons", n_buttons, + NULL); + + event = clutter_event_new (CLUTTER_DEVICE_ADDED); + clutter_event_set_device (event, device); + clutter_event_set_stage (event, stage); + clutter_event_put (event); + clutter_event_free (event); + + return device; +} + +void +meta_backend_test_remove_device (MetaBackendTest *backend_test, + ClutterInputDevice *device) +{ + MetaBackend *backend = META_BACKEND (backend_test); + ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); + ClutterEvent *event; + + event = clutter_event_new (CLUTTER_DEVICE_REMOVED); + clutter_event_set_device (event, device); + clutter_event_set_stage (event, stage); + clutter_event_put (event); + clutter_event_free (event); +} + static void meta_backend_test_class_init (MetaBackendTestClass *klass) { diff --git a/src/tests/meta-backend-test.h b/src/tests/meta-backend-test.h index ad57a42e8..abf87aeb3 100644 --- a/src/tests/meta-backend-test.h +++ b/src/tests/meta-backend-test.h @@ -34,4 +34,15 @@ void meta_backend_test_set_is_lid_closed (MetaBackendTest *backend_test, META_EXPORT MetaGpu * meta_backend_test_get_gpu (MetaBackendTest *backend_test); +META_EXPORT_TEST +ClutterInputDevice * meta_backend_test_add_test_device (MetaBackendTest *backend, + const char *name, + ClutterInputDeviceType device_type, + int n_buttons); + +META_EXPORT_TEST +void meta_backend_test_remove_device (MetaBackendTest *backend, + ClutterInputDevice *device); + + #endif /* META_BACKEND_TEST_H */ diff --git a/src/tests/monitor-unit-tests.c b/src/tests/monitor-unit-tests.c index dff80cbc9..73cff8c7f 100644 --- a/src/tests/monitor-unit-tests.c +++ b/src/tests/monitor-unit-tests.c @@ -27,10 +27,12 @@ #include "backends/meta-monitor.h" #include "backends/meta-monitor-config-migration.h" #include "backends/meta-monitor-config-store.h" +#include "backends/meta-orientation-manager.h" #include "backends/meta-output.h" #include "core/window-private.h" #include "meta-backend-test.h" #include "tests/meta-monitor-manager-test.h" +#include "tests/meta-sensors-proxy-mock.h" #include "tests/monitor-test-utils.h" #include "tests/meta-test-utils.h" #include "tests/unit-tests.h" @@ -3493,6 +3495,1283 @@ meta_test_monitor_switch_external_without_external (void) check_monitor_test_clients_state (); } +static void +check_monitor_configuration_per_orientation (MonitorTestCaseExpect *base_expect, + unsigned int monitor_index, + MetaOrientation orientation, + int width, + int height) +{ + MetaMonitorTransform transform; + MonitorTestCaseExpect expect = *base_expect; + int i = 0; + + transform = meta_monitor_transform_from_orientation (orientation); + expect.logical_monitors[monitor_index].transform = transform; + expect.crtcs[monitor_index].transform = transform; + + if (meta_monitor_transform_is_rotated (transform)) + { + expect.logical_monitors[monitor_index].layout.width = height; + expect.logical_monitors[monitor_index].layout.height = width; + } + else + { + expect.logical_monitors[monitor_index].layout.width = width; + expect.logical_monitors[monitor_index].layout.height = height; + } + + expect.screen_width = 0; + expect.screen_height = 0; + + for (i = 0; i < expect.n_logical_monitors; ++i) + { + MonitorTestCaseLogicalMonitor *monitor = + &expect.logical_monitors[i]; + int right_edge; + int bottom_edge; + + g_debug ("Got monitor %dx%d : %dx%d", monitor->layout.x, + monitor->layout.y, monitor->layout.width, monitor->layout.height); + + right_edge = (monitor->layout.width + monitor->layout.x); + if (right_edge > expect.screen_width) + expect.screen_width = right_edge; + + bottom_edge = (monitor->layout.height + monitor->layout.y); + if (bottom_edge > expect.screen_height) + expect.screen_height = bottom_edge; + } + + check_monitor_configuration (&expect); + check_monitor_test_clients_state (); +} + +typedef MetaSensorsProxyMock MetaSensorsProxyAutoResetMock; +static void +meta_sensors_proxy_reset (MetaSensorsProxyMock *proxy) +{ + meta_sensors_proxy_mock_set_orientation (proxy, + META_ORIENTATION_NORMAL); + g_object_unref (proxy); +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaSensorsProxyAutoResetMock, + meta_sensors_proxy_reset) + +static ClutterInputDevice * +meta_test_add_touch_device (MetaBackend * backend) +{ + MetaBackendTest *backend_test = META_BACKEND_TEST (backend); + ClutterInputDevice *device; + + device = meta_backend_test_add_test_device (backend_test, "test-touchscreen", + CLUTTER_TOUCHSCREEN_DEVICE, 1); + + g_assert_true (CLUTTER_IS_INPUT_DEVICE (device)); + g_assert_cmpuint (clutter_input_device_get_device_type (device), + ==, + CLUTTER_TOUCHSCREEN_DEVICE); + + return device; +} + +typedef ClutterInputDevice ClutterAutoRemoveInputDevice; +static void +input_device_test_remove (ClutterAutoRemoveInputDevice *device) +{ + MetaBackend *backend = meta_get_backend (); + + meta_backend_test_remove_device (META_BACKEND_TEST (backend), device); + g_object_unref (device); +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterAutoRemoveInputDevice, + input_device_test_remove) + +static void +meta_test_monitor_orientation_is_managed (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 = FALSE, + } + }, + .n_outputs = 1, + .crtcs = { + { + .current_mode = 0 + } + }, + .n_crtcs = 1 + }, + + .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 + } + }, + .n_monitors = 1, + .logical_monitors = { + { + .monitors = { 0 }, + .n_monitors = 1, + .layout = { .x = 0, .y = 0, .width = 1024, .height = 768 }, + .scale = 1 + } + }, + .n_logical_monitors = 1, + .primary_logical_monitor = 0, + .n_outputs = 1, + .crtcs = { + { + .current_mode = 0, + }, + }, + .n_crtcs = 1, + .n_tiled_monitors = 0, + .screen_width = 1024, + .screen_height = 768 + } + }; + MetaMonitorTestSetup *test_setup; + MetaBackend *backend = meta_get_backend (); + MetaOrientationManager *orientation_manager = + meta_backend_get_orientation_manager (backend); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); + ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend); + g_autoptr (ClutterAutoRemoveInputDevice) touch_device = NULL; + g_autoptr (MetaSensorsProxyAutoResetMock) orientation_mock = NULL; + + test_setup = create_monitor_test_setup (&test_case.setup, + MONITOR_TEST_FLAG_NO_STORED); + + g_assert_false ( + meta_monitor_manager_get_panel_orientation_managed (monitor_manager)); + + emulate_hotplug (test_setup); + check_monitor_configuration (&test_case.expect); + check_monitor_test_clients_state (); + + g_assert_false ( + meta_monitor_manager_get_panel_orientation_managed (monitor_manager)); + + g_assert_null (meta_monitor_manager_get_laptop_panel (monitor_manager)); + test_case.setup.outputs[0].is_laptop_panel = TRUE; + test_setup = create_monitor_test_setup (&test_case.setup, + MONITOR_TEST_FLAG_NO_STORED); + emulate_hotplug (test_setup); + g_assert_nonnull (meta_monitor_manager_get_laptop_panel (monitor_manager)); + + g_assert_false (clutter_seat_get_touch_mode (seat)); + touch_device = meta_test_add_touch_device (backend); + + while (!clutter_seat_get_touch_mode (seat)) + g_main_context_iteration (NULL, FALSE); + + g_assert_true (clutter_seat_get_touch_mode (seat)); + g_assert_false ( + meta_monitor_manager_get_panel_orientation_managed (monitor_manager)); + + orientation_mock = meta_sensors_proxy_mock_get (); + g_assert_false ( + meta_orientation_manager_has_accelerometer (orientation_manager)); + g_assert_false ( + meta_monitor_manager_get_panel_orientation_managed (monitor_manager)); + + meta_sensors_proxy_mock_set_property (orientation_mock, "HasAccelerometer", + g_variant_new_boolean (TRUE)); + + while (!meta_orientation_manager_has_accelerometer (orientation_manager)) + g_main_context_iteration (NULL, FALSE); + + g_assert_true ( + meta_orientation_manager_has_accelerometer (orientation_manager)); + g_assert_true ( + meta_monitor_manager_get_panel_orientation_managed (monitor_manager)); + + test_case.setup.outputs[0].is_laptop_panel = FALSE; + test_setup = create_monitor_test_setup (&test_case.setup, + MONITOR_TEST_FLAG_NO_STORED); + emulate_hotplug (test_setup); + g_assert_null (meta_monitor_manager_get_laptop_panel (monitor_manager)); + g_assert_false ( + meta_monitor_manager_get_panel_orientation_managed (monitor_manager)); + + test_case.setup.outputs[0].is_laptop_panel = TRUE; + test_setup = create_monitor_test_setup (&test_case.setup, + MONITOR_TEST_FLAG_NO_STORED); + emulate_hotplug (test_setup); + g_assert_nonnull (meta_monitor_manager_get_laptop_panel (monitor_manager)); + g_assert_true ( + meta_monitor_manager_get_panel_orientation_managed (monitor_manager)); + + meta_sensors_proxy_mock_set_property (orientation_mock, "HasAccelerometer", + g_variant_new_boolean (FALSE)); + + while (meta_orientation_manager_has_accelerometer (orientation_manager)) + g_main_context_iteration (NULL, FALSE); + + g_assert_false ( + meta_monitor_manager_get_panel_orientation_managed (monitor_manager)); + + meta_sensors_proxy_mock_set_property (orientation_mock, "HasAccelerometer", + g_variant_new_boolean (TRUE)); + + while (!meta_orientation_manager_has_accelerometer (orientation_manager)) + g_main_context_iteration (NULL, FALSE); + + g_assert_true ( + meta_monitor_manager_get_panel_orientation_managed (monitor_manager)); + + meta_backend_test_remove_device (META_BACKEND_TEST (backend), touch_device); + g_clear_object (&touch_device); + + while (clutter_seat_get_touch_mode (seat)) + g_main_context_iteration (NULL, FALSE); + + g_assert_false (clutter_seat_get_touch_mode (seat)); + g_assert_false ( + meta_monitor_manager_get_panel_orientation_managed (monitor_manager)); + + touch_device = meta_test_add_touch_device (backend); + + while (!clutter_seat_get_touch_mode (seat)) + g_main_context_iteration (NULL, FALSE); + + g_assert_true (clutter_seat_get_touch_mode (seat)); + g_assert_true ( + meta_monitor_manager_get_panel_orientation_managed (monitor_manager)); +} + +static void +meta_test_monitor_orientation_initial_rotated (void) +{ + MonitorTestCase test_case = { + .setup = { + .modes = { + { + .width = 1024, + .height = 768, + .refresh_rate = 60.000495910644531 + } + }, + .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 + }, + }, + .n_outputs = 1, + .crtcs = { + { + .current_mode = 0 + }, + }, + .n_crtcs = 1 + }, + + .expect = { + .monitors = { + { + .outputs = { 0 }, + .n_outputs = 1, + .modes = { + { + .width = 1024, + .height = 768, + .refresh_rate = 60.000495910644531, + .crtc_modes = { + { + .output = 0, + .crtc_mode = 0 + } + } + } + }, + .n_modes = 1, + .current_mode = 0, + .width_mm = 222, + .height_mm = 125, + } + }, + .n_monitors = 1, + .logical_monitors = { + { + .monitors = { 0 }, + .n_monitors = 1, + .layout = { .x = 0, .y = 0, .width = 1024, .height = 768 }, + .scale = 1 + } + }, + .n_logical_monitors = 1, + .primary_logical_monitor = 0, + .n_outputs = 1, + .crtcs = { + { + .current_mode = 0, + } + }, + .n_crtcs = 1, + .n_tiled_monitors = 0, + .screen_width = 1024, + .screen_height = 768 + } + }; + MetaMonitorTestSetup *test_setup; + MetaBackend *backend = meta_get_backend (); + MetaOrientationManager *orientation_manager = + meta_backend_get_orientation_manager (backend); + g_autoptr (MetaSensorsProxyAutoResetMock) orientation_mock = NULL; + g_autoptr (ClutterAutoRemoveInputDevice) touch_device = NULL; + MetaOrientation orientation; + + orientation_mock = meta_sensors_proxy_mock_get (); + touch_device = meta_test_add_touch_device (backend); + orientation = META_ORIENTATION_LEFT_UP; + meta_sensors_proxy_mock_set_orientation (orientation_mock, orientation); + g_assert_cmpuint ( + meta_orientation_manager_get_orientation (orientation_manager), + ==, + orientation); + + test_setup = create_monitor_test_setup (&test_case.setup, + MONITOR_TEST_FLAG_NO_STORED); + emulate_hotplug (test_setup); + + META_TEST_LOG_CALL ("Checking configuration per orientation", + check_monitor_configuration_per_orientation ( + &test_case.expect, 0, orientation, 1024, 768)); +} + +static void +meta_test_monitor_orientation_initial_rotated_no_touch_mode (void) +{ + MonitorTestCase test_case = { + .setup = { + .modes = { + { + .width = 1024, + .height = 768, + .refresh_rate = 60.000495910644531 + } + }, + .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 + }, + }, + .n_outputs = 1, + .crtcs = { + { + .current_mode = 0 + }, + }, + .n_crtcs = 1 + }, + + .expect = { + .monitors = { + { + .outputs = { 0 }, + .n_outputs = 1, + .modes = { + { + .width = 1024, + .height = 768, + .refresh_rate = 60.000495910644531, + .crtc_modes = { + { + .output = 0, + .crtc_mode = 0 + } + } + } + }, + .n_modes = 1, + .current_mode = 0, + .width_mm = 222, + .height_mm = 125, + } + }, + .n_monitors = 1, + .logical_monitors = { + { + .monitors = { 0 }, + .n_monitors = 1, + .layout = { .x = 0, .y = 0, .width = 1024, .height = 768 }, + .scale = 1 + } + }, + .n_logical_monitors = 1, + .primary_logical_monitor = 0, + .n_outputs = 1, + .crtcs = { + { + .current_mode = 0, + } + }, + .n_crtcs = 1, + .n_tiled_monitors = 0, + .screen_width = 1024, + .screen_height = 768 + } + }; + MetaMonitorTestSetup *test_setup; + MetaBackend *backend = meta_get_backend (); + MetaOrientationManager *orientation_manager = + meta_backend_get_orientation_manager (backend); + g_autoptr (MetaSensorsProxyAutoResetMock) orientation_mock = NULL; + MetaOrientation orientation; + + orientation_mock = meta_sensors_proxy_mock_get (); + orientation = META_ORIENTATION_LEFT_UP; + meta_sensors_proxy_mock_set_orientation (orientation_mock, orientation); + g_assert_cmpuint ( + meta_orientation_manager_get_orientation (orientation_manager), + ==, + orientation); + + test_setup = create_monitor_test_setup (&test_case.setup, + MONITOR_TEST_FLAG_NO_STORED); + emulate_hotplug (test_setup); + + META_TEST_LOG_CALL ("Checking configuration per orientation", + check_monitor_configuration_per_orientation ( + &test_case.expect, 0, META_ORIENTATION_NORMAL, 1024, 768)); +} + +static void +meta_test_monitor_orientation_initial_stored_rotated (void) +{ + MonitorTestCase test_case = { + .setup = { + .modes = { + { + .width = 1920, + .height = 1080, + .refresh_rate = 60.000495910644531 + } + }, + .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 + }, + }, + .n_outputs = 1, + .crtcs = { + { + .current_mode = 0 + }, + }, + .n_crtcs = 1 + }, + + .expect = { + .monitors = { + { + .outputs = { 0 }, + .n_outputs = 1, + .modes = { + { + .width = 1920, + .height = 1080, + .refresh_rate = 60.000495910644531, + .crtc_modes = { + { + .output = 0, + .crtc_mode = 0 + } + } + } + }, + .n_modes = 1, + .current_mode = 0, + .width_mm = 222, + .height_mm = 125, + } + }, + .n_monitors = 1, + .logical_monitors = { + { + .monitors = { 0 }, + .n_monitors = 1, + .layout = { .x = 0, .y = 0, .width = 960, .height = 540 }, + .scale = 2 + } + }, + .n_logical_monitors = 1, + .primary_logical_monitor = 0, + .n_outputs = 1, + .crtcs = { + { + .current_mode = 0, + } + }, + .n_crtcs = 1, + .n_tiled_monitors = 0, + .screen_width = 960, + .screen_height = 540 + } + }; + MetaMonitorTestSetup *test_setup; + MetaBackend *backend = meta_get_backend (); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + MetaOrientationManager *orientation_manager = + meta_backend_get_orientation_manager (backend); + g_autoptr (MetaSensorsProxyAutoResetMock) orientation_mock = NULL; + g_autoptr (ClutterAutoRemoveInputDevice) touch_device = NULL; + MetaOrientation orientation; + + if (!meta_is_stage_views_enabled ()) + { + g_test_skip ("Not using stage views"); + return; + } + + orientation_mock = meta_sensors_proxy_mock_get (); + touch_device = meta_test_add_touch_device (backend); + orientation = META_ORIENTATION_RIGHT_UP; + meta_sensors_proxy_mock_set_orientation (orientation_mock, orientation); + g_assert_cmpuint ( + meta_orientation_manager_get_orientation (orientation_manager), + ==, + orientation); + + test_setup = create_monitor_test_setup (&test_case.setup, + MONITOR_TEST_FLAG_NONE); + set_custom_monitor_config ("lid-scale.xml"); + emulate_hotplug (test_setup); + + + META_TEST_LOG_CALL ("Checking configuration per orientation", + check_monitor_configuration_per_orientation ( + &test_case.expect, 0, orientation, 960, 540)); + + meta_backend_test_set_is_lid_closed (META_BACKEND_TEST (backend), TRUE); + meta_monitor_manager_lid_is_closed_changed (monitor_manager); + + + META_TEST_LOG_CALL ("Checking configuration per orientation", + check_monitor_configuration_per_orientation ( + &test_case.expect, 0, orientation, 960, 540)); + + orientation = META_ORIENTATION_LEFT_UP; + meta_sensors_proxy_mock_set_orientation (orientation_mock, orientation); + + meta_backend_test_set_is_lid_closed (META_BACKEND_TEST (backend), FALSE); + meta_monitor_manager_lid_is_closed_changed (monitor_manager); + + + META_TEST_LOG_CALL ("Checking configuration per orientation", + check_monitor_configuration_per_orientation ( + &test_case.expect, 0, orientation, 960, 540)); + + /* When no touch device is available, the orientation change is ignored */ + meta_backend_test_remove_device (META_BACKEND_TEST (backend), touch_device); + + orientation = META_ORIENTATION_RIGHT_UP; + meta_sensors_proxy_mock_set_orientation (orientation_mock, orientation); + g_assert_cmpuint ( + meta_orientation_manager_get_orientation (orientation_manager), + ==, + orientation); + + META_TEST_LOG_CALL ("Checking configuration per orientation", + check_monitor_configuration_per_orientation ( + &test_case.expect, 0, META_ORIENTATION_LEFT_UP, + 960, 540)); +} + +static void +meta_test_monitor_orientation_initial_stored_rotated_no_touch (void) +{ + MonitorTestCase test_case = { + .setup = { + .modes = { + { + .width = 1920, + .height = 1080, + .refresh_rate = 60.000495910644531 + } + }, + .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 + }, + }, + .n_outputs = 1, + .crtcs = { + { + .current_mode = 0 + }, + }, + .n_crtcs = 1 + }, + + .expect = { + .monitors = { + { + .outputs = { 0 }, + .n_outputs = 1, + .modes = { + { + .width = 1920, + .height = 1080, + .refresh_rate = 60.000495910644531, + .crtc_modes = { + { + .output = 0, + .crtc_mode = 0 + } + } + } + }, + .n_modes = 1, + .current_mode = 0, + .width_mm = 222, + .height_mm = 125, + } + }, + .n_monitors = 1, + .logical_monitors = { + { + .monitors = { 0 }, + .n_monitors = 1, + .layout = { .x = 0, .y = 0, .width = 960, .height = 540 }, + .scale = 2 + } + }, + .n_logical_monitors = 1, + .primary_logical_monitor = 0, + .n_outputs = 1, + .crtcs = { + { + .current_mode = 0, + } + }, + .n_crtcs = 1, + .n_tiled_monitors = 0, + .screen_width = 960, + .screen_height = 540 + } + }; + MetaMonitorTestSetup *test_setup; + MetaBackend *backend = meta_get_backend (); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + MetaOrientationManager *orientation_manager = + meta_backend_get_orientation_manager (backend); + g_autoptr (MetaSensorsProxyAutoResetMock) orientation_mock = NULL; + MetaOrientation orientation; + + if (!meta_is_stage_views_enabled ()) + { + g_test_skip ("Not using stage views"); + return; + } + + orientation_mock = meta_sensors_proxy_mock_get (); + orientation = META_ORIENTATION_RIGHT_UP; + meta_sensors_proxy_mock_set_orientation (orientation_mock, orientation); + g_assert_cmpuint ( + meta_orientation_manager_get_orientation (orientation_manager), + ==, + orientation); + + test_setup = create_monitor_test_setup (&test_case.setup, + MONITOR_TEST_FLAG_NONE); + set_custom_monitor_config ("lid-scale.xml"); + emulate_hotplug (test_setup); + + + META_TEST_LOG_CALL ("Checking configuration per orientation", + check_monitor_configuration_per_orientation ( + &test_case.expect, 0, META_ORIENTATION_NORMAL, + 960, 540)); + + meta_backend_test_set_is_lid_closed (META_BACKEND_TEST (backend), TRUE); + meta_monitor_manager_lid_is_closed_changed (monitor_manager); + + + META_TEST_LOG_CALL ("Checking configuration per orientation", + check_monitor_configuration_per_orientation ( + &test_case.expect, 0, META_ORIENTATION_NORMAL, + 960, 540)); +} + +static void +meta_test_monitor_orientation_changes (void) +{ + MonitorTestCase test_case = { + .setup = { + .modes = { + { + .width = 1024, + .height = 768, + .refresh_rate = 60.000495910644531 + } + }, + .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 + }, + }, + .n_outputs = 1, + .crtcs = { + { + .current_mode = 0 + }, + }, + .n_crtcs = 1 + }, + + .expect = { + .monitors = { + { + .outputs = { 0 }, + .n_outputs = 1, + .modes = { + { + .width = 1024, + .height = 768, + .refresh_rate = 60.000495910644531, + .crtc_modes = { + { + .output = 0, + .crtc_mode = 0 + } + } + } + }, + .n_modes = 1, + .current_mode = 0, + .width_mm = 222, + .height_mm = 125, + } + }, + .n_monitors = 1, + .logical_monitors = { + { + .monitors = { 0 }, + .n_monitors = 1, + .layout = { .x = 0, .y = 0, .width = 1024, .height = 768 }, + .scale = 1 + } + }, + .n_logical_monitors = 1, + .primary_logical_monitor = 0, + .n_outputs = 1, + .crtcs = { + { + .current_mode = 0, + } + }, + .n_crtcs = 1, + .n_tiled_monitors = 0, + .screen_width = 1024, + .screen_height = 768 + } + }; + MetaMonitorTestSetup *test_setup; + MetaBackend *backend = meta_get_backend (); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + MetaMonitorConfigManager *config_manager = monitor_manager->config_manager; + MetaOrientationManager *orientation_manager = + meta_backend_get_orientation_manager (backend); + g_autoptr (ClutterAutoRemoveInputDevice) touch_device = NULL; + g_autoptr (MetaSensorsProxyAutoResetMock) orientation_mock = NULL; + g_autoptr (MetaMonitorsConfig) initial_config = NULL; + g_autoptr (MetaMonitorsConfig) previous_config = NULL; + MetaOrientation i; + + orientation_mock = meta_sensors_proxy_mock_get (); + touch_device = meta_test_add_touch_device (backend); + test_setup = create_monitor_test_setup (&test_case.setup, + MONITOR_TEST_FLAG_NO_STORED); + emulate_hotplug (test_setup); + + g_set_object (&previous_config, + meta_monitor_config_manager_get_previous (config_manager)); + g_set_object (&initial_config, + meta_monitor_config_manager_get_current (config_manager)); + + g_assert_cmpuint ( + meta_orientation_manager_get_orientation (orientation_manager), + ==, + META_ORIENTATION_UNDEFINED); + + for (i = META_N_ORIENTATIONS - 1; i > META_ORIENTATION_UNDEFINED; i--) + { + MetaMonitorsConfig *current; + MetaMonitorsConfig *previous; + + meta_sensors_proxy_mock_set_orientation (orientation_mock, i); + g_assert_cmpuint ( + meta_orientation_manager_get_orientation (orientation_manager), + ==, i); + + META_TEST_LOG_CALL ("Checking configuration per orientation", + check_monitor_configuration_per_orientation ( + &test_case.expect, 0, i, 1024, 768)); + + current = meta_monitor_config_manager_get_current (config_manager); + previous = meta_monitor_config_manager_get_previous (config_manager); + + g_assert (previous == previous_config); + g_assert (current != initial_config); + g_assert_true (meta_monitors_config_key_equal (current->key, + initial_config->key)); + } + + /* Ensure applying the current orientation doesn't change the config */ + g_assert_cmpuint ( + meta_orientation_manager_get_orientation (orientation_manager), + ==, + META_ORIENTATION_NORMAL); + + g_set_object (&initial_config, + meta_monitor_config_manager_get_current (config_manager)); + + meta_sensors_proxy_mock_set_orientation (orientation_mock, + META_ORIENTATION_NORMAL); + META_TEST_LOG_CALL ("Checking configuration per orientation", + check_monitor_configuration_per_orientation ( + &test_case.expect, 0, META_ORIENTATION_NORMAL, + 1024, 768)); + + g_assert (meta_monitor_config_manager_get_current (config_manager) == + initial_config); + + /* When no touch device is available, the orientation changes are ignored */ + meta_backend_test_remove_device (META_BACKEND_TEST (backend), touch_device); + + for (i = META_N_ORIENTATIONS - 1; i > META_ORIENTATION_UNDEFINED; i--) + { + MetaMonitorsConfig *current; + MetaMonitorsConfig *previous; + + meta_sensors_proxy_mock_set_orientation (orientation_mock, i); + g_assert_cmpuint ( + meta_orientation_manager_get_orientation (orientation_manager), + ==, i); + + META_TEST_LOG_CALL ("Checking configuration per orientation", + check_monitor_configuration_per_orientation ( + &test_case.expect, 0, META_ORIENTATION_NORMAL, + 1024, 768)); + + current = meta_monitor_config_manager_get_current (config_manager); + previous = meta_monitor_config_manager_get_previous (config_manager); + + g_assert (previous == previous_config); + g_assert (current == initial_config); + g_assert_true (meta_monitors_config_key_equal (current->key, + initial_config->key)); + } +} + +static void +meta_test_monitor_orientation_changes_with_hotplugging (void) +{ + MonitorTestCase test_case = { + .setup = { + .modes = { + { + .width = 1024, + .height = 768, + .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 = 220, + .height_mm = 124 + } + }, + .n_outputs = 1, /* Second is hotplugged later */ + .crtcs = { + { + .current_mode = -1 + }, + { + .current_mode = -1 + } + }, + .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 = 220, + .height_mm = 124 + } + }, + .n_monitors = 1, /* Second is hotplugged later */ + .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, + .transform = META_MONITOR_TRANSFORM_NORMAL, + } + }, + .n_logical_monitors = 1, /* Second is hotplugged later */ + .primary_logical_monitor = 0, + .n_outputs = 1, + .crtcs = { + { + .current_mode = 0, + }, + { + .current_mode = -1, + .transform = META_MONITOR_TRANSFORM_NORMAL, + } + }, + .n_crtcs = 2, + .n_tiled_monitors = 0, + .screen_width = 1024, + .screen_height = 768 + } + }; + MetaMonitorTestSetup *test_setup; + MetaBackend *backend = meta_get_backend (); + MetaOrientationManager *orientation_manager = + meta_backend_get_orientation_manager (backend); + g_autoptr (ClutterAutoRemoveInputDevice) touch_device = NULL; + g_autoptr (MetaSensorsProxyAutoResetMock) orientation_mock = NULL; + MetaOrientation i; + + orientation_mock = meta_sensors_proxy_mock_get (); + touch_device = meta_test_add_touch_device (backend); + + /* + * The first part of this test emulate the following: + * 1) Start with the lid open + * 2) Rotate the device in all directions + * 3) Connect external monitor + * 4) Rotate the device in all directions + * 5) Close lid + */ + + test_setup = create_monitor_test_setup (&test_case.setup, + MONITOR_TEST_FLAG_NO_STORED); + meta_backend_test_set_is_lid_closed (META_BACKEND_TEST (backend), FALSE); + + emulate_hotplug (test_setup); + check_monitor_configuration (&test_case.expect); + + for (i = META_N_ORIENTATIONS - 1; i > META_ORIENTATION_UNDEFINED; i--) + { + meta_sensors_proxy_mock_set_orientation (orientation_mock, i); + g_assert_cmpuint ( + meta_orientation_manager_get_orientation (orientation_manager), + ==, i); + + META_TEST_LOG_CALL ("Checking configuration per orientation", + check_monitor_configuration_per_orientation ( + &test_case.expect, 0, i, 1024, 768)); + } + + meta_sensors_proxy_mock_set_orientation (orientation_mock, + META_ORIENTATION_NORMAL); + check_monitor_configuration (&test_case.expect); + + /* External monitor connected */ + test_case.setup.n_outputs = 2; + test_case.expect.n_outputs = 2; + test_case.expect.n_monitors = 2; + test_case.expect.n_logical_monitors = 2; + test_case.expect.crtcs[1].current_mode = 0; + test_case.expect.crtcs[1].x = 1024; + test_case.expect.screen_width = 1024 * 2; + + test_setup = create_monitor_test_setup (&test_case.setup, + MONITOR_TEST_FLAG_NO_STORED); + emulate_hotplug (test_setup); + check_monitor_configuration (&test_case.expect); + + /* Rotate the monitor in all the directions */ + for (i = META_N_ORIENTATIONS - 1; i > META_ORIENTATION_UNDEFINED; i--) + { + meta_sensors_proxy_mock_set_orientation (orientation_mock, i); + g_assert_cmpuint ( + meta_orientation_manager_get_orientation (orientation_manager), + ==, i); + + META_TEST_LOG_CALL ("Checking configuration per orientation", + check_monitor_configuration_per_orientation ( + &test_case.expect, 0, i, 1024, 768)); + } + + meta_sensors_proxy_mock_set_orientation (orientation_mock, + META_ORIENTATION_NORMAL); + check_monitor_configuration (&test_case.expect); + + /* Lid closed */ + test_case.expect.monitors[0].current_mode = -1; + test_case.expect.logical_monitors[0].monitors[0] = 1, + test_case.expect.n_logical_monitors = 1; + test_case.expect.crtcs[0].current_mode = -1; + test_case.expect.crtcs[1].x = 0; + test_case.expect.screen_width = 1024; + + test_setup = create_monitor_test_setup (&test_case.setup, + MONITOR_TEST_FLAG_NO_STORED); + meta_backend_test_set_is_lid_closed (META_BACKEND_TEST (backend), TRUE); + emulate_hotplug (test_setup); + + /* Rotate the monitor in all the directions */ + for (i = META_N_ORIENTATIONS - 1; i > META_ORIENTATION_UNDEFINED; i--) + { + meta_sensors_proxy_mock_set_orientation (orientation_mock, i); + check_monitor_configuration (&test_case.expect); + } + + meta_sensors_proxy_mock_set_orientation (orientation_mock, + META_ORIENTATION_NORMAL); + + /* + * The second part of this test emulate the following at each device rotation: + * 1) Open lid + * 2) Close lid + * 3) Change orientation + * 4) Reopen the lid + * 2) Disconnect external monitor + */ + + /* Lid opened */ + test_case.expect.monitors[0].current_mode = 0; + test_case.expect.logical_monitors[0].monitors[0] = 0, + test_case.expect.logical_monitors[1].monitors[0] = 1, + test_case.expect.n_logical_monitors = 2; + test_case.expect.crtcs[0].current_mode = 0; + test_case.expect.crtcs[1].x = 1024; + test_case.expect.screen_width = 1024 * 2; + + test_setup = create_monitor_test_setup (&test_case.setup, + MONITOR_TEST_FLAG_NO_STORED); + meta_backend_test_set_is_lid_closed (META_BACKEND_TEST (backend), FALSE); + emulate_hotplug (test_setup); + check_monitor_configuration (&test_case.expect); + + for (i = META_N_ORIENTATIONS - 1; i > META_ORIENTATION_UNDEFINED; i--) + { + /* Closing lid */ + test_case.expect.monitors[0].current_mode = -1; + test_case.expect.logical_monitors[0].monitors[0] = 1, + test_case.expect.n_logical_monitors = 1; + test_case.expect.crtcs[0].current_mode = -1; + test_case.expect.crtcs[1].x = 0; + test_case.expect.screen_width = 1024; + + test_setup = create_monitor_test_setup (&test_case.setup, + MONITOR_TEST_FLAG_NO_STORED); + meta_backend_test_set_is_lid_closed (META_BACKEND_TEST (backend), TRUE); + emulate_hotplug (test_setup); + + /* Change orientation */ + meta_sensors_proxy_mock_set_orientation (orientation_mock, i); + check_monitor_configuration (&test_case.expect); + + /* Open the lid */ + test_case.expect.monitors[0].current_mode = 0; + test_case.expect.logical_monitors[0].monitors[0] = 0, + test_case.expect.logical_monitors[1].monitors[0] = 1, + test_case.expect.n_logical_monitors = 2; + test_case.expect.crtcs[0].current_mode = 0; + test_case.expect.crtcs[1].x = 1024; + + test_setup = create_monitor_test_setup (&test_case.setup, + MONITOR_TEST_FLAG_NO_STORED); + meta_backend_test_set_is_lid_closed (META_BACKEND_TEST (backend), FALSE); + emulate_hotplug (test_setup); + + META_TEST_LOG_CALL ("Checking configuration per orientation", + check_monitor_configuration_per_orientation ( + &test_case.expect, 0, i, 1024, 768)); + + /* External monitor disconnected */ + test_case.setup.n_outputs = 1; + test_case.expect.n_outputs = 1; + test_case.expect.n_monitors = 1; + test_case.expect.n_logical_monitors = 1; + test_case.expect.crtcs[1].current_mode = -1; + + test_setup = create_monitor_test_setup (&test_case.setup, + MONITOR_TEST_FLAG_NO_STORED); + emulate_hotplug (test_setup); + META_TEST_LOG_CALL ("Checking configuration per orientation", + check_monitor_configuration_per_orientation ( + &test_case.expect, 0, i, 1024, 768)); + + /* External monitor connected */ + test_case.setup.n_outputs = 2; + test_case.expect.n_outputs = 2; + test_case.expect.n_monitors = 2; + test_case.expect.n_logical_monitors = 2; + test_case.expect.crtcs[1].current_mode = 0; + test_case.expect.crtcs[1].x = 1024; + + test_setup = create_monitor_test_setup (&test_case.setup, + MONITOR_TEST_FLAG_NO_STORED); + emulate_hotplug (test_setup); + META_TEST_LOG_CALL ("Checking configuration per orientation", + check_monitor_configuration_per_orientation ( + &test_case.expect, 0, i, 1024, 768)); + } + + meta_sensors_proxy_mock_set_orientation (orientation_mock, + META_ORIENTATION_NORMAL); +} + static void meta_test_monitor_custom_vertical_config (void) { @@ -7285,6 +8564,21 @@ init_monitor_tests (void) add_monitor_test ("/backends/monitor/switch-external-without-external", meta_test_monitor_switch_external_without_external); + add_monitor_test ("/backends/monitor/orientation/is-managed", + meta_test_monitor_orientation_is_managed); + add_monitor_test ("/backends/monitor/orientation/initial-rotated", + meta_test_monitor_orientation_initial_rotated); + add_monitor_test ("/backends/monitor/orientation/initial-rotated-no-touch", + meta_test_monitor_orientation_initial_rotated_no_touch_mode); + add_monitor_test ("/backends/monitor/orientation/initial-stored-rotated", + meta_test_monitor_orientation_initial_stored_rotated); + add_monitor_test ("/backends/monitor/orientation/initial-stored-rotated-no-touch", + meta_test_monitor_orientation_initial_stored_rotated_no_touch); + add_monitor_test ("/backends/monitor/orientation/changes", + meta_test_monitor_orientation_changes); + add_monitor_test ("/backends/monitor/orientation/changes-with-hotplugging", + meta_test_monitor_orientation_changes_with_hotplugging); + add_monitor_test ("/backends/monitor/custom/vertical-config", meta_test_monitor_custom_vertical_config); add_monitor_test ("/backends/monitor/custom/primary-config",