1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2014, Red Hat, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Author(s): Carlos Garnacho <carlosg@gnome.org>
18 */
19
20 /**
21 * SECTION:gtkgesturedrag
22 * @Short_description: Drag gesture
23 * @Title: GtkGestureDrag
24 * @See_also: #GtkGestureSwipe
25 *
26 * #GtkGestureDrag is a #GtkGesture implementation that recognizes drag
27 * operations. The drag operation itself can be tracked throught the
28 * #GtkGestureDrag::drag-begin, #GtkGestureDrag::drag-update and
29 * #GtkGestureDrag::drag-end signals, or the relevant coordinates be
30 * extracted through gtk_gesture_drag_get_offset() and
31 * gtk_gesture_drag_get_start_point().
32 */
33 #include "config.h"
34 #include "gtkgesturedrag.h"
35 #include "gtkgesturedragprivate.h"
36 #include "gtkintl.h"
37 #include "gtkmarshalers.h"
38
39 typedef struct _GtkGestureDragPrivate GtkGestureDragPrivate;
40 typedef struct _EventData EventData;
41
42 struct _GtkGestureDragPrivate
43 {
44 gdouble start_x;
45 gdouble start_y;
46 gdouble last_x;
47 gdouble last_y;
48 };
49
50 enum {
51 DRAG_BEGIN,
52 DRAG_UPDATE,
53 DRAG_END,
54 N_SIGNALS
55 };
56
57 static guint signals[N_SIGNALS] = { 0 };
58
G_DEFINE_TYPE_WITH_PRIVATE(GtkGestureDrag,gtk_gesture_drag,GTK_TYPE_GESTURE_SINGLE)59 G_DEFINE_TYPE_WITH_PRIVATE (GtkGestureDrag, gtk_gesture_drag, GTK_TYPE_GESTURE_SINGLE)
60
61 static gboolean
62 gtk_gesture_drag_filter_event (GtkEventController *controller,
63 const GdkEvent *event)
64 {
65 /* Let touchpad swipe events go through, only if they match n-points */
66 if (event->type == GDK_TOUCHPAD_SWIPE)
67 {
68 guint n_points;
69
70 g_object_get (G_OBJECT (controller), "n-points", &n_points, NULL);
71
72 if (event->touchpad_swipe.n_fingers == n_points)
73 return FALSE;
74 else
75 return TRUE;
76 }
77
78 return GTK_EVENT_CONTROLLER_CLASS (gtk_gesture_drag_parent_class)->filter_event (controller, event);
79 }
80
81 static void
gtk_gesture_drag_begin(GtkGesture * gesture,GdkEventSequence * sequence)82 gtk_gesture_drag_begin (GtkGesture *gesture,
83 GdkEventSequence *sequence)
84 {
85 GtkGestureDragPrivate *priv;
86 GdkEventSequence *current;
87
88 current = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
89
90 priv = gtk_gesture_drag_get_instance_private (GTK_GESTURE_DRAG (gesture));
91 gtk_gesture_get_point (gesture, current, &priv->start_x, &priv->start_y);
92 priv->last_x = priv->start_x;
93 priv->last_y = priv->start_y;
94
95 g_signal_emit (gesture, signals[DRAG_BEGIN], 0, priv->start_x, priv->start_y);
96 }
97
98 static void
gtk_gesture_drag_update(GtkGesture * gesture,GdkEventSequence * sequence)99 gtk_gesture_drag_update (GtkGesture *gesture,
100 GdkEventSequence *sequence)
101 {
102 GtkGestureDragPrivate *priv;
103 gdouble x, y;
104
105 priv = gtk_gesture_drag_get_instance_private (GTK_GESTURE_DRAG (gesture));
106 gtk_gesture_get_point (gesture, sequence, &priv->last_x, &priv->last_y);
107 x = priv->last_x - priv->start_x;
108 y = priv->last_y - priv->start_y;
109
110 g_signal_emit (gesture, signals[DRAG_UPDATE], 0, x, y);
111 }
112
113 static void
gtk_gesture_drag_end(GtkGesture * gesture,GdkEventSequence * sequence)114 gtk_gesture_drag_end (GtkGesture *gesture,
115 GdkEventSequence *sequence)
116 {
117 GtkGestureDragPrivate *priv;
118 GdkEventSequence *current;
119 gdouble x, y;
120
121 current = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
122
123 priv = gtk_gesture_drag_get_instance_private (GTK_GESTURE_DRAG (gesture));
124 gtk_gesture_get_point (gesture, current, &priv->last_x, &priv->last_y);
125 x = priv->last_x - priv->start_x;
126 y = priv->last_y - priv->start_y;
127
128 g_signal_emit (gesture, signals[DRAG_END], 0, x, y);
129 }
130
131 static void
gtk_gesture_drag_class_init(GtkGestureDragClass * klass)132 gtk_gesture_drag_class_init (GtkGestureDragClass *klass)
133 {
134 GtkGestureClass *gesture_class = GTK_GESTURE_CLASS (klass);
135 GtkEventControllerClass *event_controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
136
137 event_controller_class->filter_event = gtk_gesture_drag_filter_event;
138
139 gesture_class->begin = gtk_gesture_drag_begin;
140 gesture_class->update = gtk_gesture_drag_update;
141 gesture_class->end = gtk_gesture_drag_end;
142
143 /**
144 * GtkGestureDrag::drag-begin:
145 * @gesture: the object which received the signal
146 * @start_x: X coordinate, relative to the widget allocation
147 * @start_y: Y coordinate, relative to the widget allocation
148 *
149 * This signal is emitted whenever dragging starts.
150 *
151 * Since: 3.14
152 */
153 signals[DRAG_BEGIN] =
154 g_signal_new (I_("drag-begin"),
155 G_TYPE_FROM_CLASS (klass),
156 G_SIGNAL_RUN_LAST,
157 G_STRUCT_OFFSET (GtkGestureDragClass, drag_begin),
158 NULL, NULL,
159 _gtk_marshal_VOID__DOUBLE_DOUBLE,
160 G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
161 g_signal_set_va_marshaller (signals[DRAG_BEGIN],
162 G_TYPE_FROM_CLASS (klass),
163 _gtk_marshal_VOID__DOUBLE_DOUBLEv);
164 /**
165 * GtkGestureDrag::drag-update:
166 * @gesture: the object which received the signal
167 * @offset_x: X offset, relative to the start point
168 * @offset_y: Y offset, relative to the start point
169 *
170 * This signal is emitted whenever the dragging point moves.
171 *
172 * Since: 3.14
173 */
174 signals[DRAG_UPDATE] =
175 g_signal_new (I_("drag-update"),
176 G_TYPE_FROM_CLASS (klass),
177 G_SIGNAL_RUN_LAST,
178 G_STRUCT_OFFSET (GtkGestureDragClass, drag_update),
179 NULL, NULL,
180 _gtk_marshal_VOID__DOUBLE_DOUBLE,
181 G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
182 g_signal_set_va_marshaller (signals[DRAG_UPDATE],
183 G_TYPE_FROM_CLASS (klass),
184 _gtk_marshal_VOID__DOUBLE_DOUBLEv);
185 /**
186 * GtkGestureDrag::drag-end:
187 * @gesture: the object which received the signal
188 * @offset_x: X offset, relative to the start point
189 * @offset_y: Y offset, relative to the start point
190 *
191 * This signal is emitted whenever the dragging is finished.
192 *
193 * Since: 3.14
194 */
195 signals[DRAG_END] =
196 g_signal_new (I_("drag-end"),
197 G_TYPE_FROM_CLASS (klass),
198 G_SIGNAL_RUN_LAST,
199 G_STRUCT_OFFSET (GtkGestureDragClass, drag_end),
200 NULL, NULL,
201 _gtk_marshal_VOID__DOUBLE_DOUBLE,
202 G_TYPE_NONE, 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
203 g_signal_set_va_marshaller (signals[DRAG_END],
204 G_TYPE_FROM_CLASS (klass),
205 _gtk_marshal_VOID__DOUBLE_DOUBLEv);
206 }
207
208 static void
gtk_gesture_drag_init(GtkGestureDrag * gesture)209 gtk_gesture_drag_init (GtkGestureDrag *gesture)
210 {
211 }
212
213 /**
214 * gtk_gesture_drag_new:
215 * @widget: a #GtkWidget
216 *
217 * Returns a newly created #GtkGesture that recognizes drags.
218 *
219 * Returns: a newly created #GtkGestureDrag
220 *
221 * Since: 3.14
222 **/
223 GtkGesture *
gtk_gesture_drag_new(GtkWidget * widget)224 gtk_gesture_drag_new (GtkWidget *widget)
225 {
226 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
227
228 return g_object_new (GTK_TYPE_GESTURE_DRAG,
229 "widget", widget,
230 NULL);
231 }
232
233 /**
234 * gtk_gesture_drag_get_start_point:
235 * @gesture: a #GtkGesture
236 * @x: (out) (nullable): X coordinate for the drag start point
237 * @y: (out) (nullable): Y coordinate for the drag start point
238 *
239 * If the @gesture is active, this function returns %TRUE
240 * and fills in @x and @y with the drag start coordinates,
241 * in window-relative coordinates.
242 *
243 * Returns: %TRUE if the gesture is active
244 *
245 * Since: 3.14
246 **/
247 gboolean
gtk_gesture_drag_get_start_point(GtkGestureDrag * gesture,gdouble * x,gdouble * y)248 gtk_gesture_drag_get_start_point (GtkGestureDrag *gesture,
249 gdouble *x,
250 gdouble *y)
251 {
252 GtkGestureDragPrivate *priv;
253 GdkEventSequence *sequence;
254
255 g_return_val_if_fail (GTK_IS_GESTURE_DRAG (gesture), FALSE);
256
257 sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
258
259 if (!gtk_gesture_handles_sequence (GTK_GESTURE (gesture), sequence))
260 return FALSE;
261
262 priv = gtk_gesture_drag_get_instance_private (gesture);
263
264 if (x)
265 *x = priv->start_x;
266
267 if (y)
268 *y = priv->start_y;
269
270 return TRUE;
271 }
272
273 /**
274 * gtk_gesture_drag_get_offset:
275 * @gesture: a #GtkGesture
276 * @x: (out) (nullable): X offset for the current point
277 * @y: (out) (nullable): Y offset for the current point
278 *
279 * If the @gesture is active, this function returns %TRUE and
280 * fills in @x and @y with the coordinates of the current point,
281 * as an offset to the starting drag point.
282 *
283 * Returns: %TRUE if the gesture is active
284 *
285 * Since: 3.14
286 **/
287 gboolean
gtk_gesture_drag_get_offset(GtkGestureDrag * gesture,gdouble * x,gdouble * y)288 gtk_gesture_drag_get_offset (GtkGestureDrag *gesture,
289 gdouble *x,
290 gdouble *y)
291 {
292 GtkGestureDragPrivate *priv;
293 GdkEventSequence *sequence;
294
295 g_return_val_if_fail (GTK_IS_GESTURE_DRAG (gesture), FALSE);
296
297 sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
298
299 if (!gtk_gesture_handles_sequence (GTK_GESTURE (gesture), sequence))
300 return FALSE;
301
302 priv = gtk_gesture_drag_get_instance_private (gesture);
303
304 if (x)
305 *x = priv->last_x - priv->start_x;
306
307 if (y)
308 *y = priv->last_y - priv->start_y;
309
310 return TRUE;
311 }
312