We may be in the middle of a software button click or a tap, so make sure we
go back to the device-neutral state by unwinding.

Signed-off-by: Peter Hutterer <peter.hutte...@who-t.net>
---
 src/evdev-mt-touchpad-buttons.c | 10 +++++
 src/evdev-mt-touchpad-tap.c     |  6 +++
 src/evdev-mt-touchpad.c         | 91 +++++++++++++++++++++++++++++++++++++++++
 src/evdev-mt-touchpad.h         | 13 ++++++
 test/device.c                   | 10 ++---
 5 files changed, 125 insertions(+), 5 deletions(-)

diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c
index f6235a0..1dd8913 100644
--- a/src/evdev-mt-touchpad-buttons.c
+++ b/src/evdev-mt-touchpad-buttons.c
@@ -484,6 +484,16 @@ tp_process_button(struct tp_dispatch *tp,
        return 0;
 }
 
+void
+tp_release_all_buttons(struct tp_dispatch *tp,
+                      uint64_t time)
+{
+       if (tp->buttons.state) {
+               tp->buttons.state = 0;
+               tp->queued |= TOUCHPAD_EVENT_BUTTON_RELEASE;
+       }
+}
+
 int
 tp_init_buttons(struct tp_dispatch *tp,
                struct evdev_device *device)
diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c
index a19d51e..8f055fc 100644
--- a/src/evdev-mt-touchpad-tap.c
+++ b/src/evdev-mt-touchpad-tap.c
@@ -693,3 +693,9 @@ tp_destroy_tap(struct tp_dispatch *tp)
 {
        libinput_timer_cancel(&tp->tap.timer);
 }
+
+void
+tp_release_all_taps(struct tp_dispatch *tp, uint64_t now)
+{
+       tp_tap_handle_timeout(now, tp);
+}
diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index cd31c48..51eced6 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -641,6 +641,41 @@ tp_destroy(struct evdev_dispatch *dispatch)
        free(tp);
 }
 
+static void
+tp_suspend(struct tp_dispatch *tp, struct evdev_device *device)
+{
+       uint64_t now = libinput_now(tp->device->base.seat->libinput);
+       struct tp_touch *t;
+
+       /* Unroll the touchpad state.
+        * Release buttons first. If tp is a clickpad, the button event
+        * must come before the touch up. If it isn't, the order doesn't
+        * matter anyway
+        *
+        * Then cancel all timeouts on the taps, triggering the last set
+        * of events.
+        *
+        * Then lift all touches so the touchpad is in a neutral state.
+        *
+        */
+       tp_release_all_buttons(tp, now);
+       tp_release_all_taps(tp, now);
+
+       tp_for_each_touch(tp, t) {
+               tp_end_touch(tp, t, now);
+       }
+
+       tp_handle_state(tp, now);
+
+       evdev_device_suspend(device);
+}
+
+static void
+tp_resume(struct tp_dispatch *tp, struct evdev_device *device)
+{
+       evdev_device_resume(device);
+}
+
 static struct evdev_dispatch_interface tp_interface = {
        tp_process,
        tp_destroy
@@ -836,6 +871,54 @@ tp_init(struct tp_dispatch *tp,
        return 0;
 }
 
+static uint32_t
+tp_sendevents_get_modes(struct libinput_device *device)
+{
+       return LIBINPUT_CONFIG_SEND_EVENTS_ENABLED |
+              LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
+}
+
+static enum libinput_config_status
+tp_sendevents_set_mode(struct libinput_device *device,
+                      enum libinput_config_send_events_mode mode)
+{
+       struct evdev_device *evdev = (struct evdev_device*)device;
+       struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
+
+       if (mode == tp->sendevents.current_mode)
+               return LIBINPUT_CONFIG_STATUS_SUCCESS;
+
+       switch(mode) {
+       case LIBINPUT_CONFIG_SEND_EVENTS_ENABLED:
+               tp_resume(tp, evdev);
+               break;
+       case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED:
+               tp_suspend(tp, evdev);
+               break;
+       default:
+               return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
+       }
+
+       tp->sendevents.current_mode = mode;
+
+       return LIBINPUT_CONFIG_STATUS_SUCCESS;
+}
+
+static enum libinput_config_send_events_mode
+tp_sendevents_get_mode(struct libinput_device *device)
+{
+       struct evdev_device *evdev = (struct evdev_device*)device;
+       struct tp_dispatch *dispatch = (struct tp_dispatch*)evdev->dispatch;
+
+       return dispatch->sendevents.current_mode;
+}
+
+static enum libinput_config_send_events_mode
+tp_sendevents_get_default_mode(struct libinput_device *device)
+{
+       return LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
+}
+
 struct evdev_dispatch *
 evdev_mt_touchpad_create(struct evdev_device *device)
 {
@@ -850,5 +933,13 @@ evdev_mt_touchpad_create(struct evdev_device *device)
                return NULL;
        }
 
+       device->base.config.sendevents = &tp->sendevents.config;
+
+       tp->sendevents.current_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
+       tp->sendevents.config.get_modes = tp_sendevents_get_modes;
+       tp->sendevents.config.set_mode = tp_sendevents_set_mode;
+       tp->sendevents.config.get_mode = tp_sendevents_get_mode;
+       tp->sendevents.config.get_default_mode = tp_sendevents_get_default_mode;
+
        return  &tp->base;
 }
diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
index 83edf4f..6988b79 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -217,6 +217,11 @@ struct tp_dispatch {
                int32_t right_edge;
                int32_t left_edge;
        } palm;
+
+       struct {
+               struct libinput_device_config_send_events config;
+               enum libinput_config_send_events_mode current_mode;
+       } sendevents;
 };
 
 #define tp_for_each_touch(_tp, _t) \
@@ -248,6 +253,10 @@ tp_process_button(struct tp_dispatch *tp,
                  const struct input_event *e,
                  uint64_t time);
 
+void
+tp_release_all_buttons(struct tp_dispatch *tp,
+                      uint64_t time);
+
 int
 tp_post_button_events(struct tp_dispatch *tp, uint64_t time);
 
@@ -260,4 +269,8 @@ tp_button_touch_active(struct tp_dispatch *tp, struct 
tp_touch *t);
 bool
 tp_button_is_inside_softbutton_area(struct tp_dispatch *tp, struct tp_touch 
*t);
 
+void
+tp_release_all_taps(struct tp_dispatch *tp,
+                   uint64_t time);
+
 #endif
diff --git a/test/device.c b/test/device.c
index 1294740..8db69fd 100644
--- a/test/device.c
+++ b/test/device.c
@@ -262,12 +262,12 @@ END_TEST
 
 int main (int argc, char **argv)
 {
-       litest_add("device:sendevents", device_sendevents_config, LITEST_ANY, 
LITEST_TOUCHPAD);
-       litest_add("device:sendevents", device_sendevents_config_default, 
LITEST_ANY, LITEST_TOUCHPAD);
-       litest_add("device:sendevents", device_disable, LITEST_POINTER, 
LITEST_TOUCHPAD);
+       litest_add("device:sendevents", device_sendevents_config, LITEST_ANY, 
LITEST_ANY);
+       litest_add("device:sendevents", device_sendevents_config_default, 
LITEST_ANY, LITEST_ANY);
+       litest_add("device:sendevents", device_disable, LITEST_POINTER, 
LITEST_ANY);
        litest_add("device:sendevents", device_disable_events_pending, 
LITEST_POINTER, LITEST_TOUCHPAD);
-       litest_add("device:sendevents", device_double_disable, LITEST_ANY, 
LITEST_TOUCHPAD);
-       litest_add("device:sendevents", device_double_enable, LITEST_ANY, 
LITEST_TOUCHPAD);
+       litest_add("device:sendevents", device_double_disable, LITEST_ANY, 
LITEST_ANY);
+       litest_add("device:sendevents", device_double_enable, LITEST_ANY, 
LITEST_ANY);
        litest_add_no_device("device:sendevents", 
device_reenable_syspath_changed);
        litest_add_no_device("device:sendevents", 
device_reenable_device_removed);
 
-- 
1.9.3

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

Reply via email to