/* SPDX-License-Identifier: MIT */ /* * Copyright © 2020 Red Hat, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include "config.h" #include #pragma once #include "libei.h" #include "libeis.h" #include "util-mem.h" enum peck_ei_mode { PECK_EI_RECEIVER = 20, PECK_EI_SENDER, }; /** * An enum to define basic server behavior in peck_dispatch_eis(). * Where a flag is **not** set for any specific behaviour, that event will * remain on the event queue after peck_dispatch_eis(). For example, a * caller setting @ref PECK_EIS_BEHAVIOR_ACCEPT_CLIENT will see * the device added event as first event in the queue. */ enum peck_eis_behavior { /** * Behavior of EIS is implemented in the test case. */ PECK_EIS_BEHAVIOR_NONE, /** * Accept all client connection requests, create default seats * **and** resume any device immediately after add. */ PECK_EIS_BEHAVIOR_ACCEPT_ALL, /** * Process connect/disconnect requests from the client. */ PECK_EIS_BEHAVIOR_ACCEPT_CLIENT, PECK_EIS_BEHAVIOR_REJECT_CLIENT, /** * Create a "default" seat. This behavior is enabled as part of * PECK_EIS_BEHAVIOR_ACCEPT_ALL. */ PECK_EIS_BEHAVIOR_DEFAULT_SEAT, /** * Do not create a "default" seat. */ PECK_EIS_BEHAVIOR_NO_DEFAULT_SEAT, /** * Handle the bind seat request */ PECK_EIS_BEHAVIOR_HANDLE_BIND_SEAT, /** * Handle the device close. This behavior is enabled as part of * PECK_EIS_BEHAVIOR_ACCEPT_ALL. */ PECK_EIS_BEHAVIOR_HANDLE_CLOSE_DEVICE, /** * Handle frame events. This behavior is enabled by default. */ PECK_EIS_BEHAVIOR_HANDLE_FRAME, /** * Handle the start/stop emulation event. This behavior is enabled as part of * PECK_EIS_BEHAVIOR_ACCEPT_ALL. */ PECK_EIS_BEHAVIOR_HANDLE_START_EMULATING, PECK_EIS_BEHAVIOR_HANDLE_STOP_EMULATING, /** * Create default devices */ PECK_EIS_BEHAVIOR_ADD_DEVICES, /**< add all of the below */ PECK_EIS_BEHAVIOR_ADD_POINTER, PECK_EIS_BEHAVIOR_ADD_POINTER_ABSOLUTE, PECK_EIS_BEHAVIOR_ADD_KEYBOARD, PECK_EIS_BEHAVIOR_ADD_TOUCH, PECK_EIS_BEHAVIOR_RESUME_DEVICE, PECK_EIS_BEHAVIOR_SUSPEND_DEVICE, }; enum peck_ei_behavior { PECK_EI_BEHAVIOR_NONE, /* enabled by default - handle the Connect event */ PECK_EI_BEHAVIOR_HANDLE_CONNECT, /* enabled by default - handle the first seat added event, setting * the default seat to the first seat and bind to it */ PECK_EI_BEHAVIOR_AUTOSEAT, /* handle Connect/Seat/Added/Resumed events, i.e. anything until the * first real device event */ PECK_EI_BEHAVIOR_AUTODEVICES, /** * Immediately send a StartEmulating request once a device is resumed. */ PECK_EI_BEHAVIOR_AUTOSTART, PECK_EI_BEHAVIOR_HANDLE_ADDED, PECK_EI_BEHAVIOR_HANDLE_ADDED_POINTER, PECK_EI_BEHAVIOR_HANDLE_ADDED_POINTER_ABSOLUTE, PECK_EI_BEHAVIOR_HANDLE_ADDED_KEYBOARD, PECK_EI_BEHAVIOR_HANDLE_ADDED_TOUCH, PECK_EI_BEHAVIOR_HANDLE_ADDED_BUTTON, PECK_EI_BEHAVIOR_HANDLE_ADDED_SCROLL, PECK_EI_BEHAVIOR_HANDLE_RESUMED, PECK_EI_BEHAVIOR_HANDLE_PAUSED, /** * Handle frame events. This behavior is enabled by default. */ PECK_EI_BEHAVIOR_HANDLE_FRAME, }; struct peck; struct peck * peck_new(void); struct peck * peck_new_context(enum peck_ei_mode ei_mode); void peck_ei_connect(struct peck *peck); void _peck_mark(struct peck *peck, const char *func, int line); /** Add debug marker to the log output */ #define peck_mark(peck_) _peck_mark(peck_, __func__, __LINE__) void peck_enable_eis_behavior(struct peck *peck, enum peck_eis_behavior behavior); void peck_enable_ei_behavior(struct peck *peck, enum peck_ei_behavior behavior); struct ei * peck_get_ei(struct peck *peck); void peck_drop_ei(struct peck *peck); struct eis * peck_get_eis(struct peck *peck); struct eis_client * peck_eis_get_default_client(struct peck *peck); struct eis_seat * peck_eis_get_default_seat(struct peck *peck); struct eis_device * peck_eis_get_default_pointer(struct peck *peck); struct eis_device * peck_eis_get_default_keyboard(struct peck *peck); struct eis_device * peck_eis_get_default_pointer_absolute(struct peck *peck); struct eis_device * peck_eis_get_default_touch(struct peck *peck); struct eis_device * peck_eis_get_default_button(struct peck *peck); struct eis_device * peck_eis_get_default_scroll(struct peck *peck); struct ei_seat * peck_ei_get_default_seat(struct peck *peck); struct ei_device * peck_ei_get_default_pointer(struct peck *peck); struct ei_device * peck_ei_get_default_button(struct peck *peck); struct ei_device * peck_ei_get_default_scroll(struct peck *peck); struct ei_device * peck_ei_get_default_keyboard(struct peck *peck); struct ei_device * peck_ei_get_default_pointer_absolute(struct peck *peck); struct ei_device * peck_ei_get_default_touch(struct peck *peck); uint64_t peck_ei_now(struct peck *peck); uint64_t peck_eis_now(struct peck *peck); /** * Dispatch all events according to the currently defined behavior. * When this function returns false, the connection is in a "stable" state * and futher calls to this function will not change that state. This stable * state may mean either there are no events or events pending to be * processed by the caller. * * @return true if at least one event was processed according to the current * behavior */ #define peck_dispatch_eis(_p) \ _peck_dispatch_eis(_p, __LINE__) bool _peck_dispatch_eis(struct peck *peck, int lineno); /** * Dispatch all events according to the currently defined behavior. * When this function returns false, the connection is in a "stable" state * and futher calls to this function will not change that state. This stable * state may mean either there are no events or events pending to be * processed by the caller. * * @return true if at least one behavior was processes according to the * current behavior */ #define peck_dispatch_ei(_p) \ _peck_dispatch_ei(_p, __LINE__) bool _peck_dispatch_ei(struct peck *peck, int lineno); struct peck * peck_unref(struct peck *peck); /** * Dispatch both EIS and EI until a stable state is reached, i.e. until * either there are no events pending or until either (or both) have events * pending that are not processed by the current behaviors. */ void _peck_dispatch_until_stable(struct peck *peck, int lineno); #define peck_dispatch_until_stable(_p) \ _peck_dispatch_until_stable((_p), __LINE__) /** * Discard all pending events. */ void peck_drain_eis(struct eis *eis); /** * Discard all pending events. */ void peck_drain_ei(struct ei *ei); void peck_assert_no_eis_events(struct eis *eis); void peck_assert_no_ei_events(struct ei *ei); #define peck_ei_next_event(_ei, _type) \ _peck_ei_next_event(_ei, _type, __LINE__) struct ei_event * _peck_ei_next_event(struct ei *ei, enum ei_event_type type, int lineno); #define peck_eis_next_event(_eis, _type) \ _peck_eis_next_event(_eis, _type, __LINE__) struct eis_event * _peck_eis_next_event(struct eis *eis, enum eis_event_type type, int lineno); #define peck_eis_touch_down(_eis, _x, _y) \ _peck_eis_touch_event(_eis, EIS_EVENT_TOUCH_DOWN, _x, _y, __LINE__) #define peck_eis_touch_motion(_eis, _x, _y) \ _peck_eis_touch_event(_eis, EIS_EVENT_TOUCH_MOTION, _x, _y, __LINE__) #define peck_eis_touch_up(_eis) \ _peck_eis_next_event(_eis, EIS_EVENT_TOUCH_UP, __LINE__) struct eis_event * _peck_eis_touch_event(struct eis *eis, enum eis_event_type type, double x, double y, int lineno); #define peck_ei_touch_down(_ei, _x, _y) \ _peck_ei_touch_event(_ei, EI_EVENT_TOUCH_DOWN, _x, _y, __LINE__) #define peck_ei_touch_motion(_ei, _x, _y) \ _peck_ei_touch_event(_ei, EI_EVENT_TOUCH_MOTION, _x, _y, __LINE__) #define peck_ei_touch_up(_ei) \ _peck_ei_next_event(_ei, EI_EVENT_TOUCH_UP, __LINE__) struct ei_event * _peck_ei_touch_event(struct ei *ei, enum ei_event_type type, double x, double y, int lineno); const char * peck_ei_event_name(struct ei_event *e); const char * peck_eis_event_name(struct eis_event *e); const char * peck_ei_event_type_name(enum ei_event_type type); const char * peck_eis_event_type_name(enum eis_event_type type); DEFINE_UNREF_CLEANUP_FUNC(peck); /* Define a bunch of _cleanup_foo_ macros for a struct foo */ DEFINE_UNREF_CLEANUP_FUNC(ei); DEFINE_UNREF_CLEANUP_FUNC(ei_event); DEFINE_UNREF_CLEANUP_FUNC(ei_device); DEFINE_UNREF_CLEANUP_FUNC(ei_touch); DEFINE_UNREF_CLEANUP_FUNC(ei_keymap); DEFINE_UNREF_CLEANUP_FUNC(ei_seat); DEFINE_UNREF_CLEANUP_FUNC(ei_region); DEFINE_UNREF_CLEANUP_FUNC(eis); DEFINE_UNREF_CLEANUP_FUNC(eis_client); DEFINE_UNREF_CLEANUP_FUNC(eis_event); DEFINE_UNREF_CLEANUP_FUNC(eis_device); DEFINE_UNREF_CLEANUP_FUNC(eis_touch); DEFINE_UNREF_CLEANUP_FUNC(eis_keymap); DEFINE_UNREF_CLEANUP_FUNC(eis_seat); DEFINE_UNREF_CLEANUP_FUNC(eis_region); /* Macros intended just for readability to make it more obvious which part of a test handles server vs client */ #define with_server(peck_) for (struct eis *eis = peck_get_eis(peck_); eis; eis = NULL) #define with_client(peck_) for (struct ei *ei = peck_get_ei(peck_); ei; ei = NULL) #define with_emulation(d_, sequence_) for (bool _loop = ({ ei_device_start_emulating(d_, sequence_); true;});\ _loop; \ ({ ei_device_stop_emulating(d_); _loop = false; })) #define peck_errno_check(_rc) { \ const int xrc = (_rc); \ if (xrc != 0) \ munit_errorf("errno is not 0: %d - %s\n", -xrc, strerror(-xrc)); \ }