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 * GtkEventController:
23 *
24 * `GtkEventController` is the base class for event controllers.
25 *
26 * These are ancillary objects associated to widgets, which react
27 * to `GdkEvents`, and possibly trigger actions as a consequence.
28 *
29 * Event controllers are added to a widget with
30 * [method@Gtk.Widget.add_controller]. It is rarely necessary to
31 * explicitly remove a controller with [method@Gtk.Widget.remove_controller].
32 *
33 * See the chapter on [input handling](input-handling.html) for
34 * an overview of the basic concepts, such as the capture and bubble
35 * phases of even propagation.
36 */
37
38#include "config.h"
39#include "gtkeventcontroller.h"
40#include "gtkeventcontrollerprivate.h"
41
42#include "gtkwidgetprivate.h"
43#include "gtktypebuiltins.h"
44#include "gtkmarshalers.h"
45#include "gtkprivate.h"
46#include "gtkintl.h"
47#include "gtknative.h"
48
49typedef struct _GtkEventControllerPrivate GtkEventControllerPrivate;
50
51enum {
52 PROP_WIDGET = 1,
53 PROP_PROPAGATION_PHASE,
54 PROP_PROPAGATION_LIMIT,
55 PROP_NAME,
56 LAST_PROP
57};
58
59static GParamSpec *properties[LAST_PROP] = { NULL, };
60
61struct _GtkEventControllerPrivate
62{
63 GtkWidget *widget;
64 GtkPropagationPhase phase;
65 GtkPropagationLimit limit;
66 char *name;
67 GtkWidget *target;
68 GdkEvent *event;
69};
70
71G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GtkEventController, gtk_event_controller, G_TYPE_OBJECT)
72
73static void
74gtk_event_controller_set_widget (GtkEventController *self,
75 GtkWidget *widget)
76{
77 GtkEventControllerPrivate *priv = gtk_event_controller_get_instance_private (self);
78
79 priv->widget = widget;
80}
81
82static void
83gtk_event_controller_unset_widget (GtkEventController *self)
84{
85 GtkEventControllerPrivate *priv = gtk_event_controller_get_instance_private (self);
86
87 priv->widget = NULL;
88}
89
90static gboolean
91gtk_event_controller_filter_event_default (GtkEventController *self,
92 GdkEvent *event)
93{
94 return FALSE;
95}
96
97static gboolean
98gtk_event_controller_handle_event_default (GtkEventController *self,
99 GdkEvent *event,
100 double x,
101 double y)
102{
103 return FALSE;
104}
105
106static void
107gtk_event_controller_handle_crossing_default (GtkEventController *self,
108 const GtkCrossingData *crossing,
109 double x,
110 double y)
111{
112}
113
114static void
115gtk_event_controller_set_property (GObject *object,
116 guint prop_id,
117 const GValue *value,
118 GParamSpec *pspec)
119{
120 GtkEventController *self = GTK_EVENT_CONTROLLER (object);
121 GtkEventControllerPrivate *priv = gtk_event_controller_get_instance_private (self);
122
123 switch (prop_id)
124 {
125 case PROP_PROPAGATION_PHASE:
126 gtk_event_controller_set_propagation_phase (controller: self,
127 phase: g_value_get_enum (value));
128 break;
129 case PROP_PROPAGATION_LIMIT:
130 gtk_event_controller_set_propagation_limit (controller: self,
131 limit: g_value_get_enum (value));
132 break;
133 case PROP_NAME:
134 g_free (mem: priv->name);
135 priv->name = g_value_dup_string (value);
136 break;
137
138 default:
139 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
140 }
141}
142
143static void
144gtk_event_controller_get_property (GObject *object,
145 guint prop_id,
146 GValue *value,
147 GParamSpec *pspec)
148{
149 GtkEventController *self = GTK_EVENT_CONTROLLER (object);
150 GtkEventControllerPrivate *priv = gtk_event_controller_get_instance_private (self);
151
152 switch (prop_id)
153 {
154 case PROP_WIDGET:
155 g_value_set_object (value, v_object: priv->widget);
156 break;
157 case PROP_PROPAGATION_PHASE:
158 g_value_set_enum (value, v_enum: priv->phase);
159 break;
160 case PROP_PROPAGATION_LIMIT:
161 g_value_set_enum (value, v_enum: priv->limit);
162 break;
163 case PROP_NAME:
164 g_value_set_string (value, v_string: priv->name);
165 break;
166 default:
167 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
168 }
169}
170
171static void
172gtk_event_controller_finalize (GObject *object)
173{
174 GtkEventController *self = GTK_EVENT_CONTROLLER (object);
175 GtkEventControllerPrivate *priv = gtk_event_controller_get_instance_private (self);
176
177 g_free (mem: priv->name);
178
179 G_OBJECT_CLASS (gtk_event_controller_parent_class)->finalize (object);
180}
181
182static void
183gtk_event_controller_class_init (GtkEventControllerClass *klass)
184{
185 GObjectClass *object_class = G_OBJECT_CLASS (klass);
186
187 klass->set_widget = gtk_event_controller_set_widget;
188 klass->unset_widget = gtk_event_controller_unset_widget;
189 klass->filter_event = gtk_event_controller_filter_event_default;
190 klass->handle_event = gtk_event_controller_handle_event_default;
191 klass->handle_crossing = gtk_event_controller_handle_crossing_default;
192
193 object_class->finalize = gtk_event_controller_finalize;
194 object_class->set_property = gtk_event_controller_set_property;
195 object_class->get_property = gtk_event_controller_get_property;
196
197 /**
198 * GtkEventController:widget: (attributes org.gtk.Property.get=gtk_event_controller_get_widget)
199 *
200 * The widget receiving the `GdkEvents` that the controller will handle.
201 */
202 properties[PROP_WIDGET] =
203 g_param_spec_object (name: "widget",
204 P_("Widget"),
205 P_("Widget the gesture relates to"),
206 GTK_TYPE_WIDGET,
207 GTK_PARAM_READABLE);
208
209 /**
210 * GtkEventController:propagation-phase: (attributes org.gtk.Property.get=gtk_event_controller_get_propagation_phase org.gtk.Property.set=gtk_event_controller_set_propagation_phase)
211 *
212 * The propagation phase at which this controller will handle events.
213 */
214 properties[PROP_PROPAGATION_PHASE] =
215 g_param_spec_enum (name: "propagation-phase",
216 P_("Propagation phase"),
217 P_("Propagation phase at which this controller is run"),
218 enum_type: GTK_TYPE_PROPAGATION_PHASE,
219 default_value: GTK_PHASE_BUBBLE,
220 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
221
222 /**
223 * GtkEventController:propagation-limit: (attributes org.gtk.Property.get=gtk_event_controller_get_propagation_limit org.gtk.Property.set=gtk_event_controller_set_propagation_limit)
224 *
225 * The limit for which events this controller will handle.
226 */
227 properties[PROP_PROPAGATION_LIMIT] =
228 g_param_spec_enum (name: "propagation-limit",
229 P_("Propagation limit"),
230 P_("Propagation limit for events handled by this controller"),
231 enum_type: GTK_TYPE_PROPAGATION_LIMIT,
232 default_value: GTK_LIMIT_SAME_NATIVE,
233 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
234
235 /**
236 * GtkEventController:name: (attributes org.gtk.Property.get=gtk_event_controller_get_name org.gtk.Property.set=gtk_event_controller_set_name)
237 *
238 * The name for this controller, typically used for debugging purposes.
239 */
240 properties[PROP_NAME] =
241 g_param_spec_string (name: "name",
242 P_("Name"),
243 P_("Name for this controller"),
244 NULL,
245 GTK_PARAM_READWRITE);
246
247 g_object_class_install_properties (oclass: object_class, n_pspecs: LAST_PROP, pspecs: properties);
248}
249
250static void
251gtk_event_controller_init (GtkEventController *controller)
252{
253 GtkEventControllerPrivate *priv;
254
255 priv = gtk_event_controller_get_instance_private (self: controller);
256 priv->phase = GTK_PHASE_BUBBLE;
257 priv->limit = GTK_LIMIT_SAME_NATIVE;
258}
259
260static gboolean
261same_native (GtkWidget *widget,
262 GtkWidget *target)
263{
264 GtkNative *native;
265 GtkNative *native2;
266
267 if (!widget || !target)
268 return TRUE;
269
270 native = gtk_widget_get_native (widget);
271 native2 = gtk_widget_get_native (widget: target);
272
273 return native == native2;
274}
275
276static gboolean
277gtk_event_controller_filter_event (GtkEventController *controller,
278 GdkEvent *event,
279 GtkWidget *target)
280{
281 GtkEventControllerPrivate *priv;
282 GtkEventControllerClass *controller_class;
283
284 priv = gtk_event_controller_get_instance_private (self: controller);
285
286 if (priv->widget && !gtk_widget_is_sensitive (widget: priv->widget))
287 return TRUE;
288
289 if (priv->limit == GTK_LIMIT_SAME_NATIVE &&
290 !same_native (widget: priv->widget, target))
291 return TRUE;
292
293 controller_class = GTK_EVENT_CONTROLLER_GET_CLASS (controller);
294
295 return controller_class->filter_event (controller, event);
296}
297
298static gboolean
299gtk_event_controller_filter_crossing (GtkEventController *controller,
300 const GtkCrossingData *data)
301{
302 GtkEventControllerPrivate *priv;
303 GtkWidget *old_target, *new_target;
304
305 priv = gtk_event_controller_get_instance_private (self: controller);
306
307 if (priv->widget && !gtk_widget_is_sensitive (widget: priv->widget))
308 return TRUE;
309
310 old_target = data->old_target;
311 new_target = data->new_target;
312
313 if (priv->limit == GTK_LIMIT_SAME_NATIVE)
314 {
315 /* treat out-of-scope targets like NULL */
316
317 if (!same_native (widget: priv->widget, target: old_target))
318 old_target = NULL;
319
320 if (!same_native (widget: priv->widget, target: new_target))
321 new_target = NULL;
322 }
323
324 if (old_target == NULL && new_target == NULL)
325 return TRUE;
326
327 return FALSE;
328}
329
330/*< private >
331 * gtk_event_controller_handle_event:
332 * @controller: a `GtkEventController`
333 * @event: a `GdkEvent`
334 * @target: the target widget
335 * @x: event position in widget coordinates, or 0 if not a pointer event
336 * @y: event position in widget coordinates, or 0 if not a pointer event
337 *
338 * Feeds an event into @controller, so it can be interpreted
339 * and the controller actions triggered.
340 *
341 * Returns: %TRUE if the event was potentially useful to trigger the
342 * controller action
343 */
344gboolean
345gtk_event_controller_handle_event (GtkEventController *controller,
346 GdkEvent *event,
347 GtkWidget *target,
348 double x,
349 double y)
350{
351 GtkEventControllerClass *controller_class;
352 GtkEventControllerPrivate *priv;
353 gboolean retval = FALSE;
354
355 priv = gtk_event_controller_get_instance_private (self: controller);
356
357 g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER (controller), FALSE);
358 g_return_val_if_fail (event != NULL, FALSE);
359
360 if (gtk_event_controller_filter_event (controller, event, target))
361 return retval;
362
363 controller_class = GTK_EVENT_CONTROLLER_GET_CLASS (controller);
364
365 priv->target = g_object_ref (target);
366 priv->event = gdk_event_ref (event);
367
368 g_object_ref (controller);
369 retval = controller_class->handle_event (controller, event, x, y);
370
371 g_clear_object (&priv->target);
372 g_clear_pointer (&priv->event, gdk_event_unref);
373 g_object_unref (object: controller);
374
375 return retval;
376}
377
378/*< private >
379 * gtk_event_controller_handle_crossing:
380 * @controller: a `GtkEventController`
381 * @crossing: a `GtkCrossingData`
382 * @x: translated event coordinates
383 * @y: translated event coordinates
384 *
385 * Feeds a crossing event into @controller, so it can be interpreted
386 * and the controller actions triggered.
387 */
388void
389gtk_event_controller_handle_crossing (GtkEventController *controller,
390 const GtkCrossingData *crossing,
391 double x,
392 double y)
393{
394 GtkEventControllerClass *controller_class;
395
396 g_return_if_fail (GTK_IS_EVENT_CONTROLLER (controller));
397 g_return_if_fail (crossing != NULL);
398
399 if (gtk_event_controller_filter_crossing (controller, data: crossing))
400 return;
401
402 controller_class = GTK_EVENT_CONTROLLER_GET_CLASS (controller);
403
404 g_object_ref (controller);
405 controller_class->handle_crossing (controller, crossing, x, y);
406 g_object_unref (object: controller);
407}
408
409/**
410 * gtk_event_controller_get_widget: (attributes org.gtk.Method.get_property=widget)
411 * @controller: a `GtkEventController`
412 *
413 * Returns the `GtkWidget` this controller relates to.
414 *
415 * Returns: (transfer none): a `GtkWidget`
416 **/
417GtkWidget *
418gtk_event_controller_get_widget (GtkEventController *controller)
419{
420 GtkEventControllerPrivate *priv;
421
422 g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER (controller), 0);
423
424 priv = gtk_event_controller_get_instance_private (self: controller);
425
426 return priv->widget;
427}
428
429/**
430 * gtk_event_controller_reset:
431 * @controller: a `GtkEventController`
432 *
433 * Resets the @controller to a clean state.
434 */
435void
436gtk_event_controller_reset (GtkEventController *controller)
437{
438 GtkEventControllerClass *controller_class;
439
440 g_return_if_fail (GTK_IS_EVENT_CONTROLLER (controller));
441
442 controller_class = GTK_EVENT_CONTROLLER_GET_CLASS (controller);
443
444 if (controller_class->reset)
445 controller_class->reset (controller);
446}
447
448/**
449 * gtk_event_controller_get_propagation_phase: (attributes org.gtk.Method.get_property=propagation-phase)
450 * @controller: a `GtkEventController`
451 *
452 * Gets the propagation phase at which @controller handles events.
453 *
454 * Returns: the propagation phase
455 */
456GtkPropagationPhase
457gtk_event_controller_get_propagation_phase (GtkEventController *controller)
458{
459 GtkEventControllerPrivate *priv;
460
461 g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER (controller), GTK_PHASE_NONE);
462
463 priv = gtk_event_controller_get_instance_private (self: controller);
464
465 return priv->phase;
466}
467
468/**
469 * gtk_event_controller_set_propagation_phase: (attributes org.gtk.Method.set_property=propagation-phase)
470 * @controller: a `GtkEventController`
471 * @phase: a propagation phase
472 *
473 * Sets the propagation phase at which a controller handles events.
474 *
475 * If @phase is %GTK_PHASE_NONE, no automatic event handling will be
476 * performed, but other additional gesture maintenance will.
477 */
478void
479gtk_event_controller_set_propagation_phase (GtkEventController *controller,
480 GtkPropagationPhase phase)
481{
482 GtkEventControllerPrivate *priv;
483
484 g_return_if_fail (GTK_IS_EVENT_CONTROLLER (controller));
485 g_return_if_fail (phase >= GTK_PHASE_NONE && phase <= GTK_PHASE_TARGET);
486
487 priv = gtk_event_controller_get_instance_private (self: controller);
488
489 if (priv->phase == phase)
490 return;
491
492 priv->phase = phase;
493
494 if (phase == GTK_PHASE_NONE)
495 gtk_event_controller_reset (controller);
496
497 g_object_notify_by_pspec (G_OBJECT (controller), pspec: properties[PROP_PROPAGATION_PHASE]);
498}
499
500/**
501 * gtk_event_controller_get_propagation_limit: (attributes org.gtk.Method.get_property=propagation-limit)
502 * @controller: a `GtkEventController`
503 *
504 * Gets the propagation limit of the event controller.
505 *
506 * Returns: the propagation limit
507 */
508GtkPropagationLimit
509gtk_event_controller_get_propagation_limit (GtkEventController *controller)
510{
511 GtkEventControllerPrivate *priv;
512
513 g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER (controller), GTK_LIMIT_SAME_NATIVE);
514
515 priv = gtk_event_controller_get_instance_private (self: controller);
516
517 return priv->limit;
518}
519
520/**
521 * gtk_event_controller_set_propagation_limit: (attributes org.gtk.Method.set_property=propagation-limit)
522 * @controller: a `GtkEventController`
523 * @limit: the propagation limit
524 *
525 * Sets the event propagation limit on the event controller.
526 *
527 * If the limit is set to %GTK_LIMIT_SAME_NATIVE, the controller
528 * won't handle events that are targeted at widgets on a different
529 * surface, such as popovers.
530 */
531void
532gtk_event_controller_set_propagation_limit (GtkEventController *controller,
533 GtkPropagationLimit limit)
534{
535 GtkEventControllerPrivate *priv;
536
537 g_return_if_fail (GTK_IS_EVENT_CONTROLLER (controller));
538
539 priv = gtk_event_controller_get_instance_private (self: controller);
540
541 if (priv->limit == limit)
542 return;
543
544 priv->limit = limit;
545
546 g_object_notify_by_pspec (G_OBJECT (controller), pspec: properties[PROP_PROPAGATION_LIMIT]);
547}
548
549/**
550 * gtk_event_controller_get_name: (attributes org.gtk.Method.get_property=name)
551 * @controller: a `GtkEventController`
552 *
553 * Gets the name of @controller.
554 *
555 * Returns: (nullable): The controller name
556 */
557const char *
558gtk_event_controller_get_name (GtkEventController *controller)
559{
560 GtkEventControllerPrivate *priv = gtk_event_controller_get_instance_private (self: controller);
561
562 g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER (controller), NULL);
563
564 return priv->name;
565}
566
567/**
568 * gtk_event_controller_set_name: (attributes org.gtk.Method.set_property=name)
569 * @controller: a `GtkEventController`
570 * @name: (nullable): a name for @controller
571 *
572 * Sets a name on the controller that can be used for debugging.
573 */
574void
575gtk_event_controller_set_name (GtkEventController *controller,
576 const char *name)
577{
578 GtkEventControllerPrivate *priv = gtk_event_controller_get_instance_private (self: controller);
579
580 g_return_if_fail (GTK_IS_EVENT_CONTROLLER (controller));
581
582 g_free (mem: priv->name);
583 priv->name = g_strdup (str: name);
584}
585
586GtkWidget *
587gtk_event_controller_get_target (GtkEventController *controller)
588{
589 GtkEventControllerPrivate *priv = gtk_event_controller_get_instance_private (self: controller);
590
591 return priv->target;
592}
593
594/**
595 * gtk_event_controller_get_current_event:
596 * @controller: a `GtkEventController`
597 *
598 * Returns the event that is currently being handled by the controller.
599 *
600 * At other times, %NULL is returned.
601 *
602 * Returns: (nullable) (transfer none): the event that is currently
603 * handled by @controller
604 */
605GdkEvent *
606gtk_event_controller_get_current_event (GtkEventController *controller)
607{
608 GtkEventControllerPrivate *priv = gtk_event_controller_get_instance_private (self: controller);
609
610 return priv->event;
611}
612
613/**
614 * gtk_event_controller_get_current_event_time:
615 * @controller: a `GtkEventController`
616 *
617 * Returns the timestamp of the event that is currently being
618 * handled by the controller.
619 *
620 * At other times, 0 is returned.
621 *
622 * Returns: timestamp of the event is currently handled by @controller
623 */
624guint32
625gtk_event_controller_get_current_event_time (GtkEventController *controller)
626{
627 GtkEventControllerPrivate *priv = gtk_event_controller_get_instance_private (self: controller);
628
629 if (priv->event)
630 return gdk_event_get_time (event: priv->event);
631
632 return 0;
633}
634
635/**
636 * gtk_event_controller_get_current_event_device:
637 * @controller: a `GtkEventController`
638 *
639 * Returns the device of the event that is currently being
640 * handled by the controller.
641 *
642 * At other times, %NULL is returned.
643 *
644 * Returns: (nullable) (transfer none): device of the event is
645 * currently handled by @controller
646 */
647GdkDevice *
648gtk_event_controller_get_current_event_device (GtkEventController *controller)
649{
650 GtkEventControllerPrivate *priv = gtk_event_controller_get_instance_private (self: controller);
651
652 if (priv->event)
653 return gdk_event_get_device (event: priv->event);
654
655 return NULL;
656}
657
658/**
659 * gtk_event_controller_get_current_event_state:
660 * @controller: a `GtkEventController`
661 *
662 * Returns the modifier state of the event that is currently being
663 * handled by the controller.
664 *
665 * At other times, 0 is returned.
666 *
667 * Returns: modifier state of the event is currently handled by @controller
668 */
669GdkModifierType
670gtk_event_controller_get_current_event_state (GtkEventController *controller)
671{
672 GtkEventControllerPrivate *priv = gtk_event_controller_get_instance_private (self: controller);
673
674 if (priv->event)
675 return gdk_event_get_modifier_state (event: priv->event);
676
677 return 0;
678}
679

source code of gtk/gtk/gtkeventcontroller.c