#include "config.h" #include #include #include #include "util-io.h" #include "util-munit.h" #include "util-memfile.h" #include "libei.h" #include "eierpecken.h" DEFINE_UNREF_CLEANUP_FUNC(peck); DEFINE_TRIVIAL_CLEANUP_FUNC(struct memfile *, memfile_unref); #define _cleanup_memfile_ _cleanup_(memfile_unrefp) MUNIT_TEST(test_ei_ref_unref) { struct ei *ei = ei_new(NULL); struct ei *refd = ei_ref(ei); munit_assert_ptr_equal(ei, refd); struct ei *unrefd = ei_unref(ei); munit_assert_ptr_null(unrefd); unrefd = ei_unref(ei); munit_assert_ptr_null(unrefd); /* memleak only shows up in valgrind */ return MUNIT_OK; } MUNIT_TEST(test_ei_disconnect_immediately) { _unref_(peck) *peck = peck_new(); /* Client is immediately rejected */ peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_REJECT_CLIENT); peck_dispatch_until_stable(peck); /* Expect the client to get a disconnect event */ with_client(peck) { ei_dispatch(ei); _unref_(ei_event) *disconnect = peck_ei_next_event(ei, EI_EVENT_DISCONNECT); } return MUNIT_OK; } MUNIT_TEST(test_ei_disconnect_after_connect) { _unref_(peck) *peck = peck_new(); _unref_(eis_client) *client = NULL; peck_dispatch_until_stable(peck); with_server(peck) { eis_dispatch(eis); _unref_(eis_event) *e = peck_eis_next_event(eis, EIS_EVENT_CLIENT_CONNECT); client = eis_client_ref(eis_event_get_client(e)); eis_client_connect(client); } with_client(peck) { ei_dispatch(ei); _unref_(ei_event) *e = peck_ei_next_event(ei, EI_EVENT_CONNECT); } with_server(peck) { eis_client_disconnect(client); } with_client(peck) { ei_dispatch(ei); _unref_(ei_event) *e = peck_ei_next_event(ei, EI_EVENT_DISCONNECT); } return MUNIT_OK; } MUNIT_TEST(test_ei_disconnect_after_add_before_received) { _unref_(peck) *peck = peck_new(); _unref_(eis_client) *client = NULL; peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_dispatch_until_stable(peck); with_client(peck) { struct ei_seat *seat = peck_ei_get_default_seat(peck); _unref_(ei_device) *device = ei_device_new(seat); ei_device_configure_name(device, __func__); ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER); ei_device_add(device); } /* We have *not* called eis_dispatch, so the device add hasn't been * processed by the server yet */ with_server(peck) { struct eis_client *client = peck_eis_get_default_client(peck); eis_client_disconnect(client); } with_client(peck) { ei_dispatch(ei); _unref_(ei_event) *device_removed = peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED); _unref_(ei_event) *seat_removed = peck_ei_next_event(ei, EI_EVENT_SEAT_REMOVED); _unref_(ei_event) *disconnect = peck_ei_next_event(ei, EI_EVENT_DISCONNECT); } return MUNIT_OK; } MUNIT_TEST(test_ei_disconnect_after_add_after_received) { _unref_(peck) *peck = peck_new(); _unref_(eis_client) *client = NULL; peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DEFAULT_SEAT); peck_dispatch_until_stable(peck); with_client(peck) { struct ei_seat *seat = peck_ei_get_default_seat(peck); _unref_(ei_device) *device = ei_device_new(seat); ei_device_configure_name(device, __func__); ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER); ei_device_add(device); } /* Receive the Added event but don't actually add the device */ peck_dispatch_eis(peck); with_server(peck) { struct eis_client *client = peck_eis_get_default_client(peck); eis_client_disconnect(client); } with_client(peck) { ei_dispatch(ei); _unref_(ei_event) *device_removed = peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED); _unref_(ei_event) *seat_removed = peck_ei_next_event(ei, EI_EVENT_SEAT_REMOVED); _unref_(ei_event) *disconnect = peck_ei_next_event(ei, EI_EVENT_DISCONNECT); } return MUNIT_OK; } MUNIT_TEST(test_ei_disconnect_after_remove_before_received) { _unref_(peck) *peck = peck_new(); _unref_(ei_device) *device = NULL; peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DEFAULT_SEAT); peck_dispatch_until_stable(peck); with_client(peck) { struct ei_seat *seat = peck_ei_get_default_seat(peck); device = ei_device_new(seat); ei_device_configure_name(device, __func__); ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER); ei_device_add(device); } peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); /* server has the device now */ peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_event) *added = peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED); _unref_(ei_event) *resumed = peck_ei_next_event(ei, EI_EVENT_DEVICE_RESUMED); ei_device_remove(device); } /* No server dispatch here so the server isn't aware of the * ei_device_remove() call. Disconnect the client, this * automatically removes all devices */ with_server(peck) { struct eis_client *client = peck_eis_get_default_client(peck); eis_client_disconnect(client); } with_client(peck) { ei_dispatch(ei); _unref_(ei_event) *device_removed = peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED); _unref_(ei_event) *seat_removed = peck_ei_next_event(ei, EI_EVENT_SEAT_REMOVED); _unref_(ei_event) *disconnect = peck_ei_next_event(ei, EI_EVENT_DISCONNECT); } return MUNIT_OK; } MUNIT_TEST(test_ei_disconnect_after_remove_after_received) { _unref_(peck) *peck = peck_new(); _unref_(ei_device) *device = NULL; peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_dispatch_until_stable(peck); with_client(peck) { struct ei_seat *seat = peck_ei_get_default_seat(peck); device = ei_device_new(seat); ei_device_configure_name(device, __func__); ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER); ei_device_add(device); } /* server has the device now */ peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_event) *added = peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED); _unref_(ei_event) *resumed = peck_ei_next_event(ei, EI_EVENT_DEVICE_RESUMED); ei_device_remove(device); } /* Dispatch, server is aware of the ei_device_remove() */ peck_dispatch_eis(peck); with_server(peck) { struct eis_client *client = peck_eis_get_default_client(peck); eis_client_disconnect(client); } peck_dispatch_ei(peck); with_client(peck) { _unref_(ei_event) *device_removed = peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED); _unref_(ei_event) *seat_removed = peck_ei_next_event(ei, EI_EVENT_SEAT_REMOVED); _unref_(ei_event) *disconnect = peck_ei_next_event(ei, EI_EVENT_DISCONNECT); } return MUNIT_OK; } MUNIT_TEST(test_ei_device_basics) { _unref_(peck) *peck = peck_new(); _unref_(ei_device) *device = NULL; peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_dispatch_until_stable(peck); /* device creation and getters/setters test */ with_client(peck) { struct ei_seat *seat = peck_ei_get_default_seat(peck); device = ei_device_new(seat); munit_assert_not_null(device); ei_device_configure_name(device, __func__); munit_assert_string_equal(ei_device_get_name(device), __func__); bool success = ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER); munit_assert(success); munit_assert(ei_device_has_capability(device, EI_DEVICE_CAP_POINTER)); /* Add it, but we don't care about whether it worked correctly in this test */ ei_device_add(device); /* Device is immutable after ei_device_add() */ bool failed_caps = ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER); munit_assert(failed_caps == false); munit_assert(ei_device_has_capability(device, EI_DEVICE_CAP_POINTER)); } /* Drain both sides, we don't care about the events themselves */ with_server(peck) { peck_drain_eis(eis); } with_client(peck) { peck_drain_ei(ei); } /* device is still immutable */ with_client(peck) { bool failed_caps = ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER); munit_assert(failed_caps == false); munit_assert(ei_device_has_capability(device, EI_DEVICE_CAP_POINTER)); } return MUNIT_OK; } MUNIT_TEST(test_ei_device_set_name) { _unref_(peck) *peck = peck_new(); _unref_(ei_device) *d1 = NULL; _unref_(ei_device) *d2 = NULL; _unref_(ei_device) *d3 = NULL; peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DEFAULT_SEAT); peck_dispatch_until_stable(peck); with_client(peck) { struct ei_seat *seat = peck_ei_get_default_seat(peck); d1 = ei_device_new(seat); ei_device_configure_name(d1, "first device"); ei_device_configure_capability(d1, EI_DEVICE_CAP_POINTER); ei_device_add(d1); d2 = ei_device_new(seat); munit_assert_not_null(d2); ei_device_configure_name(d2, "second device"); ei_device_configure_capability(d2, EI_DEVICE_CAP_POINTER); ei_device_add(d2); d3 = ei_device_new(seat); munit_assert_not_null(d3); ei_device_configure_name(d3, "third device"); ei_device_configure_capability(d3, EI_DEVICE_CAP_POINTER); ei_device_add(d3); } peck_dispatch_until_stable(peck); with_server(peck) { _unref_(eis_event) *e1 = peck_eis_next_event(eis, EIS_EVENT_DEVICE_ADDED); struct eis_device *d1 = eis_event_get_device(e1); munit_assert_string_equal(eis_device_get_name(d1), "first device"); /* change the name */ eis_device_set_name(d1, "other name"); munit_assert_string_equal(eis_device_get_name(d1), "other name"); eis_device_allow_capability(d1, EIS_DEVICE_CAP_POINTER); eis_device_connect(d1); _unref_(eis_event) *e2 = peck_eis_next_event(eis, EIS_EVENT_DEVICE_ADDED); struct eis_device *d2 = eis_event_get_device(e2); munit_assert_string_equal(eis_device_get_name(d2), "second device"); /* unset the name */ eis_device_set_name(d2, NULL); munit_assert_ptr_null(eis_device_get_name(d2)); eis_device_allow_capability(d2, EIS_DEVICE_CAP_POINTER); eis_device_connect(d2); _unref_(eis_event) *e3 = peck_eis_next_event(eis, EIS_EVENT_DEVICE_ADDED); struct eis_device *d3 = eis_event_get_device(e3); munit_assert_string_equal(eis_device_get_name(d3), "third device"); /* leave the name as-is */ eis_device_allow_capability(d3, EIS_DEVICE_CAP_POINTER); eis_device_connect(d3); } peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_event) *e1 = peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED); munit_assert_ptr_equal(d1, ei_event_get_device(e1)); munit_assert_string_equal(ei_device_get_name(d1), "other name"); _unref_(ei_event) *e2 = peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED); munit_assert_ptr_equal(d2, ei_event_get_device(e2)); munit_assert_ptr_null(ei_device_get_name(d2)); _unref_(ei_event) *e3 = peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED); munit_assert_ptr_equal(d3, ei_event_get_device(e3)); munit_assert_string_equal(ei_device_get_name(d3), "third device"); } return MUNIT_OK; } MUNIT_TEST(test_ei_device_add_remove) { _unref_(peck) *peck = peck_new(); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DEFAULT_SEAT); peck_dispatch_until_stable(peck); _unref_(ei_device) *device = NULL; with_client(peck) { struct ei_seat *seat = peck_ei_get_default_seat(peck); device = ei_device_new(seat); ei_device_configure_name(device, __func__); ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER); ei_device_add(device); } peck_dispatch_until_stable(peck); _unref_(eis_device) *eis_device = NULL; with_server(peck) { _unref_(eis_event) *event = peck_eis_next_event(eis, EIS_EVENT_DEVICE_ADDED); eis_device = eis_device_ref(eis_event_get_device(event)); eis_device_allow_capability(eis_device, EIS_DEVICE_CAP_POINTER); eis_device_connect(eis_device); } with_client(peck) { peck_dispatch_ei(peck); _unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED); struct ei_device *added = ei_event_get_device(event); munit_assert_ptr_equal(device, added); munit_assert(ei_device_has_capability(added, EI_DEVICE_CAP_POINTER)); ei_device_remove(device); } with_server(peck) { peck_dispatch_eis(peck); _unref_(eis_event) *event = peck_eis_next_event(eis, EIS_EVENT_DEVICE_REMOVED); munit_assert_ptr_equal(eis_event_get_device(event), eis_device); eis_device_disconnect(eis_device); } with_client(peck) { peck_dispatch_ei(peck); _unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED); struct ei_device *removed = ei_event_get_device(event); munit_assert_ptr_equal(device, removed); } return MUNIT_OK; } MUNIT_TEST(test_ei_device_remove_forget_disconnect) { _unref_(peck) *peck = peck_new(); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTODEVICES); peck_dispatch_until_stable(peck); _unref_(ei_device) *d1 = NULL; _unref_(ei_device) *d2 = NULL; with_client(peck) { struct ei_seat *seat = peck_ei_get_default_seat(peck); d1 = ei_device_new(seat); ei_device_configure_name(d1, "first"); ei_device_configure_capability(d1, EI_DEVICE_CAP_POINTER); ei_device_add(d1); d2 = ei_device_new(seat); ei_device_configure_name(d2, "second"); ei_device_configure_capability(d2, EI_DEVICE_CAP_KEYBOARD); ei_device_add(d2); } peck_dispatch_until_stable(peck); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_NONE); with_client(peck) { /* remove in order d1, d2 */ ei_device_remove(d1); ei_device_remove(d2); } peck_dispatch_until_stable(peck); with_server(peck) { _unref_(eis_event) *e1 = peck_eis_next_event(eis, EIS_EVENT_DEVICE_REMOVED); _unref_(eis_event) *e2 = peck_eis_next_event(eis, EIS_EVENT_DEVICE_REMOVED); /* Explicitly disconnect device d2 */ eis_device_disconnect(eis_event_get_device(e2)); /* But don't eis_device_disconnect(d1). It doesn't matter * because libeis will do this for us when receiving the * event. */ } peck_dispatch_ei(peck); with_client(peck) { _unref_(ei_event) *e1 = peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED); struct ei_device *r1 = ei_event_get_device(e1); munit_assert_ptr_equal(d1, r1); _unref_(ei_event) *e2 = peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED); struct ei_device *r2 = ei_event_get_device(e2); munit_assert_ptr_equal(d2, r2); peck_assert_no_ei_events(ei); } return MUNIT_OK; } MUNIT_TEST(test_ei_device_add_drop_caps) { _unref_(peck) *peck = peck_new(); /* Device with pointer and keyboard caps but pointer is dropped */ peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DROP_POINTER); peck_dispatch_until_stable(peck); _unref_(ei_device) *device = NULL; with_client(peck) { struct ei_seat *seat = peck_ei_get_default_seat(peck); device = ei_device_new(seat); ei_device_configure_name(device, __func__); ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER); ei_device_configure_capability(device, EI_DEVICE_CAP_KEYBOARD); ei_device_add(device); } peck_dispatch_eis(peck); with_client(peck) { ei_dispatch(ei); _unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED); struct ei_device *d = ei_event_get_device(event); munit_assert_ptr_equal(d, device); munit_assert(ei_device_has_capability(d, EI_DEVICE_CAP_KEYBOARD)); munit_assert(!ei_device_has_capability(d, EI_DEVICE_CAP_POINTER)); } return MUNIT_OK; } MUNIT_TEST(test_ei_device_add_zero_caps) { _unref_(peck) *peck = peck_new(); /* Device with pointer caps but those caps are rejected -> device immediately removed by EIS */ peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DROP_POINTER); peck_dispatch_until_stable(peck); _unref_(ei_device) *device = NULL; with_client(peck) { struct ei_seat *seat = peck_ei_get_default_seat(peck); device = ei_device_new(seat); ei_device_configure_name(device, __func__); ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER); ei_device_add(device); } peck_dispatch_eis(peck); with_client(peck) { ei_dispatch(ei); _unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED); } return MUNIT_OK; } MUNIT_TEST(test_ei_device_pointer_rel) { _unref_(peck) *peck = peck_new(); _unref_(ei_device) *device = NULL; peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTODEVICES); peck_dispatch_until_stable(peck); with_client(peck) { struct ei_seat *seat = peck_ei_get_default_seat(peck); device = ei_device_new(seat); munit_assert_not_null(device); ei_device_configure_name(device, __func__); ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER); ei_device_add(device); } peck_dispatch_until_stable(peck); with_client(peck) { ei_device_pointer_motion(device, 1, 2); ei_device_pointer_motion(device, 0.3, 1.4); ei_device_pointer_motion(device, 100, 200); } peck_dispatch_until_stable(peck); with_server(peck) { _unref_(eis_event) *first = peck_eis_next_event(eis, EIS_EVENT_POINTER_MOTION); munit_assert_double_equal(eis_event_pointer_get_dx(first), 1.0, 2 /* precision */); munit_assert_double_equal(eis_event_pointer_get_dy(first), 2.0, 2 /* precision */); _unref_(eis_event) *second = peck_eis_next_event(eis, EIS_EVENT_POINTER_MOTION); munit_assert_double_equal(eis_event_pointer_get_dx(second), 0.3, 2 /* precision */); munit_assert_double_equal(eis_event_pointer_get_dy(second), 1.4, 2 /* precision */); _unref_(eis_event) *third = peck_eis_next_event(eis, EIS_EVENT_POINTER_MOTION); munit_assert_double_equal(eis_event_pointer_get_dx(third), 100, 2 /* precision */); munit_assert_double_equal(eis_event_pointer_get_dy(third), 200, 2 /* precision */); } return MUNIT_OK; } MUNIT_TEST(test_ei_device_pointer_abs) { _unref_(peck) *peck = peck_new(); _unref_(ei_device) *device = NULL; peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DEFAULT_SEAT); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTODEVICES); peck_dispatch_until_stable(peck); with_client(peck) { struct ei_seat *seat = peck_ei_get_default_seat(peck); device = ei_device_new(seat); munit_assert_not_null(device); ei_device_configure_name(device, __func__); ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE); ei_device_pointer_configure_range(device, 1920, 1200); ei_device_add(device); } peck_dispatch_until_stable(peck); with_client(peck) { for (int i = 0; i < 10; i++) ei_device_pointer_motion_absolute(device, 1 * i , 2 + i); } peck_dispatch_until_stable(peck); with_server(peck) { for (int i = 0; i < 10; i++) { _unref_(eis_event) *e = peck_eis_next_event(eis, EIS_EVENT_POINTER_MOTION_ABSOLUTE); munit_assert_double_equal(eis_event_pointer_get_absolute_x(e), 1.0 * i, 2 /* precision */); munit_assert_double_equal(eis_event_pointer_get_absolute_y(e), 2.0 + i, 2 /* precision */); } } with_client(peck) { /* outside of pointer range, expect to be discarded */ ei_device_pointer_motion_absolute(device, 1920, 1200); ei_device_pointer_motion_absolute(device, 2000, 1400); } peck_dispatch_until_stable(peck); with_server(peck) { peck_assert_no_eis_events(eis); } with_client(peck) { ei_device_remove(device); /* absmotion after remove must not trigger an event */ ei_device_pointer_motion_absolute(device, 100, 200); } with_server(peck) { /* Don't auto-handle the removed event */ peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_NONE); peck_dispatch_eis(peck); _unref_(eis_event) *e = peck_eis_next_event(eis, EIS_EVENT_DEVICE_REMOVED); peck_assert_no_eis_events(eis); } return MUNIT_OK; } MUNIT_TEST(test_ei_device_touch) { _unref_(peck) *peck = peck_new(); _unref_(ei_device) *device = NULL; peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTODEVICES); peck_dispatch_until_stable(peck); with_client(peck) { struct ei_seat *seat = peck_ei_get_default_seat(peck); device = ei_device_new(seat); munit_assert_not_null(device); ei_device_configure_name(device, __func__); ei_device_configure_capability(device, EI_DEVICE_CAP_TOUCH); ei_device_touch_configure_range(device, 1024, 768); ei_device_add(device); } peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_touch) *t = ei_device_touch_new(device); ei_touch_down(t, 1, 2); ei_touch_motion(t, 200, 500); ei_touch_up(t); } peck_dispatch_until_stable(peck); with_server(peck) { _unref_(eis_event) *down = peck_eis_touch_down(eis, 1, 2); uint32_t tid = eis_event_touch_get_id(down); _unref_(eis_event) *motion = peck_eis_touch_motion(eis, 200, 500); munit_assert_uint32(eis_event_touch_get_id(motion), ==, tid); _unref_(eis_event) *up = peck_eis_touch_up(eis); munit_assert_uint32(eis_event_touch_get_id(up), ==, tid); } with_client(peck) { _unref_(ei_touch) *t = ei_device_touch_new(device); /* outside clip range, expect touch to be dropped */ ei_touch_down(t, 1200, 100); ei_touch_motion(t, 200, 200); ei_touch_up(t); } peck_dispatch_until_stable(peck); with_server(peck) { peck_assert_no_eis_events(eis); } with_client(peck) { _unref_(ei_touch) *t = ei_device_touch_new(device); ei_touch_down(t, 100, 200); /* outside allowed range, generates a touch up */ ei_touch_motion(t, 1200, 200); ei_touch_up(t); } peck_dispatch_until_stable(peck); with_server(peck) { _unref_(eis_event) *down = peck_eis_touch_down(eis, 100, 200); _unref_(eis_event) *up = peck_eis_touch_up(eis); } with_client(peck) { _unref_(ei_touch) *t = ei_device_touch_new(device); ei_touch_down(t, 100, 100); /* client forgets to touch up, touch_unref takes care of it */ } peck_dispatch_until_stable(peck); with_server(peck) { _unref_(eis_event) *down = peck_eis_touch_down(eis, 100, 100); _unref_(eis_event) *up = peck_eis_touch_up(eis); } with_client(peck) { /* touch only allocated, not actually set down */ _unref_(ei_touch) *t1 = ei_device_touch_new(device); /* touch never set down */ _unref_(ei_touch) *t2 = ei_device_touch_new(device); ei_touch_up(t2); /* touch never set down */ _unref_(ei_touch) *t3 = ei_device_touch_new(device); ei_touch_motion(t3, 100, 200); ei_touch_up(t3); } peck_dispatch_until_stable(peck); with_server(peck) { peck_assert_no_eis_events(eis); } with_client(peck) { /* touch re-used */ _unref_(ei_touch) *t = ei_device_touch_new(device); ei_touch_down(t, 100, 200); ei_touch_up(t); ei_touch_down(t, 200, 300); ei_touch_motion(t, 300, 400); ei_touch_up(t); } peck_dispatch_until_stable(peck); with_server(peck) { _unref_(eis_event) *down = peck_eis_touch_down(eis, 100, 200); _unref_(eis_event) *up = peck_eis_touch_up(eis); peck_assert_no_eis_events(eis); } with_client(peck) { /* double-down, double-up */ _unref_(ei_touch) *t = ei_device_touch_new(device); ei_touch_down(t, 100, 200); ei_touch_down(t, 200, 300); /* ignored */ ei_touch_motion(t, 300, 400); ei_touch_up(t); ei_touch_up(t); /* ignored */ } peck_dispatch_until_stable(peck); with_server(peck) { _unref_(eis_event) *down = peck_eis_touch_down(eis, 100, 200); _unref_(eis_event) *motion = peck_eis_touch_motion(eis, 300, 400); _unref_(eis_event) *up = peck_eis_touch_up(eis); peck_assert_no_eis_events(eis); } return MUNIT_OK; } MUNIT_TEST(test_ei_device_multitouch) { _unref_(peck) *peck = peck_new(); _unref_(ei_device) *device = NULL; peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTODEVICES); peck_dispatch_until_stable(peck); with_client(peck) { struct ei_seat *seat = peck_ei_get_default_seat(peck); device = ei_device_new(seat); munit_assert_not_null(device); ei_device_configure_name(device, __func__); ei_device_configure_capability(device, EI_DEVICE_CAP_TOUCH); ei_device_touch_configure_range(device, 1024, 768); ei_device_add(device); } peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_touch) *t1 = ei_device_touch_new(device); _unref_(ei_touch) *t2 = ei_device_touch_new(device); ei_touch_down(t1, 1, 2); ei_touch_motion(t1, 2, 3); ei_touch_down(t2, 3, 4); ei_touch_motion(t2, 4, 5); ei_touch_up(t2); ei_touch_up(t1); } peck_dispatch_until_stable(peck); with_server(peck) { _unref_(eis_event) *down1 = peck_eis_touch_down(eis, 1, 2); uint32_t tid1 = eis_event_touch_get_id(down1); _unref_(eis_event) *motion1 = peck_eis_touch_motion(eis, 2, 3); munit_assert_uint32(eis_event_touch_get_id(motion1), ==, tid1); _unref_(eis_event) *down2 = peck_eis_touch_down(eis, 3, 4); uint32_t tid2 = eis_event_touch_get_id(down2); munit_assert_uint32(tid2, !=, tid1); _unref_(eis_event) *motion2 = peck_eis_touch_motion(eis, 4, 5); munit_assert_uint32(eis_event_touch_get_id(motion2), ==, tid2); _unref_(eis_event) *up2 = peck_eis_touch_up(eis); munit_assert_uint32(eis_event_touch_get_id(up2), ==, tid2); _unref_(eis_event) *up1 = peck_eis_touch_up(eis); munit_assert_uint32(eis_event_touch_get_id(up1), ==, tid1); } return MUNIT_OK; } MUNIT_TEST(test_ei_keymap_invalid) { const char data[5] = {1, 2, 3, 4, 5}; _unref_(memfile) *fd = memfile_new(data, sizeof(data)); munit_assert_ptr_null(ei_keymap_new(EI_KEYMAP_TYPE_XKB + 1, memfile_get_fd(fd), memfile_get_size(fd))); munit_assert_ptr_null(ei_keymap_new(EI_KEYMAP_TYPE_XKB - 1, memfile_get_fd(fd), memfile_get_size(fd))); munit_assert_ptr_null(ei_keymap_new(EI_KEYMAP_TYPE_XKB, -1, memfile_get_size(fd))); munit_assert_ptr_null(ei_keymap_new(EI_KEYMAP_TYPE_XKB, memfile_get_fd(fd), 0)); /* Valid keymap, valgrind checks only */ _unref_(ei_keymap) *unused = ei_keymap_new(EI_KEYMAP_TYPE_XKB, memfile_get_fd(fd), memfile_get_size(fd)); munit_assert_ptr_not_null(unused); return MUNIT_OK; } MUNIT_TEST(test_ei_keymap_set) { const char data[5] = {1, 2, 3, 4, 5}; _unref_(peck) *peck = peck_new(); _unref_(ei_device) *device = NULL; _unref_(memfile) *fd1 = memfile_new(data, sizeof(data)); _unref_(ei_keymap) *keymap = NULL; peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DEFAULT_SEAT); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTODEVICES); peck_dispatch_until_stable(peck); with_client(peck) { _unref_(memfile) *fd2 = memfile_new(data, sizeof(data)); struct ei_seat *seat = peck_ei_get_default_seat(peck); device = ei_device_new(seat); ei_device_configure_name(device, __func__); ei_device_configure_capability(device, EI_DEVICE_CAP_KEYBOARD); keymap = ei_keymap_new(EI_KEYMAP_TYPE_XKB, memfile_get_fd(fd1), memfile_get_size(fd1)); ei_device_keyboard_configure_keymap(device, keymap); munit_assert_ptr_equal(ei_device_keyboard_get_keymap(device), keymap); /* Not possible to overwrite a keymap on a device */ _unref_(ei_keymap) *overwrite = ei_keymap_new(EI_KEYMAP_TYPE_XKB, memfile_get_fd(fd2), memfile_get_size(fd2)); ei_device_keyboard_configure_keymap(device, overwrite); munit_assert_ptr_equal(ei_device_keyboard_get_keymap(device), keymap); ei_device_add(device); /* Still impossible to overwrite after add */ _unref_(ei_keymap) *ignored = ei_keymap_new(EI_KEYMAP_TYPE_XKB, memfile_get_fd(fd2), memfile_get_size(fd2)); ei_device_keyboard_configure_keymap(device, ignored); munit_assert_ptr_equal(ei_device_keyboard_get_keymap(device), keymap); } peck_dispatch_until_stable(peck); with_server(peck) { _unref_(eis_event) *event = peck_eis_next_event(eis, EIS_EVENT_DEVICE_ADDED); struct eis_device *eis_device = eis_event_get_device(event); struct eis_keymap *eis_keymap = eis_device_keyboard_get_keymap(eis_device); int fd = eis_keymap_get_fd(eis_keymap); munit_assert_int(fd, !=, -1); munit_assert_uint(eis_keymap_get_size(eis_keymap), ==, memfile_get_size(fd1)); munit_assert_uint(eis_keymap_get_type(eis_keymap), ==, EIS_KEYMAP_TYPE_XKB); eis_device_disconnect(eis_device); } peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED); struct ei_device *d = ei_event_get_device(event); munit_assert_ptr_equal(d, device); /* Rejecting a device does not unset the keymap because * you're not supposed to do anything with the device anyway */ struct ei_keymap *km = ei_device_keyboard_get_keymap(device); munit_assert_ptr_equal(keymap, km); munit_assert_int(ei_keymap_get_source(keymap), ==, EI_KEYMAP_SOURCE_CLIENT); } return MUNIT_OK; } MUNIT_TEST(test_ei_keymap_null) { const char data[5] = {1, 2, 3, 4, 5}; _unref_(peck) *peck = peck_new(); _unref_(memfile) *fd = memfile_new(data, sizeof(data)); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DEFAULT_SEAT); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNNECT); peck_dispatch_until_stable(peck); with_client(peck) { struct ei_seat *seat = peck_ei_get_default_seat(peck); _unref_(ei_device) *device = ei_device_new(seat); ei_device_configure_name(device, __func__); ei_device_configure_capability(device, EI_DEVICE_CAP_KEYBOARD); _unref_(ei_keymap) *keymap = ei_keymap_new(EI_KEYMAP_TYPE_XKB, memfile_get_fd(fd), memfile_get_size(fd)); ei_device_keyboard_configure_keymap(device, keymap); ei_device_add(device); } peck_dispatch_until_stable(peck); /* server sets the keymap to NULL */ with_server(peck) { _unref_(eis_event) *event = peck_eis_next_event(eis, EIS_EVENT_DEVICE_ADDED); struct eis_device *device = eis_event_get_device(event); eis_device_keyboard_set_keymap(device, NULL); eis_device_allow_capability(device, EIS_DEVICE_CAP_KEYBOARD); eis_device_connect(device); } peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED); struct ei_device *device = ei_event_get_device(event); struct ei_keymap *keymap = ei_device_keyboard_get_keymap(device); munit_assert_ptr_null(keymap); } return MUNIT_OK; } MUNIT_TEST(test_ei_keymap_changed) { const char data[5] = {1, 2, 3, 4, 5}; _unref_(peck) *peck = peck_new(); _unref_(memfile) *fd1 = memfile_new(data, sizeof(data)); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DEFAULT_SEAT); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNNECT); peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_device) *device = NULL; const char otherdata[2] = {10, 20}; _unref_(memfile) *fd2 = memfile_new(data, sizeof(otherdata)); struct ei_seat *seat = peck_ei_get_default_seat(peck); device = ei_device_new(seat); ei_device_configure_name(device, __func__); ei_device_configure_capability(device, EI_DEVICE_CAP_KEYBOARD); _unref_(ei_keymap) *keymap = ei_keymap_new(EI_KEYMAP_TYPE_XKB, memfile_get_fd(fd2), memfile_get_size(fd2)); ei_device_keyboard_configure_keymap(device, keymap); ei_device_add(device); } peck_dispatch_until_stable(peck); /* server sets the keymap to some other fd */ with_server(peck) { _unref_(eis_event) *event = peck_eis_next_event(eis, EIS_EVENT_DEVICE_ADDED); struct eis_device *device = eis_event_get_device(event); _unref_(eis_keymap) *keymap = eis_keymap_new(EIS_KEYMAP_TYPE_XKB, memfile_get_fd(fd1), memfile_get_size(fd1)); eis_device_keyboard_set_keymap(device, keymap); eis_device_allow_capability(device, EIS_DEVICE_CAP_KEYBOARD); eis_device_connect(device); } peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED); struct ei_device *device = ei_event_get_device(event); struct ei_keymap *keymap = ei_device_keyboard_get_keymap(device); munit_assert_ptr_not_null(keymap); munit_assert_int(ei_keymap_get_type(keymap), ==, EI_KEYMAP_TYPE_XKB); munit_assert_int(ei_keymap_get_source(keymap), ==, EI_KEYMAP_SOURCE_SERVER); int km = ei_keymap_get_fd(keymap); char buf[5]; int rc = min(xread(km, buf, sizeof(buf)), 0); peck_errno_check(rc); munit_assert_int(memcmp(buf, data, sizeof(buf)), ==, 0); } return MUNIT_OK; } /* Emulates the XWayland behavior for calling * xdotool mousemove_relative -- -1 10 */ MUNIT_TEST(test_xdotool_rel_motion) { _unref_(peck) *peck = peck_new(); struct ei_device *device = NULL; peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_dispatch_until_stable(peck); with_client(peck) { struct ei_seat *seat = peck_ei_get_default_seat(peck); device = ei_device_new(seat); ei_device_configure_name(device, __func__); ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER); ei_device_configure_capability(device, EI_DEVICE_CAP_KEYBOARD); ei_device_add(device); } peck_dispatch_until_stable(peck); with_client(peck) { ei_device_pointer_motion(device, -1, 10); ei_device_remove(device); ei_device_unref(device); ei_unref(ei); peck_drop_ei(peck); } peck_dispatch_eis(peck); with_server(peck) { _unref_(eis_event) *motion = peck_eis_next_event(eis, EIS_EVENT_POINTER_MOTION); _unref_(eis_event) *removed = peck_eis_next_event(eis, EIS_EVENT_DEVICE_REMOVED); _unref_(eis_event) *disconnect = peck_eis_next_event(eis, EIS_EVENT_CLIENT_DISCONNECT); peck_assert_no_eis_events(eis); } return MUNIT_OK; } int main(int argc, char **argv) { return munit_tests_run(argc, argv); }