libei/src/libei-device.c
Peter Hutterer 2b29b6e1b9 libei: add ei_device_get/set_user_data
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
2020-08-20 14:44:38 +10:00

434 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_added(struct ei_device *device)
{
device->state = EI_DEVICE_STATE_ADDED;
}
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_ADDED)
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_ADDED)
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_ADDED)
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