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