1/* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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
18/*
19 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the GTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23 */
24
25#include "config.h"
26
27#include "gdkdisplayprivate.h"
28#include "gdkdragprivate.h"
29#include "gdkdropprivate.h"
30#include "gdkeventsprivate.h"
31#include "gdkintl.h"
32#include "gdkkeysprivate.h"
33#include "gdkkeysyms.h"
34#include "gdk-private.h"
35
36#include <gobject/gvaluecollector.h>
37
38#include <string.h>
39#include <math.h>
40
41/**
42 * GdkEvent: (ref-func gdk_event_ref) (unref-func gdk_event_unref)
43 *
44 * `GdkEvent`s are immutable data structures, created by GDK to
45 * represent windowing system events.
46 *
47 * In GTK applications the events are handled automatically by toplevel
48 * widgets and passed on to the event controllers of appropriate widgets,
49 * so using `GdkEvent` and its related API is rarely needed.
50 */
51
52/**
53 * GdkEventSequence:
54 *
55 * `GdkEventSequence` is an opaque type representing a sequence
56 * of related touch events.
57 */
58
59static void
60value_event_init (GValue *value)
61{
62 value->data[0].v_pointer = NULL;
63}
64
65static void
66value_event_free_value (GValue *value)
67{
68 if (value->data[0].v_pointer != NULL)
69 gdk_event_unref (event: value->data[0].v_pointer);
70}
71
72static void
73value_event_copy_value (const GValue *src,
74 GValue *dst)
75{
76 if (src->data[0].v_pointer != NULL)
77 dst->data[0].v_pointer = gdk_event_ref (event: src->data[0].v_pointer);
78 else
79 dst->data[0].v_pointer = NULL;
80}
81
82static gpointer
83value_event_peek_pointer (const GValue *value)
84{
85 return value->data[0].v_pointer;
86}
87
88static char *
89value_event_collect_value (GValue *value,
90 guint n_collect_values,
91 GTypeCValue *collect_values,
92 guint collect_flags)
93{
94 GdkEvent *event = collect_values[0].v_pointer;
95
96 if (event == NULL)
97 {
98 value->data[0].v_pointer = NULL;
99 return NULL;
100 }
101
102 if (event->parent_instance.g_class == NULL)
103 return g_strconcat (string1: "invalid unclassed GdkEvent pointer for "
104 "value type '",
105 G_VALUE_TYPE_NAME (value),
106 "'",
107 NULL);
108
109 value->data[0].v_pointer = gdk_event_ref (event);
110
111 return NULL;
112}
113
114static char *
115value_event_lcopy_value (const GValue *value,
116 guint n_collect_values,
117 GTypeCValue *collect_values,
118 guint collect_flags)
119{
120 GdkEvent **event_p = collect_values[0].v_pointer;
121
122 if (event_p == NULL)
123 return g_strconcat (string1: "value location for '",
124 G_VALUE_TYPE_NAME (value),
125 "' passed as NULL",
126 NULL);
127
128 if (value->data[0].v_pointer == NULL)
129 *event_p = NULL;
130 else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
131 *event_p = value->data[0].v_pointer;
132 else
133 *event_p = gdk_event_ref (event: value->data[0].v_pointer);
134
135 return NULL;
136}
137
138static void
139gdk_event_finalize (GdkEvent *self)
140{
141 g_clear_object (&self->surface);
142 g_clear_object (&self->device);
143
144 g_type_free_instance (instance: (GTypeInstance *) self);
145}
146
147static GdkModifierType
148gdk_event_real_get_state (GdkEvent *self)
149{
150 return 0;
151}
152
153static gboolean
154gdk_event_real_get_position (GdkEvent *self,
155 double *x,
156 double *y)
157{
158 *x = NAN;
159 *y = NAN;
160
161 return FALSE;
162}
163
164static GdkEventSequence *
165gdk_event_real_get_sequence (GdkEvent *self)
166{
167 return NULL;
168}
169
170static GdkDeviceTool *
171gdk_event_real_get_tool (GdkEvent *self)
172{
173 return NULL;
174}
175
176static gboolean
177gdk_event_real_get_axes (GdkEvent *self,
178 double **axes,
179 guint *n_axes)
180{
181 return FALSE;
182}
183
184static void
185gdk_event_class_init (GdkEventClass *klass)
186{
187 klass->finalize = gdk_event_finalize;
188 klass->get_state = gdk_event_real_get_state;
189 klass->get_position = gdk_event_real_get_position;
190 klass->get_sequence = gdk_event_real_get_sequence;
191 klass->get_tool = gdk_event_real_get_tool;
192 klass->get_axes = gdk_event_real_get_axes;
193}
194
195static void
196gdk_event_init (GdkEvent *self)
197{
198 g_ref_count_init (rc: &self->ref_count);
199}
200
201GType
202gdk_event_get_type (void)
203{
204 static gsize event_type__volatile;
205
206 if (g_once_init_enter (&event_type__volatile))
207 {
208 static const GTypeFundamentalInfo finfo = {
209 (G_TYPE_FLAG_CLASSED |
210 G_TYPE_FLAG_INSTANTIATABLE |
211 G_TYPE_FLAG_DERIVABLE |
212 G_TYPE_FLAG_DEEP_DERIVABLE),
213 };
214
215 static const GTypeValueTable value_table = {
216 value_event_init,
217 value_event_free_value,
218 value_event_copy_value,
219 value_event_peek_pointer,
220 "p",
221 value_event_collect_value,
222 "p",
223 value_event_lcopy_value,
224 };
225
226 const GTypeInfo event_info = {
227 /* Class */
228 sizeof (GdkEventClass),
229 (GBaseInitFunc) NULL,
230 (GBaseFinalizeFunc) NULL,
231 (GClassInitFunc) gdk_event_class_init,
232 (GClassFinalizeFunc) NULL,
233 NULL,
234
235 /* Instance */
236 sizeof (GdkEvent),
237 0,
238 (GInstanceInitFunc) gdk_event_init,
239
240 /* GValue */
241 &value_table,
242 };
243
244 GType event_type =
245 g_type_register_fundamental (type_id: g_type_fundamental_next (),
246 type_name: g_intern_static_string (string: "GdkEvent"),
247 info: &event_info, finfo: &finfo,
248 flags: G_TYPE_FLAG_ABSTRACT);
249
250 g_once_init_leave (&event_type__volatile, event_type);
251 }
252
253 return event_type__volatile;
254}
255
256/*< private >
257 * GdkEventTypeInfo:
258 * @instance_size: the size of the instance of a GdkEvent subclass
259 * @instance_init: (nullable): the function to initialize the instance data
260 * @finalize: (nullable): the function to free the instance data
261 * @get_state: (nullable): the function to retrieve the `GdkModifierType`:w
262 * associated to the event
263 * @get_position: (nullable): the function to retrieve the event coordinates
264 * @get_sequence: (nullable): the function to retrieve the event sequence
265 * @get_tool: (nullable): the function to retrieve the event's device tool
266 * @get_axes: (nullable): the function to retrieve the event's axes
267 *
268 * A structure used when registering a new GdkEvent type.
269 */
270typedef struct {
271 gsize instance_size;
272
273 void (* instance_init) (GdkEvent *event);
274 void (* finalize) (GdkEvent *event);
275
276 GdkModifierType (* get_state) (GdkEvent *event);
277
278 gboolean (* get_position) (GdkEvent *event,
279 double *x,
280 double *y);
281
282 GdkEventSequence *(* get_sequence) (GdkEvent *event);
283
284 GdkDeviceTool *(* get_tool) (GdkEvent *event);
285
286 gboolean (* get_axes) (GdkEvent *event,
287 double **axes,
288 guint *n_axes);
289} GdkEventTypeInfo;
290
291static void
292gdk_event_generic_class_init (gpointer g_class,
293 gpointer class_data)
294{
295 GdkEventTypeInfo *info = class_data;
296 GdkEventClass *event_class = g_class;
297
298 /* Optional */
299 if (info->finalize != NULL)
300 event_class->finalize = info->finalize;
301 if (info->get_state != NULL)
302 event_class->get_state = info->get_state;
303 if (info->get_position != NULL)
304 event_class->get_position = info->get_position;
305 if (info->get_sequence != NULL)
306 event_class->get_sequence = info->get_sequence;
307 if (info->get_tool != NULL)
308 event_class->get_tool = info->get_tool;
309 if (info->get_axes != NULL)
310 event_class->get_axes = info->get_axes;
311
312 g_free (mem: info);
313}
314
315static GType
316gdk_event_type_register_static (const char *type_name,
317 const GdkEventTypeInfo *type_info)
318{
319 GTypeInfo info;
320
321 info.class_size = sizeof (GdkEventClass);
322 info.base_init = NULL;
323 info.base_finalize = NULL;
324 info.class_init = gdk_event_generic_class_init;
325 info.class_finalize = NULL;
326 info.class_data = g_memdup2 (mem: type_info, byte_size: sizeof (GdkEventTypeInfo));
327
328 info.instance_size = type_info->instance_size;
329 info.n_preallocs = 0;
330 info.instance_init = (GInstanceInitFunc) type_info->instance_init;
331 info.value_table = NULL;
332
333 return g_type_register_static (GDK_TYPE_EVENT, type_name, info: &info, flags: 0);
334}
335
336/* Map GdkEventType to the appropriate GType */
337static GType gdk_event_types[GDK_EVENT_LAST];
338
339/*< private >
340 * GDK_EVENT_TYPE_SLOT:
341 * @ETYPE: a `GdkEvent`Type
342 *
343 * Associates a `GdkEvent` type with the given `GdkEvent`Type enumeration.
344 *
345 * This macro can only be used with %GDK_DEFINE_EVENT_TYPE.
346 */
347#define GDK_EVENT_TYPE_SLOT(ETYPE) { gdk_event_types[ETYPE] = gdk_define_event_type_id; }
348
349/*< private >
350 * GDK_DEFINE_EVENT_TYPE:
351 * @TypeName: the type name, in camel case
352 * @type_name: the type name, in snake case
353 * @type_info: the address of the `GdkEvent`TypeInfo for the event type
354 * @_C_: custom code to call after registering the event type
355 *
356 * Registers a new `GdkEvent` subclass with the given @TypeName and @type_info.
357 *
358 * Similarly to %G_DEFINE_TYPE_WITH_CODE, this macro will generate a `get_type()`
359 * function that registers the event type.
360 *
361 * You can specify code to be run after the type registration; the `GType` of
362 * the event is available in the `gdk_define_event_type_id` variable.
363 */
364#define GDK_DEFINE_EVENT_TYPE(TypeName, type_name, type_info, _C_) \
365GType \
366type_name ## _get_type (void) \
367{ \
368 static gsize gdk_define_event_type_id__volatile; \
369 if (g_once_init_enter (&gdk_define_event_type_id__volatile)) \
370 { \
371 GType gdk_define_event_type_id = \
372 gdk_event_type_register_static (g_intern_static_string (#TypeName), type_info); \
373 { _C_ } \
374 g_once_init_leave (&gdk_define_event_type_id__volatile, gdk_define_event_type_id); \
375 } \
376 return gdk_define_event_type_id__volatile; \
377}
378
379#define GDK_EVENT_SUPER(event) \
380 ((GdkEventClass *) g_type_class_peek (g_type_parent (G_TYPE_FROM_INSTANCE (event))))
381
382/*< private >
383 * gdk_event_alloc:
384 * @event_type: the `GdkEvent`Type to allocate
385 * @surface: (nullable): the `GdkSurface` of the event
386 * @device: (nullable): the `GdkDevice` of the event
387 * @time_: the event serial
388 *
389 * Allocates a `GdkEvent` for the given @event_type, and sets its
390 * common fields with the given parameters.
391 *
392 * Returns: (transfer full): the newly allocated `GdkEvent` instance
393 */
394static gpointer
395gdk_event_alloc (GdkEventType event_type,
396 GdkSurface *surface,
397 GdkDevice *device,
398 guint32 time_)
399{
400 g_assert (event_type >= GDK_DELETE && event_type < GDK_EVENT_LAST);
401 g_assert (gdk_event_types[event_type] != G_TYPE_INVALID);
402
403 GdkEvent *event = (GdkEvent *) g_type_create_instance (type: gdk_event_types[event_type]);
404
405 GDK_NOTE (EVENTS, {
406 char *str = g_enum_to_string (GDK_TYPE_EVENT_TYPE, event_type);
407 g_message ("Allocating a new %s for event type %s",
408 g_type_name (gdk_event_types[event_type]), str);
409 g_free (str);
410 });
411
412 event->event_type = event_type;
413 event->surface = surface != NULL ? g_object_ref (surface) : NULL;
414 event->device = device != NULL ? g_object_ref (device) : NULL;
415 event->time = time_;
416
417 if (device != NULL && time_ != GDK_CURRENT_TIME)
418 gdk_device_set_timestamp (device, timestamp: time_);
419
420 return event;
421}
422
423static void
424gdk_event_init_types_once (void)
425{
426 g_type_ensure (GDK_TYPE_BUTTON_EVENT);
427 g_type_ensure (GDK_TYPE_CROSSING_EVENT);
428 g_type_ensure (GDK_TYPE_DELETE_EVENT);
429 g_type_ensure (GDK_TYPE_DND_EVENT);
430 g_type_ensure (GDK_TYPE_FOCUS_EVENT);
431 g_type_ensure (GDK_TYPE_GRAB_BROKEN_EVENT);
432 g_type_ensure (GDK_TYPE_KEY_EVENT);
433 g_type_ensure (GDK_TYPE_MOTION_EVENT);
434 g_type_ensure (GDK_TYPE_PAD_EVENT);
435 g_type_ensure (GDK_TYPE_PROXIMITY_EVENT);
436 g_type_ensure (GDK_TYPE_SCROLL_EVENT);
437 g_type_ensure (GDK_TYPE_TOUCH_EVENT);
438 g_type_ensure (GDK_TYPE_TOUCHPAD_EVENT);
439}
440
441/*< private >
442 * gdk_event_init_types:
443 *
444 * Initializes all GdkEvent types.
445 */
446void
447gdk_event_init_types (void)
448{
449 static gsize event_types__volatile;
450
451 if (g_once_init_enter (&event_types__volatile))
452 {
453 gboolean initialized = FALSE;
454
455 gdk_event_init_types_once ();
456 initialized = TRUE;
457
458 g_once_init_leave (&event_types__volatile, initialized);
459 }
460}
461
462#ifdef G_ENABLE_DEBUG
463static gboolean
464check_event_sanity (GdkEvent *event)
465{
466 if (event->device != NULL &&
467 gdk_surface_get_display (surface: event->surface) != gdk_device_get_display (device: event->device))
468 {
469 char *type = g_enum_to_string (g_enum_type: GDK_TYPE_EVENT_TYPE, value: event->event_type);
470 g_warning ("Event of type %s with mismatched device display", type);
471 g_free (mem: type);
472 return FALSE;
473 }
474
475 return TRUE;
476}
477#endif
478
479void
480_gdk_event_emit (GdkEvent *event)
481{
482#ifdef G_ENABLE_DEBUG
483 if (!check_event_sanity (event))
484 return;
485#endif
486
487 if (gdk_drag_handle_source_event (event))
488 return;
489
490 gdk_surface_handle_event (event);
491}
492
493/*********************************************
494 * Functions for maintaining the event queue *
495 *********************************************/
496
497/**
498 * _gdk_event_queue_find_first:
499 * @display: a `GdkDisplay`
500 *
501 * Find the first event on the queue that is not still
502 * being filled in.
503 *
504 * Returns: (nullable): Pointer to the list node for that event
505 */
506GList*
507_gdk_event_queue_find_first (GdkDisplay *display)
508{
509 GList *tmp_list;
510 GList *pending_motion = NULL;
511
512 gboolean paused = display->event_pause_count > 0;
513
514 tmp_list = g_queue_peek_head_link (queue: &display->queued_events);
515 while (tmp_list)
516 {
517 GdkEvent *event = tmp_list->data;
518
519 if ((event->flags & GDK_EVENT_PENDING) == 0 &&
520 (!paused || (event->flags & GDK_EVENT_FLUSHED) != 0))
521 {
522 if (pending_motion)
523 return pending_motion;
524
525 if ((event->event_type == GDK_MOTION_NOTIFY ||
526 (event->event_type == GDK_SCROLL && gdk_scroll_event_get_direction (event) == GDK_SCROLL_SMOOTH)) &&
527 (event->flags & GDK_EVENT_FLUSHED) == 0)
528 pending_motion = tmp_list;
529 else
530 return tmp_list;
531 }
532
533 tmp_list = tmp_list->next;
534 }
535
536 return NULL;
537}
538
539/**
540 * _gdk_event_queue_append:
541 * @display: a `GdkDisplay`
542 * @event: Event to append
543 *
544 * Appends an event onto the tail of the event queue.
545 *
546 * Returns: the newly appended list node.
547 */
548GList *
549_gdk_event_queue_append (GdkDisplay *display,
550 GdkEvent *event)
551{
552 g_queue_push_tail (queue: &display->queued_events, data: event);
553
554 return g_queue_peek_tail_link (queue: &display->queued_events);
555}
556
557/*
558 * _gdk_event_queue_remove_link:
559 * @display: a `GdkDisplay`
560 * @node: node to remove
561 *
562 * Removes a specified list node from the event queue.
563 */
564void
565_gdk_event_queue_remove_link (GdkDisplay *display,
566 GList *node)
567{
568 g_queue_unlink (queue: &display->queued_events, link_: node);
569}
570
571/*
572 * _gdk_event_unqueue:
573 * @display: a `GdkDisplay`
574 *
575 * Removes and returns the first event from the event
576 * queue that is not still being filled in.
577 *
578 * Returns: (nullable): the event
579 */
580GdkEvent*
581_gdk_event_unqueue (GdkDisplay *display)
582{
583 GdkEvent *event = NULL;
584 GList *tmp_list;
585
586 tmp_list = _gdk_event_queue_find_first (display);
587
588 if (tmp_list)
589 {
590 event = tmp_list->data;
591 _gdk_event_queue_remove_link (display, node: tmp_list);
592 g_list_free_1 (list: tmp_list);
593 }
594
595 return event;
596}
597
598/*
599 * If the last N events in the event queue are smooth scroll events
600 * for the same surface and device, combine them into one.
601 *
602 * We give the remaining event a history with N items, and deltas
603 * that are the sum over the history entries.
604 */
605void
606gdk_event_queue_handle_scroll_compression (GdkDisplay *display)
607{
608 GList *l;
609 GdkSurface *surface = NULL;
610 GdkDevice *device = NULL;
611 GdkEvent *last_event = NULL;
612 GList *scrolls = NULL;
613 GArray *history = NULL;
614 GdkTimeCoord hist;
615
616 l = g_queue_peek_tail_link (queue: &display->queued_events);
617
618 while (l)
619 {
620 GdkEvent *event = l->data;
621
622 if (event->flags & GDK_EVENT_PENDING)
623 break;
624
625 if (event->event_type != GDK_SCROLL ||
626 gdk_scroll_event_get_direction (event) != GDK_SCROLL_SMOOTH)
627 break;
628
629 if (surface != NULL &&
630 surface != event->surface)
631 break;
632
633 if (device != NULL &&
634 device != event->device)
635 break;
636
637 if (!last_event)
638 last_event = event;
639
640 surface = event->surface;
641 device = event->device;
642 scrolls = l;
643
644 l = l->prev;
645 }
646
647 while (scrolls && scrolls->next != NULL)
648 {
649 GdkEvent *event = scrolls->data;
650 GList *next = scrolls->next;
651 double dx, dy;
652 gboolean inherited = FALSE;
653
654 if (!history && ((GdkScrollEvent *)event)->history)
655 {
656 history = ((GdkScrollEvent *)event)->history;
657 ((GdkScrollEvent *)event)->history = NULL;
658 inherited = TRUE;
659 }
660
661 if (!history)
662 history = g_array_new (FALSE, TRUE, element_size: sizeof (GdkTimeCoord));
663
664 if (!inherited)
665 {
666 gdk_scroll_event_get_deltas (event, delta_x: &dx, delta_y: &dy);
667
668 memset (s: &hist, c: 0, n: sizeof (GdkTimeCoord));
669 hist.time = gdk_event_get_time (event);
670 hist.flags = GDK_AXIS_FLAG_DELTA_X | GDK_AXIS_FLAG_DELTA_Y;
671 hist.axes[GDK_AXIS_DELTA_X] = dx;
672 hist.axes[GDK_AXIS_DELTA_Y] = dy;
673
674 g_array_append_val (history, hist);
675 }
676
677 gdk_event_unref (event);
678 g_queue_delete_link (queue: &display->queued_events, link_: scrolls);
679 scrolls = next;
680 }
681
682 if (scrolls && history)
683 {
684 GdkEvent *old_event, *event;
685 double dx, dy;
686
687 old_event = scrolls->data;
688
689 gdk_scroll_event_get_deltas (event: old_event, delta_x: &dx, delta_y: &dy);
690
691 memset (s: &hist, c: 0, n: sizeof (GdkTimeCoord));
692 hist.time = gdk_event_get_time (event: old_event);
693 hist.flags = GDK_AXIS_FLAG_DELTA_X | GDK_AXIS_FLAG_DELTA_Y;
694 hist.axes[GDK_AXIS_DELTA_X] = dx;
695 hist.axes[GDK_AXIS_DELTA_Y] = dy;
696 g_array_append_val (history, hist);
697
698 dx = dy = 0;
699 for (int i = 0; i < history->len; i++)
700 {
701 GdkTimeCoord *val = &g_array_index (history, GdkTimeCoord, i);
702 dx += val->axes[GDK_AXIS_DELTA_X];
703 dy += val->axes[GDK_AXIS_DELTA_Y];
704 }
705
706 event = gdk_scroll_event_new (surface,
707 device,
708 tool: gdk_event_get_device_tool (event: old_event),
709 time: gdk_event_get_time (event: old_event),
710 state: gdk_event_get_modifier_state (event: old_event),
711 delta_x: dx,
712 delta_y: dy,
713 is_stop: gdk_scroll_event_is_stop (event: old_event));
714
715 ((GdkScrollEvent *)event)->history = history;
716
717 g_queue_delete_link (queue: &display->queued_events, link_: scrolls);
718 g_queue_push_tail (queue: &display->queued_events, data: event);
719
720 gdk_event_unref (event: old_event);
721 }
722}
723
724static void
725gdk_motion_event_push_history (GdkEvent *event,
726 GdkEvent *history_event)
727{
728 GdkMotionEvent *self = (GdkMotionEvent *) event;
729 GdkDeviceTool *tool;
730 GdkTimeCoord hist;
731 int i;
732
733 g_assert (GDK_IS_EVENT_TYPE (event, GDK_MOTION_NOTIFY));
734 g_assert (GDK_IS_EVENT_TYPE (history_event, GDK_MOTION_NOTIFY));
735
736 if (G_UNLIKELY (!self->history))
737 self->history = g_array_new (FALSE, TRUE, element_size: sizeof (GdkTimeCoord));
738
739 if (((GdkMotionEvent *)history_event)->history)
740 {
741 GArray *history = ((GdkMotionEvent *)history_event)->history;
742 g_array_append_vals (array: self->history, data: history->data, len: history->len);
743 }
744
745 tool = gdk_event_get_device_tool (event: history_event);
746
747 memset (s: &hist, c: 0, n: sizeof (GdkTimeCoord));
748 hist.time = gdk_event_get_time (event: history_event);
749 if (tool)
750 {
751 hist.flags = gdk_device_tool_get_axes (tool);
752 for (i = GDK_AXIS_X; i < GDK_AXIS_LAST; i++)
753 gdk_event_get_axis (event: history_event, axis_use: i, value: &hist.axes[i]);
754 }
755 else
756 {
757 hist.flags = GDK_AXIS_FLAG_X | GDK_AXIS_FLAG_Y;
758 gdk_event_get_position (event: history_event, x: &hist.axes[GDK_AXIS_X], y: &hist.axes[GDK_AXIS_Y]);
759 }
760
761 g_array_append_val (self->history, hist);
762}
763
764/* If the last N events in the event queue are motion notify
765 * events for the same surface, drop all but the last.
766 *
767 * If a button is held down or the device has a tool, then
768 * we give the remaining events a history containing the N-1
769 * dropped events.
770 */
771void
772_gdk_event_queue_handle_motion_compression (GdkDisplay *display)
773{
774 GList *tmp_list;
775 GList *pending_motions = NULL;
776 GdkSurface *pending_motion_surface = NULL;
777 GdkDevice *pending_motion_device = NULL;
778 GdkEvent *last_motion = NULL;
779
780 tmp_list = g_queue_peek_tail_link (queue: &display->queued_events);
781
782 while (tmp_list)
783 {
784 GdkEvent *event = tmp_list->data;
785
786 if (event->flags & GDK_EVENT_PENDING)
787 break;
788
789 if (event->event_type != GDK_MOTION_NOTIFY)
790 break;
791
792 if (pending_motion_surface != NULL &&
793 pending_motion_surface != event->surface)
794 break;
795
796 if (pending_motion_device != NULL &&
797 pending_motion_device != event->device)
798 break;
799
800 if (!last_motion)
801 last_motion = event;
802
803 pending_motion_surface = event->surface;
804 pending_motion_device = event->device;
805 pending_motions = tmp_list;
806
807 tmp_list = tmp_list->prev;
808 }
809
810 while (pending_motions && pending_motions->next != NULL)
811 {
812 GList *next = pending_motions->next;
813
814 if (last_motion != NULL)
815 {
816 if ((gdk_event_get_modifier_state (event: last_motion) &
817 (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK |
818 GDK_BUTTON4_MASK | GDK_BUTTON5_MASK)) ||
819 gdk_event_get_device_tool (event: last_motion) != NULL)
820 gdk_motion_event_push_history (event: last_motion, history_event: pending_motions->data);
821 }
822
823 gdk_event_unref (event: pending_motions->data);
824 g_queue_delete_link (queue: &display->queued_events, link_: pending_motions);
825 pending_motions = next;
826 }
827}
828
829void
830_gdk_event_queue_flush (GdkDisplay *display)
831{
832 while (TRUE)
833 {
834 GdkEvent *event;
835
836 event = (GdkEvent *)g_queue_pop_head (queue: &display->queued_events);
837 if (!event)
838 return;
839
840 event->flags |= GDK_EVENT_FLUSHED;
841 _gdk_event_emit (event);
842 gdk_event_unref (event);
843 }
844}
845
846/**
847 * gdk_event_ref:
848 * @event: a `GdkEvent`
849 *
850 * Increase the ref count of @event.
851 *
852 * Returns: (transfer full): @event
853 */
854GdkEvent *
855gdk_event_ref (GdkEvent *event)
856{
857 g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
858
859 g_ref_count_inc (rc: &event->ref_count);
860
861 return event;
862}
863
864/**
865 * gdk_event_unref:
866 * @event: (transfer full): a `GdkEvent`
867 *
868 * Decrease the ref count of @event.
869 *
870 * If the last reference is dropped, the structure is freed.
871 */
872void
873gdk_event_unref (GdkEvent *event)
874{
875 g_return_if_fail (GDK_IS_EVENT (event));
876
877 if (g_ref_count_dec (rc: &event->ref_count))
878 GDK_EVENT_GET_CLASS (event)->finalize (event);
879}
880
881/**
882 * gdk_event_get_pointer_emulated:
883 * @event: a `GdkEvent`
884 *
885 * Returns whether this event is an 'emulated' pointer event.
886 *
887 * Emulated pointer events typically originate from a touch events.
888 *
889 * Returns: %TRUE if this event is emulated
890 */
891gboolean
892gdk_event_get_pointer_emulated (GdkEvent *event)
893{
894 switch ((int) event->event_type)
895 {
896 case GDK_TOUCH_BEGIN:
897 case GDK_TOUCH_END:
898 case GDK_TOUCH_UPDATE:
899 case GDK_TOUCH_CANCEL:
900 {
901 GdkTouchEvent *tevent = (GdkTouchEvent *) event;
902
903 return tevent->pointer_emulated;
904 }
905
906 case GDK_SCROLL:
907 case GDK_SCROLL_SMOOTH:
908 {
909 GdkScrollEvent *sevent = (GdkScrollEvent *) event;
910
911 return sevent->pointer_emulated;
912 }
913
914 default:
915 break;
916 }
917
918 return FALSE;
919}
920
921/**
922 * gdk_event_get_axis:
923 * @event: a `GdkEvent`
924 * @axis_use: the axis use to look for
925 * @value: (out): location to store the value found
926 *
927 * Extract the axis value for a particular axis use from
928 * an event structure.
929 *
930 * To find out which axes are used, use [method@Gdk.DeviceTool.get_axes]
931 * on the device tool returned by [method@Gdk.Event.get_device_tool].
932 *
933 * Returns: %TRUE if the specified axis was found, otherwise %FALSE
934 */
935gboolean
936gdk_event_get_axis (GdkEvent *event,
937 GdkAxisUse axis_use,
938 double *value)
939{
940 double *axes;
941 guint n_axes;
942
943 g_return_val_if_fail (GDK_IS_EVENT (event), FALSE);
944
945 if (axis_use == GDK_AXIS_X || axis_use == GDK_AXIS_Y)
946 {
947 double x, y;
948
949 if (!gdk_event_get_position (event, x: &x, y: &y))
950 return FALSE;
951
952 if (axis_use == GDK_AXIS_X && value != NULL)
953 *value = x;
954 if (axis_use == GDK_AXIS_Y && value != NULL)
955 *value = y;
956
957 return TRUE;
958 }
959
960 if (!gdk_event_get_axes (event, axes: &axes, n_axes: &n_axes))
961 return FALSE;
962
963 *value = axes[axis_use];
964 return TRUE;
965}
966
967/**
968 * gdk_event_triggers_context_menu:
969 * @event: a `GdkEvent`, currently only button events are meaningful values
970 *
971 * Returns whether a `GdkEvent` should trigger a context menu,
972 * according to platform conventions.
973 *
974 * The right mouse button typically triggers context menus.
975 *
976 * This function should always be used instead of simply checking for
977 * event->button == %GDK_BUTTON_SECONDARY.
978 *
979 * Returns: %TRUE if the event should trigger a context menu.
980 */
981gboolean
982gdk_event_triggers_context_menu (GdkEvent *event)
983{
984 g_return_val_if_fail (event != NULL, FALSE);
985
986 if (event->event_type == GDK_BUTTON_PRESS)
987 {
988 GdkButtonEvent *bevent = (GdkButtonEvent *) event;
989
990 g_return_val_if_fail (GDK_IS_SURFACE (event->surface), FALSE);
991
992 if (bevent->button == GDK_BUTTON_SECONDARY &&
993 ! (bevent->state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK)))
994 return TRUE;
995 }
996
997 return FALSE;
998}
999
1000static gboolean
1001gdk_events_get_axis_distances (GdkEvent *event1,
1002 GdkEvent *event2,
1003 double *x_distance,
1004 double *y_distance,
1005 double *distance)
1006{
1007 double x1, x2, y1, y2;
1008 double xd, yd;
1009
1010 if (!gdk_event_get_position (event: event1, x: &x1, y: &y1) ||
1011 !gdk_event_get_position (event: event2, x: &x2, y: &y2))
1012 return FALSE;
1013
1014 xd = x2 - x1;
1015 yd = y2 - y1;
1016
1017 if (x_distance)
1018 *x_distance = xd;
1019
1020 if (y_distance)
1021 *y_distance = yd;
1022
1023 if (distance)
1024 *distance = sqrt (x: (xd * xd) + (yd * yd));
1025
1026 return TRUE;
1027}
1028
1029/**
1030 * gdk_events_get_distance:
1031 * @event1: first `GdkEvent`
1032 * @event2: second `GdkEvent`
1033 * @distance: (out): return location for the distance
1034 *
1035 * Returns the distance between the event locations.
1036 *
1037 * This assumes that both events have X/Y information.
1038 * If not, this function returns %FALSE.
1039 *
1040 * Returns: %TRUE if the distance could be calculated.
1041 **/
1042gboolean
1043gdk_events_get_distance (GdkEvent *event1,
1044 GdkEvent *event2,
1045 double *distance)
1046{
1047 return gdk_events_get_axis_distances (event1, event2,
1048 NULL, NULL,
1049 distance);
1050}
1051
1052/**
1053 * gdk_events_get_angle:
1054 * @event1: first `GdkEvent`
1055 * @event2: second `GdkEvent`
1056 * @angle: (out): return location for the relative angle between both events
1057 *
1058 * Returns the relative angle from @event1 to @event2.
1059 *
1060 * The relative angle is the angle between the X axis and the line
1061 * through both events' positions. The rotation direction for positive
1062 * angles is from the positive X axis towards the positive Y axis.
1063 *
1064 * This assumes that both events have X/Y information.
1065 * If not, this function returns %FALSE.
1066 *
1067 * Returns: %TRUE if the angle could be calculated.
1068 */
1069gboolean
1070gdk_events_get_angle (GdkEvent *event1,
1071 GdkEvent *event2,
1072 double *angle)
1073{
1074 double x_distance, y_distance, distance;
1075
1076 if (!gdk_events_get_axis_distances (event1, event2,
1077 x_distance: &x_distance, y_distance: &y_distance,
1078 distance: &distance))
1079 return FALSE;
1080
1081 if (angle)
1082 {
1083 *angle = atan2 (y: x_distance, x: y_distance);
1084
1085 /* Invert angle */
1086 *angle = (2 * G_PI) - *angle;
1087
1088 /* Shift it 90° */
1089 *angle += G_PI / 2;
1090
1091 /* And constraint it to 0°-360° */
1092 *angle = fmod (x: *angle, y: 2 * G_PI);
1093 }
1094
1095 return TRUE;
1096}
1097
1098/**
1099 * gdk_events_get_center:
1100 * @event1: first `GdkEvent`
1101 * @event2: second `GdkEvent`
1102 * @x: (out): return location for the X coordinate of the center
1103 * @y: (out): return location for the Y coordinate of the center
1104 *
1105 * Returns the point halfway between the events' positions.
1106 *
1107 * This assumes that both events have X/Y information.
1108 * If not, this function returns %FALSE.
1109 *
1110 * Returns: %TRUE if the center could be calculated.
1111 */
1112gboolean
1113gdk_events_get_center (GdkEvent *event1,
1114 GdkEvent *event2,
1115 double *x,
1116 double *y)
1117{
1118 double x1, x2, y1, y2;
1119
1120 if (!gdk_event_get_position (event: event1, x: &x1, y: &y1) ||
1121 !gdk_event_get_position (event: event2, x: &x2, y: &y2))
1122 return FALSE;
1123
1124 if (x)
1125 *x = (x2 + x1) / 2;
1126
1127 if (y)
1128 *y = (y2 + y1) / 2;
1129
1130 return TRUE;
1131}
1132
1133static GdkEventSequence *
1134gdk_event_sequence_copy (GdkEventSequence *sequence)
1135{
1136 return sequence;
1137}
1138
1139static void
1140gdk_event_sequence_free (GdkEventSequence *sequence)
1141{
1142 /* Nothing to free here */
1143}
1144
1145G_DEFINE_BOXED_TYPE (GdkEventSequence, gdk_event_sequence,
1146 gdk_event_sequence_copy,
1147 gdk_event_sequence_free)
1148
1149
1150
1151/**
1152 * gdk_event_get_axes:
1153 * @event: a `GdkEvent`
1154 * @axes: (transfer none) (out) (array length=n_axes): the array of values for all axes
1155 * @n_axes: (out): the length of array
1156 *
1157 * Extracts all axis values from an event.
1158 *
1159 * To find out which axes are used, use [method@Gdk.DeviceTool.get_axes]
1160 * on the device tool returned by [method@Gdk.Event.get_device_tool].
1161 *
1162 * Returns: %TRUE on success, otherwise %FALSE
1163 */
1164gboolean
1165gdk_event_get_axes (GdkEvent *event,
1166 double **axes,
1167 guint *n_axes)
1168{
1169 g_return_val_if_fail (GDK_IS_EVENT (event), FALSE);
1170
1171 return GDK_EVENT_GET_CLASS (event)->get_axes (event, axes, n_axes);
1172}
1173
1174double *
1175gdk_event_dup_axes (GdkEvent *event)
1176{
1177 double *axes;
1178 guint n_axes;
1179
1180 if (gdk_event_get_axes (event, axes: &axes, n_axes: &n_axes))
1181 {
1182 double *axes_copy = g_memdup2 (mem: axes, byte_size: n_axes * sizeof (double));
1183
1184 return axes_copy;
1185 }
1186
1187 return NULL;
1188}
1189
1190/**
1191 * gdk_event_get_event_type:
1192 * @event: a `GdkEvent`
1193 *
1194 * Retrieves the type of the event.
1195 *
1196 * Returns: a `GdkEvent`Type
1197 */
1198GdkEventType
1199gdk_event_get_event_type (GdkEvent *event)
1200{
1201 g_return_val_if_fail (GDK_IS_EVENT (event), 0);
1202
1203 return event->event_type;
1204}
1205
1206/**
1207 * gdk_event_get_surface:
1208 * @event: a `GdkEvent`
1209 *
1210 * Extracts the surface associated with an event.
1211 *
1212 * Returns: (transfer none) (nullable): The `GdkSurface` associated with the event
1213 */
1214GdkSurface *
1215gdk_event_get_surface (GdkEvent *event)
1216{
1217 g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
1218
1219 return event->surface;
1220}
1221
1222/**
1223 * gdk_event_get_seat:
1224 * @event: a `GdkEvent`
1225 *
1226 * Returns the seat that originated the event.
1227 *
1228 * Returns: (nullable) (transfer none): a `GdkSeat`.
1229 */
1230GdkSeat *
1231gdk_event_get_seat (GdkEvent *event)
1232{
1233 g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
1234
1235 return event->device ? gdk_device_get_seat (device: event->device) : NULL;
1236}
1237
1238/**
1239 * gdk_event_get_device:
1240 * @event: a `GdkEvent`.
1241 *
1242 * Returns the device of an event.
1243 *
1244 * Returns: (nullable) (transfer none): a `GdkDevice`
1245 */
1246GdkDevice *
1247gdk_event_get_device (GdkEvent *event)
1248{
1249 g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
1250
1251 return event->device;
1252}
1253
1254/**
1255 * gdk_event_get_device_tool:
1256 * @event: a `GdkEvent`
1257 *
1258 * Returns a `GdkDeviceTool` representing the tool that
1259 * caused the event.
1260 *
1261 * If the was not generated by a device that supports
1262 * different tools (such as a tablet), this function will
1263 * return %NULL.
1264 *
1265 * Note: the `GdkDeviceTool` will be constant during
1266 * the application lifetime, if settings must be stored
1267 * persistently across runs, see [method@Gdk.DeviceTool.get_serial].
1268 *
1269 * Returns: (transfer none) (nullable): The current device tool
1270 */
1271GdkDeviceTool *
1272gdk_event_get_device_tool (GdkEvent *event)
1273{
1274 g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
1275
1276 return GDK_EVENT_GET_CLASS (event)->get_tool (event);
1277}
1278
1279/**
1280 * gdk_event_get_time:
1281 * @event: a `GdkEvent`
1282 *
1283 * Returns the timestamp of @event.
1284 *
1285 * Not all events have timestamps. In that case, this function
1286 * returns %GDK_CURRENT_TIME.
1287 *
1288 * Returns: timestamp field from @event
1289 */
1290guint32
1291gdk_event_get_time (GdkEvent *event)
1292{
1293 g_return_val_if_fail (GDK_IS_EVENT (event), GDK_CURRENT_TIME);
1294
1295 return event->time;
1296}
1297
1298/**
1299 * gdk_event_get_display:
1300 * @event: a `GdkEvent`
1301 *
1302 * Retrieves the display associated to the @event.
1303 *
1304 * Returns: (transfer none) (nullable): a `GdkDisplay`
1305 */
1306GdkDisplay *
1307gdk_event_get_display (GdkEvent *event)
1308{
1309 g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
1310
1311 if (event->surface)
1312 return gdk_surface_get_display (surface: event->surface);
1313
1314 return NULL;
1315}
1316
1317/**
1318 * gdk_event_get_event_sequence:
1319 * @event: a `GdkEvent`
1320 *
1321 * Retuns the event sequence to which the event belongs.
1322 *
1323 * Related touch events are connected in a sequence. Other
1324 * events typically don't have event sequence information.
1325 *
1326 * Returns: (transfer none): the event sequence that the event belongs to
1327 */
1328GdkEventSequence *
1329gdk_event_get_event_sequence (GdkEvent *event)
1330{
1331 g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
1332
1333 return GDK_EVENT_GET_CLASS (event)->get_sequence (event);
1334}
1335
1336/**
1337 * gdk_event_get_modifier_state:
1338 * @event: a `GdkEvent`
1339 *
1340 * Returns the modifier state field of an event.
1341 *
1342 * Returns: the modifier state of @event
1343 */
1344GdkModifierType
1345gdk_event_get_modifier_state (GdkEvent *event)
1346{
1347 g_return_val_if_fail (GDK_IS_EVENT (event), 0);
1348
1349 return GDK_EVENT_GET_CLASS (event)->get_state (event);
1350}
1351
1352/**
1353 * gdk_event_get_position:
1354 * @event: a `GdkEvent`
1355 * @x: (out): location to put event surface x coordinate
1356 * @y: (out): location to put event surface y coordinate
1357 *
1358 * Extract the event surface relative x/y coordinates from an event.
1359 */
1360gboolean
1361gdk_event_get_position (GdkEvent *event,
1362 double *x,
1363 double *y)
1364{
1365 g_return_val_if_fail (GDK_IS_EVENT (event), FALSE);
1366
1367 return GDK_EVENT_GET_CLASS (event)->get_position (event, x, y);
1368}
1369
1370/* {{{ GdkButtonEvent */
1371
1372/**
1373 * GdkButtonEvent:
1374 *
1375 * An event related to a button on a pointer device.
1376 */
1377
1378static void
1379gdk_button_event_finalize (GdkEvent *event)
1380{
1381 GdkButtonEvent *self = (GdkButtonEvent *) event;
1382
1383 g_clear_object (&self->tool);
1384 g_clear_pointer (&self->axes, g_free);
1385
1386 GDK_EVENT_SUPER (event)->finalize (event);
1387}
1388
1389static GdkModifierType
1390gdk_button_event_get_state (GdkEvent *event)
1391{
1392 GdkButtonEvent *self = (GdkButtonEvent *) event;
1393
1394 return self->state;
1395}
1396
1397static gboolean
1398gdk_button_event_get_position (GdkEvent *event,
1399 double *x,
1400 double *y)
1401{
1402 GdkButtonEvent *self = (GdkButtonEvent *) event;
1403
1404 *x = self->x;
1405 *y = self->y;
1406
1407 return TRUE;
1408}
1409
1410static GdkDeviceTool *
1411gdk_button_event_get_tool (GdkEvent *event)
1412{
1413 GdkButtonEvent *self = (GdkButtonEvent *) event;
1414
1415 return self->tool;
1416}
1417
1418static gboolean
1419gdk_button_event_get_axes (GdkEvent *event,
1420 double **axes,
1421 guint *n_axes)
1422{
1423 GdkButtonEvent *self = (GdkButtonEvent *) event;
1424 GdkDevice *source_device = gdk_event_get_device (event);
1425
1426 if (source_device == NULL)
1427 return FALSE;
1428
1429 *axes = self->axes;
1430 *n_axes = GDK_AXIS_LAST;
1431
1432 return TRUE;
1433}
1434
1435static const GdkEventTypeInfo gdk_button_event_info = {
1436 sizeof (GdkButtonEvent),
1437 NULL,
1438 gdk_button_event_finalize,
1439 gdk_button_event_get_state,
1440 gdk_button_event_get_position,
1441 NULL,
1442 gdk_button_event_get_tool,
1443 gdk_button_event_get_axes,
1444};
1445
1446GDK_DEFINE_EVENT_TYPE (GdkButtonEvent, gdk_button_event,
1447 &gdk_button_event_info,
1448 GDK_EVENT_TYPE_SLOT (GDK_BUTTON_PRESS)
1449 GDK_EVENT_TYPE_SLOT (GDK_BUTTON_RELEASE))
1450
1451GdkEvent *
1452gdk_button_event_new (GdkEventType type,
1453 GdkSurface *surface,
1454 GdkDevice *device,
1455 GdkDeviceTool *tool,
1456 guint32 time,
1457 GdkModifierType state,
1458 guint button,
1459 double x,
1460 double y,
1461 double *axes)
1462{
1463 g_return_val_if_fail (type == GDK_BUTTON_PRESS ||
1464 type == GDK_BUTTON_RELEASE, NULL);
1465
1466 GdkButtonEvent *self = gdk_event_alloc (event_type: type, surface, device, time_: time);
1467
1468 self->tool = tool != NULL ? g_object_ref (tool) : NULL;
1469 self->axes = axes;
1470 self->state = state;
1471 self->button = button;
1472 self->x = x;
1473 self->y = y;
1474
1475 return (GdkEvent *) self;
1476}
1477
1478/**
1479 * gdk_button_event_get_button:
1480 * @event: (type GdkButtonEvent): a button event
1481 *
1482 * Extract the button number from a button event.
1483 *
1484 * Returns: the button of @event
1485 **/
1486guint
1487gdk_button_event_get_button (GdkEvent *event)
1488{
1489 GdkButtonEvent *self = (GdkButtonEvent *) event;
1490
1491 g_return_val_if_fail (GDK_IS_EVENT (event), 0);
1492 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_BUTTON_PRESS) ||
1493 GDK_IS_EVENT_TYPE (event, GDK_BUTTON_RELEASE), 0);
1494
1495 return self->button;
1496}
1497
1498/* }}} */
1499
1500/* {{{ GdkKeyEvent */
1501
1502/**
1503 * GdkKeyEvent:
1504 *
1505 * An event related to a key-based device.
1506 */
1507
1508static GdkModifierType
1509gdk_key_event_get_state (GdkEvent *event)
1510{
1511 GdkKeyEvent *self = (GdkKeyEvent *) event;
1512
1513 return self->state;
1514}
1515
1516static const GdkEventTypeInfo gdk_key_event_info = {
1517 sizeof (GdkKeyEvent),
1518 NULL,
1519 NULL,
1520 gdk_key_event_get_state,
1521 NULL,
1522 NULL,
1523 NULL,
1524 NULL,
1525};
1526
1527GDK_DEFINE_EVENT_TYPE (GdkKeyEvent, gdk_key_event,
1528 &gdk_key_event_info,
1529 GDK_EVENT_TYPE_SLOT (GDK_KEY_PRESS)
1530 GDK_EVENT_TYPE_SLOT (GDK_KEY_RELEASE))
1531
1532/*< private >
1533 * gdk_key_event_new:
1534 * @type: the event type, either %GDK_KEY_PRESS or %GDK_KEY_RELEASE
1535 * @surface: the surface of the event
1536 * @device: the device related to the event
1537 * @time: the event's timestamp
1538 * @keycode: the keycode of the event
1539 * @state: the modifiers state
1540 * @is_modifier: whether the event is a modifiers only event
1541 * @translated: the translated key data for the given @state
1542 * @no_lock: the translated key data without the given @state
1543 *
1544 * Creates a new `GdkKeyEvent`.
1545 *
1546 * Returns: (transfer full) (type GdkKeyEvent): the newly created `GdkEvent`
1547 */
1548GdkEvent *
1549gdk_key_event_new (GdkEventType type,
1550 GdkSurface *surface,
1551 GdkDevice *device,
1552 guint32 time,
1553 guint keycode,
1554 GdkModifierType state,
1555 gboolean is_modifier,
1556 GdkTranslatedKey *translated,
1557 GdkTranslatedKey *no_lock)
1558{
1559 g_return_val_if_fail (type == GDK_KEY_PRESS ||
1560 type == GDK_KEY_RELEASE, NULL);
1561
1562 GdkKeyEvent *self = gdk_event_alloc (event_type: type, surface, device, time_: time);
1563 GdkEvent *event = (GdkEvent *) self;
1564
1565 self->keycode = keycode;
1566 self->state = state;
1567 self->key_is_modifier = is_modifier;
1568 self->translated[0] = *translated;
1569 self->translated[1] = *no_lock;
1570
1571 return event;
1572}
1573
1574/*< private >
1575 * gdk_key_event_get_translated_key:
1576 * @event: (type GdkKeyEvent): a key event
1577 * @no_lock: whether the translated key should take the event
1578 * state into account
1579 *
1580 * Extracts the translated key from a key event.
1581 *
1582 * Returns: (transfer none): the translated key
1583 */
1584GdkTranslatedKey *
1585gdk_key_event_get_translated_key (GdkEvent *event,
1586 gboolean no_lock)
1587{
1588 GdkKeyEvent *self = (GdkKeyEvent *) event;
1589
1590 g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
1591 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_KEY_PRESS) ||
1592 GDK_IS_EVENT_TYPE (event, GDK_KEY_RELEASE), NULL);
1593
1594 if (no_lock)
1595 return &(self->translated[1]);
1596
1597 return &(self->translated[0]);
1598}
1599
1600/**
1601 * gdk_key_event_get_keyval:
1602 * @event: (type GdkKeyEvent): a key event
1603 *
1604 * Extracts the keyval from a key event.
1605 *
1606 * Returns: the keyval of @event
1607 */
1608guint
1609gdk_key_event_get_keyval (GdkEvent *event)
1610{
1611 GdkKeyEvent *self = (GdkKeyEvent *) event;
1612
1613 g_return_val_if_fail (GDK_IS_EVENT (event), 0);
1614 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_KEY_PRESS) ||
1615 GDK_IS_EVENT_TYPE (event, GDK_KEY_RELEASE), 0);
1616
1617 return self->translated[0].keyval;
1618}
1619
1620/**
1621 * gdk_key_event_get_keycode:
1622 * @event: (type GdkKeyEvent): a key event
1623 *
1624 * Extracts the keycode from a key event.
1625 *
1626 * Returns: the keycode of @event
1627 */
1628guint
1629gdk_key_event_get_keycode (GdkEvent *event)
1630{
1631 GdkKeyEvent *self = (GdkKeyEvent *) event;
1632
1633 g_return_val_if_fail (GDK_IS_EVENT (event), 0);
1634 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_KEY_PRESS) ||
1635 GDK_IS_EVENT_TYPE (event, GDK_KEY_RELEASE), 0);
1636
1637 return self->keycode;
1638}
1639
1640/**
1641 * gdk_key_event_get_level:
1642 * @event: (type GdkKeyEvent): a key event
1643 *
1644 * Extracts the shift level from a key event.
1645 *
1646 * Returns: the shift level of @event
1647 */
1648guint
1649gdk_key_event_get_level (GdkEvent *event)
1650{
1651 GdkKeyEvent *self = (GdkKeyEvent *) event;
1652
1653 g_return_val_if_fail (GDK_IS_EVENT (event), 0);
1654 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_KEY_PRESS) ||
1655 GDK_IS_EVENT_TYPE (event, GDK_KEY_RELEASE), 0);
1656
1657 return self->translated[0].level;
1658}
1659
1660/**
1661 * gdk_key_event_get_layout:
1662 * @event: (type GdkKeyEvent): a key event
1663 *
1664 * Extracts the layout from a key event.
1665 *
1666 * Returns: the layout of @event
1667 */
1668guint
1669gdk_key_event_get_layout (GdkEvent *event)
1670{
1671 GdkKeyEvent *self = (GdkKeyEvent *) event;
1672
1673 g_return_val_if_fail (GDK_IS_EVENT (event), 0);
1674 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_KEY_PRESS) ||
1675 GDK_IS_EVENT_TYPE (event, GDK_KEY_RELEASE), 0);
1676
1677 return self->translated[0].layout;
1678}
1679
1680/**
1681 * gdk_key_event_get_consumed_modifiers:
1682 * @event: (type GdkKeyEvent): a key event
1683 *
1684 * Extracts the consumed modifiers from a key event.
1685 *
1686 * Returns: the consumed modifiers or @event
1687 */
1688GdkModifierType
1689gdk_key_event_get_consumed_modifiers (GdkEvent *event)
1690{
1691 GdkKeyEvent *self = (GdkKeyEvent *) event;
1692
1693 g_return_val_if_fail (GDK_IS_EVENT (event), 0);
1694 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_KEY_PRESS) ||
1695 GDK_IS_EVENT_TYPE (event, GDK_KEY_RELEASE), 0);
1696
1697 return self->translated[0].consumed;
1698}
1699
1700/**
1701 * gdk_key_event_is_modifier:
1702 * @event: (type GdkKeyEvent): a key event
1703 *
1704 * Extracts whether the key event is for a modifier key.
1705 *
1706 * Returns: %TRUE if the @event is for a modifier key
1707 */
1708gboolean
1709gdk_key_event_is_modifier (GdkEvent *event)
1710{
1711 GdkKeyEvent *self = (GdkKeyEvent *) event;
1712
1713 g_return_val_if_fail (GDK_IS_EVENT (event), 0);
1714 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_KEY_PRESS) ||
1715 GDK_IS_EVENT_TYPE (event, GDK_KEY_RELEASE), FALSE);
1716
1717 return self->key_is_modifier;
1718}
1719
1720static gboolean
1721keyval_in_group (GdkKeymap *keymap,
1722 guint keyval,
1723 int group)
1724{
1725 GdkKeymapKey *keys;
1726 guint n_keys;
1727
1728 gdk_keymap_get_cached_entries_for_keyval (keymap, keyval, keys: &keys, n_keys: &n_keys);
1729 for (int i = 0; i < n_keys; i++)
1730 {
1731 if (keys[i].group == group)
1732 return TRUE;
1733 }
1734
1735 return FALSE;
1736}
1737
1738/**
1739 * gdk_key_event_matches:
1740 * @event: (type GdkKeyEvent): a key `GdkEvent`
1741 * @keyval: the keyval to match
1742 * @modifiers: the modifiers to match
1743 *
1744 * Matches a key event against a keyval and modifiers.
1745 *
1746 * This is typically used to trigger keyboard shortcuts such as Ctrl-C.
1747 *
1748 * Partial matches are possible where the combination matches
1749 * if the currently active group is ignored.
1750 *
1751 * Note that we ignore Caps Lock for matching.
1752 *
1753 * Returns: a `GdkKeyMatch` value describing whether @event matches
1754 */
1755GdkKeyMatch
1756gdk_key_event_matches (GdkEvent *event,
1757 guint keyval,
1758 GdkModifierType modifiers)
1759{
1760 GdkKeyEvent *self = (GdkKeyEvent *) event;
1761 GdkKeymap *keymap;
1762 guint keycode;
1763 GdkModifierType state;
1764 guint ev_keyval;
1765 int layout;
1766 int level;
1767 GdkModifierType ignored_modifiers;
1768 GdkModifierType shift_group_mask;
1769 gboolean group_mod_is_accel_mod = FALSE;
1770 const GdkModifierType mask = GDK_CONTROL_MASK |
1771 GDK_SHIFT_MASK |
1772 GDK_ALT_MASK |
1773 GDK_SUPER_MASK |
1774 GDK_HYPER_MASK |
1775 GDK_META_MASK;
1776
1777 g_return_val_if_fail (GDK_IS_EVENT (event), GDK_KEY_MATCH_NONE);
1778 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_KEY_PRESS) ||
1779 GDK_IS_EVENT_TYPE (event, GDK_KEY_RELEASE), GDK_KEY_MATCH_NONE);
1780
1781 keycode = self->keycode;
1782 state = self->state & ~GDK_LOCK_MASK;
1783 ev_keyval = self->translated[1].keyval;
1784 layout = self->translated[1].layout;
1785 level = self->translated[1].level;
1786
1787 /*
1788 * If a modifier is currently active (e.g. Shift is pressed) and was marked
1789 * as consumed, we ignore it for the purposes of matching shortcuts.
1790 * For example, when Ctrl+Shift+[plus/equals key] is translated into
1791 * Ctrl+plus on a keyboard where Shift+equals is the plus sign, we want
1792 * shortcuts for either <Control><Shift>plus or <Control>plus to match.
1793 * (See https://bugzilla.gnome.org/show_bug.cgi?id=100439)
1794 *
1795 * If a modifier is *not* currently active, the X11 backend can sometimes
1796 * mark it as consumed where the Wayland and Windows backends do not.
1797 * In this case, we still want to pay attention to its state.
1798 * For example, when Ctrl+x is translated into Ctrl+x, we only want to
1799 * trigger shortcuts for <Control>x, not for <Control><Shift>x.
1800 * (See https://gitlab.gnome.org/GNOME/gtk/-/issues/5095)
1801 */
1802 ignored_modifiers = (self->translated[1].consumed & state);
1803
1804 /* if the group-toggling modifier is part of the default accel mod
1805 * mask, and it is active, disable it for matching
1806 *
1807 * FIXME: get shift group mask from backends
1808 */
1809 shift_group_mask = 0;
1810
1811 if (mask & shift_group_mask)
1812 group_mod_is_accel_mod = TRUE;
1813
1814 if ((modifiers & ~ignored_modifiers & mask) == (state & ~ignored_modifiers & mask))
1815 {
1816 /* modifier match */
1817 GdkKeymapKey *keys;
1818 guint n_keys;
1819 int i;
1820 guint key;
1821
1822 /* Shift gets consumed and applied for the event,
1823 * so apply it to our keyval to match
1824 */
1825 key = keyval;
1826 if (modifiers & GDK_SHIFT_MASK)
1827 {
1828 if (key == GDK_KEY_Tab)
1829 key = GDK_KEY_ISO_Left_Tab;
1830 else
1831 key = gdk_keyval_to_upper (keyval: key);
1832 }
1833
1834 if (ev_keyval == key && /* exact match */
1835 (!group_mod_is_accel_mod ||
1836 (state & shift_group_mask) == (modifiers & shift_group_mask)))
1837 {
1838 return GDK_KEY_MATCH_EXACT;
1839 }
1840
1841 keymap = gdk_display_get_keymap (display: gdk_event_get_display (event));
1842 gdk_keymap_get_cached_entries_for_keyval (keymap, keyval, keys: &keys, n_keys: &n_keys);
1843
1844 for (i = 0; i < n_keys; i++)
1845 {
1846 if (keys[i].keycode == keycode &&
1847 keys[i].level == level &&
1848 /* Only match for group if it's an accel mod */
1849 (keys[i].group == layout ||
1850 (!group_mod_is_accel_mod && !keyval_in_group (keymap, keyval, group: layout))))
1851 return GDK_KEY_MATCH_PARTIAL;
1852 }
1853 }
1854
1855 return GDK_KEY_MATCH_NONE;
1856}
1857
1858/**
1859 * gdk_key_event_get_match:
1860 * @event: (type GdkKeyEvent): a key `GdkEvent`
1861 * @keyval: (out): return location for a keyval
1862 * @modifiers: (out): return location for modifiers
1863 *
1864 * Gets a keyval and modifier combination that will match
1865 * the event.
1866 *
1867 * See [method@Gdk.KeyEvent.matches].
1868 *
1869 * Returns: %TRUE on success
1870 */
1871gboolean
1872gdk_key_event_get_match (GdkEvent *event,
1873 guint *keyval,
1874 GdkModifierType *modifiers)
1875{
1876 GdkKeyEvent *self = (GdkKeyEvent *) event;
1877 guint key;
1878 guint accel_key;
1879 GdkModifierType accel_mods;
1880 GdkModifierType consumed_modifiers;
1881 const GdkModifierType mask = GDK_CONTROL_MASK |
1882 GDK_SHIFT_MASK |
1883 GDK_ALT_MASK |
1884 GDK_SUPER_MASK |
1885 GDK_HYPER_MASK |
1886 GDK_META_MASK;
1887
1888 g_return_val_if_fail (GDK_IS_EVENT (event), FALSE);
1889 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_KEY_PRESS) ||
1890 GDK_IS_EVENT_TYPE (event, GDK_KEY_RELEASE), FALSE);
1891
1892 accel_key = self->translated[1].keyval;
1893 accel_mods = self->state;
1894 consumed_modifiers = self->translated[1].consumed;
1895
1896 if (accel_key == GDK_KEY_Sys_Req &&
1897 (accel_mods & GDK_ALT_MASK) != 0)
1898 {
1899 /* HACK: we don't want to use SysRq as a keybinding (but we do
1900 * want Alt+Print), so we avoid translation from Alt+Print to SysRq
1901 */
1902 *keyval = GDK_KEY_Print;
1903 *modifiers = accel_mods & mask;
1904 return TRUE;
1905 }
1906
1907 key = gdk_keyval_to_lower (keyval: accel_key);
1908
1909 if (key == GDK_KEY_ISO_Left_Tab)
1910 key = GDK_KEY_Tab;
1911
1912 accel_mods &= mask & ~consumed_modifiers;
1913
1914 if (accel_key != key)
1915 accel_mods |= GDK_SHIFT_MASK;
1916
1917 *keyval = key;
1918 *modifiers = accel_mods;
1919
1920 return TRUE;
1921}
1922
1923/* }}} */
1924
1925/* {{{ GdkTouchEvent */
1926
1927/**
1928 * GdkTouchEvent:
1929 *
1930 * An event related to a touch-based device.
1931 */
1932
1933static void
1934gdk_touch_event_finalize (GdkEvent *event)
1935{
1936 GdkTouchEvent *self = (GdkTouchEvent *) event;
1937
1938 g_clear_pointer (&self->axes, g_free);
1939
1940 GDK_EVENT_SUPER (event)->finalize (event);
1941}
1942
1943static GdkModifierType
1944gdk_touch_event_get_state (GdkEvent *event)
1945{
1946 GdkTouchEvent *self = (GdkTouchEvent *) event;
1947
1948 return self->state;
1949}
1950
1951static gboolean
1952gdk_touch_event_get_position (GdkEvent *event,
1953 double *x,
1954 double *y)
1955{
1956 GdkTouchEvent *self = (GdkTouchEvent *) event;
1957
1958 *x = self->x;
1959 *y = self->y;
1960
1961 return TRUE;
1962}
1963
1964static GdkEventSequence *
1965gdk_touch_event_get_sequence (GdkEvent *event)
1966{
1967 GdkTouchEvent *self = (GdkTouchEvent *) event;
1968
1969 return self->sequence;
1970}
1971
1972static gboolean
1973gdk_touch_event_get_axes (GdkEvent *event,
1974 double **axes,
1975 guint *n_axes)
1976{
1977 GdkTouchEvent *self = (GdkTouchEvent *) event;
1978 GdkDevice *source_device = gdk_event_get_device (event);
1979
1980 if (source_device == NULL)
1981 return FALSE;
1982
1983 *axes = self->axes;
1984 *n_axes = GDK_AXIS_LAST;
1985
1986 return TRUE;
1987}
1988
1989static const GdkEventTypeInfo gdk_touch_event_info = {
1990 sizeof (GdkTouchEvent),
1991 NULL,
1992 gdk_touch_event_finalize,
1993 gdk_touch_event_get_state,
1994 gdk_touch_event_get_position,
1995 gdk_touch_event_get_sequence,
1996 NULL,
1997 gdk_touch_event_get_axes,
1998};
1999
2000GDK_DEFINE_EVENT_TYPE (GdkTouchEvent, gdk_touch_event,
2001 &gdk_touch_event_info,
2002 GDK_EVENT_TYPE_SLOT (GDK_TOUCH_BEGIN)
2003 GDK_EVENT_TYPE_SLOT (GDK_TOUCH_END)
2004 GDK_EVENT_TYPE_SLOT (GDK_TOUCH_UPDATE)
2005 GDK_EVENT_TYPE_SLOT (GDK_TOUCH_CANCEL))
2006
2007GdkEvent *
2008gdk_touch_event_new (GdkEventType type,
2009 GdkEventSequence *sequence,
2010 GdkSurface *surface,
2011 GdkDevice *device,
2012 guint32 time,
2013 GdkModifierType state,
2014 double x,
2015 double y,
2016 double *axes,
2017 gboolean emulating)
2018{
2019 GdkTouchEvent *self;
2020
2021 g_return_val_if_fail (type == GDK_TOUCH_BEGIN ||
2022 type == GDK_TOUCH_END ||
2023 type == GDK_TOUCH_UPDATE ||
2024 type == GDK_TOUCH_CANCEL, NULL);
2025
2026 self = gdk_event_alloc (event_type: type, surface, device, time_: time);
2027 self->sequence = sequence;
2028 self->state = state;
2029 self->x = x;
2030 self->y = y;
2031 self->axes = axes;
2032 self->touch_emulating = emulating;
2033 self->pointer_emulated = emulating;
2034
2035 return (GdkEvent *) self;
2036}
2037
2038/**
2039 * gdk_touch_event_get_emulating_pointer:
2040 * @event: (type GdkTouchEvent): a touch event
2041 *
2042 * Extracts whether a touch event is emulating a pointer event.
2043 *
2044 * Returns: %TRUE if @event is emulating
2045 **/
2046gboolean
2047gdk_touch_event_get_emulating_pointer (GdkEvent *event)
2048{
2049 GdkTouchEvent *self = (GdkTouchEvent *) event;
2050
2051 g_return_val_if_fail (GDK_IS_EVENT (event), FALSE);
2052 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_TOUCH_BEGIN) ||
2053 GDK_IS_EVENT_TYPE (event, GDK_TOUCH_UPDATE) ||
2054 GDK_IS_EVENT_TYPE (event, GDK_TOUCH_END) ||
2055 GDK_IS_EVENT_TYPE (event, GDK_TOUCH_CANCEL), FALSE);
2056
2057 return self->touch_emulating;
2058}
2059
2060/* }}} */
2061
2062/* {{{ GdkCrossingEvent */
2063
2064/**
2065 * GdkCrossingEvent:
2066 *
2067 * An event caused by a pointing device moving between surfaces.
2068 */
2069
2070static void
2071gdk_crossing_event_finalize (GdkEvent *event)
2072{
2073 GdkCrossingEvent *self = (GdkCrossingEvent *) event;
2074
2075 g_clear_object (&self->child_surface);
2076
2077 GDK_EVENT_SUPER (self)->finalize (event);
2078}
2079
2080static GdkModifierType
2081gdk_crossing_event_get_state (GdkEvent *event)
2082{
2083 GdkCrossingEvent *self = (GdkCrossingEvent *) event;
2084
2085 return self->state;
2086}
2087
2088static gboolean
2089gdk_crossing_event_get_position (GdkEvent *event,
2090 double *x,
2091 double *y)
2092{
2093 GdkCrossingEvent *self = (GdkCrossingEvent *) event;
2094
2095 *x = self->x;
2096 *y = self->y;
2097
2098 return TRUE;
2099}
2100
2101static const GdkEventTypeInfo gdk_crossing_event_info = {
2102 sizeof (GdkCrossingEvent),
2103 NULL,
2104 gdk_crossing_event_finalize,
2105 gdk_crossing_event_get_state,
2106 gdk_crossing_event_get_position,
2107 NULL,
2108 NULL,
2109 NULL,
2110};
2111
2112GDK_DEFINE_EVENT_TYPE (GdkCrossingEvent, gdk_crossing_event,
2113 &gdk_crossing_event_info,
2114 GDK_EVENT_TYPE_SLOT (GDK_ENTER_NOTIFY)
2115 GDK_EVENT_TYPE_SLOT (GDK_LEAVE_NOTIFY))
2116
2117GdkEvent *
2118gdk_crossing_event_new (GdkEventType type,
2119 GdkSurface *surface,
2120 GdkDevice *device,
2121 guint32 time,
2122 GdkModifierType state,
2123 double x,
2124 double y,
2125 GdkCrossingMode mode,
2126 GdkNotifyType detail)
2127{
2128 GdkCrossingEvent *self;
2129
2130 g_return_val_if_fail (type == GDK_ENTER_NOTIFY ||
2131 type == GDK_LEAVE_NOTIFY, NULL);
2132
2133 self = gdk_event_alloc (event_type: type, surface, device, time_: time);
2134
2135 self->state = state;
2136 self->x = x;
2137 self->y = y;
2138 self->mode = mode;
2139 self->detail = detail;
2140
2141 return (GdkEvent *) self;
2142}
2143
2144/**
2145 * gdk_crossing_event_get_mode:
2146 * @event: (type GdkCrossingEvent): a crossing event
2147 *
2148 * Extracts the crossing mode from a crossing event.
2149 *
2150 * Returns: the mode of @event
2151 */
2152GdkCrossingMode
2153gdk_crossing_event_get_mode (GdkEvent *event)
2154{
2155 GdkCrossingEvent *self = (GdkCrossingEvent *) event;
2156
2157 g_return_val_if_fail (GDK_IS_EVENT (event), 0);
2158 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_ENTER_NOTIFY) ||
2159 GDK_IS_EVENT_TYPE (event, GDK_LEAVE_NOTIFY), 0);
2160
2161 return self->mode;
2162}
2163
2164/**
2165 * gdk_crossing_event_get_focus:
2166 * @event: (type GdkCrossingEvent): a crossing event
2167 *
2168 * Checks if the @event surface is the focus surface.
2169 *
2170 * Returns: %TRUE if the surface is the focus surface
2171 */
2172gboolean
2173gdk_crossing_event_get_focus (GdkEvent *event)
2174{
2175 GdkCrossingEvent *self = (GdkCrossingEvent *) event;
2176
2177 g_return_val_if_fail (GDK_IS_EVENT (event), FALSE);
2178 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_ENTER_NOTIFY) ||
2179 GDK_IS_EVENT_TYPE (event, GDK_LEAVE_NOTIFY), FALSE);
2180
2181 return self->focus;
2182}
2183
2184/**
2185 * gdk_crossing_event_get_detail:
2186 * @event: (type GdkCrossingEvent): a crossing event
2187 *
2188 * Extracts the notify detail from a crossing event.
2189 *
2190 * Returns: the notify detail of @event
2191 */
2192GdkNotifyType
2193gdk_crossing_event_get_detail (GdkEvent *event)
2194{
2195 GdkCrossingEvent *self = (GdkCrossingEvent *) event;
2196
2197 g_return_val_if_fail (GDK_IS_EVENT (event), 0);
2198 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_ENTER_NOTIFY) ||
2199 GDK_IS_EVENT_TYPE (event, GDK_LEAVE_NOTIFY), 0);
2200
2201 return self->detail;
2202}
2203
2204/* }}} */
2205
2206/* {{{ GdkDeleteEvent */
2207
2208/**
2209 * GdkDeleteEvent:
2210 *
2211 * An event related to closing a top-level surface.
2212 */
2213
2214static const GdkEventTypeInfo gdk_delete_event_info = {
2215 sizeof (GdkDeleteEvent),
2216 NULL,
2217 NULL,
2218 NULL,
2219 NULL,
2220 NULL,
2221 NULL,
2222 NULL,
2223};
2224
2225GDK_DEFINE_EVENT_TYPE (GdkDeleteEvent, gdk_delete_event,
2226 &gdk_delete_event_info,
2227 GDK_EVENT_TYPE_SLOT (GDK_DELETE))
2228
2229GdkEvent *
2230gdk_delete_event_new (GdkSurface *surface)
2231{
2232 return gdk_event_alloc (event_type: GDK_DELETE, surface, NULL, GDK_CURRENT_TIME);
2233}
2234
2235/* }}} */
2236
2237/* {{{ GdkFocusEvent */
2238
2239/**
2240 * GdkFocusEvent:
2241 *
2242 * An event related to a keyboard focus change.
2243 */
2244
2245static const GdkEventTypeInfo gdk_focus_event_info = {
2246 sizeof (GdkFocusEvent),
2247 NULL,
2248 NULL,
2249 NULL,
2250 NULL,
2251 NULL,
2252 NULL,
2253 NULL,
2254};
2255
2256GDK_DEFINE_EVENT_TYPE (GdkFocusEvent, gdk_focus_event,
2257 &gdk_focus_event_info,
2258 GDK_EVENT_TYPE_SLOT (GDK_FOCUS_CHANGE))
2259
2260GdkEvent *
2261gdk_focus_event_new (GdkSurface *surface,
2262 GdkDevice *device,
2263 gboolean focus_in)
2264{
2265 GdkFocusEvent *self = gdk_event_alloc (event_type: GDK_FOCUS_CHANGE, surface, device, GDK_CURRENT_TIME);
2266
2267 self->focus_in = focus_in;
2268
2269 return (GdkEvent *) self;
2270}
2271
2272/**
2273 * gdk_focus_event_get_in:
2274 * @event: (type GdkFocusEvent): a focus change event
2275 *
2276 * Extracts whether this event is about focus entering or
2277 * leaving the surface.
2278 *
2279 * Returns: %TRUE of the focus is entering
2280 */
2281gboolean
2282gdk_focus_event_get_in (GdkEvent *event)
2283{
2284 GdkFocusEvent *self = (GdkFocusEvent *) event;
2285
2286 g_return_val_if_fail (GDK_IS_EVENT (event), FALSE);
2287 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_FOCUS_CHANGE), FALSE);
2288
2289 return self->focus_in;
2290}
2291
2292/* }}} */
2293
2294/* {{{ GdkScrollEvent */
2295
2296/**
2297 * GdkScrollEvent:
2298 *
2299 * An event related to a scrolling motion.
2300 */
2301
2302static void
2303gdk_scroll_event_finalize (GdkEvent *event)
2304{
2305 GdkScrollEvent *self = (GdkScrollEvent *) event;
2306
2307 g_clear_object (&self->tool);
2308 if (self->history)
2309 g_array_free (array: self->history, TRUE);
2310
2311 GDK_EVENT_SUPER (self)->finalize (event);
2312}
2313
2314static GdkModifierType
2315gdk_scroll_event_get_state (GdkEvent *event)
2316{
2317 GdkScrollEvent *self = (GdkScrollEvent *) event;
2318
2319 return self->state;
2320}
2321
2322static GdkDeviceTool *
2323gdk_scroll_event_get_tool (GdkEvent *event)
2324{
2325 GdkScrollEvent *self = (GdkScrollEvent *) event;
2326
2327 return self->tool;
2328}
2329
2330static const GdkEventTypeInfo gdk_scroll_event_info = {
2331 sizeof (GdkScrollEvent),
2332 NULL,
2333 gdk_scroll_event_finalize,
2334 gdk_scroll_event_get_state,
2335 NULL,
2336 NULL,
2337 gdk_scroll_event_get_tool,
2338 NULL,
2339};
2340
2341GDK_DEFINE_EVENT_TYPE (GdkScrollEvent, gdk_scroll_event,
2342 &gdk_scroll_event_info,
2343 GDK_EVENT_TYPE_SLOT (GDK_SCROLL))
2344
2345GdkEvent *
2346gdk_scroll_event_new (GdkSurface *surface,
2347 GdkDevice *device,
2348 GdkDeviceTool *tool,
2349 guint32 time,
2350 GdkModifierType state,
2351 double delta_x,
2352 double delta_y,
2353 gboolean is_stop)
2354{
2355 GdkScrollEvent *self = gdk_event_alloc (event_type: GDK_SCROLL, surface, device, time_: time);
2356
2357 self->tool = tool != NULL ? g_object_ref (tool) : NULL;
2358 self->state = state;
2359 self->direction = GDK_SCROLL_SMOOTH;
2360 self->delta_x = delta_x;
2361 self->delta_y = delta_y;
2362 self->is_stop = is_stop;
2363
2364 return (GdkEvent *) self;
2365}
2366
2367GdkEvent *
2368gdk_scroll_event_new_discrete (GdkSurface *surface,
2369 GdkDevice *device,
2370 GdkDeviceTool *tool,
2371 guint32 time,
2372 GdkModifierType state,
2373 GdkScrollDirection direction,
2374 gboolean emulated)
2375{
2376 GdkScrollEvent *self = gdk_event_alloc (event_type: GDK_SCROLL, surface, device, time_: time);
2377
2378 self->tool = tool != NULL ? g_object_ref (tool) : NULL;
2379 self->state = state;
2380 self->direction = direction;
2381 self->pointer_emulated = emulated;
2382
2383 return (GdkEvent *) self;
2384}
2385
2386/**
2387 * gdk_scroll_event_get_direction:
2388 * @event: (type GdkScrollEvent): a scroll event
2389 *
2390 * Extracts the direction of a scroll event.
2391 *
2392 * Returns: the scroll direction of @event
2393 */
2394GdkScrollDirection
2395gdk_scroll_event_get_direction (GdkEvent *event)
2396{
2397 GdkScrollEvent *self = (GdkScrollEvent *) event;
2398
2399 g_return_val_if_fail (GDK_IS_EVENT (event), 0);
2400 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_SCROLL), 0);
2401
2402 return self->direction;
2403}
2404
2405/**
2406 * gdk_scroll_event_get_deltas:
2407 * @event: (type GdkScrollEvent): a scroll event
2408 * @delta_x: (out): return location for x scroll delta
2409 * @delta_y: (out): return location for y scroll delta
2410 *
2411 * Extracts the scroll deltas of a scroll event.
2412 *
2413 * The deltas will be zero unless the scroll direction
2414 * is %GDK_SCROLL_SMOOTH.
2415 */
2416void
2417gdk_scroll_event_get_deltas (GdkEvent *event,
2418 double *delta_x,
2419 double *delta_y)
2420{
2421 GdkScrollEvent *self = (GdkScrollEvent *) event;
2422
2423 g_return_if_fail (GDK_IS_EVENT (event));
2424 g_return_if_fail (GDK_IS_EVENT_TYPE (event, GDK_SCROLL));
2425
2426 *delta_x = self->delta_x;
2427 *delta_y = self->delta_y;
2428}
2429
2430/**
2431 * gdk_scroll_event_is_stop:
2432 * @event: (type GdkScrollEvent): a scroll event
2433 *
2434 * Check whether a scroll event is a stop scroll event.
2435 *
2436 * Scroll sequences with smooth scroll information may provide
2437 * a stop scroll event once the interaction with the device finishes,
2438 * e.g. by lifting a finger. This stop scroll event is the signal
2439 * that a widget may trigger kinetic scrolling based on the current
2440 * velocity.
2441 *
2442 * Stop scroll events always have a delta of 0/0.
2443 *
2444 * Returns: %TRUE if the event is a scroll stop event
2445 */
2446gboolean
2447gdk_scroll_event_is_stop (GdkEvent *event)
2448{
2449 GdkScrollEvent *self = (GdkScrollEvent *) event;
2450
2451 g_return_val_if_fail (GDK_IS_EVENT (event), FALSE);
2452 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_SCROLL), FALSE);
2453
2454 return self->is_stop;
2455}
2456
2457/* }}} */
2458
2459/* {{{ GdkTouchpadEvent */
2460
2461/**
2462 * GdkTouchpadEvent:
2463 *
2464 * An event related to a gesture on a touchpad device.
2465 *
2466 * Unlike touchscreens, where the windowing system sends basic
2467 * sequences of begin, update, end events, and leaves gesture
2468 * recognition to the clients, touchpad gestures are typically
2469 * processed by the system, resulting in these events.
2470 */
2471
2472static GdkModifierType
2473gdk_touchpad_event_get_state (GdkEvent *event)
2474{
2475 GdkTouchpadEvent *self = (GdkTouchpadEvent *) event;
2476
2477 return self->state;
2478}
2479
2480static GdkEventSequence *
2481gdk_touchpad_event_get_sequence (GdkEvent *event)
2482{
2483 GdkTouchpadEvent *self = (GdkTouchpadEvent *) event;
2484
2485 return self->sequence;
2486}
2487
2488static gboolean
2489gdk_touchpad_event_get_position (GdkEvent *event,
2490 double *x,
2491 double *y)
2492{
2493 GdkTouchpadEvent *self = (GdkTouchpadEvent *) event;
2494
2495 *x = self->x;
2496 *y = self->y;
2497
2498 return TRUE;
2499}
2500
2501static const GdkEventTypeInfo gdk_touchpad_event_info = {
2502 sizeof (GdkTouchpadEvent),
2503 NULL,
2504 NULL,
2505 gdk_touchpad_event_get_state,
2506 gdk_touchpad_event_get_position,
2507 gdk_touchpad_event_get_sequence,
2508 NULL,
2509 NULL,
2510};
2511
2512GDK_DEFINE_EVENT_TYPE (GdkTouchpadEvent, gdk_touchpad_event,
2513 &gdk_touchpad_event_info,
2514 GDK_EVENT_TYPE_SLOT (GDK_TOUCHPAD_SWIPE)
2515 GDK_EVENT_TYPE_SLOT (GDK_TOUCHPAD_PINCH)
2516 GDK_EVENT_TYPE_SLOT (GDK_TOUCHPAD_HOLD))
2517
2518GdkEvent *
2519gdk_touchpad_event_new_swipe (GdkSurface *surface,
2520 GdkEventSequence *sequence,
2521 GdkDevice *device,
2522 guint32 time,
2523 GdkModifierType state,
2524 GdkTouchpadGesturePhase phase,
2525 double x,
2526 double y,
2527 int n_fingers,
2528 double dx,
2529 double dy)
2530{
2531 GdkTouchpadEvent *self;
2532
2533 g_return_val_if_fail (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN ||
2534 phase == GDK_TOUCHPAD_GESTURE_PHASE_END ||
2535 phase == GDK_TOUCHPAD_GESTURE_PHASE_UPDATE ||
2536 phase == GDK_TOUCHPAD_GESTURE_PHASE_CANCEL, NULL);
2537
2538 self = gdk_event_alloc (event_type: GDK_TOUCHPAD_SWIPE, surface, device, time_: time);
2539
2540 self->sequence = sequence;
2541 self->state = state;
2542 self->phase = phase;
2543 self->x = x;
2544 self->y = y;
2545 self->dx = dx;
2546 self->dy = dy;
2547 self->n_fingers = n_fingers;
2548
2549 return (GdkEvent *) self;
2550}
2551
2552GdkEvent *
2553gdk_touchpad_event_new_pinch (GdkSurface *surface,
2554 GdkEventSequence *sequence,
2555 GdkDevice *device,
2556 guint32 time,
2557 GdkModifierType state,
2558 GdkTouchpadGesturePhase phase,
2559 double x,
2560 double y,
2561 int n_fingers,
2562 double dx,
2563 double dy,
2564 double scale,
2565 double angle_delta)
2566{
2567 GdkTouchpadEvent *self;
2568
2569 g_return_val_if_fail (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN ||
2570 phase == GDK_TOUCHPAD_GESTURE_PHASE_END ||
2571 phase == GDK_TOUCHPAD_GESTURE_PHASE_UPDATE ||
2572 phase == GDK_TOUCHPAD_GESTURE_PHASE_CANCEL, NULL);
2573
2574 self = gdk_event_alloc (event_type: GDK_TOUCHPAD_PINCH, surface, device, time_: time);
2575
2576 self->sequence = sequence;
2577 self->state = state;
2578 self->phase = phase;
2579 self->x = x;
2580 self->y = y;
2581 self->dx = dx;
2582 self->dy = dy;
2583 self->n_fingers = n_fingers;
2584 self->scale = scale;
2585 self->angle_delta = angle_delta;
2586
2587 return (GdkEvent *) self;
2588}
2589
2590GdkEvent *
2591gdk_touchpad_event_new_hold (GdkSurface *surface,
2592 GdkDevice *device,
2593 guint32 time,
2594 GdkModifierType state,
2595 GdkTouchpadGesturePhase phase,
2596 double x,
2597 double y,
2598 int n_fingers)
2599{
2600 GdkTouchpadEvent *self = gdk_event_alloc (event_type: GDK_TOUCHPAD_HOLD, surface, device, time_: time);
2601
2602 self->state = state;
2603 self->phase = phase;
2604 self->x = x;
2605 self->y = y;
2606 self->n_fingers = n_fingers;
2607
2608 return (GdkEvent *) self;
2609}
2610
2611/**
2612 * gdk_touchpad_event_get_gesture_phase:
2613 * @event: (type GdkTouchpadEvent): a touchpad event
2614 *
2615 * Extracts the touchpad gesture phase from a touchpad event.
2616 *
2617 * Returns: the gesture phase of @event
2618 **/
2619GdkTouchpadGesturePhase
2620gdk_touchpad_event_get_gesture_phase (GdkEvent *event)
2621{
2622 GdkTouchpadEvent *self = (GdkTouchpadEvent *) event;
2623
2624 g_return_val_if_fail (GDK_IS_EVENT (event), 0);
2625 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_PINCH) ||
2626 GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_SWIPE) ||
2627 GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_HOLD), 0);
2628
2629 return self->phase;
2630}
2631
2632/**
2633 * gdk_touchpad_event_get_n_fingers:
2634 * @event: (type GdkTouchpadEvent): a touchpad event
2635 *
2636 * Extracts the number of fingers from a touchpad event.
2637 *
2638 * Returns: the number of fingers for @event
2639 **/
2640guint
2641gdk_touchpad_event_get_n_fingers (GdkEvent *event)
2642{
2643 GdkTouchpadEvent *self = (GdkTouchpadEvent *) event;
2644
2645 g_return_val_if_fail (GDK_IS_EVENT (event), 0);
2646 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_PINCH) ||
2647 GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_SWIPE) ||
2648 GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_HOLD), 0);
2649
2650 return self->n_fingers;
2651}
2652
2653/**
2654 * gdk_touchpad_event_get_deltas:
2655 * @event: (type GdkTouchpadEvent): a touchpad event
2656 * @dx: (out): return location for x
2657 * @dy: (out): return location for y
2658 *
2659 * Extracts delta information from a touchpad event.
2660 */
2661void
2662gdk_touchpad_event_get_deltas (GdkEvent *event,
2663 double *dx,
2664 double *dy)
2665{
2666 GdkTouchpadEvent *self = (GdkTouchpadEvent *) event;
2667
2668 g_return_if_fail (GDK_IS_EVENT (event));
2669 g_return_if_fail (GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_PINCH) ||
2670 GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_SWIPE));
2671
2672 *dx = self->dx;
2673 *dy = self->dy;
2674}
2675
2676/**
2677 * gdk_touchpad_event_get_pinch_angle_delta:
2678 * @event: (type GdkTouchpadEvent): a touchpad pinch event
2679 *
2680 * Extracts the angle delta from a touchpad pinch event.
2681 *
2682 * Returns: the angle delta of @event
2683 */
2684double
2685gdk_touchpad_event_get_pinch_angle_delta (GdkEvent *event)
2686{
2687 GdkTouchpadEvent *self = (GdkTouchpadEvent *) event;
2688
2689 g_return_val_if_fail (GDK_IS_EVENT (event), 0.0);
2690 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_PINCH), 0.0);
2691
2692 return self->angle_delta;
2693}
2694
2695/**
2696 * gdk_touchpad_event_get_pinch_scale:
2697 * @event: (type GdkTouchpadEvent): a touchpad pinch event
2698 *
2699 * Extracts the scale from a touchpad pinch event.
2700 *
2701 * Returns: the scale of @event
2702 **/
2703double
2704gdk_touchpad_event_get_pinch_scale (GdkEvent *event)
2705{
2706 GdkTouchpadEvent *self = (GdkTouchpadEvent *) event;
2707
2708 g_return_val_if_fail (GDK_IS_EVENT (event), 0.0);
2709 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_TOUCHPAD_PINCH), 0.0);
2710
2711 return self->scale;
2712}
2713
2714/* }}} */
2715
2716/* {{{ GdkPadEvent */
2717
2718/**
2719 * GdkPadEvent:
2720 *
2721 * An event related to a pad-based device.
2722 */
2723
2724static const GdkEventTypeInfo gdk_pad_event_info = {
2725 sizeof (GdkPadEvent),
2726 NULL,
2727 NULL,
2728 NULL,
2729 NULL,
2730 NULL,
2731 NULL,
2732 NULL,
2733};
2734
2735GDK_DEFINE_EVENT_TYPE (GdkPadEvent, gdk_pad_event,
2736 &gdk_pad_event_info,
2737 GDK_EVENT_TYPE_SLOT (GDK_PAD_BUTTON_PRESS)
2738 GDK_EVENT_TYPE_SLOT (GDK_PAD_BUTTON_RELEASE)
2739 GDK_EVENT_TYPE_SLOT (GDK_PAD_RING)
2740 GDK_EVENT_TYPE_SLOT (GDK_PAD_STRIP)
2741 GDK_EVENT_TYPE_SLOT (GDK_PAD_GROUP_MODE))
2742
2743GdkEvent *
2744gdk_pad_event_new_ring (GdkSurface *surface,
2745 GdkDevice *device,
2746 guint32 time,
2747 guint group,
2748 guint index,
2749 guint mode,
2750 double value)
2751{
2752 GdkPadEvent *self = gdk_event_alloc (event_type: GDK_PAD_RING, surface, device, time_: time);
2753
2754 self->group = group;
2755 self->index = index;
2756 self->mode = mode;
2757 self->value = value;
2758
2759 return (GdkEvent *) self;
2760}
2761
2762GdkEvent *
2763gdk_pad_event_new_strip (GdkSurface *surface,
2764 GdkDevice *device,
2765 guint32 time,
2766 guint group,
2767 guint index,
2768 guint mode,
2769 double value)
2770{
2771 GdkPadEvent *self = gdk_event_alloc (event_type: GDK_PAD_STRIP, surface, device, time_: time);
2772
2773 self->group = group;
2774 self->index = index;
2775 self->mode = mode;
2776 self->value = value;
2777
2778 return (GdkEvent *) self;
2779}
2780
2781GdkEvent *
2782gdk_pad_event_new_button (GdkEventType type,
2783 GdkSurface *surface,
2784 GdkDevice *device,
2785 guint32 time,
2786 guint group,
2787 guint button,
2788 guint mode)
2789{
2790 GdkPadEvent *self;
2791
2792 g_return_val_if_fail (type == GDK_PAD_BUTTON_PRESS ||
2793 type == GDK_PAD_BUTTON_RELEASE, NULL);
2794
2795 self = gdk_event_alloc (event_type: type, surface, device, time_: time);
2796
2797 self->group = group;
2798 self->button = button;
2799 self->mode = mode;
2800
2801 return (GdkEvent *) self;
2802}
2803
2804GdkEvent *
2805gdk_pad_event_new_group_mode (GdkSurface *surface,
2806 GdkDevice *device,
2807 guint32 time,
2808 guint group,
2809 guint mode)
2810{
2811 GdkPadEvent *self = gdk_event_alloc (event_type: GDK_PAD_GROUP_MODE, surface, device, time_: time);
2812
2813 self->group = group;
2814 self->mode = mode;
2815
2816 return (GdkEvent *) self;
2817}
2818/**
2819 * gdk_pad_event_get_button:
2820 * @event: (type GdkPadEvent): a pad button event
2821 *
2822 * Extracts information about the pressed button from
2823 * a pad event.
2824 *
2825 * Returns: the button of @event
2826 */
2827guint
2828gdk_pad_event_get_button (GdkEvent *event)
2829{
2830 GdkPadEvent *self = (GdkPadEvent *) event;
2831
2832 g_return_val_if_fail (GDK_IS_EVENT (event), 0);
2833 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_PAD_BUTTON_PRESS) ||
2834 GDK_IS_EVENT_TYPE (event, GDK_PAD_BUTTON_RELEASE), 0);
2835
2836 return self->button;
2837}
2838
2839/**
2840 * gdk_pad_event_get_axis_value:
2841 * @event: (type GdkPadEvent): a pad strip or ring event
2842 * @index: (out): Return location for the axis index
2843 * @value: (out): Return location for the axis value
2844 *
2845 * Extracts the information from a pad strip or ring event.
2846 */
2847void
2848gdk_pad_event_get_axis_value (GdkEvent *event,
2849 guint *index,
2850 double *value)
2851{
2852 GdkPadEvent *self = (GdkPadEvent *) event;
2853
2854 g_return_if_fail (GDK_IS_EVENT (event));
2855 g_return_if_fail (GDK_IS_EVENT_TYPE (event, GDK_PAD_RING) ||
2856 GDK_IS_EVENT_TYPE (event, GDK_PAD_STRIP));
2857
2858 *index = self->index;
2859 *value = self->value;
2860}
2861
2862/**
2863 * gdk_pad_event_get_group_mode:
2864 * @event: (type GdkPadEvent): a pad event
2865 * @group: (out): return location for the group
2866 * @mode: (out): return location for the mode
2867 *
2868 * Extracts group and mode information from a pad event.
2869 */
2870void
2871gdk_pad_event_get_group_mode (GdkEvent *event,
2872 guint *group,
2873 guint *mode)
2874{
2875 GdkPadEvent *self = (GdkPadEvent *) event;
2876
2877 g_return_if_fail (GDK_IS_EVENT (event));
2878 g_return_if_fail (GDK_IS_EVENT_TYPE (event, GDK_PAD_GROUP_MODE) ||
2879 GDK_IS_EVENT_TYPE (event, GDK_PAD_BUTTON_PRESS) ||
2880 GDK_IS_EVENT_TYPE (event, GDK_PAD_BUTTON_RELEASE) ||
2881 GDK_IS_EVENT_TYPE (event, GDK_PAD_RING) ||
2882 GDK_IS_EVENT_TYPE (event, GDK_PAD_STRIP));
2883
2884 *group = self->group;
2885 *mode = self->mode;
2886}
2887
2888/* }}} */
2889
2890/* {{{ GdkMotionEvent */
2891
2892/**
2893 * GdkMotionEvent:
2894 *
2895 * An event related to a pointer or touch device motion.
2896 */
2897
2898static void
2899gdk_motion_event_finalize (GdkEvent *event)
2900{
2901 GdkMotionEvent *self = (GdkMotionEvent *) event;
2902
2903 g_clear_object (&self->tool);
2904 g_clear_pointer (&self->axes, g_free);
2905 if (self->history)
2906 g_array_free (array: self->history, TRUE);
2907
2908 GDK_EVENT_SUPER (event)->finalize (event);
2909}
2910
2911static GdkModifierType
2912gdk_motion_event_get_state (GdkEvent *event)
2913{
2914 GdkMotionEvent *self = (GdkMotionEvent *) event;
2915
2916 return self->state;
2917}
2918
2919static gboolean
2920gdk_motion_event_get_position (GdkEvent *event,
2921 double *x,
2922 double *y)
2923{
2924 GdkMotionEvent *self = (GdkMotionEvent *) event;
2925
2926 *x = self->x;
2927 *y = self->y;
2928
2929 return TRUE;
2930}
2931
2932static GdkDeviceTool *
2933gdk_motion_event_get_tool (GdkEvent *event)
2934{
2935 GdkMotionEvent *self = (GdkMotionEvent *) event;
2936
2937 return self->tool;
2938}
2939
2940static gboolean
2941gdk_motion_event_get_axes (GdkEvent *event,
2942 double **axes,
2943 guint *n_axes)
2944{
2945 GdkMotionEvent *self = (GdkMotionEvent *) event;
2946 GdkDevice *source_device = gdk_event_get_device (event);
2947
2948 if (source_device == NULL)
2949 return FALSE;
2950
2951 *axes = self->axes;
2952 *n_axes = GDK_AXIS_LAST;
2953
2954 return TRUE;
2955}
2956
2957static const GdkEventTypeInfo gdk_motion_event_info = {
2958 sizeof (GdkMotionEvent),
2959 NULL,
2960 gdk_motion_event_finalize,
2961 gdk_motion_event_get_state,
2962 gdk_motion_event_get_position,
2963 NULL,
2964 gdk_motion_event_get_tool,
2965 gdk_motion_event_get_axes,
2966};
2967
2968GDK_DEFINE_EVENT_TYPE (GdkMotionEvent, gdk_motion_event,
2969 &gdk_motion_event_info,
2970 GDK_EVENT_TYPE_SLOT (GDK_MOTION_NOTIFY))
2971
2972GdkEvent *
2973gdk_motion_event_new (GdkSurface *surface,
2974 GdkDevice *device,
2975 GdkDeviceTool *tool,
2976 guint32 time,
2977 GdkModifierType state,
2978 double x,
2979 double y,
2980 double *axes)
2981{
2982 GdkMotionEvent *self = gdk_event_alloc (event_type: GDK_MOTION_NOTIFY, surface, device, time_: time);
2983
2984 self->tool = tool ? g_object_ref (tool) : NULL;
2985 self->state = state;
2986 self->x = x;
2987 self->y = y;
2988 self->axes = axes;
2989 self->state = state;
2990
2991 return (GdkEvent *) self;
2992}
2993
2994/**
2995 * gdk_event_get_history:
2996 * @event: a motion or scroll event
2997 * @out_n_coords: (out): Return location for the length of the returned array
2998 *
2999 * Retrieves the history of the device that @event is for, as a list of
3000 * time and coordinates.
3001 *
3002 * The history includes positions that are not delivered as separate events
3003 * to the application because they occurred in the same frame as @event.
3004 *
3005 * Note that only motion and scroll events record history, and motion
3006 * events do it only if one of the mouse buttons is down, or the device
3007 * has a tool.
3008 *
3009 * Returns: (transfer container) (array length=out_n_coords) (nullable): an
3010 * array of time and coordinates
3011 */
3012GdkTimeCoord *
3013gdk_event_get_history (GdkEvent *event,
3014 guint *out_n_coords)
3015{
3016 GArray *history;
3017
3018 g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
3019 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_MOTION_NOTIFY) ||
3020 GDK_IS_EVENT_TYPE (event, GDK_SCROLL), NULL);
3021 g_return_val_if_fail (out_n_coords != NULL, NULL);
3022
3023 if (GDK_IS_EVENT_TYPE (event, GDK_MOTION_NOTIFY))
3024 {
3025 GdkMotionEvent *self = (GdkMotionEvent *) event;
3026 history = self->history;
3027 }
3028 else
3029 {
3030 GdkScrollEvent *self = (GdkScrollEvent *) event;
3031 history = self->history;
3032 }
3033
3034 if (history && history->len > 0)
3035 {
3036 GdkTimeCoord *result;
3037
3038 *out_n_coords = history->len;
3039
3040 result = g_malloc (n_bytes: sizeof (GdkTimeCoord) * history->len);
3041 memcpy (dest: result, src: history->data, n: sizeof (GdkTimeCoord) * history->len);
3042
3043 return result;
3044 }
3045
3046 *out_n_coords = 0;
3047 return NULL;
3048}
3049
3050/* }}} */
3051
3052/* {{{ GdkProximityEvent */
3053
3054/**
3055 * GdkProximityEvent:
3056 *
3057 * An event related to the proximity of a tool to a device.
3058 */
3059
3060static void
3061gdk_proximity_event_finalize (GdkEvent *event)
3062{
3063 GdkProximityEvent *self = (GdkProximityEvent *) event;
3064
3065 g_clear_object (&self->tool);
3066
3067 GDK_EVENT_SUPER (event)->finalize (event);
3068}
3069
3070static GdkDeviceTool *
3071gdk_proximity_event_get_tool (GdkEvent *event)
3072{
3073 GdkProximityEvent *self = (GdkProximityEvent *) event;
3074
3075 return self->tool;
3076}
3077
3078static const GdkEventTypeInfo gdk_proximity_event_info = {
3079 sizeof (GdkProximityEvent),
3080 NULL,
3081 gdk_proximity_event_finalize,
3082 NULL,
3083 NULL,
3084 NULL,
3085 gdk_proximity_event_get_tool,
3086 NULL,
3087};
3088
3089GDK_DEFINE_EVENT_TYPE (GdkProximityEvent, gdk_proximity_event,
3090 &gdk_proximity_event_info,
3091 GDK_EVENT_TYPE_SLOT (GDK_PROXIMITY_IN)
3092 GDK_EVENT_TYPE_SLOT (GDK_PROXIMITY_OUT))
3093
3094GdkEvent *
3095gdk_proximity_event_new (GdkEventType type,
3096 GdkSurface *surface,
3097 GdkDevice *device,
3098 GdkDeviceTool *tool,
3099 guint32 time)
3100{
3101 GdkProximityEvent *self;
3102
3103 g_return_val_if_fail (type == GDK_PROXIMITY_IN ||
3104 type == GDK_PROXIMITY_OUT, NULL);
3105
3106 self = gdk_event_alloc (event_type: type, surface, device, time_: time);
3107
3108 self->tool = tool ? g_object_ref (tool) : NULL;
3109
3110 return (GdkEvent *) self;
3111}
3112
3113/* }}} */
3114
3115/* {{{ GdkDNDEvent */
3116
3117/**
3118 * GdkDNDEvent:
3119 *
3120 * An event related to drag and drop operations.
3121 */
3122
3123static void
3124gdk_dnd_event_finalize (GdkEvent *event)
3125{
3126 GdkDNDEvent *self = (GdkDNDEvent *) event;
3127
3128 g_clear_object (&self->drop);
3129
3130 GDK_EVENT_SUPER (event)->finalize (event);
3131}
3132
3133static gboolean
3134gdk_dnd_event_get_position (GdkEvent *event,
3135 double *x,
3136 double *y)
3137{
3138 GdkDNDEvent *self = (GdkDNDEvent *) event;
3139
3140 *x = self->x;
3141 *y = self->y;
3142
3143 return TRUE;
3144}
3145
3146static GdkEventSequence *
3147gdk_dnd_event_get_sequence (GdkEvent *event)
3148{
3149 GdkDNDEvent *self = (GdkDNDEvent *) event;
3150
3151 return (GdkEventSequence *) self->drop;
3152}
3153
3154static const GdkEventTypeInfo gdk_dnd_event_info = {
3155 sizeof (GdkDNDEvent),
3156 NULL,
3157 gdk_dnd_event_finalize,
3158 NULL,
3159 gdk_dnd_event_get_position,
3160 gdk_dnd_event_get_sequence,
3161 NULL,
3162 NULL,
3163};
3164
3165GDK_DEFINE_EVENT_TYPE (GdkDNDEvent, gdk_dnd_event,
3166 &gdk_dnd_event_info,
3167 GDK_EVENT_TYPE_SLOT (GDK_DRAG_ENTER)
3168 GDK_EVENT_TYPE_SLOT (GDK_DRAG_MOTION)
3169 GDK_EVENT_TYPE_SLOT (GDK_DRAG_LEAVE)
3170 GDK_EVENT_TYPE_SLOT (GDK_DROP_START))
3171
3172GdkEvent *
3173gdk_dnd_event_new (GdkEventType type,
3174 GdkSurface *surface,
3175 GdkDevice *device,
3176 GdkDrop *drop,
3177 guint32 time,
3178 double x,
3179 double y)
3180{
3181 GdkDNDEvent *self;
3182
3183 g_return_val_if_fail (type == GDK_DRAG_ENTER ||
3184 type == GDK_DRAG_MOTION ||
3185 type == GDK_DRAG_LEAVE ||
3186 type == GDK_DROP_START, NULL);
3187
3188 self = gdk_event_alloc (event_type: type, surface, device, time_: time);
3189
3190 self->drop = drop != NULL ? g_object_ref (drop) : NULL;
3191 self->x = x;
3192 self->y = y;
3193
3194 return (GdkEvent *) self;
3195}
3196
3197/**
3198 * gdk_dnd_event_get_drop:
3199 * @event: (type GdkDNDEvent): a DND event
3200 *
3201 * Gets the `GdkDrop` object from a DND event.
3202 *
3203 * Returns: (transfer none) (nullable): the drop
3204 **/
3205GdkDrop *
3206gdk_dnd_event_get_drop (GdkEvent *event)
3207{
3208 GdkDNDEvent *self = (GdkDNDEvent *) event;
3209
3210 g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
3211 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_DRAG_ENTER) ||
3212 GDK_IS_EVENT_TYPE (event, GDK_DRAG_MOTION) ||
3213 GDK_IS_EVENT_TYPE (event, GDK_DRAG_LEAVE) ||
3214 GDK_IS_EVENT_TYPE (event, GDK_DROP_START), NULL);
3215
3216 return self->drop;
3217}
3218
3219/* }}} */
3220
3221/* {{{ GdkGrabBrokenEvent */
3222
3223/**
3224 * GdkGrabBrokenEvent:
3225 *
3226 * An event related to a broken windowing system grab.
3227 */
3228
3229static const GdkEventTypeInfo gdk_grab_broken_event_info = {
3230 sizeof (GdkGrabBrokenEvent),
3231 NULL,
3232 NULL,
3233 NULL,
3234 NULL,
3235 NULL,
3236 NULL,
3237 NULL,
3238};
3239
3240GDK_DEFINE_EVENT_TYPE (GdkGrabBrokenEvent, gdk_grab_broken_event,
3241 &gdk_grab_broken_event_info,
3242 GDK_EVENT_TYPE_SLOT (GDK_GRAB_BROKEN))
3243
3244GdkEvent *
3245gdk_grab_broken_event_new (GdkSurface *surface,
3246 GdkDevice *device,
3247 GdkSurface *grab_surface,
3248 gboolean implicit)
3249{
3250 GdkGrabBrokenEvent *self = gdk_event_alloc (event_type: GDK_GRAB_BROKEN, surface, device, GDK_CURRENT_TIME);
3251
3252 self->grab_surface = grab_surface;
3253 self->implicit = implicit;
3254 self->keyboard = gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD;
3255
3256 return (GdkEvent *) self;
3257}
3258
3259/**
3260 * gdk_grab_broken_event_get_grab_surface:
3261 * @event: (type GdkGrabBrokenEvent): a grab broken event
3262 *
3263 * Extracts the grab surface from a grab broken event.
3264 *
3265 * Returns: (transfer none): the grab surface of @event
3266 **/
3267GdkSurface *
3268gdk_grab_broken_event_get_grab_surface (GdkEvent *event)
3269{
3270 GdkGrabBrokenEvent *self = (GdkGrabBrokenEvent *) event;
3271
3272 g_return_val_if_fail (GDK_IS_EVENT (event), NULL);
3273 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_GRAB_BROKEN), NULL);
3274
3275 return self->grab_surface;
3276}
3277
3278/**
3279 * gdk_grab_broken_event_get_implicit:
3280 * @event: (type GdkGrabBrokenEvent): a grab broken event
3281 *
3282 * Checks whether the grab broken event is for an implicit grab.
3283 *
3284 * Returns: %TRUE if the an implicit grab was broken
3285 */
3286gboolean
3287gdk_grab_broken_event_get_implicit (GdkEvent *event)
3288{
3289 GdkGrabBrokenEvent *self = (GdkGrabBrokenEvent *) event;
3290
3291 g_return_val_if_fail (GDK_IS_EVENT (event), FALSE);
3292 g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_GRAB_BROKEN), FALSE);
3293
3294 return self->implicit;
3295}
3296
3297/* }}} */
3298

source code of gtk/gdk/gdkevents.c