#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_self_immediately) { _unref_(peck) *peck = peck_new(); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_NONE); peck_dispatch_until_stable(peck); /* Disconnect before server processed CONNECT */ with_client(peck) { peck_drop_ei(peck); ei_unref(ei); } peck_dispatch_until_stable(peck); /* Expect the client to get a disconnect event */ with_server(peck) { _unref_(eis_event) *connect = peck_eis_next_event(eis, EIS_EVENT_CLIENT_CONNECT); _unref_(eis_event) *disconnect = peck_eis_next_event(eis, EIS_EVENT_CLIENT_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_self_after_connect) { _unref_(peck) *peck = peck_new(); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_NONE); peck_dispatch_until_stable(peck); with_client(peck) { peck_drop_ei(peck); ei_unref(ei); } peck_dispatch_until_stable(peck); with_server(peck) { _unref_(eis_event) *connect = peck_eis_next_event(eis, EIS_EVENT_CLIENT_CONNECT); _unref_(eis_event) *disconnect = peck_eis_next_event(eis, EIS_EVENT_CLIENT_DISCONNECT); } return MUNIT_OK; } MUNIT_TEST(test_ei_disconnect_after_seat) { _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_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE); peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_event) *connect = peck_ei_next_event(ei, EI_EVENT_CONNECT); _unref_(ei_event) *seat = peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED); } with_server(peck) { struct eis_client *client = peck_eis_get_default_client(peck); eis_client_disconnect(client); } peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_event) *seat = 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_self_after_seat) { _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_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE); peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_event) *connect = peck_ei_next_event(ei, EI_EVENT_CONNECT); _unref_(ei_event) *seat = peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED); peck_drop_ei(peck); /* Disconnect from client */ ei_unref(ei); /* There is no way to disconnect from the server without * destroying the context, so we don't care about the actual * events here */ } peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_NONE); peck_dispatch_until_stable(peck); with_server(peck) { _unref_(eis_event) *disconnect = peck_eis_next_event(eis, EIS_EVENT_CLIENT_DISCONNECT); } return MUNIT_OK; } MUNIT_TEST(test_ei_disconnect_after_bind_before_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_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT); peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED); struct ei_seat *seat = ei_event_get_seat(event); ei_seat_bind(seat); } /* We have *not* called eis_dispatch, so the seat bind 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) *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_self_after_bind_before_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_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT); peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED); struct ei_seat *seat = ei_event_get_seat(event); ei_seat_bind(seat); /* Disconnect before the server can process the bind event */ peck_drop_ei(peck); ei_unref(ei); } peck_dispatch_eis(peck); with_server(peck) { /* Server got the bind event but client disconnected * immediately after */ _unref_(eis_event) *bind = peck_eis_next_event(eis, EIS_EVENT_SEAT_BIND); /* FIXME: libeis should insert unbind here? _unref_(eis_event) *unbind = peck_eis_next_event(eis, EIS_EVENT_SEAT_UNBIND); */ _unref_(eis_event) *disconnect = peck_eis_next_event(eis, EIS_EVENT_CLIENT_DISCONNECT); } return MUNIT_OK; } MUNIT_TEST(test_ei_disconnect_after_bind_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_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT); peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED); struct ei_seat *seat = ei_event_get_seat(event); ei_seat_bind(seat); } /* Receive the Bind event but don't actually add any devices, * disconnect the client instead */ 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) *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_self_after_bind_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_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT); peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED); struct ei_seat *seat = ei_event_get_seat(event); ei_seat_bind(seat); } /* Make sure server sees Bind, then disconnect from server */ peck_dispatch_eis(peck); with_client(peck) { peck_drop_ei(peck); ei_unref(ei); } peck_dispatch_eis(peck); with_server(peck) { _unref_(eis_event) *bind = peck_eis_next_event(eis, EIS_EVENT_SEAT_BIND); /* FIXME: libeis should insert unbind here? _unref_(eis_event) *unbind = peck_eis_next_event(eis, EIS_EVENT_SEAT_UNBIND); */ _unref_(eis_event) *disconnect = peck_eis_next_event(eis, EIS_EVENT_CLIENT_DISCONNECT); } return MUNIT_OK; } MUNIT_TEST(test_ei_disconnect_after_unbind_before_received) { _unref_(peck) *peck = peck_new(); _unref_(ei_device) *device = NULL; _unref_(ei_seat) *seat = NULL; peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT); peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED); seat = ei_seat_ref(ei_event_get_seat(event)); ei_seat_bind(seat); } peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); /* server has the Bind event now */ peck_dispatch_until_stable(peck); with_client(peck) { ei_seat_unbind(seat); } /* No server dispatch here so the server isn't aware of the * ei_seat_unbind() call. Disconnect the client */ 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) *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_unbind_after_received) { _unref_(peck) *peck = peck_new(); _unref_(ei_device) *device = NULL; _unref_(ei_seat) *seat = NULL; peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT); peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED); seat = ei_seat_ref(ei_event_get_seat(event)); ei_seat_bind(seat); } /* server has the Bind event now */ peck_dispatch_until_stable(peck); with_client(peck) { ei_seat_unbind(seat); } /* Dispatch, server is aware of the ei_seat_unbind() */ 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) *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(); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_dispatch_until_stable(peck); with_server(peck) { struct eis_seat *seat = peck_eis_get_default_seat(peck); _unref_(eis_device) *device = eis_device_new(seat); eis_device_configure_name(device, "string is freed"); munit_assert_string_equal(eis_device_get_name(device), "string is freed"); /* overwrite before eis_device_add() is possible */ eis_device_configure_name(device, __func__); munit_assert_string_equal(eis_device_get_name(device), __func__); munit_assert_false(eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER)); munit_assert_false(eis_device_has_capability(device, EIS_DEVICE_CAP_KEYBOARD)); munit_assert_false(eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE)); munit_assert_false(eis_device_has_capability(device, EIS_DEVICE_CAP_TOUCH)); eis_device_configure_capability(device, EIS_DEVICE_CAP_POINTER); munit_assert_true(eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER)); eis_device_configure_capability(device, EIS_DEVICE_CAP_KEYBOARD); munit_assert_true(eis_device_has_capability(device, EIS_DEVICE_CAP_KEYBOARD)); eis_device_add(device); /* device is read-only now */ eis_device_configure_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE); munit_assert_false(eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE)); eis_device_configure_name(device, "nope"); munit_assert_string_equal(eis_device_get_name(device), __func__); } peck_dispatch_ei(peck); /* device creation and getters/setters test */ 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); munit_assert_not_null(device); munit_assert_string_equal(ei_device_get_name(device), __func__); munit_assert_true(ei_device_has_capability(device, EI_DEVICE_CAP_POINTER)); munit_assert_true(ei_device_has_capability(device, EI_DEVICE_CAP_KEYBOARD)); munit_assert_false(ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE)); munit_assert_false(ei_device_has_capability(device, EI_DEVICE_CAP_TOUCH)); } return MUNIT_OK; } MUNIT_TEST(test_ei_device_set_name_multiple_devices) { _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); with_server(peck) { struct eis_seat *seat = peck_eis_get_default_seat(peck); _unref_(eis_device) *d1 = eis_device_new(seat); eis_device_configure_name(d1, "first device"); eis_device_configure_capability(d1, EIS_DEVICE_CAP_POINTER); eis_device_add(d1); _unref_(eis_device) *d2 = eis_device_new(seat); /* Unnamed */ eis_device_add(d2); _unref_(eis_device) *d3 = eis_device_new(seat); eis_device_configure_name(d3, "third device"); eis_device_configure_capability(d3, EIS_DEVICE_CAP_POINTER); eis_device_add(d3); } peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_event) *e1 = peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED); struct ei_device *d1 = ei_event_get_device(e1); munit_assert_string_equal(ei_device_get_name(d1), "first device"); _unref_(ei_event) *e2 = peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED); struct ei_device *d2 = ei_event_get_device(e2); munit_assert_string_equal(ei_device_get_name(d2), "unnamed device"); _unref_(ei_event) *e3 = peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED); struct ei_device *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_never_added) { _unref_(peck) *peck = peck_new(); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_dispatch_until_stable(peck); /* Unref after remove */ with_server(peck) { struct eis_seat *seat = peck_eis_get_default_seat(peck); struct eis_device *device = eis_device_new(seat); eis_device_remove(device); eis_device_unref(device); } peck_dispatch_until_stable(peck); /* device was never added, shouldn't show up */ with_client(peck) { peck_assert_no_ei_events(ei); } /* unref before remove. * * This would be invalid client code since you can't expect to have * a ref after unref, but since we know the device is still here, we * can test for the lib being correct. */ with_server(peck) { struct eis_seat *seat = peck_eis_get_default_seat(peck); struct eis_device *device = eis_device_new(seat); eis_device_unref(device); eis_device_remove(device); } peck_dispatch_until_stable(peck); with_client(peck) { peck_assert_no_ei_events(ei); } 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; _unref_(eis_device) *eis_device = NULL; with_server(peck) { struct eis_seat *seat = peck_eis_get_default_seat(peck); eis_device = eis_device_new(seat); eis_device_configure_name(eis_device, __func__); eis_device_configure_capability(eis_device, EIS_DEVICE_CAP_POINTER); eis_device_add(eis_device); } peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED); device = ei_device_ref(ei_event_get_device(event)); } with_server(peck) { eis_device_remove(eis_device); } peck_dispatch_until_stable(peck); with_client(peck) { _unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED); munit_assert_ptr_equal(ei_event_get_device(event), device); } return MUNIT_OK; } MUNIT_TEST(test_ei_device_pointer_rel) { _unref_(peck) *peck = peck_new(); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ADD_POINTER); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTODEVICES); peck_dispatch_until_stable(peck); with_client(peck) { struct ei_device *device = peck_ei_get_default_pointer(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(); struct ei_device *device = NULL; peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ADD_POINTER_ABSOLUTE); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTODEVICES); peck_dispatch_until_stable(peck); /* FIXME: missing the currently unimplemented region checks */ with_client(peck) { device = peck_ei_get_default_pointer_absolute(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); /* Don't auto-handle the DEVICE_CLOSED event */ peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_NONE); } with_client(peck) { ei_device_close(device); /* absmotion after remove must not trigger an event */ ei_device_pointer_motion_absolute(device, 100, 200); } peck_dispatch_until_stable(peck); with_server(peck) { _unref_(eis_event) *e = peck_eis_next_event(eis, EIS_EVENT_DEVICE_CLOSED); peck_assert_no_eis_events(eis); } return MUNIT_OK; } MUNIT_TEST(test_ei_device_touch) { _unref_(peck) *peck = peck_new(); struct ei_device *device = NULL; peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ADD_TOUCH); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTODEVICES); peck_dispatch_until_stable(peck); /* FIXME: missing the currently unimplemented region checks */ with_client(peck) { device = peck_ei_get_default_touch(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, 1920, 1200); ei_touch_motion(t, 1920, 1000); 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, 1950, 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(); struct ei_device *device = NULL; peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ADD_TOUCH); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTODEVICES); peck_dispatch_until_stable(peck); peck_dispatch_until_stable(peck); with_client(peck) { device = peck_ei_get_default_touch(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) { /* FIXME: needs review after the switch to server-side devices */ return MUNIT_SKIP; #if 0 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; #endif } MUNIT_TEST(test_ei_keymap_set) { /* FIXME: needs review after the switch to server-side devices */ return MUNIT_SKIP; #if 0 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; #endif } MUNIT_TEST(test_ei_keymap_null) { /* FIXME: needs review after the switch to server-side devices */ return MUNIT_SKIP; #if 0 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; #endif } MUNIT_TEST(test_ei_keymap_changed) { /* FIXME: needs review after the switch to server-side devices */ return MUNIT_SKIP; #if 0 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; #endif } /* Emulates the XWayland behavior for calling * xdotool mousemove_relative -- -1 10 */ MUNIT_TEST(test_xdotool_rel_motion) { _unref_(peck) *peck = peck_new(); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ADD_POINTER); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTODEVICES); peck_dispatch_until_stable(peck); with_client(peck) { struct ei_device *device = peck_ei_get_default_pointer(peck); ei_device_pointer_motion(device, -1, 10); ei_device_close(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) *close = peck_eis_next_event(eis, EIS_EVENT_DEVICE_CLOSED); _unref_(eis_event) *disconnect = peck_eis_next_event(eis, EIS_EVENT_CLIENT_DISCONNECT); peck_assert_no_eis_events(eis); } return MUNIT_OK; }