From 45d15b302e318f3ba9fed7c5e146152ba0e97de6 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Thu, 9 Jul 2015 19:36:30 +0200 Subject: [PATCH] wayland: Implement touchpad gesture events On wayland, the gestures protocol defines a wl_pointer_gestures global object, that will match in number with wl_seats, swipe and pinch interfaces can be obtained from it, which events are translated into GdkEventTouchpadSwipe/Pinch events. --- gdk/wayland/gdkdevice-wayland.c | 245 +++++++++++++++++++++++++++++++ gdk/wayland/gdkdisplay-wayland.c | 6 + gdk/wayland/gdkdisplay-wayland.h | 1 + 3 files changed, 252 insertions(+) diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c index 7fb27c178f..9b190f2277 100644 --- a/gdk/wayland/gdkdevice-wayland.c +++ b/gdk/wayland/gdkdevice-wayland.c @@ -29,6 +29,7 @@ #include "gdkkeysyms.h" #include "gdkdeviceprivate.h" #include "gdkdevicemanagerprivate.h" +#include "pointer-gestures-client-protocol.h" #include @@ -54,6 +55,8 @@ struct _GdkWaylandDeviceData struct wl_pointer *wl_pointer; struct wl_keyboard *wl_keyboard; struct wl_touch *wl_touch; + struct _wl_pointer_gesture_swipe *wl_pointer_gesture_swipe; + struct _wl_pointer_gesture_pinch *wl_pointer_gesture_pinch; GdkDisplay *display; GdkDeviceManager *device_manager; @@ -99,6 +102,10 @@ struct _GdkWaylandDeviceData /* Source/dest for non-local dnd */ GdkWindow *foreign_dnd_window; + + /* Some tracking on gesture events */ + guint gesture_n_fingers; + gdouble gesture_scale; }; struct _GdkWaylandDevice @@ -1653,6 +1660,213 @@ touch_handle_cancel (void *data, GDK_NOTE (EVENTS, g_message ("touch cancel")); } +static void +emit_gesture_swipe_event (GdkWaylandDeviceData *device, + GdkTouchpadGesturePhase phase, + guint32 _time, + guint32 n_fingers, + gdouble dx, + gdouble dy) +{ + GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (device->display); + GdkEvent *event; + + if (!device->pointer_focus) + return; + + device->time = _time; + + event = gdk_event_new (GDK_TOUCHPAD_SWIPE); + event->touchpad_swipe.phase = phase; + event->touchpad_swipe.window = g_object_ref (device->pointer_focus); + gdk_event_set_device (event, device->master_pointer); + gdk_event_set_source_device (event, device->pointer); + event->touchpad_swipe.time = _time; + event->touchpad_swipe.state = device->button_modifiers | device->key_modifiers; + gdk_event_set_screen (event, display->screen); + event->touchpad_swipe.dx = dx; + event->touchpad_swipe.dy = dy; + event->touchpad_swipe.n_fingers = n_fingers; + + get_coordinates (device, + &event->touchpad_swipe.x, + &event->touchpad_swipe.y, + &event->touchpad_swipe.x_root, + &event->touchpad_swipe.y_root); + + GDK_NOTE (EVENTS, + g_message ("swipe event %d, coords: %f %f, device %p state %d", + event->type, event->touchpad_swipe.x, + event->touchpad_swipe.y, device, + event->touchpad_swipe.state)); + + _gdk_wayland_display_deliver_event (device->display, event); +} + +static void +gesture_swipe_begin (void *data, + struct _wl_pointer_gesture_swipe *swipe, + uint32_t serial, + uint32_t time, + struct wl_surface *surface, + uint32_t fingers) +{ + GdkWaylandDeviceData *device = data; + GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (device->display); + + _gdk_wayland_display_update_serial (display, serial); + + emit_gesture_swipe_event (device, + GDK_TOUCHPAD_GESTURE_PHASE_BEGIN, + time, fingers, 0, 0); + device->gesture_n_fingers = fingers; +} + +static void +gesture_swipe_update (void *data, + struct _wl_pointer_gesture_swipe *swipe, + uint32_t time, + wl_fixed_t dx, + wl_fixed_t dy) +{ + GdkWaylandDeviceData *device = data; + + emit_gesture_swipe_event (device, + GDK_TOUCHPAD_GESTURE_PHASE_UPDATE, + time, + device->gesture_n_fingers, + wl_fixed_to_double (dx), + wl_fixed_to_double (dy)); +} + +static void +gesture_swipe_end (void *data, + struct _wl_pointer_gesture_swipe *swipe, + uint32_t serial, + uint32_t time, + int32_t cancelled) +{ + GdkWaylandDeviceData *device = data; + GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (device->display); + GdkTouchpadGesturePhase phase; + + _gdk_wayland_display_update_serial (display, serial); + + phase = (cancelled) ? + GDK_TOUCHPAD_GESTURE_PHASE_CANCEL : + GDK_TOUCHPAD_GESTURE_PHASE_END; + + emit_gesture_swipe_event (device, phase, time, + device->gesture_n_fingers, 0, 0); +} + +static void +emit_gesture_pinch_event (GdkWaylandDeviceData *device, + GdkTouchpadGesturePhase phase, + guint32 _time, + guint n_fingers, + gdouble dx, + gdouble dy, + gdouble scale, + gdouble angle_delta) +{ + GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (device->display); + GdkEvent *event; + + if (!device->pointer_focus) + return; + + device->time = _time; + + event = gdk_event_new (GDK_TOUCHPAD_PINCH); + event->touchpad_pinch.phase = phase; + event->touchpad_pinch.window = g_object_ref (device->pointer_focus); + gdk_event_set_device (event, device->master_pointer); + gdk_event_set_source_device (event, device->pointer); + event->touchpad_pinch.time = _time; + event->touchpad_pinch.state = device->button_modifiers | device->key_modifiers; + gdk_event_set_screen (event, display->screen); + event->touchpad_pinch.dx = dx; + event->touchpad_pinch.dy = dy; + event->touchpad_pinch.scale = scale; + event->touchpad_pinch.angle_delta = angle_delta * G_PI / 180; + event->touchpad_pinch.n_fingers = n_fingers; + + get_coordinates (device, + &event->touchpad_pinch.x, + &event->touchpad_pinch.y, + &event->touchpad_pinch.x_root, + &event->touchpad_pinch.y_root); + + GDK_NOTE (EVENTS, + g_message ("pinch event %d, coords: %f %f, device %p state %d", + event->type, event->touchpad_pinch.x, + event->touchpad_pinch.y, device, + event->touchpad_pinch.state)); + + _gdk_wayland_display_deliver_event (device->display, event); +} + +static void +gesture_pinch_begin (void *data, + struct _wl_pointer_gesture_pinch *pinch, + uint32_t serial, + uint32_t time, + struct wl_surface *surface, + uint32_t fingers) +{ + GdkWaylandDeviceData *device = data; + GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (device->display); + + _gdk_wayland_display_update_serial (display, serial); + emit_gesture_pinch_event (device, + GDK_TOUCHPAD_GESTURE_PHASE_BEGIN, + time, fingers, 0, 0, 1, 0); + device->gesture_n_fingers = fingers; +} + +static void +gesture_pinch_update (void *data, + struct _wl_pointer_gesture_pinch *pinch, + uint32_t time, + wl_fixed_t dx, + wl_fixed_t dy, + wl_fixed_t scale, + wl_fixed_t rotation) +{ + GdkWaylandDeviceData *device = data; + + emit_gesture_pinch_event (device, + GDK_TOUCHPAD_GESTURE_PHASE_UPDATE, time, + device->gesture_n_fingers, + wl_fixed_to_double (dx), + wl_fixed_to_double (dy), + wl_fixed_to_double (scale), + wl_fixed_to_double (rotation)); +} + +static void +gesture_pinch_end (void *data, + struct _wl_pointer_gesture_pinch *pinch, + uint32_t serial, + uint32_t time, + int32_t cancelled) +{ + GdkWaylandDeviceData *device = data; + GdkWaylandDisplay *display = GDK_WAYLAND_DISPLAY (device->display); + GdkTouchpadGesturePhase phase; + + _gdk_wayland_display_update_serial (display, serial); + + phase = (cancelled) ? + GDK_TOUCHPAD_GESTURE_PHASE_CANCEL : + GDK_TOUCHPAD_GESTURE_PHASE_END; + + emit_gesture_pinch_event (device, phase, + time, device->gesture_n_fingers, + 0, 0, 1, 0); +} + static const struct wl_pointer_listener pointer_listener = { pointer_handle_enter, pointer_handle_leave, @@ -1678,6 +1892,18 @@ static const struct wl_touch_listener touch_listener = { touch_handle_cancel }; +static const struct _wl_pointer_gesture_swipe_listener gesture_swipe_listener = { + gesture_swipe_begin, + gesture_swipe_update, + gesture_swipe_end +}; + +static const struct _wl_pointer_gesture_pinch_listener gesture_pinch_listener = { + gesture_pinch_begin, + gesture_pinch_update, + gesture_pinch_end +}; + static void seat_handle_capabilities (void *data, struct wl_seat *seat, @@ -1685,6 +1911,7 @@ seat_handle_capabilities (void *data, { GdkWaylandDeviceData *device = data; GdkWaylandDeviceManager *device_manager = GDK_WAYLAND_DEVICE_MANAGER (device->device_manager); + GdkWaylandDisplay *wayland_display = GDK_WAYLAND_DISPLAY (device->display); GDK_NOTE (MISC, g_message ("seat %p with %s%s%s", seat, @@ -1715,6 +1942,24 @@ seat_handle_capabilities (void *data, device->drop_context = _gdk_wayland_drop_context_new (device->master_pointer, device->data_device); + if (wayland_display->pointer_gestures) + { + device->wl_pointer_gesture_swipe = + _wl_pointer_gestures_get_swipe_gesture (wayland_display->pointer_gestures, + device->wl_pointer); + _wl_pointer_gesture_swipe_set_user_data (device->wl_pointer_gesture_swipe, + device); + _wl_pointer_gesture_swipe_add_listener (device->wl_pointer_gesture_swipe, + &gesture_swipe_listener, device); + + device->wl_pointer_gesture_pinch = + _wl_pointer_gestures_get_pinch_gesture (wayland_display->pointer_gestures, + device->wl_pointer); + _wl_pointer_gesture_pinch_set_user_data (device->wl_pointer_gesture_pinch, + device); + _wl_pointer_gesture_pinch_add_listener (device->wl_pointer_gesture_pinch, + &gesture_pinch_listener, device); + } g_signal_emit_by_name (device_manager, "device-added", device->pointer); } diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c index a0a5d0cd97..149200dc31 100644 --- a/gdk/wayland/gdkdisplay-wayland.c +++ b/gdk/wayland/gdkdisplay-wayland.c @@ -35,6 +35,7 @@ #include "gdkkeysprivate.h" #include "gdkprivate-wayland.h" #include "gdkglcontext-wayland.h" +#include "pointer-gestures-client-protocol.h" /** * SECTION:wayland_interaction @@ -357,6 +358,11 @@ gdk_registry_handle_global (void *data, display_wayland->subcompositor = wl_registry_bind (display_wayland->wl_registry, id, &wl_subcompositor_interface, 1); } + else if (strcmp (interface, "_wl_pointer_gestures") == 0) + { + display_wayland->pointer_gestures = + wl_registry_bind (display_wayland->wl_registry, id, &_wl_pointer_gestures_interface, 1); + } else handled = FALSE; diff --git a/gdk/wayland/gdkdisplay-wayland.h b/gdk/wayland/gdkdisplay-wayland.h index d6e6b06103..b834fd763e 100644 --- a/gdk/wayland/gdkdisplay-wayland.h +++ b/gdk/wayland/gdkdisplay-wayland.h @@ -71,6 +71,7 @@ struct _GdkWaylandDisplay struct wl_input_device *input_device; struct wl_data_device_manager *data_device_manager; struct wl_subcompositor *subcompositor; + struct _wl_pointer_gestures *pointer_gestures; GList *async_roundtrips;