]> Pileus Git - ~andy/gtk/blob - gdk/gdkevents.c
Work around issues with events without screens
[~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     }
523   
524   switch (event->any.type)
525     {
526     case GDK_KEY_PRESS:
527     case GDK_KEY_RELEASE:
528       new_event->key.string = g_strdup (event->key.string);
529       break;
530       
531     case GDK_ENTER_NOTIFY:
532     case GDK_LEAVE_NOTIFY:
533       if (event->crossing.subwindow != NULL)
534         g_object_ref (event->crossing.subwindow);
535       break;
536       
537     case GDK_DRAG_ENTER:
538     case GDK_DRAG_LEAVE:
539     case GDK_DRAG_MOTION:
540     case GDK_DRAG_STATUS:
541     case GDK_DROP_START:
542     case GDK_DROP_FINISHED:
543       g_object_ref (event->dnd.context);
544       break;
545       
546     case GDK_EXPOSE:
547     case GDK_DAMAGE:
548       if (event->expose.region)
549         new_event->expose.region = cairo_region_copy (event->expose.region);
550       break;
551       
552     case GDK_SETTING:
553       new_event->setting.name = g_strdup (new_event->setting.name);
554       break;
555
556     case GDK_BUTTON_PRESS:
557     case GDK_BUTTON_RELEASE:
558       if (event->button.axes) 
559         new_event->button.axes = g_memdup (event->button.axes,
560                                            sizeof (gdouble) * gdk_device_get_n_axes (event->button.device));
561       break;
562
563     case GDK_MOTION_NOTIFY:
564       if (event->motion.axes) 
565         new_event->motion.axes = g_memdup (event->motion.axes,
566                                            sizeof (gdouble) * gdk_device_get_n_axes (event->motion.device));
567       break;
568
569     default:
570       break;
571     }
572
573   if (gdk_event_is_allocated (event))
574     _gdk_display_event_data_copy (gdk_display_get_default (), event, new_event);
575
576   return new_event;
577 }
578
579 /**
580  * gdk_event_free:
581  * @event:  a #GdkEvent.
582  * 
583  * Frees a #GdkEvent, freeing or decrementing any resources associated with it.
584  * Note that this function should only be called with events returned from
585  * functions such as gdk_event_peek(), gdk_event_get(), gdk_event_copy()
586  * and gdk_event_new().
587  **/
588 void
589 gdk_event_free (GdkEvent *event)
590 {
591   g_return_if_fail (event != NULL);
592
593   if (event->any.window)
594     g_object_unref (event->any.window);
595   
596   switch (event->any.type)
597     {
598     case GDK_KEY_PRESS:
599     case GDK_KEY_RELEASE:
600       g_free (event->key.string);
601       break;
602       
603     case GDK_ENTER_NOTIFY:
604     case GDK_LEAVE_NOTIFY:
605       if (event->crossing.subwindow != NULL)
606         g_object_unref (event->crossing.subwindow);
607       break;
608       
609     case GDK_DRAG_ENTER:
610     case GDK_DRAG_LEAVE:
611     case GDK_DRAG_MOTION:
612     case GDK_DRAG_STATUS:
613     case GDK_DROP_START:
614     case GDK_DROP_FINISHED:
615       if (event->dnd.context != NULL)
616         g_object_unref (event->dnd.context);
617       break;
618
619     case GDK_BUTTON_PRESS:
620     case GDK_BUTTON_RELEASE:
621       g_free (event->button.axes);
622       break;
623       
624     case GDK_EXPOSE:
625     case GDK_DAMAGE:
626       if (event->expose.region)
627         cairo_region_destroy (event->expose.region);
628       break;
629       
630     case GDK_MOTION_NOTIFY:
631       g_free (event->motion.axes);
632       break;
633       
634     case GDK_SETTING:
635       g_free (event->setting.name);
636       break;
637       
638     default:
639       break;
640     }
641
642   _gdk_display_event_data_free (gdk_display_get_default (), event);
643
644   g_hash_table_remove (event_hash, event);
645   g_slice_free (GdkEventPrivate, (GdkEventPrivate*) event);
646 }
647
648 /**
649  * gdk_event_get_time:
650  * @event: a #GdkEvent
651  * 
652  * Returns the time stamp from @event, if there is one; otherwise
653  * returns #GDK_CURRENT_TIME. If @event is %NULL, returns #GDK_CURRENT_TIME.
654  * 
655  * Return value: time stamp field from @event
656  **/
657 guint32
658 gdk_event_get_time (const GdkEvent *event)
659 {
660   if (event)
661     switch (event->type)
662       {
663       case GDK_MOTION_NOTIFY:
664         return event->motion.time;
665       case GDK_BUTTON_PRESS:
666       case GDK_2BUTTON_PRESS:
667       case GDK_3BUTTON_PRESS:
668       case GDK_BUTTON_RELEASE:
669         return event->button.time;
670       case GDK_SCROLL:
671         return event->scroll.time;
672       case GDK_KEY_PRESS:
673       case GDK_KEY_RELEASE:
674         return event->key.time;
675       case GDK_ENTER_NOTIFY:
676       case GDK_LEAVE_NOTIFY:
677         return event->crossing.time;
678       case GDK_PROPERTY_NOTIFY:
679         return event->property.time;
680       case GDK_SELECTION_CLEAR:
681       case GDK_SELECTION_REQUEST:
682       case GDK_SELECTION_NOTIFY:
683         return event->selection.time;
684       case GDK_PROXIMITY_IN:
685       case GDK_PROXIMITY_OUT:
686         return event->proximity.time;
687       case GDK_DRAG_ENTER:
688       case GDK_DRAG_LEAVE:
689       case GDK_DRAG_MOTION:
690       case GDK_DRAG_STATUS:
691       case GDK_DROP_START:
692       case GDK_DROP_FINISHED:
693         return event->dnd.time;
694       case GDK_CLIENT_EVENT:
695       case GDK_VISIBILITY_NOTIFY:
696       case GDK_CONFIGURE:
697       case GDK_FOCUS_CHANGE:
698       case GDK_NOTHING:
699       case GDK_DAMAGE:
700       case GDK_DELETE:
701       case GDK_DESTROY:
702       case GDK_EXPOSE:
703       case GDK_MAP:
704       case GDK_UNMAP:
705       case GDK_WINDOW_STATE:
706       case GDK_SETTING:
707       case GDK_OWNER_CHANGE:
708       case GDK_GRAB_BROKEN:
709       case GDK_EVENT_LAST:
710         /* return current time */
711         break;
712       }
713   
714   return GDK_CURRENT_TIME;
715 }
716
717 /**
718  * gdk_event_get_state:
719  * @event: a #GdkEvent or NULL
720  * @state: (out): return location for state
721  * 
722  * If the event contains a "state" field, puts that field in @state. Otherwise
723  * stores an empty state (0). Returns %TRUE if there was a state field
724  * in the event. @event may be %NULL, in which case it's treated
725  * as if the event had no state field.
726  * 
727  * Return value: %TRUE if there was a state field in the event 
728  **/
729 gboolean
730 gdk_event_get_state (const GdkEvent        *event,
731                      GdkModifierType       *state)
732 {
733   g_return_val_if_fail (state != NULL, FALSE);
734   
735   if (event)
736     switch (event->type)
737       {
738       case GDK_MOTION_NOTIFY:
739         *state = event->motion.state;
740         return TRUE;
741       case GDK_BUTTON_PRESS:
742       case GDK_2BUTTON_PRESS:
743       case GDK_3BUTTON_PRESS:
744       case GDK_BUTTON_RELEASE:
745         *state =  event->button.state;
746         return TRUE;
747       case GDK_SCROLL:
748         *state =  event->scroll.state;
749         return TRUE;
750       case GDK_KEY_PRESS:
751       case GDK_KEY_RELEASE:
752         *state =  event->key.state;
753         return TRUE;
754       case GDK_ENTER_NOTIFY:
755       case GDK_LEAVE_NOTIFY:
756         *state =  event->crossing.state;
757         return TRUE;
758       case GDK_PROPERTY_NOTIFY:
759         *state =  event->property.state;
760         return TRUE;
761       case GDK_VISIBILITY_NOTIFY:
762       case GDK_CLIENT_EVENT:
763       case GDK_CONFIGURE:
764       case GDK_FOCUS_CHANGE:
765       case GDK_SELECTION_CLEAR:
766       case GDK_SELECTION_REQUEST:
767       case GDK_SELECTION_NOTIFY:
768       case GDK_PROXIMITY_IN:
769       case GDK_PROXIMITY_OUT:
770       case GDK_DAMAGE:
771       case GDK_DRAG_ENTER:
772       case GDK_DRAG_LEAVE:
773       case GDK_DRAG_MOTION:
774       case GDK_DRAG_STATUS:
775       case GDK_DROP_START:
776       case GDK_DROP_FINISHED:
777       case GDK_NOTHING:
778       case GDK_DELETE:
779       case GDK_DESTROY:
780       case GDK_EXPOSE:
781       case GDK_MAP:
782       case GDK_UNMAP:
783       case GDK_WINDOW_STATE:
784       case GDK_SETTING:
785       case GDK_OWNER_CHANGE:
786       case GDK_GRAB_BROKEN:
787       case GDK_EVENT_LAST:
788         /* no state field */
789         break;
790       }
791
792   *state = 0;
793   return FALSE;
794 }
795
796 /**
797  * gdk_event_get_coords:
798  * @event: a #GdkEvent
799  * @x_win: (out): location to put event window x coordinate
800  * @y_win: (out): location to put event window y coordinate
801  * 
802  * Extract the event window relative x/y coordinates from an event.
803  * 
804  * Return value: %TRUE if the event delivered event window coordinates
805  **/
806 gboolean
807 gdk_event_get_coords (const GdkEvent *event,
808                       gdouble        *x_win,
809                       gdouble        *y_win)
810 {
811   gdouble x = 0, y = 0;
812   gboolean fetched = TRUE;
813   
814   g_return_val_if_fail (event != NULL, FALSE);
815
816   switch (event->type)
817     {
818     case GDK_CONFIGURE:
819       x = event->configure.x;
820       y = event->configure.y;
821       break;
822     case GDK_ENTER_NOTIFY:
823     case GDK_LEAVE_NOTIFY:
824       x = event->crossing.x;
825       y = event->crossing.y;
826       break;
827     case GDK_SCROLL:
828       x = event->scroll.x;
829       y = event->scroll.y;
830       break;
831     case GDK_BUTTON_PRESS:
832     case GDK_2BUTTON_PRESS:
833     case GDK_3BUTTON_PRESS:
834     case GDK_BUTTON_RELEASE:
835       x = event->button.x;
836       y = event->button.y;
837       break;
838     case GDK_MOTION_NOTIFY:
839       x = event->motion.x;
840       y = event->motion.y;
841       break;
842     default:
843       fetched = FALSE;
844       break;
845     }
846
847   if (x_win)
848     *x_win = x;
849   if (y_win)
850     *y_win = y;
851
852   return fetched;
853 }
854
855 /**
856  * gdk_event_get_root_coords:
857  * @event: a #GdkEvent
858  * @x_root: (out): location to put root window x coordinate
859  * @y_root: (out): location to put root window y coordinate
860  * 
861  * Extract the root window relative x/y coordinates from an event.
862  * 
863  * Return value: %TRUE if the event delivered root window coordinates
864  **/
865 gboolean
866 gdk_event_get_root_coords (const GdkEvent *event,
867                            gdouble        *x_root,
868                            gdouble        *y_root)
869 {
870   gdouble x = 0, y = 0;
871   gboolean fetched = TRUE;
872   
873   g_return_val_if_fail (event != NULL, FALSE);
874
875   switch (event->type)
876     {
877     case GDK_MOTION_NOTIFY:
878       x = event->motion.x_root;
879       y = event->motion.y_root;
880       break;
881     case GDK_SCROLL:
882       x = event->scroll.x_root;
883       y = event->scroll.y_root;
884       break;
885     case GDK_BUTTON_PRESS:
886     case GDK_2BUTTON_PRESS:
887     case GDK_3BUTTON_PRESS:
888     case GDK_BUTTON_RELEASE:
889       x = event->button.x_root;
890       y = event->button.y_root;
891       break;
892     case GDK_ENTER_NOTIFY:
893     case GDK_LEAVE_NOTIFY:
894       x = event->crossing.x_root;
895       y = event->crossing.y_root;
896       break;
897     case GDK_DRAG_ENTER:
898     case GDK_DRAG_LEAVE:
899     case GDK_DRAG_MOTION:
900     case GDK_DRAG_STATUS:
901     case GDK_DROP_START:
902     case GDK_DROP_FINISHED:
903       x = event->dnd.x_root;
904       y = event->dnd.y_root;
905       break;
906     default:
907       fetched = FALSE;
908       break;
909     }
910
911   if (x_root)
912     *x_root = x;
913   if (y_root)
914     *y_root = y;
915
916   return fetched;
917 }
918
919 /**
920  * gdk_event_get_axis:
921  * @event: a #GdkEvent
922  * @axis_use: (out): the axis use to look for
923  * @value: (out): location to store the value found
924  * 
925  * Extract the axis value for a particular axis use from
926  * an event structure.
927  * 
928  * Return value: %TRUE if the specified axis was found, otherwise %FALSE
929  **/
930 gboolean
931 gdk_event_get_axis (const GdkEvent *event,
932                     GdkAxisUse      axis_use,
933                     gdouble        *value)
934 {
935   gdouble *axes;
936   GdkDevice *device;
937   
938   g_return_val_if_fail (event != NULL, FALSE);
939   
940   if (axis_use == GDK_AXIS_X || axis_use == GDK_AXIS_Y)
941     {
942       gdouble x, y;
943       
944       switch (event->type)
945         {
946         case GDK_MOTION_NOTIFY:
947           x = event->motion.x;
948           y = event->motion.y;
949           break;
950         case GDK_SCROLL:
951           x = event->scroll.x;
952           y = event->scroll.y;
953           break;
954         case GDK_BUTTON_PRESS:
955         case GDK_BUTTON_RELEASE:
956           x = event->button.x;
957           y = event->button.y;
958           break;
959         case GDK_ENTER_NOTIFY:
960         case GDK_LEAVE_NOTIFY:
961           x = event->crossing.x;
962           y = event->crossing.y;
963           break;
964           
965         default:
966           return FALSE;
967         }
968
969       if (axis_use == GDK_AXIS_X && value)
970         *value = x;
971       if (axis_use == GDK_AXIS_Y && value)
972         *value = y;
973
974       return TRUE;
975     }
976   else if (event->type == GDK_BUTTON_PRESS ||
977            event->type == GDK_BUTTON_RELEASE)
978     {
979       device = event->button.device;
980       axes = event->button.axes;
981     }
982   else if (event->type == GDK_MOTION_NOTIFY)
983     {
984       device = event->motion.device;
985       axes = event->motion.axes;
986     }
987   else
988     return FALSE;
989
990   return gdk_device_get_axis (device, axes, axis_use, value);
991 }
992
993 /**
994  * gdk_event_set_device:
995  * @event: a #GdkEvent
996  * @device: a #GdkDevice
997  *
998  * Sets the device for @event to @device. The event must
999  * have been allocated by GTK+, for instance, by
1000  * gdk_event_copy().
1001  *
1002  * Since: 3.0
1003  **/
1004 void
1005 gdk_event_set_device (GdkEvent  *event,
1006                       GdkDevice *device)
1007 {
1008   GdkEventPrivate *private;
1009
1010   g_return_if_fail (gdk_event_is_allocated (event));
1011
1012   private = (GdkEventPrivate *) event;
1013
1014   private->device = device;
1015
1016   switch (event->type)
1017     {
1018     case GDK_MOTION_NOTIFY:
1019       event->motion.device = device;
1020       break;
1021     case GDK_BUTTON_PRESS:
1022     case GDK_2BUTTON_PRESS:
1023     case GDK_3BUTTON_PRESS:
1024     case GDK_BUTTON_RELEASE:
1025       event->button.device = device;
1026       break;
1027     case GDK_SCROLL:
1028       event->scroll.device = device;
1029       break;
1030     case GDK_PROXIMITY_IN:
1031     case GDK_PROXIMITY_OUT:
1032       event->proximity.device = device;
1033       break;
1034     default:
1035       break;
1036     }
1037 }
1038
1039 /**
1040  * gdk_event_get_device:
1041  * @event: a #GdkEvent.
1042  *
1043  * If the event contains a "device" field, this function will return
1044  * it, else it will return %NULL.
1045  *
1046  * Returns: (transfer none): a #GdkDevice, or %NULL.
1047  *
1048  * Since: 3.0
1049  **/
1050 GdkDevice *
1051 gdk_event_get_device (const GdkEvent *event)
1052 {
1053   g_return_val_if_fail (event != NULL, NULL);
1054
1055   if (gdk_event_is_allocated (event))
1056     {
1057       GdkEventPrivate *private = (GdkEventPrivate *) event;
1058
1059       if (private->device)
1060         return private->device;
1061     }
1062
1063   switch (event->type)
1064     {
1065     case GDK_MOTION_NOTIFY:
1066       return event->motion.device;
1067     case GDK_BUTTON_PRESS:
1068     case GDK_2BUTTON_PRESS:
1069     case GDK_3BUTTON_PRESS:
1070     case GDK_BUTTON_RELEASE:
1071       return event->button.device;
1072     case GDK_SCROLL:
1073       return event->scroll.device;
1074     case GDK_PROXIMITY_IN:
1075     case GDK_PROXIMITY_OUT:
1076       return event->proximity.device;
1077     default:
1078       break;
1079     }
1080
1081   /* Fallback if event has no device set */
1082   switch (event->type)
1083     {
1084     case GDK_MOTION_NOTIFY:
1085     case GDK_BUTTON_PRESS:
1086     case GDK_2BUTTON_PRESS:
1087     case GDK_3BUTTON_PRESS:
1088     case GDK_BUTTON_RELEASE:
1089     case GDK_ENTER_NOTIFY:
1090     case GDK_LEAVE_NOTIFY:
1091     case GDK_FOCUS_CHANGE:
1092     case GDK_PROXIMITY_IN:
1093     case GDK_PROXIMITY_OUT:
1094     case GDK_DRAG_ENTER:
1095     case GDK_DRAG_LEAVE:
1096     case GDK_DRAG_MOTION:
1097     case GDK_DRAG_STATUS:
1098     case GDK_DROP_START:
1099     case GDK_DROP_FINISHED:
1100     case GDK_SCROLL:
1101     case GDK_GRAB_BROKEN:
1102     case GDK_KEY_PRESS:
1103     case GDK_KEY_RELEASE:
1104       {
1105         GdkDisplay *display;
1106         GdkDeviceManager *device_manager;
1107         GdkDevice *client_pointer;
1108
1109         g_warning ("Event with type %d not holding a GdkDevice. "
1110                    "It is most likely synthesized outside Gdk/GTK+\n",
1111                    event->type);
1112
1113         display = gdk_window_get_display (event->any.window);
1114         device_manager = gdk_display_get_device_manager (display);
1115         client_pointer = gdk_device_manager_get_client_pointer (device_manager);
1116
1117         if (event->type == GDK_KEY_PRESS ||
1118             event->type == GDK_KEY_RELEASE)
1119           return gdk_device_get_associated_device (client_pointer);
1120         else
1121           return client_pointer;
1122       }
1123       break;
1124     default:
1125       return NULL;
1126     }
1127 }
1128
1129 /**
1130  * gdk_event_set_source_device:
1131  * @event: a #GdkEvent
1132  * @device: a #GdkDevice
1133  *
1134  * Sets the slave device for @event to @device. The event
1135  * must have been allocated by GTK+, for instance, by
1136  * gdk_event_copy().
1137  *
1138  * Since: 3.0
1139  **/
1140 void
1141 gdk_event_set_source_device (GdkEvent  *event,
1142                              GdkDevice *device)
1143 {
1144   GdkEventPrivate *private;
1145
1146   g_return_if_fail (gdk_event_is_allocated (event));
1147   g_return_if_fail (GDK_IS_DEVICE (device));
1148
1149   private = (GdkEventPrivate *) event;
1150
1151   private->source_device = device;
1152 }
1153
1154 /**
1155  * gdk_event_get_source_device:
1156  * @event: a #GdkEvent
1157  *
1158  * This function returns the hardware (slave) #GdkDevice that has triggered the event,
1159  * falling back to the virtual (master) device (as in gdk_event_get_device()) if the
1160  * event wasn't caused by interaction with a hardware device. This may happen for
1161  * example in synthesized crossing events after a #GdkWindow updates its geometry or
1162  * a grab is acquired/released.
1163  *
1164  * If the event does not contain device field, this function will return %NULL.
1165  *
1166  * Returns: a #GdkDevice, or %NULL.
1167  *
1168  * Since: 3.0
1169  **/
1170 GdkDevice *
1171 gdk_event_get_source_device (const GdkEvent *event)
1172 {
1173   GdkEventPrivate *private;
1174
1175   g_return_val_if_fail (event != NULL, NULL);
1176
1177   if (!gdk_event_is_allocated (event))
1178     return NULL;
1179
1180   private = (GdkEventPrivate *) event;
1181
1182   if (private->source_device)
1183     return private->source_device;
1184
1185   /* Fallback to event device */
1186   return gdk_event_get_device (event);
1187 }
1188
1189 /**
1190  * gdk_event_request_motions:
1191  * @event: a valid #GdkEvent
1192  *
1193  * Request more motion notifies if @event is a motion notify hint event.
1194  * This function should be used instead of gdk_window_get_pointer() to
1195  * request further motion notifies, because it also works for extension
1196  * events where motion notifies are provided for devices other than the
1197  * core pointer. Coordinate extraction, processing and requesting more
1198  * motion events from a %GDK_MOTION_NOTIFY event usually works like this:
1199  *
1200  * |[
1201  * { 
1202  *   /&ast; motion_event handler &ast;/
1203  *   x = motion_event->x;
1204  *   y = motion_event->y;
1205  *   /&ast; handle (x,y) motion &ast;/
1206  *   gdk_event_request_motions (motion_event); /&ast; handles is_hint events &ast;/
1207  * }
1208  * ]|
1209  *
1210  * Since: 2.12
1211  **/
1212 void
1213 gdk_event_request_motions (const GdkEventMotion *event)
1214 {
1215   GdkDisplay *display;
1216   
1217   g_return_if_fail (event != NULL);
1218   
1219   if (event->type == GDK_MOTION_NOTIFY && event->is_hint)
1220     {
1221       gdk_device_get_state (event->device, event->window, NULL, NULL);
1222       
1223       display = gdk_window_get_display (event->window);
1224       _gdk_display_enable_motion_hints (display, event->device);
1225     }
1226 }
1227
1228 static gboolean
1229 gdk_events_get_axis_distances (GdkEvent *event1,
1230                                GdkEvent *event2,
1231                                gdouble  *x_distance,
1232                                gdouble  *y_distance,
1233                                gdouble  *distance)
1234 {
1235   gdouble x1, x2, y1, y2;
1236   gdouble xd, yd;
1237
1238   if (!gdk_event_get_coords (event1, &x1, &y1) ||
1239       !gdk_event_get_coords (event2, &x2, &y2))
1240     return FALSE;
1241
1242   xd = x2 - x1;
1243   yd = y2 - y1;
1244
1245   if (x_distance)
1246     *x_distance = xd;
1247
1248   if (y_distance)
1249     *y_distance = yd;
1250
1251   if (distance)
1252     *distance = sqrt ((xd * xd) + (yd * yd));
1253
1254   return TRUE;
1255 }
1256
1257 /**
1258  * gdk_events_get_distance:
1259  * @event1: first #GdkEvent
1260  * @event2: second #GdkEvent
1261  * @distance: return location for the distance
1262  *
1263  * If both events have X/Y information, the distance between both coordinates
1264  * (as in a straight line going from @event1 to @event2) will be returned.
1265  *
1266  * Returns: %TRUE if the distance could be calculated.
1267  *
1268  * Since: 3.0
1269  **/
1270 gboolean
1271 gdk_events_get_distance (GdkEvent *event1,
1272                          GdkEvent *event2,
1273                          gdouble  *distance)
1274 {
1275   return gdk_events_get_axis_distances (event1, event2,
1276                                         NULL, NULL,
1277                                         distance);
1278 }
1279
1280 /**
1281  * gdk_events_get_angle:
1282  * @event1: first #GdkEvent
1283  * @event2: second #GdkEvent
1284  * @angle: return location for the relative angle between both events
1285  *
1286  * If both events contain X/Y information, this function will return %TRUE
1287  * and return in @angle the relative angle from @event1 to @event2. The rotation
1288  * direction for positive angles is from the positive X axis towards the positive
1289  * Y axis.
1290  *
1291  * Returns: %TRUE if the angle could be calculated.
1292  *
1293  * Since: 3.0
1294  **/
1295 gboolean
1296 gdk_events_get_angle (GdkEvent *event1,
1297                       GdkEvent *event2,
1298                       gdouble  *angle)
1299 {
1300   gdouble x_distance, y_distance, distance;
1301
1302   if (!gdk_events_get_axis_distances (event1, event2,
1303                                       &x_distance, &y_distance,
1304                                       &distance))
1305     return FALSE;
1306
1307   if (angle)
1308     {
1309       *angle = atan2 (x_distance, y_distance);
1310
1311       /* Invert angle */
1312       *angle = (2 * G_PI) - *angle;
1313
1314       /* Shift it 90° */
1315       *angle += G_PI / 2;
1316
1317       /* And constraint it to 0°-360° */
1318       *angle = fmod (*angle, 2 * G_PI);
1319     }
1320
1321   return TRUE;
1322 }
1323
1324 /**
1325  * gdk_events_get_center:
1326  * @event1: first #GdkEvent
1327  * @event2: second #GdkEvent
1328  * @x: (out): return location for the X coordinate of the center
1329  * @y: (out): return location for the Y coordinate of the center
1330  *
1331  * If both events contain X/Y information, the center of both coordinates
1332  * will be returned in @x and @y.
1333  *
1334  * Returns: %TRUE if the center could be calculated.
1335  *
1336  * Since: 3.0
1337  **/
1338 gboolean
1339 gdk_events_get_center (GdkEvent *event1,
1340                        GdkEvent *event2,
1341                        gdouble  *x,
1342                        gdouble  *y)
1343 {
1344   gdouble x1, x2, y1, y2;
1345
1346   if (!gdk_event_get_coords (event1, &x1, &y1) ||
1347       !gdk_event_get_coords (event2, &x2, &y2))
1348     return FALSE;
1349
1350   if (x)
1351     *x = (x2 + x1) / 2;
1352
1353   if (y)
1354     *y = (y2 + y1) / 2;
1355
1356   return TRUE;
1357 }
1358
1359 /**
1360  * gdk_event_set_screen:
1361  * @event: a #GdkEvent
1362  * @screen: a #GdkScreen
1363  * 
1364  * Sets the screen for @event to @screen. The event must
1365  * have been allocated by GTK+, for instance, by
1366  * gdk_event_copy().
1367  *
1368  * Since: 2.2
1369  **/
1370 void
1371 gdk_event_set_screen (GdkEvent  *event,
1372                       GdkScreen *screen)
1373 {
1374   GdkEventPrivate *private;
1375   
1376   g_return_if_fail (gdk_event_is_allocated (event));
1377
1378   private = (GdkEventPrivate *)event;
1379   
1380   private->screen = screen;
1381 }
1382
1383 /**
1384  * gdk_event_get_screen:
1385  * @event: a #GdkEvent
1386  * 
1387  * Returns the screen for the event. The screen is
1388  * typically the screen for <literal>event->any.window</literal>, but
1389  * for events such as mouse events, it is the screen
1390  * where the pointer was when the event occurs -
1391  * that is, the screen which has the root window 
1392  * to which <literal>event->motion.x_root</literal> and
1393  * <literal>event->motion.y_root</literal> are relative.
1394  * 
1395  * Return value: (transfer none): the screen for the event
1396  *
1397  * Since: 2.2
1398  **/
1399 GdkScreen *
1400 gdk_event_get_screen (const GdkEvent *event)
1401 {
1402   if (gdk_event_is_allocated (event))
1403     {
1404       GdkEventPrivate *private = (GdkEventPrivate *)event;
1405
1406       if (private->screen)
1407         return private->screen;
1408     }
1409
1410   if (event->any.window)
1411     return gdk_window_get_screen (event->any.window);
1412
1413   return NULL;
1414 }
1415
1416 /**
1417  * gdk_set_show_events:
1418  * @show_events:  %TRUE to output event debugging information.
1419  * 
1420  * Sets whether a trace of received events is output.
1421  * Note that GTK+ must be compiled with debugging (that is,
1422  * configured using the <option>--enable-debug</option> option)
1423  * to use this option.
1424  **/
1425 void
1426 gdk_set_show_events (gboolean show_events)
1427 {
1428   if (show_events)
1429     _gdk_debug_flags |= GDK_DEBUG_EVENTS;
1430   else
1431     _gdk_debug_flags &= ~GDK_DEBUG_EVENTS;
1432 }
1433
1434 /**
1435  * gdk_get_show_events:
1436  * 
1437  * Gets whether event debugging output is enabled.
1438  * 
1439  * Return value: %TRUE if event debugging output is enabled.
1440  **/
1441 gboolean
1442 gdk_get_show_events (void)
1443 {
1444   return (_gdk_debug_flags & GDK_DEBUG_EVENTS) != 0;
1445 }
1446
1447 /* What do we do with G_IO_NVAL?
1448  */
1449 #define READ_CONDITION (G_IO_IN | G_IO_HUP | G_IO_ERR)
1450 #define WRITE_CONDITION (G_IO_OUT | G_IO_ERR)
1451 #define EXCEPTION_CONDITION (G_IO_PRI)
1452
1453 static void
1454 gdk_synthesize_click (GdkDisplay *display,
1455                       GdkEvent   *event,
1456                       gint        nclicks)
1457 {
1458   GdkEvent temp_event;
1459   GdkEvent *event_copy;
1460   GList *link;
1461   
1462   g_return_if_fail (event != NULL);
1463   
1464   temp_event = *event;
1465   temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
1466
1467   event_copy = gdk_event_copy (&temp_event);
1468   link = _gdk_event_queue_append (display, event_copy);
1469 }
1470
1471 void
1472 _gdk_event_button_generate (GdkDisplay *display,
1473                             GdkEvent   *event)
1474 {
1475   GdkMultipleClickInfo *info;
1476
1477   info = g_hash_table_lookup (display->multiple_click_info, event->button.device);
1478
1479   if (G_UNLIKELY (!info))
1480     {
1481       info = g_new0 (GdkMultipleClickInfo, 1);
1482       info->button_number[0] = info->button_number[1] = -1;
1483
1484       g_hash_table_insert (display->multiple_click_info,
1485                            event->button.device, info);
1486     }
1487
1488   if ((event->button.time < (info->button_click_time[1] + 2 * display->double_click_time)) &&
1489       (event->button.window == info->button_window[1]) &&
1490       (event->button.button == info->button_number[1]) &&
1491       (ABS (event->button.x - info->button_x[1]) <= display->double_click_distance) &&
1492       (ABS (event->button.y - info->button_y[1]) <= display->double_click_distance))
1493     {
1494       gdk_synthesize_click (display, event, 3);
1495
1496       info->button_click_time[1] = 0;
1497       info->button_click_time[0] = 0;
1498       info->button_window[1] = NULL;
1499       info->button_window[0] = NULL;
1500       info->button_number[1] = -1;
1501       info->button_number[0] = -1;
1502       info->button_x[0] = info->button_x[1] = 0;
1503       info->button_y[0] = info->button_y[1] = 0;
1504     }
1505   else if ((event->button.time < (info->button_click_time[0] + display->double_click_time)) &&
1506            (event->button.window == info->button_window[0]) &&
1507            (event->button.button == info->button_number[0]) &&
1508            (ABS (event->button.x - info->button_x[0]) <= display->double_click_distance) &&
1509            (ABS (event->button.y - info->button_y[0]) <= display->double_click_distance))
1510     {
1511       gdk_synthesize_click (display, event, 2);
1512       
1513       info->button_click_time[1] = info->button_click_time[0];
1514       info->button_click_time[0] = event->button.time;
1515       info->button_window[1] = info->button_window[0];
1516       info->button_window[0] = event->button.window;
1517       info->button_number[1] = info->button_number[0];
1518       info->button_number[0] = event->button.button;
1519       info->button_x[1] = info->button_x[0];
1520       info->button_x[0] = event->button.x;
1521       info->button_y[1] = info->button_y[0];
1522       info->button_y[0] = event->button.y;
1523     }
1524   else
1525     {
1526       info->button_click_time[1] = 0;
1527       info->button_click_time[0] = event->button.time;
1528       info->button_window[1] = NULL;
1529       info->button_window[0] = event->button.window;
1530       info->button_number[1] = -1;
1531       info->button_number[0] = event->button.button;
1532       info->button_x[1] = 0;
1533       info->button_x[0] = event->button.x;
1534       info->button_y[1] = 0;
1535       info->button_y[0] = event->button.y;
1536     }
1537 }
1538
1539 void
1540 gdk_synthesize_window_state (GdkWindow     *window,
1541                              GdkWindowState unset_flags,
1542                              GdkWindowState set_flags)
1543 {
1544   GdkEvent temp_event;
1545   GdkWindowState old;
1546   
1547   g_return_if_fail (window != NULL);
1548   
1549   temp_event.window_state.window = window;
1550   temp_event.window_state.type = GDK_WINDOW_STATE;
1551   temp_event.window_state.send_event = FALSE;
1552   
1553   old = temp_event.window_state.window->state;
1554   
1555   temp_event.window_state.new_window_state = old;
1556   temp_event.window_state.new_window_state |= set_flags;
1557   temp_event.window_state.new_window_state &= ~unset_flags;
1558   temp_event.window_state.changed_mask = temp_event.window_state.new_window_state ^ old;
1559
1560   if (temp_event.window_state.new_window_state == old)
1561     return; /* No actual work to do, nothing changed. */
1562
1563   /* Actually update the field in GdkWindow, this is sort of an odd
1564    * place to do it, but seems like the safest since it ensures we expose no
1565    * inconsistent state to the user.
1566    */
1567   
1568   window->state = temp_event.window_state.new_window_state;
1569
1570   if (temp_event.window_state.changed_mask & GDK_WINDOW_STATE_WITHDRAWN)
1571     _gdk_window_update_viewable (window);
1572
1573   /* We only really send the event to toplevels, since
1574    * all the window states don't apply to non-toplevels.
1575    * Non-toplevels do use the GDK_WINDOW_STATE_WITHDRAWN flag
1576    * internally so we needed to update window->state.
1577    */
1578   switch (window->window_type)
1579     {
1580     case GDK_WINDOW_TOPLEVEL:
1581     case GDK_WINDOW_TEMP: /* ? */
1582       gdk_display_put_event (gdk_window_get_display (window), &temp_event);
1583       break;
1584       
1585     case GDK_WINDOW_FOREIGN:
1586     case GDK_WINDOW_ROOT:
1587     case GDK_WINDOW_CHILD:
1588       break;
1589     }
1590 }
1591
1592 /**
1593  * gdk_display_set_double_click_time:
1594  * @display: a #GdkDisplay
1595  * @msec: double click time in milliseconds (thousandths of a second) 
1596  * 
1597  * Sets the double click time (two clicks within this time interval
1598  * count as a double click and result in a #GDK_2BUTTON_PRESS event).
1599  * Applications should <emphasis>not</emphasis> set this, it is a global 
1600  * user-configured setting.
1601  *
1602  * Since: 2.2
1603  **/
1604 void
1605 gdk_display_set_double_click_time (GdkDisplay *display,
1606                                    guint       msec)
1607 {
1608   display->double_click_time = msec;
1609 }
1610
1611 /**
1612  * gdk_set_double_click_time:
1613  * @msec: double click time in milliseconds (thousandths of a second)
1614  *
1615  * Set the double click time for the default display. See
1616  * gdk_display_set_double_click_time(). 
1617  * See also gdk_display_set_double_click_distance().
1618  * Applications should <emphasis>not</emphasis> set this, it is a 
1619  * global user-configured setting.
1620  **/
1621 void
1622 gdk_set_double_click_time (guint msec)
1623 {
1624   gdk_display_set_double_click_time (gdk_display_get_default (), msec);
1625 }
1626
1627 /**
1628  * gdk_display_set_double_click_distance:
1629  * @display: a #GdkDisplay
1630  * @distance: distance in pixels
1631  * 
1632  * Sets the double click distance (two clicks within this distance
1633  * count as a double click and result in a #GDK_2BUTTON_PRESS event).
1634  * See also gdk_display_set_double_click_time().
1635  * Applications should <emphasis>not</emphasis> set this, it is a global 
1636  * user-configured setting.
1637  *
1638  * Since: 2.4
1639  **/
1640 void
1641 gdk_display_set_double_click_distance (GdkDisplay *display,
1642                                        guint       distance)
1643 {
1644   display->double_click_distance = distance;
1645 }
1646
1647 G_DEFINE_BOXED_TYPE (GdkEvent, gdk_event,
1648                      gdk_event_copy,
1649                      gdk_event_free)
1650
1651 /**
1652  * gdk_setting_get:
1653  * @name: the name of the setting.
1654  * @value: location to store the value of the setting.
1655  *
1656  * Obtains a desktop-wide setting, such as the double-click time,
1657  * for the default screen. See gdk_screen_get_setting().
1658  *
1659  * Returns: %TRUE if the setting existed and a value was stored
1660  *   in @value, %FALSE otherwise.
1661  **/
1662 gboolean
1663 gdk_setting_get (const gchar *name,
1664                  GValue      *value)
1665 {
1666   return gdk_screen_get_setting (gdk_screen_get_default (), name, value);
1667 }