Configure serviceWorkerRegistrationDirectory on the web site data store and move...
[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 #if HAVE(GTK_GESTURES)
30
31 #include <WebCore/Scrollbar.h>
32 #include <gtk/gtk.h>
33
34 using namespace WebCore;
35
36 namespace WebKit {
37
38 GestureController::GestureController(GtkWidget* widget, std::unique_ptr<GestureControllerClient>&& client)
39     : m_client(WTFMove(client))
40     , m_dragGesture(widget, *m_client)
41     , m_swipeGesture(widget, *m_client)
42     , m_zoomGesture(widget, *m_client)
43     , m_longpressGesture(widget, *m_client)
44 {
45 }
46
47 bool GestureController::handleEvent(GdkEvent* event)
48 {
49     bool wasProcessingGestures = isProcessingGestures();
50     bool touchEnd;
51     m_dragGesture.handleEvent(event);
52     m_swipeGesture.handleEvent(event);
53     m_zoomGesture.handleEvent(event);
54     m_longpressGesture.handleEvent(event);
55     touchEnd = (event->type == GDK_TOUCH_END) || (event->type == GDK_TOUCH_CANCEL);
56     return touchEnd ? wasProcessingGestures : isProcessingGestures();
57 }
58
59 bool GestureController::isProcessingGestures() const
60 {
61     return m_dragGesture.isActive() || m_swipeGesture.isActive() || m_zoomGesture.isActive() || m_longpressGesture.isActive();
62 }
63
64 GestureController::Gesture::Gesture(GtkGesture* gesture, GestureControllerClient& client)
65     : m_gesture(adoptGRef(gesture))
66     , m_client(client)
67 {
68     gtk_event_controller_set_propagation_phase(GTK_EVENT_CONTROLLER(m_gesture.get()), GTK_PHASE_NONE);
69 }
70
71 void GestureController::Gesture::reset()
72 {
73     gtk_event_controller_reset(GTK_EVENT_CONTROLLER(m_gesture.get()));
74 }
75
76 bool GestureController::Gesture::isActive() const
77 {
78     return gtk_gesture_is_active(m_gesture.get());
79 }
80
81 void GestureController::Gesture::handleEvent(GdkEvent* event)
82 {
83     gtk_event_controller_handle_event(GTK_EVENT_CONTROLLER(m_gesture.get()), event);
84 }
85
86 void GestureController::DragGesture::startDrag(GdkEvent* event)
87 {
88     ASSERT(!m_inDrag);
89     m_client.startDrag(reinterpret_cast<GdkEventTouch*>(event), m_start);
90 }
91
92 void GestureController::DragGesture::handleDrag(GdkEvent* event, double x, double y)
93 {
94     ASSERT(m_inDrag);
95     m_client.drag(reinterpret_cast<GdkEventTouch*>(event), m_start,
96         FloatPoint::narrowPrecision((m_offset.x() - x) / Scrollbar::pixelsPerLineStep(), (m_offset.y() - y) / Scrollbar::pixelsPerLineStep()));
97 }
98
99 void GestureController::DragGesture::handleTap(GdkEvent* event)
100 {
101     ASSERT(!m_inDrag);
102     m_client.tap(reinterpret_cast<GdkEventTouch*>(event));
103 }
104
105 void GestureController::DragGesture::begin(DragGesture* dragGesture, double x, double y, GtkGesture* gesture)
106 {
107     GdkEventSequence* sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
108     gtk_gesture_set_sequence_state(gesture, sequence, GTK_EVENT_SEQUENCE_CLAIMED);
109     dragGesture->m_inDrag = false;
110     dragGesture->m_start.set(x, y);
111     dragGesture->m_offset.set(0, 0);
112
113     GtkWidget* widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture));
114     unsigned delay;
115     g_object_get(gtk_widget_get_settings(widget), "gtk-long-press-time", &delay, nullptr);
116     dragGesture->m_longPressTimeout.startOneShot(1_ms * delay);
117     dragGesture->startDrag(const_cast<GdkEvent*>(gtk_gesture_get_last_event(gesture, sequence)));
118 }
119
120 void GestureController::DragGesture::update(DragGesture* dragGesture, double x, double y, GtkGesture* gesture)
121 {
122     GdkEventSequence* sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
123     gtk_gesture_set_sequence_state(gesture, sequence, GTK_EVENT_SEQUENCE_CLAIMED);
124
125     GtkWidget* widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture));
126     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)) {
127         dragGesture->m_inDrag = true;
128         dragGesture->m_longPressTimeout.stop();
129     }
130
131     if (dragGesture->m_inDrag)
132         dragGesture->handleDrag(const_cast<GdkEvent*>(gtk_gesture_get_last_event(gesture, sequence)), x, y);
133     dragGesture->m_offset.set(x, y);
134 }
135
136 void GestureController::DragGesture::end(DragGesture* dragGesture, GdkEventSequence* sequence, GtkGesture* gesture)
137 {
138     dragGesture->m_longPressTimeout.stop();
139     if (!gtk_gesture_handles_sequence(gesture, sequence)) {
140         gtk_gesture_set_state(gesture, GTK_EVENT_SEQUENCE_DENIED);
141         return;
142     }
143     if (!dragGesture->m_inDrag) {
144         dragGesture->handleTap(const_cast<GdkEvent*>(gtk_gesture_get_last_event(gesture, sequence)));
145         gtk_gesture_set_state(gesture, GTK_EVENT_SEQUENCE_DENIED);
146     }
147 }
148
149 void GestureController::DragGesture::longPressFired()
150 {
151     m_inDrag = true;
152 }
153
154 GestureController::DragGesture::DragGesture(GtkWidget* widget, GestureControllerClient& client)
155     : Gesture(gtk_gesture_drag_new(widget), client)
156     , m_longPressTimeout(RunLoop::main(), this, &GestureController::DragGesture::longPressFired)
157 {
158     gtk_gesture_single_set_touch_only(GTK_GESTURE_SINGLE(m_gesture.get()), TRUE);
159     g_signal_connect_swapped(m_gesture.get(), "drag-begin", G_CALLBACK(begin), this);
160     g_signal_connect_swapped(m_gesture.get(), "drag-update", G_CALLBACK(update), this);
161     g_signal_connect_swapped(m_gesture.get(), "end", G_CALLBACK(end), this);
162 }
163
164 void GestureController::SwipeGesture::startMomentumScroll(GdkEvent* event, double velocityX, double velocityY)
165 {
166     m_client.swipe(reinterpret_cast<GdkEventTouch*>(event), FloatPoint::narrowPrecision(velocityX, velocityY));
167 }
168
169 void GestureController::SwipeGesture::swipe(SwipeGesture* swipeGesture, double velocityX, double velocityY, GtkGesture* gesture)
170 {
171     GdkEventSequence* sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
172     if (!gtk_gesture_handles_sequence(gesture, sequence))
173         return;
174
175     gtk_gesture_set_sequence_state(gesture, sequence, GTK_EVENT_SEQUENCE_CLAIMED);
176
177     swipeGesture->startMomentumScroll(const_cast<GdkEvent*>(gtk_gesture_get_last_event(gesture, sequence)), velocityX, velocityY);
178 }
179
180 GestureController::SwipeGesture::SwipeGesture(GtkWidget* widget, GestureControllerClient& client)
181     : Gesture(gtk_gesture_swipe_new(widget), client)
182 {
183     gtk_gesture_single_set_touch_only(GTK_GESTURE_SINGLE(m_gesture.get()), TRUE);
184     g_signal_connect_swapped(m_gesture.get(), "swipe", G_CALLBACK(swipe), this);
185 }
186
187 void GestureController::ZoomGesture::begin(ZoomGesture* zoomGesture, GdkEventSequence*, GtkGesture* gesture)
188 {
189     gtk_gesture_set_state(gesture, GTK_EVENT_SEQUENCE_CLAIMED);
190     zoomGesture->startZoom();
191 }
192
193 IntPoint GestureController::ZoomGesture::center() const
194 {
195     double x, y;
196     gtk_gesture_get_bounding_box_center(m_gesture.get(), &x, &y);
197     return IntPoint(x, y);
198 }
199
200 void GestureController::ZoomGesture::startZoom()
201 {
202     m_client.startZoom(center(), m_initialScale, m_initialPoint);
203 }
204
205 void GestureController::ZoomGesture::handleZoom()
206 {
207     m_client.zoom(m_scale);
208 }
209
210 void GestureController::ZoomGesture::scaleChanged(ZoomGesture* zoomGesture, double scale, GtkGesture*)
211 {
212     zoomGesture->m_scale = zoomGesture->m_initialScale * scale;
213     zoomGesture->m_viewPoint = zoomGesture->center();
214     if (zoomGesture->m_idle.isActive())
215         return;
216
217     zoomGesture->m_idle.startOneShot(0_s);
218 }
219
220 GestureController::ZoomGesture::ZoomGesture(GtkWidget* widget, GestureControllerClient& client)
221     : Gesture(gtk_gesture_zoom_new(widget), client)
222     , m_idle(RunLoop::main(), this, &GestureController::ZoomGesture::handleZoom)
223 {
224     g_signal_connect_swapped(m_gesture.get(), "begin", G_CALLBACK(begin), this);
225     g_signal_connect_swapped(m_gesture.get(), "scale-changed", G_CALLBACK(scaleChanged), this);
226 }
227
228 void GestureController::LongPressGesture::longPressed(GdkEvent* event)
229 {
230     m_client.longPress(reinterpret_cast<GdkEventTouch*>(event));
231 }
232
233 void GestureController::LongPressGesture::pressed(LongPressGesture* longpressGesture, double x, double y, GtkGesture* gesture)
234 {
235     GdkEventSequence* sequence = gtk_gesture_single_get_current_sequence(GTK_GESTURE_SINGLE(gesture));
236     if (!gtk_gesture_handles_sequence(gesture, sequence))
237         return;
238
239     gtk_gesture_set_sequence_state(gesture, sequence, GTK_EVENT_SEQUENCE_CLAIMED);
240
241     longpressGesture->longPressed(const_cast<GdkEvent*>(gtk_gesture_get_last_event(gesture, sequence)));
242 }
243
244 GestureController::LongPressGesture::LongPressGesture(GtkWidget* widget, GestureControllerClient& client)
245     : Gesture(gtk_gesture_long_press_new(widget), client)
246 {
247     gtk_gesture_single_set_touch_only(GTK_GESTURE_SINGLE(m_gesture.get()), TRUE);
248     g_signal_connect_swapped(m_gesture.get(), "pressed", G_CALLBACK(pressed), this);
249 }
250
251 } // namespace WebKit
252
253 #endif // HAVE(GTK_GESTURES)