[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