]> Pileus Git - ~andy/gtk/blob - gdk/gdkevents.c
Initial client-side-windows work
[~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       if (event->expose.region)
475         new_event->expose.region = gdk_region_copy (event->expose.region);
476       break;
477       
478     case GDK_SETTING:
479       new_event->setting.name = g_strdup (new_event->setting.name);
480       break;
481
482     case GDK_BUTTON_PRESS:
483     case GDK_BUTTON_RELEASE:
484       if (event->button.axes) 
485         new_event->button.axes = g_memdup (event->button.axes, 
486                                              sizeof (gdouble) * event->button.device->num_axes);
487       break;
488
489     case GDK_MOTION_NOTIFY:
490       if (event->motion.axes) 
491         new_event->motion.axes = g_memdup (event->motion.axes, 
492                                            sizeof (gdouble) * event->motion.device->num_axes);
493       
494       break;
495       
496     default:
497       break;
498     }
499
500   if (gdk_event_is_allocated (event))
501     _gdk_windowing_event_data_copy (event, new_event);
502   
503   return new_event;
504 }
505
506 /**
507  * gdk_event_free:
508  * @event:  a #GdkEvent.
509  * 
510  * Frees a #GdkEvent, freeing or decrementing any resources associated with it.
511  * Note that this function should only be called with events returned from
512  * functions such as gdk_event_peek(), gdk_event_get(),
513  * gdk_event_get_graphics_expose() and gdk_event_copy().
514  **/
515 void
516 gdk_event_free (GdkEvent *event)
517 {
518   g_return_if_fail (event != NULL);
519
520   if (event->any.window)
521     g_object_unref (event->any.window);
522   
523   switch (event->any.type)
524     {
525     case GDK_KEY_PRESS:
526     case GDK_KEY_RELEASE:
527       g_free (event->key.string);
528       break;
529       
530     case GDK_ENTER_NOTIFY:
531     case GDK_LEAVE_NOTIFY:
532       if (event->crossing.subwindow != NULL)
533         g_object_unref (event->crossing.subwindow);
534       break;
535       
536     case GDK_DRAG_ENTER:
537     case GDK_DRAG_LEAVE:
538     case GDK_DRAG_MOTION:
539     case GDK_DRAG_STATUS:
540     case GDK_DROP_START:
541     case GDK_DROP_FINISHED:
542       g_object_unref (event->dnd.context);
543       break;
544
545     case GDK_BUTTON_PRESS:
546     case GDK_BUTTON_RELEASE:
547       g_free (event->button.axes);
548       break;
549       
550     case GDK_EXPOSE:
551       if (event->expose.region)
552         gdk_region_destroy (event->expose.region);
553       break;
554       
555     case GDK_MOTION_NOTIFY:
556       g_free (event->motion.axes);
557       break;
558       
559     case GDK_SETTING:
560       g_free (event->setting.name);
561       break;
562       
563     default:
564       break;
565     }
566
567   _gdk_windowing_event_data_free (event);
568
569   g_hash_table_remove (event_hash, event);
570   g_slice_free (GdkEventPrivate, (GdkEventPrivate*) event);
571 }
572
573 /**
574  * gdk_event_get_time:
575  * @event: a #GdkEvent
576  * 
577  * Returns the time stamp from @event, if there is one; otherwise
578  * returns #GDK_CURRENT_TIME. If @event is %NULL, returns #GDK_CURRENT_TIME.
579  * 
580  * Return value: time stamp field from @event
581  **/
582 guint32
583 gdk_event_get_time (const GdkEvent *event)
584 {
585   if (event)
586     switch (event->type)
587       {
588       case GDK_MOTION_NOTIFY:
589         return event->motion.time;
590       case GDK_BUTTON_PRESS:
591       case GDK_2BUTTON_PRESS:
592       case GDK_3BUTTON_PRESS:
593       case GDK_BUTTON_RELEASE:
594         return event->button.time;
595       case GDK_SCROLL:
596         return event->scroll.time;
597       case GDK_KEY_PRESS:
598       case GDK_KEY_RELEASE:
599         return event->key.time;
600       case GDK_ENTER_NOTIFY:
601       case GDK_LEAVE_NOTIFY:
602         return event->crossing.time;
603       case GDK_PROPERTY_NOTIFY:
604         return event->property.time;
605       case GDK_SELECTION_CLEAR:
606       case GDK_SELECTION_REQUEST:
607       case GDK_SELECTION_NOTIFY:
608         return event->selection.time;
609       case GDK_PROXIMITY_IN:
610       case GDK_PROXIMITY_OUT:
611         return event->proximity.time;
612       case GDK_DRAG_ENTER:
613       case GDK_DRAG_LEAVE:
614       case GDK_DRAG_MOTION:
615       case GDK_DRAG_STATUS:
616       case GDK_DROP_START:
617       case GDK_DROP_FINISHED:
618         return event->dnd.time;
619       case GDK_CLIENT_EVENT:
620       case GDK_VISIBILITY_NOTIFY:
621       case GDK_NO_EXPOSE:
622       case GDK_CONFIGURE:
623       case GDK_FOCUS_CHANGE:
624       case GDK_NOTHING:
625       case GDK_DAMAGE:
626       case GDK_DELETE:
627       case GDK_DESTROY:
628       case GDK_EXPOSE:
629       case GDK_MAP:
630       case GDK_UNMAP:
631       case GDK_WINDOW_STATE:
632       case GDK_SETTING:
633       case GDK_OWNER_CHANGE:
634       case GDK_GRAB_BROKEN:
635         /* return current time */
636         break;
637       }
638   
639   return GDK_CURRENT_TIME;
640 }
641
642 /**
643  * gdk_event_get_state:
644  * @event: a #GdkEvent or NULL
645  * @state: return location for state
646  * 
647  * If the event contains a "state" field, puts that field in @state. Otherwise
648  * stores an empty state (0). Returns %TRUE if there was a state field
649  * in the event. @event may be %NULL, in which case it's treated
650  * as if the event had no state field.
651  * 
652  * Return value: %TRUE if there was a state field in the event 
653  **/
654 gboolean
655 gdk_event_get_state (const GdkEvent        *event,
656                      GdkModifierType       *state)
657 {
658   g_return_val_if_fail (state != NULL, FALSE);
659   
660   if (event)
661     switch (event->type)
662       {
663       case GDK_MOTION_NOTIFY:
664         *state = event->motion.state;
665         return TRUE;
666       case GDK_BUTTON_PRESS:
667       case GDK_2BUTTON_PRESS:
668       case GDK_3BUTTON_PRESS:
669       case GDK_BUTTON_RELEASE:
670         *state =  event->button.state;
671         return TRUE;
672       case GDK_SCROLL:
673         *state =  event->scroll.state;
674         return TRUE;
675       case GDK_KEY_PRESS:
676       case GDK_KEY_RELEASE:
677         *state =  event->key.state;
678         return TRUE;
679       case GDK_ENTER_NOTIFY:
680       case GDK_LEAVE_NOTIFY:
681         *state =  event->crossing.state;
682         return TRUE;
683       case GDK_PROPERTY_NOTIFY:
684         *state =  event->property.state;
685         return TRUE;
686       case GDK_VISIBILITY_NOTIFY:
687       case GDK_CLIENT_EVENT:
688       case GDK_NO_EXPOSE:
689       case GDK_CONFIGURE:
690       case GDK_FOCUS_CHANGE:
691       case GDK_SELECTION_CLEAR:
692       case GDK_SELECTION_REQUEST:
693       case GDK_SELECTION_NOTIFY:
694       case GDK_PROXIMITY_IN:
695       case GDK_PROXIMITY_OUT:
696       case GDK_DAMAGE:
697       case GDK_DRAG_ENTER:
698       case GDK_DRAG_LEAVE:
699       case GDK_DRAG_MOTION:
700       case GDK_DRAG_STATUS:
701       case GDK_DROP_START:
702       case GDK_DROP_FINISHED:
703       case GDK_NOTHING:
704       case GDK_DELETE:
705       case GDK_DESTROY:
706       case GDK_EXPOSE:
707       case GDK_MAP:
708       case GDK_UNMAP:
709       case GDK_WINDOW_STATE:
710       case GDK_SETTING:
711       case GDK_OWNER_CHANGE:
712       case GDK_GRAB_BROKEN:
713         /* no state field */
714         break;
715       }
716
717   *state = 0;
718   return FALSE;
719 }
720
721 /**
722  * gdk_event_get_coords:
723  * @event: a #GdkEvent
724  * @x_win: location to put event window x coordinate
725  * @y_win: location to put event window y coordinate
726  * 
727  * Extract the event window relative x/y coordinates from an event.
728  * 
729  * Return value: %TRUE if the event delivered event window coordinates
730  **/
731 gboolean
732 gdk_event_get_coords (const GdkEvent *event,
733                       gdouble        *x_win,
734                       gdouble        *y_win)
735 {
736   gdouble x = 0, y = 0;
737   gboolean fetched = TRUE;
738   
739   g_return_val_if_fail (event != NULL, FALSE);
740
741   switch (event->type)
742     {
743     case GDK_CONFIGURE:
744       x = event->configure.x;
745       y = event->configure.y;
746       break;
747     case GDK_ENTER_NOTIFY:
748     case GDK_LEAVE_NOTIFY:
749       x = event->crossing.x;
750       y = event->crossing.y;
751       break;
752     case GDK_SCROLL:
753       x = event->scroll.x;
754       y = event->scroll.y;
755       break;
756     case GDK_BUTTON_PRESS:
757     case GDK_2BUTTON_PRESS:
758     case GDK_3BUTTON_PRESS:
759     case GDK_BUTTON_RELEASE:
760       x = event->button.x;
761       y = event->button.y;
762       break;
763     case GDK_MOTION_NOTIFY:
764       x = event->motion.x;
765       y = event->motion.y;
766       break;
767     default:
768       fetched = FALSE;
769       break;
770     }
771
772   if (x_win)
773     *x_win = x;
774   if (y_win)
775     *y_win = y;
776
777   return fetched;
778 }
779
780 /**
781  * gdk_event_get_root_coords:
782  * @event: a #GdkEvent
783  * @x_root: location to put root window x coordinate
784  * @y_root: location to put root window y coordinate
785  * 
786  * Extract the root window relative x/y coordinates from an event.
787  * 
788  * Return value: %TRUE if the event delivered root window coordinates
789  **/
790 gboolean
791 gdk_event_get_root_coords (const GdkEvent *event,
792                            gdouble        *x_root,
793                            gdouble        *y_root)
794 {
795   gdouble x = 0, y = 0;
796   gboolean fetched = TRUE;
797   
798   g_return_val_if_fail (event != NULL, FALSE);
799
800   switch (event->type)
801     {
802     case GDK_MOTION_NOTIFY:
803       x = event->motion.x_root;
804       y = event->motion.y_root;
805       break;
806     case GDK_SCROLL:
807       x = event->scroll.x_root;
808       y = event->scroll.y_root;
809       break;
810     case GDK_BUTTON_PRESS:
811     case GDK_2BUTTON_PRESS:
812     case GDK_3BUTTON_PRESS:
813     case GDK_BUTTON_RELEASE:
814       x = event->button.x_root;
815       y = event->button.y_root;
816       break;
817     case GDK_ENTER_NOTIFY:
818     case GDK_LEAVE_NOTIFY:
819       x = event->crossing.x_root;
820       y = event->crossing.y_root;
821       break;
822     case GDK_DRAG_ENTER:
823     case GDK_DRAG_LEAVE:
824     case GDK_DRAG_MOTION:
825     case GDK_DRAG_STATUS:
826     case GDK_DROP_START:
827     case GDK_DROP_FINISHED:
828       x = event->dnd.x_root;
829       y = event->dnd.y_root;
830       break;
831     default:
832       fetched = FALSE;
833       break;
834     }
835
836   if (x_root)
837     *x_root = x;
838   if (y_root)
839     *y_root = y;
840
841   return fetched;
842 }
843
844 /**
845  * gdk_event_get_axis:
846  * @event: a #GdkEvent
847  * @axis_use: the axis use to look for
848  * @value: location to store the value found
849  * 
850  * Extract the axis value for a particular axis use from
851  * an event structure.
852  * 
853  * Return value: %TRUE if the specified axis was found, otherwise %FALSE
854  **/
855 gboolean
856 gdk_event_get_axis (const GdkEvent *event,
857                     GdkAxisUse      axis_use,
858                     gdouble        *value)
859 {
860   gdouble *axes;
861   GdkDevice *device;
862   
863   g_return_val_if_fail (event != NULL, FALSE);
864   
865   if (axis_use == GDK_AXIS_X || axis_use == GDK_AXIS_Y)
866     {
867       gdouble x, y;
868       
869       switch (event->type)
870         {
871         case GDK_MOTION_NOTIFY:
872           x = event->motion.x;
873           y = event->motion.y;
874           break;
875         case GDK_SCROLL:
876           x = event->scroll.x;
877           y = event->scroll.y;
878           break;
879         case GDK_BUTTON_PRESS:
880         case GDK_BUTTON_RELEASE:
881           x = event->button.x;
882           y = event->button.y;
883           break;
884         case GDK_ENTER_NOTIFY:
885         case GDK_LEAVE_NOTIFY:
886           x = event->crossing.x;
887           y = event->crossing.y;
888           break;
889           
890         default:
891           return FALSE;
892         }
893
894       if (axis_use == GDK_AXIS_X && value)
895         *value = x;
896       if (axis_use == GDK_AXIS_Y && value)
897         *value = y;
898
899       return TRUE;
900     }
901   else if (event->type == GDK_BUTTON_PRESS ||
902            event->type == GDK_BUTTON_RELEASE)
903     {
904       device = event->button.device;
905       axes = event->button.axes;
906     }
907   else if (event->type == GDK_MOTION_NOTIFY)
908     {
909       device = event->motion.device;
910       axes = event->motion.axes;
911     }
912   else
913     return FALSE;
914
915   return gdk_device_get_axis (device, axes, axis_use, value);
916 }
917
918 /**
919  * gdk_event_request_motions:
920  * @event: a valid #GdkEvent
921  *
922  * Request more motion notifies if @event is a motion notify hint event.
923  * This function should be used instead of gdk_window_get_pointer() to
924  * request further motion notifies, because it also works for extension
925  * events where motion notifies are provided for devices other than the
926  * core pointer. Coordinate extraction, processing and requesting more
927  * motion events from a %GDK_MOTION_NOTIFY event usually works like this:
928  *
929  * |[
930  * { 
931  *   /&ast; motion_event handler &ast;/
932  *   x = motion_event->x;
933  *   y = motion_event->y;
934  *   /&ast; handle (x,y) motion &ast;/
935  *   gdk_event_request_motions (motion_event); /&ast; handles is_hint events &ast;/
936  * }
937  * ]|
938  *
939  * Since: 2.12
940  **/
941 void
942 gdk_event_request_motions (const GdkEventMotion *event)
943 {
944   g_return_if_fail (event != NULL);
945   if (event->type == GDK_MOTION_NOTIFY && event->is_hint)
946     gdk_device_get_state (event->device, event->window, NULL, NULL);
947 }
948
949 /**
950  * gdk_event_set_screen:
951  * @event: a #GdkEvent
952  * @screen: a #GdkScreen
953  * 
954  * Sets the screen for @event to @screen. The event must
955  * have been allocated by GTK+, for instance, by
956  * gdk_event_copy().
957  *
958  * Since: 2.2
959  **/
960 void
961 gdk_event_set_screen (GdkEvent  *event,
962                       GdkScreen *screen)
963 {
964   GdkEventPrivate *private;
965   
966   g_return_if_fail (gdk_event_is_allocated (event));
967
968   private = (GdkEventPrivate *)event;
969   
970   private->screen = screen;
971 }
972
973 /**
974  * gdk_event_get_screen:
975  * @event: a #GdkEvent
976  * 
977  * Returns the screen for the event. The screen is
978  * typically the screen for <literal>event->any.window</literal>, but
979  * for events such as mouse events, it is the screen
980  * where the pointer was when the event occurs -
981  * that is, the screen which has the root window 
982  * to which <literal>event->motion.x_root</literal> and
983  * <literal>event->motion.y_root</literal> are relative.
984  * 
985  * Return value: the screen for the event
986  *
987  * Since: 2.2
988  **/
989 GdkScreen *
990 gdk_event_get_screen (const GdkEvent *event)
991 {
992   if (gdk_event_is_allocated (event))
993     {
994       GdkEventPrivate *private = (GdkEventPrivate *)event;
995
996       if (private->screen)
997         return private->screen;
998     }
999
1000   if (event->any.window)
1001     return gdk_drawable_get_screen (event->any.window);
1002
1003   return NULL;
1004 }
1005
1006 /**
1007  * gdk_set_show_events:
1008  * @show_events:  %TRUE to output event debugging information.
1009  * 
1010  * Sets whether a trace of received events is output.
1011  * Note that GTK+ must be compiled with debugging (that is,
1012  * configured using the <option>--enable-debug</option> option)
1013  * to use this option.
1014  **/
1015 void
1016 gdk_set_show_events (gboolean show_events)
1017 {
1018   if (show_events)
1019     _gdk_debug_flags |= GDK_DEBUG_EVENTS;
1020   else
1021     _gdk_debug_flags &= ~GDK_DEBUG_EVENTS;
1022 }
1023
1024 /**
1025  * gdk_get_show_events:
1026  * 
1027  * Gets whether event debugging output is enabled.
1028  * 
1029  * Return value: %TRUE if event debugging output is enabled.
1030  **/
1031 gboolean
1032 gdk_get_show_events (void)
1033 {
1034   return (_gdk_debug_flags & GDK_DEBUG_EVENTS) != 0;
1035 }
1036
1037 static void
1038 gdk_io_destroy (gpointer data)
1039 {
1040   GdkIOClosure *closure = data;
1041
1042   if (closure->notify)
1043     closure->notify (closure->data);
1044
1045   g_free (closure);
1046 }
1047
1048 /* What do we do with G_IO_NVAL?
1049  */
1050 #define READ_CONDITION (G_IO_IN | G_IO_HUP | G_IO_ERR)
1051 #define WRITE_CONDITION (G_IO_OUT | G_IO_ERR)
1052 #define EXCEPTION_CONDITION (G_IO_PRI)
1053
1054 static gboolean  
1055 gdk_io_invoke (GIOChannel   *source,
1056                GIOCondition  condition,
1057                gpointer      data)
1058 {
1059   GdkIOClosure *closure = data;
1060   GdkInputCondition gdk_cond = 0;
1061
1062   if (condition & READ_CONDITION)
1063     gdk_cond |= GDK_INPUT_READ;
1064   if (condition & WRITE_CONDITION)
1065     gdk_cond |= GDK_INPUT_WRITE;
1066   if (condition & EXCEPTION_CONDITION)
1067     gdk_cond |= GDK_INPUT_EXCEPTION;
1068
1069   if (closure->condition & gdk_cond)
1070     closure->function (closure->data, g_io_channel_unix_get_fd (source), gdk_cond);
1071
1072   return TRUE;
1073 }
1074
1075 /**
1076  * gdk_input_add_full:
1077  * @source: a file descriptor.
1078  * @condition: the condition.
1079  * @function: the callback function.
1080  * @data: callback data passed to @function.
1081  * @destroy: callback function to call with @data when the input
1082  * handler is removed.
1083  *
1084  * Establish a callback when a condition becomes true on
1085  * a file descriptor.
1086  *
1087  * Returns: a tag that can later be used as an argument to
1088  * gdk_input_remove().
1089  *
1090  * Deprecated: Use g_io_add_watch_full() on a #GIOChannel
1091  */
1092 gint
1093 gdk_input_add_full (gint              source,
1094                     GdkInputCondition condition,
1095                     GdkInputFunction  function,
1096                     gpointer          data,
1097                     GDestroyNotify    destroy)
1098 {
1099   guint result;
1100   GdkIOClosure *closure = g_new (GdkIOClosure, 1);
1101   GIOChannel *channel;
1102   GIOCondition cond = 0;
1103
1104   closure->function = function;
1105   closure->condition = condition;
1106   closure->notify = destroy;
1107   closure->data = data;
1108
1109   if (condition & GDK_INPUT_READ)
1110     cond |= READ_CONDITION;
1111   if (condition & GDK_INPUT_WRITE)
1112     cond |= WRITE_CONDITION;
1113   if (condition & GDK_INPUT_EXCEPTION)
1114     cond |= EXCEPTION_CONDITION;
1115
1116   channel = g_io_channel_unix_new (source);
1117   result = g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, cond, 
1118                                 gdk_io_invoke,
1119                                 closure, gdk_io_destroy);
1120   g_io_channel_unref (channel);
1121
1122   return result;
1123 }
1124
1125 /**
1126  * gdk_input_add:
1127  * @source: a file descriptor.
1128  * @condition: the condition.
1129  * @function: the callback function.
1130  * @data: callback data passed to @function.
1131  *
1132  * Establish a callback when a condition becomes true on
1133  * a file descriptor.
1134  *
1135  * Returns: a tag that can later be used as an argument to
1136  * gdk_input_remove().
1137  *
1138  * Deprecated: Use g_io_add_watch() on a #GIOChannel
1139  */
1140 gint
1141 gdk_input_add (gint              source,
1142                GdkInputCondition condition,
1143                GdkInputFunction  function,
1144                gpointer          data)
1145 {
1146   return gdk_input_add_full (source, condition, function, data, NULL);
1147 }
1148
1149 void
1150 gdk_input_remove (gint tag)
1151 {
1152   g_source_remove (tag);
1153 }
1154
1155 static void
1156 gdk_synthesize_click (GdkDisplay *display,
1157                       GdkEvent   *event,
1158                       gint        nclicks)
1159 {
1160   GdkEvent temp_event;
1161   GdkEvent *event_copy;
1162   GList *link;
1163   
1164   g_return_if_fail (event != NULL);
1165   
1166   temp_event = *event;
1167   temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
1168
1169   event_copy = gdk_event_copy (&temp_event);
1170   link = _gdk_event_queue_append (display, event_copy);
1171 }
1172
1173 void
1174 _gdk_event_button_generate (GdkDisplay *display,
1175                             GdkEvent   *event)
1176 {
1177   if ((event->button.time < (display->button_click_time[1] + 2*display->double_click_time)) &&
1178       (event->button.window == display->button_window[1]) &&
1179       (event->button.button == display->button_number[1]) &&
1180       (ABS (event->button.x - display->button_x[1]) <= display->double_click_distance) &&
1181       (ABS (event->button.y - display->button_y[1]) <= display->double_click_distance))
1182 {
1183       gdk_synthesize_click (display, event, 3);
1184             
1185       display->button_click_time[1] = 0;
1186       display->button_click_time[0] = 0;
1187       display->button_window[1] = NULL;
1188       display->button_window[0] = NULL;
1189       display->button_number[1] = -1;
1190       display->button_number[0] = -1;
1191       display->button_x[0] = display->button_x[1] = 0;
1192       display->button_y[0] = display->button_y[1] = 0;
1193     }
1194   else if ((event->button.time < (display->button_click_time[0] + display->double_click_time)) &&
1195            (event->button.window == display->button_window[0]) &&
1196            (event->button.button == display->button_number[0]) &&
1197            (ABS (event->button.x - display->button_x[0]) <= display->double_click_distance) &&
1198            (ABS (event->button.y - display->button_y[0]) <= display->double_click_distance))
1199     {
1200       gdk_synthesize_click (display, event, 2);
1201       
1202       display->button_click_time[1] = display->button_click_time[0];
1203       display->button_click_time[0] = event->button.time;
1204       display->button_window[1] = display->button_window[0];
1205       display->button_window[0] = event->button.window;
1206       display->button_number[1] = display->button_number[0];
1207       display->button_number[0] = event->button.button;
1208       display->button_x[1] = display->button_x[0];
1209       display->button_x[0] = event->button.x;
1210       display->button_y[1] = display->button_y[0];
1211       display->button_y[0] = event->button.y;
1212     }
1213   else
1214     {
1215       display->button_click_time[1] = 0;
1216       display->button_click_time[0] = event->button.time;
1217       display->button_window[1] = NULL;
1218       display->button_window[0] = event->button.window;
1219       display->button_number[1] = -1;
1220       display->button_number[0] = event->button.button;
1221       display->button_x[1] = 0;
1222       display->button_x[0] = event->button.x;
1223       display->button_y[1] = 0;
1224       display->button_y[0] = event->button.y;
1225     }
1226 }
1227
1228 void
1229 gdk_synthesize_window_state (GdkWindow     *window,
1230                              GdkWindowState unset_flags,
1231                              GdkWindowState set_flags)
1232 {
1233   GdkEvent temp_event;
1234   GdkWindowState old;
1235   
1236   g_return_if_fail (window != NULL);
1237   
1238   temp_event.window_state.window = window;
1239   temp_event.window_state.type = GDK_WINDOW_STATE;
1240   temp_event.window_state.send_event = FALSE;
1241   
1242   old = ((GdkWindowObject*) temp_event.window_state.window)->state;
1243   
1244   temp_event.window_state.new_window_state = old;
1245   temp_event.window_state.new_window_state |= set_flags;
1246   temp_event.window_state.new_window_state &= ~unset_flags;
1247   temp_event.window_state.changed_mask = temp_event.window_state.new_window_state ^ old;
1248
1249   if (temp_event.window_state.new_window_state == old)
1250     return; /* No actual work to do, nothing changed. */
1251
1252   /* Actually update the field in GdkWindow, this is sort of an odd
1253    * place to do it, but seems like the safest since it ensures we expose no
1254    * inconsistent state to the user.
1255    */
1256   
1257   ((GdkWindowObject*) window)->state = temp_event.window_state.new_window_state;
1258
1259   /* We only really send the event to toplevels, since
1260    * all the window states don't apply to non-toplevels.
1261    * Non-toplevels do use the GDK_WINDOW_STATE_WITHDRAWN flag
1262    * internally so we needed to update window->state.
1263    */
1264   switch (((GdkWindowObject*) window)->window_type)
1265     {
1266     case GDK_WINDOW_TOPLEVEL:
1267     case GDK_WINDOW_DIALOG:
1268     case GDK_WINDOW_TEMP: /* ? */
1269       gdk_display_put_event (gdk_drawable_get_display (window), &temp_event);
1270       break;
1271       
1272     case GDK_WINDOW_FOREIGN:
1273     case GDK_WINDOW_ROOT:
1274     case GDK_WINDOW_CHILD:
1275       break;
1276     }
1277 }
1278
1279 /**
1280  * gdk_display_set_double_click_time:
1281  * @display: a #GdkDisplay
1282  * @msec: double click time in milliseconds (thousandths of a second) 
1283  * 
1284  * Sets the double click time (two clicks within this time interval
1285  * count as a double click and result in a #GDK_2BUTTON_PRESS event).
1286  * Applications should <emphasis>not</emphasis> set this, it is a global 
1287  * user-configured setting.
1288  *
1289  * Since: 2.2
1290  **/
1291 void
1292 gdk_display_set_double_click_time (GdkDisplay *display,
1293                                    guint       msec)
1294 {
1295   display->double_click_time = msec;
1296 }
1297
1298 /**
1299  * gdk_set_double_click_time:
1300  * @msec: double click time in milliseconds (thousandths of a second)
1301  *
1302  * Set the double click time for the default display. See
1303  * gdk_display_set_double_click_time(). 
1304  * See also gdk_display_set_double_click_distance().
1305  * Applications should <emphasis>not</emphasis> set this, it is a 
1306  * global user-configured setting.
1307  **/
1308 void
1309 gdk_set_double_click_time (guint msec)
1310 {
1311   gdk_display_set_double_click_time (gdk_display_get_default (), msec);
1312 }
1313
1314 /**
1315  * gdk_display_set_double_click_distance:
1316  * @display: a #GdkDisplay
1317  * @distance: distance in pixels
1318  * 
1319  * Sets the double click distance (two clicks within this distance
1320  * count as a double click and result in a #GDK_2BUTTON_PRESS event).
1321  * See also gdk_display_set_double_click_time().
1322  * Applications should <emphasis>not</emphasis> set this, it is a global 
1323  * user-configured setting.
1324  *
1325  * Since: 2.4
1326  **/
1327 void
1328 gdk_display_set_double_click_distance (GdkDisplay *display,
1329                                        guint       distance)
1330 {
1331   display->double_click_distance = distance;
1332 }
1333
1334 GType
1335 gdk_event_get_type (void)
1336 {
1337   static GType our_type = 0;
1338   
1339   if (our_type == 0)
1340     our_type = g_boxed_type_register_static (g_intern_static_string ("GdkEvent"),
1341                                              (GBoxedCopyFunc)gdk_event_copy,
1342                                              (GBoxedFreeFunc)gdk_event_free);
1343   return our_type;
1344 }
1345
1346 /**
1347  * gdk_setting_get:
1348  * @name: the name of the setting.
1349  * @value: location to store the value of the setting.
1350  *
1351  * Obtains a desktop-wide setting, such as the double-click time,
1352  * for the default screen. See gdk_screen_get_setting().
1353  *
1354  * Returns: %TRUE if the setting existed and a value was stored
1355  *   in @value, %FALSE otherwise.
1356  **/
1357 gboolean
1358 gdk_setting_get (const gchar *name,
1359                  GValue      *value)
1360 {
1361   return gdk_screen_get_setting (gdk_screen_get_default (), name, value);
1362 }
1363
1364 #define __GDK_EVENTS_C__
1365 #include "gdkaliasdef.c"