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