[WPE][GTK] Bump minimum versions of GLib, GTK, libsoup, ATK, GStreamer, and Cairo
[WebKit-https.git] / Source / WebKit / UIProcess / gtk / GestureController.cpp
1 /*
2  * Copyright (C) 2014 Igalia S.L.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "GestureController.h"
28
29 #include <WebCore/Scrollbar.h>
30 #include <gtk/gtk.h>
31
32 namespace WebKit {
33 using namespace WebCore;
34
35 static const double maximumZoom = 3.0;
36
37 GestureController::GestureController(GtkWidget* widget, std::unique_ptr<GestureControllerClient>&& client)
38     : m_client(WTFMove(client))
39     , m_dragGesture(widget, *m_client)
40     , m_swipeGesture(widget, *m_client)
41     , m_zoomGesture(widget, *m_client)
42     , m_longpressGesture(widget, *m_client)
43 {
44 }
45
46 bool GestureController::handleEvent(GdkEvent* event)
47 {
48     bool wasProcessingGestures = isProcessingGestures();
49     bool touchEnd;
50     m_dragGesture.handleEvent(event);
51     m_swipeGesture.handleEvent(event);
52     m_zoomGesture.handleEvent(event);
53     m_longpressGesture.handleEvent(event);
54     touchEnd = (gdk_event_get_event_type(event) == GDK_TOUCH_END) || (gdk_event_get_event_type(event) == GDK_TOUCH_CANCEL);
55     return touchEnd ? wasProcessingGestures : isProcessingGestures();
56 }
57
58 bool GestureController::isProcessingGestures() const
59 {
60     return m_dragGesture.isActive() || m_swipeGesture.isActive() || m_zoomGesture.isActive() || m_longpressGesture.isActive();
61 }
62
63 GestureController::Gesture::Gesture(GtkGesture* gesture, GestureControllerClient& client)
64     : m_gesture(adoptGRef(gesture))
65     , m_client(client)
66 {
67     gtk_event_controller_set_propagation_phase(GTK_EVENT_CONTROLLER(m_gesture.get()), GTK_PHASE_NONE);
68 }
69
70 void GestureController::Gesture::reset()
71 {
72     gtk_event_controller_reset(GTK_EVENT_CONTROLLER(m_gesture.get()));
73 }
74
75 bool GestureController::Gesture::isActive() const
76 {
77     return gtk_gesture_is_active(m_gesture.get());
78 }
79
80 void GestureController::Gesture::handleEvent(GdkEvent* event)
81 {
82     gtk_event_controller_handle_event(GTK_EVENT_CONTROLLER(m_gesture.get()), event);
83 }
84
85 void GestureController::DragGesture::startDrag(GdkEvent* event)
86 {
87     ASSERT(!m_inDrag);
88     m_client.startDrag(reinterpret_cast<GdkEventTouch*>(event), m_start);
89 }
90
91 void GestureController::DragGesture::handleDrag(GdkEvent* event, double x, double y)
92 {
93     ASSERT(m_inDrag);
94     m_client.drag(reinterpret_cast<GdkEventTouch*>(event), m_start,
95         FloatPoint::narrowPrecision((m_offset.x() - x) / Scrollbar::pixelsPerLineStep(), (m_offset.y() - y) / Scrollbar::pixelsPerLineStep()));
96 }
97
98 void GestureController::DragGesture::handleTap(GdkEvent* event)
99 {
100     ASSERT(!m_inDrag);
101     m_client.tap(reinterpret_cast<GdkEventTouch*>(event));
102 }
103
104 void GestureController::DragGesture::begin(DragGesture* dragGesture, double x, double y, GtkGesture* gesture)
105 {
106     GdkEventSequence* sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
107     gtk_gesture_set_sequence_state(gesture, sequence, GTK_EVENT_SEQUENCE_CLAIMED);
108     dragGesture->m_inDrag = false;
109     dragGesture->m_start.set(x, y);
110     dragGesture->m_offset.set(0, 0);
111
112     GtkWidget* widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture));
113     unsigned delay;
114     g_object_get(gtk_widget_get_settings(widget), "gtk-long-press-time", &delay, nullptr);
115     dragGesture->m_longPressTimeout.startOneShot(1_ms * delay);
116     dragGesture->startDrag(const_cast<GdkEvent*>(gtk_gesture_get_last_event(gesture, sequence)));
117 }
118
119 void GestureController::DragGesture::update(DragGesture* dragGesture, double x, double y, GtkGesture* gesture)
120 {
121     GdkEventSequence* sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
122     gtk_gesture_set_sequence_state(gesture, sequence, GTK_EVENT_SEQUENCE_CLAIMED);
123
124     GtkWidget* widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture));
125     if (!dragGesture->m_inDrag && gtk_drag_check_threshold(widget, dragGesture->m_start.x(), dragGesture->m_start.y(), dragGesture->m_start.x() + x, dragGesture->m_start.y() + y)) {
126         dragGesture->m_inDrag = true;
127         dragGesture->m_longPressTimeout.stop();
128     }
129
130     if (dragGesture->m_inDrag)
131         dragGesture->handleDrag(const_cast<GdkEvent*>(gtk_gesture_get_last_event(gesture, sequence)), x, y);
132     dragGesture->m_offset.set(x, y);
133 }
134
135 void GestureController::DragGesture::end(DragGesture* dragGesture, GdkEventSequence* sequence, GtkGesture* gesture)
136 {
137     dragGesture->m_longPressTimeout.stop();
138     if (!gtk_gesture_handles_sequence(gesture, sequence)) {
139         gtk_gesture_set_state(gesture, GTK_EVENT_SEQUENCE_DENIED);
140         return;
141     }
142     if (!dragGesture->m_inDrag) {
143         dragGesture->handleTap(const_cast<GdkEvent*>(gtk_gesture_get_last_event(gesture, sequence)));
144         gtk_gesture_set_state(gesture, GTK_EVENT_SEQUENCE_DENIED);
145     }
146 }
147
148 void GestureController::DragGesture::longPressFired()
149 {
150     m_inDrag = true;
151 }
152
153 GestureController::DragGesture::DragGesture(GtkWidget* widget, GestureControllerClient& client)
154     : Gesture(gtk_gesture_drag_new(widget), client)
155     , m_longPressTimeout(RunLoop::main(), this, &GestureController::DragGesture::longPressFired)
156 {
157     gtk_gesture_single_set_touch_only(GTK_GESTURE_SINGLE(m_gesture.get()), TRUE);
158     g_signal_connect_swapped(m_gesture.get(), "drag-begin", G_CALLBACK(begin), this);
159     g_signal_connect_swapped(m_gesture.get(), "drag-update", G_CALLBACK(update), this);
160     g_signal_connect_swapped(m_gesture.get(), "end", G_CALLBACK(end), this);
161 }
162
163 void GestureController::SwipeGesture::startMomentumScroll(GdkEvent* event, double velocityX, double velocityY)
164 {
165     m_client.swipe(reinterpret_cast<GdkEventTouch*>(event), FloatPoint::narrowPrecision(velocityX, velocityY));
166 }
167
168 void GestureController::SwipeGesture::swipe(SwipeGesture* swipeGesture, double velocityX, double velocityY, GtkGesture* gesture)
169 {
170     GdkEventSequence* sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
171     if (!gtk_gesture_handles_sequence(gesture, sequence))
172         return;
173
174     gtk_gesture_set_sequence_state(gesture, sequence, GTK_EVENT_SEQUENCE_CLAIMED);
175
176     swipeGesture->startMomentumScroll(const_cast<GdkEvent*>(gtk_gesture_get_last_event(gesture, sequence)), velocityX, velocityY);
177 }
178
179 GestureController::SwipeGesture::SwipeGesture(GtkWidget* widget, GestureControllerClient& client)
180     : Gesture(gtk_gesture_swipe_new(widget), client)
181 {
182     gtk_gesture_single_set_touch_only(GTK_GESTURE_SINGLE(m_gesture.get()), TRUE);
183     g_signal_connect_swapped(m_gesture.get(), "swipe", G_CALLBACK(swipe), this);
184 }
185
186 void GestureController::ZoomGesture::begin(ZoomGesture* zoomGesture, GdkEventSequence*, GtkGesture* gesture)
187 {
188     gtk_gesture_set_state(gesture, GTK_EVENT_SEQUENCE_CLAIMED);
189     zoomGesture->startZoom();
190 }
191
192 IntPoint GestureController::ZoomGesture::center() const
193 {
194     double x, y;
195     gtk_gesture_get_bounding_box_center(m_gesture.get(), &x, &y);
196     return IntPoint(x, y);
197 }
198
199 void GestureController::ZoomGesture::startZoom()
200 {
201     m_client.startZoom(center(), m_initialScale, m_initialPoint);
202 }
203
204 void GestureController::ZoomGesture::handleZoom()
205 {
206     FloatPoint scaledZoomCenter(m_initialPoint);
207     scaledZoomCenter.scale(m_scale);
208
209     m_client.zoom(m_scale, WebCore::roundedIntPoint(FloatPoint(scaledZoomCenter - m_viewPoint)));
210 }
211
212 void GestureController::ZoomGesture::scaleChanged(ZoomGesture* zoomGesture, double scale, GtkGesture*)
213 {
214     zoomGesture->m_scale = zoomGesture->m_initialScale * scale;
215     if (zoomGesture->m_scale < 1.0)
216         zoomGesture->m_scale = 1.0;
217     if (zoomGesture->m_scale > maximumZoom)
218         zoomGesture->m_scale = maximumZoom;
219
220     zoomGesture->m_viewPoint = zoomGesture->center();
221
222     if (zoomGesture->m_idle.isActive())
223         return;
224
225     zoomGesture->m_idle.startOneShot(0_s);
226 }
227
228 GestureController::ZoomGesture::ZoomGesture(GtkWidget* widget, GestureControllerClient& client)
229     : Gesture(gtk_gesture_zoom_new(widget), client)
230     , m_idle(RunLoop::main(), this, &GestureController::ZoomGesture::handleZoom)
231 {
232     g_signal_connect_swapped(m_gesture.get(), "begin", G_CALLBACK(begin), this);
233     g_signal_connect_swapped(m_gesture.get(), "scale-changed", G_CALLBACK(scaleChanged), this);
234 }
235
236 void GestureController::LongPressGesture::longPressed(GdkEvent* event)
237 {
238     m_client.longPress(reinterpret_cast<GdkEventTouch*>(event));
239 }
240
241 void GestureController::LongPressGesture::pressed(LongPressGesture* longpressGesture, double x, double y, GtkGesture* gesture)
242 {
243     GdkEventSequence* sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
244     if (!gtk_gesture_handles_sequence(gesture, sequence))
245         return;
246
247     gtk_gesture_set_sequence_state(gesture, sequence, GTK_EVENT_SEQUENCE_CLAIMED);
248
249     longpressGesture->longPressed(const_cast<GdkEvent*>(gtk_gesture_get_last_event(gesture, sequence)));
250 }
251
252 GestureController::LongPressGesture::LongPressGesture(GtkWidget* widget, GestureControllerClient& client)
253     : Gesture(gtk_gesture_long_press_new(widget), client)
254 {
255     gtk_gesture_single_set_touch_only(GTK_GESTURE_SINGLE(m_gesture.get()), TRUE);
256     g_signal_connect_swapped(m_gesture.get(), "pressed", G_CALLBACK(pressed), this);
257 }
258
259 } // namespace WebKit