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 | |
39 | typedef struct _GtkGestureDragPrivate GtkGestureDragPrivate; |
40 | typedef struct _EventData EventData; |
41 | |
42 | struct _GtkGestureDragPrivate |
43 | { |
44 | double start_x; |
45 | double start_y; |
46 | double last_x; |
47 | double 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 | |
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 | 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 | |
83 | static void |
84 | gtk_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 | |
100 | static void |
101 | gtk_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 | |
115 | static void |
116 | gtk_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 | |
133 | static void |
134 | gtk_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 | |
204 | static void |
205 | gtk_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 | **/ |
216 | GtkGesture * |
217 | gtk_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 | */ |
237 | gboolean |
238 | gtk_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 | */ |
277 | gboolean |
278 | gtk_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 | |