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