libei/src/libeis-device.c
Peter Hutterer 37467881e6 Drop the trailing newline from the log messages
Punt this job to the caller, any structured logging handler doesn't need
them anyway and it makes handling of messages more awkward.

For our default log handlers (fprintf) we can just append them
ourselves.

Fixes #19
2022-08-11 10:09:27 +10:00

999 lines
24 KiB
C

/* 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 <errno.h>
#include "util-macros.h"
#include "util-bits.h"
#include "util-io.h"
#include "libeis-private.h"
#include "libeis-proto.h"
_public_
OBJECT_IMPLEMENT_REF(eis_keymap);
_public_
OBJECT_IMPLEMENT_UNREF_CLEANUP(eis_keymap);
_public_
OBJECT_IMPLEMENT_GETTER(eis_keymap, type, enum eis_keymap_type);
_public_
OBJECT_IMPLEMENT_GETTER(eis_keymap, fd, int);
_public_
OBJECT_IMPLEMENT_GETTER(eis_keymap, size, size_t);
_public_
OBJECT_IMPLEMENT_GETTER(eis_keymap, device, struct eis_device *);
_public_
OBJECT_IMPLEMENT_GETTER(eis_keymap, user_data, void *);
_public_
OBJECT_IMPLEMENT_SETTER(eis_keymap, user_data, void *);
static void
eis_keymap_destroy(struct eis_keymap *keymap)
{
if (!keymap->assigned)
eis_device_unref(keymap->device);
xclose(keymap->fd);
}
static
OBJECT_IMPLEMENT_CREATE(eis_keymap);
_public_ struct eis_keymap *
eis_device_new_keymap(struct eis_device *device,
enum eis_keymap_type type, int fd, size_t size)
{
switch (type) {
case EIS_KEYMAP_TYPE_XKB:
break;
default:
return NULL;
}
if (fd < 0 || size == 0)
return NULL;
int newfd = dup(fd);
if (newfd < 0)
return NULL;
struct eis_keymap *keymap = eis_keymap_create(NULL);
keymap->device = eis_device_ref(device);
keymap->fd = newfd;
keymap->type = type;
keymap->size = size;
return keymap;
}
struct eis *
eis_device_get_context(struct eis_device *device)
{
return eis_client_get_context(eis_device_get_client(device));
}
_public_ void
eis_keymap_add(struct eis_keymap *keymap)
{
struct eis_device *device = eis_keymap_get_device(keymap);
if (device->state != EIS_DEVICE_STATE_NEW) {
log_bug_client(eis_device_get_context(device),
"%s: device already (dis)connected", __func__);
return;
}
if (device->keymap) {
log_bug_client(eis_device_get_context(device),
"%s: only one keymap can only be assigned and only once", __func__);
return;
}
/* New keymap holds ref to the device, for assigned keymap the device
* holds the ref to the keymap instead */
device->keymap = eis_keymap_ref(keymap);
keymap->assigned = true;
eis_device_unref(keymap->device);
}
_public_ struct eis_keymap *
eis_device_keyboard_get_keymap(struct eis_device *device)
{
return device->keymap;
}
static void
eis_device_destroy(struct eis_device *device)
{
struct eis_region *r;
struct eis_event *event;
list_for_each_safe(r, &device->regions, link)
eis_region_unref(r);
/* regions_new does not own a ref */
eis_keymap_unref(device->keymap);
list_for_each_safe(event, &device->pending_event_queue, link) {
list_remove(&event->link);
eis_event_unref(event);
}
free(device->name);
}
_public_
OBJECT_IMPLEMENT_REF(eis_device);
_public_
OBJECT_IMPLEMENT_UNREF_CLEANUP(eis_device);
static
OBJECT_IMPLEMENT_CREATE(eis_device);
static
OBJECT_IMPLEMENT_PARENT(eis_device, eis_seat);
_public_
OBJECT_IMPLEMENT_GETTER(eis_device, user_data, void *);
_public_
OBJECT_IMPLEMENT_SETTER(eis_device, user_data, void *);
_public_
OBJECT_IMPLEMENT_GETTER(eis_device, name, const char *);
_public_
OBJECT_IMPLEMENT_GETTER(eis_device, type, enum eis_device_type);
_public_
OBJECT_IMPLEMENT_GETTER(eis_device, width, uint32_t);
_public_
OBJECT_IMPLEMENT_GETTER(eis_device, height, uint32_t);
_public_ struct eis_seat *
eis_device_get_seat(struct eis_device *device)
{
return eis_device_parent(device);
}
_public_ struct eis_region *
eis_device_get_region(struct eis_device *device, size_t index)
{
return list_nth_entry(struct eis_region, &device->regions, link, index);
}
_public_ struct eis_client *
eis_device_get_client(struct eis_device *device)
{
return eis_seat_get_client(eis_device_get_seat(device));
}
_public_ struct eis_device *
eis_seat_new_device(struct eis_seat *seat)
{
static uint32_t deviceid;
struct eis_device *device = eis_device_create(&seat->object);
device->id = seat->id | ++deviceid;
device->name = xstrdup("unnamed device");
device->capabilities = 0;
device->state = EIS_DEVICE_STATE_NEW;
device->type = EIS_DEVICE_TYPE_VIRTUAL;
list_init(&device->regions);
list_init(&device->regions_new);
list_init(&device->pending_event_queue);
list_append(&seat->devices, &device->link);
return eis_device_ref(device);
}
_public_ void
eis_device_configure_type(struct eis_device *device, enum eis_device_type type)
{
if (device->state != EIS_DEVICE_STATE_NEW)
return;
switch (type) {
case EIS_DEVICE_TYPE_VIRTUAL:
case EIS_DEVICE_TYPE_PHYSICAL:
break;
default:
log_bug_client(eis_device_get_context(device), "Invalid device type %u", type);
return;
}
device->type = type;
}
_public_ void
eis_device_configure_name(struct eis_device *device, const char *name)
{
if (device->state != EIS_DEVICE_STATE_NEW)
return;
free(device->name);
device->name = xstrdup(name);
}
_public_ void
eis_device_configure_capability(struct eis_device *device, enum eis_device_capability cap)
{
if (device->state != EIS_DEVICE_STATE_NEW)
return;
if (!eis_seat_has_capability(eis_device_get_seat(device), cap))
return;
flag_set(device->capabilities, cap);
}
_public_ void
eis_device_configure_size(struct eis_device *device, uint32_t width, uint32_t height)
{
if (device->type != EIS_DEVICE_TYPE_PHYSICAL) {
log_bug_client(eis_device_get_context(device), "Device type physical requird for size");
return;
}
if (width > 2000 || height > 2000)
log_warn(eis_device_get_context(device), "Suspicious device size: %ux%umm", width, height);
device->width = width;
device->height = height;
}
_public_ void
eis_device_add(struct eis_device *device)
{
if (device->state != EIS_DEVICE_STATE_NEW) {
log_bug_client(eis_device_get_context(device),
"%s: device already (dis)connected", __func__);
return;
}
if (!device->capabilities) {
log_bug_client(eis_device_get_context(device),
"%s: adding device without capabilities", __func__);
}
device->state = EIS_DEVICE_STATE_PAUSED;
eis_client_add_device(eis_device_get_client(device), device);
}
_public_ void
eis_device_remove(struct eis_device *device)
{
if (device->state == EIS_DEVICE_STATE_DEAD)
return;
if (device->state == EIS_DEVICE_STATE_EMULATING)
eis_device_stop_emulating(device);
device->state = EIS_DEVICE_STATE_DEAD;
eis_client_remove_device(eis_device_get_client(device), device);
list_remove(&device->link);
eis_device_unref(device);
}
_public_ bool
eis_device_has_capability(struct eis_device *device,
enum eis_device_capability cap)
{
switch (cap) {
case EIS_DEVICE_CAP_POINTER:
case EIS_DEVICE_CAP_POINTER_ABSOLUTE:
case EIS_DEVICE_CAP_KEYBOARD:
case EIS_DEVICE_CAP_TOUCH:
return flag_is_set(device->capabilities, cap);
}
return false;
}
#define handle_request_noargs(device_, func_) { \
struct eis *eis = eis_device_get_context(device); \
eis->requests->func_(device_, device->id); \
}
#define handle_request(device_, func_, ...) { \
struct eis *eis = eis_device_get_context(device); \
eis->requests->func_(device_, device->id, __VA_ARGS__); \
}
static void
eis_device_frame_now(struct eis_device *device)
{
uint64_t now = eis_now(eis_device_get_context(device));
eis_device_frame(device, now);
}
static void
_flush_frame(struct eis_device *device, const char *func)
{
if (device->send_frame_event) {
log_bug_client(eis_device_get_context(device),
"%s: missing call to eis_device_frame()", func);
eis_device_frame_now(device);
}
}
#define eis_device_flush_frame(d_) _flush_frame(d_, __func__)
_public_ void
eis_device_start_emulating(struct eis_device *device)
{
if (device->state != EIS_DEVICE_STATE_RESUMED)
return;
assert(!device->send_frame_event);
device->state = EIS_DEVICE_STATE_EMULATING;
handle_request_noargs(device, start_emulating);
}
_public_ void
eis_device_stop_emulating(struct eis_device *device)
{
if (device->state != EIS_DEVICE_STATE_EMULATING)
return;
eis_device_flush_frame(device);
device->state = EIS_DEVICE_STATE_RESUMED;
handle_request_noargs(device, stop_emulating);
}
_public_ void
eis_device_pointer_motion(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;
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return;
device->send_frame_event = true;
handle_request(device, rel, x, y);
}
_public_ void
eis_device_pointer_motion_absolute(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;
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return;
struct eis_region *r;
list_for_each(r, &device->regions, link) {
if (!eis_region_contains(r, x, y)) {
return;
}
}
device->send_frame_event = true;
handle_request(device, abs, x, y);
}
_public_ void
eis_device_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;
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return;
/* Ignore anything < BTN_MOUSE. Avoids the common error of sending
* numerical buttons instead of BTN_LEFT and friends. */
if (button < 0x110) {
log_bug_client(eis_device_get_context(device),
"%s: button code must be one of BTN_*", __func__);
return;
}
device->send_frame_event = true;
handle_request(device, button, button, is_press);
}
static inline void
eis_device_resume_scrolling(struct eis_device *device, double x, double y)
{
if (x) {
device->scroll.x_is_stopped = false;
device->scroll.x_is_cancelled = false;
}
if (y) {
device->scroll.y_is_stopped = false;
device->scroll.y_is_cancelled = false;
}
}
_public_ void
eis_device_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__);
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return;
eis_device_resume_scrolling(device, x, y);
device->send_frame_event = true;
handle_request(device, scroll, x, y);
}
_public_ void
eis_device_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__);
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return;
/* Filter out duplicate scroll stop requests */
if (x && !device->scroll.x_is_stopped)
device->scroll.x_is_stopped = true;
else
x = false;
if (y && !device->scroll.y_is_stopped)
device->scroll.y_is_stopped = true;
else
y = false;
if (x || y) {
device->send_frame_event = true;
handle_request(device, scroll_stop, x, y, false);
}
}
_public_ void
eis_device_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__);
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return;
/* Filter out duplicate scroll cancelled requests */
if (x && !device->scroll.x_is_cancelled) {
device->scroll.x_is_stopped = true;
device->scroll.x_is_cancelled = true;
} else {
x = false;
}
if (y && !device->scroll.y_is_cancelled) {
device->scroll.y_is_stopped = true;
device->scroll.y_is_cancelled = true;
} else {
y = false;
}
if (x || y) {
device->send_frame_event = true;
handle_request(device, scroll_stop, x, y, true);
}
}
_public_ void
eis_device_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__);
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return;
eis_device_resume_scrolling(device, x, y);
device->send_frame_event = true;
handle_request(device, scroll_discrete, x, y);
}
_public_ void
eis_device_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;
}
if (device->state != EIS_DEVICE_STATE_EMULATING)
return;
device->send_frame_event = true;
handle_request(device, key, key, is_press);
}
_public_
OBJECT_IMPLEMENT_REF(eis_touch);
_public_
OBJECT_IMPLEMENT_UNREF_CLEANUP(eis_touch);
_public_
OBJECT_IMPLEMENT_GETTER(eis_touch, device, struct eis_device*);
_public_
OBJECT_IMPLEMENT_GETTER(eis_touch, user_data, void *);
_public_
OBJECT_IMPLEMENT_SETTER(eis_touch, user_data, void *);
static void
eis_touch_destroy(struct eis_touch *touch)
{
if (touch->state == TOUCH_IS_DOWN)
eis_touch_up(touch);
/* Enforce a frame, otherwise we're just pending. If the client
* doesn't want this, it needs to eis_touch_up() */
eis_device_frame_now(touch->device);
eis_device_unref(touch->device);
}
static
OBJECT_IMPLEMENT_CREATE(eis_touch);
_public_ struct eis_touch *
eis_device_touch_new(struct eis_device *device)
{
static uint32_t tracking_id = 0;
/* Not using the device as parent object because we need a ref
* to it */
struct eis_touch *touch = eis_touch_create(NULL);
touch->device = eis_device_ref(device);
touch->state = TOUCH_IS_NEW;
touch->tracking_id = ++tracking_id;
return touch;
}
_public_ void
eis_touch_down(struct eis_touch *touch, double x, double y)
{
struct eis_device *device = eis_touch_get_device(touch);
if (touch->state != TOUCH_IS_NEW) {
log_bug_client(eis_device_get_context(device),
"%s: touch %u already down or up", __func__, touch->tracking_id);
return;
}
struct eis_region *r;
list_for_each(r, &device->regions, link) {
if (!eis_region_contains(r, x, y)) {
log_bug_client(eis_device_get_context(device),
"%s: touch %u has invalid x/y coordinates", __func__, touch->tracking_id);
touch->state = TOUCH_IS_UP;
return;
}
}
touch->state = TOUCH_IS_DOWN;
device->send_frame_event = true;
handle_request(device, touch_down, touch->tracking_id, x, y);
}
_public_ void
eis_touch_motion(struct eis_touch *touch, double x, double y)
{
if (touch->state != TOUCH_IS_DOWN)
return;
struct eis_device *device = eis_touch_get_device(touch);
struct eis_region *r;
list_for_each(r, &device->regions, link) {
if (!eis_region_contains(r, x, y)) {
log_bug_client(eis_device_get_context(device),
"%s: touch %u has invalid x/y coordinates", __func__, touch->tracking_id);
eis_touch_up(touch);
return;
}
}
device->send_frame_event = true;
handle_request(device, touch_motion, touch->tracking_id, x, y);
}
_public_ void
eis_touch_up(struct eis_touch *touch)
{
struct eis_device *device = eis_touch_get_device(touch);
if (touch->state != TOUCH_IS_DOWN) {
log_bug_client(eis_device_get_context(device),
"%s: touch %u is not currently down", __func__, touch->tracking_id);
return;
}
touch->state = TOUCH_IS_UP;
device->send_frame_event = true;
handle_request(device, touch_up, touch->tracking_id);
}
_public_ void
eis_device_frame(struct eis_device *device, uint64_t time)
{
if (device->state != EIS_DEVICE_STATE_EMULATING)
return;
if (!device->send_frame_event)
return;
device->send_frame_event = false;
handle_request(device, frame, time);
}
int
eis_device_event_frame(struct eis_device *device, uint64_t time)
{
if (device->state != EIS_DEVICE_STATE_EMULATING)
return -EINVAL;
eis_queue_frame_event(device, time);
return 0;
}
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))
return -EINVAL;
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)
{
switch (device->state) {
case EIS_DEVICE_STATE_DEAD:
case EIS_DEVICE_STATE_CLOSED_BY_CLIENT:
/* libei bug, ignore */
break;
case EIS_DEVICE_STATE_EMULATING:
if (!eis_client_is_sender(eis_device_get_client(device)))
eis_queue_device_stop_emulating_event(device);
_fallthrough_;
case EIS_DEVICE_STATE_NEW:
case EIS_DEVICE_STATE_PAUSED:
case EIS_DEVICE_STATE_RESUMED:
eis_queue_device_closed_event(device);
device->state = EIS_DEVICE_STATE_CLOSED_BY_CLIENT;
break;
}
}
void
eis_device_event_start_emulating(struct eis_device *device)
{
switch (device->state) {
case EIS_DEVICE_STATE_DEAD:
case EIS_DEVICE_STATE_CLOSED_BY_CLIENT:
case EIS_DEVICE_STATE_NEW:
case EIS_DEVICE_STATE_PAUSED:
break;
case EIS_DEVICE_STATE_RESUMED:
eis_queue_device_start_emulating_event(device);
device->state = EIS_DEVICE_STATE_EMULATING;
break;
case EIS_DEVICE_STATE_EMULATING:
break;
}
}
void
eis_device_event_stop_emulating(struct eis_device *device)
{
switch (device->state) {
case EIS_DEVICE_STATE_DEAD:
case EIS_DEVICE_STATE_CLOSED_BY_CLIENT:
case EIS_DEVICE_STATE_NEW:
case EIS_DEVICE_STATE_PAUSED:
case EIS_DEVICE_STATE_RESUMED:
break;
case EIS_DEVICE_STATE_EMULATING:
eis_queue_device_stop_emulating_event(device);
device->state = EIS_DEVICE_STATE_RESUMED;
break;
}
}
_public_ void
eis_device_pause(struct eis_device *device)
{
if (device->state != EIS_DEVICE_STATE_RESUMED)
return;
device->state = EIS_DEVICE_STATE_PAUSED;
eis_client_pause_device(eis_device_get_client(device), device);
}
_public_ void
eis_device_resume(struct eis_device *device)
{
if (device->state != EIS_DEVICE_STATE_PAUSED)
return;
device->state = EIS_DEVICE_STATE_RESUMED;
eis_client_resume_device(eis_device_get_client(device), device);
}
_public_ void
eis_device_keyboard_send_xkb_modifiers(struct eis_device *device, uint32_t depressed,
uint32_t latched, uint32_t locked, uint32_t group)
{
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;
}
eis_client_keyboard_modifiers(eis_device_get_client(device),
device, depressed, latched, locked, group);
}