gdkevents.c 85 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GDK - The GIMP Drawing Kit
2
3
4
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6
7
8
9
10
11
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * 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
Javier Jardón's avatar
Javier Jardón committed
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
21
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
Matthias Clasen's avatar
Matthias Clasen committed
22
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23
24
 */

25
#include "config.h"
26

27
#include "gdkdisplayprivate.h"
Matthias Clasen's avatar
Matthias Clasen committed
28
#include "gdkdragprivate.h"
Benjamin Otte's avatar
Benjamin Otte committed
29
#include "gdkdropprivate.h"
30
31
#include "gdkeventsprivate.h"
#include "gdkintl.h"
32
#include "gdkkeysprivate.h"
33
#include "gdkkeysyms.h"
34
#include "gdk-private.h"
35

36
37
#include <gobject/gvaluecollector.h>

38
39
#include <string.h>
#include <math.h>
40

Matthias Clasen's avatar
Matthias Clasen committed
41
/**
42
 * GdkEvent: (ref-func gdk_event_ref) (unref-func gdk_event_unref)
Matthias Clasen's avatar
Matthias Clasen committed
43
 *
Matthias Clasen's avatar
Matthias Clasen committed
44
45
 * `GdkEvent`s are immutable data structures, created by GDK to
 * represent windowing system events.
46
47
48
49
 *
 * In GTK applications the events are handled automatically by toplevel
 * widgets and passed on to the event controllers of appropriate widgets,
 * so using `GdkEvent` and its related API is rarely needed.
Matthias Clasen's avatar
Matthias Clasen committed
50
51
52
53
54
 */

/**
 * GdkEventSequence:
 *
Matthias Clasen's avatar
Matthias Clasen committed
55
 * `GdkEventSequence` is an opaque type representing a sequence
Matthias Clasen's avatar
Matthias Clasen committed
56
57
 * of related touch events.
 */
58

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
static void
value_event_init (GValue *value)
{
  value->data[0].v_pointer = NULL;
}

static void
value_event_free_value (GValue *value)
{
  if (value->data[0].v_pointer != NULL)
    gdk_event_unref (value->data[0].v_pointer);
}

static void
value_event_copy_value (const GValue *src,
                        GValue       *dst)
{
  if (src->data[0].v_pointer != NULL)
    dst->data[0].v_pointer = gdk_event_ref (src->data[0].v_pointer);
  else
    dst->data[0].v_pointer = NULL;
}

static gpointer
value_event_peek_pointer (const GValue *value)
{
  return value->data[0].v_pointer;
}

static char *
value_event_collect_value (GValue      *value,
                           guint        n_collect_values,
                           GTypeCValue *collect_values,
                           guint        collect_flags)
{
  GdkEvent *event = collect_values[0].v_pointer;

  if (event == NULL)
    {
      value->data[0].v_pointer = NULL;
      return NULL;
    }

  if (event->parent_instance.g_class == NULL)
    return g_strconcat ("invalid unclassed GdkEvent pointer for "
                        "value type '",
                        G_VALUE_TYPE_NAME (value),
                        "'",
                        NULL);

  value->data[0].v_pointer = gdk_event_ref (event);

  return NULL;
}

Benjamin Otte's avatar
Benjamin Otte committed
114
static char *
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
value_event_lcopy_value (const GValue *value,
                         guint         n_collect_values,
                         GTypeCValue  *collect_values,
                         guint         collect_flags)
{
  GdkEvent **event_p = collect_values[0].v_pointer;

  if (event_p == NULL)
    return g_strconcat ("value location for '",
                        G_VALUE_TYPE_NAME (value),
                        "' passed as NULL",
                        NULL);

  if (value->data[0].v_pointer == NULL)
    *event_p = NULL;
  else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
    *event_p = value->data[0].v_pointer;
  else
    *event_p = gdk_event_ref (value->data[0].v_pointer);

  return NULL;
}

static void
gdk_event_finalize (GdkEvent *self)
{
  g_clear_object (&self->surface);
  g_clear_object (&self->device);

  g_type_free_instance ((GTypeInstance *) self);
}

static GdkModifierType
gdk_event_real_get_state (GdkEvent *self)
{
  return 0;
}

static gboolean
gdk_event_real_get_position (GdkEvent *self,
                             double   *x,
                             double   *y)
{
  *x = NAN;
  *y = NAN;

  return FALSE;
}

static GdkEventSequence *
gdk_event_real_get_sequence (GdkEvent *self)
{
  return NULL;
}

static GdkDeviceTool *
gdk_event_real_get_tool (GdkEvent *self)
{
  return NULL;
}

static gboolean
gdk_event_real_get_axes (GdkEvent  *self,
                         double   **axes,
                         guint     *n_axes)
{
  return FALSE;
}

static void
gdk_event_class_init (GdkEventClass *klass)
{
  klass->finalize = gdk_event_finalize;
  klass->get_state = gdk_event_real_get_state;
  klass->get_position = gdk_event_real_get_position;
  klass->get_sequence = gdk_event_real_get_sequence;
  klass->get_tool = gdk_event_real_get_tool;
  klass->get_axes = gdk_event_real_get_axes;
}

static void
gdk_event_init (GdkEvent *self)
{
  g_ref_count_init (&self->ref_count);
}

GType
gdk_event_get_type (void)
{
204
  static gsize event_type__volatile;
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260

  if (g_once_init_enter (&event_type__volatile))
    {
      static const GTypeFundamentalInfo finfo = {
        (G_TYPE_FLAG_CLASSED |
         G_TYPE_FLAG_INSTANTIATABLE |
         G_TYPE_FLAG_DERIVABLE |
         G_TYPE_FLAG_DEEP_DERIVABLE),
      };

      static const GTypeValueTable value_table = {
        value_event_init,
        value_event_free_value,
        value_event_copy_value,
        value_event_peek_pointer,
        "p",
        value_event_collect_value,
        "p",
        value_event_lcopy_value,
      };

      const GTypeInfo event_info = {
        /* Class */
        sizeof (GdkEventClass),
        (GBaseInitFunc) NULL,
        (GBaseFinalizeFunc) NULL,
        (GClassInitFunc) gdk_event_class_init,
        (GClassFinalizeFunc) NULL,
        NULL,

        /* Instance */
        sizeof (GdkEvent),
        0,
        (GInstanceInitFunc) gdk_event_init,

        /* GValue */
        &value_table,
      };

      GType event_type =
        g_type_register_fundamental (g_type_fundamental_next (),
                                     g_intern_static_string ("GdkEvent"),
                                     &event_info, &finfo,
                                     G_TYPE_FLAG_ABSTRACT);

      g_once_init_leave (&event_type__volatile, event_type);
    }

  return event_type__volatile;
}

/*< private >
 * GdkEventTypeInfo:
 * @instance_size: the size of the instance of a GdkEvent subclass
 * @instance_init: (nullable): the function to initialize the instance data
 * @finalize: (nullable): the function to free the instance data
Matthias Clasen's avatar
Matthias Clasen committed
261
 * @get_state: (nullable): the function to retrieve the `GdkModifierType`:w
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
 *   associated to the event
 * @get_position: (nullable): the function to retrieve the event coordinates
 * @get_sequence: (nullable): the function to retrieve the event sequence
 * @get_tool: (nullable): the function to retrieve the event's device tool
 * @get_axes: (nullable): the function to retrieve the event's axes
 *
 * A structure used when registering a new GdkEvent type.
 */
typedef struct {
  gsize instance_size;

  void (* instance_init) (GdkEvent *event);
  void (* finalize) (GdkEvent *event);

  GdkModifierType (* get_state) (GdkEvent *event);

  gboolean (* get_position) (GdkEvent *event,
                             double *x,
                             double *y);

  GdkEventSequence *(* get_sequence) (GdkEvent *event);

  GdkDeviceTool *(* get_tool) (GdkEvent *event);

  gboolean (* get_axes) (GdkEvent  *event,
                         double   **axes,
                         guint     *n_axes);
} GdkEventTypeInfo;

static void
gdk_event_generic_class_init (gpointer g_class,
                              gpointer class_data)
{
  GdkEventTypeInfo *info = class_data;
  GdkEventClass *event_class = g_class;

  /* Optional */
  if (info->finalize != NULL)
    event_class->finalize = info->finalize;
  if (info->get_state != NULL)
    event_class->get_state = info->get_state;
  if (info->get_position != NULL)
    event_class->get_position = info->get_position;
  if (info->get_sequence != NULL)
    event_class->get_sequence = info->get_sequence;
  if (info->get_tool != NULL)
    event_class->get_tool = info->get_tool;
  if (info->get_axes != NULL)
    event_class->get_axes = info->get_axes;

  g_free (info);
}

static GType
gdk_event_type_register_static (const char             *type_name,
                                const GdkEventTypeInfo *type_info)
{
  GTypeInfo info;

  info.class_size = sizeof (GdkEventClass);
  info.base_init = NULL;
  info.base_finalize = NULL;
  info.class_init = gdk_event_generic_class_init;
  info.class_finalize = NULL;
326
  info.class_data = g_memdup2 (type_info, sizeof (GdkEventTypeInfo));
327
328
329
330
331
332
333
334
335
336
337
338
339
340

  info.instance_size = type_info->instance_size;
  info.n_preallocs = 0;
  info.instance_init = (GInstanceInitFunc) type_info->instance_init;
  info.value_table = NULL;

  return g_type_register_static (GDK_TYPE_EVENT, type_name, &info, 0);
}

/* Map GdkEventType to the appropriate GType */
static GType gdk_event_types[GDK_EVENT_LAST];

/*< private >
 * GDK_EVENT_TYPE_SLOT:
Matthias Clasen's avatar
Matthias Clasen committed
341
 * @ETYPE: a `GdkEvent`Type
342
 *
Matthias Clasen's avatar
Matthias Clasen committed
343
 * Associates a `GdkEvent` type with the given `GdkEvent`Type enumeration.
344
345
346
347
348
349
350
351
352
 *
 * This macro can only be used with %GDK_DEFINE_EVENT_TYPE.
 */
#define GDK_EVENT_TYPE_SLOT(ETYPE) { gdk_event_types[ETYPE] = gdk_define_event_type_id; }

/*< private >
 * GDK_DEFINE_EVENT_TYPE:
 * @TypeName: the type name, in camel case
 * @type_name: the type name, in snake case
Matthias Clasen's avatar
Matthias Clasen committed
353
 * @type_info: the address of the `GdkEvent`TypeInfo for the event type
354
355
 * @_C_: custom code to call after registering the event type
 *
Matthias Clasen's avatar
Matthias Clasen committed
356
 * Registers a new `GdkEvent` subclass with the given @TypeName and @type_info.
357
358
359
360
 *
 * Similarly to %G_DEFINE_TYPE_WITH_CODE, this macro will generate a `get_type()`
 * function that registers the event type.
 *
Matthias Clasen's avatar
Matthias Clasen committed
361
 * You can specify code to be run after the type registration; the `GType` of
362
363
364
365
366
367
 * the event is available in the `gdk_define_event_type_id` variable.
 */
#define GDK_DEFINE_EVENT_TYPE(TypeName, type_name, type_info, _C_) \
GType \
type_name ## _get_type (void) \
{ \
368
  static gsize gdk_define_event_type_id__volatile; \
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
  if (g_once_init_enter (&gdk_define_event_type_id__volatile)) \
    { \
      GType gdk_define_event_type_id = \
        gdk_event_type_register_static (g_intern_static_string (#TypeName), type_info); \
      { _C_ } \
      g_once_init_leave (&gdk_define_event_type_id__volatile, gdk_define_event_type_id); \
    } \
  return gdk_define_event_type_id__volatile; \
}

#define GDK_EVENT_SUPER(event) \
  ((GdkEventClass *) g_type_class_peek (g_type_parent (G_TYPE_FROM_INSTANCE (event))))

/*< private >
 * gdk_event_alloc:
Matthias Clasen's avatar
Matthias Clasen committed
384
 * @event_type: the `GdkEvent`Type to allocate
Matthias Clasen's avatar
Matthias Clasen committed
385
386
 * @surface: (nullable): the `GdkSurface` of the event
 * @device: (nullable): the `GdkDevice` of the event
387
388
 * @time_: the event serial
 *
Matthias Clasen's avatar
Matthias Clasen committed
389
 * Allocates a `GdkEvent` for the given @event_type, and sets its
390
391
 * common fields with the given parameters.
 *
Matthias Clasen's avatar
Matthias Clasen committed
392
 * Returns: (transfer full): the newly allocated `GdkEvent` instance
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
 */
static gpointer
gdk_event_alloc (GdkEventType event_type,
                 GdkSurface   *surface,
                 GdkDevice    *device,
                 guint32       time_)
{
  g_assert (event_type >= GDK_DELETE && event_type < GDK_EVENT_LAST);
  g_assert (gdk_event_types[event_type] != G_TYPE_INVALID);

  GdkEvent *event = (GdkEvent *) g_type_create_instance (gdk_event_types[event_type]);

  GDK_NOTE (EVENTS, {
            char *str = g_enum_to_string (GDK_TYPE_EVENT_TYPE, event_type);
            g_message ("Allocating a new %s for event type %s",
                       g_type_name (gdk_event_types[event_type]), str);
            g_free (str);
            });

  event->event_type = event_type;
  event->surface = surface != NULL ? g_object_ref (surface) : NULL;
  event->device = device != NULL ? g_object_ref (device) : NULL;
  event->time = time_;

417
418
419
  if (device != NULL && time_ != GDK_CURRENT_TIME)
    gdk_device_set_timestamp (device, time_);

420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
  return event;
}

static void
gdk_event_init_types_once (void)
{
  g_type_ensure (GDK_TYPE_BUTTON_EVENT);
  g_type_ensure (GDK_TYPE_CROSSING_EVENT);
  g_type_ensure (GDK_TYPE_DELETE_EVENT);
  g_type_ensure (GDK_TYPE_DND_EVENT);
  g_type_ensure (GDK_TYPE_FOCUS_EVENT);
  g_type_ensure (GDK_TYPE_GRAB_BROKEN_EVENT);
  g_type_ensure (GDK_TYPE_KEY_EVENT);
  g_type_ensure (GDK_TYPE_MOTION_EVENT);
  g_type_ensure (GDK_TYPE_PAD_EVENT);
  g_type_ensure (GDK_TYPE_PROXIMITY_EVENT);
  g_type_ensure (GDK_TYPE_SCROLL_EVENT);
  g_type_ensure (GDK_TYPE_TOUCH_EVENT);
  g_type_ensure (GDK_TYPE_TOUCHPAD_EVENT);
}

/*< private >
 * gdk_event_init_types:
 *
 * Initializes all GdkEvent types.
 */
void
gdk_event_init_types (void)
{
449
  static gsize event_types__volatile;
450
451
452
453
454
455
456

  if (g_once_init_enter (&event_types__volatile))
    {
      gboolean initialized = FALSE;

      gdk_event_init_types_once ();
      initialized = TRUE;
457

458
459
460
      g_once_init_leave (&event_types__volatile, initialized);
    }
}
461

462
#ifdef G_ENABLE_DEBUG
463
static gboolean
464
check_event_sanity (GdkEvent *event)
465
{
466
467
  if (event->device != NULL &&
      gdk_surface_get_display (event->surface) != gdk_device_get_display (event->device))
468
    {
469
      char *type = g_enum_to_string (GDK_TYPE_EVENT_TYPE, event->event_type);
470
      g_warning ("Event of type %s with mismatched device display", type);
471
472
473
474
475
476
      g_free (type);
      return FALSE;
    }

  return TRUE;
}
477
#endif
478
479
480
481

void
_gdk_event_emit (GdkEvent *event)
{
482
#ifdef G_ENABLE_DEBUG
483
484
  if (!check_event_sanity (event))
    return;
485
#endif
486

487
  if (gdk_drag_handle_source_event (event))
488
489
    return;

Matthias Clasen's avatar
Matthias Clasen committed
490
  gdk_surface_handle_event (event);
491
}
492

493
494
495
496
/*********************************************
 * Functions for maintaining the event queue *
 *********************************************/

497
/**
498
 * _gdk_event_queue_find_first:
Matthias Clasen's avatar
Matthias Clasen committed
499
500
 * @display: a `GdkDisplay`
 *
501
502
 * Find the first event on the queue that is not still
 * being filled in.
Matthias Clasen's avatar
Matthias Clasen committed
503
504
505
 *
 * Returns: (nullable): Pointer to the list node for that event
 */
506
GList*
507
_gdk_event_queue_find_first (GdkDisplay *display)
508
{
509
510
511
  GList *tmp_list;
  GList *pending_motion = NULL;

512
  gboolean paused = display->event_pause_count > 0;
513

514
  tmp_list = g_queue_peek_head_link (&display->queued_events);
515
516
  while (tmp_list)
    {
517
      GdkEvent *event = tmp_list->data;
518

519
520
      if ((event->flags & GDK_EVENT_PENDING) == 0 &&
	  (!paused || (event->flags & GDK_EVENT_FLUSHED) != 0))
521
522
523
524
        {
          if (pending_motion)
            return pending_motion;

525
526
          if ((event->event_type == GDK_MOTION_NOTIFY ||
               (event->event_type == GDK_SCROLL && gdk_scroll_event_get_direction (event) == GDK_SCROLL_SMOOTH)) &&
Matthias Clasen's avatar
Matthias Clasen committed
527
              (event->flags & GDK_EVENT_FLUSHED) == 0)
528
529
530
531
            pending_motion = tmp_list;
          else
            return tmp_list;
        }
532

533
      tmp_list = tmp_list->next;
534
535
536
537
538
    }

  return NULL;
}

539
540
/**
 * _gdk_event_queue_append:
Matthias Clasen's avatar
Matthias Clasen committed
541
542
543
 * @display: a `GdkDisplay`
 * @event: Event to append
 *
544
545
546
 * Appends an event onto the tail of the event queue.
 *
 * Returns: the newly appended list node.
Matthias Clasen's avatar
Matthias Clasen committed
547
 */
548
549
550
551
GList *
_gdk_event_queue_append (GdkDisplay *display,
			 GdkEvent   *event)
{
552
  g_queue_push_tail (&display->queued_events, event);
553

554
  return g_queue_peek_tail_link (&display->queued_events);
555
}
556

557
/*
558
 * _gdk_event_queue_remove_link:
Matthias Clasen's avatar
Matthias Clasen committed
559
 * @display: a `GdkDisplay`
560
 * @node: node to remove
561
 *
562
 * Removes a specified list node from the event queue.
Matthias Clasen's avatar
Matthias Clasen committed
563
 */
564
void
565
566
_gdk_event_queue_remove_link (GdkDisplay *display,
			      GList      *node)
567
{
568
  g_queue_unlink (&display->queued_events, node);
569
570
}

571
/*
572
 * _gdk_event_unqueue:
Matthias Clasen's avatar
Matthias Clasen committed
573
 * @display: a `GdkDisplay`
574
 *
575
576
 * Removes and returns the first event from the event
 * queue that is not still being filled in.
577
 *
Matthias Clasen's avatar
Matthias Clasen committed
578
 * Returns: (nullable): the event
Matthias Clasen's avatar
Matthias Clasen committed
579
 */
580
581
GdkEvent*
_gdk_event_unqueue (GdkDisplay *display)
582
{
583
584
585
586
587
588
589
590
591
592
593
594
595
  GdkEvent *event = NULL;
  GList *tmp_list;

  tmp_list = _gdk_event_queue_find_first (display);

  if (tmp_list)
    {
      event = tmp_list->data;
      _gdk_event_queue_remove_link (display, tmp_list);
      g_list_free_1 (tmp_list);
    }

  return event;
596
597
}

Matthias Clasen's avatar
Matthias Clasen committed
598
599
/*
 * If the last N events in the event queue are smooth scroll events
600
601
 * for the same surface, the same device and the same scroll unit,
 * combine them into one.
Matthias Clasen's avatar
Matthias Clasen committed
602
603
604
 *
 * We give the remaining event a history with N items, and deltas
 * that are the sum over the history entries.
Matthias Clasen's avatar
Matthias Clasen committed
605
606
607
608
609
610
611
612
613
 */
void
gdk_event_queue_handle_scroll_compression (GdkDisplay *display)
{
  GList *l;
  GdkSurface *surface = NULL;
  GdkDevice *device = NULL;
  GdkEvent *last_event = NULL;
  GList *scrolls = NULL;
Matthias Clasen's avatar
Matthias Clasen committed
614
  GArray *history = NULL;
615
616
  GdkScrollUnit scroll_unit = GDK_SCROLL_UNIT_WHEEL;
  gboolean scroll_unit_defined = FALSE;
617
  GdkTimeCoord hist;
Matthias Clasen's avatar
Matthias Clasen committed
618
619
620
621
622
623

  l = g_queue_peek_tail_link (&display->queued_events);

  while (l)
    {
      GdkEvent *event = l->data;
624
      GdkScrollEvent *scroll_event = (GdkScrollEvent *) event;
Matthias Clasen's avatar
Matthias Clasen committed
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640

      if (event->flags & GDK_EVENT_PENDING)
        break;

      if (event->event_type != GDK_SCROLL ||
          gdk_scroll_event_get_direction (event) != GDK_SCROLL_SMOOTH)
        break;

      if (surface != NULL &&
          surface != event->surface)
        break;

      if (device != NULL &&
          device != event->device)
        break;

641
642
643
644
      if (scroll_unit_defined &&
          scroll_unit != scroll_event->unit)
        break;

Matthias Clasen's avatar
Matthias Clasen committed
645
646
647
648
649
      if (!last_event)
        last_event = event;

      surface = event->surface;
      device = event->device;
650
651
      scroll_unit = scroll_event->unit;
      scroll_unit_defined = TRUE;
Matthias Clasen's avatar
Matthias Clasen committed
652
653
654
655
656
657
658
      scrolls = l;

      l = l->prev;
    }

  while (scrolls && scrolls->next != NULL)
    {
Matthias Clasen's avatar
Matthias Clasen committed
659
      GdkEvent *event = scrolls->data;
Matthias Clasen's avatar
Matthias Clasen committed
660
      GList *next = scrolls->next;
Matthias Clasen's avatar
Matthias Clasen committed
661
      double dx, dy;
Matthias Clasen's avatar
Matthias Clasen committed
662
663
664
665
666
667
668
669
      gboolean inherited = FALSE;

      if (!history && ((GdkScrollEvent *)event)->history)
        {
          history = ((GdkScrollEvent *)event)->history;
          ((GdkScrollEvent *)event)->history = NULL;
          inherited = TRUE;
        }
Matthias Clasen's avatar
Matthias Clasen committed
670
671

      if (!history)
672
        history = g_array_new (FALSE, TRUE, sizeof (GdkTimeCoord));
Matthias Clasen's avatar
Matthias Clasen committed
673

Matthias Clasen's avatar
Matthias Clasen committed
674
675
676
      if (!inherited)
        {
          gdk_scroll_event_get_deltas (event, &dx, &dy);
Matthias Clasen's avatar
Matthias Clasen committed
677

Matthias Clasen's avatar
Matthias Clasen committed
678
679
680
681
682
          memset (&hist, 0, sizeof (GdkTimeCoord));
          hist.time = gdk_event_get_time (event);
          hist.flags = GDK_AXIS_FLAG_DELTA_X | GDK_AXIS_FLAG_DELTA_Y;
          hist.axes[GDK_AXIS_DELTA_X] = dx;
          hist.axes[GDK_AXIS_DELTA_Y] = dy;
683

Matthias Clasen's avatar
Matthias Clasen committed
684
685
          g_array_append_val (history, hist);
       }
Matthias Clasen's avatar
Matthias Clasen committed
686
687

      gdk_event_unref (event);
Matthias Clasen's avatar
Matthias Clasen committed
688
689
690
691
      g_queue_delete_link (&display->queued_events, scrolls);
      scrolls = next;
    }

Matthias Clasen's avatar
Matthias Clasen committed
692
  if (scrolls && history)
Matthias Clasen's avatar
Matthias Clasen committed
693
694
    {
      GdkEvent *old_event, *event;
Matthias Clasen's avatar
Matthias Clasen committed
695
      double dx, dy;
Matthias Clasen's avatar
Matthias Clasen committed
696
697
698

      old_event = scrolls->data;

Matthias Clasen's avatar
Matthias Clasen committed
699
      gdk_scroll_event_get_deltas (old_event, &dx, &dy);
Matthias Clasen's avatar
Matthias Clasen committed
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715

      memset (&hist, 0, sizeof (GdkTimeCoord));
      hist.time = gdk_event_get_time (old_event);
      hist.flags = GDK_AXIS_FLAG_DELTA_X | GDK_AXIS_FLAG_DELTA_Y;
      hist.axes[GDK_AXIS_DELTA_X] = dx;
      hist.axes[GDK_AXIS_DELTA_Y] = dy;
      g_array_append_val (history, hist);

      dx = dy = 0;
      for (int i = 0; i < history->len; i++)
        {
          GdkTimeCoord *val = &g_array_index (history, GdkTimeCoord, i);
          dx += val->axes[GDK_AXIS_DELTA_X];
          dy += val->axes[GDK_AXIS_DELTA_Y];
        }

Matthias Clasen's avatar
Matthias Clasen committed
716
717
718
719
720
      event = gdk_scroll_event_new (surface,
                                    device,
                                    gdk_event_get_device_tool (old_event),
                                    gdk_event_get_time (old_event),
                                    gdk_event_get_modifier_state (old_event),
Matthias Clasen's avatar
Matthias Clasen committed
721
722
                                    dx,
                                    dy,
723
724
                                    gdk_scroll_event_is_stop (old_event),
                                    scroll_unit);
Matthias Clasen's avatar
Matthias Clasen committed
725

Matthias Clasen's avatar
Matthias Clasen committed
726
727
      ((GdkScrollEvent *)event)->history = history;

Matthias Clasen's avatar
Matthias Clasen committed
728
729
      g_queue_delete_link (&display->queued_events, scrolls);
      g_queue_push_tail (&display->queued_events, event);
730
731

      gdk_event_unref (old_event);
Matthias Clasen's avatar
Matthias Clasen committed
732
733
734
    }
}

735
static void
736
737
gdk_motion_event_push_history (GdkEvent *event,
                               GdkEvent *history_event)
738
{
739
  GdkMotionEvent *self = (GdkMotionEvent *) event;
740
  GdkDeviceTool *tool;
741
  GdkTimeCoord hist;
742
  int i;
743

744
745
  g_assert (GDK_IS_EVENT_TYPE (event, GDK_MOTION_NOTIFY));
  g_assert (GDK_IS_EVENT_TYPE (history_event, GDK_MOTION_NOTIFY));
746

Matthias Clasen's avatar
Matthias Clasen committed
747
748
749
750
751
752
753
754
  if (G_UNLIKELY (!self->history))
    self->history = g_array_new (FALSE, TRUE, sizeof (GdkTimeCoord));

  if (((GdkMotionEvent *)history_event)->history)
    {
      GArray *history = ((GdkMotionEvent *)history_event)->history;
      g_array_append_vals (self->history, history->data, history->len);
    }
755
756

  tool = gdk_event_get_device_tool (history_event);
757

758
759
  memset (&hist, 0, sizeof (GdkTimeCoord));
  hist.time = gdk_event_get_time (history_event);
760

Matthias Clasen's avatar
Matthias Clasen committed
761
762
763
764
765
766
  if (tool)
    {
      hist.flags = gdk_device_tool_get_axes (tool);
      for (i = GDK_AXIS_X; i < GDK_AXIS_LAST; i++)
        gdk_event_get_axis (history_event, i, &hist.axes[i]);
    }
767
768
769
770
771
772

  /* GdkTimeCoord has no dedicated fields to record event position. For plain
   * pointer events, and for tools which don't report GDK_AXIS_X/GDK_AXIS_Y
   * on their own, we surface the position using the X and Y input axes.
   */
  if (!(hist.flags & GDK_AXIS_FLAG_X) || !(hist.flags & GDK_AXIS_FLAG_Y))
Matthias Clasen's avatar
Matthias Clasen committed
773
    {
774
      hist.flags |= GDK_AXIS_FLAG_X | GDK_AXIS_FLAG_Y;
Matthias Clasen's avatar
Matthias Clasen committed
775
776
      gdk_event_get_position (history_event, &hist.axes[GDK_AXIS_X], &hist.axes[GDK_AXIS_Y]);
    }
777
778

  g_array_append_val (self->history, hist);
779
780
}

Matthias Clasen's avatar
Matthias Clasen committed
781
782
783
784
785
786
787
/* If the last N events in the event queue are motion notify
 * events for the same surface, drop all but the last.
 *
 * If a button is held down or the device has a tool, then
 * we give the remaining events a history containing the N-1
 * dropped events.
 */
788
789
790
791
792
void
_gdk_event_queue_handle_motion_compression (GdkDisplay *display)
{
  GList *tmp_list;
  GList *pending_motions = NULL;
793
  GdkSurface *pending_motion_surface = NULL;
794
  GdkDevice *pending_motion_device = NULL;
795
  GdkEvent *last_motion = NULL;
796

797
  tmp_list = g_queue_peek_tail_link (&display->queued_events);
798
799
800

  while (tmp_list)
    {
801
      GdkEvent *event = tmp_list->data;
802

803
      if (event->flags & GDK_EVENT_PENDING)
804
805
        break;

806
      if (event->event_type != GDK_MOTION_NOTIFY)
807
808
        break;

809
      if (pending_motion_surface != NULL &&
810
          pending_motion_surface != event->surface)
811
812
        break;

813
      if (pending_motion_device != NULL &&
814
          pending_motion_device != event->device)
815
816
        break;

817
818
819
      if (!last_motion)
        last_motion = event;

820
821
      pending_motion_surface = event->surface;
      pending_motion_device = event->device;
822
823
824
825
826
827
828
829
      pending_motions = tmp_list;

      tmp_list = tmp_list->prev;
    }

  while (pending_motions && pending_motions->next != NULL)
    {
      GList *next = pending_motions->next;
830

831
832
      if (last_motion != NULL)
        {
Matthias Clasen's avatar
Matthias Clasen committed
833
834
835
836
837
          if ((gdk_event_get_modifier_state (last_motion) &
               (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK |
                GDK_BUTTON4_MASK | GDK_BUTTON5_MASK)) ||
               gdk_event_get_device_tool (last_motion) != NULL)
            gdk_motion_event_push_history (last_motion, pending_motions->data);
838
        }
839

840
      gdk_event_unref (pending_motions->data);
841
      g_queue_delete_link (&display->queued_events, pending_motions);
842
843
844
845
      pending_motions = next;
    }
}

846
847
848
void
_gdk_event_queue_flush (GdkDisplay *display)
{
849
  while (TRUE)
850
    {
851
852
853
854
855
856
      GdkEvent *event;

      event = (GdkEvent *)g_queue_pop_head (&display->queued_events);
      if (!event)
        return;

857
      event->flags |= GDK_EVENT_FLUSHED;
858
859
      _gdk_event_emit (event);
      gdk_event_unref (event);
860
861
862
    }
}

Matthias Clasen's avatar
Matthias Clasen committed
863
864
/**
 * gdk_event_ref:
Matthias Clasen's avatar
Matthias Clasen committed
865
 * @event: a `GdkEvent`
Matthias Clasen's avatar
Matthias Clasen committed
866
867
868
 *
 * Increase the ref count of @event.
 *
869
 * Returns: (transfer full): @event
Matthias Clasen's avatar
Matthias Clasen committed
870
 */
871
872
873
GdkEvent *
gdk_event_ref (GdkEvent *event)
{
874
875
876
877
  g_return_val_if_fail (GDK_IS_EVENT (event), NULL);

  g_ref_count_inc (&event->ref_count);

Matthias Clasen's avatar
Matthias Clasen committed
878
  return event;
879
880
}

Matthias Clasen's avatar
Matthias Clasen committed
881
882
/**
 * gdk_event_unref:
Matthias Clasen's avatar
Matthias Clasen committed
883
 * @event: (transfer full): a `GdkEvent`
Matthias Clasen's avatar
Matthias Clasen committed
884
 *
Matthias Clasen's avatar
Matthias Clasen committed
885
886
887
 * Decrease the ref count of @event.
 *
 * If the last reference is dropped, the structure is freed.
Matthias Clasen's avatar
Matthias Clasen committed
888
 */
889
890
891
void
gdk_event_unref (GdkEvent *event)
{
892
893
894
895
  g_return_if_fail (GDK_IS_EVENT (event));

  if (g_ref_count_dec (&event->ref_count))
    GDK_EVENT_GET_CLASS (event)->finalize (event);
896
897
}

Matthias Clasen's avatar
Matthias Clasen committed
898
899
/**
 * gdk_event_get_pointer_emulated:
Matthias Clasen's avatar
Matthias Clasen committed
900
901
902
 * @event: a `GdkEvent`
 *
 * Returns whether this event is an 'emulated' pointer event.
Matthias Clasen's avatar
Matthias Clasen committed
903
 *
Matthias Clasen's avatar
Matthias Clasen committed
904
 * Emulated pointer events typically originate from a touch events.
Matthias Clasen's avatar
Matthias Clasen committed
905
906
907
 *
 * Returns: %TRUE if this event is emulated
 */
908
gboolean
909
gdk_event_get_pointer_emulated (GdkEvent *event)
910
{
911
  switch ((int) event->event_type)
912
    {
913
914
    case GDK_TOUCH_BEGIN:
    case GDK_TOUCH_END:
915
    case GDK_TOUCH_UPDATE:
916
    case GDK_TOUCH_CANCEL:
917
918
      {
        GdkTouchEvent *tevent = (GdkTouchEvent *) event;
919

920
921
        return tevent->pointer_emulated;
      }
922
923

    case GDK_SCROLL:
924
925
926
927
928
929
    case GDK_SCROLL_SMOOTH:
      {
        GdkScrollEvent *sevent = (GdkScrollEvent *) event;

        return sevent->pointer_emulated;
      }
930

931
932
933
    default:
      break;
    }
934

935
  return FALSE;
936
937
}

938
/**
Matthias Clasen's avatar
Matthias Clasen committed
939
 * gdk_event_get_axis:
Matthias Clasen's avatar
Matthias Clasen committed
940
 * @event: a `GdkEvent`
Matthias Clasen's avatar
Matthias Clasen committed
941
942
 * @axis_use: the axis use to look for
 * @value: (out): location to store the value found
943
 *
Matthias Clasen's avatar
Matthias Clasen committed
944
945
 * Extract the axis value for a particular axis use from
 * an event structure.
946
 *
947
948
949
 * To find out which axes are used, use [method@Gdk.DeviceTool.get_axes]
 * on the device tool returned by [method@Gdk.Event.get_device_tool].
 *
Matthias Clasen's avatar
Matthias Clasen committed
950
 * Returns: %TRUE if the specified axis was found, otherwise %FALSE
Matthias Clasen's avatar
Matthias Clasen committed
951
 */
Matthias Clasen's avatar
Matthias Clasen committed
952
953
954
955
gboolean
gdk_event_get_axis (GdkEvent   *event,
		    GdkAxisUse  axis_use,
		    double     *value)
956
{
Matthias Clasen's avatar
Matthias Clasen committed
957
  double *axes;
958
959
960
  guint n_axes;

  g_return_val_if_fail (GDK_IS_EVENT (event), FALSE);
961

Matthias Clasen's avatar
Matthias Clasen committed
962
963
  if (axis_use == GDK_AXIS_X || axis_use == GDK_AXIS_Y)
    {
964
965
966
967
968
969
      double x, y;

      if (!gdk_event_get_position (event, &x, &y))
        return FALSE;

      if (axis_use == GDK_AXIS_X && value != NULL)
Matthias Clasen's avatar
Matthias Clasen committed
970
	*value = x;
971
      if (axis_use == GDK_AXIS_Y && value != NULL)
Matthias Clasen's avatar
Matthias Clasen committed
972
973
974
975
	*value = y;

      return TRUE;
    }
976
977
978
979

  if (!gdk_event_get_axes (event, &axes, &n_axes))
    return FALSE;

980
981
  *value = axes[axis_use];
  return TRUE;
982
983
}

984
/**
Matthias Clasen's avatar
Matthias Clasen committed
985
 * gdk_event_triggers_context_menu:
Matthias Clasen's avatar
Matthias Clasen committed
986
987
988
989
 * @event: a `GdkEvent`, currently only button events are meaningful values
 *
 * Returns whether a `GdkEvent` should trigger a context menu,
 * according to platform conventions.
Matthias Clasen's avatar
Matthias Clasen committed
990
 *
Matthias Clasen's avatar
Matthias Clasen committed
991
 * The right mouse button typically triggers context menus.
Matthias Clasen's avatar
Matthias Clasen committed
992
 *
Matthias Clasen's avatar
Matthias Clasen committed
993
994
 * This function should always be used instead of simply checking for
 * event->button == %GDK_BUTTON_SECONDARY.
Matthias Clasen's avatar
Matthias Clasen committed
995
 *
Matthias Clasen's avatar
Matthias Clasen committed
996
 * Returns: %TRUE if the event should trigger a context menu.
Matthias Clasen's avatar
Matthias Clasen committed
997
 */
998
gboolean
Matthias Clasen's avatar
Matthias Clasen committed
999
gdk_event_triggers_context_menu (GdkEvent *event)
1000
{