1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2012, One Laptop Per Child.
3 * Copyright (C) 2014, Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author(s): Carlos Garnacho <carlosg@gnome.org>
19 */
20
21 /**
22 * SECTION:gtkeventcontroller
23 * @Short_description: Self-contained handler of series of events
24 * @Title: GtkEventController
25 * @See_also: #GtkGesture
26 *
27 * #GtkEventController is a base, low-level implementation for event
28 * controllers. Those react to a series of #GdkEvents, and possibly trigger
29 * actions as a consequence of those.
30 */
31
32 #include "config.h"
33 #include "gtkeventcontroller.h"
34 #include "gtkeventcontrollerprivate.h"
35 #include "gtkwidgetprivate.h"
36 #include "gtktypebuiltins.h"
37 #include "gtkmarshalers.h"
38 #include "gtkprivate.h"
39 #include "gtkintl.h"
40
41 typedef struct _GtkEventControllerPrivate GtkEventControllerPrivate;
42
43 enum {
44 PROP_WIDGET = 1,
45 PROP_PROPAGATION_PHASE,
46 LAST_PROP
47 };
48
49 static GParamSpec *properties[LAST_PROP] = { NULL, };
50
51 struct _GtkEventControllerPrivate
52 {
53 GtkWidget *widget;
54 guint evmask;
55 GtkPropagationPhase phase;
56 };
57
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(GtkEventController,gtk_event_controller,G_TYPE_OBJECT)58 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GtkEventController, gtk_event_controller, G_TYPE_OBJECT)
59
60 static gboolean
61 gtk_event_controller_handle_event_default (GtkEventController *controller,
62 const GdkEvent *event)
63 {
64 return FALSE;
65 }
66
67 static void
gtk_event_controller_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)68 gtk_event_controller_set_property (GObject *object,
69 guint prop_id,
70 const GValue *value,
71 GParamSpec *pspec)
72 {
73 GtkEventControllerPrivate *priv;
74
75 priv = gtk_event_controller_get_instance_private (GTK_EVENT_CONTROLLER (object));
76
77 switch (prop_id)
78 {
79 case PROP_WIDGET:
80 priv->widget = g_value_get_object (value);
81 if (priv->widget)
82 g_object_add_weak_pointer (G_OBJECT (priv->widget), (gpointer *) &priv->widget);
83 break;
84 case PROP_PROPAGATION_PHASE:
85 gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (object),
86 g_value_get_enum (value));
87 break;
88 default:
89 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
90 }
91 }
92
93 static void
gtk_event_controller_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)94 gtk_event_controller_get_property (GObject *object,
95 guint prop_id,
96 GValue *value,
97 GParamSpec *pspec)
98 {
99 GtkEventControllerPrivate *priv;
100
101 priv = gtk_event_controller_get_instance_private (GTK_EVENT_CONTROLLER (object));
102
103 switch (prop_id)
104 {
105 case PROP_WIDGET:
106 g_value_set_object (value, priv->widget);
107 break;
108 case PROP_PROPAGATION_PHASE:
109 g_value_set_enum (value, priv->phase);
110 break;
111 default:
112 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
113 }
114 }
115
116 static void
gtk_event_controller_constructed(GObject * object)117 gtk_event_controller_constructed (GObject *object)
118 {
119 GtkEventController *controller = GTK_EVENT_CONTROLLER (object);
120 GtkEventControllerPrivate *priv;
121
122 G_OBJECT_CLASS (gtk_event_controller_parent_class)->constructed (object);
123
124 priv = gtk_event_controller_get_instance_private (controller);
125 if (priv->widget)
126 _gtk_widget_add_controller (priv->widget, controller);
127 }
128
129 static void
gtk_event_controller_dispose(GObject * object)130 gtk_event_controller_dispose (GObject *object)
131 {
132 GtkEventController *controller = GTK_EVENT_CONTROLLER (object);
133 GtkEventControllerPrivate *priv;
134
135 priv = gtk_event_controller_get_instance_private (controller);
136 if (priv->widget)
137 {
138 _gtk_widget_remove_controller (priv->widget, controller);
139 g_object_remove_weak_pointer (G_OBJECT (priv->widget), (gpointer *) &priv->widget);
140 priv->widget = NULL;
141 }
142
143 G_OBJECT_CLASS (gtk_event_controller_parent_class)->dispose (object);
144 }
145
146 static void
gtk_event_controller_class_init(GtkEventControllerClass * klass)147 gtk_event_controller_class_init (GtkEventControllerClass *klass)
148 {
149 GObjectClass *object_class = G_OBJECT_CLASS (klass);
150
151 klass->filter_event = gtk_event_controller_handle_event_default;
152 klass->handle_event = gtk_event_controller_handle_event_default;
153
154 object_class->set_property = gtk_event_controller_set_property;
155 object_class->get_property = gtk_event_controller_get_property;
156 object_class->constructed = gtk_event_controller_constructed;
157 object_class->dispose = gtk_event_controller_dispose;
158
159 /**
160 * GtkEventController:widget:
161 *
162 * The widget receiving the #GdkEvents that the controller will handle.
163 *
164 * Since: 3.14
165 */
166 properties[PROP_WIDGET] =
167 g_param_spec_object ("widget",
168 P_("Widget"),
169 P_("Widget the gesture relates to"),
170 GTK_TYPE_WIDGET,
171 GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
172 /**
173 * GtkEventController:propagation-phase:
174 *
175 * The propagation phase at which this controller will handle events.
176 *
177 * Since: 3.14
178 */
179 properties[PROP_PROPAGATION_PHASE] =
180 g_param_spec_enum ("propagation-phase",
181 P_("Propagation phase"),
182 P_("Propagation phase at which this controller is run"),
183 GTK_TYPE_PROPAGATION_PHASE,
184 GTK_PHASE_BUBBLE,
185 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
186
187 g_object_class_install_properties (object_class, LAST_PROP, properties);
188 }
189
190 static void
gtk_event_controller_init(GtkEventController * controller)191 gtk_event_controller_init (GtkEventController *controller)
192 {
193 GtkEventControllerPrivate *priv;
194
195 priv = gtk_event_controller_get_instance_private (controller);
196 priv->phase = GTK_PHASE_BUBBLE;
197 }
198
199 /**
200 * gtk_event_controller_handle_event:
201 * @controller: a #GtkEventController
202 * @event: a #GdkEvent
203 *
204 * Feeds an events into @controller, so it can be interpreted
205 * and the controller actions triggered.
206 *
207 * Returns: %TRUE if the event was potentially useful to trigger the
208 * controller action
209 *
210 * Since: 3.14
211 **/
212 gboolean
gtk_event_controller_handle_event(GtkEventController * controller,const GdkEvent * event)213 gtk_event_controller_handle_event (GtkEventController *controller,
214 const GdkEvent *event)
215 {
216 GtkEventControllerClass *controller_class;
217 gboolean retval = FALSE;
218
219 g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER (controller), FALSE);
220 g_return_val_if_fail (event != NULL, FALSE);
221
222 controller_class = GTK_EVENT_CONTROLLER_GET_CLASS (controller);
223
224 if (controller_class->filter_event (controller, event))
225 return retval;
226
227 if (controller_class->handle_event)
228 {
229 g_object_ref (controller);
230 retval = controller_class->handle_event (controller, event);
231 g_object_unref (controller);
232 }
233
234 return retval;
235 }
236
237 void
gtk_event_controller_set_event_mask(GtkEventController * controller,GdkEventMask event_mask)238 gtk_event_controller_set_event_mask (GtkEventController *controller,
239 GdkEventMask event_mask)
240 {
241 GtkEventControllerPrivate *priv;
242
243 g_return_if_fail (GTK_IS_EVENT_CONTROLLER (controller));
244
245 priv = gtk_event_controller_get_instance_private (controller);
246
247 if (priv->evmask == event_mask)
248 return;
249
250 priv->evmask = event_mask;
251 }
252
253 GdkEventMask
gtk_event_controller_get_event_mask(GtkEventController * controller)254 gtk_event_controller_get_event_mask (GtkEventController *controller)
255 {
256 GtkEventControllerPrivate *priv;
257
258 g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER (controller), 0);
259
260 priv = gtk_event_controller_get_instance_private (controller);
261
262 return priv->evmask;
263 }
264
265 /**
266 * gtk_event_controller_get_widget:
267 * @controller: a #GtkEventController
268 *
269 * Returns the #GtkWidget this controller relates to.
270 *
271 * Returns: (transfer none): a #GtkWidget
272 *
273 * Since: 3.14
274 **/
275 GtkWidget *
gtk_event_controller_get_widget(GtkEventController * controller)276 gtk_event_controller_get_widget (GtkEventController *controller)
277 {
278 GtkEventControllerPrivate *priv;
279
280 g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER (controller), 0);
281
282 priv = gtk_event_controller_get_instance_private (controller);
283
284 return priv->widget;
285 }
286
287 /**
288 * gtk_event_controller_reset:
289 * @controller: a #GtkEventController
290 *
291 * Resets the @controller to a clean state. Every interaction
292 * the controller did through #GtkEventController::handle-event
293 * will be dropped at this point.
294 *
295 * Since: 3.14
296 **/
297 void
gtk_event_controller_reset(GtkEventController * controller)298 gtk_event_controller_reset (GtkEventController *controller)
299 {
300 GtkEventControllerClass *controller_class;
301
302 g_return_if_fail (GTK_IS_EVENT_CONTROLLER (controller));
303
304 controller_class = GTK_EVENT_CONTROLLER_GET_CLASS (controller);
305
306 if (controller_class->reset)
307 controller_class->reset (controller);
308 }
309
310 /**
311 * gtk_event_controller_get_propagation_phase:
312 * @controller: a #GtkEventController
313 *
314 * Gets the propagation phase at which @controller handles events.
315 *
316 * Returns: the propagation phase
317 *
318 * Since: 3.14
319 **/
320 GtkPropagationPhase
gtk_event_controller_get_propagation_phase(GtkEventController * controller)321 gtk_event_controller_get_propagation_phase (GtkEventController *controller)
322 {
323 GtkEventControllerPrivate *priv;
324
325 g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER (controller), GTK_PHASE_NONE);
326
327 priv = gtk_event_controller_get_instance_private (controller);
328
329 return priv->phase;
330 }
331
332 /**
333 * gtk_event_controller_set_propagation_phase:
334 * @controller: a #GtkEventController
335 * @phase: a propagation phase
336 *
337 * Sets the propagation phase at which a controller handles events.
338 *
339 * If @phase is %GTK_PHASE_NONE, no automatic event handling will be
340 * performed, but other additional gesture maintenance will. In that phase,
341 * the events can be managed by calling gtk_event_controller_handle_event().
342 *
343 * Since: 3.14
344 **/
345 void
gtk_event_controller_set_propagation_phase(GtkEventController * controller,GtkPropagationPhase phase)346 gtk_event_controller_set_propagation_phase (GtkEventController *controller,
347 GtkPropagationPhase phase)
348 {
349 GtkEventControllerPrivate *priv;
350
351 g_return_if_fail (GTK_IS_EVENT_CONTROLLER (controller));
352 g_return_if_fail (phase >= GTK_PHASE_NONE && phase <= GTK_PHASE_TARGET);
353
354 priv = gtk_event_controller_get_instance_private (controller);
355
356 if (priv->phase == phase)
357 return;
358
359 priv->phase = phase;
360
361 if (phase == GTK_PHASE_NONE)
362 gtk_event_controller_reset (controller);
363
364 g_object_notify_by_pspec (G_OBJECT (controller), properties[PROP_PROPAGATION_PHASE]);
365 }
366