gdkevents.c 63 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
22
23
24
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

25
#include "config.h"
26

27
#include "gdkinternals.h"
28
#include "gdkdisplayprivate.h"
29
#include "gdkdndprivate.h"
30

31
32
#include <string.h>
#include <math.h>
33

34
35
36
37
38

/**
 * SECTION:events
 * @Short_description: Functions for handling events from the window system
 * @Title: Events
39
 * @See_also: [Event Structures][gdk3-Event-Structures]
40
41
42
43
44
45
46
 *
 * This section describes functions dealing with events from the window
 * system.
 *
 * In GTK+ applications the events are handled automatically in
 * gtk_main_do_event() and passed on to the appropriate widgets, so these
 * functions are rarely needed. Though some of the fields in the
47
 * [Event Structures][gdk3-Event-Structures] are useful.
48
49
50
 */


51
typedef struct _GdkIOClosure GdkIOClosure;
52

53
54
struct _GdkIOClosure
{
Michael Natterer's avatar
Michael Natterer committed
55
  GDestroyNotify notify;
56
57
58
59
60
61
  gpointer data;
};

/* Private variable declarations
 */

62
63
64
65
66
67
68
static GdkEventFunc   _gdk_event_func = NULL;    /* Callback for events */
static gpointer       _gdk_event_data = NULL;
static GDestroyNotify _gdk_event_notify = NULL;

void
_gdk_event_emit (GdkEvent *event)
{
69
70
71
  if (gdk_drag_context_handle_source_event (event))
    return;

72
73
  if (_gdk_event_func)
    (*_gdk_event_func) (event, _gdk_event_data);
74
75
76

  if (gdk_drag_context_handle_dest_event (event))
    return;
77
}
78

79
80
81
82
/*********************************************
 * Functions for maintaining the event queue *
 *********************************************/

83
/**
84
 * _gdk_event_queue_find_first:
85
86
87
88
89
 * @display: a #GdkDisplay
 * 
 * Find the first event on the queue that is not still
 * being filled in.
 * 
90
91
 * Returns: (nullable): Pointer to the list node for that event, or
 *   %NULL.
92
 **/
93
GList*
94
_gdk_event_queue_find_first (GdkDisplay *display)
95
{
96
97
98
  GList *tmp_list;
  GList *pending_motion = NULL;

99
  gboolean paused = display->event_pause_count > 0;
100

101
  tmp_list = display->queued_events;
102
103
  while (tmp_list)
    {
104
      GdkEventPrivate *event = tmp_list->data;
105

106
107
      if ((event->flags & GDK_EVENT_PENDING) == 0 &&
	  (!paused || (event->flags & GDK_EVENT_FLUSHED) != 0))
108
109
110
111
        {
          if (pending_motion)
            return pending_motion;

112
          if (event->event.type == GDK_MOTION_NOTIFY && (event->flags & GDK_EVENT_FLUSHED) == 0)
113
114
115
116
            pending_motion = tmp_list;
          else
            return tmp_list;
        }
117

118
      tmp_list = tmp_list->next;
119
120
121
122
123
    }

  return NULL;
}

124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/**
 * _gdk_event_queue_append:
 * @display: a #GdkDisplay
 * @event: Event to append.
 * 
 * Appends an event onto the tail of the event queue.
 *
 * Returns: the newly appended list node.
 **/
GList *
_gdk_event_queue_append (GdkDisplay *display,
			 GdkEvent   *event)
{
  display->queued_tail = g_list_append (display->queued_tail, event);
  
  if (!display->queued_events)
    display->queued_events = display->queued_tail;
  else
    display->queued_tail = display->queued_tail->next;

  return display->queued_tail;
}
146

147
148
149
150
151
152
/**
 * _gdk_event_queue_insert_after:
 * @display: a #GdkDisplay
 * @sibling: Append after this event.
 * @event: Event to append.
 *
153
 * Appends an event after the specified event, or if it isn’t in
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
 * the queue, onto the tail of the event queue.
 *
 * Returns: the newly appended list node.
 *
 * Since: 2.16
 */
GList*
_gdk_event_queue_insert_after (GdkDisplay *display,
                               GdkEvent   *sibling,
                               GdkEvent   *event)
{
  GList *prev = g_list_find (display->queued_events, sibling);
  if (prev && prev->next)
    {
      display->queued_events = g_list_insert_before (display->queued_events, prev->next, event);
      return prev->next;
    }
  else
    return _gdk_event_queue_append (display, event);
}

/**
Matthias Clasen's avatar
Matthias Clasen committed
176
 * _gdk_event_queue_insert_before:
177
 * @display: a #GdkDisplay
Matthias Clasen's avatar
Matthias Clasen committed
178
179
 * @sibling: Append before this event
 * @event: Event to prepend
180
 *
181
 * Prepends an event before the specified event, or if it isn’t in
Matthias Clasen's avatar
Matthias Clasen committed
182
 * the queue, onto the head of the event queue.
183
 *
Matthias Clasen's avatar
Matthias Clasen committed
184
 * Returns: the newly prepended list node.
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
 *
 * Since: 2.16
 */
GList*
_gdk_event_queue_insert_before (GdkDisplay *display,
				GdkEvent   *sibling,
				GdkEvent   *event)
{
  GList *next = g_list_find (display->queued_events, sibling);
  if (next)
    {
      display->queued_events = g_list_insert_before (display->queued_events, next, event);
      return next->prev;
    }
  else
    return _gdk_event_queue_append (display, event);
}


204
205
206
207
208
209
210
/**
 * _gdk_event_queue_remove_link:
 * @display: a #GdkDisplay
 * @node: node to remove
 * 
 * Removes a specified list node from the event queue.
 **/
211
void
212
213
_gdk_event_queue_remove_link (GdkDisplay *display,
			      GList      *node)
214
215
216
217
{
  if (node->prev)
    node->prev->next = node->next;
  else
218
    display->queued_events = node->next;
219
220
221
222
  
  if (node->next)
    node->next->prev = node->prev;
  else
223
    display->queued_tail = node->prev;
224
225
}

226
227
228
229
230
231
232
/**
 * _gdk_event_unqueue:
 * @display: a #GdkDisplay
 * 
 * Removes and returns the first event from the event
 * queue that is not still being filled in.
 * 
233
 * Returns: (nullable): the event, or %NULL. Ownership is transferred
234
235
236
237
 * to the caller.
 **/
GdkEvent*
_gdk_event_unqueue (GdkDisplay *display)
238
{
239
240
241
242
243
244
245
246
247
248
249
250
251
  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;
252
253
}

254
255
256
257
258
259
void
_gdk_event_queue_handle_motion_compression (GdkDisplay *display)
{
  GList *tmp_list;
  GList *pending_motions = NULL;
  GdkWindow *pending_motion_window = NULL;
260
  GdkDevice *pending_motion_device = NULL;
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280

  /* If the last N events in the event queue are motion notify
   * events for the same window, drop all but the last */

  tmp_list = display->queued_tail;

  while (tmp_list)
    {
      GdkEventPrivate *event = tmp_list->data;

      if (event->flags & GDK_EVENT_PENDING)
        break;

      if (event->event.type != GDK_MOTION_NOTIFY)
        break;

      if (pending_motion_window != NULL &&
          pending_motion_window != event->event.motion.window)
        break;

281
282
283
284
      if (pending_motion_device != NULL &&
          pending_motion_device != event->event.motion.device)
        break;

285
286
287
      if (!event->event.motion.window->event_compression)
        break;

288
      pending_motion_window = event->event.motion.window;
289
      pending_motion_device = event->event.motion.device;
290
291
292
293
294
295
296
297
      pending_motions = tmp_list;

      tmp_list = tmp_list->prev;
    }

  while (pending_motions && pending_motions->next != NULL)
    {
      GList *next = pending_motions->next;
298
      gdk_event_free (pending_motions->data);
299
300
301
302
303
304
305
306
307
308
      display->queued_events = g_list_delete_link (display->queued_events,
                                                   pending_motions);
      pending_motions = next;
    }

  if (pending_motions &&
      pending_motions == display->queued_events &&
      pending_motions == display->queued_tail)
    {
      GdkFrameClock *clock = gdk_window_get_frame_clock (pending_motion_window);
309
310
      if (clock) /* might be NULL if window was destroyed */
	gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS);
311
312
313
    }
}

314
315
316
317
318
319
320
321
322
323
324
325
void
_gdk_event_queue_flush (GdkDisplay *display)
{
  GList *tmp_list;

  for (tmp_list = display->queued_events; tmp_list; tmp_list = tmp_list->next)
    {
      GdkEventPrivate *event = tmp_list->data;
      event->flags |= GDK_EVENT_FLUSHED;
    }
}

326
/**
327
 * gdk_event_handler_set:
328
329
330
331
 * @func: the function to call to handle events from GDK.
 * @data: user data to pass to the function. 
 * @notify: the function to call when the handler function is removed, i.e. when
 *          gdk_event_handler_set() is called with another event handler.
332
 * 
333
334
335
336
337
338
339
 * Sets the function to call to handle all events from GDK.
 *
 * Note that GTK+ uses this to install its own event handler, so it is
 * usually not useful for GTK+ applications. (Although an application
 * can call this function then call gtk_main_do_event() to pass
 * events to GTK+.)
 **/
340
341
342
343
344
void 
gdk_event_handler_set (GdkEventFunc   func,
		       gpointer       data,
		       GDestroyNotify notify)
{
345
346
  if (_gdk_event_notify)
    (*_gdk_event_notify) (_gdk_event_data);
347

348
349
350
  _gdk_event_func = func;
  _gdk_event_data = data;
  _gdk_event_notify = notify;
351
352
}

353
354
355
356
357
/**
 * gdk_events_pending:
 *
 * Checks if any events are ready to be processed for any display.
 *
358
 * Returns: %TRUE if any events are pending.
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
 */
gboolean
gdk_events_pending (void)
{
  GSList *list, *l;
  gboolean pending;

  pending = FALSE;
  list = gdk_display_manager_list_displays (gdk_display_manager_get ());
  for (l = list; l; l = l->next)
    {
      if (_gdk_event_queue_find_first (l->data))
        {
          pending = TRUE;
          goto out;
        }
    }

  for (l = list; l; l = l->next)
    {
      if (gdk_display_has_pending (l->data))
        {
          pending = TRUE;
          goto out;
        }
    }

 out:
  g_slist_free (list);

  return pending;
}

392
393
394
395
396
397
398
/**
 * gdk_event_get:
 * 
 * Checks all open displays for a #GdkEvent to process,to be processed
 * on, fetching events from the windowing system if necessary.
 * See gdk_display_get_event().
 * 
399
400
401
 * Returns: (nullable): the next #GdkEvent to be processed, or %NULL
 * if no events are pending. The returned #GdkEvent should be freed
 * with gdk_event_free().
402
 **/
403
GdkEvent*
404
405
gdk_event_get (void)
{
406
407
  GSList *list, *l;
  GdkEvent *event;
408

409
410
411
  event = NULL;
  list = gdk_display_manager_list_displays (gdk_display_manager_get ());
  for (l = list; l; l = l->next)
412
    {
413
      event = gdk_display_get_event (l->data);
414
      if (event)
415
        break;
416
417
    }

418
419
420
  g_slist_free (list);

  return event;
421
422
}

423
424
/**
 * gdk_event_peek:
425
 *
426
427
428
 * If there is an event waiting in the event queue of some open
 * display, returns a copy of it. See gdk_display_peek_event().
 * 
429
430
431
 * Returns: (nullable): a copy of the first #GdkEvent on some event
 * queue, or %NULL if no events are in any queues. The returned
 * #GdkEvent should be freed with gdk_event_free().
432
 **/
433
GdkEvent*
434
435
gdk_event_peek (void)
{
436
437
  GSList *list, *l;
  GdkEvent *event;
438

439
440
441
  event = NULL;
  list = gdk_display_manager_list_displays (gdk_display_manager_get ());
  for (l = list; l; l = l->next)
442
    {
443
      event = gdk_display_peek_event (l->data);
444
      if (event)
445
        break;
446
447
    }

448
449
450
  g_slist_free (list);

  return event;
451
452
}

453
454
455
456
457
458
459
460
461
static GdkDisplay *
event_get_display (const GdkEvent *event)
{
  if (event->any.window)
    return gdk_window_get_display (event->any.window);
  else
    return gdk_display_get_default ();
}

462
463
464
465
466
/**
 * gdk_event_put:
 * @event: a #GdkEvent.
 *
 * Appends a copy of the given event onto the front of the event
467
 * queue for event->any.window’s display, or the default event
468
469
 * queue if event->any.window is %NULL. See gdk_display_put_event().
 **/
470
void
471
gdk_event_put (const GdkEvent *event)
472
{
473
  GdkDisplay *display;
474
475
  
  g_return_if_fail (event != NULL);
476

477
  display = event_get_display (event);
478

479
480
  gdk_display_put_event (display, event);
}
481

482
static GHashTable *event_hash = NULL;
483

Matthias Clasen's avatar
Matthias Clasen committed
484
485
486
487
488
489
/**
 * gdk_event_new:
 * @type: a #GdkEventType 
 * 
 * Creates a new event of the given type. All fields are set to 0.
 * 
490
 * Returns: a newly-allocated #GdkEvent. The returned #GdkEvent 
Matthias Clasen's avatar
Matthias Clasen committed
491
 * should be freed with gdk_event_free().
Matthias Clasen's avatar
Matthias Clasen committed
492
493
 *
 * Since: 2.2
Matthias Clasen's avatar
Matthias Clasen committed
494
 **/
495
GdkEvent*
496
gdk_event_new (GdkEventType type)
497
{
498
499
  GdkEventPrivate *new_private;
  GdkEvent *new_event;
500
  
501
502
503
  if (!event_hash)
    event_hash = g_hash_table_new (g_direct_hash, NULL);

504
  new_private = g_slice_new0 (GdkEventPrivate);
505
506
507
508
509
510
511
512
513
  
  new_private->flags = 0;
  new_private->screen = NULL;

  g_hash_table_insert (event_hash, new_private, GUINT_TO_POINTER (1));

  new_event = (GdkEvent *) new_private;

  new_event->any.type = type;
514

515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
  /*
   * Bytewise 0 initialization is reasonable for most of the 
   * current event types. Explicitely initialize double fields
   * since I trust bytewise 0 == 0. less than for integers
   * or pointers.
   */
  switch (type)
    {
    case GDK_MOTION_NOTIFY:
      new_event->motion.x = 0.;
      new_event->motion.y = 0.;
      new_event->motion.x_root = 0.;
      new_event->motion.y_root = 0.;
      break;
    case GDK_BUTTON_PRESS:
    case GDK_2BUTTON_PRESS:
    case GDK_3BUTTON_PRESS:
    case GDK_BUTTON_RELEASE:
      new_event->button.x = 0.;
      new_event->button.y = 0.;
      new_event->button.x_root = 0.;
      new_event->button.y_root = 0.;
      break;
538
539
540
541
542
543
544
545
546
    case GDK_TOUCH_BEGIN:
    case GDK_TOUCH_UPDATE:
    case GDK_TOUCH_END:
    case GDK_TOUCH_CANCEL:
      new_event->touch.x = 0.;
      new_event->touch.y = 0.;
      new_event->touch.x_root = 0.;
      new_event->touch.y_root = 0.;
      break;
547
548
549
550
551
    case GDK_SCROLL:
      new_event->scroll.x = 0.;
      new_event->scroll.y = 0.;
      new_event->scroll.x_root = 0.;
      new_event->scroll.y_root = 0.;
552
553
      new_event->scroll.delta_x = 0.;
      new_event->scroll.delta_y = 0.;
554
      new_event->scroll.is_stop = FALSE;
555
556
557
558
559
560
561
562
      break;
    case GDK_ENTER_NOTIFY:
    case GDK_LEAVE_NOTIFY:
      new_event->crossing.x = 0.;
      new_event->crossing.y = 0.;
      new_event->crossing.x_root = 0.;
      new_event->crossing.y_root = 0.;
      break;
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
    case GDK_TOUCHPAD_SWIPE:
      new_event->touchpad_swipe.x = 0;
      new_event->touchpad_swipe.y = 0;
      new_event->touchpad_swipe.dx = 0;
      new_event->touchpad_swipe.dy = 0;
      new_event->touchpad_swipe.x_root = 0;
      new_event->touchpad_swipe.y_root = 0;
      break;
    case GDK_TOUCHPAD_PINCH:
      new_event->touchpad_pinch.x = 0;
      new_event->touchpad_pinch.y = 0;
      new_event->touchpad_pinch.dx = 0;
      new_event->touchpad_pinch.dy = 0;
      new_event->touchpad_pinch.angle_delta = 0;
      new_event->touchpad_pinch.scale = 0;
      new_event->touchpad_pinch.x_root = 0;
      new_event->touchpad_pinch.y_root = 0;
      break;
581
582
583
    default:
      break;
    }
584
  
585
  return new_event;
586
587
}

588
gboolean
589
gdk_event_is_allocated (const GdkEvent *event)
590
591
592
{
  if (event_hash)
    return g_hash_table_lookup (event_hash, event) != NULL;
593
594

  return FALSE;
595
}
596
597

void
598
599
gdk_event_set_pointer_emulated (GdkEvent *event,
                                gboolean  emulated)
600
601
602
603
604
605
606
607
608
609
610
611
{
  if (gdk_event_is_allocated (event))
    {
      GdkEventPrivate *private = (GdkEventPrivate *) event;

      if (emulated)
        private->flags |= GDK_EVENT_POINTER_EMULATED;
      else
        private->flags &= ~(GDK_EVENT_POINTER_EMULATED);
    }
}

Matthias Clasen's avatar
Matthias Clasen committed
612
613
614
615
616
617
618
619
620
621
622
/**
 * gdk_event_get_pointer_emulated:
 * #event: a #GdkEvent
 *
 * Returns whether this event is an 'emulated' pointer event (typically
 * from a touch event), as opposed to a real one.
 *
 * Returns: %TRUE if this event is emulated
 *
 * Since: 3.22
 */
623
gboolean
624
gdk_event_get_pointer_emulated (GdkEvent *event)
625
626
627
628
629
630
631
{
  if (gdk_event_is_allocated (event))
    return (((GdkEventPrivate *) event)->flags & GDK_EVENT_POINTER_EMULATED) != 0;

  return FALSE;
}

632
633
634
635
636
/**
 * gdk_event_copy:
 * @event: a #GdkEvent
 * 
 * Copies a #GdkEvent, copying or incrementing the reference count of the
637
 * resources associated with it (e.g. #GdkWindow’s and strings).
638
 * 
639
 * Returns: a copy of @event. The returned #GdkEvent should be freed with
640
641
 * gdk_event_free().
 **/
642
GdkEvent*
643
gdk_event_copy (const GdkEvent *event)
644
{
645
  GdkEventPrivate *new_private;
646
  GdkEvent *new_event;
647

648
  g_return_val_if_fail (event != NULL, NULL);
649

650
651
652
  new_event = gdk_event_new (GDK_NOTHING);
  new_private = (GdkEventPrivate *)new_event;

653
  *new_event = *event;
654
  if (new_event->any.window)
655
    g_object_ref (new_event->any.window);
656

657
658
659
660
661
  if (gdk_event_is_allocated (event))
    {
      GdkEventPrivate *private = (GdkEventPrivate *)event;

      new_private->screen = private->screen;
662
663
      new_private->device = private->device ? g_object_ref (private->device) : NULL;
      new_private->source_device = private->source_device ? g_object_ref (private->source_device) : NULL;
664
      new_private->seat = private->seat;
665
      new_private->tool = private->tool;
666
667
668

#ifdef GDK_WINDOWING_WIN32
      new_private->translation_len = private->translation_len;
Isopod's avatar
Isopod committed
669
      new_private->translation = g_memdup (private->translation, private->translation_len * sizeof (private->translation[0]));
670
#endif
671
    }
672

673
674
675
676
677
678
  switch (event->any.type)
    {
    case GDK_KEY_PRESS:
    case GDK_KEY_RELEASE:
      new_event->key.string = g_strdup (event->key.string);
      break;
679

680
681
682
    case GDK_ENTER_NOTIFY:
    case GDK_LEAVE_NOTIFY:
      if (event->crossing.subwindow != NULL)
683
        g_object_ref (event->crossing.subwindow);
684
      break;
685

686
687
688
689
690
691
    case GDK_DRAG_ENTER:
    case GDK_DRAG_LEAVE:
    case GDK_DRAG_MOTION:
    case GDK_DRAG_STATUS:
    case GDK_DROP_START:
    case GDK_DROP_FINISHED:
692
      g_object_ref (event->dnd.context);
693
      break;
694

695
    case GDK_EXPOSE:
Matthias Clasen's avatar
Matthias Clasen committed
696
    case GDK_DAMAGE:
697
      if (event->expose.region)
698
        new_event->expose.region = cairo_region_copy (event->expose.region);
699
      break;
700

701
702
703
    case GDK_SETTING:
      new_event->setting.name = g_strdup (new_event->setting.name);
      break;
Larry Ewing's avatar
Larry Ewing committed
704
705

    case GDK_BUTTON_PRESS:
706
707
    case GDK_2BUTTON_PRESS:
    case GDK_3BUTTON_PRESS:
Larry Ewing's avatar
Larry Ewing committed
708
    case GDK_BUTTON_RELEASE:
709
710
      if (event->button.axes)
        new_event->button.axes = g_memdup (event->button.axes,
711
                                           sizeof (gdouble) * gdk_device_get_n_axes (event->button.device));
Larry Ewing's avatar
Larry Ewing committed
712
713
      break;

714
715
716
717
718
719
720
721
722
    case GDK_TOUCH_BEGIN:
    case GDK_TOUCH_UPDATE:
    case GDK_TOUCH_END:
    case GDK_TOUCH_CANCEL:
      if (event->touch.axes)
        new_event->touch.axes = g_memdup (event->touch.axes,
                                           sizeof (gdouble) * gdk_device_get_n_axes (event->touch.device));
      break;

Larry Ewing's avatar
Larry Ewing committed
723
    case GDK_MOTION_NOTIFY:
724
725
726
      if (event->motion.axes)
        new_event->motion.axes = g_memdup (event->motion.axes,
                                           sizeof (gdouble) * gdk_device_get_n_axes (event->motion.device));
Larry Ewing's avatar
Larry Ewing committed
727
      break;
728

729
    case GDK_OWNER_CHANGE:
730
731
732
      new_event->owner_change.owner = event->owner_change.owner;
      if (new_event->owner_change.owner)
        g_object_ref (new_event->owner_change.owner);
733
734
      break;

735
736
737
738
739
    case GDK_SELECTION_CLEAR:
    case GDK_SELECTION_NOTIFY:
    case GDK_SELECTION_REQUEST:
      new_event->selection.requestor = event->selection.requestor;
      if (new_event->selection.requestor)
740
        g_object_ref (new_event->selection.requestor);
741
742
      break;

743
    default:
744
745
      break;
    }
746
747

  if (gdk_event_is_allocated (event))
748
    _gdk_display_event_data_copy (event_get_display (event), event, new_event);
749

750
751
752
  return new_event;
}

753
754
755
756
757
758
/**
 * gdk_event_free:
 * @event:  a #GdkEvent.
 * 
 * Frees a #GdkEvent, freeing or decrementing any resources associated with it.
 * Note that this function should only be called with events returned from
759
760
 * functions such as gdk_event_peek(), gdk_event_get(), gdk_event_copy()
 * and gdk_event_new().
761
 **/
762
763
764
void
gdk_event_free (GdkEvent *event)
{
765
  GdkEventPrivate *private;
766
767
  GdkDisplay *display;

768
  g_return_if_fail (event != NULL);
769

770
771
772
773
774
  if (gdk_event_is_allocated (event))
    {
      private = (GdkEventPrivate *) event;
      g_clear_object (&private->device);
      g_clear_object (&private->source_device);
775
#ifdef GDK_WINDOWING_WIN32
Isopod's avatar
Isopod committed
776
      g_free (private->translation);
777
#endif
778
779
    }

780
781
782
783
784
785
786
787
788
789
  switch (event->any.type)
    {
    case GDK_KEY_PRESS:
    case GDK_KEY_RELEASE:
      g_free (event->key.string);
      break;
      
    case GDK_ENTER_NOTIFY:
    case GDK_LEAVE_NOTIFY:
      if (event->crossing.subwindow != NULL)
790
	g_object_unref (event->crossing.subwindow);
791
792
793
794
795
796
797
798
      break;
      
    case GDK_DRAG_ENTER:
    case GDK_DRAG_LEAVE:
    case GDK_DRAG_MOTION:
    case GDK_DRAG_STATUS:
    case GDK_DROP_START:
    case GDK_DROP_FINISHED:
799
800
      if (event->dnd.context != NULL)
        g_object_unref (event->dnd.context);
801
      break;
802
803

    case GDK_BUTTON_PRESS:
804
805
    case GDK_2BUTTON_PRESS:
    case GDK_3BUTTON_PRESS:
806
    case GDK_BUTTON_RELEASE:
807
      g_free (event->button.axes);
808
      break;
809
810
811
812
813
814
815
816

    case GDK_TOUCH_BEGIN:
    case GDK_TOUCH_UPDATE:
    case GDK_TOUCH_END:
    case GDK_TOUCH_CANCEL:
      g_free (event->touch.axes);
      break;

817
    case GDK_EXPOSE:
Matthias Clasen's avatar
Matthias Clasen committed
818
    case GDK_DAMAGE:
819
      if (event->expose.region)
Benjamin Otte's avatar
Benjamin Otte committed
820
	cairo_region_destroy (event->expose.region);
821
822
      break;
      
823
    case GDK_MOTION_NOTIFY:
824
      g_free (event->motion.axes);
825
      break;
826
      
827
828
829
830
    case GDK_SETTING:
      g_free (event->setting.name);
      break;
      
831
    case GDK_OWNER_CHANGE:
832
833
      if (event->owner_change.owner)
        g_object_unref (event->owner_change.owner);
834
835
      break;

836
837
838
839
840
841
842
    case GDK_SELECTION_CLEAR:
    case GDK_SELECTION_NOTIFY:
    case GDK_SELECTION_REQUEST:
      if (event->selection.requestor)
        g_object_unref (event->selection.requestor);
      break;

843
844
845
    default:
      break;
    }
846

847
  display = event_get_display (event);
848
849
  if (display)
    _gdk_display_event_data_free (display, event);
850

851
852
853
  if (event->any.window)
    g_object_unref (event->any.window);

854
  g_hash_table_remove (event_hash, event);
855
  g_slice_free (GdkEventPrivate, (GdkEventPrivate*) event);
856
857
}

858
859
860
861
862
863
/**
 * gdk_event_get_window:
 * @event: a #GdkEvent
 *
 * Extracts the #GdkWindow associated with an event.
 *
864
 * Returns: (transfer none): The #GdkWindow associated with the event
865
866
867
868
869
870
871
872
873
874
875
 *
 * Since: 3.10
 */
GdkWindow *
gdk_event_get_window (const GdkEvent *event)
{
  g_return_val_if_fail (event != NULL, NULL);

  return event->any.window;
}

876
/**
877
 * gdk_event_get_time:
878
879
880
881
882
 * @event: a #GdkEvent
 * 
 * Returns the time stamp from @event, if there is one; otherwise
 * returns #GDK_CURRENT_TIME. If @event is %NULL, returns #GDK_CURRENT_TIME.
 * 
883
 * Returns: time stamp field from @event
884
 **/
885
guint32
886
gdk_event_get_time (const GdkEvent *event)
887
888
889
890
891
892
893
894
895
896
897
{
  if (event)
    switch (event->type)
      {
      case GDK_MOTION_NOTIFY:
	return event->motion.time;
      case GDK_BUTTON_PRESS:
      case GDK_2BUTTON_PRESS:
      case GDK_3BUTTON_PRESS:
      case GDK_BUTTON_RELEASE:
	return event->button.time;
898
899
900
901
902
      case GDK_TOUCH_BEGIN:
      case GDK_TOUCH_UPDATE:
      case GDK_TOUCH_END:
      case GDK_TOUCH_CANCEL:
        return event->touch.time;
903
904
905
906
      case GDK_TOUCHPAD_SWIPE:
        return event->touchpad_swipe.time;
      case GDK_TOUCHPAD_PINCH:
        return event->touchpad_pinch.time;
907
908
      case GDK_SCROLL:
        return event->scroll.time;
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
      case GDK_KEY_PRESS:
      case GDK_KEY_RELEASE:
	return event->key.time;
      case GDK_ENTER_NOTIFY:
      case GDK_LEAVE_NOTIFY:
	return event->crossing.time;
      case GDK_PROPERTY_NOTIFY:
	return event->property.time;
      case GDK_SELECTION_CLEAR:
      case GDK_SELECTION_REQUEST:
      case GDK_SELECTION_NOTIFY:
	return event->selection.time;
      case GDK_PROXIMITY_IN:
      case GDK_PROXIMITY_OUT:
	return event->proximity.time;
      case GDK_DRAG_ENTER:
      case GDK_DRAG_LEAVE:
      case GDK_DRAG_MOTION:
      case GDK_DRAG_STATUS:
      case GDK_DROP_START:
      case GDK_DROP_FINISHED:
	return event->dnd.time;
931
932
933
934
935
936
937
938
      case GDK_PAD_BUTTON_PRESS:
      case GDK_PAD_BUTTON_RELEASE:
        return event->pad_button.time;
      case GDK_PAD_RING:
      case GDK_PAD_STRIP:
        return event->pad_axis.time;
      case GDK_PAD_GROUP_MODE:
        return event->pad_group_mode.time;
939
940
941
942
943
      case GDK_CLIENT_EVENT:
      case GDK_VISIBILITY_NOTIFY:
      case GDK_CONFIGURE:
      case GDK_FOCUS_CHANGE:
      case GDK_NOTHING:
944
      case GDK_DAMAGE:
945
946
947
948
949
      case GDK_DELETE:
      case GDK_DESTROY:
      case GDK_EXPOSE:
      case GDK_MAP:
      case GDK_UNMAP:
Havoc Pennington's avatar
Havoc Pennington committed
950
      case GDK_WINDOW_STATE:
951
      case GDK_SETTING:
952
      case GDK_OWNER_CHANGE:
953
      case GDK_GRAB_BROKEN:
954
      case GDK_EVENT_LAST:
955
956
        /* return current time */
        break;
957
958
959
960
961
      }
  
  return GDK_CURRENT_TIME;
}

962
963
/**
 * gdk_event_get_state:
964
 * @event: (allow-none): a #GdkEvent or %NULL
965
 * @state: (out): return location for state
966
 * 
William Jon McCann's avatar
William Jon McCann committed
967
 * If the event contains a “state” field, puts that field in @state. Otherwise
968
 * stores an empty state (0). Returns %TRUE if there was a state field
969
 * in the event. @event may be %NULL, in which case it’s treated
970
 * as if the event had no state field.
971
 * 
972
 * Returns: %TRUE if there was a state field in the event 
973
974
 **/
gboolean
975
976
gdk_event_get_state (const GdkEvent        *event,
                     GdkModifierType       *state)
977
{
978
979
  g_return_val_if_fail (state != NULL, FALSE);
  
980
981
982
983
  if (event)
    switch (event->type)
      {
      case GDK_MOTION_NOTIFY:
984
985
	*state = event->motion.state;
        return TRUE;
986
987
988
989
      case GDK_BUTTON_PRESS:
      case GDK_2BUTTON_PRESS:
      case GDK_3BUTTON_PRESS:
      case GDK_BUTTON_RELEASE:
990
991
992
993
994
995
996
        *state = event->button.state;
        return TRUE;
      case GDK_TOUCH_BEGIN:
      case GDK_TOUCH_UPDATE:
      case GDK_TOUCH_END:
      case GDK_TOUCH_CANCEL:
        *state = event->touch.state;
997
        return TRUE;
998
999
1000
1001
1002
1003
      case GDK_TOUCHPAD_SWIPE:
        *state = event->touchpad_swipe.state;
        return TRUE;
      case GDK_TOUCHPAD_PINCH:
        *state = event->touchpad_pinch.state;
        return TRUE;
1004
      case GDK_SCROLL:
1005
1006
	*state =  event->scroll.state;
        return TRUE;
1007
1008
      case GDK_KEY_PRESS:
      case GDK_KEY_RELEASE:
1009
1010
	*state =  event->key.state;
        return TRUE;
1011
1012
      case GDK_ENTER_NOTIFY:
      case GDK_LEAVE_NOTIFY:
1013
1014
	*state =  event->crossing.state;
        return TRUE;
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
      case GDK_PROPERTY_NOTIFY:
      case GDK_VISIBILITY_NOTIFY:
      case GDK_CLIENT_EVENT:
      case GDK_CONFIGURE:
      case GDK_FOCUS_CHANGE:
      case GDK_SELECTION_CLEAR:
      case GDK_SELECTION_REQUEST:
      case GDK_SELECTION_NOTIFY:
      case GDK_PROXIMITY_IN:
      case GDK_PROXIMITY_OUT:
1025
      case GDK_DAMAGE:
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
      case GDK_DRAG_ENTER:
      case GDK_DRAG_LEAVE:
      case GDK_DRAG_MOTION:
      case GDK_DRAG_STATUS:
      case GDK_DROP_START:
      case GDK_DROP_FINISHED:
      case GDK_NOTHING:
      case GDK_DELETE:
      case GDK_DESTROY:
      case GDK_EXPOSE:
      case GDK_MAP:
      case GDK_UNMAP:
Havoc Pennington's avatar
Havoc Pennington committed
1038
      case GDK_WINDOW_STATE:
1039
      case GDK_SETTING:
1040
      case GDK_OWNER_CHANGE:
1041
      case GDK_GRAB_BROKEN:
1042
1043
1044
1045
1046
      case GDK_PAD_BUTTON_PRESS:
      case GDK_PAD_BUTTON_RELEASE:
      case GDK_PAD_RING:
      case GDK_PAD_STRIP:
      case GDK_PAD_GROUP_MODE:
1047
      case GDK_EVENT_LAST:
1048
1049
1050
1051
        /* no state field */
        break;
      }

1052
1053
  *state = 0;
  return FALSE;
1054
1055
}

1056
1057
1058
/**
 * gdk_event_get_coords:
 * @event: a #GdkEvent
1059
1060
 * @x_win: (out) (optional): location to put event window x coordinate
 * @y_win: (out) (optional): location to put event window y coordinate
1061
1062
1063
 * 
 * Extract the event window relative x/y coordinates from an event.
 * 
1064
 * Returns: %TRUE if the event delivered event window coordinates
1065
1066
 **/
gboolean
1067
1068
1069
gdk_event_get_coords (const GdkEvent *event,
		      gdouble        *x_win,
		      gdouble        *y_win)
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
{
  gdouble x = 0, y = 0;
  gboolean fetched = TRUE;
  
  g_return_val_if_fail (event != NULL, FALSE);

  switch (event->type)
    {
    case GDK_CONFIGURE:
      x = event->configure.x;
      y = event->configure.y;
      break;
    case GDK_ENTER_NOTIFY:
    case GDK_LEAVE_NOTIFY:
      x = event->crossing.x;
      y = event->crossing.y;
      break;
    case GDK_SCROLL:
      x = event->scroll.x;
      y = event->scroll.y;
      break;
    case GDK_BUTTON_PRESS:
    case GDK_2BUTTON_PRESS:
    case GDK_3BUTTON_PRESS:
    case GDK_BUTTON_RELEASE:
      x = event->button.x;
      y = event->button.y;
      break;
1098
1099
1100
1101
1102
1103
1104
    case GDK_TOUCH_BEGIN:
    case GDK_TOUCH_UPDATE:
    case GDK_TOUCH_END:
    case GDK_TOUCH_CANCEL:
      x = event->touch.x;
      y = event->touch.y;
      break;
1105
1106
1107
1108
    case GDK_MOTION_NOTIFY:
      x = event->motion.x;
      y = event->motion.y;
      break;
1109
1110
1111
1112
1113
1114
1115
1116
    case GDK_TOUCHPAD_SWIPE:
      x = event->touchpad_swipe.x;
      y = event->touchpad_swipe.y;
      break;
    case GDK_TOUCHPAD_PINCH:
      x = event->touchpad_pinch.x;
      y = event->touchpad_pinch.y;
      break;
1117
1118
1119
1120
1121
1122
1123
1124
    default:
      fetched = FALSE;
      break;
    }

  if (x_win)
    *x_win = x;
  if (y_win)
1125
    *y_win = y;
1126
1127
1128
1129
1130
1131
1132

  return fetched;
}

/**
 * gdk_event_get_root_coords:
 * @event: a #GdkEvent
1133
1134
 * @x_root: (out) (optional): location to put root window x coordinate
 * @y_root: (out) (optional): location to put root window y coordinate
1135
1136
1137
 * 
 * Extract the root window relative x/y coordinates from an event.
 * 
1138
 * Returns: %TRUE if the event delivered root window coordinates
1139
1140
 **/
gboolean
1141
1142
1143
gdk_event_get_root_coords (const GdkEvent *event,
			   gdouble        *x_root,
			   gdouble        *y_root)
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
{
  gdouble x = 0, y = 0;
  gboolean fetched = TRUE;
  
  g_return_val_if_fail (event != NULL, FALSE);

  switch (event->type)
    {
    case GDK_MOTION_NOTIFY:
      x = event->motion.x_root;
      y = event->motion.y_root;
      break;
1156
1157
1158
1159
    case GDK_SCROLL:
      x = event->scroll.x_root;
      y = event->scroll.y_root;
      break;
1160
1161
1162
1163
1164
1165
1166
    case GDK_BUTTON_PRESS:
    case GDK_2BUTTON_PRESS:
    case GDK_3BUTTON_PRESS:
    case GDK_BUTTON_RELEASE:
      x = event->button.x_root;
      y = event->button.y_root;
      break;
1167
1168
1169
1170
1171
1172
1173
    case GDK_TOUCH_BEGIN:
    case GDK_TOUCH_UPDATE:
    case GDK_TOUCH_END:
    case GDK_TOUCH_CANCEL:
      x = event->touch.x_root;
      y = event->touch.y_root;
      break;
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
    case GDK_ENTER_NOTIFY:
    case GDK_LEAVE_NOTIFY:
      x = event->crossing.x_root;
      y = event->crossing.y_root;
      break;
    case GDK_DRAG_ENTER:
    case GDK_DRAG_LEAVE:
    case GDK_DRAG_MOTION:
    case GDK_DRAG_STATUS:
    case GDK_DROP_START:
    case GDK_DROP_FINISHED:
      x = event->dnd.x_root;
      y = event->dnd.y_root;
      break;
1188
1189
1190
1191
1192
1193
1194
1195
    case GDK_TOUCHPAD_SWIPE:
      x = event->touchpad_swipe.x_root;
      y = event->touchpad_swipe.y_root;
      break;
    case GDK_TOUCHPAD_PINCH:
      x = event->touchpad_pinch.x_root;
      y = event->touchpad_pinch.y_root;
      break;
1196
1197
1198
1199
1200
1201
1202
1203
    default:
      fetched = FALSE;
      break;
    }

  if (x_root)
    *x_root = x;
  if (y_root)
1204
    *y_root = y;
1205
1206
1207
1208

  return fetched;
}

1209
1210
1211
1212
1213
1214
1215
/**
 * gdk_event_get_button:
 * @event: a #GdkEvent
 * @button: (out): location to store mouse button number
 *
 * Extract the button number from an event.
 *
1216
 * Returns: %TRUE if the event delivered a button number
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
 *
 * Since: 3.2
 **/
gboolean
gdk_event_get_button (const GdkEvent *event,
                      guint *button)
{
  gboolean fetched = TRUE;
  guint number = 0;

  g_return_val_if_fail (event != NULL, FALSE);
  
  switch (event->type)
    {
    case GDK_BUTTON_PRESS:
    case GDK_2BUTTON_PRESS:
    case GDK_3BUTTON_PRESS:
    case GDK_BUTTON_RELEASE:
      number = event->button.button;
      break;
1237
1238
1239
1240
    case GDK_PAD_BUTTON_PRESS:
    case GDK_PAD_BUTTON_RELEASE:
      number = event->pad_button.button;
      break;
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
    default:
      fetched = FALSE;
      break;
    }

  if (button)
    *button = number;

  return fetched;
}

/**
 * gdk_event_get_click_count:
 * @event: a #GdkEvent
 * @click_count: (out): location to store click count
 *
 * Extracts the click count from an event.
 *
1259
 * Returns: %TRUE if the event delivered a click count
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
 *
 * Since: 3.2
 */
gboolean
gdk_event_get_click_count (const GdkEvent *event,
                           guint *click_count)
{
  gboolean fetched = TRUE;
  guint number = 0;

  g_return_val_if_fail (event != NULL, FALSE);

  switch (event->type)
    {
    case GDK_BUTTON_PRESS:
    case GDK_BUTTON_RELEASE:
      number = 1;
      break;
    case GDK_2BUTTON_PRESS:
      number = 2;
      break;
    case GDK_3BUTTON_PRESS:
      number = 3;
      break;
    default:
      fetched = FALSE;
      break;
    }

  if (click_count)
    *click_count = number;

  return fetched;
}

/**
 * gdk_event_get_keyval:
 * @event: a #GdkEvent
 * @keyval: (out): location to store the keyval
 *
 * Extracts the keyval from an event.
 *
1302
 * Returns: %TRUE if the event delivered a key symbol