libei/test/test-ei.c
Peter Hutterer c317de742b libei: immediately remove devices added for a removed seat
Once the SEAT_REMOVED event has been processed, adding new devices is
pointless. But we do promise a DEVICE_REMOVED event for any device added with
ei_device_add(), so let's immediately queue an event and mark the device as
dead.

Since the SEAT_REMOVED event may still be pending in the queue (i.e. not yet
read by the client), we need to prepend the event to the queue. Note that
client that immediately add a device when a device is removed will cause
an infinite loop.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-10-29 14:10:47 +10:00

1545 lines
42 KiB
C

#include "config.h"
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#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_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_self_after_add_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_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);
peck_drop_ei(peck);
ei_unref(ei);
}
peck_dispatch_eis(peck);
with_server(peck) {
_unref_(eis_event) *added =
peck_eis_next_event(eis, EIS_EVENT_DEVICE_ADDED);
/* Device is already gone, but let's say we add it anyway */
struct eis_device *device = eis_event_get_device(added);
eis_device_connect(device);
_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);
}
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_self_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);
}
peck_dispatch_eis(peck);
with_client(peck) {
peck_drop_ei(peck);
ei_unref(ei);
}
peck_dispatch_eis(peck);
with_server(peck) {
_unref_(eis_event) *added =
peck_eis_next_event(eis, EIS_EVENT_DEVICE_ADDED);
/* Device is already gone, but let's say we add it anyway */
struct eis_device *device = eis_event_get_device(added);
eis_device_connect(device);
_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);
}
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_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_client(peck) {
struct ei_seat *seat = peck_ei_get_default_seat(peck);
_unref_(ei_device) *device = ei_device_new(seat);
ei_device_remove(device);
}
peck_dispatch_until_stable(peck);
/* 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_client(peck) {
struct ei_seat *seat = peck_ei_get_default_seat(peck);
struct ei_device *device = ei_device_new(seat);
ei_device_unref(device);
ei_device_remove(device);
}
peck_dispatch_until_stable(peck);
with_server(peck) {
peck_assert_no_eis_events(eis);
}
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_add_after_seat_remove)
{
_unref_(peck) *peck = peck_new();
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_HANDLE_ADDED);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_HANDLE_RESUMED);
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);
}
peck_dispatch_until_stable(peck);
with_server(peck) {
struct eis_seat *seat = peck_eis_get_default_seat(peck);
eis_seat_remove(seat);
}
/* Seat was removed by server but we don't know this yet, let's add
* a device */
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);
}
peck_dispatch_until_stable(peck);
/* Now add a device while the SEAT_REMOVED event is pending */
with_client(peck) {
/* The original device */
_unref_(ei_event) *removed1 =
peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED);
/* The device added before we knew about seat removal */
_unref_(ei_event) *removed2 =
peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED);
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);
/* The device added just above */
_unref_(ei_event) *removed3 =
peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED);
_unref_(ei_event) *seat_removed =
peck_ei_next_event(ei, EI_EVENT_SEAT_REMOVED);
}
/* Now add a device when the seat had already been removed */
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);
_unref_(ei_event) *removed =
peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_device_add_after_disconnect)
{
_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_client *client = peck_eis_get_default_client(peck);
eis_client_disconnect(client);
}
peck_dispatch_until_stable(peck);
with_client(peck) {
struct ei_seat *seat = peck_ei_get_default_seat(peck);
_unref_(ei_device) *d1 = ei_device_new(seat);
ei_device_configure_name(d1, __func__);
ei_device_configure_capability(d1, EI_DEVICE_CAP_POINTER);
ei_device_add(d1);
_unref_(ei_event) *removed1 =
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_device) *d2 = ei_device_new(seat);
ei_device_configure_name(d2, __func__);
ei_device_configure_capability(d2, EI_DEVICE_CAP_POINTER);
ei_device_add(d2);
_unref_(ei_event) *removed2 =
peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED);
_unref_(ei_event) *disconnect =
peck_ei_next_event(ei, EI_EVENT_DISCONNECT);
}
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);
}