mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2026-02-04 18:50:28 +01:00
A libei context can be initialized as active or passive context - an "active" context sends events, a "passive" context receives events. The EIS context supports both simultaneously, it is up to the implementation to disconnect libei clients that it does not want to suppport. For example, the xdotool use-case creates an active libei context. The EIS implementation controls and sets up the devices, but libei sends the events. In an input-capturing use-case, the EIS implementation controls and sets up the devices **and** sends the events. libei is merely the receiver for any event, it cannot send events. Thus this use-case requires a passive libei context. Most of this code is copy/paste with minor modifications - libei already had the code to send events, libeis had the code to receive events, so the vast majority of this patch is copying the code into the respective other library, swap "ei" and "eis" and then apply the various minor modifications needed to hook into the existing library. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
1424 lines
31 KiB
C
1424 lines
31 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 <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
|
|
|
|
#include "util-io.h"
|
|
#include "util-macros.h"
|
|
#include "util-object.h"
|
|
#include "util-sources.h"
|
|
#include "util-strings.h"
|
|
|
|
#include "libei.h"
|
|
#include "libei-private.h"
|
|
#include "libei-proto.h"
|
|
#include "brei-shared.h"
|
|
|
|
_Static_assert(sizeof(enum ei_device_capability) == sizeof(int), "Invalid enum size");
|
|
_Static_assert(sizeof(enum ei_property_permission) == sizeof(int), "Invalid enum size");
|
|
_Static_assert(sizeof(enum ei_keymap_type) == sizeof(int), "Invalid enum size");
|
|
_Static_assert(sizeof(enum ei_event_type) == sizeof(int), "Invalid enum size");
|
|
_Static_assert(sizeof(enum ei_log_priority) == sizeof(int), "Invalid enum size");
|
|
|
|
static struct ei_seat *
|
|
ei_find_seat(struct ei *ei, uint32_t seatid)
|
|
{
|
|
struct ei_seat *seat;
|
|
|
|
list_for_each(seat, &ei->seats, link) {
|
|
if (seat->id == seatid)
|
|
return seat;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static struct ei_device *
|
|
ei_find_device(struct ei *ei, uint32_t deviceid)
|
|
{
|
|
struct ei_seat *seat;
|
|
|
|
list_for_each(seat, &ei->seats, link) {
|
|
struct ei_device *device = ei_seat_find_device(seat, deviceid);
|
|
if (device)
|
|
return device;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
ei_destroy(struct ei *ei)
|
|
{
|
|
ei_disconnect(ei);
|
|
|
|
struct ei_event *e;
|
|
while ((e = ei_get_event(ei)) != NULL)
|
|
ei_event_unref(e);
|
|
|
|
if (ei->backend_interface.destroy)
|
|
ei->backend_interface.destroy(ei, ei->backend);
|
|
ei->backend = NULL;
|
|
sink_unref(ei->sink);
|
|
free(ei->name);
|
|
|
|
struct ei_property *prop;
|
|
list_for_each_safe(prop, &ei->properties, link) {
|
|
ei_property_unref(prop);
|
|
}
|
|
}
|
|
|
|
static
|
|
OBJECT_IMPLEMENT_CREATE(ei);
|
|
_public_
|
|
OBJECT_IMPLEMENT_REF(ei);
|
|
_public_
|
|
OBJECT_IMPLEMENT_UNREF_CLEANUP(ei);
|
|
_public_
|
|
OBJECT_IMPLEMENT_SETTER(ei, user_data, void *);
|
|
_public_
|
|
OBJECT_IMPLEMENT_GETTER(ei, user_data, void *);
|
|
|
|
DEFINE_UNREF_CLEANUP_FUNC(ei_device);
|
|
DEFINE_UNREF_CLEANUP_FUNC(ei_region);
|
|
|
|
static void
|
|
set_prop_cmdline(struct ei *ei)
|
|
{
|
|
_cleanup_free_ char *cmdline = cmdline_as_str();
|
|
ei_property_update(ei, "ei.application.cmdline", cmdline, EI_PROPERTY_PERM_NONE);
|
|
}
|
|
|
|
static void
|
|
set_prop_pid(struct ei *ei)
|
|
{
|
|
char pid[64];
|
|
|
|
xsnprintf(pid, sizeof(pid), "%d", getpid());
|
|
ei_property_update(ei, "ei.application.pid", pid, EI_PROPERTY_PERM_NONE);
|
|
}
|
|
|
|
static void
|
|
set_prop_type(struct ei *ei)
|
|
{
|
|
ei_property_update(ei, "ei.connection.type", "socket", EI_PROPERTY_PERM_NONE);
|
|
}
|
|
|
|
static struct ei *
|
|
ei_create_context(bool is_active, void *user_data)
|
|
{
|
|
_unref_(ei) *ei = ei_create(NULL);
|
|
|
|
ei->state = EI_STATE_NEW;
|
|
ei->requests = ei_proto_get_requests();
|
|
list_init(&ei->event_queue);
|
|
list_init(&ei->seats);
|
|
list_init(&ei->properties);
|
|
|
|
ei_log_set_handler(ei, NULL);
|
|
ei_log_set_priority(ei, EI_LOG_PRIORITY_INFO);
|
|
ei->sink = sink_new();
|
|
if (!ei->sink)
|
|
return NULL;
|
|
|
|
ei->user_data = user_data;
|
|
ei->backend = NULL;
|
|
ei->is_active = is_active;
|
|
|
|
set_prop_pid(ei);
|
|
set_prop_cmdline(ei);
|
|
set_prop_type(ei);
|
|
|
|
return steal(&ei);
|
|
}
|
|
|
|
_public_ struct ei *
|
|
ei_new(void *user_data)
|
|
{
|
|
return ei_new_active(user_data);
|
|
}
|
|
|
|
_public_ struct ei *
|
|
ei_new_active(void *user_data)
|
|
{
|
|
return ei_create_context(true, user_data);
|
|
}
|
|
|
|
_public_ struct ei *
|
|
ei_new_passive(void *user_data)
|
|
{
|
|
return ei_create_context(false, user_data);
|
|
}
|
|
|
|
_public_ int
|
|
ei_get_fd(struct ei *ei)
|
|
{
|
|
return sink_get_fd(ei->sink);
|
|
}
|
|
|
|
_public_ void
|
|
ei_dispatch(struct ei *ei)
|
|
{
|
|
sink_dispatch(ei->sink);
|
|
}
|
|
|
|
static void
|
|
queue_event(struct ei *ei, struct ei_event *event)
|
|
{
|
|
log_debug(ei, "queuing event type %s (%u)\n",
|
|
ei_event_type_to_string(event->type), event->type);
|
|
|
|
list_append(&ei->event_queue, &event->link);
|
|
}
|
|
|
|
static void
|
|
insert_event(struct ei *ei, struct ei_event *event)
|
|
{
|
|
log_debug(ei, "inserting event type %s (%u)\n",
|
|
ei_event_type_to_string(event->type), event->type);
|
|
|
|
list_insert(&ei->event_queue, &event->link);
|
|
}
|
|
|
|
|
|
static void
|
|
queue_connect_event(struct ei *ei)
|
|
{
|
|
struct ei_event *e = ei_event_new(ei);
|
|
e->type = EI_EVENT_CONNECT;
|
|
|
|
queue_event(ei, e);
|
|
}
|
|
|
|
static void
|
|
queue_disconnect_event(struct ei *ei)
|
|
{
|
|
struct ei_event *e = ei_event_new(ei);
|
|
e->type = EI_EVENT_DISCONNECT;
|
|
|
|
queue_event(ei, e);
|
|
}
|
|
|
|
static void
|
|
queue_seat_added_event(struct ei_seat *seat)
|
|
{
|
|
struct ei *ei= ei_seat_get_context(seat);
|
|
|
|
struct ei_event *e = ei_event_new(ei);
|
|
e->type = EI_EVENT_SEAT_ADDED;
|
|
e->seat = ei_seat_ref(seat);
|
|
|
|
queue_event(ei, e);
|
|
}
|
|
|
|
static void
|
|
queue_seat_removed_event(struct ei_seat *seat)
|
|
{
|
|
struct ei *ei= ei_seat_get_context(seat);
|
|
|
|
struct ei_event *e = ei_event_new(ei);
|
|
e->type = EI_EVENT_SEAT_REMOVED;
|
|
e->seat = ei_seat_ref(seat);
|
|
|
|
queue_event(ei, e);
|
|
}
|
|
|
|
void
|
|
ei_queue_seat_removed_event(struct ei_seat *seat)
|
|
{
|
|
queue_seat_removed_event(seat);
|
|
}
|
|
|
|
static void
|
|
queue_device_added_event(struct ei_device *device)
|
|
{
|
|
struct ei *ei= ei_device_get_context(device);
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_DEVICE_ADDED;
|
|
|
|
queue_event(ei, e);
|
|
}
|
|
|
|
static void
|
|
queue_device_removed_event(struct ei_device *device)
|
|
{
|
|
struct ei *ei= ei_device_get_context(device);
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_DEVICE_REMOVED;
|
|
|
|
queue_event(ei, e);
|
|
}
|
|
|
|
static void
|
|
insert_device_removed_event(struct ei_device *device)
|
|
{
|
|
struct ei *ei= ei_device_get_context(device);
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_DEVICE_REMOVED;
|
|
|
|
insert_event(ei, e);
|
|
}
|
|
|
|
static void
|
|
queue_paused_event(struct ei_device *device)
|
|
{
|
|
struct ei *ei= ei_device_get_context(device);
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_DEVICE_PAUSED;
|
|
|
|
queue_event(ei, e);
|
|
}
|
|
|
|
static void
|
|
queue_resumed_event(struct ei_device *device)
|
|
{
|
|
struct ei *ei= ei_device_get_context(device);
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_DEVICE_RESUMED;
|
|
|
|
queue_event(ei, e);
|
|
}
|
|
|
|
static void
|
|
queue_keyboard_modifiers_event(struct ei_device *device,
|
|
const struct ei_xkb_modifiers *mods)
|
|
{
|
|
struct ei *ei= ei_device_get_context(device);
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_KEYBOARD_MODIFIERS;
|
|
e->modifiers = *mods;
|
|
|
|
queue_event(ei, e);
|
|
}
|
|
|
|
static void
|
|
queue_property_event(struct ei *ei, const char *name,
|
|
const char *value, uint32_t permissions)
|
|
{
|
|
struct ei_event *e = ei_event_new(ei);
|
|
e->type = EI_EVENT_PROPERTY;
|
|
e->prop.name = xstrdup(name);
|
|
e->prop.value = xstrdup(value);
|
|
e->prop.permissions = permissions;
|
|
|
|
queue_event(ei, e);
|
|
}
|
|
|
|
void
|
|
ei_queue_frame_event(struct ei_device *device)
|
|
{
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_FRAME;
|
|
|
|
queue_event(ei_device_get_context(device), e);
|
|
}
|
|
|
|
void
|
|
ei_queue_device_start_emulating_event(struct ei_device *device)
|
|
{
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_DEVICE_START_EMULATING;
|
|
|
|
queue_event(ei_device_get_context(device), e);
|
|
}
|
|
|
|
void
|
|
ei_queue_device_stop_emulating_event(struct ei_device *device)
|
|
{
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_DEVICE_STOP_EMULATING;
|
|
|
|
queue_event(ei_device_get_context(device), e);
|
|
}
|
|
|
|
void
|
|
ei_queue_pointer_rel_event(struct ei_device *device,
|
|
double dx, double dy)
|
|
{
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_POINTER_MOTION;
|
|
e->pointer.dx = dx;
|
|
e->pointer.dy = dy;
|
|
|
|
queue_event(ei_device_get_context(device), e);
|
|
}
|
|
|
|
void
|
|
ei_queue_pointer_abs_event(struct ei_device *device,
|
|
double x, double y)
|
|
{
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_POINTER_MOTION_ABSOLUTE;
|
|
e->pointer.absx = x;
|
|
e->pointer.absy = y;
|
|
|
|
queue_event(ei_device_get_context(device), e);
|
|
}
|
|
|
|
void
|
|
ei_queue_pointer_button_event(struct ei_device *device, uint32_t button,
|
|
bool is_press)
|
|
{
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_POINTER_BUTTON;
|
|
e->pointer.button = button;
|
|
e->pointer.button_is_press = is_press;
|
|
|
|
queue_event(ei_device_get_context(device), e);
|
|
}
|
|
|
|
void
|
|
ei_queue_pointer_scroll_event(struct ei_device *device,
|
|
double x, double y)
|
|
{
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_POINTER_SCROLL;
|
|
e->pointer.sx = x;
|
|
e->pointer.sy = y;
|
|
|
|
queue_event(ei_device_get_context(device), e);
|
|
}
|
|
|
|
void
|
|
ei_queue_pointer_scroll_discrete_event(struct ei_device *device,
|
|
int32_t x, int32_t y)
|
|
{
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_POINTER_SCROLL_DISCRETE;
|
|
e->pointer.sdx = x;
|
|
e->pointer.sdy = y;
|
|
|
|
queue_event(ei_device_get_context(device), e);
|
|
}
|
|
|
|
void
|
|
ei_queue_pointer_scroll_stop_event(struct ei_device *device, bool x, bool y)
|
|
{
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_POINTER_SCROLL_STOP;
|
|
e->pointer.stop_x = x;
|
|
e->pointer.stop_y = y;
|
|
|
|
queue_event(ei_device_get_context(device), e);
|
|
}
|
|
|
|
void
|
|
ei_queue_pointer_scroll_cancel_event(struct ei_device *device, bool x, bool y)
|
|
{
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_POINTER_SCROLL_CANCEL;
|
|
e->pointer.stop_x = x;
|
|
e->pointer.stop_y = y;
|
|
|
|
queue_event(ei_device_get_context(device), e);
|
|
}
|
|
|
|
void
|
|
ei_queue_keyboard_key_event(struct ei_device *device, uint32_t key,
|
|
bool is_press)
|
|
{
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_KEYBOARD_KEY;
|
|
e->keyboard.key = key;
|
|
e->keyboard.key_is_press = is_press;
|
|
|
|
queue_event(ei_device_get_context(device), e);
|
|
}
|
|
|
|
void
|
|
ei_queue_touch_down_event(struct ei_device *device, uint32_t touchid,
|
|
double x, double y)
|
|
{
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_TOUCH_DOWN;
|
|
e->touch.touchid = touchid,
|
|
e->touch.x = x;
|
|
e->touch.y = y;
|
|
|
|
queue_event(ei_device_get_context(device), e);
|
|
}
|
|
|
|
void
|
|
ei_queue_touch_motion_event(struct ei_device *device, uint32_t touchid,
|
|
double x, double y)
|
|
{
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_TOUCH_MOTION;
|
|
e->touch.touchid = touchid,
|
|
e->touch.x = x;
|
|
e->touch.y = y;
|
|
|
|
queue_event(ei_device_get_context(device), e);
|
|
}
|
|
|
|
void
|
|
ei_queue_touch_up_event(struct ei_device *device, uint32_t touchid)
|
|
{
|
|
struct ei_event *e = ei_event_new_for_device(device);
|
|
|
|
e->type = EI_EVENT_TOUCH_UP;
|
|
e->touch.touchid = touchid,
|
|
|
|
queue_event(ei_device_get_context(device), e);
|
|
}
|
|
|
|
void
|
|
ei_disconnect(struct ei *ei)
|
|
{
|
|
if (ei->state == EI_STATE_DISCONNECTED ||
|
|
ei->state == EI_STATE_DISCONNECTING)
|
|
return;
|
|
|
|
enum ei_state state = ei->state;
|
|
|
|
/* We need the disconnecting state to be re-entrant
|
|
ei_device_remove() may call ei_disconnect() on a socket error */
|
|
ei->state = EI_STATE_DISCONNECTING;
|
|
|
|
struct ei_seat *seat;
|
|
list_for_each_safe(seat, &ei->seats, link) {
|
|
ei_seat_remove(seat);
|
|
}
|
|
|
|
if (state != EI_STATE_NEW) {
|
|
ei->requests->disconnect(ei);
|
|
}
|
|
queue_disconnect_event(ei);
|
|
ei->state = EI_STATE_DISCONNECTED;
|
|
if (ei->source)
|
|
source_remove(ei->source);
|
|
ei->source = source_unref(ei->source);
|
|
}
|
|
|
|
static int
|
|
handle_msg_seat_added(struct ei *ei, uint32_t seatid,
|
|
const char *name, uint32_t capabilities)
|
|
{
|
|
log_debug(ei, "Added seat %#x '%s' with caps %#x\n",
|
|
seatid, name, capabilities);
|
|
|
|
struct ei_seat *seat = ei_seat_new(ei, seatid, name, capabilities);
|
|
|
|
/* seats list owns the ref */
|
|
list_append(&ei->seats, &seat->link);
|
|
|
|
queue_seat_added_event(seat);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
handle_msg_seat_removed(struct ei *ei, uint32_t seatid)
|
|
{
|
|
log_debug(ei, "server removed seat %#x\n", seatid);
|
|
|
|
struct ei_seat *seat = ei_find_seat(ei, seatid);
|
|
if (seat) {
|
|
ei_seat_remove(seat);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
handle_msg_device_added(struct ei *ei, uint32_t deviceid, uint32_t seatid,
|
|
const char *name, uint32_t capabilities)
|
|
{
|
|
struct ei_seat *seat = ei_find_seat(ei, seatid);
|
|
|
|
if (!seat) {
|
|
log_bug(ei, "Invalid seat id %#x for device %s (%#x)\n",
|
|
seatid, name, deviceid);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Wrong device id or a device already removed by the client but we
|
|
* won't know which unless we keep some device ID table. Not worth
|
|
* it, so just silently ignore */
|
|
if (ei_seat_find_device(seat, deviceid)) {
|
|
log_error(ei, "Server sent duplicate device id %#x\n", deviceid);
|
|
return -EINVAL;
|
|
}
|
|
|
|
_unref_(ei_device) *device = ei_device_new(seat, deviceid);
|
|
ei_device_set_name(device, name);
|
|
ei_device_set_capabilities(device, capabilities);
|
|
ei_device_added(device);
|
|
|
|
log_debug(ei,
|
|
"Added device %#x '%s' caps: %s%s%s%s seat: %s\n",
|
|
deviceid, name,
|
|
ei_device_has_capability(device, EI_DEVICE_CAP_POINTER) ? "p" : "",
|
|
ei_device_has_capability(device, EI_DEVICE_CAP_POINTER_ABSOLUTE) ? "a" : "",
|
|
ei_device_has_capability(device, EI_DEVICE_CAP_KEYBOARD) ? "k" : "",
|
|
ei_device_has_capability(device, EI_DEVICE_CAP_TOUCH) ? "t" : "",
|
|
ei_seat_get_name(seat));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
handle_msg_device_keymap(struct ei *ei, uint32_t deviceid,
|
|
enum ei_keymap_type keymap_type,
|
|
int keymap_fd, size_t keymap_sz)
|
|
{
|
|
log_debug(ei, "Adding keymap for %#x\n", deviceid);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
if (!device)
|
|
return 0;
|
|
|
|
ei_device_set_keymap(device, keymap_type, keymap_fd, keymap_sz);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
ei_queue_device_removed_event(struct ei_device *device)
|
|
{
|
|
queue_device_removed_event(device);
|
|
}
|
|
|
|
void
|
|
ei_insert_device_removed_event(struct ei_device *device)
|
|
{
|
|
insert_device_removed_event(device);
|
|
}
|
|
|
|
static int
|
|
handle_msg_device_added_done(struct ei *ei, uint32_t deviceid)
|
|
{
|
|
log_debug(ei, "Done with device %#x\n", deviceid);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
if (!device)
|
|
return 0;
|
|
|
|
queue_device_added_event(device);
|
|
ei_device_done(device);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
handle_msg_device_region(struct ei *ei, uint32_t deviceid,
|
|
uint32_t x, uint32_t y,
|
|
uint32_t w, uint32_t h,
|
|
double scale)
|
|
{
|
|
log_debug(ei, "Adding device region for %#x\n", deviceid);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
if (!device)
|
|
return 0;
|
|
|
|
_unref_(ei_region) *r = ei_region_new();
|
|
ei_region_set_offset(r, x, y);
|
|
ei_region_set_size(r, w, h);
|
|
ei_region_set_physical_scale(r, scale);
|
|
|
|
ei_device_add_region(device, r);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
handle_msg_keyboard_modifiers(struct ei *ei, uint32_t deviceid,
|
|
uint32_t depressed, uint32_t latched,
|
|
uint32_t locked, uint32_t group)
|
|
{
|
|
log_debug(ei, "Setting modifiers for %#x\n", deviceid);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
if (!device)
|
|
return 0;
|
|
|
|
if (!ei_device_has_capability(device, EI_DEVICE_CAP_KEYBOARD)) {
|
|
log_bug(ei,"Modifier event for non-keyboard\n");
|
|
return -EPROTO;
|
|
}
|
|
|
|
struct ei_xkb_modifiers mods = {
|
|
.depressed = depressed,
|
|
.latched = latched,
|
|
.locked = locked,
|
|
.group = group,
|
|
};
|
|
queue_keyboard_modifiers_event(device, &mods);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
handle_msg_property(struct ei *ei, const char *name, const char *value,
|
|
uint32_t permissions)
|
|
{
|
|
int rc = ei_property_update(ei, name, value, permissions);
|
|
if (rc == 0)
|
|
queue_property_event(ei, name, value, permissions);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
handle_msg_device_removed(struct ei *ei, uint32_t deviceid)
|
|
{
|
|
log_debug(ei, "Removed device %#x\n", deviceid);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
if (!device)
|
|
return 0;
|
|
|
|
ei_device_removed_by_server(device);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
handle_msg_device_resumed(struct ei *ei, uint32_t deviceid)
|
|
{
|
|
log_debug(ei, "Resumed device %#x\n", deviceid);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
if (device) {
|
|
ei_device_resumed(device);
|
|
queue_resumed_event(device);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
handle_msg_device_paused(struct ei *ei, uint32_t deviceid)
|
|
{
|
|
log_debug(ei, "Paused device %#x\n", deviceid);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
if (device) {
|
|
ei_device_paused(device);
|
|
queue_paused_event(device);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
ei_send_property(struct ei *ei, const char *name, const char *value, uint32_t permissions)
|
|
{
|
|
/* properties before CONNECTED_DONE are handled in a custom way */
|
|
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
|
return 0;
|
|
|
|
int rc = ei->requests->property(ei, name, value, permissions);
|
|
if (rc)
|
|
ei_disconnect(ei);
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
ei_send_close_device(struct ei_device *device)
|
|
{
|
|
struct ei *ei = ei_device_get_context(device);
|
|
|
|
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
|
return 0;
|
|
|
|
int rc = ei->requests->close_device(device);
|
|
if (rc)
|
|
ei_disconnect(ei);
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
ei_send_start_emulating(struct ei_device *device)
|
|
{
|
|
struct ei *ei = ei_device_get_context(device);
|
|
|
|
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
|
return 0;
|
|
|
|
int rc = ei->requests->start_emulating(device);
|
|
if (rc)
|
|
ei_disconnect(ei);
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
ei_send_stop_emulating(struct ei_device *device)
|
|
{
|
|
struct ei *ei = ei_device_get_context(device);
|
|
|
|
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
|
return 0;
|
|
|
|
int rc = ei->requests->stop_emulating(device);
|
|
if (rc)
|
|
ei_disconnect(ei);
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
ei_send_seat_bind(struct ei_seat *seat, uint32_t capabilities)
|
|
{
|
|
struct ei *ei = ei_seat_get_context(seat);
|
|
|
|
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
|
return 0;
|
|
|
|
int rc = ei->requests->bind_seat(seat, capabilities);
|
|
if (rc)
|
|
ei_disconnect(ei);
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
ei_send_seat_unbind(struct ei_seat *seat)
|
|
{
|
|
struct ei *ei = ei_seat_get_context(seat);
|
|
|
|
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
|
return 0;
|
|
|
|
int rc = ei->requests->unbind_seat(seat);
|
|
if (rc)
|
|
ei_disconnect(ei);
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
ei_send_frame(struct ei_device *device)
|
|
{
|
|
struct ei *ei = ei_device_get_context(device);
|
|
|
|
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
|
return 0;
|
|
|
|
int rc = ei->requests->frame(device);
|
|
if (rc)
|
|
ei_disconnect(ei);
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
ei_send_pointer_rel(struct ei_device *device, double x, double y)
|
|
{
|
|
struct ei *ei = ei_device_get_context(device);
|
|
|
|
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
|
return 0;
|
|
|
|
int rc = ei->requests->rel(device, x, y);
|
|
if (rc)
|
|
ei_disconnect(ei);
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
ei_send_pointer_abs(struct ei_device *device, double x, double y)
|
|
{
|
|
struct ei *ei = ei_device_get_context(device);
|
|
|
|
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
|
return 0;
|
|
|
|
int rc = ei->requests->abs(device, x, y);
|
|
if (rc)
|
|
ei_disconnect(ei);
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
ei_send_pointer_button(struct ei_device *device, uint32_t button, bool is_press)
|
|
{
|
|
struct ei *ei = ei_device_get_context(device);
|
|
|
|
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
|
return 0;
|
|
|
|
int rc = ei->requests->button(device, button, is_press);
|
|
if (rc)
|
|
ei_disconnect(ei);
|
|
return rc;
|
|
}
|
|
|
|
int ei_send_pointer_scroll(struct ei_device *device, double x, double y)
|
|
{
|
|
struct ei *ei = ei_device_get_context(device);
|
|
|
|
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
|
return 0;
|
|
|
|
int rc = ei->requests->scroll(device, x, y);
|
|
if (rc)
|
|
ei_disconnect(ei);
|
|
return rc;
|
|
}
|
|
|
|
int ei_send_pointer_scroll_stop(struct ei_device *device, double x, double y)
|
|
{
|
|
struct ei *ei = ei_device_get_context(device);
|
|
|
|
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
|
return 0;
|
|
|
|
int rc = ei->requests->scroll_stop(device, x, y);
|
|
if (rc)
|
|
ei_disconnect(ei);
|
|
return rc;
|
|
}
|
|
|
|
int ei_send_pointer_scroll_cancel(struct ei_device *device, double x, double y)
|
|
{
|
|
struct ei *ei = ei_device_get_context(device);
|
|
|
|
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
|
return 0;
|
|
|
|
int rc = ei->requests->scroll_cancel(device, x, y);
|
|
if (rc)
|
|
ei_disconnect(ei);
|
|
return rc;
|
|
}
|
|
|
|
|
|
int ei_send_pointer_scroll_discrete(struct ei_device *device, int32_t x, int32_t y)
|
|
{
|
|
struct ei *ei = ei_device_get_context(device);
|
|
|
|
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
|
return 0;
|
|
|
|
int rc = ei->requests->scroll_discrete(device, x, y);
|
|
if (rc)
|
|
ei_disconnect(ei);
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
ei_send_keyboard_key(struct ei_device *device, uint32_t key, bool is_press)
|
|
{
|
|
struct ei *ei = ei_device_get_context(device);
|
|
|
|
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
|
return 0;
|
|
|
|
int rc = ei->requests->key(device, key, is_press);
|
|
if (rc)
|
|
ei_disconnect(ei);
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
ei_send_touch_down(struct ei_device *device, uint32_t tid,
|
|
double x, double y)
|
|
{
|
|
struct ei *ei = ei_device_get_context(device);
|
|
|
|
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
|
return 0;
|
|
|
|
int rc = ei->requests->touch_down(device, tid, x, y);
|
|
if (rc)
|
|
ei_disconnect(ei);
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
ei_send_touch_motion(struct ei_device *device, uint32_t tid,
|
|
double x, double y)
|
|
{
|
|
struct ei *ei = ei_device_get_context(device);
|
|
|
|
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
|
return 0;
|
|
|
|
int rc = ei->requests->touch_motion(device, tid, x, y);
|
|
if (rc)
|
|
ei_disconnect(ei);
|
|
return rc;
|
|
}
|
|
|
|
int
|
|
ei_send_touch_up(struct ei_device *device, uint32_t tid)
|
|
{
|
|
struct ei *ei = ei_device_get_context(device);
|
|
|
|
if (ei->state == EI_STATE_NEW || ei->state == EI_STATE_DISCONNECTED)
|
|
return 0;
|
|
|
|
int rc = ei->requests->touch_up(device, tid);
|
|
if (rc)
|
|
ei_disconnect(ei);
|
|
return rc;
|
|
}
|
|
|
|
_public_ struct ei_event*
|
|
ei_get_event(struct ei *ei)
|
|
{
|
|
if (list_empty(&ei->event_queue))
|
|
return NULL;
|
|
|
|
struct ei_event *e = list_first_entry(&ei->event_queue, e, link);
|
|
list_remove(&e->link);
|
|
|
|
return e;
|
|
}
|
|
|
|
_public_ struct ei_event*
|
|
ei_peek_event(struct ei *ei)
|
|
{
|
|
if (list_empty(&ei->event_queue))
|
|
return NULL;
|
|
|
|
struct ei_event *e = list_first_entry(&ei->event_queue, e, link);
|
|
return ei_event_ref(e);
|
|
}
|
|
|
|
static int handle_msg_connected(struct ei *ei) {
|
|
ei->state = EI_STATE_CONNECTED;
|
|
queue_connect_event(ei);
|
|
return 0;
|
|
}
|
|
|
|
static int handle_msg_disconnected(struct ei *ei, bool is_active) {
|
|
if (ei->is_active == is_active) {
|
|
log_bug_client(ei, "Unable to connect %s ei context to %s EIS implementation\n",
|
|
is_active ? "active" : "passive",
|
|
is_active ? "active" : "passive");
|
|
}
|
|
return -ECANCELED;
|
|
}
|
|
|
|
#define DISCONNECT_IF_ACTIVE_CONTEXT(ei_) do {\
|
|
if (ei_->is_active) { \
|
|
log_bug_client(ei_, "Invalid event from passive EIS context. Disconnecting\n"); \
|
|
return -ECANCELED; \
|
|
} \
|
|
} while(0)
|
|
|
|
static int
|
|
handle_msg_start_emulating(struct ei *ei, uint32_t deviceid)
|
|
{
|
|
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
|
|
if (device)
|
|
ei_device_event_start_emulating(device);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
handle_msg_stop_emulating(struct ei *ei, uint32_t deviceid)
|
|
{
|
|
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
|
|
if (device)
|
|
ei_device_event_stop_emulating(device);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
handle_msg_frame(struct ei *ei, uint32_t deviceid)
|
|
{
|
|
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
|
|
if (device)
|
|
return ei_device_event_frame(device);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
handle_msg_pointer_rel(struct ei *ei, uint32_t deviceid,
|
|
double x, double y)
|
|
{
|
|
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
|
|
if (device)
|
|
return ei_device_event_pointer_rel(device, x, y);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int
|
|
handle_msg_pointer_abs(struct ei *ei, uint32_t deviceid,
|
|
double x, double y)
|
|
{
|
|
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
|
|
if (device)
|
|
return ei_device_event_pointer_abs(device, x, y);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int
|
|
handle_msg_pointer_button(struct ei *ei, uint32_t deviceid,
|
|
uint32_t button, bool state)
|
|
{
|
|
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
|
|
if (device)
|
|
return ei_device_event_pointer_button(device, button, state);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int
|
|
handle_msg_pointer_scroll(struct ei *ei, uint32_t deviceid,
|
|
double x, double y)
|
|
{
|
|
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
|
|
if (device)
|
|
return ei_device_event_pointer_scroll(device, x, y);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int
|
|
handle_msg_pointer_scroll_discrete(struct ei *ei, uint32_t deviceid,
|
|
int32_t x, int32_t y)
|
|
{
|
|
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
|
|
if (device)
|
|
return ei_device_event_pointer_scroll_discrete(device, x, y);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int
|
|
handle_msg_pointer_scroll_stop(struct ei *ei, uint32_t deviceid,
|
|
bool x, bool y, bool is_cancel)
|
|
{
|
|
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
|
|
if (device) {
|
|
if (is_cancel)
|
|
return ei_device_event_pointer_scroll_cancel(device, x, y);
|
|
else
|
|
return ei_device_event_pointer_scroll_stop(device, x, y);
|
|
}
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int
|
|
handle_msg_keyboard_key(struct ei *ei, uint32_t deviceid,
|
|
uint32_t key, bool state)
|
|
{
|
|
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
|
|
if (device)
|
|
return ei_device_event_keyboard_key(device, key, state);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int
|
|
handle_msg_touch_down(struct ei *ei, uint32_t deviceid,
|
|
uint32_t touchid, double x, double y)
|
|
{
|
|
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
|
|
if (device)
|
|
return ei_device_event_touch_down(device, touchid, x, y);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int
|
|
handle_msg_touch_motion(struct ei *ei, uint32_t deviceid,
|
|
uint32_t touchid, double x, double y)
|
|
{
|
|
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
|
|
if (device)
|
|
return ei_device_event_touch_motion(device, touchid, x, y);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int
|
|
handle_msg_touch_up(struct ei *ei, uint32_t deviceid, uint32_t touchid)
|
|
{
|
|
DISCONNECT_IF_ACTIVE_CONTEXT(ei);
|
|
|
|
struct ei_device *device = ei_find_device(ei, deviceid);
|
|
|
|
if (device)
|
|
return ei_device_event_touch_up(device, touchid);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static const struct ei_proto_interface intf_state_backend = {
|
|
/* Everything triggers -EPROTO */
|
|
.connected = NULL,
|
|
};
|
|
|
|
static const struct ei_proto_interface intf_state_connecting = {
|
|
.connected = handle_msg_connected,
|
|
.disconnected = handle_msg_disconnected,
|
|
};
|
|
|
|
static const struct ei_proto_interface intf_state_connected = {
|
|
.disconnected = handle_msg_disconnected,
|
|
.seat_added = handle_msg_seat_added,
|
|
.seat_removed = handle_msg_seat_removed,
|
|
.device_added = handle_msg_device_added,
|
|
.device_removed = handle_msg_device_removed,
|
|
.device_resumed = handle_msg_device_resumed,
|
|
.device_paused = handle_msg_device_paused,
|
|
.device_region = handle_msg_device_region,
|
|
.device_keymap = handle_msg_device_keymap,
|
|
.device_done = handle_msg_device_added_done,
|
|
.keyboard_modifiers = handle_msg_keyboard_modifiers,
|
|
.property = handle_msg_property,
|
|
|
|
/* events */
|
|
.start_emulating = handle_msg_start_emulating,
|
|
.stop_emulating = handle_msg_stop_emulating,
|
|
.rel = handle_msg_pointer_rel,
|
|
.abs = handle_msg_pointer_abs,
|
|
.button = handle_msg_pointer_button,
|
|
.scroll = handle_msg_pointer_scroll,
|
|
.scroll_stop = handle_msg_pointer_scroll_stop,
|
|
.scroll_discrete = handle_msg_pointer_scroll_discrete,
|
|
.key = handle_msg_keyboard_key,
|
|
.touch_down = handle_msg_touch_down,
|
|
.touch_motion = handle_msg_touch_motion,
|
|
.touch_up = handle_msg_touch_up,
|
|
.frame = handle_msg_frame,
|
|
};
|
|
|
|
static const struct ei_proto_interface *interfaces[] = {
|
|
[EI_STATE_NEW] = NULL,
|
|
[EI_STATE_BACKEND] = &intf_state_backend,
|
|
[EI_STATE_CONNECTING] = &intf_state_connecting,
|
|
[EI_STATE_CONNECTED] = &intf_state_connected,
|
|
[EI_STATE_DISCONNECTING] = NULL,
|
|
[EI_STATE_DISCONNECTED] = NULL,
|
|
};
|
|
|
|
static int
|
|
connection_message_callback(struct brei_message *bmsg, void *userdata)
|
|
{
|
|
struct ei *ei = userdata;
|
|
|
|
assert(ei->state < ARRAY_LENGTH(interfaces));
|
|
const struct ei_proto_interface *intf = interfaces[ei->state];
|
|
|
|
return ei_proto_handle_message(ei, intf, bmsg);
|
|
}
|
|
|
|
static void
|
|
connection_dispatch(struct source *source, void *userdata)
|
|
{
|
|
struct ei *ei = userdata;
|
|
enum ei_state old_state = ei->state;
|
|
|
|
int rc = brei_dispatch(source_get_fd(source), connection_message_callback, ei);
|
|
if (rc < 0) {
|
|
brei_drain_fd(source_get_fd(source));
|
|
ei_disconnect(ei);
|
|
}
|
|
|
|
static const char *states[] = {
|
|
"NEW",
|
|
"BACKEND",
|
|
"CONNECTING",
|
|
"CONNECTED",
|
|
"DISCONNECTED",
|
|
"DISCONNECTING",
|
|
};
|
|
if (rc == -ECANCELED)
|
|
log_info(ei, "Disconnected\n");
|
|
else if (rc)
|
|
log_warn(ei, "Connnection error: %s\n", strerror(-rc));
|
|
|
|
if (old_state != ei->state)
|
|
log_debug(ei, "Connnection dispatch: %s -> %s\n",
|
|
states[old_state],
|
|
states[ei->state]);
|
|
}
|
|
|
|
int
|
|
ei_set_connection(struct ei *ei, int fd)
|
|
{
|
|
struct source *source = source_new(fd, connection_dispatch, ei);
|
|
int rc = sink_add_source(ei->sink, source);
|
|
if (rc == 0) {
|
|
ei->source = source_ref(source);
|
|
ei->state = EI_STATE_BACKEND;
|
|
rc = ei->requests->connect(ei);
|
|
|
|
struct ei_property *prop;
|
|
list_for_each_safe(prop, &ei->properties, link) {
|
|
if (rc == 0)
|
|
rc = ei->requests->property(ei, prop->name, prop->value, prop->permissions);
|
|
}
|
|
|
|
if (rc == 0) {
|
|
rc = ei->requests->connect_done(ei);
|
|
}
|
|
if (rc == 0) {
|
|
ei->state = EI_STATE_CONNECTING;
|
|
}
|
|
if (rc != 0) {
|
|
log_error(ei, "message failed to send: %s\n", strerror(-rc));
|
|
ei_disconnect(ei);
|
|
}
|
|
}
|
|
|
|
source_unref(source);
|
|
|
|
return rc;
|
|
}
|
|
|
|
_public_ void
|
|
ei_configure_name(struct ei *ei, const char *name)
|
|
{
|
|
if (ei->state != EI_STATE_NEW) {
|
|
log_bug_client(ei,"Client is already connected\n");
|
|
return;
|
|
}
|
|
|
|
if (strlen(name) > 1024) {
|
|
log_bug_client(ei, "Client name too long\n");
|
|
return;
|
|
}
|
|
|
|
free(ei->name);
|
|
ei->name = xstrdup(name);
|
|
}
|
|
|
|
#ifdef _enable_tests_
|
|
#include "util-munit.h"
|
|
|
|
MUNIT_TEST(test_init_unref)
|
|
{
|
|
struct ei *ei = ei_new(NULL);
|
|
|
|
munit_assert_int(ei->state, ==, EI_STATE_NEW);
|
|
munit_assert(list_empty(&ei->event_queue));
|
|
munit_assert(list_empty(&ei->seats));
|
|
|
|
munit_assert_not_null(ei->sink);
|
|
|
|
struct ei *refd = ei_ref(ei);
|
|
munit_assert_ptr_equal(ei, refd);
|
|
munit_assert_int(ei->object.refcount, ==, 2);
|
|
|
|
struct ei *unrefd = ei_unref(ei);
|
|
munit_assert_null(unrefd);
|
|
|
|
unrefd = ei_unref(ei);
|
|
munit_assert_null(unrefd);
|
|
|
|
return MUNIT_OK;
|
|
}
|
|
|
|
MUNIT_TEST(test_configure_name)
|
|
{
|
|
struct ei *ei = ei_new(NULL);
|
|
|
|
ei_configure_name(ei, "foo");
|
|
munit_assert_string_equal(ei->name, "foo");
|
|
ei_configure_name(ei, "bar");
|
|
munit_assert_string_equal(ei->name, "bar");
|
|
|
|
/* ignore names that are too long */
|
|
char buf[1200] = {0};
|
|
memset(buf, 'a', sizeof(buf) - 1);
|
|
ei_configure_name(ei, buf);
|
|
munit_assert_string_equal(ei->name, "bar");
|
|
|
|
/* ignore names in all other states */
|
|
for (enum ei_state state = EI_STATE_NEW + 1;
|
|
state <= EI_STATE_DISCONNECTED;
|
|
state++) {
|
|
ei->state = state;
|
|
ei_configure_name(ei, "expect ignored");
|
|
munit_assert_string_equal(ei->name, "bar");
|
|
}
|
|
|
|
ei_unref(ei);
|
|
|
|
return MUNIT_OK;
|
|
}
|
|
#endif
|