diff --git a/src/tests/native-kms-hotplug.c b/src/tests/native-kms-hotplug.c index d52ed7a6e..4a6f2e0aa 100644 --- a/src/tests/native-kms-hotplug.c +++ b/src/tests/native-kms-hotplug.c @@ -18,7 +18,10 @@ #include "config.h" #include "backends/meta-monitor-manager-private.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" typedef enum _State { @@ -91,11 +94,126 @@ meta_test_reload (void) g_signal_handler_disconnect (stage, presented_handler_id); } +static void +disconnect_connector_filter (gpointer resource, + gpointer user_data) +{ + drmModeConnector *drm_connector = resource; + + drm_connector->connection = DRM_MODE_DISCONNECTED; +} + +static void +frame_cb (CoglOnscreen *onscreen, + CoglFrameEvent frame_event, + CoglFrameInfo *frame_info, + void *user_data) +{ + State *state = user_data; + + if (frame_event == COGL_FRAME_EVENT_SYNC) + return; + + if (*state == PAINTED) + *state = PRESENTED; +} + +static void +meta_test_disconnect_connect (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); + MetaUdev *udev = meta_backend_native_get_udev (META_BACKEND_NATIVE (backend)); + g_autolist (GObject) udev_devices = NULL; + GUdevDevice *udev_device; + GList *logical_monitors; + gulong after_paint_handler_id; + gulong presented_handler_id; + ClutterStageView *view; + CoglFramebuffer *onscreen; + g_autoptr (GError) error = NULL; + State state; + + udev_devices = meta_udev_list_drm_devices (udev, &error); + g_assert_cmpuint (g_list_length (udev_devices), ==, 1); + udev_device = g_list_first (udev_devices)->data; + + logical_monitors = + meta_monitor_manager_get_logical_monitors (monitor_manager); + g_assert_cmpuint (g_list_length (logical_monitors), ==, 1); + + 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_debug ("Disconnect during page flip"); + view = clutter_stage_peek_stage_views (CLUTTER_STAGE (stage))->data; + onscreen = clutter_stage_view_get_onscreen (view); + g_assert_true (COGL_IS_ONSCREEN (onscreen)); + state = INIT; + clutter_actor_queue_redraw (stage); + while (state < PAINTED) + g_main_context_iteration (NULL, TRUE); + drm_mock_set_resource_filter (DRM_MOCK_CALL_FILTER_GET_CONNECTOR, + disconnect_connector_filter, NULL); + g_signal_emit_by_name (udev, "hotplug", udev_device); + logical_monitors = + meta_monitor_manager_get_logical_monitors (monitor_manager); + g_assert_cmpuint (g_list_length (logical_monitors), ==, 0); + + g_debug ("Wait until page flip completes"); + cogl_onscreen_add_frame_callback (COGL_ONSCREEN (onscreen), + frame_cb, &state, NULL); + while (state < PRESENTED) + g_main_context_iteration (NULL, TRUE); + + g_debug ("Reconnect connector, wait for presented"); + drm_mock_unset_resource_filter (DRM_MOCK_CALL_FILTER_GET_CONNECTOR); + g_signal_emit_by_name (udev, "hotplug", udev_device); + logical_monitors = + meta_monitor_manager_get_logical_monitors (monitor_manager); + g_assert_cmpuint (g_list_length (logical_monitors), ==, 1); + state = INIT; + clutter_actor_queue_redraw (stage); + while (state < PRESENTED) + g_main_context_iteration (NULL, TRUE); + + g_debug ("Disconnect after page flip"); + drm_mock_set_resource_filter (DRM_MOCK_CALL_FILTER_GET_CONNECTOR, + disconnect_connector_filter, NULL); + g_signal_emit_by_name (udev, "hotplug", udev_device); + logical_monitors = + meta_monitor_manager_get_logical_monitors (monitor_manager); + g_assert_cmpuint (g_list_length (logical_monitors), ==, 0); + while (TRUE) + { + if (!g_main_context_iteration (NULL, FALSE)) + break; + } + + g_debug ("Restore"); + drm_mock_unset_resource_filter (DRM_MOCK_CALL_FILTER_GET_CONNECTOR); + g_signal_emit_by_name (udev, "hotplug", udev_device); + logical_monitors = + meta_monitor_manager_get_logical_monitors (monitor_manager); + g_assert_cmpuint (g_list_length (logical_monitors), ==, 1); + + g_signal_handler_disconnect (stage, after_paint_handler_id); + g_signal_handler_disconnect (stage, presented_handler_id); +} + static void init_tests (void) { g_test_add_func ("/hotplug/reload", meta_test_reload); + g_test_add_func ("/hotplug/disconnect-connect", + meta_test_disconnect_connect); } int