From b14894e794a24b6fcfe12fa70c515c181a2591b2 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 26 Nov 2025 10:33:38 +1000 Subject: [PATCH] tablet: only apply eraser button settings if we have a device If the device is unplugged, our tool's last_device is NULL. If a caller then tries to the toggle the eraser button setting libinput would crash. Fix this by simply skipping the configuration until the tool goes back into proximity over some other device (if any). Closes #1223 (cherry picked from commit 1e8901d009898a8735b7a71ba354e0ea145b4c2f) Part-of: --- src/evdev-tablet.c | 9 ++++++--- test/test-tablet.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c index f60ba7a5..dfbed4cd 100644 --- a/src/evdev-tablet.c +++ b/src/evdev-tablet.c @@ -1272,10 +1272,13 @@ static void eraser_button_toggle(struct libinput_tablet_tool *tool) { struct libinput_device *libinput_device = tool->last_device; - struct evdev_device *device = evdev_device(libinput_device); - struct tablet_dispatch *tablet = tablet_dispatch(device->dispatch); - tablet_tool_apply_eraser_button(tablet, tool); + if (libinput_device) { + struct evdev_device *device = evdev_device(libinput_device); + struct tablet_dispatch *tablet = tablet_dispatch(device->dispatch); + + tablet_tool_apply_eraser_button(tablet, tool); + } } static enum libinput_config_status diff --git a/test/test-tablet.c b/test/test-tablet.c index 0a96a540..895df2d5 100644 --- a/test/test-tablet.c +++ b/test/test-tablet.c @@ -7722,6 +7722,51 @@ START_TEST(tablet_eraser_button_disabled) } END_TEST +START_TEST(tablet_eraser_button_config_after_device_removal) +{ + _litest_context_destroy_ struct libinput *li = litest_create_context(); + struct litest_device *tablet = litest_add_device(li, LITEST_ELAN_TABLET); + struct axis_replacement axes[] = { + { ABS_DISTANCE, 10 }, + { ABS_PRESSURE, 0 }, + { -1, -1 }, + }; + + litest_drain_events(li); + + litest_tablet_set_tool_type(tablet, BTN_TOOL_RUBBER); + litest_tablet_proximity_in(tablet, 10, 10, axes); + + litest_dispatch(li); + auto event = libinput_get_event(li); + auto tev = litest_is_tablet_event(event, LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + auto tool = libinput_event_tablet_tool_get_tool(tev); + libinput_tablet_tool_ref(tool); + libinput_event_destroy(event); + + litest_device_destroy(tablet); + litest_drain_events(li); + + /* Tool isn't associated with a device but config should take effect anyway */ + auto status = libinput_tablet_tool_config_eraser_button_set_mode( + tool, + LIBINPUT_CONFIG_ERASER_BUTTON_BUTTON); + litest_assert_enum_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + status = + libinput_tablet_tool_config_eraser_button_set_button(tool, BTN_STYLUS2); + litest_assert_enum_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + litest_assert_enum_eq(libinput_tablet_tool_config_eraser_button_get_mode(tool), + LIBINPUT_CONFIG_ERASER_BUTTON_BUTTON); + litest_assert_int_eq(libinput_tablet_tool_config_eraser_button_get_button(tool), + (unsigned)BTN_STYLUS2); + + litest_drain_events(li); + + libinput_tablet_tool_unref(tool); +} +END_TEST + TEST_COLLECTION(tablet) { /* clang-format off */ @@ -7886,6 +7931,8 @@ TEST_COLLECTION(tablet_eraser) "with-motion-events", 'b') { litest_add_parametrized(tablet_eraser_button_disabled, LITEST_TABLET, LITEST_TOTEM|LITEST_FORCED_PROXOUT, params); } + + litest_add_no_device(tablet_eraser_button_config_after_device_removal); /* clang-format on */ }