]> Pileus Git - ~andy/gtk/blob - gdk/gdkevents.c
API: add accessors for GdkEvent fields
[~andy/gtk] / gdk / gdkevents.c
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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28
29 #include "gdkinternals.h"
30 #include "gdkdisplayprivate.h"
31
32 #include <string.h>
33 #include <math.h>
34
35
36 /**
37  * SECTION:events
38  * @Short_description: Functions for handling events from the window system
39  * @Title: Events
40  * @See_also: <link linkend="gdk-Event-Structures">Event Structures</link>
41  *
42  * This section describes functions dealing with events from the window
43  * system.
44  *
45  * In GTK+ applications the events are handled automatically in
46  * gtk_main_do_event() and passed on to the appropriate widgets, so these
47  * functions are rarely needed. Though some of the fields in the
48  * <link linkend="gdk-Event-Structures">Event Structures</link> are useful.
49  */
50
51
52 typedef struct _GdkIOClosure GdkIOClosure;
53
54 struct _GdkIOClosure
55 {
56   GDestroyNotify notify;
57   gpointer data;
58 };
59
60 /* Private variable declarations
61  */
62
63 static GdkEventFunc   _gdk_event_func = NULL;    /* Callback for events */
64 static gpointer       _gdk_event_data = NULL;
65 static GDestroyNotify _gdk_event_notify = NULL;
66
67 void
68 _gdk_event_emit (GdkEvent *event)
69 {
70   if (_gdk_event_func)
71     (*_gdk_event_func) (event, _gdk_event_data);
72 }
73
74 /*********************************************
75  * Functions for maintaining the event queue *
76  *********************************************/
77
78 /**
79  * _gdk_event_queue_find_first:
80  * @display: a #GdkDisplay
81  * 
82  * Find the first event on the queue that is not still
83  * being filled in.
84  * 
85  * Return value: Pointer to the list node for that event, or NULL.
86  **/
87 GList*
88 _gdk_event_queue_find_first (GdkDisplay *display)
89 {
90   GList *tmp_list = display->queued_events;
91
92   while (tmp_list)
93     {
94       GdkEventPrivate *event = tmp_list->data;
95       if (!(event->flags & GDK_EVENT_PENDING))
96         return tmp_list;
97
98       tmp_list = g_list_next (tmp_list);
99     }
100
101   return NULL;
102 }
103
104 /**
105  * _gdk_event_queue_prepend:
106  * @display: a #GdkDisplay
107  * @event: Event to prepend.
108  *
109  * Prepends an event before the head of the event queue.
110  *
111  * Returns: the newly prepended list node.
112  **/
113 GList*
114 _gdk_event_queue_prepend (GdkDisplay *display,
115                           GdkEvent   *event)
116 {
117   display->queued_events = g_list_prepend (display->queued_events, event);
118   if (!display->queued_tail)
119     display->queued_tail = display->queued_events;
120   return display->queued_events;
121 }
122
123 /**
124  * _gdk_event_queue_append:
125  * @display: a #GdkDisplay
126  * @event: Event to append.
127  * 
128  * Appends an event onto the tail of the event queue.
129  *
130  * Returns: the newly appended list node.
131  **/
132 GList *
133 _gdk_event_queue_append (GdkDisplay *display,
134                          GdkEvent   *event)
135 {
136   display->queued_tail = g_list_append (display->queued_tail, event);
137   
138   if (!display->queued_events)
139     display->queued_events = display->queued_tail;
140   else
141     display->queued_tail = display->queued_tail->next;
142
143   return display->queued_tail;
144 }
145
146 /**
147  * _gdk_event_queue_insert_after:
148  * @display: a #GdkDisplay
149  * @sibling: Append after this event.
150  * @event: Event to append.
151  *
152  * Appends an event after the specified event, or if it isn't in
153  * the queue, onto the tail of the event queue.
154  *
155  * Returns: the newly appended list node.
156  *
157  * Since: 2.16
158  */
159 GList*
160 _gdk_event_queue_insert_after (GdkDisplay *display,
161                                GdkEvent   *sibling,
162                                GdkEvent   *event)
163 {
164   GList *prev = g_list_find (display->queued_events, sibling);
165   if (prev && prev->next)
166     {
167       display->queued_events = g_list_insert_before (display->queued_events, prev->next, event);
168       return prev->next;
169     }
170   else
171     return _gdk_event_queue_append (display, event);
172 }
173
174 /**
175  * _gdk_event_queue_insert_after:
176  * @display: a #GdkDisplay
177  * @sibling: Append after this event.
178  * @event: Event to append.
179  *
180  * Appends an event before the specified event, or if it isn't in
181  * the queue, onto the tail of the event queue.
182  *
183  * Returns: the newly appended list node.
184  *
185  * Since: 2.16
186  */
187 GList*
188 _gdk_event_queue_insert_before (GdkDisplay *display,
189                                 GdkEvent   *sibling,
190                                 GdkEvent   *event)
191 {
192   GList *next = g_list_find (display->queued_events, sibling);
193   if (next)
194     {
195       display->queued_events = g_list_insert_before (display->queued_events, next, event);
196       return next->prev;
197     }
198   else
199     return _gdk_event_queue_append (display, event);
200 }
201
202
203 /**
204  * _gdk_event_queue_remove_link:
205  * @display: a #GdkDisplay
206  * @node: node to remove
207  * 
208  * Removes a specified list node from the event queue.
209  **/
210 void
211 _gdk_event_queue_remove_link (GdkDisplay *display,
212                               GList      *node)
213 {
214   if (node->prev)
215     node->prev->next = node->next;
216   else
217     display->queued_events = node->next;
218   
219   if (node->next)
220     node->next->prev = node->prev;
221   else
222     display->queued_tail = node->prev;
223 }
224
225 /**
226  * _gdk_event_unqueue:
227  * @display: a #GdkDisplay
228  * 
229  * Removes and returns the first event from the event
230  * queue that is not still being filled in.
231  * 
232  * Return value: the event, or %NULL. Ownership is transferred
233  * to the caller.
234  **/
235 GdkEvent*
236 _gdk_event_unqueue (GdkDisplay *display)
237 {
238   GdkEvent *event = NULL;
239   GList *tmp_list;
240
241   tmp_list = _gdk_event_queue_find_first (display);
242
243   if (tmp_list)
244     {
245       event = tmp_list->data;
246       _gdk_event_queue_remove_link (display, tmp_list);
247       g_list_free_1 (tmp_list);
248     }
249
250   return event;
251 }
252
253 /**
254  * gdk_event_handler_set:
255  * @func: the function to call to handle events from GDK.
256  * @data: user data to pass to the function. 
257  * @notify: the function to call when the handler function is removed, i.e. when
258  *          gdk_event_handler_set() is called with another event handler.
259  * 
260  * Sets the function to call to handle all events from GDK.
261  *
262  * Note that GTK+ uses this to install its own event handler, so it is
263  * usually not useful for GTK+ applications. (Although an application
264  * can call this function then call gtk_main_do_event() to pass
265  * events to GTK+.)
266  **/
267 void 
268 gdk_event_handler_set (GdkEventFunc   func,
269                        gpointer       data,
270                        GDestroyNotify notify)
271 {
272   if (_gdk_event_notify)
273     (*_gdk_event_notify) (_gdk_event_data);
274
275   _gdk_event_func = func;
276   _gdk_event_data = data;
277   _gdk_event_notify = notify;
278 }
279
280 /**
281  * gdk_events_pending:
282  *
283  * Checks if any events are ready to be processed for any display.
284  *
285  * Return value: %TRUE if any events are pending.
286  */
287 gboolean
288 gdk_events_pending (void)
289 {
290   GSList *list, *l;
291   gboolean pending;
292
293   pending = FALSE;
294   list = gdk_display_manager_list_displays (gdk_display_manager_get ());
295   for (l = list; l; l = l->next)
296     {
297       if (_gdk_event_queue_find_first (l->data))
298         {
299           pending = TRUE;
300           goto out;
301         }
302     }
303
304   for (l = list; l; l = l->next)
305     {
306       if (gdk_display_has_pending (l->data))
307         {
308           pending = TRUE;
309           goto out;
310         }
311     }
312
313  out:
314   g_slist_free (list);
315
316   return pending;
317 }
318
319 /**
320  * gdk_event_get:
321  * 
322  * Checks all open displays for a #GdkEvent to process,to be processed
323  * on, fetching events from the windowing system if necessary.
324  * See gdk_display_get_event().
325  * 
326  * Return value: the next #GdkEvent to be processed, or %NULL if no events
327  * are pending. The returned #GdkEvent should be freed with gdk_event_free().
328  **/
329 GdkEvent*
330 gdk_event_get (void)
331 {
332   GSList *list, *l;
333   GdkEvent *event;
334
335   event = NULL;
336   list = gdk_display_manager_list_displays (gdk_display_manager_get ());
337   for (l = list; l; l = l->next)
338     {
339       event = gdk_display_get_event (l->data);
340       if (event)
341         break;
342     }
343
344   g_slist_free (list);
345
346   return event;
347 }
348
349 /**
350  * gdk_event_peek:
351  *
352  * If there is an event waiting in the event queue of some open
353  * display, returns a copy of it. See gdk_display_peek_event().
354  * 
355  * Return value: a copy of the first #GdkEvent on some event queue, or %NULL if no
356  * events are in any queues. The returned #GdkEvent should be freed with
357  * gdk_event_free().
358  **/
359 GdkEvent*
360 gdk_event_peek (void)
361 {
362   GSList *list, *l;
363   GdkEvent *event;
364
365   event = NULL;
366   list = gdk_display_manager_list_displays (gdk_display_manager_get ());
367   for (l = list; l; l = l->next)
368     {
369       event = gdk_display_peek_event (l->data);
370       if (event)
371         break;
372     }
373
374   g_slist_free (list);
375
376   return event;
377 }
378
379 /**
380  * gdk_event_put:
381  * @event: a #GdkEvent.
382  *
383  * Appends a copy of the given event onto the front of the event
384  * queue for event->any.window's display, or the default event
385  * queue if event->any.window is %NULL. See gdk_display_put_event().
386  **/
387 void
388 gdk_event_put (const GdkEvent *event)
389 {
390   GdkDisplay *display;
391   
392   g_return_if_fail (event != NULL);
393
394   if (event->any.window)
395     display = gdk_window_get_display (event->any.window);
396   else
397     {
398       GDK_NOTE (MULTIHEAD,
399                 g_message ("Falling back to default display for gdk_event_put()"));
400       display = gdk_display_get_default ();
401     }
402
403   gdk_display_put_event (display, event);
404 }
405
406 static GHashTable *event_hash = NULL;
407
408 /**
409  * gdk_event_new:
410  * @type: a #GdkEventType 
411  * 
412  * Creates a new event of the given type. All fields are set to 0.
413  * 
414  * Return value: a newly-allocated #GdkEvent. The returned #GdkEvent 
415  * should be freed with gdk_event_free().
416  *
417  * Since: 2.2
418  **/
419 GdkEvent*
420 gdk_event_new (GdkEventType type)
421 {
422   GdkEventPrivate *new_private;
423   GdkEvent *new_event;
424   
425   if (!event_hash)
426     event_hash = g_hash_table_new (g_direct_hash, NULL);
427
428   new_private = g_slice_new0 (GdkEventPrivate);
429   
430   new_private->flags = 0;
431   new_private->screen = NULL;
432
433   g_hash_table_insert (event_hash, new_private, GUINT_TO_POINTER (1));
434
435   new_event = (GdkEvent *) new_private;
436
437   new_event->any.type = type;
438
439   /*
440    * Bytewise 0 initialization is reasonable for most of the 
441    * current event types. Explicitely initialize double fields
442    * since I trust bytewise 0 == 0. less than for integers
443    * or pointers.
444    */
445   switch (type)
446     {
447     case GDK_MOTION_NOTIFY:
448       new_event->motion.x = 0.;
449       new_event->motion.y = 0.;
450       new_event->motion.x_root = 0.;
451       new_event->motion.y_root = 0.;
452       break;
453     case GDK_BUTTON_PRESS:
454     case GDK_2BUTTON_PRESS:
455     case GDK_3BUTTON_PRESS:
456     case GDK_BUTTON_RELEASE:
457       new_event->button.x = 0.;
458       new_event->button.y = 0.;
459       new_event->button.x_root = 0.;
460       new_event->button.y_root = 0.;
461       break;
462     case GDK_SCROLL:
463       new_event->scroll.x = 0.;
464       new_event->scroll.y = 0.;
465       new_event->scroll.x_root = 0.;
466       new_event->scroll.y_root = 0.;
467       break;
468     case GDK_ENTER_NOTIFY:
469     case GDK_LEAVE_NOTIFY:
470       new_event->crossing.x = 0.;
471       new_event->crossing.y = 0.;
472       new_event->crossing.x_root = 0.;
473       new_event->crossing.y_root = 0.;
474       break;
475     default:
476       break;
477     }
478   
479   return new_event;
480 }
481
482 static gboolean
483 gdk_event_is_allocated (const GdkEvent *event)
484 {
485   if (event_hash)
486     return g_hash_table_lookup (event_hash, event) != NULL;
487
488   return FALSE;
489 }
490  
491 /**
492  * gdk_event_copy:
493  * @event: a #GdkEvent
494  * 
495  * Copies a #GdkEvent, copying or incrementing the reference count of the
496  * resources associated with it (e.g. #GdkWindow's and strings).
497  * 
498  * Return value: a copy of @event. The returned #GdkEvent should be freed with
499  * gdk_event_free().
500  **/
501 GdkEvent*
502 gdk_event_copy (const GdkEvent *event)
503 {
504   GdkEventPrivate *new_private;
505   GdkEvent *new_event;
506
507   g_return_val_if_fail (event != NULL, NULL);
508
509   new_event = gdk_event_new (GDK_NOTHING);
510   new_private = (GdkEventPrivate *)new_event;
511
512   *new_event = *event;
513   if (new_event->any.window)
514     g_object_ref (new_event->any.window);
515
516   if (gdk_event_is_allocated (event))
517     {
518       GdkEventPrivate *private = (GdkEventPrivate *)event;
519
520       new_private->screen = private->screen;
521       new_private->device = private->device;
522       new_private->source_device = private->source_device;
523     }
524
525   switch (event->any.type)
526     {
527     case GDK_KEY_PRESS:
528     case GDK_KEY_RELEASE:
529       new_event->key.string = g_strdup (event->key.string);
530       break;
531
532     case GDK_ENTER_NOTIFY:
533     case GDK_LEAVE_NOTIFY:
534       if (event->crossing.subwindow != NULL)
535         g_object_ref (event->crossing.subwindow);
536       break;
537
538     case GDK_DRAG_ENTER:
539     case GDK_DRAG_LEAVE:
540     case GDK_DRAG_MOTION:
541     case GDK_DRAG_STATUS:
542     case GDK_DROP_START:
543     case GDK_DROP_FINISHED:
544       g_object_ref (event->dnd.context);
545       break;
546
547     case GDK_EXPOSE:
548     case GDK_DAMAGE:
549       if (event->expose.region)
550         new_event->expose.region = cairo_region_copy (event->expose.region);
551       break;
552
553     case GDK_SETTING:
554       new_event->setting.name = g_strdup (new_event->setting.name);
555       break;
556
557     case GDK_BUTTON_PRESS:
558     case GDK_2BUTTON_PRESS:
559     case GDK_3BUTTON_PRESS:
560     case GDK_BUTTON_RELEASE:
561       if (event->button.axes)
562         new_event->button.axes = g_memdup (event->button.axes,
563                                            sizeof (gdouble) * gdk_device_get_n_axes (event->button.device));
564       break;
565
566     case GDK_MOTION_NOTIFY:
567       if (event->motion.axes)
568         new_event->motion.axes = g_memdup (event->motion.axes,
569                                            sizeof (gdouble) * gdk_device_get_n_axes (event->motion.device));
570       break;
571
572     case GDK_OWNER_CHANGE:
573       new_event->owner_change.owner = event->owner_change.owner;
574       if (new_event->owner_change.owner)
575         g_object_ref (new_event->owner_change.owner);
576       break;
577
578     case GDK_SELECTION_CLEAR:
579     case GDK_SELECTION_NOTIFY:
580     case GDK_SELECTION_REQUEST:
581       new_event->selection.requestor = event->selection.requestor;
582       if (new_event->selection.requestor)
583         g_object_unref (new_event->selection.requestor);
584       break;
585
586     default:
587       break;
588     }
589
590   if (gdk_event_is_allocated (event))
591     _gdk_display_event_data_copy (gdk_display_get_default (), event, new_event);
592
593   return new_event;
594 }
595
596 /**
597  * gdk_event_free:
598  * @event:  a #GdkEvent.
599  * 
600  * Frees a #GdkEvent, freeing or decrementing any resources associated with it.
601  * Note that this function should only be called with events returned from
602  * functions such as gdk_event_peek(), gdk_event_get(), gdk_event_copy()
603  * and gdk_event_new().
604  **/
605 void
606 gdk_event_free (GdkEvent *event)
607 {
608   GdkDisplay *display;
609
610   g_return_if_fail (event != NULL);
611
612   if (event->any.window)
613     g_object_unref (event->any.window);
614   
615   switch (event->any.type)
616     {
617     case GDK_KEY_PRESS:
618     case GDK_KEY_RELEASE:
619       g_free (event->key.string);
620       break;
621       
622     case GDK_ENTER_NOTIFY:
623     case GDK_LEAVE_NOTIFY:
624       if (event->crossing.subwindow != NULL)
625         g_object_unref (event->crossing.subwindow);
626       break;
627       
628     case GDK_DRAG_ENTER:
629     case GDK_DRAG_LEAVE:
630     case GDK_DRAG_MOTION:
631     case GDK_DRAG_STATUS:
632     case GDK_DROP_START:
633     case GDK_DROP_FINISHED:
634       if (event->dnd.context != NULL)
635         g_object_unref (event->dnd.context);
636       break;
637
638     case GDK_BUTTON_PRESS:
639     case GDK_2BUTTON_PRESS:
640     case GDK_3BUTTON_PRESS:
641     case GDK_BUTTON_RELEASE:
642       g_free (event->button.axes);
643       break;
644       
645     case GDK_EXPOSE:
646     case GDK_DAMAGE:
647       if (event->expose.region)
648         cairo_region_destroy (event->expose.region);
649       break;
650       
651     case GDK_MOTION_NOTIFY:
652       g_free (event->motion.axes);
653       break;
654       
655     case GDK_SETTING:
656       g_free (event->setting.name);
657       break;
658       
659     case GDK_OWNER_CHANGE:
660       if (event->owner_change.owner)
661         g_object_unref (event->owner_change.owner);
662       break;
663
664     case GDK_SELECTION_CLEAR:
665     case GDK_SELECTION_NOTIFY:
666     case GDK_SELECTION_REQUEST:
667       if (event->selection.requestor)
668         g_object_unref (event->selection.requestor);
669       break;
670
671     default:
672       break;
673     }
674
675   display = gdk_display_get_default ();
676   if (display)
677     _gdk_display_event_data_free (display, event);
678
679   g_hash_table_remove (event_hash, event);
680   g_slice_free (GdkEventPrivate, (GdkEventPrivate*) event);
681 }
682
683 /**
684  * gdk_event_get_time:
685  * @event: a #GdkEvent
686  * 
687  * Returns the time stamp from @event, if there is one; otherwise
688  * returns #GDK_CURRENT_TIME. If @event is %NULL, returns #GDK_CURRENT_TIME.
689  * 
690  * Return value: time stamp field from @event
691  **/
692 guint32
693 gdk_event_get_time (const GdkEvent *event)
694 {
695   if (event)
696     switch (event->type)
697       {
698       case GDK_MOTION_NOTIFY:
699         return event->motion.time;
700       case GDK_BUTTON_PRESS:
701       case GDK_2BUTTON_PRESS:
702       case GDK_3BUTTON_PRESS:
703       case GDK_BUTTON_RELEASE:
704         return event->button.time;
705       case GDK_SCROLL:
706         return event->scroll.time;
707       case GDK_KEY_PRESS:
708       case GDK_KEY_RELEASE:
709         return event->key.time;
710       case GDK_ENTER_NOTIFY:
711       case GDK_LEAVE_NOTIFY:
712         return event->crossing.time;
713       case GDK_PROPERTY_NOTIFY:
714         return event->property.time;
715       case GDK_SELECTION_CLEAR:
716       case GDK_SELECTION_REQUEST:
717       case GDK_SELECTION_NOTIFY:
718         return event->selection.time;
719       case GDK_PROXIMITY_IN:
720       case GDK_PROXIMITY_OUT:
721         return event->proximity.time;
722       case GDK_DRAG_ENTER:
723       case GDK_DRAG_LEAVE:
724       case GDK_DRAG_MOTION:
725       case GDK_DRAG_STATUS:
726       case GDK_DROP_START:
727       case GDK_DROP_FINISHED:
728         return event->dnd.time;
729       case GDK_CLIENT_EVENT:
730       case GDK_VISIBILITY_NOTIFY:
731       case GDK_CONFIGURE:
732       case GDK_FOCUS_CHANGE:
733       case GDK_NOTHING:
734       case GDK_DAMAGE:
735       case GDK_DELETE:
736       case GDK_DESTROY:
737       case GDK_EXPOSE:
738       case GDK_MAP:
739       case GDK_UNMAP:
740       case GDK_WINDOW_STATE:
741       case GDK_SETTING:
742       case GDK_OWNER_CHANGE:
743       case GDK_GRAB_BROKEN:
744       case GDK_EVENT_LAST:
745         /* return current time */
746         break;
747       }
748   
749   return GDK_CURRENT_TIME;
750 }
751
752 /**
753  * gdk_event_get_state:
754  * @event: a #GdkEvent or NULL
755  * @state: (out): return location for state
756  * 
757  * If the event contains a "state" field, puts that field in @state. Otherwise
758  * stores an empty state (0). Returns %TRUE if there was a state field
759  * in the event. @event may be %NULL, in which case it's treated
760  * as if the event had no state field.
761  * 
762  * Return value: %TRUE if there was a state field in the event 
763  **/
764 gboolean
765 gdk_event_get_state (const GdkEvent        *event,
766                      GdkModifierType       *state)
767 {
768   g_return_val_if_fail (state != NULL, FALSE);
769   
770   if (event)
771     switch (event->type)
772       {
773       case GDK_MOTION_NOTIFY:
774         *state = event->motion.state;
775         return TRUE;
776       case GDK_BUTTON_PRESS:
777       case GDK_2BUTTON_PRESS:
778       case GDK_3BUTTON_PRESS:
779       case GDK_BUTTON_RELEASE:
780         *state =  event->button.state;
781         return TRUE;
782       case GDK_SCROLL:
783         *state =  event->scroll.state;
784         return TRUE;
785       case GDK_KEY_PRESS:
786       case GDK_KEY_RELEASE:
787         *state =  event->key.state;
788         return TRUE;
789       case GDK_ENTER_NOTIFY:
790       case GDK_LEAVE_NOTIFY:
791         *state =  event->crossing.state;
792         return TRUE;
793       case GDK_PROPERTY_NOTIFY:
794       case GDK_VISIBILITY_NOTIFY:
795       case GDK_CLIENT_EVENT:
796       case GDK_CONFIGURE:
797       case GDK_FOCUS_CHANGE:
798       case GDK_SELECTION_CLEAR:
799       case GDK_SELECTION_REQUEST:
800       case GDK_SELECTION_NOTIFY:
801       case GDK_PROXIMITY_IN:
802       case GDK_PROXIMITY_OUT:
803       case GDK_DAMAGE:
804       case GDK_DRAG_ENTER:
805       case GDK_DRAG_LEAVE:
806       case GDK_DRAG_MOTION:
807       case GDK_DRAG_STATUS:
808       case GDK_DROP_START:
809       case GDK_DROP_FINISHED:
810       case GDK_NOTHING:
811       case GDK_DELETE:
812       case GDK_DESTROY:
813       case GDK_EXPOSE:
814       case GDK_MAP:
815       case GDK_UNMAP:
816       case GDK_WINDOW_STATE:
817       case GDK_SETTING:
818       case GDK_OWNER_CHANGE:
819       case GDK_GRAB_BROKEN:
820       case GDK_EVENT_LAST:
821         /* no state field */
822         break;
823       }
824
825   *state = 0;
826   return FALSE;
827 }
828
829 /**
830  * gdk_event_get_coords:
831  * @event: a #GdkEvent
832  * @x_win: (out): location to put event window x coordinate
833  * @y_win: (out): location to put event window y coordinate
834  * 
835  * Extract the event window relative x/y coordinates from an event.
836  * 
837  * Return value: %TRUE if the event delivered event window coordinates
838  **/
839 gboolean
840 gdk_event_get_coords (const GdkEvent *event,
841                       gdouble        *x_win,
842                       gdouble        *y_win)
843 {
844   gdouble x = 0, y = 0;
845   gboolean fetched = TRUE;
846   
847   g_return_val_if_fail (event != NULL, FALSE);
848
849   switch (event->type)
850     {
851     case GDK_CONFIGURE:
852       x = event->configure.x;
853       y = event->configure.y;
854       break;
855     case GDK_ENTER_NOTIFY:
856     case GDK_LEAVE_NOTIFY:
857       x = event->crossing.x;
858       y = event->crossing.y;
859       break;
860     case GDK_SCROLL:
861       x = event->scroll.x;
862       y = event->scroll.y;
863       break;
864     case GDK_BUTTON_PRESS:
865     case GDK_2BUTTON_PRESS:
866     case GDK_3BUTTON_PRESS:
867     case GDK_BUTTON_RELEASE:
868       x = event->button.x;
869       y = event->button.y;
870       break;
871     case GDK_MOTION_NOTIFY:
872       x = event->motion.x;
873       y = event->motion.y;
874       break;
875     default:
876       fetched = FALSE;
877       break;
878     }
879
880   if (x_win)
881     *x_win = x;
882   if (y_win)
883     *y_win = y;
884
885   return fetched;
886 }
887
888 /**
889  * gdk_event_get_root_coords:
890  * @event: a #GdkEvent
891  * @x_root: (out): location to put root window x coordinate
892  * @y_root: (out): location to put root window y coordinate
893  * 
894  * Extract the root window relative x/y coordinates from an event.
895  * 
896  * Return value: %TRUE if the event delivered root window coordinates
897  **/
898 gboolean
899 gdk_event_get_root_coords (const GdkEvent *event,
900                            gdouble        *x_root,
901                            gdouble        *y_root)
902 {
903   gdouble x = 0, y = 0;
904   gboolean fetched = TRUE;
905   
906   g_return_val_if_fail (event != NULL, FALSE);
907
908   switch (event->type)
909     {
910     case GDK_MOTION_NOTIFY:
911       x = event->motion.x_root;
912       y = event->motion.y_root;
913       break;
914     case GDK_SCROLL:
915       x = event->scroll.x_root;
916       y = event->scroll.y_root;
917       break;
918     case GDK_BUTTON_PRESS:
919     case GDK_2BUTTON_PRESS:
920     case GDK_3BUTTON_PRESS:
921     case GDK_BUTTON_RELEASE:
922       x = event->button.x_root;
923       y = event->button.y_root;
924       break;
925     case GDK_ENTER_NOTIFY:
926     case GDK_LEAVE_NOTIFY:
927       x = event->crossing.x_root;
928       y = event->crossing.y_root;
929       break;
930     case GDK_DRAG_ENTER:
931     case GDK_DRAG_LEAVE:
932     case GDK_DRAG_MOTION:
933     case GDK_DRAG_STATUS:
934     case GDK_DROP_START:
935     case GDK_DROP_FINISHED:
936       x = event->dnd.x_root;
937       y = event->dnd.y_root;
938       break;
939     default:
940       fetched = FALSE;
941       break;
942     }
943
944   if (x_root)
945     *x_root = x;
946   if (y_root)
947     *y_root = y;
948
949   return fetched;
950 }
951
952 /**
953  * gdk_event_get_button:
954  * @event: a #GdkEvent
955  * @button: (out): location to store mouse button number
956  *
957  * Extract the button number from an event.
958  *
959  * Return value: %TRUE if the event delivered a button number
960  *
961  * Since: 3.2
962  **/
963 gboolean
964 gdk_event_get_button (const GdkEvent *event,
965                       guint *button)
966 {
967   gboolean fetched = TRUE;
968   guint number = 0;
969
970   g_return_val_if_fail (event != NULL, FALSE);
971   
972   switch (event->type)
973     {
974     case GDK_BUTTON_PRESS:
975     case GDK_2BUTTON_PRESS:
976     case GDK_3BUTTON_PRESS:
977     case GDK_BUTTON_RELEASE:
978       number = event->button.button;
979       break;
980     default:
981       fetched = FALSE;
982       break;
983     }
984
985   if (button)
986     *button = number;
987
988   return fetched;
989 }
990
991 /**
992  * gdk_event_get_click_count:
993  * @event: a #GdkEvent
994  * @click_count: (out): location to store click count
995  *
996  * Extracts the click count from an event.
997  *
998  * Return value: %TRUE if the event delivered a click count
999  *
1000  * Since: 3.2
1001  */
1002 gboolean
1003 gdk_event_get_click_count (const GdkEvent *event,
1004                            guint *click_count)
1005 {
1006   gboolean fetched = TRUE;
1007   guint number = 0;
1008
1009   g_return_val_if_fail (event != NULL, FALSE);
1010
1011   switch (event->type)
1012     {
1013     case GDK_BUTTON_PRESS:
1014     case GDK_BUTTON_RELEASE:
1015       number = 1;
1016       break;
1017     case GDK_2BUTTON_PRESS:
1018       number = 2;
1019       break;
1020     case GDK_3BUTTON_PRESS:
1021       number = 3;
1022       break;
1023     default:
1024       fetched = FALSE;
1025       break;
1026     }
1027
1028   if (click_count)
1029     *click_count = number;
1030
1031   return fetched;
1032 }
1033
1034 /**
1035  * gdk_event_get_keyval:
1036  * @event: a #GdkEvent
1037  * @keyval: (out): location to store the keyval
1038  *
1039  * Extracts the keyval from an event.
1040  *
1041  * Return value: %TRUE if the event delivered a key symbol
1042  *
1043  * Since: 3.2
1044  */
1045 gboolean
1046 gdk_event_get_keyval (const GdkEvent *event,
1047                       guint *keyval)
1048 {
1049   gboolean fetched = TRUE;
1050   guint number = 0;
1051
1052   switch (event->type)
1053     {
1054     case GDK_KEY_PRESS:
1055     case GDK_KEY_RELEASE:
1056       number = event->key.keyval;
1057       break;
1058     default:
1059       fetched = FALSE;
1060       break;
1061     }
1062
1063   if (keyval)
1064     *keyval = number;
1065
1066   return fetched;
1067 }
1068
1069 /**
1070  * gdk_event_get_keycode:
1071  * @event: a #GdkEvent
1072  * @keycode: (out): location to store the keycode
1073  *
1074  * Extracts the hardware keycode from an event.
1075  *
1076  * Return value: %TRUE if the event delivered a hardware keycode
1077  *
1078  * Since: 3.2
1079  */
1080 gboolean
1081 gdk_event_get_keycode (const GdkEvent *event,
1082                        guint16 *keycode)
1083 {
1084   gboolean fetched = TRUE;
1085   guint16 number = 0;
1086
1087   switch (event->type)
1088     {
1089     case GDK_KEY_PRESS:
1090     case GDK_KEY_RELEASE:
1091       number = event->key.hardware_keycode;
1092       break;
1093     default:
1094       fetched = FALSE;
1095       break;
1096     }
1097
1098   if (keycode)
1099     *keycode = number;
1100
1101   return fetched;
1102 }
1103
1104 /**
1105  * gdk_event_get_scroll_direction:
1106  * @event: a #GdkEvent
1107  * @direction: (out): location to store the scroll direction
1108  *
1109  * Extracts the scroll direction from an event.
1110  *
1111  * Return value: %TRUE if the event delivered a scroll direction
1112  *
1113  * Since: 3.2
1114  */
1115 gboolean
1116 gdk_event_get_scroll_direction (const GdkEvent *event,
1117                                 GdkScrollDirection *direction)
1118 {
1119   gboolean fetched = TRUE;
1120   GdkScrollDirection dir = 0;
1121
1122   switch (event->type)
1123     {
1124     case GDK_SCROLL:
1125       dir = event->scroll.direction;
1126       break;
1127     default:
1128       fetched = FALSE;
1129       break;
1130     }
1131
1132   if (direction)
1133     *direction = dir;
1134
1135   return fetched;
1136 }
1137
1138 /**
1139  * gdk_event_get_axis:
1140  * @event: a #GdkEvent
1141  * @axis_use: the axis use to look for
1142  * @value: (out): location to store the value found
1143  * 
1144  * Extract the axis value for a particular axis use from
1145  * an event structure.
1146  * 
1147  * Return value: %TRUE if the specified axis was found, otherwise %FALSE
1148  **/
1149 gboolean
1150 gdk_event_get_axis (const GdkEvent *event,
1151                     GdkAxisUse      axis_use,
1152                     gdouble        *value)
1153 {
1154   gdouble *axes;
1155   GdkDevice *device;
1156   
1157   g_return_val_if_fail (event != NULL, FALSE);
1158   
1159   if (axis_use == GDK_AXIS_X || axis_use == GDK_AXIS_Y)
1160     {
1161       gdouble x, y;
1162       
1163       switch (event->type)
1164         {
1165         case GDK_MOTION_NOTIFY:
1166           x = event->motion.x;
1167           y = event->motion.y;
1168           break;
1169         case GDK_SCROLL:
1170           x = event->scroll.x;
1171           y = event->scroll.y;
1172           break;
1173         case GDK_BUTTON_PRESS:
1174         case GDK_BUTTON_RELEASE:
1175           x = event->button.x;
1176           y = event->button.y;
1177           break;
1178         case GDK_ENTER_NOTIFY:
1179         case GDK_LEAVE_NOTIFY:
1180           x = event->crossing.x;
1181           y = event->crossing.y;
1182           break;
1183           
1184         default:
1185           return FALSE;
1186         }
1187
1188       if (axis_use == GDK_AXIS_X && value)
1189         *value = x;
1190       if (axis_use == GDK_AXIS_Y && value)
1191         *value = y;
1192
1193       return TRUE;
1194     }
1195   else if (event->type == GDK_BUTTON_PRESS ||
1196            event->type == GDK_BUTTON_RELEASE)
1197     {
1198       device = event->button.device;
1199       axes = event->button.axes;
1200     }
1201   else if (event->type == GDK_MOTION_NOTIFY)
1202     {
1203       device = event->motion.device;
1204       axes = event->motion.axes;
1205     }
1206   else
1207     return FALSE;
1208
1209   return gdk_device_get_axis (device, axes, axis_use, value);
1210 }
1211
1212 /**
1213  * gdk_event_set_device:
1214  * @event: a #GdkEvent
1215  * @device: a #GdkDevice
1216  *
1217  * Sets the device for @event to @device. The event must
1218  * have been allocated by GTK+, for instance, by
1219  * gdk_event_copy().
1220  *
1221  * Since: 3.0
1222  **/
1223 void
1224 gdk_event_set_device (GdkEvent  *event,
1225                       GdkDevice *device)
1226 {
1227   GdkEventPrivate *private;
1228
1229   g_return_if_fail (gdk_event_is_allocated (event));
1230
1231   private = (GdkEventPrivate *) event;
1232
1233   private->device = device;
1234
1235   switch (event->type)
1236     {
1237     case GDK_MOTION_NOTIFY:
1238       event->motion.device = device;
1239       break;
1240     case GDK_BUTTON_PRESS:
1241     case GDK_2BUTTON_PRESS:
1242     case GDK_3BUTTON_PRESS:
1243     case GDK_BUTTON_RELEASE:
1244       event->button.device = device;
1245       break;
1246     case GDK_SCROLL:
1247       event->scroll.device = device;
1248       break;
1249     case GDK_PROXIMITY_IN:
1250     case GDK_PROXIMITY_OUT:
1251       event->proximity.device = device;
1252       break;
1253     default:
1254       break;
1255     }
1256 }
1257
1258 /**
1259  * gdk_event_get_device:
1260  * @event: a #GdkEvent.
1261  *
1262  * If the event contains a "device" field, this function will return
1263  * it, else it will return %NULL.
1264  *
1265  * Returns: (transfer none): a #GdkDevice, or %NULL.
1266  *
1267  * Since: 3.0
1268  **/
1269 GdkDevice *
1270 gdk_event_get_device (const GdkEvent *event)
1271 {
1272   g_return_val_if_fail (event != NULL, NULL);
1273
1274   if (gdk_event_is_allocated (event))
1275     {
1276       GdkEventPrivate *private = (GdkEventPrivate *) event;
1277
1278       if (private->device)
1279         return private->device;
1280     }
1281
1282   switch (event->type)
1283     {
1284     case GDK_MOTION_NOTIFY:
1285       return event->motion.device;
1286     case GDK_BUTTON_PRESS:
1287     case GDK_2BUTTON_PRESS:
1288     case GDK_3BUTTON_PRESS:
1289     case GDK_BUTTON_RELEASE:
1290       return event->button.device;
1291     case GDK_SCROLL:
1292       return event->scroll.device;
1293     case GDK_PROXIMITY_IN:
1294     case GDK_PROXIMITY_OUT:
1295       return event->proximity.device;
1296     default:
1297       break;
1298     }
1299
1300   /* Fallback if event has no device set */
1301   switch (event->type)
1302     {
1303     case GDK_MOTION_NOTIFY:
1304     case GDK_BUTTON_PRESS:
1305     case GDK_2BUTTON_PRESS:
1306     case GDK_3BUTTON_PRESS:
1307     case GDK_BUTTON_RELEASE:
1308     case GDK_ENTER_NOTIFY:
1309     case GDK_LEAVE_NOTIFY:
1310     case GDK_FOCUS_CHANGE:
1311     case GDK_PROXIMITY_IN:
1312     case GDK_PROXIMITY_OUT:
1313     case GDK_DRAG_ENTER:
1314     case GDK_DRAG_LEAVE:
1315     case GDK_DRAG_MOTION:
1316     case GDK_DRAG_STATUS:
1317     case GDK_DROP_START:
1318     case GDK_DROP_FINISHED:
1319     case GDK_SCROLL:
1320     case GDK_GRAB_BROKEN:
1321     case GDK_KEY_PRESS:
1322     case GDK_KEY_RELEASE:
1323       {
1324         GdkDisplay *display;
1325         GdkDeviceManager *device_manager;
1326         GdkDevice *client_pointer;
1327
1328         g_warning ("Event with type %d not holding a GdkDevice. "
1329                    "It is most likely synthesized outside Gdk/GTK+\n",
1330                    event->type);
1331
1332         display = gdk_window_get_display (event->any.window);
1333         device_manager = gdk_display_get_device_manager (display);
1334         client_pointer = gdk_device_manager_get_client_pointer (device_manager);
1335
1336         if (event->type == GDK_KEY_PRESS ||
1337             event->type == GDK_KEY_RELEASE)
1338           return gdk_device_get_associated_device (client_pointer);
1339         else
1340           return client_pointer;
1341       }
1342       break;
1343     default:
1344       return NULL;
1345     }
1346 }
1347
1348 /**
1349  * gdk_event_set_source_device:
1350  * @event: a #GdkEvent
1351  * @device: a #GdkDevice
1352  *
1353  * Sets the slave device for @event to @device.
1354  *
1355  * The event must have been allocated by GTK+,
1356  * for instance by gdk_event_copy().
1357  *
1358  * Since: 3.0
1359  **/
1360 void
1361 gdk_event_set_source_device (GdkEvent  *event,
1362                              GdkDevice *device)
1363 {
1364   GdkEventPrivate *private;
1365
1366   g_return_if_fail (gdk_event_is_allocated (event));
1367   g_return_if_fail (GDK_IS_DEVICE (device));
1368
1369   private = (GdkEventPrivate *) event;
1370
1371   private->source_device = device;
1372 }
1373
1374 /**
1375  * gdk_event_get_source_device:
1376  * @event: a #GdkEvent
1377  *
1378  * This function returns the hardware (slave) #GdkDevice that has
1379  * triggered the event, falling back to the virtual (master) device
1380  * (as in gdk_event_get_device()) if the event wasn't caused by
1381  * interaction with a hardware device. This may happen for example
1382  * in synthesized crossing events after a #GdkWindow updates its
1383  * geometry or a grab is acquired/released.
1384  *
1385  * If the event does not contain a device field, this function will
1386  * return %NULL.
1387  *
1388  * Returns: (transfer none): a #GdkDevice, or %NULL.
1389  *
1390  * Since: 3.0
1391  **/
1392 GdkDevice *
1393 gdk_event_get_source_device (const GdkEvent *event)
1394 {
1395   GdkEventPrivate *private;
1396
1397   g_return_val_if_fail (event != NULL, NULL);
1398
1399   if (!gdk_event_is_allocated (event))
1400     return NULL;
1401
1402   private = (GdkEventPrivate *) event;
1403
1404   if (private->source_device)
1405     return private->source_device;
1406
1407   /* Fallback to event device */
1408   return gdk_event_get_device (event);
1409 }
1410
1411 /**
1412  * gdk_event_request_motions:
1413  * @event: a valid #GdkEvent
1414  *
1415  * Request more motion notifies if @event is a motion notify hint event.
1416  *
1417  * This function should be used instead of gdk_window_get_pointer() to
1418  * request further motion notifies, because it also works for extension
1419  * events where motion notifies are provided for devices other than the
1420  * core pointer. Coordinate extraction, processing and requesting more
1421  * motion events from a %GDK_MOTION_NOTIFY event usually works like this:
1422  *
1423  * |[
1424  * {
1425  *   /&ast; motion_event handler &ast;/
1426  *   x = motion_event->x;
1427  *   y = motion_event->y;
1428  *   /&ast; handle (x,y) motion &ast;/
1429  *   gdk_event_request_motions (motion_event); /&ast; handles is_hint events &ast;/
1430  * }
1431  * ]|
1432  *
1433  * Since: 2.12
1434  **/
1435 void
1436 gdk_event_request_motions (const GdkEventMotion *event)
1437 {
1438   GdkDisplay *display;
1439   
1440   g_return_if_fail (event != NULL);
1441   
1442   if (event->type == GDK_MOTION_NOTIFY && event->is_hint)
1443     {
1444       gdk_device_get_state (event->device, event->window, NULL, NULL);
1445       
1446       display = gdk_window_get_display (event->window);
1447       _gdk_display_enable_motion_hints (display, event->device);
1448     }
1449 }
1450
1451 static gboolean
1452 gdk_events_get_axis_distances (GdkEvent *event1,
1453                                GdkEvent *event2,
1454                                gdouble  *x_distance,
1455                                gdouble  *y_distance,
1456                                gdouble  *distance)
1457 {
1458   gdouble x1, x2, y1, y2;
1459   gdouble xd, yd;
1460
1461   if (!gdk_event_get_coords (event1, &x1, &y1) ||
1462       !gdk_event_get_coords (event2, &x2, &y2))
1463     return FALSE;
1464
1465   xd = x2 - x1;
1466   yd = y2 - y1;
1467
1468   if (x_distance)
1469     *x_distance = xd;
1470
1471   if (y_distance)
1472     *y_distance = yd;
1473
1474   if (distance)
1475     *distance = sqrt ((xd * xd) + (yd * yd));
1476
1477   return TRUE;
1478 }
1479
1480 /**
1481  * gdk_events_get_distance:
1482  * @event1: first #GdkEvent
1483  * @event2: second #GdkEvent
1484  * @distance: (out): return location for the distance
1485  *
1486  * If both events have X/Y information, the distance between both coordinates
1487  * (as in a straight line going from @event1 to @event2) will be returned.
1488  *
1489  * Returns: %TRUE if the distance could be calculated.
1490  *
1491  * Since: 3.0
1492  **/
1493 gboolean
1494 gdk_events_get_distance (GdkEvent *event1,
1495                          GdkEvent *event2,
1496                          gdouble  *distance)
1497 {
1498   return gdk_events_get_axis_distances (event1, event2,
1499                                         NULL, NULL,
1500                                         distance);
1501 }
1502
1503 /**
1504  * gdk_events_get_angle:
1505  * @event1: first #GdkEvent
1506  * @event2: second #GdkEvent
1507  * @angle: (out): return location for the relative angle between both events
1508  *
1509  * If both events contain X/Y information, this function will return %TRUE
1510  * and return in @angle the relative angle from @event1 to @event2. The rotation
1511  * direction for positive angles is from the positive X axis towards the positive
1512  * Y axis.
1513  *
1514  * Returns: %TRUE if the angle could be calculated.
1515  *
1516  * Since: 3.0
1517  **/
1518 gboolean
1519 gdk_events_get_angle (GdkEvent *event1,
1520                       GdkEvent *event2,
1521                       gdouble  *angle)
1522 {
1523   gdouble x_distance, y_distance, distance;
1524
1525   if (!gdk_events_get_axis_distances (event1, event2,
1526                                       &x_distance, &y_distance,
1527                                       &distance))
1528     return FALSE;
1529
1530   if (angle)
1531     {
1532       *angle = atan2 (x_distance, y_distance);
1533
1534       /* Invert angle */
1535       *angle = (2 * G_PI) - *angle;
1536
1537       /* Shift it 90° */
1538       *angle += G_PI / 2;
1539
1540       /* And constraint it to 0°-360° */
1541       *angle = fmod (*angle, 2 * G_PI);
1542     }
1543
1544   return TRUE;
1545 }
1546
1547 /**
1548  * gdk_events_get_center:
1549  * @event1: first #GdkEvent
1550  * @event2: second #GdkEvent
1551  * @x: (out): return location for the X coordinate of the center
1552  * @y: (out): return location for the Y coordinate of the center
1553  *
1554  * If both events contain X/Y information, the center of both coordinates
1555  * will be returned in @x and @y.
1556  *
1557  * Returns: %TRUE if the center could be calculated.
1558  *
1559  * Since: 3.0
1560  **/
1561 gboolean
1562 gdk_events_get_center (GdkEvent *event1,
1563                        GdkEvent *event2,
1564                        gdouble  *x,
1565                        gdouble  *y)
1566 {
1567   gdouble x1, x2, y1, y2;
1568
1569   if (!gdk_event_get_coords (event1, &x1, &y1) ||
1570       !gdk_event_get_coords (event2, &x2, &y2))
1571     return FALSE;
1572
1573   if (x)
1574     *x = (x2 + x1) / 2;
1575
1576   if (y)
1577     *y = (y2 + y1) / 2;
1578
1579   return TRUE;
1580 }
1581
1582 /**
1583  * gdk_event_set_screen:
1584  * @event: a #GdkEvent
1585  * @screen: a #GdkScreen
1586  * 
1587  * Sets the screen for @event to @screen. The event must
1588  * have been allocated by GTK+, for instance, by
1589  * gdk_event_copy().
1590  *
1591  * Since: 2.2
1592  **/
1593 void
1594 gdk_event_set_screen (GdkEvent  *event,
1595                       GdkScreen *screen)
1596 {
1597   GdkEventPrivate *private;
1598   
1599   g_return_if_fail (gdk_event_is_allocated (event));
1600
1601   private = (GdkEventPrivate *)event;
1602   
1603   private->screen = screen;
1604 }
1605
1606 /**
1607  * gdk_event_get_screen:
1608  * @event: a #GdkEvent
1609  * 
1610  * Returns the screen for the event. The screen is
1611  * typically the screen for <literal>event->any.window</literal>, but
1612  * for events such as mouse events, it is the screen
1613  * where the pointer was when the event occurs -
1614  * that is, the screen which has the root window 
1615  * to which <literal>event->motion.x_root</literal> and
1616  * <literal>event->motion.y_root</literal> are relative.
1617  * 
1618  * Return value: (transfer none): the screen for the event
1619  *
1620  * Since: 2.2
1621  **/
1622 GdkScreen *
1623 gdk_event_get_screen (const GdkEvent *event)
1624 {
1625   if (gdk_event_is_allocated (event))
1626     {
1627       GdkEventPrivate *private = (GdkEventPrivate *)event;
1628
1629       if (private->screen)
1630         return private->screen;
1631     }
1632
1633   if (event->any.window)
1634     return gdk_window_get_screen (event->any.window);
1635
1636   return NULL;
1637 }
1638
1639 /**
1640  * gdk_set_show_events:
1641  * @show_events:  %TRUE to output event debugging information.
1642  * 
1643  * Sets whether a trace of received events is output.
1644  * Note that GTK+ must be compiled with debugging (that is,
1645  * configured using the <option>--enable-debug</option> option)
1646  * to use this option.
1647  **/
1648 void
1649 gdk_set_show_events (gboolean show_events)
1650 {
1651   if (show_events)
1652     _gdk_debug_flags |= GDK_DEBUG_EVENTS;
1653   else
1654     _gdk_debug_flags &= ~GDK_DEBUG_EVENTS;
1655 }
1656
1657 /**
1658  * gdk_get_show_events:
1659  * 
1660  * Gets whether event debugging output is enabled.
1661  * 
1662  * Return value: %TRUE if event debugging output is enabled.
1663  **/
1664 gboolean
1665 gdk_get_show_events (void)
1666 {
1667   return (_gdk_debug_flags & GDK_DEBUG_EVENTS) != 0;
1668 }
1669
1670 /* What do we do with G_IO_NVAL?
1671  */
1672 #define READ_CONDITION (G_IO_IN | G_IO_HUP | G_IO_ERR)
1673 #define WRITE_CONDITION (G_IO_OUT | G_IO_ERR)
1674 #define EXCEPTION_CONDITION (G_IO_PRI)
1675
1676 static void
1677 gdk_synthesize_click (GdkDisplay *display,
1678                       GdkEvent   *event,
1679                       gint        nclicks)
1680 {
1681   GdkEvent *event_copy;
1682
1683   event_copy = gdk_event_copy (event);
1684   event_copy->type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
1685
1686   _gdk_event_queue_append (display, event_copy);
1687 }
1688
1689 void
1690 _gdk_event_button_generate (GdkDisplay *display,
1691                             GdkEvent   *event)
1692 {
1693   GdkMultipleClickInfo *info;
1694
1695   g_return_if_fail (event->type == GDK_BUTTON_PRESS);
1696
1697   info = g_hash_table_lookup (display->multiple_click_info, event->button.device);
1698
1699   if (G_UNLIKELY (!info))
1700     {
1701       info = g_new0 (GdkMultipleClickInfo, 1);
1702       info->button_number[0] = info->button_number[1] = -1;
1703
1704       g_hash_table_insert (display->multiple_click_info,
1705                            event->button.device, info);
1706     }
1707
1708   if ((event->button.time < (info->button_click_time[1] + 2 * display->double_click_time)) &&
1709       (event->button.window == info->button_window[1]) &&
1710       (event->button.button == info->button_number[1]) &&
1711       (ABS (event->button.x - info->button_x[1]) <= display->double_click_distance) &&
1712       (ABS (event->button.y - info->button_y[1]) <= display->double_click_distance))
1713     {
1714       gdk_synthesize_click (display, event, 3);
1715
1716       info->button_click_time[1] = 0;
1717       info->button_click_time[0] = 0;
1718       info->button_window[1] = NULL;
1719       info->button_window[0] = NULL;
1720       info->button_number[1] = -1;
1721       info->button_number[0] = -1;
1722       info->button_x[0] = info->button_x[1] = 0;
1723       info->button_y[0] = info->button_y[1] = 0;
1724     }
1725   else if ((event->button.time < (info->button_click_time[0] + display->double_click_time)) &&
1726            (event->button.window == info->button_window[0]) &&
1727            (event->button.button == info->button_number[0]) &&
1728            (ABS (event->button.x - info->button_x[0]) <= display->double_click_distance) &&
1729            (ABS (event->button.y - info->button_y[0]) <= display->double_click_distance))
1730     {
1731       gdk_synthesize_click (display, event, 2);
1732       
1733       info->button_click_time[1] = info->button_click_time[0];
1734       info->button_click_time[0] = event->button.time;
1735       info->button_window[1] = info->button_window[0];
1736       info->button_window[0] = event->button.window;
1737       info->button_number[1] = info->button_number[0];
1738       info->button_number[0] = event->button.button;
1739       info->button_x[1] = info->button_x[0];
1740       info->button_x[0] = event->button.x;
1741       info->button_y[1] = info->button_y[0];
1742       info->button_y[0] = event->button.y;
1743     }
1744   else
1745     {
1746       info->button_click_time[1] = 0;
1747       info->button_click_time[0] = event->button.time;
1748       info->button_window[1] = NULL;
1749       info->button_window[0] = event->button.window;
1750       info->button_number[1] = -1;
1751       info->button_number[0] = event->button.button;
1752       info->button_x[1] = 0;
1753       info->button_x[0] = event->button.x;
1754       info->button_y[1] = 0;
1755       info->button_y[0] = event->button.y;
1756     }
1757 }
1758
1759 void
1760 gdk_synthesize_window_state (GdkWindow     *window,
1761                              GdkWindowState unset_flags,
1762                              GdkWindowState set_flags)
1763 {
1764   GdkEvent temp_event;
1765   GdkWindowState old;
1766   
1767   g_return_if_fail (window != NULL);
1768   
1769   temp_event.window_state.window = window;
1770   temp_event.window_state.type = GDK_WINDOW_STATE;
1771   temp_event.window_state.send_event = FALSE;
1772   
1773   old = temp_event.window_state.window->state;
1774   
1775   temp_event.window_state.new_window_state = old;
1776   temp_event.window_state.new_window_state |= set_flags;
1777   temp_event.window_state.new_window_state &= ~unset_flags;
1778   temp_event.window_state.changed_mask = temp_event.window_state.new_window_state ^ old;
1779
1780   if (temp_event.window_state.new_window_state == old)
1781     return; /* No actual work to do, nothing changed. */
1782
1783   /* Actually update the field in GdkWindow, this is sort of an odd
1784    * place to do it, but seems like the safest since it ensures we expose no
1785    * inconsistent state to the user.
1786    */
1787   
1788   window->state = temp_event.window_state.new_window_state;
1789
1790   if (temp_event.window_state.changed_mask & GDK_WINDOW_STATE_WITHDRAWN)
1791     _gdk_window_update_viewable (window);
1792
1793   /* We only really send the event to toplevels, since
1794    * all the window states don't apply to non-toplevels.
1795    * Non-toplevels do use the GDK_WINDOW_STATE_WITHDRAWN flag
1796    * internally so we needed to update window->state.
1797    */
1798   switch (window->window_type)
1799     {
1800     case GDK_WINDOW_TOPLEVEL:
1801     case GDK_WINDOW_TEMP: /* ? */
1802       gdk_display_put_event (gdk_window_get_display (window), &temp_event);
1803       break;
1804       
1805     case GDK_WINDOW_FOREIGN:
1806     case GDK_WINDOW_ROOT:
1807     case GDK_WINDOW_CHILD:
1808       break;
1809     }
1810 }
1811
1812 /**
1813  * gdk_display_set_double_click_time:
1814  * @display: a #GdkDisplay
1815  * @msec: double click time in milliseconds (thousandths of a second) 
1816  * 
1817  * Sets the double click time (two clicks within this time interval
1818  * count as a double click and result in a #GDK_2BUTTON_PRESS event).
1819  * Applications should <emphasis>not</emphasis> set this, it is a global 
1820  * user-configured setting.
1821  *
1822  * Since: 2.2
1823  **/
1824 void
1825 gdk_display_set_double_click_time (GdkDisplay *display,
1826                                    guint       msec)
1827 {
1828   display->double_click_time = msec;
1829 }
1830
1831 /**
1832  * gdk_set_double_click_time:
1833  * @msec: double click time in milliseconds (thousandths of a second)
1834  *
1835  * Set the double click time for the default display. See
1836  * gdk_display_set_double_click_time(). 
1837  * See also gdk_display_set_double_click_distance().
1838  * Applications should <emphasis>not</emphasis> set this, it is a 
1839  * global user-configured setting.
1840  **/
1841 void
1842 gdk_set_double_click_time (guint msec)
1843 {
1844   gdk_display_set_double_click_time (gdk_display_get_default (), msec);
1845 }
1846
1847 /**
1848  * gdk_display_set_double_click_distance:
1849  * @display: a #GdkDisplay
1850  * @distance: distance in pixels
1851  * 
1852  * Sets the double click distance (two clicks within this distance
1853  * count as a double click and result in a #GDK_2BUTTON_PRESS event).
1854  * See also gdk_display_set_double_click_time().
1855  * Applications should <emphasis>not</emphasis> set this, it is a global 
1856  * user-configured setting.
1857  *
1858  * Since: 2.4
1859  **/
1860 void
1861 gdk_display_set_double_click_distance (GdkDisplay *display,
1862                                        guint       distance)
1863 {
1864   display->double_click_distance = distance;
1865 }
1866
1867 G_DEFINE_BOXED_TYPE (GdkEvent, gdk_event,
1868                      gdk_event_copy,
1869                      gdk_event_free)
1870
1871 /**
1872  * gdk_setting_get:
1873  * @name: the name of the setting.
1874  * @value: location to store the value of the setting.
1875  *
1876  * Obtains a desktop-wide setting, such as the double-click time,
1877  * for the default screen. See gdk_screen_get_setting().
1878  *
1879  * Returns: %TRUE if the setting existed and a value was stored
1880  *   in @value, %FALSE otherwise.
1881  **/
1882 gboolean
1883 gdk_setting_get (const gchar *name,
1884                  GValue      *value)
1885 {
1886   return gdk_screen_get_setting (gdk_screen_get_default (), name, value);
1887 }