]> Pileus Git - ~andy/gtk/blob - gdk/gdkevents.c
Merge branch 'native-layout-incubator'
[~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 #include <string.h>             /* For memset() */
29
30 #include "gdk.h"
31 #include "gdkinternals.h"
32 #include "gdkalias.h"
33
34 typedef struct _GdkIOClosure GdkIOClosure;
35
36 struct _GdkIOClosure
37 {
38   GdkInputFunction function;
39   GdkInputCondition condition;
40   GDestroyNotify notify;
41   gpointer data;
42 };
43
44 /* Private variable declarations
45  */
46
47 GdkEventFunc   _gdk_event_func = NULL;    /* Callback for events */
48 gpointer       _gdk_event_data = NULL;
49 GDestroyNotify _gdk_event_notify = NULL;
50
51 /*********************************************
52  * Functions for maintaining the event queue *
53  *********************************************/
54
55 /**
56  * _gdk_event_queue_find_first:
57  * @display: a #GdkDisplay
58  * 
59  * Find the first event on the queue that is not still
60  * being filled in.
61  * 
62  * Return value: Pointer to the list node for that event, or NULL.
63  **/
64 GList*
65 _gdk_event_queue_find_first (GdkDisplay *display)
66 {
67   GList *tmp_list = display->queued_events;
68
69   while (tmp_list)
70     {
71       GdkEventPrivate *event = tmp_list->data;
72       if (!(event->flags & GDK_EVENT_PENDING))
73         return tmp_list;
74
75       tmp_list = g_list_next (tmp_list);
76     }
77
78   return NULL;
79 }
80
81 /**
82  * _gdk_event_queue_prepend:
83  * @display: a #GdkDisplay
84  * @event: Event to prepend.
85  *
86  * Prepends an event before the head of the event queue.
87  *
88  * Returns: the newly prepended list node.
89  **/
90 GList*
91 _gdk_event_queue_prepend (GdkDisplay *display,
92                           GdkEvent   *event)
93 {
94   display->queued_events = g_list_prepend (display->queued_events, event);
95   if (!display->queued_tail)
96     display->queued_tail = display->queued_events;
97   return display->queued_events;
98 }
99
100 /**
101  * _gdk_event_queue_append:
102  * @display: a #GdkDisplay
103  * @event: Event to append.
104  * 
105  * Appends an event onto the tail of the event queue.
106  *
107  * Returns: the newly appended list node.
108  **/
109 GList *
110 _gdk_event_queue_append (GdkDisplay *display,
111                          GdkEvent   *event)
112 {
113   display->queued_tail = g_list_append (display->queued_tail, event);
114   
115   if (!display->queued_events)
116     display->queued_events = display->queued_tail;
117   else
118     display->queued_tail = display->queued_tail->next;
119
120   return display->queued_tail;
121 }
122
123 /**
124  * _gdk_event_queue_insert_after:
125  * @display: a #GdkDisplay
126  * @sibling: Append after this event.
127  * @event: Event to append.
128  *
129  * Appends an event after the specified event, or if it isn't in
130  * the queue, onto the tail of the event queue.
131  *
132  * Returns: the newly appended list node.
133  *
134  * Since: 2.16
135  */
136 GList*
137 _gdk_event_queue_insert_after (GdkDisplay *display,
138                                GdkEvent   *sibling,
139                                GdkEvent   *event)
140 {
141   GList *prev = g_list_find (display->queued_events, sibling);
142   if (prev && prev->next)
143     {
144       display->queued_events = g_list_insert_before (display->queued_events, prev->next, event);
145       return prev->next;
146     }
147   else
148     return _gdk_event_queue_append (display, event);
149 }
150
151 /**
152  * _gdk_event_queue_insert_after:
153  * @display: a #GdkDisplay
154  * @sibling: Append after this event.
155  * @event: Event to append.
156  *
157  * Appends an event before the specified event, or if it isn't in
158  * the queue, onto the tail of the event queue.
159  *
160  * Returns: the newly appended list node.
161  *
162  * Since: 2.16
163  */
164 GList*
165 _gdk_event_queue_insert_before (GdkDisplay *display,
166                                 GdkEvent   *sibling,
167                                 GdkEvent   *event)
168 {
169   GList *next = g_list_find (display->queued_events, sibling);
170   if (next)
171     {
172       display->queued_events = g_list_insert_before (display->queued_events, next, event);
173       return next->prev;
174     }
175   else
176     return _gdk_event_queue_append (display, event);
177 }
178
179
180 /**
181  * _gdk_event_queue_remove_link:
182  * @display: a #GdkDisplay
183  * @node: node to remove
184  * 
185  * Removes a specified list node from the event queue.
186  **/
187 void
188 _gdk_event_queue_remove_link (GdkDisplay *display,
189                               GList      *node)
190 {
191   if (node->prev)
192     node->prev->next = node->next;
193   else
194     display->queued_events = node->next;
195   
196   if (node->next)
197     node->next->prev = node->prev;
198   else
199     display->queued_tail = node->prev;
200 }
201
202 /**
203  * _gdk_event_unqueue:
204  * @display: a #GdkDisplay
205  * 
206  * Removes and returns the first event from the event
207  * queue that is not still being filled in.
208  * 
209  * Return value: the event, or %NULL. Ownership is transferred
210  * to the caller.
211  **/
212 GdkEvent*
213 _gdk_event_unqueue (GdkDisplay *display)
214 {
215   GdkEvent *event = NULL;
216   GList *tmp_list;
217
218   tmp_list = _gdk_event_queue_find_first (display);
219
220   if (tmp_list)
221     {
222       event = tmp_list->data;
223       _gdk_event_queue_remove_link (display, tmp_list);
224       g_list_free_1 (tmp_list);
225     }
226
227   return event;
228 }
229
230 /**
231  * gdk_event_handler_set:
232  * @func: the function to call to handle events from GDK.
233  * @data: user data to pass to the function. 
234  * @notify: the function to call when the handler function is removed, i.e. when
235  *          gdk_event_handler_set() is called with another event handler.
236  * 
237  * Sets the function to call to handle all events from GDK.
238  *
239  * Note that GTK+ uses this to install its own event handler, so it is
240  * usually not useful for GTK+ applications. (Although an application
241  * can call this function then call gtk_main_do_event() to pass
242  * events to GTK+.)
243  **/
244 void 
245 gdk_event_handler_set (GdkEventFunc   func,
246                        gpointer       data,
247                        GDestroyNotify notify)
248 {
249   if (_gdk_event_notify)
250     (*_gdk_event_notify) (_gdk_event_data);
251
252   _gdk_event_func = func;
253   _gdk_event_data = data;
254   _gdk_event_notify = notify;
255 }
256
257 /**
258  * gdk_event_get:
259  * 
260  * Checks all open displays for a #GdkEvent to process,to be processed
261  * on, fetching events from the windowing system if necessary.
262  * See gdk_display_get_event().
263  * 
264  * Return value: the next #GdkEvent to be processed, or %NULL if no events
265  * are pending. The returned #GdkEvent should be freed with gdk_event_free().
266  **/
267 GdkEvent*
268 gdk_event_get (void)
269 {
270   GSList *tmp_list;
271
272   for (tmp_list = _gdk_displays; tmp_list; tmp_list = tmp_list->next)
273     {
274       GdkEvent *event = gdk_display_get_event (tmp_list->data);
275       if (event)
276         return event;
277     }
278
279   return NULL;
280 }
281
282 /**
283  * gdk_event_peek:
284  *
285  * If there is an event waiting in the event queue of some open
286  * display, returns a copy of it. See gdk_display_peek_event().
287  * 
288  * Return value: a copy of the first #GdkEvent on some event queue, or %NULL if no
289  * events are in any queues. The returned #GdkEvent should be freed with
290  * gdk_event_free().
291  **/
292 GdkEvent*
293 gdk_event_peek (void)
294 {
295   GSList *tmp_list;
296
297   for (tmp_list = _gdk_displays; tmp_list; tmp_list = tmp_list->next)
298     {
299       GdkEvent *event = gdk_display_peek_event (tmp_list->data);
300       if (event)
301         return event;
302     }
303
304   return NULL;
305 }
306
307 /**
308  * gdk_event_put:
309  * @event: a #GdkEvent.
310  *
311  * Appends a copy of the given event onto the front of the event
312  * queue for event->any.window's display, or the default event
313  * queue if event->any.window is %NULL. See gdk_display_put_event().
314  **/
315 void
316 gdk_event_put (const GdkEvent *event)
317 {
318   GdkDisplay *display;
319   
320   g_return_if_fail (event != NULL);
321
322   if (event->any.window)
323     display = gdk_drawable_get_display (event->any.window);
324   else
325     {
326       GDK_NOTE (MULTIHEAD,
327                 g_message ("Falling back to default display for gdk_event_put()"));
328       display = gdk_display_get_default ();
329     }
330
331   gdk_display_put_event (display, event);
332 }
333
334 static GHashTable *event_hash = NULL;
335
336 /**
337  * gdk_event_new:
338  * @type: a #GdkEventType 
339  * 
340  * Creates a new event of the given type. All fields are set to 0.
341  * 
342  * Return value: a newly-allocated #GdkEvent. The returned #GdkEvent 
343  * should be freed with gdk_event_free().
344  *
345  * Since: 2.2
346  **/
347 GdkEvent*
348 gdk_event_new (GdkEventType type)
349 {
350   GdkEventPrivate *new_private;
351   GdkEvent *new_event;
352   
353   if (!event_hash)
354     event_hash = g_hash_table_new (g_direct_hash, NULL);
355
356   new_private = g_slice_new0 (GdkEventPrivate);
357   
358   new_private->flags = 0;
359   new_private->screen = NULL;
360
361   g_hash_table_insert (event_hash, new_private, GUINT_TO_POINTER (1));
362
363   new_event = (GdkEvent *) new_private;
364
365   new_event->any.type = type;
366
367   /*
368    * Bytewise 0 initialization is reasonable for most of the 
369    * current event types. Explicitely initialize double fields
370    * since I trust bytewise 0 == 0. less than for integers
371    * or pointers.
372    */
373   switch (type)
374     {
375     case GDK_MOTION_NOTIFY:
376       new_event->motion.x = 0.;
377       new_event->motion.y = 0.;
378       new_event->motion.x_root = 0.;
379       new_event->motion.y_root = 0.;
380       break;
381     case GDK_BUTTON_PRESS:
382     case GDK_2BUTTON_PRESS:
383     case GDK_3BUTTON_PRESS:
384     case GDK_BUTTON_RELEASE:
385       new_event->button.x = 0.;
386       new_event->button.y = 0.;
387       new_event->button.x_root = 0.;
388       new_event->button.y_root = 0.;
389       break;
390     case GDK_SCROLL:
391       new_event->scroll.x = 0.;
392       new_event->scroll.y = 0.;
393       new_event->scroll.x_root = 0.;
394       new_event->scroll.y_root = 0.;
395       break;
396     case GDK_ENTER_NOTIFY:
397     case GDK_LEAVE_NOTIFY:
398       new_event->crossing.x = 0.;
399       new_event->crossing.y = 0.;
400       new_event->crossing.x_root = 0.;
401       new_event->crossing.y_root = 0.;
402       break;
403     default:
404       break;
405     }
406   
407   return new_event;
408 }
409
410 static gboolean
411 gdk_event_is_allocated (const GdkEvent *event)
412 {
413   if (event_hash)
414     return g_hash_table_lookup (event_hash, event) != NULL;
415
416   return FALSE;
417 }
418  
419 /**
420  * gdk_event_copy:
421  * @event: a #GdkEvent
422  * 
423  * Copies a #GdkEvent, copying or incrementing the reference count of the
424  * resources associated with it (e.g. #GdkWindow's and strings).
425  * 
426  * Return value: a copy of @event. The returned #GdkEvent should be freed with
427  * gdk_event_free().
428  **/
429 GdkEvent*
430 gdk_event_copy (const GdkEvent *event)
431 {
432   GdkEventPrivate *new_private;
433   GdkEvent *new_event;
434   
435   g_return_val_if_fail (event != NULL, NULL);
436   
437   new_event = gdk_event_new (GDK_NOTHING);
438   new_private = (GdkEventPrivate *)new_event;
439
440   *new_event = *event;
441   if (new_event->any.window)
442     g_object_ref (new_event->any.window);
443
444   if (gdk_event_is_allocated (event))
445     {
446       GdkEventPrivate *private = (GdkEventPrivate *)event;
447
448       new_private->screen = private->screen;
449     }
450   
451   switch (event->any.type)
452     {
453     case GDK_KEY_PRESS:
454     case GDK_KEY_RELEASE:
455       new_event->key.string = g_strdup (event->key.string);
456       break;
457       
458     case GDK_ENTER_NOTIFY:
459     case GDK_LEAVE_NOTIFY:
460       if (event->crossing.subwindow != NULL)
461         g_object_ref (event->crossing.subwindow);
462       break;
463       
464     case GDK_DRAG_ENTER:
465     case GDK_DRAG_LEAVE:
466     case GDK_DRAG_MOTION:
467     case GDK_DRAG_STATUS:
468     case GDK_DROP_START:
469     case GDK_DROP_FINISHED:
470       g_object_ref (event->dnd.context);
471       break;
472       
473     case GDK_EXPOSE:
474     case GDK_DAMAGE:
475       if (event->expose.region)
476         new_event->expose.region = gdk_region_copy (event->expose.region);
477       break;
478       
479     case GDK_SETTING:
480       new_event->setting.name = g_strdup (new_event->setting.name);
481       break;
482
483     case GDK_BUTTON_PRESS:
484     case GDK_BUTTON_RELEASE:
485       if (event->button.axes) 
486         new_event->button.axes = g_memdup (event->button.axes, 
487                                              sizeof (gdouble) * event->button.device->num_axes);
488       break;
489
490     case GDK_MOTION_NOTIFY:
491       if (event->motion.axes) 
492         new_event->motion.axes = g_memdup (event->motion.axes, 
493                                            sizeof (gdouble) * event->motion.device->num_axes);
494       
495       break;
496       
497     default:
498       break;
499     }
500
501   if (gdk_event_is_allocated (event))
502     _gdk_windowing_event_data_copy (event, new_event);
503   
504   return new_event;
505 }
506
507 /**
508  * gdk_event_free:
509  * @event:  a #GdkEvent.
510  * 
511  * Frees a #GdkEvent, freeing or decrementing any resources associated with it.
512  * Note that this function should only be called with events returned from
513  * functions such as gdk_event_peek(), gdk_event_get(),
514  * gdk_event_get_graphics_expose() and gdk_event_copy() and gdk_event_new().
515  **/
516 void
517 gdk_event_free (GdkEvent *event)
518 {
519   g_return_if_fail (event != NULL);
520
521   if (event->any.window)
522     g_object_unref (event->any.window);
523   
524   switch (event->any.type)
525     {
526     case GDK_KEY_PRESS:
527     case GDK_KEY_RELEASE:
528       g_free (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_unref (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_unref (event->dnd.context);
544       break;
545
546     case GDK_BUTTON_PRESS:
547     case GDK_BUTTON_RELEASE:
548       g_free (event->button.axes);
549       break;
550       
551     case GDK_EXPOSE:
552     case GDK_DAMAGE:
553       if (event->expose.region)
554         gdk_region_destroy (event->expose.region);
555       break;
556       
557     case GDK_MOTION_NOTIFY:
558       g_free (event->motion.axes);
559       break;
560       
561     case GDK_SETTING:
562       g_free (event->setting.name);
563       break;
564       
565     default:
566       break;
567     }
568
569   _gdk_windowing_event_data_free (event);
570
571   g_hash_table_remove (event_hash, event);
572   g_slice_free (GdkEventPrivate, (GdkEventPrivate*) event);
573 }
574
575 /**
576  * gdk_event_get_time:
577  * @event: a #GdkEvent
578  * 
579  * Returns the time stamp from @event, if there is one; otherwise
580  * returns #GDK_CURRENT_TIME. If @event is %NULL, returns #GDK_CURRENT_TIME.
581  * 
582  * Return value: time stamp field from @event
583  **/
584 guint32
585 gdk_event_get_time (const GdkEvent *event)
586 {
587   if (event)
588     switch (event->type)
589       {
590       case GDK_MOTION_NOTIFY:
591         return event->motion.time;
592       case GDK_BUTTON_PRESS:
593       case GDK_2BUTTON_PRESS:
594       case GDK_3BUTTON_PRESS:
595       case GDK_BUTTON_RELEASE:
596         return event->button.time;
597       case GDK_SCROLL:
598         return event->scroll.time;
599       case GDK_KEY_PRESS:
600       case GDK_KEY_RELEASE:
601         return event->key.time;
602       case GDK_ENTER_NOTIFY:
603       case GDK_LEAVE_NOTIFY:
604         return event->crossing.time;
605       case GDK_PROPERTY_NOTIFY:
606         return event->property.time;
607       case GDK_SELECTION_CLEAR:
608       case GDK_SELECTION_REQUEST:
609       case GDK_SELECTION_NOTIFY:
610         return event->selection.time;
611       case GDK_PROXIMITY_IN:
612       case GDK_PROXIMITY_OUT:
613         return event->proximity.time;
614       case GDK_DRAG_ENTER:
615       case GDK_DRAG_LEAVE:
616       case GDK_DRAG_MOTION:
617       case GDK_DRAG_STATUS:
618       case GDK_DROP_START:
619       case GDK_DROP_FINISHED:
620         return event->dnd.time;
621       case GDK_CLIENT_EVENT:
622       case GDK_VISIBILITY_NOTIFY:
623       case GDK_NO_EXPOSE:
624       case GDK_CONFIGURE:
625       case GDK_FOCUS_CHANGE:
626       case GDK_NOTHING:
627       case GDK_DAMAGE:
628       case GDK_DELETE:
629       case GDK_DESTROY:
630       case GDK_EXPOSE:
631       case GDK_MAP:
632       case GDK_UNMAP:
633       case GDK_WINDOW_STATE:
634       case GDK_SETTING:
635       case GDK_OWNER_CHANGE:
636       case GDK_GRAB_BROKEN:
637       case GDK_EVENT_LAST:
638         /* return current time */
639         break;
640       }
641   
642   return GDK_CURRENT_TIME;
643 }
644
645 /**
646  * gdk_event_get_state:
647  * @event: a #GdkEvent or NULL
648  * @state: return location for state
649  * 
650  * If the event contains a "state" field, puts that field in @state. Otherwise
651  * stores an empty state (0). Returns %TRUE if there was a state field
652  * in the event. @event may be %NULL, in which case it's treated
653  * as if the event had no state field.
654  * 
655  * Return value: %TRUE if there was a state field in the event 
656  **/
657 gboolean
658 gdk_event_get_state (const GdkEvent        *event,
659                      GdkModifierType       *state)
660 {
661   g_return_val_if_fail (state != NULL, FALSE);
662   
663   if (event)
664     switch (event->type)
665       {
666       case GDK_MOTION_NOTIFY:
667         *state = event->motion.state;
668         return TRUE;
669       case GDK_BUTTON_PRESS:
670       case GDK_2BUTTON_PRESS:
671       case GDK_3BUTTON_PRESS:
672       case GDK_BUTTON_RELEASE:
673         *state =  event->button.state;
674         return TRUE;
675       case GDK_SCROLL:
676         *state =  event->scroll.state;
677         return TRUE;
678       case GDK_KEY_PRESS:
679       case GDK_KEY_RELEASE:
680         *state =  event->key.state;
681         return TRUE;
682       case GDK_ENTER_NOTIFY:
683       case GDK_LEAVE_NOTIFY:
684         *state =  event->crossing.state;
685         return TRUE;
686       case GDK_PROPERTY_NOTIFY:
687         *state =  event->property.state;
688         return TRUE;
689       case GDK_VISIBILITY_NOTIFY:
690       case GDK_CLIENT_EVENT:
691       case GDK_NO_EXPOSE:
692       case GDK_CONFIGURE:
693       case GDK_FOCUS_CHANGE:
694       case GDK_SELECTION_CLEAR:
695       case GDK_SELECTION_REQUEST:
696       case GDK_SELECTION_NOTIFY:
697       case GDK_PROXIMITY_IN:
698       case GDK_PROXIMITY_OUT:
699       case GDK_DAMAGE:
700       case GDK_DRAG_ENTER:
701       case GDK_DRAG_LEAVE:
702       case GDK_DRAG_MOTION:
703       case GDK_DRAG_STATUS:
704       case GDK_DROP_START:
705       case GDK_DROP_FINISHED:
706       case GDK_NOTHING:
707       case GDK_DELETE:
708       case GDK_DESTROY:
709       case GDK_EXPOSE:
710       case GDK_MAP:
711       case GDK_UNMAP:
712       case GDK_WINDOW_STATE:
713       case GDK_SETTING:
714       case GDK_OWNER_CHANGE:
715       case GDK_GRAB_BROKEN:
716       case GDK_EVENT_LAST:
717         /* no state field */
718         break;
719       }
720
721   *state = 0;
722   return FALSE;
723 }
724
725 /**
726  * gdk_event_get_coords:
727  * @event: a #GdkEvent
728  * @x_win: location to put event window x coordinate
729  * @y_win: location to put event window y coordinate
730  * 
731  * Extract the event window relative x/y coordinates from an event.
732  * 
733  * Return value: %TRUE if the event delivered event window coordinates
734  **/
735 gboolean
736 gdk_event_get_coords (const GdkEvent *event,
737                       gdouble        *x_win,
738                       gdouble        *y_win)
739 {
740   gdouble x = 0, y = 0;
741   gboolean fetched = TRUE;
742   
743   g_return_val_if_fail (event != NULL, FALSE);
744
745   switch (event->type)
746     {
747     case GDK_CONFIGURE:
748       x = event->configure.x;
749       y = event->configure.y;
750       break;
751     case GDK_ENTER_NOTIFY:
752     case GDK_LEAVE_NOTIFY:
753       x = event->crossing.x;
754       y = event->crossing.y;
755       break;
756     case GDK_SCROLL:
757       x = event->scroll.x;
758       y = event->scroll.y;
759       break;
760     case GDK_BUTTON_PRESS:
761     case GDK_2BUTTON_PRESS:
762     case GDK_3BUTTON_PRESS:
763     case GDK_BUTTON_RELEASE:
764       x = event->button.x;
765       y = event->button.y;
766       break;
767     case GDK_MOTION_NOTIFY:
768       x = event->motion.x;
769       y = event->motion.y;
770       break;
771     default:
772       fetched = FALSE;
773       break;
774     }
775
776   if (x_win)
777     *x_win = x;
778   if (y_win)
779     *y_win = y;
780
781   return fetched;
782 }
783
784 /**
785  * gdk_event_get_root_coords:
786  * @event: a #GdkEvent
787  * @x_root: location to put root window x coordinate
788  * @y_root: location to put root window y coordinate
789  * 
790  * Extract the root window relative x/y coordinates from an event.
791  * 
792  * Return value: %TRUE if the event delivered root window coordinates
793  **/
794 gboolean
795 gdk_event_get_root_coords (const GdkEvent *event,
796                            gdouble        *x_root,
797                            gdouble        *y_root)
798 {
799   gdouble x = 0, y = 0;
800   gboolean fetched = TRUE;
801   
802   g_return_val_if_fail (event != NULL, FALSE);
803
804   switch (event->type)
805     {
806     case GDK_MOTION_NOTIFY:
807       x = event->motion.x_root;
808       y = event->motion.y_root;
809       break;
810     case GDK_SCROLL:
811       x = event->scroll.x_root;
812       y = event->scroll.y_root;
813       break;
814     case GDK_BUTTON_PRESS:
815     case GDK_2BUTTON_PRESS:
816     case GDK_3BUTTON_PRESS:
817     case GDK_BUTTON_RELEASE:
818       x = event->button.x_root;
819       y = event->button.y_root;
820       break;
821     case GDK_ENTER_NOTIFY:
822     case GDK_LEAVE_NOTIFY:
823       x = event->crossing.x_root;
824       y = event->crossing.y_root;
825       break;
826     case GDK_DRAG_ENTER:
827     case GDK_DRAG_LEAVE:
828     case GDK_DRAG_MOTION:
829     case GDK_DRAG_STATUS:
830     case GDK_DROP_START:
831     case GDK_DROP_FINISHED:
832       x = event->dnd.x_root;
833       y = event->dnd.y_root;
834       break;
835     default:
836       fetched = FALSE;
837       break;
838     }
839
840   if (x_root)
841     *x_root = x;
842   if (y_root)
843     *y_root = y;
844
845   return fetched;
846 }
847
848 /**
849  * gdk_event_get_axis:
850  * @event: a #GdkEvent
851  * @axis_use: the axis use to look for
852  * @value: location to store the value found
853  * 
854  * Extract the axis value for a particular axis use from
855  * an event structure.
856  * 
857  * Return value: %TRUE if the specified axis was found, otherwise %FALSE
858  **/
859 gboolean
860 gdk_event_get_axis (const GdkEvent *event,
861                     GdkAxisUse      axis_use,
862                     gdouble        *value)
863 {
864   gdouble *axes;
865   GdkDevice *device;
866   
867   g_return_val_if_fail (event != NULL, FALSE);
868   
869   if (axis_use == GDK_AXIS_X || axis_use == GDK_AXIS_Y)
870     {
871       gdouble x, y;
872       
873       switch (event->type)
874         {
875         case GDK_MOTION_NOTIFY:
876           x = event->motion.x;
877           y = event->motion.y;
878           break;
879         case GDK_SCROLL:
880           x = event->scroll.x;
881           y = event->scroll.y;
882           break;
883         case GDK_BUTTON_PRESS:
884         case GDK_BUTTON_RELEASE:
885           x = event->button.x;
886           y = event->button.y;
887           break;
888         case GDK_ENTER_NOTIFY:
889         case GDK_LEAVE_NOTIFY:
890           x = event->crossing.x;
891           y = event->crossing.y;
892           break;
893           
894         default:
895           return FALSE;
896         }
897
898       if (axis_use == GDK_AXIS_X && value)
899         *value = x;
900       if (axis_use == GDK_AXIS_Y && value)
901         *value = y;
902
903       return TRUE;
904     }
905   else if (event->type == GDK_BUTTON_PRESS ||
906            event->type == GDK_BUTTON_RELEASE)
907     {
908       device = event->button.device;
909       axes = event->button.axes;
910     }
911   else if (event->type == GDK_MOTION_NOTIFY)
912     {
913       device = event->motion.device;
914       axes = event->motion.axes;
915     }
916   else
917     return FALSE;
918
919   return gdk_device_get_axis (device, axes, axis_use, value);
920 }
921
922 /**
923  * gdk_event_request_motions:
924  * @event: a valid #GdkEvent
925  *
926  * Request more motion notifies if @event is a motion notify hint event.
927  * This function should be used instead of gdk_window_get_pointer() to
928  * request further motion notifies, because it also works for extension
929  * events where motion notifies are provided for devices other than the
930  * core pointer. Coordinate extraction, processing and requesting more
931  * motion events from a %GDK_MOTION_NOTIFY event usually works like this:
932  *
933  * |[
934  * { 
935  *   /&ast; motion_event handler &ast;/
936  *   x = motion_event->x;
937  *   y = motion_event->y;
938  *   /&ast; handle (x,y) motion &ast;/
939  *   gdk_event_request_motions (motion_event); /&ast; handles is_hint events &ast;/
940  * }
941  * ]|
942  *
943  * Since: 2.12
944  **/
945 void
946 gdk_event_request_motions (const GdkEventMotion *event)
947 {
948   GdkDisplay *display;
949   
950   g_return_if_fail (event != NULL);
951   
952   if (event->type == GDK_MOTION_NOTIFY && event->is_hint)
953     {
954       gdk_device_get_state (event->device, event->window, NULL, NULL);
955       
956       display = gdk_drawable_get_display (event->window);
957       _gdk_display_enable_motion_hints (display);
958     }
959 }
960
961 /**
962  * gdk_event_set_screen:
963  * @event: a #GdkEvent
964  * @screen: a #GdkScreen
965  * 
966  * Sets the screen for @event to @screen. The event must
967  * have been allocated by GTK+, for instance, by
968  * gdk_event_copy().
969  *
970  * Since: 2.2
971  **/
972 void
973 gdk_event_set_screen (GdkEvent  *event,
974                       GdkScreen *screen)
975 {
976   GdkEventPrivate *private;
977   
978   g_return_if_fail (gdk_event_is_allocated (event));
979
980   private = (GdkEventPrivate *)event;
981   
982   private->screen = screen;
983 }
984
985 /**
986  * gdk_event_get_screen:
987  * @event: a #GdkEvent
988  * 
989  * Returns the screen for the event. The screen is
990  * typically the screen for <literal>event->any.window</literal>, but
991  * for events such as mouse events, it is the screen
992  * where the pointer was when the event occurs -
993  * that is, the screen which has the root window 
994  * to which <literal>event->motion.x_root</literal> and
995  * <literal>event->motion.y_root</literal> are relative.
996  * 
997  * Return value: the screen for the event
998  *
999  * Since: 2.2
1000  **/
1001 GdkScreen *
1002 gdk_event_get_screen (const GdkEvent *event)
1003 {
1004   if (gdk_event_is_allocated (event))
1005     {
1006       GdkEventPrivate *private = (GdkEventPrivate *)event;
1007
1008       if (private->screen)
1009         return private->screen;
1010     }
1011
1012   if (event->any.window)
1013     return gdk_drawable_get_screen (event->any.window);
1014
1015   return NULL;
1016 }
1017
1018 /**
1019  * gdk_set_show_events:
1020  * @show_events:  %TRUE to output event debugging information.
1021  * 
1022  * Sets whether a trace of received events is output.
1023  * Note that GTK+ must be compiled with debugging (that is,
1024  * configured using the <option>--enable-debug</option> option)
1025  * to use this option.
1026  **/
1027 void
1028 gdk_set_show_events (gboolean show_events)
1029 {
1030   if (show_events)
1031     _gdk_debug_flags |= GDK_DEBUG_EVENTS;
1032   else
1033     _gdk_debug_flags &= ~GDK_DEBUG_EVENTS;
1034 }
1035
1036 /**
1037  * gdk_get_show_events:
1038  * 
1039  * Gets whether event debugging output is enabled.
1040  * 
1041  * Return value: %TRUE if event debugging output is enabled.
1042  **/
1043 gboolean
1044 gdk_get_show_events (void)
1045 {
1046   return (_gdk_debug_flags & GDK_DEBUG_EVENTS) != 0;
1047 }
1048
1049 static void
1050 gdk_io_destroy (gpointer data)
1051 {
1052   GdkIOClosure *closure = data;
1053
1054   if (closure->notify)
1055     closure->notify (closure->data);
1056
1057   g_free (closure);
1058 }
1059
1060 /* What do we do with G_IO_NVAL?
1061  */
1062 #define READ_CONDITION (G_IO_IN | G_IO_HUP | G_IO_ERR)
1063 #define WRITE_CONDITION (G_IO_OUT | G_IO_ERR)
1064 #define EXCEPTION_CONDITION (G_IO_PRI)
1065
1066 static gboolean  
1067 gdk_io_invoke (GIOChannel   *source,
1068                GIOCondition  condition,
1069                gpointer      data)
1070 {
1071   GdkIOClosure *closure = data;
1072   GdkInputCondition gdk_cond = 0;
1073
1074   if (condition & READ_CONDITION)
1075     gdk_cond |= GDK_INPUT_READ;
1076   if (condition & WRITE_CONDITION)
1077     gdk_cond |= GDK_INPUT_WRITE;
1078   if (condition & EXCEPTION_CONDITION)
1079     gdk_cond |= GDK_INPUT_EXCEPTION;
1080
1081   if (closure->condition & gdk_cond)
1082     closure->function (closure->data, g_io_channel_unix_get_fd (source), gdk_cond);
1083
1084   return TRUE;
1085 }
1086
1087 /**
1088  * gdk_input_add_full:
1089  * @source: a file descriptor.
1090  * @condition: the condition.
1091  * @function: the callback function.
1092  * @data: callback data passed to @function.
1093  * @destroy: callback function to call with @data when the input
1094  * handler is removed.
1095  *
1096  * Establish a callback when a condition becomes true on
1097  * a file descriptor.
1098  *
1099  * Returns: a tag that can later be used as an argument to
1100  * gdk_input_remove().
1101  *
1102  * Deprecated: 2.14: Use g_io_add_watch_full() on a #GIOChannel
1103  */
1104 gint
1105 gdk_input_add_full (gint              source,
1106                     GdkInputCondition condition,
1107                     GdkInputFunction  function,
1108                     gpointer          data,
1109                     GDestroyNotify    destroy)
1110 {
1111   guint result;
1112   GdkIOClosure *closure = g_new (GdkIOClosure, 1);
1113   GIOChannel *channel;
1114   GIOCondition cond = 0;
1115
1116   closure->function = function;
1117   closure->condition = condition;
1118   closure->notify = destroy;
1119   closure->data = data;
1120
1121   if (condition & GDK_INPUT_READ)
1122     cond |= READ_CONDITION;
1123   if (condition & GDK_INPUT_WRITE)
1124     cond |= WRITE_CONDITION;
1125   if (condition & GDK_INPUT_EXCEPTION)
1126     cond |= EXCEPTION_CONDITION;
1127
1128   channel = g_io_channel_unix_new (source);
1129   result = g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, cond, 
1130                                 gdk_io_invoke,
1131                                 closure, gdk_io_destroy);
1132   g_io_channel_unref (channel);
1133
1134   return result;
1135 }
1136
1137 /**
1138  * gdk_input_add:
1139  * @source: a file descriptor.
1140  * @condition: the condition.
1141  * @function: the callback function.
1142  * @data: callback data passed to @function.
1143  *
1144  * Establish a callback when a condition becomes true on
1145  * a file descriptor.
1146  *
1147  * Returns: a tag that can later be used as an argument to
1148  * gdk_input_remove().
1149  *
1150  * Deprecated: 2.14: Use g_io_add_watch() on a #GIOChannel
1151  */
1152 gint
1153 gdk_input_add (gint              source,
1154                GdkInputCondition condition,
1155                GdkInputFunction  function,
1156                gpointer          data)
1157 {
1158   return gdk_input_add_full (source, condition, function, data, NULL);
1159 }
1160
1161 void
1162 gdk_input_remove (gint tag)
1163 {
1164   g_source_remove (tag);
1165 }
1166
1167 static void
1168 gdk_synthesize_click (GdkDisplay *display,
1169                       GdkEvent   *event,
1170                       gint        nclicks)
1171 {
1172   GdkEvent temp_event;
1173   GdkEvent *event_copy;
1174   GList *link;
1175   
1176   g_return_if_fail (event != NULL);
1177   
1178   temp_event = *event;
1179   temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
1180
1181   event_copy = gdk_event_copy (&temp_event);
1182   link = _gdk_event_queue_append (display, event_copy);
1183 }
1184
1185 void
1186 _gdk_event_button_generate (GdkDisplay *display,
1187                             GdkEvent   *event)
1188 {
1189   if ((event->button.time < (display->button_click_time[1] + 2*display->double_click_time)) &&
1190       (event->button.window == display->button_window[1]) &&
1191       (event->button.button == display->button_number[1]) &&
1192       (ABS (event->button.x - display->button_x[1]) <= display->double_click_distance) &&
1193       (ABS (event->button.y - display->button_y[1]) <= display->double_click_distance))
1194 {
1195       gdk_synthesize_click (display, event, 3);
1196             
1197       display->button_click_time[1] = 0;
1198       display->button_click_time[0] = 0;
1199       display->button_window[1] = NULL;
1200       display->button_window[0] = NULL;
1201       display->button_number[1] = -1;
1202       display->button_number[0] = -1;
1203       display->button_x[0] = display->button_x[1] = 0;
1204       display->button_y[0] = display->button_y[1] = 0;
1205     }
1206   else if ((event->button.time < (display->button_click_time[0] + display->double_click_time)) &&
1207            (event->button.window == display->button_window[0]) &&
1208            (event->button.button == display->button_number[0]) &&
1209            (ABS (event->button.x - display->button_x[0]) <= display->double_click_distance) &&
1210            (ABS (event->button.y - display->button_y[0]) <= display->double_click_distance))
1211     {
1212       gdk_synthesize_click (display, event, 2);
1213       
1214       display->button_click_time[1] = display->button_click_time[0];
1215       display->button_click_time[0] = event->button.time;
1216       display->button_window[1] = display->button_window[0];
1217       display->button_window[0] = event->button.window;
1218       display->button_number[1] = display->button_number[0];
1219       display->button_number[0] = event->button.button;
1220       display->button_x[1] = display->button_x[0];
1221       display->button_x[0] = event->button.x;
1222       display->button_y[1] = display->button_y[0];
1223       display->button_y[0] = event->button.y;
1224     }
1225   else
1226     {
1227       display->button_click_time[1] = 0;
1228       display->button_click_time[0] = event->button.time;
1229       display->button_window[1] = NULL;
1230       display->button_window[0] = event->button.window;
1231       display->button_number[1] = -1;
1232       display->button_number[0] = event->button.button;
1233       display->button_x[1] = 0;
1234       display->button_x[0] = event->button.x;
1235       display->button_y[1] = 0;
1236       display->button_y[0] = event->button.y;
1237     }
1238 }
1239
1240 void
1241 gdk_synthesize_window_state (GdkWindow     *window,
1242                              GdkWindowState unset_flags,
1243                              GdkWindowState set_flags)
1244 {
1245   GdkEvent temp_event;
1246   GdkWindowState old;
1247   
1248   g_return_if_fail (window != NULL);
1249   
1250   temp_event.window_state.window = window;
1251   temp_event.window_state.type = GDK_WINDOW_STATE;
1252   temp_event.window_state.send_event = FALSE;
1253   
1254   old = ((GdkWindowObject*) temp_event.window_state.window)->state;
1255   
1256   temp_event.window_state.new_window_state = old;
1257   temp_event.window_state.new_window_state |= set_flags;
1258   temp_event.window_state.new_window_state &= ~unset_flags;
1259   temp_event.window_state.changed_mask = temp_event.window_state.new_window_state ^ old;
1260
1261   if (temp_event.window_state.new_window_state == old)
1262     return; /* No actual work to do, nothing changed. */
1263
1264   /* Actually update the field in GdkWindow, this is sort of an odd
1265    * place to do it, but seems like the safest since it ensures we expose no
1266    * inconsistent state to the user.
1267    */
1268   
1269   ((GdkWindowObject*) window)->state = temp_event.window_state.new_window_state;
1270
1271   if (temp_event.window_state.changed_mask & GDK_WINDOW_STATE_WITHDRAWN)
1272     _gdk_window_update_viewable (window);
1273
1274   /* We only really send the event to toplevels, since
1275    * all the window states don't apply to non-toplevels.
1276    * Non-toplevels do use the GDK_WINDOW_STATE_WITHDRAWN flag
1277    * internally so we needed to update window->state.
1278    */
1279   switch (((GdkWindowObject*) window)->window_type)
1280     {
1281     case GDK_WINDOW_TOPLEVEL:
1282     case GDK_WINDOW_DIALOG:
1283     case GDK_WINDOW_TEMP: /* ? */
1284       gdk_display_put_event (gdk_drawable_get_display (window), &temp_event);
1285       break;
1286       
1287     case GDK_WINDOW_FOREIGN:
1288     case GDK_WINDOW_ROOT:
1289     case GDK_WINDOW_CHILD:
1290       break;
1291     }
1292 }
1293
1294 /**
1295  * gdk_display_set_double_click_time:
1296  * @display: a #GdkDisplay
1297  * @msec: double click time in milliseconds (thousandths of a second) 
1298  * 
1299  * Sets the double click time (two clicks within this time interval
1300  * count as a double click and result in a #GDK_2BUTTON_PRESS event).
1301  * Applications should <emphasis>not</emphasis> set this, it is a global 
1302  * user-configured setting.
1303  *
1304  * Since: 2.2
1305  **/
1306 void
1307 gdk_display_set_double_click_time (GdkDisplay *display,
1308                                    guint       msec)
1309 {
1310   display->double_click_time = msec;
1311 }
1312
1313 /**
1314  * gdk_set_double_click_time:
1315  * @msec: double click time in milliseconds (thousandths of a second)
1316  *
1317  * Set the double click time for the default display. See
1318  * gdk_display_set_double_click_time(). 
1319  * See also gdk_display_set_double_click_distance().
1320  * Applications should <emphasis>not</emphasis> set this, it is a 
1321  * global user-configured setting.
1322  **/
1323 void
1324 gdk_set_double_click_time (guint msec)
1325 {
1326   gdk_display_set_double_click_time (gdk_display_get_default (), msec);
1327 }
1328
1329 /**
1330  * gdk_display_set_double_click_distance:
1331  * @display: a #GdkDisplay
1332  * @distance: distance in pixels
1333  * 
1334  * Sets the double click distance (two clicks within this distance
1335  * count as a double click and result in a #GDK_2BUTTON_PRESS event).
1336  * See also gdk_display_set_double_click_time().
1337  * Applications should <emphasis>not</emphasis> set this, it is a global 
1338  * user-configured setting.
1339  *
1340  * Since: 2.4
1341  **/
1342 void
1343 gdk_display_set_double_click_distance (GdkDisplay *display,
1344                                        guint       distance)
1345 {
1346   display->double_click_distance = distance;
1347 }
1348
1349 GType
1350 gdk_event_get_type (void)
1351 {
1352   static GType our_type = 0;
1353   
1354   if (our_type == 0)
1355     our_type = g_boxed_type_register_static (g_intern_static_string ("GdkEvent"),
1356                                              (GBoxedCopyFunc)gdk_event_copy,
1357                                              (GBoxedFreeFunc)gdk_event_free);
1358   return our_type;
1359 }
1360
1361 /**
1362  * gdk_setting_get:
1363  * @name: the name of the setting.
1364  * @value: location to store the value of the setting.
1365  *
1366  * Obtains a desktop-wide setting, such as the double-click time,
1367  * for the default screen. See gdk_screen_get_setting().
1368  *
1369  * Returns: %TRUE if the setting existed and a value was stored
1370  *   in @value, %FALSE otherwise.
1371  **/
1372 gboolean
1373 gdk_setting_get (const gchar *name,
1374                  GValue      *value)
1375 {
1376   return gdk_screen_get_setting (gdk_screen_get_default (), name, value);
1377 }
1378
1379 #define __GDK_EVENTS_C__
1380 #include "gdkaliasdef.c"