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