With tablets that don't support serial numbers, we can't guarantee that the tool
objects are unique. Because of this, this can give clients the false impression
that a tool without a serial number is being shared between tablets when it very
well might not be. So we keep tools without serial numbers in a list that's
local to the tablet they belong to, and keep tools with serials in a list that's
local to the libinput context.

Signed-off-by: Stephen Chandler Paul <thatsly...@gmail.com>
---

Changes:
        - Added a description to the patch
        - Fixed all of the memory leaks, passes make check with flying colors
          now

 src/evdev-tablet.c | 37 ++++++++++++++++++-----
 src/evdev-tablet.h |  4 +++
 test/tablet.c      | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 120 insertions(+), 8 deletions(-)

diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c
index 31dd8d7..43da67a 100644
--- a/src/evdev-tablet.c
+++ b/src/evdev-tablet.c
@@ -259,17 +259,32 @@ tablet_process_misc(struct tablet_dispatch *tablet,
 }
 
 static struct libinput_tool *
-tablet_get_tool(struct libinput *li,
+tablet_get_tool(struct tablet_dispatch *tablet,
                enum libinput_tool_type type,
                uint32_t serial)
 {
        struct libinput_tool *tool = NULL, *t;
+       struct list *tool_list;
 
-       /* Check if we already have the tool in our list of tools */
-       list_for_each(t, &li->tool_list, link) {
-               if (type == t->type && serial == t->serial) {
-                       tool = t;
-                       break;
+       if (serial) {
+               tool_list = &tablet->device->base.seat->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) {
+                               tool = t;
+                               break;
+                       }
+               }
+       } else {
+               tool_list = &tablet->tool_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;
+                       }
                }
        }
 
@@ -283,7 +298,7 @@ tablet_get_tool(struct libinput *li,
                        .refcount = 1,
                };
 
-               list_insert(&li->tool_list, &tool->link);
+               list_insert(tool_list, &tool->link);
        }
 
        return tool;
@@ -382,7 +397,7 @@ tablet_flush(struct tablet_dispatch *tablet,
             uint32_t time)
 {
        struct libinput_tool *tool =
-               tablet_get_tool(device->base.seat->libinput,
+               tablet_get_tool(tablet,
                                tablet->current_tool_type,
                                tablet->current_tool_serial);
 
@@ -473,6 +488,11 @@ tablet_destroy(struct evdev_dispatch *dispatch)
 {
        struct tablet_dispatch *tablet =
                (struct tablet_dispatch*)dispatch;
+       struct libinput_tool *tool, *tmp;
+
+       list_for_each_safe(tool, tmp, &tablet->tool_list, link) {
+               libinput_tool_unref(tool);
+       }
 
        free(tablet);
 }
@@ -490,6 +510,7 @@ tablet_init(struct tablet_dispatch *tablet,
        tablet->device = device;
        tablet->status = TABLET_NONE;
        tablet->current_tool_type = LIBINPUT_TOOL_NONE;
+       list_init(&tablet->tool_list);
 
        tablet_mark_all_axes_changed(tablet, device);
 
diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h
index 1b53d20..d16aef3 100644
--- a/src/evdev-tablet.h
+++ b/src/evdev-tablet.h
@@ -26,6 +26,7 @@
 #define EVDEV_TABLET_H
 
 #include "evdev.h"
+#include <stdbool.h>
 
 enum tablet_status {
        TABLET_NONE = 0,
@@ -49,6 +50,9 @@ struct tablet_dispatch {
        unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_CNT)];
        double axes[LIBINPUT_TABLET_AXIS_CNT];
 
+       /* Only used for tablets that don't report serial numbers */
+       struct list tool_list;
+
        struct button_state button_state;
        struct button_state prev_button_state;
 
diff --git a/test/tablet.c b/test/tablet.c
index 0cd6357..2de0989 100644
--- a/test/tablet.c
+++ b/test/tablet.c
@@ -681,6 +681,91 @@ START_TEST(pad_buttons_ignored)
 }
 END_TEST
 
+START_TEST(tools_with_serials)
+{
+       struct libinput *li = litest_create_context();
+       struct litest_device *dev[2];
+       struct libinput_tool *tool[2];
+       struct libinput_event *event;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               dev[i] = litest_add_device_with_overrides(li,
+                                                         LITEST_WACOM_INTUOS,
+                                                         NULL,
+                                                         NULL,
+                                                         NULL,
+                                                         NULL);
+
+               litest_event(dev[i], EV_KEY, BTN_TOOL_PEN, 1);
+               litest_event(dev[i], EV_MSC, MSC_SERIAL, 100);
+               litest_event(dev[i], EV_SYN, SYN_REPORT, 0);
+
+               libinput_dispatch(li);
+               while ((event = libinput_get_event(li))) {
+                       if (libinput_event_get_type(event) ==
+                           LIBINPUT_EVENT_TABLET_PROXIMITY_IN) {
+                               struct libinput_event_tablet *t =
+                                       libinput_event_get_tablet_event(event);
+
+                               tool[i] = libinput_event_tablet_get_tool(t);
+                       }
+
+                       libinput_event_destroy(event);
+               }
+       }
+
+       /* We should get the same object for both devices */
+       ck_assert_ptr_eq(tool[0], tool[1]);
+
+       litest_delete_device(dev[0]);
+       litest_delete_device(dev[1]);
+       libinput_unref(li);
+}
+END_TEST
+
+START_TEST(tools_without_serials)
+{
+       struct libinput *li = litest_create_context();
+       struct litest_device *dev[2];
+       struct libinput_tool *tool[2];
+       struct libinput_event *event;
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               dev[i] = litest_add_device_with_overrides(li,
+                                                         LITEST_WACOM_ISDV4,
+                                                         NULL,
+                                                         NULL,
+                                                         NULL,
+                                                         NULL);
+
+               litest_event(dev[i], EV_KEY, BTN_TOOL_PEN, 1);
+               litest_event(dev[i], EV_SYN, SYN_REPORT, 0);
+
+               libinput_dispatch(li);
+               while ((event = libinput_get_event(li))) {
+                       if (libinput_event_get_type(event) ==
+                           LIBINPUT_EVENT_TABLET_PROXIMITY_IN) {
+                               struct libinput_event_tablet *t =
+                                       libinput_event_get_tablet_event(event);
+
+                               tool[i] = libinput_event_tablet_get_tool(t);
+                       }
+
+                       libinput_event_destroy(event);
+               }
+       }
+
+       /* We should get different tool objects for each device */
+       ck_assert_ptr_ne(tool[0], tool[1]);
+
+       litest_delete_device(dev[0]);
+       litest_delete_device(dev[1]);
+       libinput_unref(li);
+}
+END_TEST
+
 int
 main(int argc, char **argv)
 {
@@ -688,6 +773,8 @@ main(int argc, char **argv)
        litest_add("tablet:tool_serial", tool_serial, LITEST_TABLET | 
LITEST_TOOL_SERIAL, LITEST_ANY);
        litest_add("tablet:tool_serial", serial_changes_tool, LITEST_TABLET | 
LITEST_TOOL_SERIAL, LITEST_ANY);
        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("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", bad_distance_events, LITEST_TABLET | 
LITEST_DISTANCE, LITEST_ANY);
-- 
1.8.5.5

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to