eis: remove some indirection from the device event handling

Now that we only have one nice hook as entry point for those events,
let's move (and harden) the code there.
This commit is contained in:
Peter Hutterer 2023-02-21 09:12:13 +10:00
parent 876e4044ab
commit 03d7f96ddd
2 changed files with 164 additions and 268 deletions

View file

@ -203,6 +203,19 @@ eis_device_get_client(struct eis_device *device)
return eis_seat_get_client(eis_device_get_seat(device));
}
static inline bool
eis_device_in_region(struct eis_device *device, double x, double y)
{
struct eis_region *r;
list_for_each(r, &device->regions, link) {
if (eis_region_contains(r, x, y))
return true;
}
return false;
}
static struct brei_result *
client_msg_release(struct eis_device *device)
{
@ -274,17 +287,45 @@ client_msg_stop_emulating(struct eis_device *device)
return result;
}
static struct brei_result *
maybe_error_on_device_state(struct eis_device *device, const char *event_type)
{
switch (device->state) {
case EIS_DEVICE_STATE_RESUMED:
/* could be a race condition, but it's unlikely unless the
* EIS implementation pauses and resumes immediately without
* giving the client a chance to catch up. So let's
* treat this as error until we see real issues.
*/
break;
case EIS_DEVICE_STATE_PAUSED:
/* we paused the device but the client sent us an event
* - most likely a race condition, so let's ignore it */
return NULL;
case EIS_DEVICE_STATE_EMULATING:
return NULL;
case EIS_DEVICE_STATE_NEW:
case EIS_DEVICE_STATE_CLOSED_BY_CLIENT:
case EIS_DEVICE_STATE_DEAD:
break;
}
return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL,
"Invalid device state %ud for a %s event", device->state, event_type);
}
static struct brei_result *
client_msg_frame(struct eis_device *device, uint32_t time, uint32_t micros)
{
DISCONNECT_IF_RECEIVER_CONTEXT(device);
if (device->state != EIS_DEVICE_STATE_EMULATING)
return brei_result_new_from_neg_errno(-EINVAL);
if (device->state == EIS_DEVICE_STATE_EMULATING) {
eis_queue_frame_event(device, ms2us(time) + micros);
return NULL;
}
eis_queue_frame_event(device, ms2us(time) + micros);
return NULL;
return maybe_error_on_device_state(device, "frame");
}
@ -308,7 +349,17 @@ client_msg_pointer_rel(struct eis_pointer *pointer, float x, float y)
DISCONNECT_IF_RECEIVER_CONTEXT(device);
return brei_result_new_from_neg_errno(eis_device_event_pointer_rel(device, x, y));
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER)) {
return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL,
"Pointer rel event for non-pointer device");
}
if (device->state == EIS_DEVICE_STATE_EMULATING) {
eis_queue_pointer_rel_event(device, x, y);
return NULL;
}
return maybe_error_on_device_state(device, "pointer rel");
}
static struct brei_result *
@ -318,7 +369,18 @@ client_msg_pointer_abs(struct eis_pointer *pointer, float x, float y)
DISCONNECT_IF_RECEIVER_CONTEXT(device);
return brei_result_new_from_neg_errno(eis_device_event_pointer_abs(device, x, y));
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE)) {
return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL,
"Pointer abs event for non-pointer device");
}
if (device->state == EIS_DEVICE_STATE_EMULATING) {
if (eis_device_in_region(device, x, y))
eis_queue_pointer_abs_event(device, x, y);
return NULL;
}
return maybe_error_on_device_state(device, "pointer abs");
}
static struct brei_result *
@ -328,7 +390,18 @@ client_msg_pointer_button(struct eis_pointer *pointer, uint32_t button, uint32_t
DISCONNECT_IF_RECEIVER_CONTEXT(device);
return brei_result_new_from_neg_errno(eis_device_event_pointer_button(device, button, !!state));
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE) &&
!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER)) {
return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL,
"Pointer button event for non-pointer device");
}
if (device->state == EIS_DEVICE_STATE_EMULATING) {
eis_queue_pointer_button_event(device, button, !!state);
return NULL;
}
return maybe_error_on_device_state(device, "pointer button");
}
static struct brei_result *
@ -338,7 +411,18 @@ client_msg_pointer_scroll(struct eis_pointer *pointer, float x, float y)
DISCONNECT_IF_RECEIVER_CONTEXT(device);
return brei_result_new_from_neg_errno(eis_device_event_pointer_scroll(device, x, y));
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE) &&
!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER)) {
return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL,
"Pointer scroll event for non-pointer device");
}
if (device->state == EIS_DEVICE_STATE_EMULATING) {
eis_queue_pointer_scroll_event(device, x, y);
return NULL;
}
return maybe_error_on_device_state(device, "pointer scroll");
}
static struct brei_result *
@ -348,7 +432,18 @@ client_msg_pointer_scroll_discrete(struct eis_pointer *pointer, int32_t x, int32
DISCONNECT_IF_RECEIVER_CONTEXT(device);
return brei_result_new_from_neg_errno(eis_device_event_pointer_scroll_discrete(device, x, y));
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE) &&
!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER)) {
return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL,
"Pointer scroll discrete event for non-pointer device");
}
if (device->state == EIS_DEVICE_STATE_EMULATING) {
eis_queue_pointer_scroll_discrete_event(device, x, y);
return NULL;
}
return maybe_error_on_device_state(device, "pointer scroll discrete");
}
static struct brei_result *
@ -359,10 +454,21 @@ client_msg_pointer_scroll_stop(struct eis_pointer *pointer,
DISCONNECT_IF_RECEIVER_CONTEXT(device);
if (is_cancel)
return brei_result_new_from_neg_errno(eis_device_event_pointer_scroll_cancel(device, !!x, !!y));
else
return brei_result_new_from_neg_errno(eis_device_event_pointer_scroll_stop(device, !!x, !!y));
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE) &&
!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER)) {
return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL,
"Pointer scroll stop event for non-pointer device");
}
if (device->state == EIS_DEVICE_STATE_EMULATING) {
if (is_cancel)
eis_queue_pointer_scroll_cancel_event(device, !!x, !!y);
else
eis_queue_pointer_scroll_stop_event(device, !!x, !!y);
return NULL;
}
return maybe_error_on_device_state(device, "pointer scroll stop");
}
static struct brei_result *
@ -397,7 +503,17 @@ client_msg_keyboard_key(struct eis_keyboard *keyboard, uint32_t key, uint32_t st
DISCONNECT_IF_RECEIVER_CONTEXT(device);
return brei_result_new_from_neg_errno(eis_device_event_keyboard_key(device, key, !!state));
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_KEYBOARD)) {
return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL,
"Key event for non-keyboard device");
}
if (device->state == EIS_DEVICE_STATE_EMULATING) {
eis_queue_keyboard_key_event(device, key, !!state);
return NULL;
}
return maybe_error_on_device_state(device, "key");
}
static struct brei_result *
@ -428,7 +544,17 @@ client_msg_touch_down(struct eis_touchscreen *touchscreen,
DISCONNECT_IF_RECEIVER_CONTEXT(device);
return brei_result_new_from_neg_errno(eis_device_event_touch_down(device, touchid, x, y));
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_TOUCH)) {
return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL,
"Touch down event for non-touch device");
}
if (device->state == EIS_DEVICE_STATE_EMULATING) {
eis_queue_touch_down_event(device, touchid, x, y);
return NULL;
}
return maybe_error_on_device_state(device, "touch down");
}
static struct brei_result *
@ -439,7 +565,17 @@ client_msg_touch_motion(struct eis_touchscreen *touchscreen,
DISCONNECT_IF_RECEIVER_CONTEXT(device);
return brei_result_new_from_neg_errno(eis_device_event_touch_motion(device, touchid, x, y));
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_TOUCH)) {
return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL,
"Touch motion event for non-touch device");
}
if (device->state == EIS_DEVICE_STATE_EMULATING) {
eis_queue_touch_motion_event(device, touchid, x, y);
return NULL;
}
return maybe_error_on_device_state(device, "touch motion");
}
static struct brei_result *
@ -449,7 +585,17 @@ client_msg_touch_up(struct eis_touchscreen *touchscreen, uint32_t touchid)
DISCONNECT_IF_RECEIVER_CONTEXT(device);
return brei_result_new_from_neg_errno(eis_device_event_touch_up(device, touchid));
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_TOUCH)) {
return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL,
"Touch up event for non-touch device");
}
if (device->state == EIS_DEVICE_STATE_EMULATING) {
eis_queue_touch_up_event(device, touchid);
return NULL;
}
return maybe_error_on_device_state(device, "touch up");
}
static struct brei_result *
@ -1052,217 +1198,6 @@ eis_device_frame(struct eis_device *device, uint64_t time)
eis_device_event_frame(device, us2ms(time), time % 1000);
}
int
eis_device_event_pointer_rel(struct eis_device *device,
double x, double y)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER)) {
log_bug_client(eis_device_get_context(device),
"%s: device is not a pointer", __func__);
return -EINVAL;
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return -EINVAL;
eis_queue_pointer_rel_event(device, x, y);
return 0;
}
static inline bool
eis_device_in_region(struct eis_device *device, double x, double y)
{
struct eis_region *r;
list_for_each(r, &device->regions, link) {
if (eis_region_contains(r, x, y))
return true;
}
return false;
}
int
eis_device_event_pointer_abs(struct eis_device *device,
double x, double y)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE)) {
log_bug_client(eis_device_get_context(device),
"%s: device is not an absolute pointer", __func__);
return -EINVAL;
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return -EINVAL;
if (eis_device_in_region(device, x, y))
eis_queue_pointer_abs_event(device, x, y);
return 0;
}
int
eis_device_event_pointer_button(struct eis_device *device,
uint32_t button, bool is_press)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER)) {
log_bug_client(eis_device_get_context(device),
"%s: device is not a pointer", __func__);
return -EINVAL;
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return -EINVAL;
eis_queue_pointer_button_event(device, button, is_press);
return 0;
}
int
eis_device_event_pointer_scroll(struct eis_device *device,
double x, double y)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER) &&
!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE)) {
log_bug_client(eis_device_get_context(device),
"%s: device is not a (absolute) pointer", __func__);
return -EINVAL;
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return -EINVAL;
eis_queue_pointer_scroll_event(device, x, y);
return 0;
}
int
eis_device_event_pointer_scroll_discrete(struct eis_device *device,
int32_t x, int32_t y)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER) &&
!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE)) {
log_bug_client(eis_device_get_context(device),
"%s: device is not a (absolute) pointer", __func__);
return -EINVAL;
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return -EINVAL;
eis_queue_pointer_scroll_discrete_event(device, x, y);
return 0;
}
int
eis_device_event_pointer_scroll_stop(struct eis_device *device, bool x, bool y)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER) &&
!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE)) {
log_bug_client(eis_device_get_context(device),
"%s: device is not a (absolute) pointer", __func__);
return -EINVAL;
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return -EINVAL;
eis_queue_pointer_scroll_stop_event(device, x, y);
return 0;
}
int
eis_device_event_pointer_scroll_cancel(struct eis_device *device, bool x, bool y)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER) &&
!eis_device_has_capability(device, EIS_DEVICE_CAP_POINTER_ABSOLUTE)) {
log_bug_client(eis_device_get_context(device),
"%s: device is not a (absolute) pointer", __func__);
return -EINVAL;
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return -EINVAL;
eis_queue_pointer_scroll_cancel_event(device, x, y);
return 0;
}
int
eis_device_event_keyboard_key(struct eis_device *device,
uint32_t key, bool is_press)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_KEYBOARD)) {
log_bug_client(eis_device_get_context(device),
"%s: device is not a keyboard", __func__);
return -EINVAL;
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return -EINVAL;
eis_queue_keyboard_key_event(device, key, is_press);
return 0;
}
int
eis_device_event_touch_down(struct eis_device *device, uint32_t touchid, double x, double y)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_TOUCH)) {
log_bug_client(eis_device_get_context(device),
"%s: device is not a touch device", __func__);
return -EINVAL;
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return -EINVAL;
eis_queue_touch_down_event(device, touchid, x, y);
return 0;
}
int
eis_device_event_touch_motion(struct eis_device *device, uint32_t touchid, double x, double y)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_TOUCH)) {
log_bug_client(eis_device_get_context(device),
"%s: device is not a touch device", __func__);
return -EINVAL;
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return -EINVAL;
eis_queue_touch_motion_event(device, touchid, x, y);
return 0;
}
int
eis_device_event_touch_up(struct eis_device *device, uint32_t touchid)
{
if (!eis_device_has_capability(device, EIS_DEVICE_CAP_TOUCH)) {
log_bug_client(eis_device_get_context(device),
"%s: device is not a touch device", __func__);
return -EINVAL;
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return -EINVAL;
eis_queue_touch_up_event(device, touchid);
return 0;
}
void
eis_device_closed_by_client(struct eis_device *device)
{

View file

@ -117,45 +117,6 @@ eis_device_set_client_keymap(struct eis_device *device,
enum eis_keymap_type type,
int keymap_fd, size_t size);
int
eis_device_event_pointer_rel(struct eis_device *device,
double x, double y);
int
eis_device_event_pointer_abs(struct eis_device *device,
double x, double y);
int
eis_device_event_pointer_button(struct eis_device *device,
uint32_t button, bool state);
int
eis_device_event_pointer_scroll(struct eis_device *device,
double x, double y);
int
eis_device_event_pointer_scroll_discrete(struct eis_device *device,
int32_t x, int32_t y);
int
eis_device_event_pointer_scroll_stop(struct eis_device *device, bool x, bool y);
int
eis_device_event_pointer_scroll_cancel(struct eis_device *device, bool x, bool y);
int
eis_device_event_keyboard_key(struct eis_device *device,
uint32_t key, bool state);
int
eis_device_event_touch_down(struct eis_device *device, uint32_t touchid,
double x, double y);
int
eis_device_event_touch_motion(struct eis_device *device, uint32_t touchid,
double x, double y);
int
eis_device_event_touch_up(struct eis_device *device, uint32_t touchid);
void
eis_device_closed_by_client(struct eis_device *device);