diff --git a/tests/seat_test.c b/tests/seat_test.c index 2b445ec..8517bb5 100644 --- a/tests/seat_test.c +++ b/tests/seat_test.c @@ -20,39 +20,83 @@ along with 12to11. If not, see . */ #include "test_harness.h" #include +#include enum test_expect_event_kind { POINTER_ENTER_EVENT, POINTER_FRAME_EVENT, POINTER_MOTION_EVENT, + POINTER_LEAVE_EVENT, + POINTER_BUTTON_EVENT, }; -struct test_expect_data +struct test_recorded_event { - /* The coordinates of the event. */ - double x, y; - - /* What kind of event is being waited for. */ + /* What kind of event this is. */ enum test_expect_event_kind kind; - /* Whether or not the expected event arrived. */ - bool arrived; + /* The last event. */ + struct test_recorded_event *last; +}; + +struct test_recorded_enter_event +{ + /* The event header. */ + struct test_recorded_event header; + + /* The surface of the event. */ + struct wl_surface *surface; + + /* The coordinates of the event. */ + double x, y; +}; + +struct test_recorded_frame_event +{ + /* The event header. */ + struct test_recorded_event header; +}; + +struct test_recorded_motion_event +{ + /* The event header. */ + struct test_recorded_event header; + + /* The coordinates of the event. */ + double x, y; +}; + +struct test_recorded_leave_event +{ + /* The event header. */ + struct test_recorded_event header; +}; + +struct test_recorded_button_event +{ + /* The event header. */ + struct test_recorded_event header; + + /* The button and state. */ + uint32_t button, state; }; enum test_kind { MAP_WINDOW_KIND, TEST_ENTRY_KIND, + TEST_CLICK_KIND, }; static const char *test_names[] = { "map_window", "test_entry", + "test_click", }; -#define LAST_TEST TEST_ENTRY_KIND +#define LAST_TEST TEST_CLICK_KIND #define TEST_SOURCE_DEVICE 4500000 /* The display. */ @@ -71,11 +115,11 @@ static Window test_surface_window; static struct test_surface *test_surface; static struct wl_surface *wayland_surface; -/* How many elements are in the current listener data. */ -static int num_listener_data; +/* Whether or not events are being recorded. */ +static bool recording_events; -/* The current listener data. */ -struct test_expect_data *current_listener_data; +/* If so, the tail of the event list. */ +static struct test_recorded_event *record_tail; @@ -83,6 +127,13 @@ struct test_expect_data *current_listener_data; static void submit_surface_damage (struct wl_surface *, int, int, int, int); static void expect_surface_enter (double, double); static void expect_surface_motion (double, double); +static void record_events (void); +static void expect_frame_event (void); +static void expect_enter_event (double, double); +static void expect_motion_event (double, double); +static void expect_leave_event (void); +static void expect_button_event (int, int); +static void expect_no_events (void); @@ -110,11 +161,148 @@ test_get_root (void) +static void +run_click_test (struct test_XIButtonState *button_state) +{ + /* First, get all events that should already have arrived. */ + wl_display_roundtrip (display->display); + + /* Next, dispatch the button press events. */ + test_seat_controller_dispatch_XI_ButtonPress (display->seat->controller, + test_get_time (), + TEST_SOURCE_DEVICE, + 1, + test_get_root (), + test_surface_window, + None, + wl_fixed_from_double (1.0), + wl_fixed_from_double (2.0), + wl_fixed_from_double (1.0), + wl_fixed_from_double (2.0), + 0, + button_state, + NULL, NULL, NULL); + test_XIButtonState_add_button (button_state, 1); + + test_seat_controller_dispatch_XI_ButtonPress (display->seat->controller, + test_get_time (), + TEST_SOURCE_DEVICE, + 2, + test_get_root (), + test_surface_window, + None, + wl_fixed_from_double (1.0), + wl_fixed_from_double (2.0), + wl_fixed_from_double (1.0), + wl_fixed_from_double (2.0), + 0, + button_state, + NULL, NULL, NULL); + test_XIButtonState_add_button (button_state, 2); + + /* Now, dispatch the motion and leave events. */ + test_seat_controller_dispatch_XI_Motion (display->seat->controller, + test_get_time (), + TEST_SOURCE_DEVICE, + 0, + test_get_root (), + test_surface_window, + None, + wl_fixed_from_double (550.0), + wl_fixed_from_double (550.0), + wl_fixed_from_double (550.0), + wl_fixed_from_double (550.0), + 0, + button_state, + NULL, NULL, NULL); + test_seat_controller_dispatch_XI_Leave (display->seat->controller, + test_get_time (), + TEST_SOURCE_DEVICE, + XINotifyAncestor, + test_get_root (), + test_surface_window, + None, + wl_fixed_from_double (550.0), + wl_fixed_from_double (550.0), + wl_fixed_from_double (550.0), + wl_fixed_from_double (550.0), + XINotifyNormal, + False, True, + button_state, NULL, NULL); + + /* And release the buttons. */ + test_seat_controller_dispatch_XI_ButtonRelease (display->seat->controller, + test_get_time (), + TEST_SOURCE_DEVICE, + 1, + test_get_root (), + test_surface_window, + None, + wl_fixed_from_double (550.0), + wl_fixed_from_double (550.0), + wl_fixed_from_double (550.0), + wl_fixed_from_double (550.0), + 0, + button_state, + NULL, NULL, NULL); + test_XIButtonState_remove_button (button_state, 2); + + test_seat_controller_dispatch_XI_ButtonRelease (display->seat->controller, + test_get_time (), + TEST_SOURCE_DEVICE, + 2, + test_get_root (), + test_surface_window, + None, + wl_fixed_from_double (550.0), + wl_fixed_from_double (550.0), + wl_fixed_from_double (550.0), + wl_fixed_from_double (550.0), + 0, + button_state, + NULL, NULL, NULL); + test_XIButtonState_remove_button (button_state, 1); + + /* Send the ungrab leave event. */ + test_seat_controller_dispatch_XI_Leave (display->seat->controller, + test_get_time (), + TEST_SOURCE_DEVICE, + XINotifyAncestor, + test_get_root (), + test_surface_window, + None, + wl_fixed_from_double (550.0), + wl_fixed_from_double (550.0), + wl_fixed_from_double (550.0), + wl_fixed_from_double (550.0), + XINotifyUngrab, + False, True, + button_state, NULL, NULL); + + /* Now, verify the events that arrive. */ + record_events (); + expect_frame_event (); + expect_leave_event (); + expect_frame_event (); + expect_button_event (BTN_MIDDLE, WL_POINTER_BUTTON_STATE_RELEASED); + expect_frame_event (); + expect_button_event (BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED); + expect_frame_event (); + expect_motion_event (550.0, 550.0); + expect_frame_event (); + expect_button_event (BTN_MIDDLE, WL_POINTER_BUTTON_STATE_PRESSED); + expect_frame_event (); + expect_button_event (BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED); + expect_no_events (); +} + static void test_single_step (enum test_kind kind) { struct wl_buffer *buffer; + struct test_XIButtonState *button_state; + again: test_log ("running test step: %s", test_names[kind]); switch (kind) @@ -169,7 +357,39 @@ test_single_step (enum test_kind kind) /* Expect mouse motion at the specified coordinates. */ expect_surface_motion (1.0, 2.0); - break; + + /* Run the click test. */ + kind = TEST_CLICK_KIND; + goto again; + + case TEST_CLICK_KIND: + /* Test clicking and grab processing. Press buttons 1 and 2, + dispatch a motion event at 550, 550, a NotifyNormal leave + event at 550, 550, and finally button release events for both + buttons followed by a NotifyUngrab leave event. Verify that + only the following events are sent in the given order: + + button (SERIAL, TIME, BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED) + frame () + button (SERIAL, TIME, BTN_MIDDLE, WL_POINTER_BUTTON_STATE_PRESSED) + frame () + motion (TIME, 550.0, 550.0) + frame () + button (SERIAL, TIME, BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED) + frame () + button (SERIAL, TIME, BTN_MIDDLE, WL_POINTER_BUTTON_STATE_RELEASED) + frame () + leave () + frame () */ + + /* Initialize the button state. */ + button_state + = test_seat_controller_get_XIButtonState (display->seat->controller); + + if (!button_state) + report_test_failure ("failed to obtain button state resource"); + + run_click_test (button_state); } if (kind == LAST_TEST) @@ -178,62 +398,164 @@ test_single_step (enum test_kind kind) +/* Record events previously sent to the seat's pointer or keyboard + device, and place them into `record_tail'. */ + +static void +record_events (void) +{ + recording_events = true; + wl_display_roundtrip (display->display); + recording_events = false; +} + +static void +expect_frame_event (void) +{ + struct test_recorded_event *event; + + event = record_tail; + + if (!event) + report_test_failure ("expected event not sent"); + + record_tail = event->last; + + if (event->kind == POINTER_FRAME_EVENT) + free (event); + else + report_test_failure ("a frame event was expected, but not received"); +} + +static void +expect_enter_event (double x, double y) +{ + struct test_recorded_event *event; + struct test_recorded_enter_event *enter; + + event = record_tail; + + if (!event) + report_test_failure ("expected event not sent"); + + record_tail = event->last; + + if (event->kind == POINTER_ENTER_EVENT) + { + enter = (struct test_recorded_enter_event *) event; + + if (enter->x == x && enter->y == y) + free (event); + else + report_test_failure ("expected enter event received " + "with incorrect coordinates"); + } + else + report_test_failure ("expected enter event, but it was not received"); +} + +static void +expect_motion_event (double x, double y) +{ + struct test_recorded_event *event; + struct test_recorded_motion_event *motion; + + event = record_tail; + + if (!event) + report_test_failure ("expected event not sent"); + + record_tail = event->last; + + if (event->kind == POINTER_MOTION_EVENT) + { + motion = (struct test_recorded_motion_event *) event; + + if (motion->x == x && motion->y == y) + free (event); + else + report_test_failure ("expected motion event received " + "with incorrect coordinates"); + } + else + report_test_failure ("expected motion event, but it was not received"); +} + +static void +expect_leave_event (void) +{ + struct test_recorded_event *event; + + event = record_tail; + + if (!event) + report_test_failure ("expected event not sent"); + + record_tail = event->last; + + if (event->kind == POINTER_LEAVE_EVENT) + free (event); + else + report_test_failure ("a leave event was expected, but not received"); +} + +static void +expect_button_event (int button, int state) +{ + struct test_recorded_event *event; + struct test_recorded_button_event *button_event; + + event = record_tail; + + if (!event) + report_test_failure ("expected event not sent"); + + record_tail = event->last; + + if (event->kind == POINTER_BUTTON_EVENT) + { + button_event = (struct test_recorded_button_event *) event; + + if (button_event->button == button && button_event->state == state) + free (event); + else + report_test_failure ("expected button event received " + "with incorrect parameters"); + } + else + report_test_failure ("expected button event, but it was not received"); +} + +static void +expect_no_events (void) +{ + if (record_tail) + report_test_failure ("expected there to be no more events, " + "yet some arrived"); +} + static void expect_surface_enter (double x, double y) { - struct test_expect_data data[2]; + /* Record events. */ + record_events (); - test_log ("waiting for enter at %g, %g", x, y); - - memset (data, 0, sizeof data); - - data[0].x = x; - data[0].y = y; - data[0].kind = POINTER_ENTER_EVENT; - data[1].kind = POINTER_FRAME_EVENT; - - /* Set the current listener data and do a roundtrip. */ - current_listener_data = data; - num_listener_data = 2; - - wl_display_roundtrip (display->display); - current_listener_data = NULL; - num_listener_data = 0; - - /* See whether or not the event arrived. */ - if (!data[0].arrived || !data[1].arrived) - report_test_failure ("expected events did not arrive"); - else - test_log ("received enter followed by frame"); + /* Expect an enter event, followed by a frame event. */ + expect_frame_event (); + expect_enter_event (x, y); + expect_no_events (); } static void expect_surface_motion (double x, double y) { - struct test_expect_data data[2]; + /* Record events. */ + record_events (); - test_log ("waiting for motion at %g, %g", x, y); - - memset (data, 0, sizeof data); - - data[0].x = x; - data[0].y = y; - data[0].kind = POINTER_MOTION_EVENT; - data[1].kind = POINTER_FRAME_EVENT; - - /* Set the current listener data and do a roundtrip. */ - current_listener_data = data; - num_listener_data = 2; - - wl_display_roundtrip (display->display); - current_listener_data = NULL; - num_listener_data = 0; - - /* See whether or not the event arrived. */ - if (!data[0].arrived || !data[1].arrived) - report_test_failure ("expected events did not arrive"); - else - test_log ("received motion followed by frame"); + /* Expect a motion event followed by a frame event. */ + expect_frame_event (); + expect_motion_event (x, y); + expect_no_events (); } @@ -260,36 +582,14 @@ static const struct test_surface_listener test_surface_listener = -/* Obtain the next test data record. The events arriving are checked - to be in the order in which they arrive in - current_listener_data. */ - -static struct test_expect_data * -get_next_expect_data (void) -{ - int i; - - for (i = 0; i < num_listener_data; ++i) - { - if (current_listener_data[i].arrived) - continue; - - return ¤t_listener_data[i]; - } - - return NULL; -} - static void handle_pointer_enter (void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { - struct test_expect_data *test_data; + struct test_recorded_enter_event *event; - test_data = get_next_expect_data (); - - if (!test_data) + if (!recording_events) { test_log ("ignored enter event at %g %g", wl_fixed_to_double (surface_x), @@ -297,26 +597,40 @@ handle_pointer_enter (void *data, struct wl_pointer *wl_pointer, return; } - if (test_data->kind != POINTER_ENTER_EVENT) - return; + event = malloc (sizeof *event); - test_log ("got enter event at %g, %g", - wl_fixed_to_double (surface_x), - wl_fixed_to_double (surface_y)); + if (!event) + report_test_failure ("failed to record event"); - if (test_data->x == wl_fixed_to_double (surface_x) - && test_data->y == wl_fixed_to_double (surface_y)) - test_data->arrived = true; - else - report_test_failure ("missed enter event at %g %g", - test_data->x, test_data->y); + event->header.kind = POINTER_ENTER_EVENT; + event->header.last = record_tail; + record_tail = &event->header; + + event->x = wl_fixed_to_double (surface_x); + event->y = wl_fixed_to_double (surface_x); + event->surface = surface; } static void handle_pointer_leave (void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface) { - /* ... */ + struct test_recorded_leave_event *event; + + if (!recording_events) + { + test_log ("ignored leave event"); + return; + } + + event = malloc (sizeof *event); + + if (!event) + report_test_failure ("failed to record event"); + + event->header.kind = POINTER_LEAVE_EVENT; + event->header.last = record_tail; + record_tail = &event->header; } static void @@ -324,11 +638,9 @@ handle_pointer_motion (void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { - struct test_expect_data *test_data; + struct test_recorded_motion_event *event; - test_data = get_next_expect_data (); - - if (!test_data) + if (!recording_events) { test_log ("ignored motion event at %g %g", wl_fixed_to_double (surface_x), @@ -336,19 +648,17 @@ handle_pointer_motion (void *data, struct wl_pointer *wl_pointer, return; } - if (test_data->kind != POINTER_MOTION_EVENT) - return; + event = malloc (sizeof *event); - test_log ("got motion event at %g, %g", - wl_fixed_to_double (surface_x), - wl_fixed_to_double (surface_y)); + if (!event) + report_test_failure ("failed to record event"); - if (test_data->x == wl_fixed_to_double (surface_x) - && test_data->y == wl_fixed_to_double (surface_y)) - test_data->arrived = true; - else - report_test_failure ("missed motion event at %g %g", - test_data->x, test_data->y); + event->header.kind = POINTER_MOTION_EVENT; + event->header.last = record_tail; + record_tail = &event->header; + + event->x = wl_fixed_to_double (surface_x); + event->y = wl_fixed_to_double (surface_y); } static void @@ -356,7 +666,34 @@ handle_pointer_button (void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { - /* TODO... */ + struct test_recorded_button_event *event; + + if (!recording_events) + { + test_log ("ignored button event"); + return; + } + + event = malloc (sizeof *event); + + if (!event) + report_test_failure ("failed to record event"); + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" +#endif + + event->header.kind = POINTER_BUTTON_EVENT; + event->header.last = record_tail; + record_tail = &event->header; + + event->button = button; + event->state = state; + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif } static void @@ -369,21 +706,31 @@ handle_pointer_axis (void *data, struct wl_pointer *wl_pointer, static void handle_pointer_frame (void *data, struct wl_pointer *wl_pointer) { - struct test_expect_data *test_data; + struct test_recorded_frame_event *event; - test_data = get_next_expect_data (); - - if (!test_data) + if (!recording_events) { test_log ("ignored frame event"); return; } - if (test_data->kind != POINTER_FRAME_EVENT) - return; + event = malloc (sizeof *event); - test_log ("got frame event"); - test_data->arrived = true; + if (!event) + report_test_failure ("failed to record event"); + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" +#endif + + event->header.kind = POINTER_FRAME_EVENT; + event->header.last = record_tail; + record_tail = &event->header; + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif } static void