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