[PATCH 2/2] touchpad: Add edge-scrolling support
Hans de Goede
hdegoede at redhat.com
Wed Nov 19 02:50:13 PST 2014
Hi,
On 11/11/2014 02:20 AM, Peter Hutterer wrote:
> sorry for the duplicate Hans, wayland-devel got dropped of the first reply.
>
> On Fri, Nov 07, 2014 at 02:25:06PM +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.
>>
>> Signed-off-by: Hans de Goede <hdegoede at redhat.com>
>> ---
>> src/Makefile.am | 1 +
>> src/evdev-mt-touchpad-edge-scroll.c | 366 ++++++++++++++++++++++++++++++++++++
>> src/evdev-mt-touchpad.c | 59 +++++-
>> src/evdev-mt-touchpad.h | 46 +++++
>> 4 files changed, 463 insertions(+), 9 deletions(-)
>> create mode 100644 src/evdev-mt-touchpad-edge-scroll.c
>>
>> 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..2968db4
>> --- /dev/null
>> +++ b/src/evdev-mt-touchpad-edge-scroll.c
>> @@ -0,0 +1,366 @@
>> +/*
>> + * 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
>> +
>> +enum scroll_event {
>> + SCROLL_EVENT_TOUCH,
>> + SCROLL_EVENT_MOTION,
>> + SCROLL_EVENT_RELEASE,
>> + SCROLL_EVENT_TIMEOUT,
>> +};
>> +
>> +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;
>> +
>> + 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)
>
> fwiw, I prefer all args on separate lines if you need to split them anway.
Ok, will fix for v2.
>> +{
>> + 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:
>> + 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;
>> + }
>> +}
>
> can we make a pretty diagram for this statemachine? makes it a lot easier to
> visualize.
Done for v2.
>> +
>> +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:
>> + t->scroll.edge = tp_touch_get_edge(tp, t);
>> + if (t->scroll.edge) {
>> + 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:
>> + 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:
>> + 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;
>> + }
>> +}
>> +
>> +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:
>> + 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 = abs(device->abs.absinfo_x->maximum -
>> + device->abs.absinfo_x->minimum);
>> + height = abs(device->abs.absinfo_y->maximum -
>> + device->abs.absinfo_y->minimum);
>
> huh, I only just noticed that. we don't need the abs() here.
Fixed for v2.
>
>> +
>> + 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:
>
> the unibody macbooks already had a clickpad, so this isn't needed
>
>> + edge_width = width * .085;
>> + edge_height = height * .085;
>> + break;
>> + default:
>> + edge_width = width * .04;
>> + edge_height = height * .054;
>> + }
>
> fwiw, there is a bit of history there and many oddities are based on a
> the edges in synaptics being 'wrong'. the kernel exports the synaptics
> dimensions as the coordinates produced by 'an average finger', but it's not
> hard to go beyond min/max. iirc for alps and other devices the edges are the
> actual edges (and for the T440-style synaptics pads that we manually fixed
> up). Hence the need for different edge zones on synaptics.
>
> And the default numbers come from the synaptics user interface guide.
> Typical bezel limits: x 1472–5472 y 1408–4448
> Typical edge margins: x 1632–5312 y 1568–4288
> i.e. 4% and 5.4% are interpolated from those
>
> so in short, we don't need MODEL_SYNAPTICS, it's covered by the defaults.
>
> that just leaves APPLETOUCH and ALPS, I wonder if these have resolutions
> set (the synaptics code pre-dates resolution support in the kernel). if so,
> just defining a sensible size for the edge is enough (10mm?). or based on
> the diagonal.
As also mentioned in a private mail not all alps devices have resolution set,
so at least for some devices we will need to take a percentage of width / height
(no idea why you mention diagonal here).
>
>> +
>> + 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;
>> + 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;
>> + 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;
>> +
>> + if (t->scroll.state == EDGE_SCROLL_TOUCH_STATE_EDGE_NEW) {
>> + tp_edge_scroll_set_state(tp, t,
>> + EDGE_SCROLL_TOUCH_STATE_EDGE);
>> + }
>
> what happens if two touches are moving in the same edge zone? should we
> simply say "we've moved vertically already, ignore any other vertical edge
> movement"?
I've chosen to make edge scrolling 101% er per touch thing, which keeps
things nice and simple. So if the user does this both fingers generate independent
scroll events.
>
>> + }
>> +
>> + return 0; /* Edge touches are suppressed by edge_scroll_touch_active */
>> +}
>> +
>> +void
>> +tp_edge_scroll_stop(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 d2ee6ea..fb78fcd 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
>> @@ -431,6 +433,7 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
>> }
>>
>> tp_button_handle_state(tp, time);
>> + tp_edge_scroll_handle_state(tp, time);
>
> let's move scrolling into a 2-tier hierarchy, so any call is to
> tp_scroll_foo() and then splits up to:
> -> tp_scroll_2fg_foo
> -> tp_scroll_edge_foo
>
> that makes the code easier to follow and more consistent. that hierarchy is
> partially there already (tp_post_scroll_events() for example) but missing
> from here and e.g. tp_init.
Good idea, will fix for v2.
>
>>
>> /*
>> * We have a physical button down event on a clickpad. To avoid
>> @@ -503,15 +506,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_2fg_scroll_post_events(struct tp_dispatch *tp, uint64_t time)
>
> we have at least one call "...twofinger_scroll", this needs to be consistent.
Will fix for v2.
>> {
>> 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;
>>
>> @@ -530,6 +530,22 @@ tp_post_scroll_events(struct tp_dispatch *tp, uint64_t time)
>> return 1;
>> }
>>
>> +static int
>> +tp_post_scroll_events(struct tp_dispatch *tp, uint64_t time)
>> +{
>> + switch (tp->scroll.mode) {
>> + case LIBINPUT_CONFIG_SCROLL_NO_SCROLL:
>> + return 0;
>> + case LIBINPUT_CONFIG_SCROLL_2FG:
>> + return tp_2fg_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:
>> + return 0; /* Not supported */
>
> libinput_log_bug()?
>
>> + }
>> + return 0; /* Never reached */
>> +}
>> +
>> static void
>> tp_post_events(struct tp_dispatch *tp, uint64_t time)
>> {
>> @@ -626,6 +642,7 @@ tp_destroy(struct evdev_dispatch *dispatch)
>> tp_destroy_tap(tp);
>> tp_destroy_buttons(tp);
>> tp_destroy_sendevents(tp);
>> + tp_destroy_edge_scroll(tp);
>
> tp_destroy_scroll() -> tp_destroy_edge_scroll()
>
>>
>> free(tp->touches);
>> free(tp);
>> @@ -958,6 +975,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 +991,18 @@ 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));
>> + switch (tp->scroll.mode) {
>> + case LIBINPUT_CONFIG_SCROLL_NO_SCROLL:
>> + case LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN:
>> + break; /* Not supported */
>> + case LIBINPUT_CONFIG_SCROLL_2FG:
>> + evdev_stop_scroll(evdev, libinput_now(device->seat->libinput));
>> + break;
>> + case LIBINPUT_CONFIG_SCROLL_EDGE:
>> + tp_edge_scroll_stop(tp, libinput_now(device->seat->libinput));
>> + break;
>> + }
>> +
>> tp->scroll.mode = mode;
>>
>> return LIBINPUT_CONFIG_STATUS_SUCCESS;
>> @@ -989,7 +1020,13 @@ 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
>> @@ -1096,6 +1133,9 @@ tp_init(struct tp_dispatch *tp,
>> if (tp_init_scroll(tp) != 0)
>> return -1;
>>
>> + if (tp_edge_scroll_init(tp, device) != 0)
>> + return -1;
>
> tp_scroll_init() -> tp_edge_scroll_init()
>
>> +
>> device->seat_caps |= EVDEV_DEVICE_POINTER;
>>
>> return 0;
>> @@ -1239,6 +1279,7 @@ evdev_mt_touchpad_create(struct evdev_device *device)
>>
>> tp->model = tp_get_model(device);
>>
>> + device->dispatch = &tp->base;
>
> I guess this is needed for some check or another? if so, can we either pass
> in the data that's needed, or alternatively make it consistent that the
> create method sets device->dispatch for the fallback interface as well.
This is needed because the initial value for tp->scroll.mode is set
by calling tp_scroll_config_scroll_mode_get_default_mode(device).
Regards,
Hans
More information about the wayland-devel
mailing list