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