[PATCH libinput v2 3/3] touchpad: Add edge-scrolling support
Peter Hutterer
peter.hutterer at who-t.net
Wed Nov 19 22:21:45 PST 2014
On Wed, Nov 19, 2014 at 01:45:35PM +0100, Hans de Goede wrote:
> Add edge-scrolling support for non multi-touch touchpads as well as for
> users who prefer edge-scrolling (as long as they don't have a clickpad).
>
> Note the percentage to use of the width / height as scroll-edge differs from
> one manufacturer to the next, the various per model percentages were taken
> from xf86-input-synaptics.
>
> BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=85635
> Signed-off-by: Hans de Goede <hdegoede at redhat.com>
> ---
> doc/touchpad-edge-scrolling-state-machine.svg | 262 ++++++++++++++++++
> src/Makefile.am | 1 +
> src/evdev-mt-touchpad-edge-scroll.c | 373 ++++++++++++++++++++++++++
> src/evdev-mt-touchpad.c | 93 ++++++-
> src/evdev-mt-touchpad.h | 46 ++++
> 5 files changed, 763 insertions(+), 12 deletions(-)
> create mode 100644 doc/touchpad-edge-scrolling-state-machine.svg
> create mode 100644 src/evdev-mt-touchpad-edge-scroll.c
>
> diff --git a/doc/touchpad-edge-scrolling-state-machine.svg b/doc/touchpad-edge-scrolling-state-machine.svg
> new file mode 100644
> index 0000000..7a82d88
[...]
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 5cc52a6..027e08c 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -15,6 +15,7 @@ libinput_la_SOURCES = \
> evdev-mt-touchpad.h \
> evdev-mt-touchpad-tap.c \
> evdev-mt-touchpad-buttons.c \
> + evdev-mt-touchpad-edge-scroll.c \
> filter.c \
> filter.h \
> filter-private.h \
> diff --git a/src/evdev-mt-touchpad-edge-scroll.c b/src/evdev-mt-touchpad-edge-scroll.c
> new file mode 100644
> index 0000000..3647546
> --- /dev/null
> +++ b/src/evdev-mt-touchpad-edge-scroll.c
> @@ -0,0 +1,373 @@
> +/*
> + * Copyright © 2014 Red Hat, Inc.
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and
> + * its documentation for any purpose is hereby granted without fee, provided
> + * that the above copyright notice appear in all copies and that both that
> + * copyright notice and this permission notice appear in supporting
> + * documentation, and that the name of the copyright holders not be used in
> + * advertising or publicity pertaining to distribution of the software
> + * without specific, written prior permission. The copyright holders make
> + * no representations about the suitability of this software for any
> + * purpose. It is provided "as is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <errno.h>
> +#include <limits.h>
> +#include <math.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include "linux/input.h"
> +
> +#include "evdev-mt-touchpad.h"
> +
> +#define DEFAULT_SCROLL_LOCK_TIMEOUT 300 /* ms */
> +/* Use a reasonably large threshold until locked into scrolling mode, to
> + avoid accidentally locking in scrolling mode when trying to use the entire
> + touchpad to move the pointer. The user can wait for the timeout to trigger
> + to do a small scroll. */
> +#define DEFAULT_SCROLL_THRESHOLD 10.0
what's the unit of this? should be mentioned
> +
> +enum scroll_event {
> + SCROLL_EVENT_TOUCH,
> + SCROLL_EVENT_MOTION,
> + SCROLL_EVENT_RELEASE,
> + SCROLL_EVENT_TIMEOUT,
> + SCROLL_EVENT_POSTED,
> +};
> +
> +static uint32_t
> +tp_touch_get_edge(struct tp_dispatch *tp, struct tp_touch *touch)
> +{
> + uint32_t edge = EDGE_NONE;
> +
> + if (tp->scroll.mode != LIBINPUT_CONFIG_SCROLL_EDGE)
> + return 0;
> +
could just return edge (or EDGE_NONE if you want to be specific)
> + if (touch->x > tp->scroll.right_edge)
> + edge |= EDGE_RIGHT;
> +
> + if (touch->y > tp->scroll.bottom_edge)
> + edge |= EDGE_BOTTOM;
> +
> + return edge;
> +}
> +
> +static void
> +tp_edge_scroll_set_state(struct tp_dispatch *tp,
> + struct tp_touch *t,
> + enum tp_edge_scroll_touch_state state)
> +{
> + libinput_timer_cancel(&t->scroll.timer);
> +
> + t->scroll.state = state;
> +
> + switch (state) {
> + case EDGE_SCROLL_TOUCH_STATE_NONE:
> + t->scroll.edge = EDGE_NONE;
> + t->scroll.threshold = DEFAULT_SCROLL_THRESHOLD;
> + break;
> + case EDGE_SCROLL_TOUCH_STATE_EDGE_NEW:
> + t->scroll.edge = tp_touch_get_edge(tp, t);
> + libinput_timer_set(&t->scroll.timer,
> + t->millis + DEFAULT_SCROLL_LOCK_TIMEOUT);
> + break;
> + case EDGE_SCROLL_TOUCH_STATE_EDGE:
> + t->scroll.threshold = 0.01; /* Do not allow 0.0 events */
> + break;
> + case EDGE_SCROLL_TOUCH_STATE_AREA:
> + t->scroll.edge = EDGE_NONE;
> + tp_set_pointer(tp, t);
> + break;
> + }
> +}
> +
> +static void
> +tp_edge_scroll_handle_none(struct tp_dispatch *tp,
> + struct tp_touch *t,
> + enum scroll_event event)
> +{
> + struct libinput *libinput = tp->device->base.seat->libinput;
> +
> + switch (event) {
> + case SCROLL_EVENT_TOUCH:
> + if (tp_touch_get_edge(tp, t)) {
> + tp_edge_scroll_set_state(tp, t,
> + EDGE_SCROLL_TOUCH_STATE_EDGE_NEW);
> + } else {
> + tp_edge_scroll_set_state(tp, t,
> + EDGE_SCROLL_TOUCH_STATE_AREA);
> + }
> + break;
> + case SCROLL_EVENT_MOTION:
> + case SCROLL_EVENT_RELEASE:
> + case SCROLL_EVENT_TIMEOUT:
> + case SCROLL_EVENT_POSTED:
> + log_bug_libinput(libinput,
> + "unexpect scroll event in none state\n");
> + break;
> + }
> +}
> +
> +static void
> +tp_edge_scroll_handle_edge_new(struct tp_dispatch *tp,
> + struct tp_touch *t,
> + enum scroll_event event)
> +{
> + struct libinput *libinput = tp->device->base.seat->libinput;
> +
> + switch (event) {
> + case SCROLL_EVENT_TOUCH:
> + log_bug_libinput(libinput,
> + "unexpect scroll event in edge new state\n");
> + break;
> + case SCROLL_EVENT_MOTION:
> + t->scroll.edge &= tp_touch_get_edge(tp, t);
> + if (!t->scroll.edge)
> + tp_edge_scroll_set_state(tp, t,
> + EDGE_SCROLL_TOUCH_STATE_AREA);
> + break;
> + case SCROLL_EVENT_RELEASE:
> + tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_NONE);
> + break;
> + case SCROLL_EVENT_TIMEOUT:
> + case SCROLL_EVENT_POSTED:
> + tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_EDGE);
> + break;
> + }
> +}
> +
> +static void
> +tp_edge_scroll_handle_edge(struct tp_dispatch *tp,
> + struct tp_touch *t,
> + enum scroll_event event)
> +{
> + struct libinput *libinput = tp->device->base.seat->libinput;
> +
> + switch (event) {
> + case SCROLL_EVENT_TOUCH:
> + case SCROLL_EVENT_TIMEOUT:
> + log_bug_libinput(libinput,
> + "unexpect scroll event in edge state\n");
> + break;
> + case SCROLL_EVENT_MOTION:
> + /* If started at the bottom right, decide in which dir to scroll */
> + if (t->scroll.edge == (EDGE_RIGHT | EDGE_BOTTOM)) {
> + t->scroll.edge &= tp_touch_get_edge(tp, t);
> + if (!t->scroll.edge)
> + tp_edge_scroll_set_state(tp, t,
> + EDGE_SCROLL_TOUCH_STATE_AREA);
> + }
> + break;
> + case SCROLL_EVENT_RELEASE:
> + tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_NONE);
> + break;
> + case SCROLL_EVENT_POSTED:
> + break;
> + }
> +}
> +
> +static void
> +tp_edge_scroll_handle_area(struct tp_dispatch *tp,
> + struct tp_touch *t,
> + enum scroll_event event)
> +{
> + struct libinput *libinput = tp->device->base.seat->libinput;
> +
> + switch (event) {
> + case SCROLL_EVENT_TOUCH:
> + case SCROLL_EVENT_TIMEOUT:
> + case SCROLL_EVENT_POSTED:
> + log_bug_libinput(libinput,
> + "unexpect scroll event in area state\n");
> + break;
> + case SCROLL_EVENT_MOTION:
> + break;
> + case SCROLL_EVENT_RELEASE:
> + tp_edge_scroll_set_state(tp, t, EDGE_SCROLL_TOUCH_STATE_NONE);
> + break;
> + }
> +}
> +
> +static void
> +tp_edge_scroll_handle_event(struct tp_dispatch *tp,
> + struct tp_touch *t,
> + enum scroll_event event)
> +{
> + switch (t->scroll.state) {
> + case EDGE_SCROLL_TOUCH_STATE_NONE:
> + tp_edge_scroll_handle_none(tp, t, event);
> + break;
> + case EDGE_SCROLL_TOUCH_STATE_EDGE_NEW:
> + tp_edge_scroll_handle_edge_new(tp, t, event);
> + break;
> + case EDGE_SCROLL_TOUCH_STATE_EDGE:
> + tp_edge_scroll_handle_edge(tp, t, event);
> + break;
> + case EDGE_SCROLL_TOUCH_STATE_AREA:
> + tp_edge_scroll_handle_area(tp, t, event);
> + break;
> + }
> +}
> +
> +static void
> +tp_edge_scroll_handle_timeout(uint64_t now, void *data)
> +{
> + struct tp_touch *t = data;
> +
> + tp_edge_scroll_handle_event(t->tp, t, SCROLL_EVENT_TIMEOUT);
> +}
> +
> +int
> +tp_edge_scroll_init(struct tp_dispatch *tp, struct evdev_device *device)
> +{
> + struct tp_touch *t;
> + int width, height;
> + int edge_width, edge_height;
> +
> + width = device->abs.absinfo_x->maximum - device->abs.absinfo_x->minimum;
> + height = device->abs.absinfo_y->maximum - device->abs.absinfo_y->minimum;
> +
> + switch (tp->model) {
> + case MODEL_SYNAPTICS:
> + edge_width = width * .07;
> + edge_height = height * .07;
> + break;
> + case MODEL_ALPS:
> + edge_width = width * .15;
> + edge_height = height * .15;
> + break;
> + case MODEL_APPLETOUCH:
> + case MODEL_UNIBODY_MACBOOK:
unless there's one I didn't find in my quick search, the unibodies all had
clickpads so we should skip this here and maybe leave a comment for that.
> + edge_width = width * .085;
> + edge_height = height * .085;
> + break;
> + default:
> + edge_width = width * .04;
> + edge_height = height * .054;
make MODEL_SYNAPTICS the same as default please
> + }
> +
> + tp->scroll.right_edge = device->abs.absinfo_x->maximum - edge_width;
> + tp->scroll.bottom_edge = device->abs.absinfo_y->maximum - edge_height;
> +
> + tp_for_each_touch(tp, t) {
> + t->scroll.last_axis = -1;
can we name this direction like in the main scrolling code? or will this
lead to confusion?
> + t->scroll.threshold = DEFAULT_SCROLL_THRESHOLD;
> + libinput_timer_init(&t->scroll.timer,
> + device->base.seat->libinput,
> + tp_edge_scroll_handle_timeout, t);
> + }
> +
> + return 0;
> +}
> +
> +void
> +tp_destroy_edge_scroll(struct tp_dispatch *tp)
> +{
> + struct tp_touch *t;
> +
> + tp_for_each_touch(tp, t)
> + libinput_timer_cancel(&t->scroll.timer);
> +}
> +
> +void
> +tp_edge_scroll_handle_state(struct tp_dispatch *tp, uint64_t time)
> +{
> + struct tp_touch *t;
> +
> + tp_for_each_touch(tp, t) {
> + if (!t->dirty)
> + continue;
> +
> + switch (t->state) {
> + case TOUCH_NONE:
> + break;
> + case TOUCH_BEGIN:
> + tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_TOUCH);
> + break;
> + case TOUCH_UPDATE:
> + tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_MOTION);
> + break;
> + case TOUCH_END:
> + tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_RELEASE);
> + break;
> + }
> + }
> +}
> +
> +int
> +tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time)
> +{
> + struct libinput_device *device = &tp->device->base;
> + struct tp_touch *t;
> + enum libinput_pointer_axis axis;
> + double dx, dy, *delta;
> +
> + tp_for_each_touch(tp, t) {
> + if (!t->dirty)
> + continue;
> +
> + switch (t->scroll.edge) {
> + case EDGE_NONE:
> + if (t->scroll.last_axis != -1) {
> + /* Send stop scroll event */
> + pointer_notify_axis(device, time,
> + t->scroll.last_axis, 0.0);
> + t->scroll.last_axis = -1;
> + }
> + continue;
this needs a big comment, I read over it a couple of times :)
but I think it's be better to initialize *delta to NULL and then have a
if (delta == NULL) continue; check after the switch. much less suprising.
ack to the rest, but the series doesn't apply here anymore. just push the
next one to your fdo repo and I can merge/c-p it from there. thanks.
Cheers,
Peter
> + case EDGE_RIGHT:
> + axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
> + delta = &dy;
> + break;
> + case EDGE_BOTTOM:
> + axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL;
> + delta = &dx;
> + break;
> + default: /* EDGE_RIGHT | EDGE_BOTTOM */
> + continue; /* Don't know direction yet, skip */
> + }
> +
> + tp_get_delta(t, &dx, &dy);
> + tp_filter_motion(tp, &dx, &dy, time);
> +
> + if (fabs(*delta) < t->scroll.threshold)
> + continue;
> +
> + pointer_notify_axis(device, time, axis, *delta);
> + t->scroll.last_axis = axis;
> +
> + tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_POSTED);
> + }
> +
> + return 0; /* Edge touches are suppressed by edge_scroll_touch_active */
> +}
> +
> +void
> +tp_edge_scroll_stop_events(struct tp_dispatch *tp, uint64_t time)
> +{
> + struct libinput_device *device = &tp->device->base;
> + struct tp_touch *t;
> +
> + tp_for_each_touch(tp, t) {
> + if (t->scroll.last_axis != -1) {
> + pointer_notify_axis(device, time,
> + t->scroll.last_axis, 0.0);
> + t->scroll.last_axis = -1;
> + }
> + }
> +}
> +
> +int
> +tp_edge_scroll_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
> +{
> + return t->scroll.state == EDGE_SCROLL_TOUCH_STATE_AREA;
> +}
> diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
> index 4ef5e66..e9b9049 100644
> --- a/src/evdev-mt-touchpad.c
> +++ b/src/evdev-mt-touchpad.c
> @@ -56,7 +56,7 @@ tp_motion_history_offset(struct tp_touch *t, int offset)
> return &t->history.samples[offset_index];
> }
>
> -static void
> +void
> tp_filter_motion(struct tp_dispatch *tp,
> double *dx, double *dy, uint64_t time)
> {
> @@ -339,7 +339,9 @@ tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
> {
> return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) &&
> !t->palm.is_palm &&
> - !t->pinned.is_pinned && tp_button_touch_active(tp, t);
> + !t->pinned.is_pinned &&
> + tp_button_touch_active(tp, t) &&
> + tp_edge_scroll_touch_active(tp, t);
> }
>
> void
> @@ -435,15 +437,12 @@ tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time)
> }
>
> static int
> -tp_post_scroll_events(struct tp_dispatch *tp, uint64_t time)
> +tp_twofinger_scroll_post_events(struct tp_dispatch *tp, uint64_t time)
> {
> struct tp_touch *t;
> int nfingers_down = 0;
>
> - if (tp->scroll.mode != LIBINPUT_CONFIG_SCROLL_2FG)
> - return 0;
> -
> - /* No scrolling during tap-n-drag */
> + /* No 2fg scrolling during tap-n-drag */
> if (tp_tap_dragging(tp))
> return 0;
>
> @@ -463,6 +462,60 @@ tp_post_scroll_events(struct tp_dispatch *tp, uint64_t time)
> }
>
> static void
> +tp_scroll_handle_state(struct tp_dispatch *tp, uint64_t time)
> +{
> + /* Note this must be always called, so that it knows the state of
> + * touches when the scroll-mode changes.
> + */
> + tp_edge_scroll_handle_state(tp, time);
> +}
> +
> +static int
> +tp_post_scroll_events(struct tp_dispatch *tp, uint64_t time)
> +{
> + struct libinput *libinput = tp->device->base.seat->libinput;
> +
> + switch (tp->scroll.mode) {
> + case LIBINPUT_CONFIG_SCROLL_NO_SCROLL:
> + break;
> + case LIBINPUT_CONFIG_SCROLL_2FG:
> + return tp_twofinger_scroll_post_events(tp, time);
> + case LIBINPUT_CONFIG_SCROLL_EDGE:
> + return tp_edge_scroll_post_events(tp, time);
> + case LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN:
> + log_bug_libinput(libinput, "Unexpected scroll mode\n");
> + break;
> + }
> + return 0;
> +}
> +
> +static void
> +tp_stop_scroll_events(struct tp_dispatch *tp, uint64_t time)
> +{
> + struct libinput *libinput = tp->device->base.seat->libinput;
> +
> + switch (tp->scroll.mode) {
> + case LIBINPUT_CONFIG_SCROLL_NO_SCROLL:
> + break;
> + case LIBINPUT_CONFIG_SCROLL_2FG:
> + evdev_stop_scroll(tp->device, time);
> + break;
> + case LIBINPUT_CONFIG_SCROLL_EDGE:
> + tp_edge_scroll_stop_events(tp, time);
> + break;
> + case LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN:
> + log_bug_libinput(libinput, "Unexpected scroll mode\n");
> + break;
> + }
> +}
> +
> +static void
> +tp_destroy_scroll(struct tp_dispatch *tp)
> +{
> + tp_destroy_edge_scroll(tp);
> +}
> +
> +static void
> tp_process_state(struct tp_dispatch *tp, uint64_t time)
> {
> struct tp_touch *t;
> @@ -495,6 +548,7 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
> }
>
> tp_button_handle_state(tp, time);
> + tp_scroll_handle_state(tp, time);
>
> /*
> * We have a physical button down event on a clickpad. To avoid
> @@ -530,6 +584,7 @@ tp_post_process_state(struct tp_dispatch *tp, uint64_t time)
> tp->queued = TOUCHPAD_EVENT_NONE;
> }
>
> +
> static void
> tp_post_events(struct tp_dispatch *tp, uint64_t time)
> {
> @@ -547,7 +602,7 @@ tp_post_events(struct tp_dispatch *tp, uint64_t time)
> filter_motion |= tp_post_button_events(tp, time);
>
> if (filter_motion || tp->sendevents.trackpoint_active) {
> - evdev_stop_scroll(tp->device, time);
> + tp_stop_scroll_events(tp, time);
> return;
> }
>
> @@ -626,6 +681,7 @@ tp_destroy(struct evdev_dispatch *dispatch)
> tp_destroy_tap(tp);
> tp_destroy_buttons(tp);
> tp_destroy_sendevents(tp);
> + tp_destroy_scroll(tp);
>
> free(tp->touches);
> free(tp);
> @@ -958,6 +1014,9 @@ tp_scroll_config_scroll_mode_get_modes(struct libinput_device *device)
> if (tp->ntouches >= 2)
> modes |= LIBINPUT_CONFIG_SCROLL_2FG;
>
> + if (!tp->buttons.is_clickpad)
> + modes |= LIBINPUT_CONFIG_SCROLL_EDGE;
> +
> return modes;
> }
>
> @@ -971,7 +1030,8 @@ tp_scroll_config_scroll_mode_set_mode(struct libinput_device *device,
> if (mode == tp->scroll.mode)
> return LIBINPUT_CONFIG_STATUS_SUCCESS;
>
> - evdev_stop_scroll(evdev, libinput_now(device->seat->libinput));
> + tp_stop_scroll_events(tp, libinput_now(device->seat->libinput));
> +
> tp->scroll.mode = mode;
>
> return LIBINPUT_CONFIG_STATUS_SUCCESS;
> @@ -989,12 +1049,20 @@ tp_scroll_config_scroll_mode_get_mode(struct libinput_device *device)
> static enum libinput_config_scroll_mode
> tp_scroll_config_scroll_mode_get_default_mode(struct libinput_device *device)
> {
> - return LIBINPUT_CONFIG_SCROLL_2FG;
> + struct evdev_device *evdev = (struct evdev_device*)device;
> + struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
> +
> + if (tp->ntouches >= 2)
> + return LIBINPUT_CONFIG_SCROLL_2FG;
> + else
> + return LIBINPUT_CONFIG_SCROLL_EDGE;
> }
>
> static int
> -tp_init_scroll(struct tp_dispatch *tp)
> +tp_init_scroll(struct tp_dispatch *tp, struct evdev_device *device)
> {
> + if (tp_edge_scroll_init(tp, device) != 0)
> + return -1;
>
> tp->scroll.config_natural.has = tp_scroll_config_natural_has;
> tp->scroll.config_natural.set_enabled = tp_scroll_config_natural_set;
> @@ -1096,7 +1164,7 @@ tp_init(struct tp_dispatch *tp,
> if (tp_init_sendevents(tp, device) != 0)
> return -1;
>
> - if (tp_init_scroll(tp) != 0)
> + if (tp_init_scroll(tp, device) != 0)
> return -1;
>
> device->seat_caps |= EVDEV_DEVICE_POINTER;
> @@ -1242,6 +1310,7 @@ evdev_mt_touchpad_create(struct evdev_device *device)
>
> tp->model = tp_get_model(device);
>
> + device->dispatch = &tp->base;
> if (tp_init(tp, device) != 0) {
> tp_destroy(&tp->base);
> return NULL;
> diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
> index d012458..1282e8d 100644
> --- a/src/evdev-mt-touchpad.h
> +++ b/src/evdev-mt-touchpad.h
> @@ -103,6 +103,20 @@ enum tp_tap_touch_state {
> TAP_TOUCH_STATE_DEAD, /**< exceeded motion/timeout */
> };
>
> +/* For edge scrolling, so we only care about right and bottom */
> +enum tp_edge {
> + EDGE_NONE = 0,
> + EDGE_RIGHT = (1 << 0),
> + EDGE_BOTTOM = (1 << 1),
> +};
> +
> +enum tp_edge_scroll_touch_state {
> + EDGE_SCROLL_TOUCH_STATE_NONE,
> + EDGE_SCROLL_TOUCH_STATE_EDGE_NEW,
> + EDGE_SCROLL_TOUCH_STATE_EDGE,
> + EDGE_SCROLL_TOUCH_STATE_AREA,
> +};
> +
> struct tp_motion {
> int32_t x;
> int32_t y;
> @@ -151,6 +165,14 @@ struct tp_touch {
> } tap;
>
> struct {
> + enum tp_edge_scroll_touch_state state;
> + uint32_t edge;
> + int last_axis;
> + double threshold;
> + struct libinput_timer timer;
> + } scroll;
> +
> + struct {
> bool is_palm;
> int32_t x, y; /* first coordinates if is_palm == true */
> uint32_t time; /* first timestamp if is_palm == true */
> @@ -216,6 +238,8 @@ struct tp_dispatch {
> struct libinput_device_config_scroll_mode config_mode;
> bool natural_scrolling_enabled;
> enum libinput_config_scroll_mode mode;
> + int32_t right_edge;
> + int32_t bottom_edge;
> } scroll;
>
> enum touchpad_event queued;
> @@ -252,6 +276,10 @@ tp_get_delta(struct tp_touch *t, double *dx, double *dy);
> void
> tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t);
>
> +void
> +tp_filter_motion(struct tp_dispatch *tp,
> + double *dx, double *dy, uint64_t time);
> +
> int
> tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time);
>
> @@ -306,4 +334,22 @@ tp_tap_resume(struct tp_dispatch *tp, uint64_t time);
> bool
> tp_tap_dragging(struct tp_dispatch *tp);
>
> +int
> +tp_edge_scroll_init(struct tp_dispatch *tp, struct evdev_device *device);
> +
> +void
> +tp_destroy_edge_scroll(struct tp_dispatch *tp);
> +
> +void
> +tp_edge_scroll_handle_state(struct tp_dispatch *tp, uint64_t time);
> +
> +int
> +tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time);
> +
> +void
> +tp_edge_scroll_stop_events(struct tp_dispatch *tp, uint64_t time);
> +
> +int
> +tp_edge_scroll_touch_active(struct tp_dispatch *tp, struct tp_touch *t);
> +
> #endif
> --
> 2.1.0
>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
>
More information about the wayland-devel
mailing list