Change axis events to carry all directions

Sending separate axis events instead of one unified events is limiting,
especially when simultaneously scrolling in both directions and the caller
tries to implement kinetic scrolling.

Take a page from the tablet-support branch and instead implement the axis
event as a generic event that can contain multiple axes simultaneously.

Right now we only have two (scroll) axes and we could easily just check both
for non-zero values. If we want to allow further axes in the future, we need
a check whether an axis is set in an event, that's what
libinput_event_pointer_has_axis to scroll events() is for.

We also need the mask to notify of a scroll stop event, which could otherwise
be confused as a vertical-only or horizontal-only event.

This is an API and ABI break.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
This commit is contained in:
Peter Hutterer 2014-12-24 11:10:04 +10:00
parent c35885e87d
commit 1baf109b40
12 changed files with 133 additions and 108 deletions

View file

@ -325,9 +325,9 @@ tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time)
if (t->scroll.direction != -1) {
/* Send stop scroll event */
pointer_notify_axis(device, time,
t->scroll.direction,
AS_MASK(t->scroll.direction),
LIBINPUT_POINTER_AXIS_SOURCE_FINGER,
0.0);
0.0, 0.0);
t->scroll.direction = -1;
}
continue;
@ -349,9 +349,10 @@ tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time)
if (fabs(*delta) < t->scroll.threshold)
continue;
pointer_notify_axis(device, time, axis,
pointer_notify_axis(device, time,
AS_MASK(axis),
LIBINPUT_POINTER_AXIS_SOURCE_FINGER,
*delta);
dx, dy);
t->scroll.direction = axis;
tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_POSTED);
@ -369,9 +370,9 @@ tp_edge_scroll_stop_events(struct tp_dispatch *tp, uint64_t time)
tp_for_each_touch(tp, t) {
if (t->scroll.direction != -1) {
pointer_notify_axis(device, time,
t->scroll.direction,
AS_MASK(t->scroll.direction),
LIBINPUT_POINTER_AXIS_SOURCE_FINGER,
0.0);
0.0, 0.0);
t->scroll.direction = -1;
}
}

View file

@ -539,18 +539,20 @@ evdev_process_absolute_motion(struct evdev_device *device,
static void
evdev_notify_axis(struct evdev_device *device,
uint64_t time,
enum libinput_pointer_axis axis,
uint32_t axes,
enum libinput_pointer_axis_source source,
double value)
double x, double y)
{
if (device->scroll.natural_scrolling_enabled)
value *= -1;
if (device->scroll.natural_scrolling_enabled) {
x *= -1;
y *= -1;
}
pointer_notify_axis(&device->base,
time,
axis,
axes,
source,
value);
x, y);
}
static inline void
@ -575,8 +577,9 @@ evdev_process_relative(struct evdev_device *device,
evdev_notify_axis(
device,
time,
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
AS_MASK(LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL),
LIBINPUT_POINTER_AXIS_SOURCE_WHEEL,
0,
-1 * e->value * device->scroll.wheel_click_angle);
break;
case REL_HWHEEL:
@ -584,9 +587,10 @@ evdev_process_relative(struct evdev_device *device,
evdev_notify_axis(
device,
time,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
AS_MASK(LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL),
LIBINPUT_POINTER_AXIS_SOURCE_WHEEL,
e->value * device->scroll.wheel_click_angle);
e->value * device->scroll.wheel_click_angle,
0);
break;
}
}
@ -1796,7 +1800,7 @@ evdev_is_scrolling(const struct evdev_device *device,
assert(axis == LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL ||
axis == LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
return (device->scroll.direction & (1 << axis)) != 0;
return (device->scroll.direction & AS_MASK(axis)) != 0;
}
static inline void
@ -1806,7 +1810,7 @@ evdev_start_scrolling(struct evdev_device *device,
assert(axis == LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL ||
axis == LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
device->scroll.direction |= (1 << axis);
device->scroll.direction |= AS_MASK(axis);
}
void
@ -1857,25 +1861,20 @@ evdev_post_scroll(struct evdev_device *device,
/* We use the trigger to enable, but the delta from this event for
* the actual scroll movement. Otherwise we get a jump once
* scrolling engages */
if (dy != 0.0 &&
evdev_is_scrolling(device,
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) {
evdev_notify_axis(device,
time,
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
source,
dy);
}
if (!evdev_is_scrolling(device,
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL))
dy = 0.0;
if (!evdev_is_scrolling(device,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL))
dx = 0.0;
if (dx != 0.0 &&
evdev_is_scrolling(device,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) {
if (dx != 0.0 || dy != 0.0)
evdev_notify_axis(device,
time,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
device->scroll.direction,
source,
dx);
}
dx,
dy);
}
void
@ -1884,18 +1883,12 @@ evdev_stop_scroll(struct evdev_device *device,
enum libinput_pointer_axis_source source)
{
/* terminate scrolling with a zero scroll event */
if (device->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL))
if (device->scroll.direction != 0)
pointer_notify_axis(&device->base,
time,
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
device->scroll.direction,
source,
0);
if (device->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL))
pointer_notify_axis(&device->base,
time,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
source,
0);
0.0, 0.0);
device->scroll.buildup_horizontal = 0;
device->scroll.buildup_vertical = 0;

View file

@ -278,9 +278,9 @@ pointer_notify_button(struct libinput_device *device,
void
pointer_notify_axis(struct libinput_device *device,
uint64_t time,
enum libinput_pointer_axis axis,
uint32_t axes,
enum libinput_pointer_axis_source source,
double value);
double x, double y);
void
touch_notify_touch_down(struct libinput_device *device,

View file

@ -79,6 +79,7 @@ int list_empty(const struct list *list);
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
#define ARRAY_FOR_EACH(_arr, _elem) \
for (size_t _i = 0; _i < ARRAY_LENGTH(_arr) && (_elem = &_arr[_i]); _i++)
#define AS_MASK(v) (1 << (v))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define max(a, b) (((a) > (b)) ? (a) : (b))

View file

@ -64,9 +64,8 @@ struct libinput_event_pointer {
uint32_t button;
uint32_t seat_button_count;
enum libinput_button_state state;
enum libinput_pointer_axis axis;
enum libinput_pointer_axis_source source;
double value;
uint32_t axes;
};
struct libinput_event_touch {
@ -379,16 +378,41 @@ libinput_event_pointer_get_seat_button_count(
return event->seat_button_count;
}
LIBINPUT_EXPORT enum libinput_pointer_axis
libinput_event_pointer_get_axis(struct libinput_event_pointer *event)
LIBINPUT_EXPORT int
libinput_event_pointer_has_axis(struct libinput_event_pointer *event,
enum libinput_pointer_axis axis)
{
return event->axis;
if (event->base.type == LIBINPUT_EVENT_POINTER_AXIS) {
switch (axis) {
case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL:
case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL:
return !!(event->axes & AS_MASK(axis));
}
}
return 0;
}
LIBINPUT_EXPORT double
libinput_event_pointer_get_axis_value(struct libinput_event_pointer *event)
libinput_event_pointer_get_axis_value(struct libinput_event_pointer *event,
enum libinput_pointer_axis axis)
{
return event->value;
struct libinput *libinput = event->base.device->seat->libinput;
double value = 0;
if (!libinput_event_pointer_has_axis(event, axis)) {
log_bug_client(libinput, "value requested for unset axis\n");
} else {
switch (axis) {
case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL:
value = event->x;
break;
case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL:
value = event->y;
break;
}
}
return value;
}
LIBINPUT_EXPORT enum libinput_pointer_axis_source
@ -992,9 +1016,9 @@ pointer_notify_button(struct libinput_device *device,
void
pointer_notify_axis(struct libinput_device *device,
uint64_t time,
enum libinput_pointer_axis axis,
uint32_t axes,
enum libinput_pointer_axis_source source,
double value)
double x, double y)
{
struct libinput_event_pointer *axis_event;
@ -1004,9 +1028,10 @@ pointer_notify_axis(struct libinput_device *device,
*axis_event = (struct libinput_event_pointer) {
.time = time,
.axis = axis,
.value = value,
.x = x,
.y = y,
.source = source,
.axes = axes,
};
post_device_event(device, time,

View file

@ -653,17 +653,17 @@ libinput_event_pointer_get_seat_button_count(
/**
* @ingroup event_pointer
*
* Return the axis that triggered this event.
* For pointer events that are not of type @ref LIBINPUT_EVENT_POINTER_AXIS,
* this function returns 0.
* Check if the event has a valid value for the given axis.
*
* @note It is an application bug to call this function for events other than
* @ref LIBINPUT_EVENT_POINTER_AXIS.
* If this function returns non-zero for an axis and
* libinput_event_pointer_get_axis_value() returns a value of 0, the event
* is a scroll stop event.
*
* @return the axis triggering this event
* @return non-zero if this event contains a value for this axis
*/
enum libinput_pointer_axis
libinput_event_pointer_get_axis(struct libinput_event_pointer *event);
int
libinput_event_pointer_has_axis(struct libinput_event_pointer *event,
enum libinput_pointer_axis axis);
/**
* @ingroup event_pointer
@ -676,6 +676,9 @@ libinput_event_pointer_get_axis(struct libinput_event_pointer *event);
* respectively. For the interpretation of the value, see
* libinput_event_pointer_get_axis_source().
*
* If libinput_event_pointer_has_axis() returns 0 for an axis, this function
* returns 0 for that axis.
*
* For pointer events that are not of type @ref LIBINPUT_EVENT_POINTER_AXIS,
* this function returns 0.
*
@ -685,7 +688,8 @@ libinput_event_pointer_get_axis(struct libinput_event_pointer *event);
* @return the axis value of this event
*/
double
libinput_event_pointer_get_axis_value(struct libinput_event_pointer *event);
libinput_event_pointer_get_axis_value(struct libinput_event_pointer *event,
enum libinput_pointer_axis axis);
/**
* @ingroup event_pointer

View file

@ -82,6 +82,7 @@ global:
libinput_event_pointer_get_dy_unaccelerated;
libinput_event_pointer_get_seat_button_count;
libinput_event_pointer_get_time;
libinput_event_pointer_has_axis;
libinput_event_touch_get_base_event;
libinput_event_touch_get_seat_slot;
libinput_event_touch_get_slot;

View file

@ -983,11 +983,11 @@ litest_print_event(struct libinput_event *event)
case LIBINPUT_EVENT_POINTER_AXIS:
p = libinput_event_get_pointer_event(event);
fprintf(stderr,
"axis %s value %.2f",
libinput_event_pointer_get_axis(p) ==
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL ?
"vert" : "horiz",
libinput_event_pointer_get_axis_value(p));
"vert %.f horiz %.2f",
libinput_event_pointer_get_axis_value(p,
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL),
libinput_event_pointer_get_axis_value(p,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL));
break;
default:
break;
@ -1198,23 +1198,24 @@ litest_assert_scroll(struct libinput *li,
LIBINPUT_EVENT_POINTER_AXIS);
ptrev = libinput_event_get_pointer_event(event);
ck_assert(ptrev != NULL);
ck_assert_int_eq(libinput_event_pointer_get_axis(ptrev), axis);
if (next_event) {
/* Normal scroll event, check dir */
if (minimum_movement > 0) {
ck_assert_int_ge(
libinput_event_pointer_get_axis_value(ptrev),
libinput_event_pointer_get_axis_value(ptrev,
axis),
minimum_movement);
} else {
ck_assert_int_le(
libinput_event_pointer_get_axis_value(ptrev),
libinput_event_pointer_get_axis_value(ptrev,
axis),
minimum_movement);
}
} else {
/* Last scroll event, must be 0 */
ck_assert_int_eq(
libinput_event_pointer_get_axis_value(ptrev),
libinput_event_pointer_get_axis_value(ptrev, axis),
0);
}
libinput_event_destroy(event);

View file

@ -348,6 +348,7 @@ test_wheel_event(struct litest_device *dev, int which, int amount)
struct libinput *li = dev->libinput;
struct libinput_event *event;
struct libinput_event_pointer *ptrev;
enum libinput_pointer_axis axis;
/* the current evdev implementation scales the scroll wheel events
up by a factor 15 */
@ -372,11 +373,13 @@ test_wheel_event(struct litest_device *dev, int which, int amount)
ptrev = libinput_event_get_pointer_event(event);
ck_assert(ptrev != NULL);
ck_assert_int_eq(libinput_event_pointer_get_axis(ptrev),
which == REL_WHEEL ?
axis = (which == REL_WHEEL) ?
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL :
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
ck_assert_int_eq(libinput_event_pointer_get_axis_value(ptrev), expected);
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL;
ck_assert_int_eq(libinput_event_pointer_get_axis_value(ptrev, axis),
expected);
ck_assert_int_eq(libinput_event_pointer_get_axis_source(ptrev),
LIBINPUT_POINTER_AXIS_SOURCE_WHEEL);
libinput_event_destroy(event);

View file

@ -1439,18 +1439,19 @@ START_TEST(touchpad_2fg_scroll_slow_distance)
/* last event is value 0, tested elsewhere */
while (libinput_next_event_type(li) != LIBINPUT_EVENT_NONE) {
double axisval;
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_POINTER_AXIS);
ptrev = libinput_event_get_pointer_event(event);
ck_assert_int_eq(libinput_event_pointer_get_axis(ptrev),
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
ck_assert(libinput_event_pointer_get_axis_value(ptrev) > 0.0);
axisval = libinput_event_pointer_get_axis_value(ptrev,
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
ck_assert(axisval > 0.0);
/* this is to verify we test the right thing, if the value
is greater than scroll.threshold we triggered the wrong
condition */
ck_assert(libinput_event_pointer_get_axis_value(ptrev) < 5.0);
ck_assert(axisval < 5.0);
libinput_event_destroy(event);
event = libinput_get_event(li);
@ -1627,18 +1628,19 @@ START_TEST(touchpad_edge_scroll_slow_distance)
ck_assert_notnull(event);
while (libinput_next_event_type(li) != LIBINPUT_EVENT_NONE) {
double axisval;
ck_assert_int_eq(libinput_event_get_type(event),
LIBINPUT_EVENT_POINTER_AXIS);
ptrev = libinput_event_get_pointer_event(event);
ck_assert_int_eq(libinput_event_pointer_get_axis(ptrev),
axisval = libinput_event_pointer_get_axis_value(ptrev,
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
ck_assert(libinput_event_pointer_get_axis_value(ptrev) > 0.0);
ck_assert(axisval > 0.0);
/* this is to verify we test the right thing, if the value
is greater than scroll.threshold we triggered the wrong
condition */
ck_assert(libinput_event_pointer_get_axis_value(ptrev) < 5.0);
ck_assert(axisval < 5.0);
libinput_event_destroy(event);
event = libinput_get_event(li);

View file

@ -225,24 +225,18 @@ static void
print_axis_event(struct libinput_event *ev)
{
struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
enum libinput_pointer_axis axis = libinput_event_pointer_get_axis(p);
const char *ax;
double val;
switch (axis) {
case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL:
ax = "vscroll";
break;
case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL:
ax = "hscroll";
break;
default:
abort();
}
double v = 0, h = 0;
if (libinput_event_pointer_has_axis(p,
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL))
v = libinput_event_pointer_get_axis_value(p,
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
if (libinput_event_pointer_has_axis(p,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL))
h = libinput_event_pointer_get_axis_value(p,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
print_event_time(libinput_event_pointer_get_time(p));
val = libinput_event_pointer_get_axis_value(p);
printf("%s %.2f\n", ax, val);
printf("vert %.2f horiz %.2f\n", v, h);
}
static void

View file

@ -358,20 +358,20 @@ static void
handle_event_axis(struct libinput_event *ev, struct window *w)
{
struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
enum libinput_pointer_axis axis = libinput_event_pointer_get_axis(p);
double v = libinput_event_pointer_get_axis_value(p);
double v, h;
switch (axis) {
case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL:
v = libinput_event_pointer_get_axis_value(p,
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
h = libinput_event_pointer_get_axis_value(p,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
if (v != 0.0) {
w->vy += (int)v;
w->vy = clip(w->vy, 0, w->height);
break;
case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL:
}
if (h != 0.0) {
w->hx += (int)v;
w->hx = clip(w->hx, 0, w->width);
break;
default:
abort();
}
}