mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2026-01-19 04:30:30 +01:00
This was already spelled out in the documentation but just not yet implemented. New starting state for any device added by EIS is "suspended", the server needs to explicitly resume it before events are accepted. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
446 lines
11 KiB
C
446 lines
11 KiB
C
/*
|
|
* 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-bits.h"
|
|
#include "util-macros.h"
|
|
#include "util-mem.h"
|
|
#include "util-strings.h"
|
|
|
|
#include "libei-private.h"
|
|
|
|
static void
|
|
ei_device_destroy(struct ei_device *device)
|
|
{
|
|
free(device->name);
|
|
}
|
|
|
|
_public_
|
|
OBJECT_IMPLEMENT_REF(ei_device);
|
|
_public_
|
|
OBJECT_IMPLEMENT_UNREF(ei_device);
|
|
#define _cleanup_ei_device_ _cleanup_(ei_device_cleanup)
|
|
|
|
OBJECT_IMPLEMENT_CREATE(ei_device);
|
|
static
|
|
OBJECT_IMPLEMENT_PARENT(ei_device, ei);
|
|
_public_
|
|
OBJECT_IMPLEMENT_GETTER(ei_device, name, const char *);
|
|
_public_
|
|
OBJECT_IMPLEMENT_GETTER(ei_device, user_data, void *);
|
|
_public_
|
|
OBJECT_IMPLEMENT_SETTER(ei_device, user_data, void *);
|
|
|
|
_public_ struct ei*
|
|
ei_device_get_context(struct ei_device *device)
|
|
{
|
|
assert(device);
|
|
return ei_device_parent(device);
|
|
}
|
|
|
|
_public_
|
|
struct ei_device *
|
|
ei_device_new(struct ei *ei)
|
|
{
|
|
/* device IDs are managed by the client, the server merely accepts
|
|
* them and fails where they're being reused. */
|
|
static uint32_t deviceid = 0;
|
|
struct ei_device *device = ei_device_create(&ei->object);
|
|
|
|
device->capabilities = 0;
|
|
device->id = ++deviceid;
|
|
device->state = EI_DEVICE_STATE_NEW;
|
|
device->name = xaprintf("unnamed device %d", device->id);
|
|
|
|
return device;
|
|
}
|
|
|
|
_public_ void
|
|
ei_device_configure_name(struct ei_device *device, const char *name)
|
|
{
|
|
if (device->state != EI_DEVICE_STATE_NEW)
|
|
return;
|
|
|
|
free(device->name);
|
|
device->name = xstrdup(name);
|
|
}
|
|
|
|
_public_ bool
|
|
ei_device_configure_capability(struct ei_device *device,
|
|
enum ei_device_capability cap)
|
|
{
|
|
if (device->state != EI_DEVICE_STATE_NEW)
|
|
return false;
|
|
|
|
switch (cap) {
|
|
case EI_DEVICE_CAP_POINTER:
|
|
case EI_DEVICE_CAP_POINTER_ABSOLUTE:
|
|
case EI_DEVICE_CAP_KEYBOARD:
|
|
case EI_DEVICE_CAP_TOUCH:
|
|
device->capabilities |= bit(cap);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
_public_ void
|
|
ei_device_configure_pointer_range(struct ei_device *device,
|
|
uint32_t width,
|
|
uint32_t height)
|
|
{
|
|
if (device->state != EI_DEVICE_STATE_NEW ||
|
|
!flag_is_set(device->capabilities, EI_DEVICE_CAP_POINTER_ABSOLUTE))
|
|
return;
|
|
|
|
if (width == 0 || height == 0)
|
|
return;
|
|
|
|
device->abs.dim.width = width;
|
|
device->abs.dim.height = height;
|
|
}
|
|
|
|
_public_ void
|
|
ei_device_configure_touch_range(struct ei_device *device,
|
|
uint32_t width,
|
|
uint32_t height)
|
|
{
|
|
if (device->state != EI_DEVICE_STATE_NEW ||
|
|
!flag_is_set(device->capabilities, EI_DEVICE_CAP_TOUCH))
|
|
return;
|
|
|
|
if (width == 0 || height == 0)
|
|
return;
|
|
|
|
device->touch.dim.width = width;
|
|
device->touch.dim.height = height;
|
|
}
|
|
|
|
_public_ void
|
|
ei_device_add(struct ei_device *device)
|
|
{
|
|
ei_add_device(device);
|
|
device->state = EI_DEVICE_STATE_CONNECTING;
|
|
}
|
|
|
|
_public_ void
|
|
ei_device_remove(struct ei_device *device)
|
|
{
|
|
if (device->state == EI_DEVICE_STATE_REMOVED)
|
|
return;
|
|
|
|
device->state = EI_DEVICE_STATE_REMOVED;
|
|
ei_remove_device(device);
|
|
}
|
|
|
|
void
|
|
ei_device_resumed(struct ei_device *device)
|
|
{
|
|
device->state = EI_DEVICE_STATE_RESUMED;
|
|
}
|
|
|
|
void
|
|
ei_device_suspended(struct ei_device *device)
|
|
{
|
|
device->state = EI_DEVICE_STATE_SUSPENDED;
|
|
}
|
|
|
|
void
|
|
ei_device_added(struct ei_device *device)
|
|
{
|
|
ei_device_suspended(device);
|
|
}
|
|
|
|
void
|
|
ei_device_set_capabilities(struct ei_device *device,
|
|
uint32_t capabilities)
|
|
{
|
|
device->capabilities = capabilities;
|
|
}
|
|
|
|
_public_ bool
|
|
ei_device_has_capability(struct ei_device *device,
|
|
enum ei_device_capability cap)
|
|
{
|
|
switch (cap) {
|
|
case EI_DEVICE_CAP_POINTER:
|
|
case EI_DEVICE_CAP_POINTER_ABSOLUTE:
|
|
case EI_DEVICE_CAP_KEYBOARD:
|
|
case EI_DEVICE_CAP_TOUCH:
|
|
return flag_is_set(device->capabilities, cap);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
_public_ uint32_t
|
|
ei_device_get_pointer_width(struct ei_device *device)
|
|
{
|
|
return device->abs.dim.width;
|
|
}
|
|
|
|
_public_ uint32_t
|
|
ei_device_get_pointer_height(struct ei_device *device)
|
|
{
|
|
return device->abs.dim.height;
|
|
}
|
|
|
|
_public_ uint32_t
|
|
ei_device_get_touch_width(struct ei_device *device)
|
|
{
|
|
return device->touch.dim.width;
|
|
}
|
|
|
|
_public_ uint32_t
|
|
ei_device_get_touch_height(struct ei_device *device)
|
|
{
|
|
return device->touch.dim.height;
|
|
}
|
|
|
|
_public_ void
|
|
ei_device_pointer_motion(struct ei_device *device,
|
|
double x, double y)
|
|
{
|
|
if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER))
|
|
return;
|
|
|
|
if (device->state != EI_DEVICE_STATE_RESUMED)
|
|
return;
|
|
|
|
ei_pointer_rel(device, x, y);
|
|
}
|
|
|
|
_public_ void
|
|
ei_device_pointer_button(struct ei_device *device,
|
|
uint32_t button, bool is_press)
|
|
{
|
|
if (!ei_device_has_capability(device, EI_DEVICE_CAP_POINTER))
|
|
return;
|
|
|
|
if (device->state != EI_DEVICE_STATE_RESUMED)
|
|
return;
|
|
|
|
ei_pointer_button(device, button, is_press);
|
|
}
|
|
|
|
_public_ void
|
|
ei_device_keyboard_key(struct ei_device *device,
|
|
uint32_t key, bool is_press)
|
|
{
|
|
if (!ei_device_has_capability(device, EI_DEVICE_CAP_KEYBOARD))
|
|
return;
|
|
|
|
if (device->state != EI_DEVICE_STATE_RESUMED)
|
|
return;
|
|
|
|
ei_keyboard_key(device, key, is_press);
|
|
}
|
|
|
|
|
|
|
|
#ifdef _enable_tests_
|
|
#include <munit.h>
|
|
|
|
static MunitResult
|
|
test_device_new(const MunitParameter params[], void *user_data)
|
|
{
|
|
struct ei ei = {0};
|
|
struct ei_device *d = ei_device_new(&ei);
|
|
|
|
munit_assert_int(d->id, >, 0);
|
|
munit_assert_int(d->capabilities, ==, 0);
|
|
munit_assert_int(d->state, ==, EI_DEVICE_STATE_NEW);
|
|
|
|
struct ei_device *unrefd = ei_device_unref(d);
|
|
munit_assert_ptr_null(unrefd);
|
|
return MUNIT_OK;
|
|
}
|
|
|
|
static MunitResult
|
|
test_device_ids(const MunitParameter params[], void *user_data)
|
|
{
|
|
struct ei ei = {0};
|
|
_cleanup_ei_device_ struct ei_device *d1 = ei_device_new(&ei);
|
|
_cleanup_ei_device_ struct ei_device *d2 = ei_device_new(&ei);
|
|
_cleanup_ei_device_ struct ei_device *d3 = ei_device_new(&ei);
|
|
|
|
munit_assert_int(d1->id, <, d2->id);
|
|
munit_assert_int(d1->id, <, d3->id);
|
|
munit_assert_int(d2->id, <, d3->id);
|
|
|
|
return MUNIT_OK;
|
|
}
|
|
|
|
static MunitResult
|
|
test_device_ref_unref(const MunitParameter params[], void *user_data)
|
|
{
|
|
struct ei ei = {0};
|
|
struct ei_device *d = ei_device_new(&ei);
|
|
|
|
munit_assert_int(d->object.refcount, ==, 1);
|
|
|
|
struct ei_device *refd = ei_device_ref(d);
|
|
munit_assert_ptr_equal(d, refd);
|
|
munit_assert_int(d->object.refcount, ==, 2);
|
|
|
|
struct ei_device *unrefd = ei_device_unref(d);
|
|
munit_assert_ptr_null(unrefd);
|
|
munit_assert_int(d->object.refcount, ==, 1);
|
|
|
|
unrefd = ei_device_unref(d);
|
|
munit_assert_ptr_null(unrefd);
|
|
|
|
return MUNIT_OK;
|
|
}
|
|
|
|
static MunitResult
|
|
test_device_cap(const MunitParameter params[], void *user_data)
|
|
{
|
|
struct ei ei = {0};
|
|
_cleanup_ei_device_ struct ei_device *d = ei_device_new(&ei);
|
|
|
|
munit_assert(ei_device_configure_capability(d, EI_DEVICE_CAP_POINTER));
|
|
/* twice is fine */
|
|
munit_assert(ei_device_configure_capability(d, EI_DEVICE_CAP_POINTER));
|
|
munit_assert(ei_device_has_capability(d, EI_DEVICE_CAP_POINTER));
|
|
|
|
munit_assert(ei_device_configure_capability(d, EI_DEVICE_CAP_POINTER_ABSOLUTE));
|
|
munit_assert(ei_device_has_capability(d, EI_DEVICE_CAP_POINTER_ABSOLUTE));
|
|
|
|
munit_assert(ei_device_configure_capability(d, EI_DEVICE_CAP_KEYBOARD));
|
|
munit_assert(ei_device_has_capability(d, EI_DEVICE_CAP_KEYBOARD));
|
|
|
|
munit_assert(ei_device_configure_capability(d, EI_DEVICE_CAP_TOUCH));
|
|
munit_assert(ei_device_has_capability(d, EI_DEVICE_CAP_TOUCH));
|
|
|
|
/* Invalid caps */
|
|
munit_assert(!ei_device_configure_capability(d, 0));
|
|
munit_assert(!ei_device_has_capability(d, 0));
|
|
munit_assert(!ei_device_configure_capability(d, EI_DEVICE_CAP_TOUCH + 1));
|
|
munit_assert(!ei_device_has_capability(d, EI_DEVICE_CAP_TOUCH + 1));
|
|
|
|
return MUNIT_OK;
|
|
}
|
|
|
|
static MunitResult
|
|
test_device_context(const MunitParameter params[], void *user_data)
|
|
{
|
|
struct ei ei = {0};
|
|
_cleanup_ei_device_ struct ei_device *d = ei_device_new(&ei);
|
|
|
|
munit_assert_ptr_equal(d->object.parent, &ei);
|
|
|
|
return MUNIT_OK;
|
|
}
|
|
|
|
static MunitResult
|
|
test_device_pointer_ranges(const MunitParameter params[], void *user_data)
|
|
{
|
|
struct ei ei = {0};
|
|
_cleanup_ei_device_ struct ei_device *d = ei_device_new(&ei);
|
|
|
|
/* Missing the cap */
|
|
ei_device_configure_pointer_range(d, 1920, 1200);
|
|
munit_assert_int(ei_device_get_pointer_width(d), ==, 0);
|
|
munit_assert_int(ei_device_get_pointer_height(d), ==, 0);
|
|
|
|
munit_assert(ei_device_configure_capability(d, EI_DEVICE_CAP_POINTER_ABSOLUTE));
|
|
|
|
ei_device_configure_pointer_range(d, 1024, 768);
|
|
munit_assert_int(ei_device_get_pointer_width(d), ==, 1024);
|
|
munit_assert_int(ei_device_get_pointer_height(d), ==, 768);
|
|
|
|
/* Twice is fine before adding the device */
|
|
ei_device_configure_pointer_range(d, 640, 480);
|
|
munit_assert_int(ei_device_get_pointer_width(d), ==, 640);
|
|
munit_assert_int(ei_device_get_pointer_height(d), ==, 480);
|
|
|
|
/* But zero is silently rejected */
|
|
ei_device_configure_pointer_range(d, 0, 480);
|
|
munit_assert_int(ei_device_get_pointer_width(d), ==, 640);
|
|
munit_assert_int(ei_device_get_pointer_height(d), ==, 480);
|
|
ei_device_configure_pointer_range(d, 640, 0);
|
|
munit_assert_int(ei_device_get_pointer_width(d), ==, 640);
|
|
munit_assert_int(ei_device_get_pointer_height(d), ==, 480);
|
|
|
|
return MUNIT_OK;
|
|
}
|
|
|
|
static MunitResult
|
|
test_device_touch_ranges(const MunitParameter params[], void *user_data)
|
|
{
|
|
struct ei ei = {0};
|
|
_cleanup_ei_device_ struct ei_device *d = ei_device_new(&ei);
|
|
|
|
/* Missing the cap */
|
|
ei_device_configure_touch_range(d, 1920, 1200);
|
|
munit_assert_int(ei_device_get_touch_width(d), ==, 0);
|
|
munit_assert_int(ei_device_get_touch_height(d), ==, 0);
|
|
|
|
munit_assert(ei_device_configure_capability(d, EI_DEVICE_CAP_TOUCH));
|
|
|
|
ei_device_configure_touch_range(d, 1024, 768);
|
|
munit_assert_int(ei_device_get_touch_width(d), ==, 1024);
|
|
munit_assert_int(ei_device_get_touch_height(d), ==, 768);
|
|
|
|
/* Twice is fine before adding the device */
|
|
ei_device_configure_touch_range(d, 640, 480);
|
|
munit_assert_int(ei_device_get_touch_width(d), ==, 640);
|
|
munit_assert_int(ei_device_get_touch_height(d), ==, 480);
|
|
|
|
/* But zero is silently rejected */
|
|
ei_device_configure_touch_range(d, 0, 480);
|
|
munit_assert_int(ei_device_get_touch_width(d), ==, 640);
|
|
munit_assert_int(ei_device_get_touch_height(d), ==, 480);
|
|
ei_device_configure_touch_range(d, 640, 0);
|
|
munit_assert_int(ei_device_get_touch_width(d), ==, 640);
|
|
munit_assert_int(ei_device_get_touch_height(d), ==, 480);
|
|
|
|
return MUNIT_OK;
|
|
}
|
|
|
|
#define TEST(_func) \
|
|
{ .name = #_func, .test = _func }
|
|
static MunitTest ei_device_tests[] = {
|
|
TEST(test_device_new),
|
|
TEST(test_device_ids),
|
|
TEST(test_device_ref_unref),
|
|
TEST(test_device_cap),
|
|
TEST(test_device_context),
|
|
TEST(test_device_pointer_ranges),
|
|
TEST(test_device_touch_ranges),
|
|
{ NULL },
|
|
};
|
|
|
|
static const MunitSuite libei_device_suite
|
|
__attribute__((used))
|
|
__attribute__((section("test_section"))) = {
|
|
"/device/",
|
|
ei_device_tests,
|
|
NULL,
|
|
1,
|
|
MUNIT_SUITE_OPTION_NONE,
|
|
};
|
|
#endif
|