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 * GtkGestureDrag:
22 *
23 * `GtkGestureDrag` is a `GtkGesture` implementation for drags.
24 *
25 * The drag operation itself can be tracked throughout the
26 * [signal@Gtk.GestureDrag::drag-begin],
27 * [signal@Gtk.GestureDrag::drag-update] and
28 * [signal@Gtk.GestureDrag::drag-end] signals, and the relevant
29 * coordinates can be extracted through
30 * [method@Gtk.GestureDrag.get_offset] and
31 * [method@Gtk.GestureDrag.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
39typedef struct _GtkGestureDragPrivate GtkGestureDragPrivate;
40typedef struct _EventData EventData;
41
42struct _GtkGestureDragPrivate
43{
44 double start_x;
45 double start_y;
46 double last_x;
47 double last_y;
48};
49
50enum {
51 DRAG_BEGIN,
52 DRAG_UPDATE,
53 DRAG_END,
54 N_SIGNALS
55};
56
57static guint signals[N_SIGNALS] = { 0 };
58
59G_DEFINE_TYPE_WITH_PRIVATE (GtkGestureDrag, gtk_gesture_drag, GTK_TYPE_GESTURE_SINGLE)
60
61static gboolean
62gtk_gesture_drag_filter_event (GtkEventController *controller,
63 GdkEvent *event)
64{
65 /* Let touchpad swipe events go through, only if they match n-points */
66 if (gdk_event_get_event_type (event) == GDK_TOUCHPAD_SWIPE)
67 {
68 guint n_points;
69 guint n_fingers;
70
71 g_object_get (G_OBJECT (controller), first_property_name: "n-points", &n_points, NULL);
72 n_fingers = gdk_touchpad_event_get_n_fingers (event);
73
74 if (n_fingers == n_points)
75 return FALSE;
76 else
77 return TRUE;
78 }
79
80 return GTK_EVENT_CONTROLLER_CLASS (gtk_gesture_drag_parent_class)->filter_event (controller, event);
81}
82
83static void
84gtk_gesture_drag_begin (GtkGesture *gesture,
85 GdkEventSequence *sequence)
86{
87 GtkGestureDragPrivate *priv;
88 GdkEventSequence *current;
89
90 current = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
91
92 priv = gtk_gesture_drag_get_instance_private (GTK_GESTURE_DRAG (gesture));
93 gtk_gesture_get_point (gesture, sequence: current, x: &priv->start_x, y: &priv->start_y);
94 priv->last_x = priv->start_x;
95 priv->last_y = priv->start_y;
96
97 g_signal_emit (instance: gesture, signal_id: signals[DRAG_BEGIN], detail: 0, priv->start_x, priv->start_y);
98}
99
100static void
101gtk_gesture_drag_update (GtkGesture *gesture,
102 GdkEventSequence *sequence)
103{
104 GtkGestureDragPrivate *priv;
105 double x, y;
106
107 priv = gtk_gesture_drag_get_instance_private (GTK_GESTURE_DRAG (gesture));
108 gtk_gesture_get_point (gesture, sequence, x: &priv->last_x, y: &priv->last_y);
109 x = priv->last_x - priv->start_x;
110 y = priv->last_y - priv->start_y;
111
112 g_signal_emit (instance: gesture, signal_id: signals[DRAG_UPDATE], detail: 0, x, y);
113}
114
115static void
116gtk_gesture_drag_end (GtkGesture *gesture,
117 GdkEventSequence *sequence)
118{
119 GtkGestureDragPrivate *priv;
120 GdkEventSequence *current;
121 double x, y;
122
123 current = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
124
125 priv = gtk_gesture_drag_get_instance_private (GTK_GESTURE_DRAG (gesture));
126 gtk_gesture_get_point (gesture, sequence: current, x: &priv->last_x, y: &priv->last_y);
127 x = priv->last_x - priv->start_x;
128 y = priv->last_y - priv->start_y;
129
130 g_signal_emit (instance: gesture, signal_id: signals[DRAG_END], detail: 0, x, y);
131}
132
133static void
134gtk_gesture_drag_class_init (GtkGestureDragClass *klass)
135{
136 GtkGestureClass *gesture_class = GTK_GESTURE_CLASS (klass);
137 GtkEventControllerClass *event_controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
138
139 event_controller_class->filter_event = gtk_gesture_drag_filter_event;
140
141 gesture_class->begin = gtk_gesture_drag_begin;
142 gesture_class->update = gtk_gesture_drag_update;
143 gesture_class->end = gtk_gesture_drag_end;
144
145 /**
146 * GtkGestureDrag::drag-begin:
147 * @gesture: the object which received the signal
148 * @start_x: X coordinate, relative to the widget allocation
149 * @start_y: Y coordinate, relative to the widget allocation
150 *
151 * Emitted whenever dragging starts.
152 */
153 signals[DRAG_BEGIN] =
154 g_signal_new (I_("drag-begin"),
155 G_TYPE_FROM_CLASS (klass),
156 signal_flags: G_SIGNAL_RUN_LAST,
157 G_STRUCT_OFFSET (GtkGestureDragClass, drag_begin),
158 NULL, NULL,
159 c_marshaller: _gtk_marshal_VOID__DOUBLE_DOUBLE,
160 G_TYPE_NONE, n_params: 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
161 g_signal_set_va_marshaller (signal_id: signals[DRAG_BEGIN],
162 G_TYPE_FROM_CLASS (klass),
163 va_marshaller: _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 * Emitted whenever the dragging point moves.
171 */
172 signals[DRAG_UPDATE] =
173 g_signal_new (I_("drag-update"),
174 G_TYPE_FROM_CLASS (klass),
175 signal_flags: G_SIGNAL_RUN_LAST,
176 G_STRUCT_OFFSET (GtkGestureDragClass, drag_update),
177 NULL, NULL,
178 c_marshaller: _gtk_marshal_VOID__DOUBLE_DOUBLE,
179 G_TYPE_NONE, n_params: 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
180 g_signal_set_va_marshaller (signal_id: signals[DRAG_UPDATE],
181 G_TYPE_FROM_CLASS (klass),
182 va_marshaller: _gtk_marshal_VOID__DOUBLE_DOUBLEv);
183 /**
184 * GtkGestureDrag::drag-end:
185 * @gesture: the object which received the signal
186 * @offset_x: X offset, relative to the start point
187 * @offset_y: Y offset, relative to the start point
188 *
189 * Emitted whenever the dragging is finished.
190 */
191 signals[DRAG_END] =
192 g_signal_new (I_("drag-end"),
193 G_TYPE_FROM_CLASS (klass),
194 signal_flags: G_SIGNAL_RUN_LAST,
195 G_STRUCT_OFFSET (GtkGestureDragClass, drag_end),
196 NULL, NULL,
197 c_marshaller: _gtk_marshal_VOID__DOUBLE_DOUBLE,
198 G_TYPE_NONE, n_params: 2, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
199 g_signal_set_va_marshaller (signal_id: signals[DRAG_END],
200 G_TYPE_FROM_CLASS (klass),
201 va_marshaller: _gtk_marshal_VOID__DOUBLE_DOUBLEv);
202}
203
204static void
205gtk_gesture_drag_init (GtkGestureDrag *gesture)
206{
207}
208
209/**
210 * gtk_gesture_drag_new:
211 *
212 * Returns a newly created `GtkGesture` that recognizes drags.
213 *
214 * Returns: a newly created `GtkGestureDrag`
215 **/
216GtkGesture *
217gtk_gesture_drag_new (void)
218{
219 return g_object_new (GTK_TYPE_GESTURE_DRAG,
220 NULL);
221}
222
223/**
224 * gtk_gesture_drag_get_start_point:
225 * @gesture: a `GtkGesture`
226 * @x: (out) (nullable): X coordinate for the drag start point
227 * @y: (out) (nullable): Y coordinate for the drag start point
228 *
229 * Gets the point where the drag started.
230 *
231 * If the @gesture is active, this function returns %TRUE
232 * and fills in @x and @y with the drag start coordinates,
233 * in surface-relative coordinates.
234 *
235 * Returns: %TRUE if the gesture is active
236 */
237gboolean
238gtk_gesture_drag_get_start_point (GtkGestureDrag *gesture,
239 double *x,
240 double *y)
241{
242 GtkGestureDragPrivate *priv;
243 GdkEventSequence *sequence;
244
245 g_return_val_if_fail (GTK_IS_GESTURE_DRAG (gesture), FALSE);
246
247 sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
248
249 if (!gtk_gesture_handles_sequence (GTK_GESTURE (gesture), sequence))
250 return FALSE;
251
252 priv = gtk_gesture_drag_get_instance_private (self: gesture);
253
254 if (x)
255 *x = priv->start_x;
256
257 if (y)
258 *y = priv->start_y;
259
260 return TRUE;
261}
262
263/**
264 * gtk_gesture_drag_get_offset:
265 * @gesture: a `GtkGesture`
266 * @x: (out) (nullable): X offset for the current point
267 * @y: (out) (nullable): Y offset for the current point
268 *
269 * Gets the offset from the start point.
270 *
271 * If the @gesture is active, this function returns %TRUE and
272 * fills in @x and @y with the coordinates of the current point,
273 * as an offset to the starting drag point.
274 *
275 * Returns: %TRUE if the gesture is active
276 */
277gboolean
278gtk_gesture_drag_get_offset (GtkGestureDrag *gesture,
279 double *x,
280 double *y)
281{
282 GtkGestureDragPrivate *priv;
283 GdkEventSequence *sequence;
284
285 g_return_val_if_fail (GTK_IS_GESTURE_DRAG (gesture), FALSE);
286
287 sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
288
289 if (!gtk_gesture_handles_sequence (GTK_GESTURE (gesture), sequence))
290 return FALSE;
291
292 priv = gtk_gesture_drag_get_instance_private (self: gesture);
293
294 if (x)
295 *x = priv->last_x - priv->start_x;
296
297 if (y)
298 *y = priv->last_y - priv->start_y;
299
300 return TRUE;
301}
302

source code of gtk/gtk/gtkgesturedrag.c