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