[PATCH 3/6] toytoolkit: add multitouch support with sample gesture mechanism
Tiago Vignatti
vignatti at freedesktop.org
Fri Dec 16 07:59:39 PST 2011
From: Tiago Vignatti <tiago.vignatti at intel.com>
Save touch point information, get pinch and zoom gesture and send over to
client that register a touch_handler.
Signed-off-by: Tiago Vignatti <tiago.vignatti at intel.com>
---
clients/window.c | 253 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
clients/window.h | 8 ++
2 files changed, 261 insertions(+), 0 deletions(-)
diff --git a/clients/window.c b/clients/window.c
index e8e3508..9696b7c 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -82,6 +82,7 @@ struct display {
struct wl_list window_list;
struct wl_list input_list;
struct wl_list output_list;
+ struct wl_array touch_points;
char *device_name;
cairo_surface_t *active_frame, *inactive_frame, *shadow;
struct xkb_desc *xkb;
@@ -132,6 +133,7 @@ struct window {
window_button_handler_t button_handler;
window_keyboard_focus_handler_t keyboard_focus_handler;
window_motion_handler_t motion_handler;
+ window_touch_handler_t touch_handler;
window_enter_handler_t enter_handler;
window_leave_handler_t leave_handler;
window_item_focus_handler_t item_focus_handler;
@@ -1437,12 +1439,256 @@ window_handle_keyboard_focus(void *data,
}
}
+struct touch_point {
+ uint32_t id;
+ int x, y;
+};
+
+/*
+ * touch_point_info - return the number of touch points (fingers down)
+ */
+static int
+touch_point_info(struct display *d)
+{
+ struct touch_point *tp, *end;
+ int n = 0;
+
+ end = d->touch_points.data + d->touch_points.size;
+ for (tp = d->touch_points.data; tp < end; tp++)
+ n++;
+
+ return n;
+}
+
+static struct touch_point *
+touch_point_lookup(struct display *d, int id)
+{
+ struct touch_point *tp, *end;
+
+ end = d->touch_points.data + d->touch_points.size;
+ for (tp = d->touch_points.data; tp < end; tp++) {
+ if (tp->id == id)
+ return tp;
+ }
+
+ return NULL;
+}
+
+static struct touch_point *
+touch_point_begin(struct display *d, int id)
+{
+ struct touch_point *tp;
+
+ tp = wl_array_add(&d->touch_points, sizeof (struct touch_point));
+ tp->id = id;
+
+ return tp;
+}
+
+static int
+touch_point_end(struct display *d, int id)
+{
+ struct touch_point *tp, *end;
+
+ end = d->touch_points.data + d->touch_points.size;
+ for (tp = d->touch_points.data; tp < end; tp++) {
+ if (tp->id == id)
+ *tp = *--end;
+ }
+ d->touch_points.size = (void *) end - d->touch_points.data;
+
+ return 0;
+}
+
+#define NUM_FINGERS 2
+#define NUM_SNAPSHOT 10
+
+struct gesture_state {
+ struct {
+ int x;
+ int y;
+ } finger[NUM_FINGERS];
+};
+
+/* smaller the snapshot number, more recent it happened */
+struct gesture_state hand_state[NUM_SNAPSHOT];
+
+static void
+gesture_reset_state(void)
+{
+ int i, j;
+
+ for (i = 0; i < NUM_SNAPSHOT; i++) {
+ for (j = 0; j < NUM_FINGERS; j++) {
+ hand_state[i].finger[j].x = -1;
+ hand_state[i].finger[j].y = -1;
+ }
+ }
+}
+
+static void
+gesture_save_state(struct display *d, struct touch_point *tp)
+{
+ int i, j;
+ struct gesture_state last_down;
+ last_down.finger[0].x = -1;
+ last_down.finger[0].y = -1;
+
+ /* shift one position back the hand state array */
+ for (i = NUM_SNAPSHOT; i > 0; i--) {
+ for (j = 0; j < NUM_FINGERS; j++) {
+ hand_state[i].finger[j].x =
+ hand_state[i - 1].finger[j].x;
+ hand_state[i].finger[j].y =
+ hand_state[i - 1].finger[j].y;
+
+ if (hand_state[i].finger[j].x != -1 &&
+ hand_state[i].finger[j].y != -1) {
+ last_down.finger[j].x =
+ hand_state[i].finger[j].x;
+ last_down.finger[j].y =
+ hand_state[i].finger[j].y;
+ }
+ }
+ }
+
+ /* fill up the last hand state */
+ for (i = 0; i < NUM_FINGERS; i++) {
+ if (tp->id == i) {
+ hand_state[0].finger[i].x = tp->x;
+ hand_state[0].finger[i].y = tp->y;
+ } else {
+ hand_state[0].finger[i].x = last_down.finger[i].x;
+ hand_state[0].finger[i].y = last_down.finger[i].y;
+ }
+ }
+}
+
+static double
+gesture_euclidean_distance(void)
+{
+ double x1, x2, y1, y2;
+
+ x1 = hand_state[0].finger[0].x;
+ y1 = hand_state[0].finger[0].y;
+ x2 = hand_state[0].finger[1].x;
+ y2 = hand_state[0].finger[1].y;
+
+ return sqrt(pow((x2 - x1), 2) + pow((y2 - y1), 2));
+}
+
+/**
+ * gesture_recognizer - recognizes pinch and zoom
+ *
+ * return 1 for zoom, -1 for pinch and 0 if nothing happened
+ */
+static int
+gesture_recognizer(struct display *d, struct touch_point *tp)
+{
+ int fingers_down = touch_point_info(d);
+ static double distance, last_distance;
+ static int pinch, zoom;
+
+ /* we only care about two fingers down now */
+ if (fingers_down < 2) {
+ pinch = 0;
+ zoom = 0;
+ gesture_reset_state();
+ return 0;
+ }
+
+ gesture_save_state(d, tp);
+
+ distance = gesture_euclidean_distance();
+ /* accepting fuzzy values */
+ if (last_distance - distance > 0) {
+ pinch++;
+ zoom--;
+ }
+ else {
+ pinch--;
+ zoom++;
+ }
+
+ if (pinch > NUM_SNAPSHOT)
+ return -1;
+ else if (zoom > NUM_SNAPSHOT)
+ return 1;
+
+ if (pinch < 0)
+ pinch = 0;
+ if (zoom < 0)
+ zoom = 0;
+ last_distance = distance;
+
+ return 0;
+}
+
+#define TOUCH_DOWN (1 << 0)
+#define TOUCH_UP (1 << 1)
+#define TOUCH_MOTION (1 << 2)
+
+static void
+window_handle_touch(void *data, struct wl_input_device *input_device,
+ uint32_t time, int id, int x, int y, int type)
+{
+ struct input *input = data;
+ struct display *d = input->display;
+ struct window *window = input->pointer_focus;
+ struct touch_point *tp;
+ int resize;
+
+ tp = touch_point_lookup(d, id);
+ if (!tp) {
+ if (type != TOUCH_DOWN) {
+ fprintf(stderr, "error: wrong touch cycle order\n");
+ return;
+ }
+ tp = touch_point_begin(d, id);
+ }
+ else if (type == TOUCH_UP)
+ touch_point_end(d, id);
+
+ tp->x = x;
+ tp->y = y;
+ resize = gesture_recognizer(d, tp);
+
+ if (window->touch_handler && resize != 0)
+ (*window->touch_handler)(window, input, time, resize,
+ window->user_data);
+}
+
+static void
+window_handle_touch_down(void *data, struct wl_input_device *wl_input_device,
+ uint32_t time, int id, int x, int y)
+{
+ window_handle_touch(data, wl_input_device, time, id, 0, 0, TOUCH_DOWN);
+}
+
+static void
+window_handle_touch_up(void *data, struct wl_input_device *wl_input_device,
+ uint32_t time, int id)
+{
+ window_handle_touch(data, wl_input_device, time, id, 0, 0, TOUCH_UP);
+}
+
+static void
+window_handle_touch_motion(void *data, struct wl_input_device *wl_input_device,
+ uint32_t time, int id, int x, int y)
+{
+ window_handle_touch(data, wl_input_device, time, id, x, y,
+ TOUCH_MOTION);
+}
+
static const struct wl_input_device_listener input_device_listener = {
window_handle_motion,
window_handle_button,
window_handle_key,
window_handle_pointer_focus,
window_handle_keyboard_focus,
+ window_handle_touch_down,
+ window_handle_touch_up,
+ window_handle_touch_motion,
};
void
@@ -1929,6 +2175,12 @@ window_set_drop_handler(struct window *window, window_drop_handler_t handler)
}
void
+window_set_touch_handler(struct window *window, window_touch_handler_t handler)
+{
+ window->touch_handler = handler;
+}
+
+void
window_set_transparent(struct window *window, int transparent)
{
window->transparent = transparent;
@@ -2416,6 +2668,7 @@ display_create(int *argc, char **argv[], const GOptionEntry *option_entries)
wl_list_init(&d->deferred_list);
wl_list_init(&d->input_list);
wl_list_init(&d->output_list);
+ wl_array_init(&d->touch_points);
/* Set up listener so we'll catch all events. */
wl_display_add_global_listener(d->display,
diff --git a/clients/window.h b/clients/window.h
index e5dc008..5172977 100644
--- a/clients/window.h
+++ b/clients/window.h
@@ -191,6 +191,10 @@ typedef void (*window_drop_handler_t)(struct window *window,
typedef void (*window_item_focus_handler_t)(struct window *window,
struct item *focus, void *data);
+typedef void (*window_touch_handler_t)(struct window *window,
+ struct input *input, uint32_t time,
+ int resize, void* data);
+
struct window *
window_create(struct display *display, int32_t width, int32_t height);
struct window *
@@ -331,6 +335,10 @@ window_set_drop_handler(struct window *window,
window_drop_handler_t handler);
void
+window_set_touch_handler(struct window *window,
+ window_touch_handler_t handler);
+
+void
window_set_title(struct window *window, const char *title);
const char *
--
1.7.5.4
More information about the wayland-devel
mailing list