tablet: centralize the libwacom handling

Instead of re-creating the the libwacom device from the database every
time we need it let's create it once during tablet|pad_init and pass it
down to the functions.

This allows us to have one point per tablet/pad where we can log an
error if the device is not supported by libwacom - previously this was
printed during the left-handed setup.

Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1073>
This commit is contained in:
Peter Hutterer 2024-10-29 09:46:05 +10:00
parent d3bc0c79ff
commit 2b2959fc8b
7 changed files with 154 additions and 165 deletions

View file

@ -404,23 +404,13 @@ pad_find_button_group(struct pad_dispatch *pad,
static int
pad_init_leds_from_libwacom(struct pad_dispatch *pad,
struct evdev_device *device)
struct evdev_device *device,
WacomDevice *wacom)
{
struct libinput *li = pad_libinput_context(pad);
WacomDeviceDatabase *db = NULL;
WacomDevice *wacom = NULL;
int rc = -EINVAL;
db = libinput_libwacom_ref(li);
if (!db)
goto out;
wacom = libwacom_new_from_path(db,
udev_device_get_devnode(device->udev_device),
WFALLBACK_NONE,
NULL);
if (!wacom)
goto out;
return -ENOENT;
for (int b = 0; b < libwacom_get_num_buttons(wacom); b++) {
char btn = 'A' + b;
@ -523,11 +513,6 @@ pad_init_leds_from_libwacom(struct pad_dispatch *pad,
rc = 0;
out:
if (wacom)
libwacom_destroy(wacom);
if (db)
libinput_libwacom_unref(li);
if (rc != 0) {
if (rc == -ENOENT && is_litest_device(pad->device)) {
evdev_log_error(pad->device,
@ -567,7 +552,8 @@ pad_init_fallback_group(struct pad_dispatch *pad)
int
pad_init_leds(struct pad_dispatch *pad,
struct evdev_device *device)
struct evdev_device *device,
WacomDevice *wacom)
{
int rc = 1;
@ -582,7 +568,7 @@ pad_init_leds(struct pad_dispatch *pad,
/* If libwacom fails, we init one fallback group anyway */
#if HAVE_LIBWACOM
rc = pad_init_leds_from_libwacom(pad, device);
rc = pad_init_leds_from_libwacom(pad, device, wacom);
#endif
if (rc != 0)
rc = pad_init_fallback_group(pad);

View file

@ -642,58 +642,28 @@ static struct evdev_dispatch_interface pad_interface = {
static bool
pad_init_buttons_from_libwacom(struct pad_dispatch *pad,
struct evdev_device *device)
struct evdev_device *device,
WacomDevice *tablet)
{
bool rc = false;
#if HAVE_LIBWACOM
struct libinput *li = pad_libinput_context(pad);
WacomDeviceDatabase *db = NULL;
WacomDevice *tablet = NULL;
int num_buttons;
int map = 0;
char event_path[64];
db = libinput_libwacom_ref(li);
if (!db)
goto out;
if (tablet) {
int num_buttons = libwacom_get_num_buttons(tablet);
int map = 0;
for (int i = 0; i < num_buttons; i++) {
unsigned int code;
snprintf(event_path,
sizeof(event_path),
"/dev/input/%s",
evdev_device_get_sysname(device));
tablet = libwacom_new_from_path(db,
event_path,
WFALLBACK_NONE,
NULL);
if (!tablet) {
tablet = libwacom_new_from_usbid(db,
evdev_device_get_id_vendor(device),
evdev_device_get_id_product(device),
NULL);
code = libwacom_get_button_evdev_code(tablet, 'A' + i);
if (code == 0)
continue;
map_set_button_map(pad->button_map[code], map++);
}
pad->nbuttons = map;
rc = true;
}
if (!tablet)
goto out;
num_buttons = libwacom_get_num_buttons(tablet);
for (int i = 0; i < num_buttons; i++) {
unsigned int code;
code = libwacom_get_button_evdev_code(tablet, 'A' + i);
if (code == 0)
continue;
map_set_button_map(pad->button_map[code], map++);
}
pad->nbuttons = map;
rc = true;
out:
if (tablet)
libwacom_destroy(tablet);
if (db)
libinput_libwacom_unref(li);
#endif
return rc;
}
@ -750,23 +720,30 @@ pad_init_keys(struct pad_dispatch *pad, struct evdev_device *device)
static void
pad_init_buttons(struct pad_dispatch *pad,
struct evdev_device *device)
struct evdev_device *device,
WacomDevice *wacom)
{
size_t i;
for (i = 0; i < ARRAY_LENGTH(pad->button_map); i++)
map_init(pad->button_map[i]);
if (!pad_init_buttons_from_libwacom(pad, device))
if (!pad_init_buttons_from_libwacom(pad, device, wacom))
pad_init_buttons_from_kernel(pad, device);
pad_init_keys(pad, device);
}
static void
pad_init_left_handed(struct evdev_device *device)
pad_init_left_handed(struct evdev_device *device,
WacomDevice *wacom)
{
if (evdev_tablet_has_left_handed(device))
bool has_left_handed = true;
#if HAVE_LIBWACOM
has_left_handed = !wacom || libwacom_is_reversible(wacom);
#endif
if (has_left_handed)
evdev_init_left_handed(device,
pad_change_to_left_handed);
}
@ -774,6 +751,34 @@ pad_init_left_handed(struct evdev_device *device)
static int
pad_init(struct pad_dispatch *pad, struct evdev_device *device)
{
int rc = 1;
struct libinput *li = evdev_libinput_context(device);
WacomDevice *wacom = NULL;
#if HAVE_LIBWACOM
WacomDeviceDatabase *db = libinput_libwacom_ref(li);
if (db) {
char event_path[64];
snprintf(event_path,
sizeof(event_path),
"/dev/input/%s",
evdev_device_get_sysname(device));
wacom = libwacom_new_from_path(db, event_path, WFALLBACK_NONE, NULL);
if (!wacom) {
wacom = libwacom_new_from_usbid(db,
evdev_device_get_id_vendor(device),
evdev_device_get_id_product(device),
NULL);
}
if (!wacom) {
evdev_log_info(device,
"device \"%s\" (%04x:%04x) is not known to libwacom\n",
evdev_device_get_name(device),
evdev_device_get_id_vendor(device),
evdev_device_get_id_product(device));
}
}
#endif
pad->base.dispatch_type = DISPATCH_TABLET_PAD;
pad->base.interface = &pad_interface;
pad->device = device;
@ -787,15 +792,21 @@ pad_init(struct pad_dispatch *pad, struct evdev_device *device)
if (libevdev_has_event_code(device->evdev, EV_REL, REL_WHEEL) &&
libevdev_has_event_code(device->evdev, EV_REL, REL_DIAL)) {
log_bug_libinput(pad_libinput_context(pad), "Unsupported combination REL_DIAL and REL_WHEEL\n");
log_bug_libinput(li, "Unsupported combination REL_DIAL and REL_WHEEL\n");
}
pad_init_buttons(pad, device);
pad_init_left_handed(device);
if (pad_init_leds(pad, device) != 0)
return 1;
pad_init_buttons(pad, device, wacom);
pad_init_left_handed(device, wacom);
return 0;
rc = pad_init_leds(pad, device, wacom);
#if HAVE_LIBWACOM
if (wacom)
libwacom_destroy(wacom);
if (db)
libinput_libwacom_unref(li);
#endif
return rc;
}
static uint32_t

View file

@ -26,6 +26,10 @@
#include "evdev.h"
#if !HAVE_LIBWACOM
typedef void * WacomDevice;
#endif
#define LIBINPUT_BUTTONSET_AXIS_NONE 0
enum pad_status {
@ -106,9 +110,13 @@ pad_libinput_context(const struct pad_dispatch *pad)
}
int
pad_init_leds(struct pad_dispatch *pad, struct evdev_device *device);
pad_init_leds(struct pad_dispatch *pad,
struct evdev_device *device,
WacomDevice *wacom);
void
pad_destroy_leds(struct pad_dispatch *pad);
void
pad_button_update_mode(struct libinput_tablet_pad_mode_group *g,
unsigned int button_index,

View file

@ -2577,56 +2577,53 @@ tablet_init_accel(struct tablet_dispatch *tablet, struct evdev_device *device)
}
static void
tablet_init_left_handed(struct evdev_device *device)
tablet_init_left_handed(struct evdev_device *device,
WacomDevice *wacom)
{
if (evdev_tablet_has_left_handed(device))
bool has_left_handed = true;
#if HAVE_LIBWACOM
has_left_handed = !wacom || libwacom_is_reversible(wacom);
#endif
if (has_left_handed)
evdev_init_left_handed(device,
tablet_change_to_left_handed);
}
static void
tablet_lookup_libwacom(struct evdev_device *device,
struct tablet_dispatch *tablet,
bool *is_aes,
bool *is_display_tablet)
static inline bool
tablet_is_display_tablet(WacomDevice *wacom)
{
#if HAVE_LIBWACOM
return wacom &&
!!(libwacom_get_integration_flags(wacom) & (WACOM_DEVICE_INTEGRATED_SYSTEM|WACOM_DEVICE_INTEGRATED_DISPLAY));
#else
return false;
#endif
}
static inline bool
tablet_is_aes(struct evdev_device *device, WacomDevice *wacom)
{
#if HAVE_LIBWACOM
const char *devnode;
WacomDeviceDatabase *db;
WacomDevice *libwacom_device = NULL;
int vid = evdev_device_get_id_vendor(device);
db = tablet_libinput_context(tablet)->libwacom.db;
if (!db)
return;
devnode = udev_device_get_devnode(device->udev_device);
libwacom_device = libwacom_new_from_path(db, devnode, WFALLBACK_NONE, NULL);
if (!libwacom_device)
return;
*is_display_tablet = !!(libwacom_get_integration_flags(libwacom_device)
& (WACOM_DEVICE_INTEGRATED_SYSTEM|WACOM_DEVICE_INTEGRATED_DISPLAY));
/* Wacom-specific check for whether smoothing is required:
* libwacom keeps all the AES pens in a single group, so any device
* that supports AES pens will list all AES pens. 0x11 is one of the
* lenovo pens so we use that as the flag of whether the tablet
* is an AES tablet
*/
if (vid == VENDOR_ID_WACOM) {
if (wacom && vid == VENDOR_ID_WACOM) {
int nstyli;
const int *stylus_ids = libwacom_get_supported_styli(libwacom_device, &nstyli);
const int *stylus_ids = libwacom_get_supported_styli(wacom, &nstyli);
for (int i = 0; i < nstyli; i++) {
if (stylus_ids[i] == 0x11) {
*is_aes = true;
break;
return true;
}
}
}
libwacom_destroy(libwacom_device);
#endif
return false;
}
static void
@ -2737,9 +2734,35 @@ static int
tablet_init(struct tablet_dispatch *tablet,
struct evdev_device *device)
{
struct libinput *li = evdev_libinput_context(device);
struct libevdev *evdev = device->evdev;
enum libinput_tablet_tool_axis axis;
int rc;
int rc = -1;
WacomDevice *wacom = NULL;
#if HAVE_LIBWACOM
WacomDeviceDatabase *db = libinput_libwacom_ref(li);
if (db) {
char event_path[64];
snprintf(event_path,
sizeof(event_path),
"/dev/input/%s",
evdev_device_get_sysname(device));
wacom = libwacom_new_from_path(db, event_path, WFALLBACK_NONE, NULL);
if (!wacom) {
wacom = libwacom_new_from_usbid(db,
evdev_device_get_id_vendor(device),
evdev_device_get_id_product(device),
NULL);
}
if (!wacom) {
evdev_log_info(device,
"device \"%s\" (%04x:%04x) is not known to libwacom\n",
evdev_device_get_name(device),
evdev_device_get_id_vendor(device),
evdev_device_get_id_product(device));
}
}
#endif
tablet->base.dispatch_type = DISPATCH_TABLET;
tablet->base.interface = &tablet_interface;
@ -2749,11 +2772,10 @@ tablet_init(struct tablet_dispatch *tablet,
list_init(&tablet->tool_list);
if (tablet_reject_device(device))
return -1;
goto out;
bool is_aes = false;
bool is_display_tablet = false;
tablet_lookup_libwacom(device, tablet, &is_aes, &is_display_tablet);
bool is_aes = tablet_is_aes(device, wacom);
bool is_display_tablet = tablet_is_display_tablet(wacom);
if (!libevdev_has_event_code(evdev, EV_KEY, BTN_TOOL_PEN)) {
libevdev_enable_event_code(evdev, EV_KEY, BTN_TOOL_PEN, NULL);
@ -2772,10 +2794,10 @@ tablet_init(struct tablet_dispatch *tablet,
tablet_init_proximity_threshold(tablet, device);
rc = tablet_init_accel(tablet, device);
if (rc != 0)
return rc;
goto out;
evdev_init_sendevents(device, &tablet->base);
tablet_init_left_handed(device);
tablet_init_left_handed(device, wacom);
tablet_init_smoothing(device, tablet, is_aes);
for (axis = LIBINPUT_TABLET_TOOL_AXIS_X;
@ -2792,12 +2814,20 @@ tablet_init(struct tablet_dispatch *tablet,
tablet->quirks.need_to_force_prox_out = true;
libinput_timer_init(&tablet->quirks.prox_out_timer,
tablet_libinput_context(tablet),
li,
"proxout",
tablet_proximity_out_quirk_timer_func,
tablet);
return 0;
rc = 0;
out:
#if HAVE_LIBWACOM
if (wacom)
libwacom_destroy(wacom);
if (db)
libinput_libwacom_unref(li);
#endif
return rc;
}
struct evdev_dispatch *

View file

@ -27,6 +27,10 @@
#include "evdev.h"
#if !HAVE_LIBWACOM
typedef void * WacomDevice;
#endif
#define LIBINPUT_TABLET_TOOL_AXIS_NONE 0
#define LIBINPUT_TOOL_NONE 0
#define LIBINPUT_TABLET_TOOL_TYPE_MAX LIBINPUT_TABLET_TOOL_TYPE_LENS

View file

@ -3128,50 +3128,3 @@ evdev_device_destroy(struct evdev_device *device)
udev_device_unref(device->udev_device);
free(device);
}
bool
evdev_tablet_has_left_handed(struct evdev_device *device)
{
bool has_left_handed = true;
#if HAVE_LIBWACOM
struct libinput *li = evdev_libinput_context(device);
WacomDeviceDatabase *db = NULL;
WacomDevice *d = NULL;
WacomError *error;
const char *devnode;
db = libinput_libwacom_ref(li);
if (!db)
goto out;
error = libwacom_error_new();
devnode = udev_device_get_devnode(device->udev_device);
d = libwacom_new_from_path(db,
devnode,
WFALLBACK_NONE,
error);
if (d) {
has_left_handed = !!libwacom_is_reversible(d);
} else if (libwacom_error_get_code(error) == WERROR_UNKNOWN_MODEL) {
evdev_log_info(device,
"tablet '%s' unknown to libwacom\n",
device->devname);
} else {
evdev_log_error(device,
"libwacom error: %s\n",
libwacom_error_get_message(error));
}
if (error)
libwacom_error_free(&error);
if (d)
libwacom_destroy(d);
if (db)
libinput_libwacom_unref(li);
out:
#endif
return has_left_handed;
}

View file

@ -671,9 +671,6 @@ void
evdev_init_left_handed(struct evdev_device *device,
void (*change_to_left_handed)(struct evdev_device *));
bool
evdev_tablet_has_left_handed(struct evdev_device *device);
static inline uint32_t
evdev_to_left_handed(struct evdev_device *device,
uint32_t button)