diff --git a/doc/device-configuration-via-udev.dox b/doc/device-configuration-via-udev.dox
index 4107f943..fc1c0af8 100644
--- a/doc/device-configuration-via-udev.dox
+++ b/doc/device-configuration-via-udev.dox
@@ -11,7 +11,22 @@ The following udev properties are supported:
LIBINPUT_CALIBRATION_MATRIX
Sets the calibration matrix, see
libinput_device_config_calibration_get_default_matrix(). If unset,
-defaults to the identity matrix.
+defaults to the identity matrix.
+
+The udev property is parsed as 6 floating point numbers separated by a
+single space each (scanf(3) format "%f %f %f %f %f %f").
+The 6 values represent the first two rows of the calibration matrix as
+described in libinput_device_config_calibration_set_matrix().
+
+Example values are:
+@code
+ ENV{LIBINPUT_CALIBRATION_MATRIX}="1 0 0 0 1 0" # default
+ ENV{LIBINPUT_CALIBRATION_MATRIX}="0 -1 1 1 0 0" # 90 degree clockwise
+ ENV{LIBINPUT_CALIBRATION_MATRIX}="-1 0 1 0 -1 1" # 180 degree clockwise
+ ENV{LIBINPUT_CALIBRATION_MATRIX}="0 1 0 -1 0 1" # 270 degree clockwise
+ ENV{LIBINPUT_CALIBRATION_MATRIX}="-1 0 1 1 0 0" # reflect along y axis
+@endcode
+
LIBINPUT_DEVICE_GROUP
A string identifying the @ref libinput_device_group for this device. Two
devices with the same property value are grouped into the same device group,
diff --git a/src/Makefile.am b/src/Makefile.am
index e807e236..d5cd4f41 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -17,6 +17,7 @@ libinput_la_SOURCES = \
evdev-mt-touchpad-tap.c \
evdev-mt-touchpad-buttons.c \
evdev-mt-touchpad-edge-scroll.c \
+ evdev-mt-touchpad-gestures.c \
filter.c \
filter.h \
filter-private.h \
diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c
index 9dbb5137..12f80234 100644
--- a/src/evdev-mt-touchpad-buttons.c
+++ b/src/evdev-mt-touchpad-buttons.c
@@ -156,7 +156,6 @@ tp_button_set_state(struct tp_dispatch *tp, struct tp_touch *t,
break;
case BUTTON_STATE_AREA:
t->button.curr = BUTTON_EVENT_IN_AREA;
- tp_set_pointer(tp, t);
break;
case BUTTON_STATE_BOTTOM:
t->button.curr = event;
diff --git a/src/evdev-mt-touchpad-edge-scroll.c b/src/evdev-mt-touchpad-edge-scroll.c
index 8d0a13e3..28f29c2f 100644
--- a/src/evdev-mt-touchpad-edge-scroll.c
+++ b/src/evdev-mt-touchpad-edge-scroll.c
@@ -86,7 +86,6 @@ tp_edge_scroll_set_state(struct tp_dispatch *tp,
break;
case EDGE_SCROLL_TOUCH_STATE_AREA:
t->scroll.edge = EDGE_NONE;
- tp_set_pointer(tp, t);
break;
}
}
@@ -317,6 +316,9 @@ tp_edge_scroll_post_events(struct tp_dispatch *tp, uint64_t time)
enum libinput_pointer_axis axis;
double dx, dy, *delta;
+ if (tp->scroll.method != LIBINPUT_CONFIG_SCROLL_EDGE)
+ return 0;
+
tp_for_each_touch(tp, t) {
if (!t->dirty)
continue;
diff --git a/src/evdev-mt-touchpad-gestures.c b/src/evdev-mt-touchpad-gestures.c
new file mode 100644
index 00000000..c1ed1c26
--- /dev/null
+++ b/src/evdev-mt-touchpad-gestures.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright © 2015 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 "config.h"
+
+#include
+#include
+#include
+#include
+
+#include "evdev-mt-touchpad.h"
+
+#define DEFAULT_GESTURE_SWITCH_TIMEOUT 100 /* ms */
+
+static void
+tp_get_touches_delta(struct tp_dispatch *tp, double *dx, double *dy, bool average)
+{
+ struct tp_touch *t;
+ unsigned int i, nchanged = 0;
+ double tmpx, tmpy;
+
+ *dx = 0.0;
+ *dy = 0.0;
+
+ for (i = 0; i < tp->real_touches; i++) {
+ t = &tp->touches[i];
+
+ if (tp_touch_active(tp, t) && t->dirty) {
+ nchanged++;
+ tp_get_delta(t, &tmpx, &tmpy);
+
+ *dx += tmpx;
+ *dy += tmpy;
+ }
+ }
+
+ if (!average || nchanged == 0)
+ return;
+
+ *dx /= nchanged;
+ *dy /= nchanged;
+}
+
+static inline void
+tp_get_combined_touches_delta(struct tp_dispatch *tp, double *dx, double *dy)
+{
+ tp_get_touches_delta(tp, dx, dy, false);
+}
+
+static inline void
+tp_get_average_touches_delta(struct tp_dispatch *tp, double *dx, double *dy)
+{
+ tp_get_touches_delta(tp, dx, dy, true);
+}
+
+static void
+tp_gesture_start(struct tp_dispatch *tp, uint64_t time)
+{
+ if (tp->gesture.started)
+ return;
+
+ switch (tp->gesture.finger_count) {
+ case 2:
+ /* NOP */
+ break;
+ }
+ tp->gesture.started = true;
+}
+
+static void
+tp_gesture_post_pointer_motion(struct tp_dispatch *tp, uint64_t time)
+{
+ double dx = 0.0, dy = 0.0;
+ double dx_unaccel, dy_unaccel;
+
+ /* When a clickpad is clicked, combine motion of all active touches */
+ if (tp->buttons.is_clickpad && tp->buttons.state)
+ tp_get_combined_touches_delta(tp, &dx, &dy);
+ else
+ tp_get_average_touches_delta(tp, &dx, &dy);
+
+ tp_filter_motion(tp, &dx, &dy, &dx_unaccel, &dy_unaccel, time);
+
+ if (dx != 0.0 || dy != 0.0 || dx_unaccel != 0.0 || dy_unaccel != 0.0) {
+ pointer_notify_motion(&tp->device->base, time,
+ dx, dy, dx_unaccel, dy_unaccel);
+ }
+}
+
+static void
+tp_gesture_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time)
+{
+ double dx = 0, dy =0;
+
+ tp_get_average_touches_delta(tp, &dx, &dy);
+ tp_filter_motion(tp, &dx, &dy, NULL, NULL, time);
+
+ if (dx == 0.0 && dy == 0.0)
+ return;
+
+ tp_gesture_start(tp, time);
+ evdev_post_scroll(tp->device,
+ time,
+ LIBINPUT_POINTER_AXIS_SOURCE_FINGER,
+ dx, dy);
+}
+
+void
+tp_gesture_post_events(struct tp_dispatch *tp, uint64_t time)
+{
+ if (tp->gesture.finger_count == 0)
+ return;
+
+ /* When tap-and-dragging, or a clickpad is clicked force 1fg mode */
+ if (tp_tap_dragging(tp) || (tp->buttons.is_clickpad && tp->buttons.state)) {
+ tp_gesture_stop(tp, time);
+ tp->gesture.finger_count = 1;
+ tp->gesture.finger_count_pending = 0;
+ }
+
+ /* Don't send events when we're unsure in which mode we are */
+ if (tp->gesture.finger_count_pending)
+ return;
+
+ switch (tp->gesture.finger_count) {
+ case 1:
+ tp_gesture_post_pointer_motion(tp, time);
+ break;
+ case 2:
+ tp_gesture_post_twofinger_scroll(tp, time);
+ break;
+ }
+}
+
+void
+tp_gesture_stop_twofinger_scroll(struct tp_dispatch *tp, uint64_t time)
+{
+ evdev_stop_scroll(tp->device,
+ time,
+ LIBINPUT_POINTER_AXIS_SOURCE_FINGER);
+}
+
+void
+tp_gesture_stop(struct tp_dispatch *tp, uint64_t time)
+{
+ if (!tp->gesture.started)
+ return;
+
+ switch (tp->gesture.finger_count) {
+ case 2:
+ tp_gesture_stop_twofinger_scroll(tp, time);
+ break;
+ }
+ tp->gesture.started = false;
+}
+
+static void
+tp_gesture_finger_count_switch_timeout(uint64_t now, void *data)
+{
+ struct tp_dispatch *tp = data;
+
+ if (!tp->gesture.finger_count_pending)
+ return;
+
+ tp_gesture_stop(tp, now); /* End current gesture */
+ tp->gesture.finger_count = tp->gesture.finger_count_pending;
+ tp->gesture.finger_count_pending = 0;
+}
+
+void
+tp_gesture_handle_state(struct tp_dispatch *tp, uint64_t time)
+{
+ unsigned int active_touches = 0;
+ struct tp_touch *t;
+
+ tp_for_each_touch(tp, t)
+ if (tp_touch_active(tp, t))
+ active_touches++;
+
+ if (active_touches != tp->gesture.finger_count) {
+ /* If all fingers are lifted immediately end the gesture */
+ if (active_touches == 0) {
+ tp_gesture_stop(tp, time);
+ tp->gesture.finger_count = 0;
+ tp->gesture.finger_count_pending = 0;
+ /* Immediately switch to new mode to avoid initial latency */
+ } else if (!tp->gesture.started) {
+ tp->gesture.finger_count = active_touches;
+ tp->gesture.finger_count_pending = 0;
+ /* Else debounce finger changes */
+ } else if (active_touches != tp->gesture.finger_count_pending) {
+ tp->gesture.finger_count_pending = active_touches;
+ libinput_timer_set(&tp->gesture.finger_count_switch_timer,
+ time + DEFAULT_GESTURE_SWITCH_TIMEOUT);
+ }
+ } else {
+ tp->gesture.finger_count_pending = 0;
+ }
+}
+
+int
+tp_init_gesture(struct tp_dispatch *tp)
+{
+ libinput_timer_init(&tp->gesture.finger_count_switch_timer,
+ tp->device->base.seat->libinput,
+ tp_gesture_finger_count_switch_timeout, tp);
+ return 0;
+}
+
+void
+tp_remove_gesture(struct tp_dispatch *tp)
+{
+ libinput_timer_cancel(&tp->gesture.finger_count_switch_timer);
+}
diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index e0b0c364..b90d84c5 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -227,7 +227,6 @@ tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
}
t->dirty = true;
- t->is_pointer = false;
t->palm.is_palm = false;
t->state = TOUCH_END;
t->pinned.is_pinned = false;
@@ -424,7 +423,6 @@ tp_unpin_finger(struct tp_dispatch *tp, struct tp_touch *t)
if (xdist * xdist + ydist * ydist >=
tp->buttons.motion_dist * tp->buttons.motion_dist) {
t->pinned.is_pinned = false;
- tp_set_pointer(tp, t);
return;
}
@@ -439,14 +437,13 @@ tp_pin_fingers(struct tp_dispatch *tp)
struct tp_touch *t;
tp_for_each_touch(tp, t) {
- t->is_pointer = false;
t->pinned.is_pinned = true;
t->pinned.center_x = t->x;
t->pinned.center_y = t->y;
}
}
-static int
+int
tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
{
return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) &&
@@ -456,21 +453,6 @@ tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
tp_edge_scroll_touch_active(tp, t);
}
-void
-tp_set_pointer(struct tp_dispatch *tp, struct tp_touch *t)
-{
- struct tp_touch *tmp = NULL;
-
- /* Only set the touch as pointer if we don't have one yet */
- tp_for_each_touch(tp, tmp) {
- if (tmp->is_pointer)
- return;
- }
-
- if (tp_touch_active(tp, t))
- t->is_pointer = true;
-}
-
static void
tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
{
@@ -487,7 +469,6 @@ tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
int dirs = vector_get_direction(t->x - t->palm.x, t->y - t->palm.y);
if ((dirs & DIRECTIONS) && !(dirs & ~DIRECTIONS)) {
t->palm.is_palm = false;
- tp_set_pointer(tp, t);
}
}
return;
@@ -512,153 +493,6 @@ tp_palm_detect(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
t->palm.y = t->y;
}
-static void
-tp_post_twofinger_scroll(struct tp_dispatch *tp, uint64_t time)
-{
- struct tp_touch *t;
- int nchanged = 0;
- double dx = 0, dy =0;
- double tmpx, tmpy;
-
- tp_for_each_touch(tp, t) {
- if (tp_touch_active(tp, t) && t->dirty) {
- nchanged++;
- tp_get_delta(t, &tmpx, &tmpy);
-
- dx += tmpx;
- dy += tmpy;
- }
- /* Stop spurious MOTION events at the end of scrolling */
- t->is_pointer = false;
- }
-
- if (nchanged == 0)
- return;
-
- dx /= nchanged;
- dy /= nchanged;
-
- tp_filter_motion(tp, &dx, &dy, NULL, NULL, time);
-
- evdev_post_scroll(tp->device,
- time,
- LIBINPUT_POINTER_AXIS_SOURCE_FINGER,
- dx, dy);
- tp->scroll.twofinger_state = TWOFINGER_SCROLL_STATE_ACTIVE;
-}
-
-static void
-tp_twofinger_stop_scroll(struct tp_dispatch *tp, uint64_t time)
-{
- struct tp_touch *t, *ptr = NULL;
- int nfingers_down = 0;
-
- evdev_stop_scroll(tp->device,
- time,
- LIBINPUT_POINTER_AXIS_SOURCE_FINGER);
-
- /* If we were scrolling and now there's exactly 1 active finger,
- switch back to pointer movement */
- if (tp->scroll.twofinger_state == TWOFINGER_SCROLL_STATE_ACTIVE) {
- tp_for_each_touch(tp, t) {
- if (tp_touch_active(tp, t)) {
- nfingers_down++;
- if (ptr == NULL)
- ptr = t;
- }
- }
-
- if (nfingers_down == 1)
- tp_set_pointer(tp, ptr);
- }
-
- tp->scroll.twofinger_state = TWOFINGER_SCROLL_STATE_NONE;
-}
-
-static int
-tp_twofinger_scroll_post_events(struct tp_dispatch *tp, uint64_t time)
-{
- struct tp_touch *t;
- int nfingers_down = 0;
-
- /* No 2fg scrolling during tap-n-drag */
- if (tp_tap_dragging(tp))
- return 0;
-
- /* No 2fg scrolling while a clickpad is clicked */
- if (tp->buttons.is_clickpad && tp->buttons.state)
- return 0;
-
- /* Only count active touches for 2 finger scrolling */
- tp_for_each_touch(tp, t) {
- if (tp_touch_active(tp, t))
- nfingers_down++;
- }
-
- if (nfingers_down == 2) {
- tp_post_twofinger_scroll(tp, time);
- return 1;
- }
-
- tp_twofinger_stop_scroll(tp, time);
-
- return 0;
-}
-
-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.method) {
- 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.method) {
- case LIBINPUT_CONFIG_SCROLL_NO_SCROLL:
- break;
- case LIBINPUT_CONFIG_SCROLL_2FG:
- tp_twofinger_stop_scroll(tp, 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_remove_scroll(struct tp_dispatch *tp)
-{
- tp_remove_edge_scroll(tp);
-}
-
static void
tp_unhover_touches(struct tp_dispatch *tp, uint64_t time)
{
@@ -749,7 +583,7 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
}
tp_button_handle_state(tp, time);
- tp_scroll_handle_state(tp, time);
+ tp_edge_scroll_handle_state(tp, time);
/*
* We have a physical button down event on a clickpad. To avoid
@@ -760,6 +594,8 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
if ((tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS) &&
tp->buttons.is_clickpad)
tp_pin_fingers(tp);
+
+ tp_gesture_handle_state(tp, time);
}
static void
@@ -790,63 +626,6 @@ tp_post_process_state(struct tp_dispatch *tp, uint64_t time)
tp->queued = TOUCHPAD_EVENT_NONE;
}
-static void
-tp_get_pointer_delta(struct tp_dispatch *tp, double *dx, double *dy)
-{
- struct tp_touch *t = tp_current_touch(tp);
-
- if (!t->is_pointer) {
- tp_for_each_touch(tp, t) {
- if (t->is_pointer)
- break;
- }
- }
-
- if (!t->is_pointer || !t->dirty)
- return;
-
- tp_get_delta(t, dx, dy);
-}
-
-static void
-tp_get_active_touches_delta(struct tp_dispatch *tp, double *dx, double *dy)
-{
- struct tp_touch *t;
- double tdx, tdy;
- unsigned int i;
-
- for (i = 0; i < tp->real_touches; i++) {
- t = tp_get_touch(tp, i);
-
- if (!tp_touch_active(tp, t) || !t->dirty)
- continue;
-
- tp_get_delta(t, &tdx, &tdy);
- *dx += tdx;
- *dy += tdy;
- }
-}
-
-static void
-tp_post_pointer_motion(struct tp_dispatch *tp, uint64_t time)
-{
- double dx = 0.0, dy = 0.0;
- double dx_unaccel, dy_unaccel;
-
- /* When a clickpad is clicked, combine motion of all active touches */
- if (tp->buttons.is_clickpad && tp->buttons.state)
- tp_get_active_touches_delta(tp, &dx, &dy);
- else
- tp_get_pointer_delta(tp, &dx, &dy);
-
- tp_filter_motion(tp, &dx, &dy, &dx_unaccel, &dy_unaccel, time);
-
- if (dx != 0.0 || dy != 0.0 || dx_unaccel != 0.0 || dy_unaccel != 0.0) {
- pointer_notify_motion(&tp->device->base, time,
- dx, dy, dx_unaccel, dy_unaccel);
- }
-}
-
static void
tp_post_events(struct tp_dispatch *tp, uint64_t time)
{
@@ -862,14 +641,15 @@ 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) {
- tp_stop_scroll_events(tp, time);
+ tp_edge_scroll_stop_events(tp, time);
+ tp_gesture_stop(tp, time);
return;
}
- if (tp_post_scroll_events(tp, time) != 0)
+ if (tp_edge_scroll_post_events(tp, time) != 0)
return;
- tp_post_pointer_motion(tp, time);
+ tp_gesture_post_events(tp, time);
}
static void
@@ -925,7 +705,8 @@ tp_remove(struct evdev_dispatch *dispatch)
tp_remove_tap(tp);
tp_remove_buttons(tp);
tp_remove_sendevents(tp);
- tp_remove_scroll(tp);
+ tp_remove_edge_scroll(tp);
+ tp_remove_gesture(tp);
}
static void
@@ -1017,9 +798,8 @@ tp_trackpoint_event(uint64_t time, struct libinput_event *event, void *data)
return;
if (!tp->sendevents.trackpoint_active) {
- evdev_stop_scroll(tp->device,
- time,
- LIBINPUT_POINTER_AXIS_SOURCE_FINGER);
+ tp_edge_scroll_stop_events(tp, time);
+ tp_gesture_stop(tp, time);
tp_tap_suspend(tp, time);
tp->sendevents.trackpoint_active = true;
}
@@ -1254,11 +1034,14 @@ tp_scroll_config_scroll_method_set_method(struct libinput_device *device,
{
struct evdev_device *evdev = (struct evdev_device*)device;
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
+ uint64_t time = libinput_now(device->seat->libinput);
if (method == tp->scroll.method)
return LIBINPUT_CONFIG_STATUS_SUCCESS;
- tp_stop_scroll_events(tp, libinput_now(device->seat->libinput));
+ tp_edge_scroll_stop_events(tp, time);
+ tp_gesture_stop_twofinger_scroll(tp, time);
+
tp->scroll.method = method;
return LIBINPUT_CONFIG_STATUS_SUCCESS;
@@ -1395,6 +1178,9 @@ tp_init(struct tp_dispatch *tp,
if (tp_init_scroll(tp, device) != 0)
return -1;
+ if (tp_init_gesture(tp) != 0)
+ return -1;
+
device->seat_caps |= EVDEV_DEVICE_POINTER;
return 0;
diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
index d552c26d..f04cc112 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -117,11 +117,6 @@ enum tp_edge_scroll_touch_state {
EDGE_SCROLL_TOUCH_STATE_AREA,
};
-enum tp_twofinger_scroll_state {
- TWOFINGER_SCROLL_STATE_NONE,
- TWOFINGER_SCROLL_STATE_ACTIVE,
-};
-
struct tp_motion {
int32_t x;
int32_t y;
@@ -132,7 +127,6 @@ struct tp_touch {
enum touch_state state;
bool has_ended; /* TRACKING_ID == -1 */
bool dirty;
- bool is_pointer; /* the pointer-controlling touch */
int32_t x;
int32_t y;
uint64_t millis;
@@ -215,6 +209,13 @@ struct tp_dispatch {
double y_scale_coeff;
} accel;
+ struct {
+ bool started;
+ unsigned int finger_count;
+ unsigned int finger_count_pending;
+ struct libinput_timer finger_count_switch_timer;
+ } gesture;
+
struct {
bool is_clickpad; /* true for clickpads */
bool has_topbuttons;
@@ -252,7 +253,6 @@ struct tp_dispatch {
enum libinput_config_scroll_method method;
int32_t right_edge;
int32_t bottom_edge;
- enum tp_twofinger_scroll_state twofinger_state;
} scroll;
enum touchpad_event queued;
@@ -286,15 +286,15 @@ struct tp_dispatch {
void
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,
double *dx_unaccel, double *dy_unaccel,
uint64_t time);
+int
+tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t);
+
int
tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time);
@@ -367,4 +367,22 @@ 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);
+int
+tp_init_gesture(struct tp_dispatch *tp);
+
+void
+tp_remove_gesture(struct tp_dispatch *tp);
+
+void
+tp_gesture_stop(struct tp_dispatch *tp, uint64_t time);
+
+void
+tp_gesture_handle_state(struct tp_dispatch *tp, uint64_t time);
+
+void
+tp_gesture_post_events(struct tp_dispatch *tp, uint64_t time);
+
+void
+tp_gesture_stop_twofinger_scroll(struct tp_dispatch *tp, uint64_t time);
+
#endif
diff --git a/src/evdev.c b/src/evdev.c
index bbc3dce5..b90ea7c7 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -58,6 +58,7 @@ enum evdev_device_udev_tags {
EVDEV_UDEV_TAG_TABLET = (1 << 5),
EVDEV_UDEV_TAG_JOYSTICK = (1 << 6),
EVDEV_UDEV_TAG_ACCELEROMETER = (1 << 7),
+ EVDEV_UDEV_TAG_BUTTONSET = (1 << 8),
};
struct evdev_udev_tag_match {
@@ -73,6 +74,7 @@ static const struct evdev_udev_tag_match evdev_udev_tag_matches[] = {
{"ID_INPUT_TOUCHPAD", EVDEV_UDEV_TAG_TOUCHPAD},
{"ID_INPUT_TOUCHSCREEN", EVDEV_UDEV_TAG_TOUCHSCREEN},
{"ID_INPUT_TABLET", EVDEV_UDEV_TAG_TABLET},
+ {"ID_INPUT_TABLET_PAD", EVDEV_UDEV_TAG_BUTTONSET},
{"ID_INPUT_JOYSTICK", EVDEV_UDEV_TAG_JOYSTICK},
{"ID_INPUT_ACCELEROMETER", EVDEV_UDEV_TAG_ACCELEROMETER},
@@ -524,6 +526,14 @@ evdev_process_touch(struct evdev_device *device,
{
switch (e->code) {
case ABS_MT_SLOT:
+ if ((size_t)e->value >= device->mt.slots_len) {
+ log_bug_libinput(device->base.seat->libinput,
+ "%s exceeds slots (%d of %d)\n",
+ device->devname,
+ e->value,
+ device->mt.slots_len);
+ e->value = device->mt.slots_len - 1;
+ }
evdev_flush_pending_event(device, time);
device->mt.slot = e->value;
break;
@@ -1400,7 +1410,7 @@ evdev_configure_device(struct evdev_device *device)
}
log_info(libinput,
- "input device '%s', %s is tagged by udev as:%s%s%s%s%s%s%s\n",
+ "input device '%s', %s is tagged by udev as:%s%s%s%s%s%s%s%s\n",
device->devname, devnode,
udev_tags & EVDEV_UDEV_TAG_KEYBOARD ? " Keyboard" : "",
udev_tags & EVDEV_UDEV_TAG_MOUSE ? " Mouse" : "",
@@ -1408,7 +1418,8 @@ evdev_configure_device(struct evdev_device *device)
udev_tags & EVDEV_UDEV_TAG_TOUCHSCREEN ? " Touchscreen" : "",
udev_tags & EVDEV_UDEV_TAG_TABLET ? " Tablet" : "",
udev_tags & EVDEV_UDEV_TAG_JOYSTICK ? " Joystick" : "",
- udev_tags & EVDEV_UDEV_TAG_ACCELEROMETER ? " Accelerometer" : "");
+ udev_tags & EVDEV_UDEV_TAG_ACCELEROMETER ? " Accelerometer" : "",
+ udev_tags & EVDEV_UDEV_TAG_BUTTONSET ? " Buttonset" : "");
/* libwacom *adds* TABLET, TOUCHPAD but leaves JOYSTICK in place, so
make sure we only ignore real joystick devices */
@@ -1419,6 +1430,14 @@ evdev_configure_device(struct evdev_device *device)
return -1;
}
+ /* libwacom assigns tablet _and_ tablet_pad to the pad devices */
+ if (udev_tags & EVDEV_UDEV_TAG_BUTTONSET) {
+ log_info(libinput,
+ "input device '%s', %s is a buttonset, ignoring\n",
+ device->devname, devnode);
+ return -1;
+ }
+
if (libevdev_has_event_type(evdev, EV_ABS)) {
if ((absinfo = libevdev_get_abs_info(evdev, ABS_X))) {
@@ -1467,10 +1486,9 @@ evdev_configure_device(struct evdev_device *device)
if (!device->mtdev)
return -1;
- num_slots = device->mtdev->caps.slot.maximum;
- if (device->mtdev->caps.slot.minimum < 0 ||
- num_slots <= 0)
- return -1;
+ /* pick 10 slots as default for type A
+ devices. */
+ num_slots = 10;
active_slot = device->mtdev->caps.slot.value;
} else {
num_slots = libevdev_get_num_slots(device->evdev);
diff --git a/src/libinput.h b/src/libinput.h
index 17be1797..06207fd7 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -48,8 +48,7 @@ enum libinput_log_priority {
* @ingroup device
*
* Capabilities on a device. A device may have one or more capabilities
- * at a time, and capabilities may appear or disappear during the
- * lifetime of the device.
+ * at a time, capabilities remain static for the lifetime of the device.
*/
enum libinput_device_capability {
LIBINPUT_DEVICE_CAP_KEYBOARD = 0,
@@ -94,7 +93,8 @@ enum libinput_button_state {
/**
* @ingroup device
*
- * Axes on a device that are not x or y coordinates.
+ * Axes on a device with the capability @ref LIBINPUT_DEVICE_CAP_POINTER
+ * that are not x or y coordinates.
*
* The two scroll axes @ref LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL and
* @ref LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL are engaged separately,
@@ -411,9 +411,9 @@ libinput_event_get_context(struct libinput_event *event);
/**
* @ingroup event
*
- * Return the device associated with this event, if applicable. For device
- * added/removed events this is the device added or removed. For all other
- * device events, this is the device that generated the event.
+ * Return the device associated with this event. For device added/removed
+ * events this is the device added or removed. For all other device events,
+ * this is the device that generated the event.
*
* This device is not refcounted and its lifetime is that of the event. Use
* libinput_device_ref() before using the device outside of this scope.
@@ -544,10 +544,10 @@ libinput_event_keyboard_get_base_event(struct libinput_event_keyboard *event);
* of keys pressed on all devices on the associated seat after the event was
* triggered.
*
- " @note It is an application bug to call this function for events other than
+ * @note It is an application bug to call this function for events other than
* @ref LIBINPUT_EVENT_KEYBOARD_KEY. For other events, this function returns 0.
*
- * @return the seat wide pressed key count for the key of this event
+ * @return The seat wide pressed key count for the key of this event
*/
uint32_t
libinput_event_keyboard_get_seat_key_count(
@@ -584,7 +584,7 @@ libinput_event_pointer_get_time(struct libinput_event_pointer *event);
* @note It is an application bug to call this function for events other than
* @ref LIBINPUT_EVENT_POINTER_MOTION.
*
- * @return the relative x movement since the last event
+ * @return The relative x movement since the last event
*/
double
libinput_event_pointer_get_dx(struct libinput_event_pointer *event);
@@ -605,7 +605,7 @@ libinput_event_pointer_get_dx(struct libinput_event_pointer *event);
* @note It is an application bug to call this function for events other than
* @ref LIBINPUT_EVENT_POINTER_MOTION.
*
- * @return the relative y movement since the last event
+ * @return The relative y movement since the last event
*/
double
libinput_event_pointer_get_dy(struct libinput_event_pointer *event);
@@ -625,7 +625,7 @@ libinput_event_pointer_get_dy(struct libinput_event_pointer *event);
* @note It is an application bug to call this function for events other than
* @ref LIBINPUT_EVENT_POINTER_MOTION.
*
- * @return the unaccelerated relative x movement since the last event
+ * @return The unaccelerated relative x movement since the last event
*/
double
libinput_event_pointer_get_dx_unaccelerated(
@@ -646,7 +646,7 @@ libinput_event_pointer_get_dx_unaccelerated(
* @note It is an application bug to call this function for events other than
* @ref LIBINPUT_EVENT_POINTER_MOTION.
*
- * @return the unaccelerated relative y movement since the last event
+ * @return The unaccelerated relative y movement since the last event
*/
double
libinput_event_pointer_get_dy_unaccelerated(
@@ -665,7 +665,7 @@ libinput_event_pointer_get_dy_unaccelerated(
* @note It is an application bug to call this function for events other than
* @ref LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE.
*
- * @return the current absolute x coordinate
+ * @return The current absolute x coordinate
*/
double
libinput_event_pointer_get_absolute_x(struct libinput_event_pointer *event);
@@ -683,7 +683,7 @@ libinput_event_pointer_get_absolute_x(struct libinput_event_pointer *event);
* @note It is an application bug to call this function for events other than
* @ref LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE.
*
- * @return the current absolute y coordinate
+ * @return The current absolute y coordinate
*/
double
libinput_event_pointer_get_absolute_y(struct libinput_event_pointer *event);
@@ -703,7 +703,7 @@ libinput_event_pointer_get_absolute_y(struct libinput_event_pointer *event);
*
* @param event The libinput pointer event
* @param width The current output screen width
- * @return the current absolute x coordinate transformed to a screen coordinate
+ * @return The current absolute x coordinate transformed to a screen coordinate
*/
double
libinput_event_pointer_get_absolute_x_transformed(
@@ -725,7 +725,7 @@ libinput_event_pointer_get_absolute_x_transformed(
*
* @param event The libinput pointer event
* @param height The current output screen height
- * @return the current absolute y coordinate transformed to a screen coordinate
+ * @return The current absolute y coordinate transformed to a screen coordinate
*/
double
libinput_event_pointer_get_absolute_y_transformed(
@@ -742,7 +742,7 @@ libinput_event_pointer_get_absolute_y_transformed(
* @note It is an application bug to call this function for events other than
* @ref LIBINPUT_EVENT_POINTER_BUTTON.
*
- * @return the button triggering this event
+ * @return The button triggering this event
*/
uint32_t
libinput_event_pointer_get_button(struct libinput_event_pointer *event);
@@ -757,7 +757,7 @@ libinput_event_pointer_get_button(struct libinput_event_pointer *event);
* @note It is an application bug to call this function for events other than
* @ref LIBINPUT_EVENT_POINTER_BUTTON.
*
- * @return the button state triggering this event
+ * @return The button state triggering this event
*/
enum libinput_button_state
libinput_event_pointer_get_button_state(struct libinput_event_pointer *event);
@@ -769,11 +769,11 @@ libinput_event_pointer_get_button_state(struct libinput_event_pointer *event);
* total number of buttons pressed on all devices on the associated seat
* after the event was triggered.
*
- " @note It is an application bug to call this function for events other than
+ * @note It is an application bug to call this function for events other than
* @ref LIBINPUT_EVENT_POINTER_BUTTON. For other events, this function
* returns 0.
*
- * @return the seat wide pressed button count for the key of this event
+ * @return The seat wide pressed button count for the key of this event
*/
uint32_t
libinput_event_pointer_get_seat_button_count(
@@ -788,7 +788,7 @@ libinput_event_pointer_get_seat_button_count(
* libinput_event_pointer_get_axis_value() returns a value of 0, the event
* is a scroll stop event.
*
- * @return non-zero if this event contains a value for this axis
+ * @return Non-zero if this event contains a value for this axis
*/
int
libinput_event_pointer_has_axis(struct libinput_event_pointer *event,
@@ -814,7 +814,7 @@ libinput_event_pointer_has_axis(struct libinput_event_pointer *event,
* @note It is an application bug to call this function for events other than
* @ref LIBINPUT_EVENT_POINTER_AXIS.
*
- * @return the axis value of this event
+ * @return The axis value of this event
*
* @see libinput_event_pointer_get_axis_value_discrete
*/
@@ -855,7 +855,7 @@ libinput_event_pointer_get_axis_value(struct libinput_event_pointer *event,
* @note It is an application bug to call this function for events other than
* @ref LIBINPUT_EVENT_POINTER_AXIS.
*
- * @return the source for this axis event
+ * @return The source for this axis event
*/
enum libinput_pointer_axis_source
libinput_event_pointer_get_axis_source(struct libinput_event_pointer *event);
@@ -867,7 +867,7 @@ libinput_event_pointer_get_axis_source(struct libinput_event_pointer *event);
* value translates into a discrete step depends on the source.
*
* If the source is @ref LIBINPUT_POINTER_AXIS_SOURCE_WHEEL, the discrete
- * value correspond to the number of physical mouse clicks.
+ * value correspond to the number of physical mouse wheel clicks.
*
* If the source is @ref LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS or @ref
* LIBINPUT_POINTER_AXIS_SOURCE_FINGER, the discrete value is always 0.
@@ -947,7 +947,7 @@ libinput_event_touch_get_seat_slot(struct libinput_event_touch *event);
* LIBINPUT_EVENT_TOUCH_DOWN and @ref LIBINPUT_EVENT_TOUCH_MOTION.
*
* @param event The libinput touch event
- * @return the current absolute x coordinate
+ * @return The current absolute x coordinate
*/
double
libinput_event_touch_get_x(struct libinput_event_touch *event);
@@ -965,7 +965,7 @@ libinput_event_touch_get_x(struct libinput_event_touch *event);
* @ref LIBINPUT_EVENT_TOUCH_MOTION.
*
* @param event The libinput touch event
- * @return the current absolute y coordinate
+ * @return The current absolute y coordinate
*/
double
libinput_event_touch_get_y(struct libinput_event_touch *event);
@@ -981,7 +981,7 @@ libinput_event_touch_get_y(struct libinput_event_touch *event);
*
* @param event The libinput touch event
* @param width The current output screen width
- * @return the current absolute x coordinate transformed to a screen coordinate
+ * @return The current absolute x coordinate transformed to a screen coordinate
*/
double
libinput_event_touch_get_x_transformed(struct libinput_event_touch *event,
@@ -998,7 +998,7 @@ libinput_event_touch_get_x_transformed(struct libinput_event_touch *event,
*
* @param event The libinput touch event
* @param height The current output screen height
- * @return the current absolute y coordinate transformed to a screen coordinate
+ * @return The current absolute y coordinate transformed to a screen coordinate
*/
double
libinput_event_touch_get_y_transformed(struct libinput_event_touch *event,
@@ -1390,7 +1390,7 @@ struct libinput_interface {
* @param user_data The user_data provided in
* libinput_udev_create_context()
*
- * @return the file descriptor, or a negative errno on failure.
+ * @return The file descriptor, or a negative errno on failure.
*/
int (*open_restricted)(const char *path, int flags, void *user_data);
/**
@@ -1520,7 +1520,7 @@ libinput_path_remove_device(struct libinput_device *device);
* libinput keeps a single file descriptor for all events. Call into
* libinput_dispatch() if any events become available on this fd.
*
- * @return the file descriptor used to notify of pending events.
+ * @return The file descriptor used to notify of pending events.
*/
int
libinput_get_fd(struct libinput *libinput);
@@ -1532,7 +1532,11 @@ libinput_get_fd(struct libinput *libinput);
* and processes them internally. Use libinput_get_event() to retrieve the
* events.
*
- * Dispatching does not necessarily queue libinput events.
+ * Dispatching does not necessarily queue libinput events. This function
+ * should be called immediately once data is available on the file
+ * descriptor returned by libinput_get_fd(). libinput has a number of
+ * timing-sensitive features (e.g. tap-to-click), any delay in calling
+ * libinput_dispatch() may prevent these features from working correctly.
*
* @param libinput A previously initialized libinput context
*
@@ -1563,8 +1567,8 @@ libinput_get_event(struct libinput *libinput);
* libinput_get_event() returns that event.
*
* @param libinput A previously initialized libinput context
- * @return The event type of the next available event or LIBINPUT_EVENT_NONE
- * if no event is availble.
+ * @return The event type of the next available event or @ref
+ * LIBINPUT_EVENT_NONE if no event is availble.
*/
enum libinput_event_type
libinput_next_event_type(struct libinput *libinput);
@@ -1572,6 +1576,10 @@ libinput_next_event_type(struct libinput *libinput);
/**
* @ingroup base
*
+ * Set caller-specific data associated with this context. libinput does
+ * not manage, look at, or modify this data. The caller must ensure the
+ * data is valid.
+ *
* @param libinput A previously initialized libinput context
* @param user_data Caller-specific data passed to the various callback
* interfaces.
@@ -1583,8 +1591,10 @@ libinput_set_user_data(struct libinput *libinput,
/**
* @ingroup base
*
+ * Get the caller-specific data associated with this context, if any.
+ *
* @param libinput A previously initialized libinput context
- * @return the caller-specific data previously assigned in
+ * @return The caller-specific data previously assigned in
* libinput_create_udev().
*/
void *
@@ -1644,10 +1654,11 @@ libinput_unref(struct libinput *libinput);
/**
* @ingroup base
*
- * Set the global log priority. Messages with priorities equal to or
- * higher than the argument will be printed to the current log handler.
+ * Set the log priority for the libinput context. Messages with priorities
+ * equal to or higher than the argument will be printed to the context's
+ * log handler.
*
- * The default log priority is LIBINPUT_LOG_PRIORITY_ERROR.
+ * The default log priority is @ref LIBINPUT_LOG_PRIORITY_ERROR.
*
* @param libinput A previously initialized libinput context
* @param priority The minimum priority of log messages to print.
@@ -1662,10 +1673,10 @@ libinput_log_set_priority(struct libinput *libinput,
/**
* @ingroup base
*
- * Get the global log priority. Messages with priorities equal to or
+ * Get the context's log priority. Messages with priorities equal to or
* higher than the argument will be printed to the current log handler.
*
- * The default log priority is LIBINPUT_LOG_PRIORITY_ERROR.
+ * The default log priority is @ref LIBINPUT_LOG_PRIORITY_ERROR.
*
* @param libinput A previously initialized libinput context
* @return The minimum priority of log messages to print.
@@ -1698,8 +1709,8 @@ typedef void (*libinput_log_handler)(struct libinput *libinput,
/**
* @ingroup base
*
- * Set the global log handler. Messages with priorities equal to or higher
- * than the current log priority will be passed to the given
+ * Set the context's log handler. Messages with priorities equal to or
+ * higher than the context's log priority will be passed to the given
* log handler.
*
* The default log handler prints to stderr.
@@ -1727,7 +1738,7 @@ libinput_log_set_handler(struct libinput *libinput,
* @ingroup seat
*
* Increase the refcount of the seat. A seat will be freed whenever the
- * refcount reaches 0. This may happen during dispatch if the
+ * refcount reaches 0. This may happen during libinput_dispatch() if the
* seat was removed from the system. A caller must ensure to reference
* the seat correctly to avoid dangling pointers.
*
@@ -1741,7 +1752,7 @@ libinput_seat_ref(struct libinput_seat *seat);
* @ingroup seat
*
* Decrease the refcount of the seat. A seat will be freed whenever the
- * refcount reaches 0. This may happen during dispatch if the
+ * refcount reaches 0. This may happen during libinput_dispatch() if the
* seat was removed from the system. A caller must ensure to reference
* the seat correctly to avoid dangling pointers.
*
@@ -1802,7 +1813,7 @@ libinput_seat_get_context(struct libinput_seat *seat);
* be available to the caller.
*
* @param seat A previously obtained seat
- * @return the physical name of this seat
+ * @return The physical name of this seat
*/
const char *
libinput_seat_get_physical_name(struct libinput_seat *seat);
@@ -1814,7 +1825,7 @@ libinput_seat_get_physical_name(struct libinput_seat *seat);
* of devices within the compositor.
*
* @param seat A previously obtained seat
- * @return the logical name of this seat
+ * @return The logical name of this seat
*/
const char *
libinput_seat_get_logical_name(struct libinput_seat *seat);
@@ -1827,9 +1838,9 @@ libinput_seat_get_logical_name(struct libinput_seat *seat);
* @ingroup device
*
* Increase the refcount of the input device. An input device will be freed
- * whenever the refcount reaches 0. This may happen during dispatch if the
- * device was removed from the system. A caller must ensure to reference
- * the device correctly to avoid dangling pointers.
+ * whenever the refcount reaches 0. This may happen during
+ * libinput_dispatch() if the device was removed from the system. A caller
+ * must ensure to reference the device correctly to avoid dangling pointers.
*
* @param device A previously obtained device
* @return The passed device
@@ -1841,9 +1852,9 @@ libinput_device_ref(struct libinput_device *device);
* @ingroup device
*
* Decrease the refcount of the input device. An input device will be freed
- * whenever the refcount reaches 0. This may happen during dispatch if the
- * device was removed from the system. A caller must ensure to reference
- * the device correctly to avoid dangling pointers.
+ * whenever the refcount reaches 0. This may happen during libinput_dispatch
+ * if the device was removed from the system. A caller must ensure to
+ * reference the device correctly to avoid dangling pointers.
*
* @param device A previously obtained device
* @return NULL if the device was destroyed, otherwise the passed device
@@ -2011,7 +2022,7 @@ libinput_device_get_id_vendor(struct libinput_device *device);
* beyond the boundaries of this output. An absolute device has its input
* coordinates mapped to the extents of this output.
*
- * @return the name of the output this device is mapped to, or NULL if no
+ * @return The name of the output this device is mapped to, or NULL if no
* output is set
*/
const char *
@@ -2020,7 +2031,8 @@ libinput_device_get_output_name(struct libinput_device *device);
/**
* @ingroup device
*
- * Get the seat associated with this input device.
+ * Get the seat associated with this input device, see @ref seats for
+ * details.
*
* A seat can be uniquely identified by the physical and logical seat name.
* There will ever be only one seat instance with a given physical and logical
@@ -2040,10 +2052,13 @@ libinput_device_get_seat(struct libinput_device *device);
* device and adding it to the new seat.
*
* This command is identical to physically unplugging the device, then
- * re-plugging it as member of the new seat,
- * @ref LIBINPUT_EVENT_DEVICE_REMOVED and @ref LIBINPUT_EVENT_DEVICE_ADDED
- * events are sent accordingly. Those events mark the end of the lifetime
- * of this device and the start of a new device.
+ * re-plugging it as member of the new seat. libinput will generate a
+ * @ref LIBINPUT_EVENT_DEVICE_REMOVED event and this @ref libinput_device is
+ * considered removed from the context; it will not generate further events
+ * and will be freed when the refcount reaches zero.
+ * A @ref LIBINPUT_EVENT_DEVICE_ADDED event is generated with a new @ref
+ * libinput_device handle. It is the caller's responsibility to update
+ * references to the new device accordingly.
*
* If the logical seat name already exists in the device's physical seat,
* the device is added to this seat. Otherwise, a new seat is created.
@@ -2064,7 +2079,9 @@ libinput_device_set_seat_logical_name(struct libinput_device *device,
*
* Return a udev handle to the device that is this libinput device, if any.
* The returned handle has a refcount of at least 1, the caller must call
- * udev_device_unref() once to release the associated resources.
+ * udev_device_unref() once to release the associated resources.
+ * See the [libudev documentation]
+ * (http://www.freedesktop.org/software/systemd/libudev/) for details.
*
* Some devices may not have a udev device, or the udev device may be
* unobtainable. This function returns NULL if no udev device was available.
@@ -2098,7 +2115,7 @@ libinput_device_led_update(struct libinput_device *device,
*
* Check if the given device has the specified capability
*
- * @return 1 if the given device has the capability or 0 if not
+ * @return Non-zero if the given device has the capability or zero otherwise
*/
int
libinput_device_has_capability(struct libinput_device *device,
@@ -2127,10 +2144,10 @@ libinput_device_get_size(struct libinput_device *device,
* @ingroup device
*
* Check if a @ref LIBINPUT_DEVICE_CAP_POINTER device has a button with the
- * passed in code (see linux/input.h).
+ * given code (see linux/input.h).
*
* @param device A current input device
- * @param code button code to check for
+ * @param code Button code to check for, e.g. BTN_LEFT
*
* @return 1 if the device supports this button code, 0 if it does not, -1
* on error.
@@ -2150,9 +2167,10 @@ libinput_device_has_button(struct libinput_device *device, uint32_t code) LIBINP
* @ingroup device
*
* Increase the refcount of the device group. A device group will be freed
- * whenever the refcount reaches 0. This may happen during dispatch if all
- * devices of this group were removed from the system. A caller must ensure
- * to reference the device group correctly to avoid dangling pointers.
+ * whenever the refcount reaches 0. This may happen during
+ * libinput_dispatch() if all devices of this group were removed from the
+ * system. A caller must ensure to reference the device group correctly to
+ * avoid dangling pointers.
*
* @param group A previously obtained device group
* @return The passed device group
@@ -2164,9 +2182,10 @@ libinput_device_group_ref(struct libinput_device_group *group);
* @ingroup device
*
* Decrease the refcount of the device group. A device group will be freed
- * whenever the refcount reaches 0. This may happen during dispatch if all
- * devices of this group were removed from the system. A caller must ensure
- * to reference the device group correctly to avoid dangling pointers.
+ * whenever the refcount reaches 0. This may happen during
+ * libinput_dispatch() if all devices of this group were removed from the
+ * system. A caller must ensure to reference the device group correctly to
+ * avoid dangling pointers.
*
* @param group A previously obtained device group
* @return NULL if the device group was destroyed, otherwise the passed
@@ -2213,7 +2232,7 @@ libinput_device_group_get_user_data(struct libinput_device_group *group);
*
* Some configuration option may be dependent on or mutually exclusive with
* with other options. The behavior in those cases is
- * implementation-defined, the caller must ensure that the options are set
+ * implementation-dependent, the caller must ensure that the options are set
* in the right order.
*/
@@ -2254,7 +2273,8 @@ enum libinput_config_tap_state {
/**
* @ingroup config
*
- * Check if the device supports tap-to-click. See
+ * Check if the device supports tap-to-click and how many fingers can be
+ * used for tapping. See
* libinput_device_config_tap_set_enabled() for more information.
*
* @param device The device to configure
@@ -2300,8 +2320,8 @@ libinput_device_config_tap_set_enabled(struct libinput_device *device,
*
* @param device The device to configure
*
- * @return @ref LIBINPUT_CONFIG_TAP_ENABLED if tapping is currently enabled,
- * or @ref LIBINPUT_CONFIG_TAP_DISABLED is currently disabled
+ * @retval LIBINPUT_CONFIG_TAP_ENABLED If tapping is currently enabled
+ * @retval LIBINPUT_CONFIG_TAP_DISABLED If tapping is currently disabled
*
* @see libinput_device_config_tap_get_finger_count
* @see libinput_device_config_tap_set_enabled
@@ -2313,11 +2333,12 @@ libinput_device_config_tap_get_enabled(struct libinput_device *device);
/**
* @ingroup config
*
- * Return the default setting for whether tapping is enabled on this device.
+ * Return the default setting for whether tap-to-click is enabled on this
+ * device.
*
* @param device The device to configure
- * @return @ref LIBINPUT_CONFIG_TAP_ENABLED if tapping is enabled by default,
- * or @ref LIBINPUT_CONFIG_TAP_DISABLED is disabled by default
+ * @retval LIBINPUT_CONFIG_TAP_ENABLED If tapping is enabled by default
+ * @retval LIBINPUT_CONFIG_TAP_DISABLED If tapping Is disabled by default
*
* @see libinput_device_config_tap_get_finger_count
* @see libinput_device_config_tap_set_enabled
@@ -2332,7 +2353,7 @@ libinput_device_config_tap_get_default_enabled(struct libinput_device *device);
* Check if the device can be calibrated via a calibration matrix.
*
* @param device The device to check
- * @return non-zero if the device can be calibrated, zero otherwise.
+ * @return Non-zero if the device can be calibrated, zero otherwise.
*
* @see libinput_device_config_calibration_set_matrix
* @see libinput_device_config_calibration_get_matrix
@@ -2420,21 +2441,7 @@ libinput_device_config_calibration_get_matrix(struct libinput_device *device,
* Return the default calibration matrix for this device. On most devices,
* this is the identity matrix. If the udev property
* LIBINPUT_CALIBRATION_MATRIX is set on the respective udev device,
- * that property's value becomes the default matrix.
- *
- * The udev property is parsed as 6 floating point numbers separated by a
- * single space each (scanf(3) format "%f %f %f %f %f %f").
- * The 6 values represent the first two rows of the calibration matrix as
- * described in libinput_device_config_calibration_set_matrix().
- *
- * Example values are:
- * @code
- * ENV{LIBINPUT_CALIBRATION_MATRIX}="1 0 0 0 1 0" # default
- * ENV{LIBINPUT_CALIBRATION_MATRIX}="0 -1 1 1 0 0" # 90 degree clockwise
- * ENV{LIBINPUT_CALIBRATION_MATRIX}="-1 0 1 0 -1 1" # 180 degree clockwise
- * ENV{LIBINPUT_CALIBRATION_MATRIX}="0 1 0 -1 0 1" # 270 degree clockwise
- * ENV{LIBINPUT_CALIBRATION_MATRIX}="-1 0 1 1 0 0" # reflect along y axis
- * @endcode
+ * that property's value becomes the default matrix, see @ref udev_config.
*
* @param device The device to configure
* @param matrix Set to the array representing the first two rows of a 3x3 matrix as
@@ -2652,7 +2659,7 @@ libinput_device_config_accel_get_default_speed(struct libinput_device *device);
*
* @param device The device to configure
*
- * @return 0 if natural scrolling is not supported, non-zero if natural
+ * @return Zero if natural scrolling is not supported, non-zero if natural
* scrolling is supported by this device
*
* @see libinput_device_config_set_natural_scroll_enabled
@@ -2670,7 +2677,7 @@ libinput_device_config_scroll_has_natural_scroll(struct libinput_device *device)
* @param device The device to configure
* @param enable non-zero to enable, zero to disable natural scrolling
*
- * @return a config status code
+ * @return A config status code
*
* @see libinput_device_config_has_natural_scroll
* @see libinput_device_config_get_natural_scroll_enabled
@@ -2686,7 +2693,7 @@ libinput_device_config_scroll_set_natural_scroll_enabled(struct libinput_device
*
* @param device The device to configure
*
- * @return zero if natural scrolling is disabled, non-zero if enabled
+ * @return Zero if natural scrolling is disabled, non-zero if enabled
*
* @see libinput_device_config_has_natural_scroll
* @see libinput_device_config_set_natural_scroll_enabled
@@ -2702,7 +2709,7 @@ libinput_device_config_scroll_get_natural_scroll_enabled(struct libinput_device
*
* @param device The device to configure
*
- * @return zero if natural scrolling is disabled by default, non-zero if enabled
+ * @return Zero if natural scrolling is disabled by default, non-zero if enabled
*
* @see libinput_device_config_has_natural_scroll
* @see libinput_device_config_set_natural_scroll_enabled
@@ -2730,9 +2737,7 @@ libinput_device_config_left_handed_is_available(struct libinput_device *device);
/**
* @ingroup config
*
- * Set the left-handed configuration of the device. For example, a pointing
- * device may reverse it's buttons and send a right button click when the
- * left button is pressed, and vice versa.
+ * Set the left-handed configuration of the device.
*
* The exact behavior is device-dependent. On a mouse and most pointing
* devices, left and right buttons are swapped but the middle button is
@@ -2798,7 +2803,7 @@ libinput_device_config_left_handed_get_default(struct libinput_device *device);
enum libinput_config_click_method {
/**
* Do not send software-emulated button events. This has no effect
- * on physical button generations.
+ * on events generated by physical buttons.
*/
LIBINPUT_CONFIG_CLICK_METHOD_NONE = 0,
/**
@@ -2898,15 +2903,16 @@ libinput_device_config_click_get_default_method(struct libinput_device *device);
enum libinput_config_scroll_method {
/**
* Never send scroll events instead of pointer motion events.
- * Note scroll wheels, etc. will still send scroll events.
+ * This has no effect on events generated by scroll wheels.
*/
LIBINPUT_CONFIG_SCROLL_NO_SCROLL = 0,
/**
- * Send scroll events when 2 fingers are down on the device.
+ * Send scroll events when two fingers are logically down on the
+ * device.
*/
LIBINPUT_CONFIG_SCROLL_2FG = (1 << 0),
/**
- * Send scroll events when a finger is moved along the bottom or
+ * Send scroll events when a finger moves along the bottom or
* right edge of a device.
*/
LIBINPUT_CONFIG_SCROLL_EDGE = (1 << 1),
@@ -3024,10 +3030,11 @@ libinput_device_config_scroll_get_default_method(struct libinput_device *device)
* @param device The device to configure
* @param button The button which when pressed switches to sending scroll events
*
- * @return a config status code
- * @retval LIBINPUT_CONFIG_STATUS_SUCCESS on success
- * @retval LIBINPUT_CONFIG_STATUS_UNSUPPORTED if @ref LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN is not supported
- * @retval LIBINPUT_CONFIG_STATUS_INVALID the given button does not
+ * @return A config status code
+ * @retval LIBINPUT_CONFIG_STATUS_SUCCESS On success
+ * @retval LIBINPUT_CONFIG_STATUS_UNSUPPORTED If @ref
+ * LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN is not supported
+ * @retval LIBINPUT_CONFIG_STATUS_INVALID The given button does not
* exist on this device
*
* @see libinput_device_config_scroll_get_methods
@@ -3044,11 +3051,11 @@ libinput_device_config_scroll_set_button(struct libinput_device *device,
/**
* @ingroup config
*
- * Get the button for the @ref LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN method for
- * this device.
+ * Get the button for the @ref LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN method
+ * for this device.
*
- * If @ref LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN scroll method is not supported,
- * or no button is set, this function returns 0.
+ * If @ref LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN scroll method is not
+ * supported, or no button is set, this function returns 0.
*
* @note The return value is independent of the currently selected
* scroll-method. For button scrolling to activate, a device must have the
@@ -3071,14 +3078,15 @@ libinput_device_config_scroll_get_button(struct libinput_device *device);
/**
* @ingroup config
*
- * Get the default button for LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN method
- * for this device.
+ * Get the default button for the @ref LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN
+ * method for this device.
*
* If @ref LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN scroll method is not supported,
* or no default button is set, this function returns 0.
*
* @param device The device to configure
- * @return The default button for LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN method
+ * @return The default button for the @ref
+ * LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN method
*
* @see libinput_device_config_scroll_get_methods
* @see libinput_device_config_scroll_set_method
diff --git a/test/Makefile.am b/test/Makefile.am
index a0c93414..220575f2 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -19,6 +19,7 @@ liblitest_la_SOURCES = \
litest-keyboard.c \
litest-mouse.c \
litest-ms-surface-cover.c \
+ litest-protocol-a-touch-screen.c \
litest-qemu-usb-tablet.c \
litest-synaptics.c \
litest-synaptics-hover.c \
diff --git a/test/litest-protocol-a-touch-screen.c b/test/litest-protocol-a-touch-screen.c
new file mode 100644
index 00000000..2c930060
--- /dev/null
+++ b/test/litest-protocol-a-touch-screen.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright © 2015 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.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "litest.h"
+#include "litest-int.h"
+
+static void
+litest_protocol_a_touch_setup(void)
+{
+ struct litest_device *d = litest_create_device(LITEST_PROTOCOL_A_SCREEN);
+ litest_set_current_device(d);
+}
+
+static struct input_event down[] = {
+ { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_SYN, .code = SYN_MT_REPORT, .value = 0 },
+ { .type = EV_KEY, .code = BTN_TOUCH, .value = 1 },
+ { .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
+ { .type = -1, .code = -1 },
+};
+
+static struct input_event move[] = {
+ { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_SYN, .code = SYN_MT_REPORT, .value = 0 },
+ { .type = EV_KEY, .code = BTN_TOUCH, .value = 1 },
+ { .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
+ { .type = -1, .code = -1 },
+};
+
+static struct litest_device_interface interface = {
+ .touch_down_events = down,
+ .touch_move_events = move,
+};
+
+static struct input_absinfo absinfo[] = {
+ { ABS_X, 0, 32767, 0, 0, 0 },
+ { ABS_Y, 0, 32767, 0, 0, 0 },
+ { ABS_MT_POSITION_X, 0, 32767, 0, 0, 0 },
+ { ABS_MT_POSITION_Y, 0, 32767, 0, 0, 0 },
+ { ABS_MT_PRESSURE, 0, 1, 0, 0, 0 },
+ { .value = -1 },
+};
+
+static struct input_id input_id = {
+ .bustype = 0x18,
+ .vendor = 0xeef,
+ .product = 0x20,
+};
+
+static int events[] = {
+ EV_KEY, BTN_TOUCH,
+ INPUT_PROP_MAX, INPUT_PROP_DIRECT,
+ -1, -1,
+};
+
+struct litest_test_device litest_protocol_a_screen = {
+ .type = LITEST_PROTOCOL_A_SCREEN,
+ .features = LITEST_PROTOCOL_A,
+ .shortname = "protocol A",
+ .setup = litest_protocol_a_touch_setup,
+ .interface = &interface,
+
+ .name = "Protocol A touch screen",
+ .id = &input_id,
+ .events = events,
+ .absinfo = absinfo,
+};
diff --git a/test/litest.c b/test/litest.c
index 6d4bfdbc..263e9b81 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -100,6 +100,7 @@ extern struct litest_test_device litest_xen_virtual_pointer_device;
extern struct litest_test_device litest_vmware_virtmouse_device;
extern struct litest_test_device litest_synaptics_hover_device;
extern struct litest_test_device litest_synaptics_carbon3rd_device;
+extern struct litest_test_device litest_protocol_a_screen;
struct litest_test_device* devices[] = {
&litest_synaptics_clickpad_device,
@@ -121,6 +122,7 @@ struct litest_test_device* devices[] = {
&litest_vmware_virtmouse_device,
&litest_synaptics_hover_device,
&litest_synaptics_carbon3rd_device,
+ &litest_protocol_a_screen,
NULL,
};
@@ -1507,6 +1509,12 @@ litest_timeout_buttonscroll(void)
msleep(300);
}
+void
+litest_timeout_finger_switch(void)
+{
+ msleep(120);
+}
+
void
litest_push_event_frame(struct litest_device *dev)
{
diff --git a/test/litest.h b/test/litest.h
index 40b3910e..4fbffd7a 100644
--- a/test/litest.h
+++ b/test/litest.h
@@ -51,10 +51,11 @@ enum litest_device_type {
LITEST_VMWARE_VIRTMOUSE = -15,
LITEST_SYNAPTICS_HOVER_SEMI_MT = -16,
LITEST_SYNAPTICS_TRACKPOINT_BUTTONS = -17,
- LITEST_WACOM_BAMBOO = -18,
- LITEST_WACOM_CINTIQ = -19,
- LITEST_WACOM_INTUOS = -20,
- LITEST_WACOM_ISDV4 = -21,
+ LITEST_PROTOCOL_A_SCREEN = -18,
+ LITEST_WACOM_BAMBOO = -19,
+ LITEST_WACOM_CINTIQ = -20,
+ LITEST_WACOM_INTUOS = -21,
+ LITEST_WACOM_ISDV4 = -22,
};
enum litest_device_feature {
@@ -74,9 +75,10 @@ enum litest_device_feature {
LITEST_POINTINGSTICK = 1 << 11,
LITEST_FAKE_MT = 1 << 12,
LITEST_ABSOLUTE = 1 << 13,
- LITEST_TABLET = 1 << 14,
- LITEST_DISTANCE = 1 << 15,
- LITEST_TOOL_SERIAL = 1 << 16,
+ LITEST_PROTOCOL_A = 1 << 14,
+ LITEST_TABLET = 1 << 15,
+ LITEST_DISTANCE = 1 << 16,
+ LITEST_TOOL_SERIAL = 1 << 17,
};
struct litest_device {
@@ -218,6 +220,7 @@ struct libevdev_uinput * litest_create_uinput_abs_device(const char *name,
void litest_timeout_tap(void);
void litest_timeout_softbuttons(void);
void litest_timeout_buttonscroll(void);
+void litest_timeout_finger_switch(void);
void litest_push_event_frame(struct litest_device *dev);
void litest_pop_event_frame(struct litest_device *dev);
diff --git a/test/pointer.c b/test/pointer.c
index 24ea7266..23bf0d7c 100644
--- a/test/pointer.c
+++ b/test/pointer.c
@@ -826,7 +826,7 @@ int main (int argc, char **argv) {
litest_add("pointer:scroll", pointer_scroll_natural_wheel, LITEST_WHEEL, LITEST_ANY);
litest_add_no_device("pointer:seat button count", pointer_seat_button_count);
- litest_add("pointer:calibration", pointer_no_calibration, LITEST_ANY, LITEST_TOUCH|LITEST_SINGLE_TOUCH|LITEST_ABSOLUTE);
+ litest_add("pointer:calibration", pointer_no_calibration, LITEST_ANY, LITEST_TOUCH|LITEST_SINGLE_TOUCH|LITEST_ABSOLUTE|LITEST_PROTOCOL_A);
/* tests touchpads too */
litest_add("pointer:left-handed", pointer_left_handed_defaults, LITEST_BUTTON, LITEST_ANY);
diff --git a/test/touch.c b/test/touch.c
index 29890a41..2d918b2d 100644
--- a/test/touch.c
+++ b/test/touch.c
@@ -465,6 +465,124 @@ START_TEST(fake_mt_no_touch_events)
}
END_TEST
+START_TEST(touch_protocol_a_init)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct libinput_device *device = dev->libinput_device;
+
+ ck_assert_int_ne(libinput_next_event_type(li),
+ LIBINPUT_EVENT_NONE);
+
+ ck_assert(libinput_device_has_capability(device,
+ LIBINPUT_DEVICE_CAP_TOUCH));
+}
+END_TEST
+
+START_TEST(touch_protocol_a_touch)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct libinput_event *ev;
+ struct libinput_event_touch *tev;
+ double x, y, oldx, oldy;
+
+ litest_drain_events(li);
+
+ litest_touch_down(dev, 0, 5, 95);
+
+ litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_DOWN, -1);
+
+ ev = libinput_get_event(li);
+ tev = libinput_event_get_touch_event(ev);
+
+ oldx = libinput_event_touch_get_x(tev);
+ oldy = libinput_event_touch_get_y(tev);
+
+ libinput_event_destroy(ev);
+
+ litest_touch_move_to(dev, 0, 10, 90, 90, 10, 20, 1);
+ litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_MOTION, -1);
+
+ while ((ev = libinput_get_event(li))) {
+ if (libinput_event_get_type(ev) ==
+ LIBINPUT_EVENT_TOUCH_FRAME) {
+ libinput_event_destroy(ev);
+ continue;
+ }
+ ck_assert_int_eq(libinput_event_get_type(ev),
+ LIBINPUT_EVENT_TOUCH_MOTION);
+
+ tev = libinput_event_get_touch_event(ev);
+ x = libinput_event_touch_get_x(tev);
+ y = libinput_event_touch_get_y(tev);
+
+ ck_assert_int_gt(x, oldx);
+ ck_assert_int_lt(y, oldy);
+
+ oldx = x;
+ oldy = y;
+
+ libinput_event_destroy(ev);
+ }
+
+ litest_touch_up(dev, 0);
+ litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_UP, -1);
+}
+END_TEST
+
+START_TEST(touch_protocol_a_2fg_touch)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct libinput_event *ev;
+ struct libinput_event_touch *tev;
+ int pos;
+
+ litest_drain_events(li);
+
+ litest_push_event_frame(dev);
+ litest_touch_down(dev, 0, 5, 95);
+ litest_touch_down(dev, 0, 95, 5);
+ litest_pop_event_frame(dev);
+
+ litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_DOWN, -1);
+
+ ev = libinput_get_event(li);
+ libinput_event_destroy(ev);
+
+ litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_DOWN, -1);
+
+ ev = libinput_get_event(li);
+ libinput_event_destroy(ev);
+
+ for (pos = 10; pos < 100; pos += 10) {
+ litest_push_event_frame(dev);
+ litest_touch_move_to(dev, 0, pos, 100 - pos, pos, 100 - pos, 1, 1);
+ litest_touch_move_to(dev, 0, 100 - pos, pos, 100 - pos, pos, 1, 1);
+ litest_pop_event_frame(dev);
+ litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_MOTION, -1);
+ ev = libinput_get_event(li);
+ tev = libinput_event_get_touch_event(ev);
+ ck_assert_int_eq(libinput_event_touch_get_slot(tev),
+ 0);
+ libinput_event_destroy(ev);
+
+ litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_MOTION, -1);
+ ev = libinput_get_event(li);
+ tev = libinput_event_get_touch_event(ev);
+ ck_assert_int_eq(libinput_event_touch_get_slot(tev),
+ 1);
+ libinput_event_destroy(ev);
+ }
+
+ litest_event(dev, EV_SYN, SYN_MT_REPORT, 0);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_UP, -1);
+ litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TOUCH_UP, -1);
+}
+END_TEST
+
int
main(int argc, char **argv)
{
@@ -484,5 +602,9 @@ main(int argc, char **argv)
litest_add("touch:fake-mt", fake_mt_exists, LITEST_FAKE_MT, LITEST_ANY);
litest_add("touch:fake-mt", fake_mt_no_touch_events, LITEST_FAKE_MT, LITEST_ANY);
+ litest_add("touch:protocol a", touch_protocol_a_init, LITEST_PROTOCOL_A, LITEST_ANY);
+ litest_add("touch:protocol a", touch_protocol_a_touch, LITEST_PROTOCOL_A, LITEST_ANY);
+ litest_add("touch:protocol a", touch_protocol_a_2fg_touch, LITEST_PROTOCOL_A, LITEST_ANY);
+
return litest_run(argc, argv);
}
diff --git a/test/touchpad.c b/test/touchpad.c
index 9b3ba812..b70d3732 100644
--- a/test/touchpad.c
+++ b/test/touchpad.c
@@ -1871,6 +1871,9 @@ START_TEST(touchpad_2fg_scroll_return_to_motion)
litest_touch_move_to(dev, 0, 47, 50, 47, 70, 5, 0);
litest_touch_move_to(dev, 1, 53, 50, 53, 70, 5, 0);
litest_touch_up(dev, 1);
+ libinput_dispatch(li);
+ litest_timeout_finger_switch();
+ libinput_dispatch(li);
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
litest_touch_move_to(dev, 0, 47, 70, 47, 50, 10, 0);
@@ -1881,6 +1884,9 @@ START_TEST(touchpad_2fg_scroll_return_to_motion)
litest_touch_move_to(dev, 0, 47, 50, 47, 70, 5, 0);
litest_touch_move_to(dev, 1, 53, 50, 53, 70, 5, 0);
litest_touch_up(dev, 0);
+ libinput_dispatch(li);
+ litest_timeout_finger_switch();
+ libinput_dispatch(li);
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
/* move with second finger */
diff --git a/test/valgrind.suppressions b/test/valgrind.suppressions
index fc9251a7..4ad22ab2 100644
--- a/test/valgrind.suppressions
+++ b/test/valgrind.suppressions
@@ -7,6 +7,12 @@
fun:litest_run
fun:main
}
+{
+ mtdev:conditional_jumps_uninitialized_value
+ Memcheck:Cond
+ ...
+ fun:mtdev_put_event
+}
{
Memcheck:Leak