From 61e8542d6e578fd6fa7679452738c9ad3edf22e7 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Tue, 2 Aug 2016 17:03:54 +1000 Subject: [PATCH] evdev: release current touches when the device is suspended Previously suspending a touch device with at least one touch down would never release the touch point. Signed-off-by: Peter Hutterer Reviewed-by: Jason Gerecke --- src/evdev.c | 39 ++++++++++++++++++++---- test/device.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 6 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index b35c1eaa..7c668b11 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -1084,17 +1084,38 @@ fallback_process(struct evdev_dispatch *evdev_dispatch, } } +static void +release_touches(struct fallback_dispatch *dispatch, + struct evdev_device *device, + uint64_t time) +{ + unsigned int idx; + bool need_frame = false; + + need_frame = fallback_flush_st_up(dispatch, device, time); + + for (idx = 0; idx < dispatch->mt.slots_len; idx++) { + struct mt_slot *slot = &dispatch->mt.slots[idx]; + + if (slot->seat_slot == -1) + continue; + + if (fallback_flush_mt_up(dispatch, device, idx, time)) + need_frame = true; + } + + if (need_frame) + touch_notify_frame(&device->base, time); +} + static void release_pressed_keys(struct fallback_dispatch *dispatch, - struct evdev_device *device) + struct evdev_device *device, + uint64_t time) { struct libinput *libinput = evdev_libinput_context(device); - uint64_t time; int code; - if ((time = libinput_now(libinput)) == 0) - return; - for (code = 0; code < KEY_CNT; code++) { int count = get_key_down_count(device, code); @@ -1143,8 +1164,14 @@ fallback_suspend(struct evdev_dispatch *evdev_dispatch, struct evdev_device *device) { struct fallback_dispatch *dispatch = (struct fallback_dispatch*)evdev_dispatch; + struct libinput *libinput = evdev_libinput_context(device); + uint64_t time; - release_pressed_keys(dispatch, device); + if ((time = libinput_now(libinput)) == 0) + return; + + release_touches(dispatch, device, time); + release_pressed_keys(dispatch, device, time); memset(dispatch->hw_key_mask, 0, sizeof(dispatch->hw_key_mask)); } diff --git a/test/device.c b/test/device.c index 82ef03be..68f9b8b5 100644 --- a/test/device.c +++ b/test/device.c @@ -211,6 +211,85 @@ START_TEST(device_disable_touchpad) } END_TEST +START_TEST(device_disable_touch) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_device *device; + enum libinput_config_status status; + + device = dev->libinput_device; + + litest_drain_events(li); + + status = libinput_device_config_send_events_set_mode(device, + LIBINPUT_CONFIG_SEND_EVENTS_DISABLED); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + /* no event from disabling */ + litest_assert_empty_queue(li); + + litest_touch_down(dev, 0, 50, 50); + litest_touch_move_to(dev, 0, 50, 50, 90, 90, 10, 0); + litest_touch_up(dev, 0); + + litest_assert_empty_queue(li); + + /* no event from resuming */ + status = libinput_device_config_send_events_set_mode(device, + LIBINPUT_CONFIG_SEND_EVENTS_ENABLED); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + litest_assert_empty_queue(li); +} +END_TEST + +START_TEST(device_disable_touch_during_touch) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_device *device; + enum libinput_config_status status; + struct libinput_event *event; + + device = dev->libinput_device; + + litest_touch_down(dev, 0, 50, 50); + litest_touch_move_to(dev, 0, 50, 50, 90, 90, 10, 0); + litest_drain_events(li); + + status = libinput_device_config_send_events_set_mode(device, + LIBINPUT_CONFIG_SEND_EVENTS_DISABLED); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + + /* after disabling sendevents we require a touch up */ + libinput_dispatch(li); + event = libinput_get_event(li); + litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_UP); + libinput_event_destroy(event); + + event = libinput_get_event(li); + litest_is_touch_event(event, LIBINPUT_EVENT_TOUCH_FRAME); + libinput_event_destroy(event); + + litest_assert_empty_queue(li); + + litest_touch_move_to(dev, 0, 90, 90, 50, 50, 10, 0); + litest_touch_up(dev, 0); + + litest_touch_down(dev, 0, 50, 50); + litest_touch_move_to(dev, 0, 50, 50, 90, 90, 10, 0); + litest_touch_up(dev, 0); + + litest_assert_empty_queue(li); + + /* no event from resuming */ + status = libinput_device_config_send_events_set_mode(device, + LIBINPUT_CONFIG_SEND_EVENTS_ENABLED); + ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS); + litest_assert_empty_queue(li); +} +END_TEST + START_TEST(device_disable_events_pending) { struct litest_device *dev = litest_current_device(); @@ -1353,6 +1432,10 @@ litest_setup_tests_device(void) litest_add("device:sendevents", device_sendevents_config_default, LITEST_ANY, LITEST_TABLET); litest_add("device:sendevents", device_disable, LITEST_RELATIVE, LITEST_TABLET); litest_add("device:sendevents", device_disable_touchpad, LITEST_TOUCHPAD, LITEST_TABLET); + litest_add("device:sendevents", device_disable_touch, LITEST_TOUCH, LITEST_ANY); + litest_add("device:sendevents", device_disable_touch_during_touch, LITEST_TOUCH, LITEST_ANY); + litest_add("device:sendevents", device_disable_touch, LITEST_SINGLE_TOUCH, LITEST_TOUCHPAD); + litest_add("device:sendevents", device_disable_touch_during_touch, LITEST_SINGLE_TOUCH, LITEST_TOUCHPAD); litest_add("device:sendevents", device_disable_events_pending, LITEST_RELATIVE, LITEST_TOUCHPAD|LITEST_TABLET); litest_add("device:sendevents", device_double_disable, LITEST_ANY, LITEST_TABLET); litest_add("device:sendevents", device_double_enable, LITEST_ANY, LITEST_TABLET);