Change axis events to carry all directions
authorPeter Hutterer <peter.hutterer@who-t.net>
Wed, 24 Dec 2014 01:10:04 +0000 (11:10 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Tue, 13 Jan 2015 03:54:21 +0000 (13:54 +1000)
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>
12 files changed:
src/evdev-mt-touchpad-edge-scroll.c
src/evdev.c
src/libinput-private.h
src/libinput-util.h
src/libinput.c
src/libinput.h
src/libinput.sym
test/litest.c
test/pointer.c
test/touchpad.c
tools/event-debug.c
tools/event-gui.c

index a4dc093..6268986 100644 (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;
                }
        }
index d80594d..076db29 100644 (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))
-               pointer_notify_axis(&device->base,
-                                   time,
-                                   LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
-                                   source,
-                                   0);
-       if (device->scroll.direction & (1 << LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL))
+       if (device->scroll.direction != 0)
                pointer_notify_axis(&device->base,
                                    time,
-                                   LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
+                                   device->scroll.direction,
                                    source,
-                                   0);
+                                   0.0, 0.0);
 
        device->scroll.buildup_horizontal = 0;
        device->scroll.buildup_vertical = 0;
index 84a0d44..0cb9b25 100644 (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,
index dc70bcd..f76439f 100644 (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))
index 426c306..2442b06 100644 (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)
-{
-       return event->axis;
+LIBINPUT_EXPORT int
+libinput_event_pointer_has_axis(struct libinput_event_pointer *event,
+                               enum libinput_pointer_axis 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,
index f605e52..89cc0f0 100644 (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
index 826bfde..c5d9b63 100644 (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;
index 392ffe2..757f445 100644 (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);
index d12c9f6..dd9ea0d 100644 (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);
index 422e8fe..dbe16a3 100644 (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);
index 090fc3f..4d845ce 100644 (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
index 9a08d8e..4f9d7e6 100644 (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();
        }
 }