From: Tiago Vignatti <tiago.vigna...@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.vigna...@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

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to