mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-25 02:20:05 +01:00
Introduce device groups to group logical devices together
Devices like Wacom tablets have multiple event nodes (touch, pad and stylus). This requires some logical grouping, e.g. setting an Intuos 5 tablet left-handed effectively turns it upside down. That then applies to both the stylus and the touch device. Merging the devices into one struct libinput_device is not feasable, it complicates the API for little benefit. A caller would still need access to all subdevices to get udev handles, etc. Some configuration options apply to the whole device (left-handed) but some (may) only apply to a single subdevice (calibration, natural scrolling). Addressing this would make the libinput API unwieldly and hard to use. Instead, add a device group concept. Each device is a member of a device group - a singleton for most devices. Wacom tablets will have a single group across multiple devices, allowing the caller to associate the devices together if needed. The API is intentionally very simple and requires the caller to keep track of groups and which/how many devices are in it. The caller has more powerful libraries available to do that than we have. This patch does not address the actual merging of devices into the same device group, it simply creates a new group for each new device. [rebased on top of 0.10] Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Jonas Ådahl <jadahl@gmail.com>
This commit is contained in:
parent
ca4e03fb11
commit
e3a43902f9
6 changed files with 246 additions and 0 deletions
10
src/evdev.c
10
src/evdev.c
|
|
@ -1572,6 +1572,7 @@ evdev_device_create(struct libinput_seat *seat,
|
|||
int fd;
|
||||
int unhandled_device = 0;
|
||||
const char *devnode = udev_device_get_devnode(udev_device);
|
||||
struct libinput_device_group *group;
|
||||
|
||||
/* Use non-blocking mode so that we can loop on read on
|
||||
* evdev_device_data() until all events on the fd are
|
||||
|
|
@ -1642,6 +1643,12 @@ evdev_device_create(struct libinput_seat *seat,
|
|||
if (!device->source)
|
||||
goto err;
|
||||
|
||||
group = libinput_device_group_create();
|
||||
if (!group)
|
||||
goto err;
|
||||
libinput_device_set_device_group(&device->base, group);
|
||||
libinput_device_group_unref(group);
|
||||
|
||||
list_insert(seat->devices_list.prev, &device->base.link);
|
||||
|
||||
evdev_tag_device(device);
|
||||
|
|
@ -2123,6 +2130,9 @@ evdev_device_destroy(struct evdev_device *device)
|
|||
if (dispatch)
|
||||
dispatch->interface->destroy(dispatch);
|
||||
|
||||
if (device->base.group)
|
||||
libinput_device_group_unref(device->base.group);
|
||||
|
||||
filter_destroy(device->pointer.filter);
|
||||
libinput_seat_unref(device->base.seat);
|
||||
libevdev_free(device->evdev);
|
||||
|
|
|
|||
|
|
@ -165,8 +165,14 @@ struct libinput_device_config {
|
|||
struct libinput_device_config_click_method *click_method;
|
||||
};
|
||||
|
||||
struct libinput_device_group {
|
||||
int refcount;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
struct libinput_device {
|
||||
struct libinput_seat *seat;
|
||||
struct libinput_device_group *group;
|
||||
struct list link;
|
||||
struct list event_listeners;
|
||||
void *user_data;
|
||||
|
|
@ -240,6 +246,13 @@ void
|
|||
libinput_device_init(struct libinput_device *device,
|
||||
struct libinput_seat *seat);
|
||||
|
||||
struct libinput_device_group *
|
||||
libinput_device_group_create(void);
|
||||
|
||||
void
|
||||
libinput_device_set_device_group(struct libinput_device *device,
|
||||
struct libinput_device_group *group);
|
||||
|
||||
void
|
||||
libinput_device_add_event_listener(struct libinput_device *device,
|
||||
struct libinput_event_listener *listener,
|
||||
|
|
|
|||
|
|
@ -1277,6 +1277,12 @@ libinput_device_get_context(struct libinput_device *device)
|
|||
return libinput_seat_get_context(device->seat);
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT struct libinput_device_group *
|
||||
libinput_device_get_device_group(struct libinput_device *device)
|
||||
{
|
||||
return device->group;
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT const char *
|
||||
libinput_device_get_sysname(struct libinput_device *device)
|
||||
{
|
||||
|
|
@ -1387,6 +1393,64 @@ libinput_event_touch_get_base_event(struct libinput_event_touch *event)
|
|||
return &event->base;
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT struct libinput_device_group *
|
||||
libinput_device_group_ref(struct libinput_device_group *group)
|
||||
{
|
||||
group->refcount++;
|
||||
return group;
|
||||
}
|
||||
|
||||
struct libinput_device_group *
|
||||
libinput_device_group_create(void)
|
||||
{
|
||||
struct libinput_device_group *group;
|
||||
|
||||
group = zalloc(sizeof *group);
|
||||
if (group)
|
||||
group->refcount = 1;
|
||||
return group;
|
||||
}
|
||||
|
||||
void
|
||||
libinput_device_set_device_group(struct libinput_device *device,
|
||||
struct libinput_device_group *group)
|
||||
{
|
||||
device->group = group;
|
||||
libinput_device_group_ref(group);
|
||||
}
|
||||
|
||||
static void
|
||||
libinput_device_group_destroy(struct libinput_device_group *group)
|
||||
{
|
||||
free(group);
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT struct libinput_device_group *
|
||||
libinput_device_group_unref(struct libinput_device_group *group)
|
||||
{
|
||||
assert(group->refcount > 0);
|
||||
group->refcount--;
|
||||
if (group->refcount == 0) {
|
||||
libinput_device_group_destroy(group);
|
||||
return NULL;
|
||||
} else {
|
||||
return group;
|
||||
}
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT void
|
||||
libinput_device_group_set_user_data(struct libinput_device_group *group,
|
||||
void *user_data)
|
||||
{
|
||||
group->user_data = user_data;
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT void *
|
||||
libinput_device_group_get_user_data(struct libinput_device_group *group)
|
||||
{
|
||||
return group->user_data;
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT const char *
|
||||
libinput_config_status_to_str(enum libinput_config_status status)
|
||||
{
|
||||
|
|
|
|||
100
src/libinput.h
100
src/libinput.h
|
|
@ -194,6 +194,16 @@ struct libinput;
|
|||
*/
|
||||
struct libinput_device;
|
||||
|
||||
/**
|
||||
* @ingroup device
|
||||
* @struct libinput_device_group
|
||||
*
|
||||
* A base handle for accessing libinput device groups. This struct is
|
||||
* refcounted, use libinput_device_group_ref() and
|
||||
* libinput_device_group_unref().
|
||||
*/
|
||||
struct libinput_device_group;
|
||||
|
||||
/**
|
||||
* @ingroup seat
|
||||
* @struct libinput_seat
|
||||
|
|
@ -1406,6 +1416,39 @@ libinput_device_get_user_data(struct libinput_device *device);
|
|||
struct libinput *
|
||||
libinput_device_get_context(struct libinput_device *device);
|
||||
|
||||
/**
|
||||
* @ingroup device
|
||||
*
|
||||
* Get the device group this device is assigned to. Some physical
|
||||
* devices like graphics tablets are represented by multiple kernel
|
||||
* devices and thus by multiple struct libinput_device.
|
||||
*
|
||||
* libinput assigns these devices to the same libinput_device_group
|
||||
* allowing the caller to identify such devices and adjust configuration
|
||||
* settings accordingly. For example, setting a tablet to left-handed often
|
||||
* means turning it upside down. A touch device on the same tablet would
|
||||
* need to be turned upside down too to work correctly.
|
||||
*
|
||||
* All devices are part of a device group though for most devices the group
|
||||
* will be a singleton. A device is assigned to a device group on @ref
|
||||
* LIBINPUT_EVENT_DEVICE_ADDED and removed from that group on @ref
|
||||
* LIBINPUT_EVENT_DEVICE_REMOVED. It is up to the caller to track how many
|
||||
* devices are in each device group.
|
||||
*
|
||||
* Device groups do not get re-used once the last device in the group was
|
||||
* removed, i.e. unplugging and re-plugging a physical device with grouped
|
||||
* devices will return a different device group after every unplug.
|
||||
*
|
||||
* The returned device group is not refcounted and may become invalid after
|
||||
* the next call to libinput. Use libinput_device_group_ref() and
|
||||
* libinput_device_group_unref() to continue using the handle outside of the
|
||||
* immediate scope.
|
||||
*
|
||||
* @return The device group this device belongs to
|
||||
*/
|
||||
struct libinput_device_group *
|
||||
libinput_device_get_device_group(struct libinput_device *device);
|
||||
|
||||
/**
|
||||
* @ingroup device
|
||||
*
|
||||
|
|
@ -1593,6 +1636,63 @@ libinput_device_get_size(struct libinput_device *device,
|
|||
int
|
||||
libinput_device_has_button(struct libinput_device *device, uint32_t code);
|
||||
|
||||
/**
|
||||
* @ingroup device
|
||||
*
|
||||
* Increase the refcount of the device group. A device group will be freed
|
||||
* whenever the refcount reaches 0. This may happen during dispatch if all
|
||||
* devices of this group were removed from the system. A caller must ensure
|
||||
* to reference the device group correctly to avoid dangling pointers.
|
||||
*
|
||||
* @param group A previously obtained device group
|
||||
* @return The passed device group
|
||||
*/
|
||||
struct libinput_device_group *
|
||||
libinput_device_group_ref(struct libinput_device_group *group);
|
||||
|
||||
/**
|
||||
* @ingroup device
|
||||
*
|
||||
* Decrease the refcount of the device group. A device group will be freed
|
||||
* whenever the refcount reaches 0. This may happen during dispatch if all
|
||||
* devices of this group were removed from the system. A caller must ensure
|
||||
* to reference the device group correctly to avoid dangling pointers.
|
||||
*
|
||||
* @param group A previously obtained device group
|
||||
* @return NULL if the device group was destroyed, otherwise the passed
|
||||
* device group
|
||||
*/
|
||||
struct libinput_device_group *
|
||||
libinput_device_group_unref(struct libinput_device_group *group);
|
||||
|
||||
/**
|
||||
* @ingroup device
|
||||
*
|
||||
* Set caller-specific data associated with this device group. libinput does
|
||||
* not manage, look at, or modify this data. The caller must ensure the
|
||||
* data is valid.
|
||||
*
|
||||
* @param group A previously obtained device group
|
||||
* @param user_data Caller-specific data pointer
|
||||
* @see libinput_device_group_get_user_data
|
||||
*/
|
||||
void
|
||||
libinput_device_group_set_user_data(struct libinput_device_group *group,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @ingroup device
|
||||
*
|
||||
* Get the caller-specific data associated with this input device group, if
|
||||
* any.
|
||||
*
|
||||
* @param group A previously obtained group
|
||||
* @return Caller-specific data pointer or NULL if none was set
|
||||
* @see libinput_device_group_set_user_data
|
||||
*/
|
||||
void *
|
||||
libinput_device_group_get_user_data(struct libinput_device_group *group);
|
||||
|
||||
/**
|
||||
* @defgroup config Device configuration
|
||||
*
|
||||
|
|
|
|||
|
|
@ -126,3 +126,11 @@ global:
|
|||
libinput_device_config_click_get_methods;
|
||||
libinput_device_config_click_set_method;
|
||||
} LIBINPUT_0.8.0;
|
||||
|
||||
LIBINPUT_0.11.0 {
|
||||
libinput_device_get_device_group;
|
||||
libinput_device_group_get_user_data;
|
||||
libinput_device_group_ref;
|
||||
libinput_device_group_set_user_data;
|
||||
libinput_device_group_unref;
|
||||
} LIBINPUT_0.9.0;
|
||||
|
|
|
|||
|
|
@ -661,6 +661,54 @@ START_TEST(device_context)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(device_group_get)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput_device_group *group;
|
||||
|
||||
int userdata = 10;
|
||||
|
||||
group = libinput_device_get_device_group(dev->libinput_device);
|
||||
ck_assert_notnull(group);
|
||||
|
||||
libinput_device_group_ref(group);
|
||||
|
||||
libinput_device_group_set_user_data(group, &userdata);
|
||||
ck_assert_ptr_eq(&userdata,
|
||||
libinput_device_group_get_user_data(group));
|
||||
|
||||
libinput_device_group_unref(group);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(device_group_ref)
|
||||
{
|
||||
struct libinput *li = litest_create_context();
|
||||
struct litest_device *dev = litest_add_device(li,
|
||||
LITEST_MOUSE);
|
||||
struct libinput_device *device = dev->libinput_device;
|
||||
struct libinput_device_group *group;
|
||||
|
||||
group = libinput_device_get_device_group(device);
|
||||
ck_assert_notnull(group);
|
||||
libinput_device_group_ref(group);
|
||||
|
||||
libinput_device_ref(device);
|
||||
litest_drain_events(li);
|
||||
litest_delete_device(dev);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* make sure the device is dead but the group is still around */
|
||||
ck_assert(libinput_device_unref(device) == NULL);
|
||||
|
||||
libinput_device_group_ref(group);
|
||||
ck_assert_notnull(libinput_device_group_unref(group));
|
||||
ck_assert(libinput_device_group_unref(group) == NULL);
|
||||
|
||||
libinput_unref(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
litest_add("device:sendevents", device_sendevents_config, LITEST_ANY, LITEST_TOUCHPAD);
|
||||
|
|
@ -686,5 +734,8 @@ int main (int argc, char **argv)
|
|||
|
||||
litest_add("device:udev", device_get_udev_handle, LITEST_ANY, LITEST_ANY);
|
||||
|
||||
litest_add("device:group", device_group_get, LITEST_ANY, LITEST_ANY);
|
||||
litest_add_no_device("device:group", device_group_ref);
|
||||
|
||||
return litest_run(argc, argv);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue