/* * 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 #include #include #include #include "util-logger.h" #include "util-macros.h" #include "util-object.h" #include "util-sources.h" #include "util-strings.h" #include "libeis.h" #include "libeis-private.h" static struct eis_event* eis_event_ref(struct eis_event *event); static void eis_event_destroy(struct eis_event *event) { switch (event->type) { case EIS_EVENT_CLIENT_CONNECT: case EIS_EVENT_CLIENT_DISCONNECT: case EIS_EVENT_DEVICE_ADDED: case EIS_EVENT_DEVICE_REMOVED: case EIS_EVENT_POINTER_BUTTON: case EIS_EVENT_POINTER_MOTION: case EIS_EVENT_KEYBOARD_KEY: break; default: abort(); /* not yet implemented */ } event->device = eis_device_unref(event->device); event->client = eis_client_unref(event->client); } static OBJECT_IMPLEMENT_INIT(eis_event); /* this one is not public */ OBJECT_IMPLEMENT_REF(eis_event); _public_ OBJECT_IMPLEMENT_UNREF(eis_event); _public_ OBJECT_IMPLEMENT_GETTER(eis_event, type, enum eis_event_type); _public_ OBJECT_IMPLEMENT_GETTER(eis_event, client, struct eis_client*); _public_ OBJECT_IMPLEMENT_GETTER(eis_event, device, struct eis_device*); /* FIXME: these should contain error checks but for now this will do */ _public_ OBJECT_IMPLEMENT_GETTER(eis_event_pointer, x, int); _public_ OBJECT_IMPLEMENT_GETTER(eis_event_pointer, y, int); _public_ OBJECT_IMPLEMENT_GETTER(eis_event_pointer, button, uint32_t); _public_ OBJECT_IMPLEMENT_GETTER(eis_event_pointer, button_is_press, bool); _public_ OBJECT_IMPLEMENT_GETTER(eis_event_keyboard, key, uint32_t); _public_ OBJECT_IMPLEMENT_GETTER(eis_event_keyboard, key_is_press, bool); _public_ struct eis_event_pointer * eis_event_get_pointer_event(struct eis_event *e) { switch (e->type) { case EIS_EVENT_NONE: case EIS_EVENT_CLIENT_CONNECT: case EIS_EVENT_CLIENT_DISCONNECT: case EIS_EVENT_DEVICE_ADDED: case EIS_EVENT_DEVICE_REMOVED: case EIS_EVENT_REQUEST_CAPABILITY: case EIS_EVENT_CANCEL_CAPABILITY: break; case EIS_EVENT_POINTER_MOTION: case EIS_EVENT_POINTER_MOTION_ABSOLUTE: case EIS_EVENT_POINTER_BUTTON: case EIS_EVENT_POINTER_SCROLL: case EIS_EVENT_POINTER_SCROLL_DISCRETE: return container_of(e, struct eis_event_pointer, base); case EIS_EVENT_KEYBOARD_KEY: case EIS_EVENT_TOUCH_DOWN: case EIS_EVENT_TOUCH_UP: case EIS_EVENT_TOUCH_MOTION: break; } return NULL; } _public_ struct eis_event_keyboard * eis_event_get_keyboard_event(struct eis_event *e) { switch (e->type) { case EIS_EVENT_NONE: case EIS_EVENT_CLIENT_CONNECT: case EIS_EVENT_CLIENT_DISCONNECT: case EIS_EVENT_DEVICE_ADDED: case EIS_EVENT_DEVICE_REMOVED: case EIS_EVENT_REQUEST_CAPABILITY: case EIS_EVENT_CANCEL_CAPABILITY: case EIS_EVENT_POINTER_MOTION: case EIS_EVENT_POINTER_MOTION_ABSOLUTE: case EIS_EVENT_POINTER_BUTTON: case EIS_EVENT_POINTER_SCROLL: case EIS_EVENT_POINTER_SCROLL_DISCRETE: break; case EIS_EVENT_KEYBOARD_KEY: return container_of(e, struct eis_event_keyboard, base); case EIS_EVENT_TOUCH_DOWN: case EIS_EVENT_TOUCH_UP: case EIS_EVENT_TOUCH_MOTION: break; } return NULL; } static void eis_destroy(struct eis *eis) { struct eis_client *c, *tmp; list_for_each_safe(c, tmp, &eis->clients, link) { eis_client_disconnect(c); } struct eis_event *e; while ((e = eis_get_event(eis)) != NULL) eis_event_unref(e); eis->logger = logger_unref(eis->logger); if (eis->backend_interface.destroy) eis->backend_interface.destroy(eis, eis->backend); sink_unref(eis->sink); } OBJECT_IMPLEMENT_CREATE(eis); _public_ OBJECT_IMPLEMENT_REF(eis); _public_ OBJECT_IMPLEMENT_UNREF(eis); #define _cleanup_eis_ _cleanup_(eis_cleanup) _public_ OBJECT_IMPLEMENT_SETTER(eis, userdata, void *); OBJECT_IMPLEMENT_GETTER(eis, userdata, void *); _public_ struct eis * eis_new(void *user_data) { _cleanup_eis_ struct eis *eis = eis_create(NULL); list_init(&eis->clients); list_init(&eis->event_queue); eis->logger = logger_new("eis", eis); logger_set_priority(eis->logger, LOGGER_DEBUG); eis->sink = sink_new(); if (!eis->sink) return NULL; return steal(&eis); } _public_ int eis_get_fd(struct eis *eis) { return sink_get_fd(eis->sink); } _public_ void eis_dispatch(struct eis *eis) { sink_dispatch(eis->sink); } static void eis_queue_event(struct eis *eis, struct eis_event *event) { log_debug(eis, "queuing event type %d\n", event->type); list_append(&eis->event_queue, &event->link); } void eis_queue_connect_event(struct eis_client *client) { struct eis *eis = eis_client_get_context(client); struct eis_event_client *e = xalloc(sizeof(*e)); eis_event_init_object(&e->base, &eis->object); e->base.client = eis_client_ref(client); e->base.type = EIS_EVENT_CLIENT_CONNECT; eis_queue_event(eis, &e->base); } void eis_queue_disconnect_event(struct eis_client *client) { struct eis *eis = eis_client_get_context(client); struct eis_event_client *e = xalloc(sizeof(*e)); eis_event_init_object(&e->base, &eis->object); e->base.type = EIS_EVENT_CLIENT_DISCONNECT; e->base.client = eis_client_ref(client); eis_queue_event(eis, &e->base); } void eis_queue_added_event(struct eis_device *device) { struct eis_client *client = eis_device_get_client(device); struct eis *eis = eis_client_get_context(client); struct eis_event_client *e = xalloc(sizeof(*e)); eis_event_init_object(&e->base, &eis->object); e->base.type = EIS_EVENT_DEVICE_ADDED; e->base.client = eis_client_ref(client); e->base.device = eis_device_ref(device); eis_queue_event(eis, &e->base); } void eis_queue_removed_event(struct eis_device *device) { struct eis_client *client = eis_device_get_client(device); struct eis *eis = eis_client_get_context(client); struct eis_event_client *e = xalloc(sizeof(*e)); eis_event_init_object(&e->base, &eis->object); e->base.type = EIS_EVENT_DEVICE_REMOVED; e->base.client = eis_client_ref(client); e->base.device = eis_device_ref(device); eis_queue_event(eis, &e->base); } void eis_queue_pointer_rel_event(struct eis_device *device, int x, int y) { struct eis_client *client = eis_device_get_client(device); struct eis *eis = eis_client_get_context(client); struct eis_event_pointer *e = xalloc(sizeof(*e)); eis_event_init_object(&e->base, &eis->object); e->base.type = EIS_EVENT_POINTER_MOTION; e->base.client = eis_client_ref(client); e->base.device = eis_device_ref(device); e->x = x; e->y = y; eis_queue_event(eis, &e->base); } void eis_queue_pointer_button_event(struct eis_device *device, uint32_t button, bool is_press) { struct eis_client *client = eis_device_get_client(device); struct eis *eis = eis_client_get_context(client); struct eis_event_pointer *e = xalloc(sizeof(*e)); eis_event_init_object(&e->base, &eis->object); e->base.type = EIS_EVENT_POINTER_BUTTON; e->base.client = eis_client_ref(client); e->base.device = eis_device_ref(device); e->button = button; e->button_is_press = is_press; eis_queue_event(eis, &e->base); } void eis_queue_keyboard_key_event(struct eis_device *device, uint32_t key, bool is_press) { struct eis_client *client = eis_device_get_client(device); struct eis *eis = eis_client_get_context(client); struct eis_event_keyboard *e = xalloc(sizeof(*e)); eis_event_init_object(&e->base, &eis->object); e->base.type = EIS_EVENT_KEYBOARD_KEY; e->base.client = eis_client_ref(client); e->base.device = eis_device_ref(device); e->key = key; e->key_is_press = is_press; eis_queue_event(eis, &e->base); } _public_ struct eis_event* eis_get_event(struct eis *eis) { if (list_empty(&eis->event_queue)) return NULL; struct eis_event *e = list_first_entry(&eis->event_queue, e, link); list_remove(&e->link); return e; } _public_ struct eis_event * eis_peek_event(struct eis *eis) { if (list_empty(&eis->event_queue)) return NULL; struct eis_event *e = list_first_entry(&eis->event_queue, e, link); return eis_event_ref(e); } _public_ enum eis_event_type eis_next_event_type(struct eis *eis) { if (list_empty(&eis->event_queue)) return EIS_EVENT_NONE; struct eis_event *e = list_first_entry(&eis->event_queue, e, link); return e->type; } void eis_add_client(struct eis *eis, struct eis_client *client) { list_append(&eis->clients, &client->link); }