[PATCH 3/6] toytoolkit: add multitouch support with sample gesture mechanism

Tiago Vignatti vignatti at freedesktop.org
Wed Dec 21 09:34:11 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 |  259 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 clients/window.h |    8 ++
 2 files changed, 267 insertions(+), 0 deletions(-)

diff --git a/clients/window.c b/clients/window.c
index 09e9b70..148356d 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;
@@ -133,6 +134,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;
@@ -158,6 +160,7 @@ struct input {
 	struct wl_input_device *input_device;
 	struct window *pointer_focus;
 	struct window *keyboard_focus;
+	struct window *touch_focus;
 	uint32_t current_pointer_image;
 	uint32_t modifiers;
 	int32_t x, y, sx, sy;
@@ -1411,12 +1414,261 @@ 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->touch_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, struct wl_surface *surface)
+{
+	struct input *input = data;
+
+	if (surface)
+		input->touch_focus = wl_surface_get_user_data(surface);
+
+	window_handle_touch(data, wl_input_device, time, id, x, y, 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
@@ -1903,6 +2155,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;
@@ -2530,6 +2788,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 59397f0..3f7984d 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 *
@@ -334,6 +338,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