uint32_t tool_id,
uint32_t serial)
{
+ struct libinput *libinput = tablet_libinput_context(tablet);
struct libinput_tablet_tool *tool = NULL, *t;
struct list *tool_list;
if (serial) {
- struct libinput *libinput = tablet_libinput_context(tablet);
tool_list = &libinput->tool_list;
-
/* Check if we already have the tool in our list of tools */
list_for_each(t, tool_list, link) {
if (type == t->type && serial == t->serial) {
break;
}
}
- } else {
+ }
+
+ /* If we get a tool with a delayed serial number, we already created
+ * a 0-serial number tool for it earlier. Re-use that, even though
+ * it means we can't distinguish this tool from others.
+ * https://bugs.freedesktop.org/show_bug.cgi?id=97526
+ */
+ if (!tool) {
+ tool_list = &tablet->tool_list;
/* We can't guarantee that tools without serial numbers are
* unique, so we keep them local to the tablet that they come
* into proximity of instead of storing them in the global tool
- * list */
- tool_list = &tablet->tool_list;
-
- /* Same as above, but don't bother checking the serial number */
+ * list
+ * Same as above, but don't bother checking the serial number
+ */
list_for_each(t, tool_list, link) {
if (type == t->type) {
tool = t;
break;
}
}
+
+ /* Didn't find the tool but we have a serial. Switch
+ * tool_list back so we create in the correct list */
+ if (!tool && serial)
+ tool_list = &libinput->tool_list;
}
/* If we didn't already have the new_tool in our list of tools,
}
END_TEST
+START_TEST(tool_delayed_serial)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct libinput_event *event;
+ struct libinput_event_tablet_tool *tev;
+ struct libinput_tablet_tool *tool;
+ unsigned int serial;
+
+ litest_drain_events(li);
+
+ litest_event(dev, EV_ABS, ABS_X, 4500);
+ litest_event(dev, EV_ABS, ABS_Y, 2000);
+ litest_event(dev, EV_MSC, MSC_SERIAL, 0);
+ litest_event(dev, EV_KEY, BTN_TOOL_PEN, 1);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ libinput_dispatch(li);
+
+ event = libinput_get_event(li);
+ tev = litest_is_tablet_event(event,
+ LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
+ tool = libinput_event_tablet_tool_get_tool(tev);
+ serial = libinput_tablet_tool_get_serial(tool);
+ ck_assert_int_eq(serial, 0);
+ libinput_event_destroy(event);
+
+ for (int x = 4500; x < 8000; x += 1000) {
+ litest_event(dev, EV_ABS, ABS_X, x);
+ litest_event(dev, EV_ABS, ABS_Y, 2000);
+ litest_event(dev, EV_MSC, MSC_SERIAL, 0);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ libinput_dispatch(li);
+ }
+ litest_drain_events(li);
+
+ /* Now send the serial */
+ litest_event(dev, EV_ABS, ABS_X, 4500);
+ litest_event(dev, EV_ABS, ABS_Y, 2000);
+ litest_event(dev, EV_MSC, MSC_SERIAL, 1234566);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ libinput_dispatch(li);
+
+ event = libinput_get_event(li);
+ tev = litest_is_tablet_event(event,
+ LIBINPUT_EVENT_TABLET_TOOL_AXIS);
+ tool = libinput_event_tablet_tool_get_tool(tev);
+ serial = libinput_tablet_tool_get_serial(tool);
+ ck_assert_int_eq(serial, 0);
+ libinput_event_destroy(event);
+
+ for (int x = 4500; x < 8000; x += 500) {
+ litest_event(dev, EV_ABS, ABS_X, x);
+ litest_event(dev, EV_ABS, ABS_Y, 2000);
+ litest_event(dev, EV_MSC, MSC_SERIAL, 1234566);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ libinput_dispatch(li);
+ }
+
+ event = libinput_get_event(li);
+ do {
+ tev = litest_is_tablet_event(event,
+ LIBINPUT_EVENT_TABLET_TOOL_AXIS);
+ tool = libinput_event_tablet_tool_get_tool(tev);
+ serial = libinput_tablet_tool_get_serial(tool);
+ ck_assert_int_eq(serial, 0);
+ libinput_event_destroy(event);
+ event = libinput_get_event(li);
+ } while (event != NULL);
+
+ /* Quirk: tool out event is a serial of 0 */
+ litest_event(dev, EV_ABS, ABS_X, 4500);
+ litest_event(dev, EV_ABS, ABS_Y, 2000);
+ litest_event(dev, EV_MSC, MSC_SERIAL, 0);
+ litest_event(dev, EV_KEY, BTN_TOOL_PEN, 0);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ libinput_dispatch(li);
+
+ event = libinput_get_event(li);
+ tev = litest_is_tablet_event(event,
+ LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
+ tool = libinput_event_tablet_tool_get_tool(tev);
+ serial = libinput_tablet_tool_get_serial(tool);
+ ck_assert_int_eq(serial, 0);
+ libinput_event_destroy(event);
+}
+END_TEST
+
START_TEST(tool_capabilities)
{
struct libinput *li = litest_create_context();
litest_add("tablet:tool_serial", invalid_serials, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
litest_add_no_device("tablet:tool_serial", tools_with_serials);
litest_add_no_device("tablet:tool_serial", tools_without_serials);
+ litest_add_for_device("tablet:tool_serial", tool_delayed_serial, LITEST_WACOM_HID4800_PEN);
litest_add("tablet:proximity", proximity_out_clear_buttons, LITEST_TABLET, LITEST_ANY);
litest_add("tablet:proximity", proximity_in_out, LITEST_TABLET, LITEST_ANY);
litest_add("tablet:proximity", proximity_in_button_down, LITEST_TABLET, LITEST_ANY);