]> Pileus Git - ~andy/gtk/blob - gdk/gdkevents.c
Added notice to look in AUTHORS and ChangeLog files for a list of changes.
[~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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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-1999.  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 "gdkx.h"
29 #include "gdkprivate.h"
30 #include "gdkinput.h"
31 #include "gdkkeysyms.h"
32
33 #if HAVE_CONFIG_H
34 #  include <config.h>
35 #  if STDC_HEADERS
36 #    include <string.h>
37 #  endif
38 #endif
39
40
41 typedef struct _GdkIOClosure GdkIOClosure;
42 typedef struct _GdkEventPrivate GdkEventPrivate;
43
44 #define DOUBLE_CLICK_TIME      250
45 #define TRIPLE_CLICK_TIME      500
46 #define DOUBLE_CLICK_DIST      5
47 #define TRIPLE_CLICK_DIST      5
48
49 typedef enum
50 {
51   /* Following flag is set for events on the event queue during
52    * translation and cleared afterwards.
53    */
54   GDK_EVENT_PENDING = 1 << 0
55 } GdkEventFlags;
56
57 struct _GdkIOClosure
58 {
59   GdkInputFunction function;
60   GdkInputCondition condition;
61   GdkDestroyNotify notify;
62   gpointer data;
63 };
64
65 struct _GdkEventPrivate
66 {
67   GdkEvent event;
68   guint    flags;
69 };
70
71 /* 
72  * Private function declarations
73  */
74
75 static GdkEvent *gdk_event_new          (void);
76 static gint      gdk_event_apply_filters (XEvent   *xevent,
77                                           GdkEvent *event,
78                                           GList    *filters);
79 static gint      gdk_event_translate     (GdkEvent *event, 
80                                           XEvent   *xevent);
81 #if 0
82 static Bool      gdk_event_get_type     (Display   *display, 
83                                          XEvent    *xevent, 
84                                          XPointer   arg);
85 #endif
86 static void      gdk_events_queue       (void);
87 static GdkEvent* gdk_event_unqueue      (void);
88
89 static gboolean  gdk_event_prepare      (gpointer   source_data, 
90                                          GTimeVal  *current_time,
91                                          gint      *timeout);
92 static gboolean  gdk_event_check        (gpointer   source_data,
93                                          GTimeVal  *current_time);
94 static gboolean  gdk_event_dispatch     (gpointer   source_data,
95                                          GTimeVal  *current_time,
96                                          gpointer   user_data);
97
98 static void      gdk_synthesize_click   (GdkEvent  *event, 
99                                          gint       nclicks);
100
101 GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev,
102                                          GdkEvent  *event,
103                                          gpointer   data);
104
105 /* Private variable declarations
106  */
107
108 static int connection_number = 0;           /* The file descriptor number of our
109                                              *  connection to the X server. This
110                                              *  is used so that we may determine
111                                              *  when events are pending by using
112                                              *  the "select" system call.
113                                              */
114 static guint32 button_click_time[2];        /* The last 2 button click times. Used
115                                              *  to determine if the latest button click
116                                              *  is part of a double or triple click.
117                                              */
118 static GdkWindow *button_window[2];         /* The last 2 windows to receive button presses.
119                                              *  Also used to determine if the latest button
120                                              *  click is part of a double or triple click.
121                                              */
122 static guint button_number[2];              /* The last 2 buttons to be pressed.
123                                              */
124 static GdkEventFunc   event_func = NULL;    /* Callback for events */
125 static gpointer       event_data = NULL;
126 static GDestroyNotify event_notify = NULL;
127
128 static GList *client_filters;               /* Filters for client messages */
129
130 /* FIFO's for event queue, and for events put back using
131  * gdk_event_put().
132  */
133 static GList *queued_events = NULL;
134 static GList *queued_tail = NULL;
135
136 static GSourceFuncs event_funcs = {
137   gdk_event_prepare,
138   gdk_event_check,
139   gdk_event_dispatch,
140   (GDestroyNotify)g_free
141 };
142
143 GPollFD event_poll_fd;
144
145 /*********************************************
146  * Functions for maintaining the event queue *
147  *********************************************/
148
149 /*************************************************************
150  * gdk_event_queue_find_first:
151  *     Find the first event on the queue that is not still
152  *     being filled in.
153  *   arguments:
154  *     
155  *   results:
156  *     Pointer to the list node for that event, or NULL
157  *************************************************************/
158
159 static GList*
160 gdk_event_queue_find_first (void)
161 {
162   GList *tmp_list = queued_events;
163
164   while (tmp_list)
165     {
166       GdkEventPrivate *event = tmp_list->data;
167       if (!(event->flags & GDK_EVENT_PENDING))
168         return tmp_list;
169
170       tmp_list = g_list_next (tmp_list);
171     }
172
173   return NULL;
174 }
175
176 /*************************************************************
177  * gdk_event_queue_remove_link:
178  *     Remove a specified list node from the event queue.
179  *   arguments:
180  *     node: Node to remove.
181  *   results:
182  *************************************************************/
183
184 static void
185 gdk_event_queue_remove_link (GList *node)
186 {
187   if (node->prev)
188     node->prev->next = node->next;
189   else
190     queued_events = node->next;
191   
192   if (node->next)
193     node->next->prev = node->prev;
194   else
195     queued_tail = node->prev;
196   
197 }
198
199 /*************************************************************
200  * gdk_event_queue_append:
201  *     Append an event onto the tail of the event queue.
202  *   arguments:
203  *     event: Event to append.
204  *   results:
205  *************************************************************/
206
207 static void
208 gdk_event_queue_append (GdkEvent *event)
209 {
210   queued_tail = g_list_append (queued_tail, event);
211   
212   if (!queued_events)
213     queued_events = queued_tail;
214   else
215     queued_tail = queued_tail->next;
216 }
217
218 void 
219 gdk_events_init (void)
220 {
221   connection_number = ConnectionNumber (gdk_display);
222   GDK_NOTE (MISC,
223             g_message ("connection number: %d", connection_number));
224
225   g_source_add (GDK_PRIORITY_EVENTS, TRUE, &event_funcs, NULL, NULL, NULL);
226
227   event_poll_fd.fd = connection_number;
228   event_poll_fd.events = G_IO_IN;
229   
230   g_main_add_poll (&event_poll_fd, GDK_PRIORITY_EVENTS);
231
232   button_click_time[0] = 0;
233   button_click_time[1] = 0;
234   button_window[0] = NULL;
235   button_window[1] = NULL;
236   button_number[0] = -1;
237   button_number[1] = -1;
238
239   gdk_add_client_message_filter (gdk_wm_protocols, 
240                                  gdk_wm_protocols_filter, NULL);
241 }
242
243 /*
244  *--------------------------------------------------------------
245  * gdk_events_pending
246  *
247  *   Returns if events are pending on the queue.
248  *
249  * Arguments:
250  *
251  * Results:
252  *   Returns TRUE if events are pending
253  *
254  * Side effects:
255  *
256  *--------------------------------------------------------------
257  */
258
259 gboolean
260 gdk_events_pending (void)
261 {
262   return (gdk_event_queue_find_first() || XPending (gdk_display));
263 }
264
265 /*
266  *--------------------------------------------------------------
267  * gdk_event_get_graphics_expose
268  *
269  *   Waits for a GraphicsExpose or NoExpose event
270  *
271  * Arguments:
272  *
273  * Results: 
274  *   For GraphicsExpose events, returns a pointer to the event
275  *   converted into a GdkEvent Otherwise, returns NULL.
276  *
277  * Side effects:
278  *
279  *-------------------------------------------------------------- */
280
281 static Bool
282 graphics_expose_predicate (Display  *display,
283                            XEvent   *xevent,
284                            XPointer  arg)
285 {
286   GdkWindowPrivate *private = (GdkWindowPrivate*) arg;
287   
288   g_return_val_if_fail (private != NULL, False);
289   
290   if (xevent->xany.window == private->xwindow &&
291       (xevent->xany.type == GraphicsExpose ||
292        xevent->xany.type == NoExpose))
293     return True;
294   else
295     return False;
296 }
297
298 GdkEvent*
299 gdk_event_get_graphics_expose (GdkWindow *window)
300 {
301   XEvent xevent;
302   GdkEvent *event;
303   
304   g_return_val_if_fail (window != NULL, NULL);
305   
306   XIfEvent (gdk_display, &xevent, graphics_expose_predicate, (XPointer) window);
307   
308   if (xevent.xany.type == GraphicsExpose)
309     {
310       event = gdk_event_new ();
311       
312       if (gdk_event_translate (event, &xevent))
313         return event;
314       else
315         gdk_event_free (event);
316     }
317   
318   return NULL;  
319 }
320
321 /************************
322  * Exposure compression *
323  ************************/
324
325 /*
326  * The following implements simple exposure compression. It is
327  * modelled after the way Xt does exposure compression - in
328  * particular compress_expose = XtExposeCompressMultiple.
329  * It compress consecutive sequences of exposure events,
330  * but not sequences that cross other events. (This is because
331  * if it crosses a ConfigureNotify, we could screw up and
332  * mistakenly compress the exposures generated for the new
333  * size - could we just check for ConfigureNotify?)
334  *
335  * Xt compresses to a region / bounding rectangle, we compress
336  * to two rectangles, and try find the two rectangles of minimal
337  * area for this - this is supposed to handle the typical
338  * L-shaped regions generated by OpaqueMove.
339  */
340
341 /* Given three rectangles, find the two rectangles that cover
342  * them with the smallest area.
343  */
344 static void
345 gdk_add_rect_to_rects (GdkRectangle *rect1,
346                        GdkRectangle *rect2, 
347                        GdkRectangle *new_rect)
348 {
349   GdkRectangle t1, t2, t3;
350   gint size1, size2, size3;
351
352   gdk_rectangle_union (rect1, rect2, &t1);
353   gdk_rectangle_union (rect1, new_rect, &t2);
354   gdk_rectangle_union (rect2, new_rect, &t3);
355
356   size1 = t1.width * t1.height + new_rect->width * new_rect->height;
357   size2 = t2.width * t2.height + rect2->width * rect2->height;
358   size3 = t1.width * t1.height + rect1->width * rect1->height;
359
360   if (size1 < size2)
361     {
362       if (size1 < size3)
363         {
364           *rect1 = t1;
365           *rect2 = *new_rect;
366         }
367       else
368         *rect2 = t3;
369     }
370   else
371     {
372       if (size2 < size3)
373         *rect1 = t2;
374       else
375         *rect2 = t3;
376     }
377 }
378
379 typedef struct _GdkExposeInfo GdkExposeInfo;
380
381 struct _GdkExposeInfo
382 {
383   Window window;
384   gboolean seen_nonmatching;
385 };
386
387 static Bool
388 expose_predicate (Display *display,
389                   XEvent  *xevent,
390                   XPointer arg)
391 {
392   GdkExposeInfo *info = (GdkExposeInfo*) arg;
393
394   /* Compressing across GravityNotify events is safe, because
395    * we completely ignore them, so they can't change what
396    * we are going to draw. Compressing across GravityNotify
397    * events is necessay because during window-unshading animation
398    * we'll get a whole bunch of them interspersed with
399    * expose events.
400    */
401   if (xevent->xany.type != Expose && 
402       xevent->xany.type != GravityNotify)
403     {
404       info->seen_nonmatching = TRUE;
405     }
406
407   if (info->seen_nonmatching ||
408       xevent->xany.type != Expose ||
409       xevent->xany.window != info->window)
410     return FALSE;
411   else
412     return TRUE;
413 }
414
415 void
416 gdk_compress_exposures (XEvent    *xevent,
417                         GdkWindow *window)
418 {
419   gint nrects = 1;
420   gint count = 0;
421   GdkRectangle rect1;
422   GdkRectangle rect2;
423   GdkRectangle tmp_rect;
424   XEvent tmp_event;
425   GdkFilterReturn result;
426   GdkExposeInfo info;
427   GdkEvent event;
428
429   info.window = xevent->xany.window;
430   info.seen_nonmatching = FALSE;
431   
432   rect1.x = xevent->xexpose.x;
433   rect1.y = xevent->xexpose.y;
434   rect1.width = xevent->xexpose.width;
435   rect1.height = xevent->xexpose.height;
436
437   while (1)
438     {
439       if (count == 0)
440         {
441           if (!XCheckIfEvent (gdk_display, 
442                               &tmp_event, 
443                               expose_predicate, 
444                               (XPointer)&info))
445             break;
446         }
447       else
448         XIfEvent (gdk_display, 
449                   &tmp_event, 
450                   expose_predicate, 
451                   (XPointer)&info);
452       
453       /* We apply filters here, and if it was filtered, completely
454        * ignore the return
455        */
456       result = gdk_event_apply_filters (xevent, &event,
457                                         window ? 
458                                           ((GdkWindowPrivate *)window)->filters
459                                           : gdk_default_filters);
460       
461       if (result != GDK_FILTER_CONTINUE)
462         {
463           if (result == GDK_FILTER_TRANSLATE)
464             gdk_event_put (&event);
465           continue;
466         }
467
468       if (nrects == 1)
469         {
470           rect2.x = tmp_event.xexpose.x;
471           rect2.y = tmp_event.xexpose.y;
472           rect2.width = tmp_event.xexpose.width;
473           rect2.height = tmp_event.xexpose.height;
474
475           nrects++;
476         }
477       else
478         {
479           tmp_rect.x = tmp_event.xexpose.x;
480           tmp_rect.y = tmp_event.xexpose.y;
481           tmp_rect.width = tmp_event.xexpose.width;
482           tmp_rect.height = tmp_event.xexpose.height;
483
484           gdk_add_rect_to_rects (&rect1, &rect2, &tmp_rect);
485         }
486
487       count = tmp_event.xexpose.count;
488     }
489
490   if (nrects == 2)
491     {
492       gdk_rectangle_union (&rect1, &rect2, &tmp_rect);
493
494       if ((tmp_rect.width * tmp_rect.height) <
495           2 * (rect1.height * rect1.width +
496                rect2.height * rect2.width))
497         {
498           rect1 = tmp_rect;
499           nrects = 1;
500         }
501     }
502
503   if (nrects == 2)
504     {
505       event.expose.type = GDK_EXPOSE;
506       event.expose.window = window;
507       event.expose.area.x = rect2.x;
508       event.expose.area.y = rect2.y;
509       event.expose.area.width = rect2.width;
510       event.expose.area.height = rect2.height;
511       event.expose.count = 0;
512
513       gdk_event_put (&event);
514     }
515
516   xevent->xexpose.count = nrects - 1;
517   xevent->xexpose.x = rect1.x;
518   xevent->xexpose.y = rect1.y;
519   xevent->xexpose.width = rect1.width;
520   xevent->xexpose.height = rect1.height;
521 }
522
523 /*************************************************************
524  * gdk_event_handler_set:
525  *     
526  *   arguments:
527  *     func: Callback function to be called for each event.
528  *     data: Data supplied to the function
529  *     notify: function called when function is no longer needed
530  * 
531  *   results:
532  *************************************************************/
533
534 void 
535 gdk_event_handler_set (GdkEventFunc   func,
536                        gpointer       data,
537                        GDestroyNotify notify)
538 {
539   if (event_notify)
540     (*event_notify) (event_data);
541
542   event_func = func;
543   event_data = data;
544   event_notify = notify;
545 }
546
547 /*
548  *--------------------------------------------------------------
549  * gdk_event_get
550  *
551  *   Gets the next event.
552  *
553  * Arguments:
554  *
555  * Results:
556  *   If an event is waiting that we care about, returns 
557  *   a pointer to that event, to be freed with gdk_event_free.
558  *   Otherwise, returns NULL.
559  *
560  * Side effects:
561  *
562  *--------------------------------------------------------------
563  */
564
565 GdkEvent*
566 gdk_event_get (void)
567 {
568   gdk_events_queue ();
569
570   return gdk_event_unqueue ();
571 }
572
573 /*
574  *--------------------------------------------------------------
575  * gdk_event_peek
576  *
577  *   Gets the next event.
578  *
579  * Arguments:
580  *
581  * Results:
582  *   If an event is waiting that we care about, returns 
583  *   a copy of that event, but does not remove it from
584  *   the queue. The pointer is to be freed with gdk_event_free.
585  *   Otherwise, returns NULL.
586  *
587  * Side effects:
588  *
589  *--------------------------------------------------------------
590  */
591
592 GdkEvent*
593 gdk_event_peek (void)
594 {
595   GList *tmp_list;
596
597   tmp_list = gdk_event_queue_find_first ();
598   
599   if (tmp_list)
600     return gdk_event_copy (tmp_list->data);
601   else
602     return NULL;
603 }
604
605 void
606 gdk_event_put (GdkEvent *event)
607 {
608   GdkEvent *new_event;
609   
610   g_return_if_fail (event != NULL);
611   
612   new_event = gdk_event_copy (event);
613
614   gdk_event_queue_append (new_event);
615 }
616
617 /*
618  *--------------------------------------------------------------
619  * gdk_event_copy
620  *
621  *   Copy a event structure into new storage.
622  *
623  * Arguments:
624  *   "event" is the event struct to copy.
625  *
626  * Results:
627  *   A new event structure.  Free it with gdk_event_free.
628  *
629  * Side effects:
630  *   The reference count of the window in the event is increased.
631  *
632  *--------------------------------------------------------------
633  */
634
635 static GMemChunk *event_chunk = NULL;
636
637 static GdkEvent*
638 gdk_event_new (void)
639 {
640   GdkEventPrivate *new_event;
641   
642   if (event_chunk == NULL)
643     event_chunk = g_mem_chunk_new ("events",
644                                    sizeof (GdkEventPrivate),
645                                    4096,
646                                    G_ALLOC_AND_FREE);
647   
648   new_event = g_chunk_new (GdkEventPrivate, event_chunk);
649   new_event->flags = 0;
650   
651   return (GdkEvent*) new_event;
652 }
653
654 GdkEvent*
655 gdk_event_copy (GdkEvent *event)
656 {
657   GdkEvent *new_event;
658   
659   g_return_val_if_fail (event != NULL, NULL);
660   
661   new_event = gdk_event_new ();
662   
663   *new_event = *event;
664   gdk_window_ref (new_event->any.window);
665   
666   switch (event->any.type)
667     {
668     case GDK_KEY_PRESS:
669     case GDK_KEY_RELEASE:
670       new_event->key.string = g_strdup (event->key.string);
671       break;
672       
673     case GDK_ENTER_NOTIFY:
674     case GDK_LEAVE_NOTIFY:
675       if (event->crossing.subwindow != NULL)
676         gdk_window_ref (event->crossing.subwindow);
677       break;
678       
679     case GDK_DRAG_ENTER:
680     case GDK_DRAG_LEAVE:
681     case GDK_DRAG_MOTION:
682     case GDK_DRAG_STATUS:
683     case GDK_DROP_START:
684     case GDK_DROP_FINISHED:
685       gdk_drag_context_ref (event->dnd.context);
686       break;
687       
688     default:
689       break;
690     }
691   
692   return new_event;
693 }
694
695 /*
696  *--------------------------------------------------------------
697  * gdk_event_free
698  *
699  *   Free a event structure obtained from gdk_event_copy.  Do not use
700  *   with other event structures.
701  *
702  * Arguments:
703  *   "event" is the event struct to free.
704  *
705  * Results:
706  *
707  * Side effects:
708  *   The reference count of the window in the event is decreased and
709  *   might be freed, too.
710  *
711  *-------------------------------------------------------------- */
712
713 void
714 gdk_event_free (GdkEvent *event)
715 {
716   g_return_if_fail (event != NULL);
717
718   g_assert (event_chunk != NULL); /* paranoid */
719   
720   if (event->any.window)
721     gdk_window_unref (event->any.window);
722   
723   switch (event->any.type)
724     {
725     case GDK_KEY_PRESS:
726     case GDK_KEY_RELEASE:
727       g_free (event->key.string);
728       break;
729       
730     case GDK_ENTER_NOTIFY:
731     case GDK_LEAVE_NOTIFY:
732       if (event->crossing.subwindow != NULL)
733         gdk_window_unref (event->crossing.subwindow);
734       break;
735       
736     case GDK_DRAG_ENTER:
737     case GDK_DRAG_LEAVE:
738     case GDK_DRAG_MOTION:
739     case GDK_DRAG_STATUS:
740     case GDK_DROP_START:
741     case GDK_DROP_FINISHED:
742       gdk_drag_context_unref (event->dnd.context);
743       break;
744       
745     default:
746       break;
747     }
748   
749   g_mem_chunk_free (event_chunk, event);
750 }
751
752 /*
753  *--------------------------------------------------------------
754  * gdk_event_get_time:
755  *    Get the timestamp from an event.
756  *   arguments:
757  *     event:
758  *   results:
759  *    The event's time stamp, if it has one, otherwise
760  *    GDK_CURRENT_TIME.
761  *--------------------------------------------------------------
762  */
763
764 guint32
765 gdk_event_get_time (GdkEvent *event)
766 {
767   if (event)
768     switch (event->type)
769       {
770       case GDK_MOTION_NOTIFY:
771         return event->motion.time;
772       case GDK_BUTTON_PRESS:
773       case GDK_2BUTTON_PRESS:
774       case GDK_3BUTTON_PRESS:
775       case GDK_BUTTON_RELEASE:
776         return event->button.time;
777       case GDK_KEY_PRESS:
778       case GDK_KEY_RELEASE:
779         return event->key.time;
780       case GDK_ENTER_NOTIFY:
781       case GDK_LEAVE_NOTIFY:
782         return event->crossing.time;
783       case GDK_PROPERTY_NOTIFY:
784         return event->property.time;
785       case GDK_SELECTION_CLEAR:
786       case GDK_SELECTION_REQUEST:
787       case GDK_SELECTION_NOTIFY:
788         return event->selection.time;
789       case GDK_PROXIMITY_IN:
790       case GDK_PROXIMITY_OUT:
791         return event->proximity.time;
792       case GDK_DRAG_ENTER:
793       case GDK_DRAG_LEAVE:
794       case GDK_DRAG_MOTION:
795       case GDK_DRAG_STATUS:
796       case GDK_DROP_START:
797       case GDK_DROP_FINISHED:
798         return event->dnd.time;
799       default:                  /* use current time */
800         break;
801       }
802   
803   return GDK_CURRENT_TIME;
804 }
805
806 /*
807  *--------------------------------------------------------------
808  * gdk_set_show_events
809  *
810  *   Turns on/off the showing of events.
811  *
812  * Arguments:
813  *   "show_events" is a boolean describing whether or
814  *   not to show the events gdk receives.
815  *
816  * Results:
817  *
818  * Side effects:
819  *   When "show_events" is TRUE, calls to "gdk_event_get"
820  *   will output debugging informatin regarding the event
821  *   received to stdout.
822  *
823  *--------------------------------------------------------------
824  */
825
826 void
827 gdk_set_show_events (gint show_events)
828 {
829   if (show_events)
830     gdk_debug_flags |= GDK_DEBUG_EVENTS;
831   else
832     gdk_debug_flags &= ~GDK_DEBUG_EVENTS;
833 }
834
835 gint
836 gdk_get_show_events (void)
837 {
838   return gdk_debug_flags & GDK_DEBUG_EVENTS;
839 }
840
841 static void
842 gdk_io_destroy (gpointer data)
843 {
844   GdkIOClosure *closure = data;
845
846   if (closure->notify)
847     closure->notify (closure->data);
848
849   g_free (closure);
850 }
851
852 static gboolean  
853 gdk_io_invoke (GIOChannel   *source,
854                GIOCondition  condition,
855                gpointer      data)
856 {
857   GdkIOClosure *closure = data;
858   GdkInputCondition gdk_cond = 0;
859
860   if (condition & (G_IO_IN | G_IO_PRI))
861     gdk_cond |= GDK_INPUT_READ;
862   if (condition & G_IO_OUT)
863     gdk_cond |= GDK_INPUT_WRITE;
864   if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
865     gdk_cond |= GDK_INPUT_EXCEPTION;
866
867   if (closure->condition & gdk_cond)
868     closure->function (closure->data, g_io_channel_unix_get_fd (source), gdk_cond);
869
870   return TRUE;
871 }
872
873 gint
874 gdk_input_add_full (gint              source,
875                     GdkInputCondition condition,
876                     GdkInputFunction  function,
877                     gpointer          data,
878                     GdkDestroyNotify  destroy)
879 {
880   guint result;
881   GdkIOClosure *closure = g_new (GdkIOClosure, 1);
882   GIOChannel *channel;
883   GIOCondition cond = 0;
884
885   closure->function = function;
886   closure->condition = condition;
887   closure->notify = destroy;
888   closure->data = data;
889
890   if (condition & GDK_INPUT_READ)
891     cond |= (G_IO_IN | G_IO_PRI);
892   if (condition & GDK_INPUT_WRITE)
893     cond |= G_IO_OUT;
894   if (condition & GDK_INPUT_EXCEPTION)
895     cond |= G_IO_ERR|G_IO_HUP|G_IO_NVAL;
896
897   channel = g_io_channel_unix_new (source);
898   result = g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, cond, 
899                                 gdk_io_invoke,
900                                 closure, gdk_io_destroy);
901   g_io_channel_unref (channel);
902
903   return result;
904 }
905
906 gint
907 gdk_input_add (gint              source,
908                GdkInputCondition condition,
909                GdkInputFunction  function,
910                gpointer          data)
911 {
912   return gdk_input_add_full (source, condition, function, data, NULL);
913 }
914
915 void
916 gdk_input_remove (gint tag)
917 {
918   g_source_remove (tag);
919 }
920
921 static gint
922 gdk_event_apply_filters (XEvent *xevent,
923                          GdkEvent *event,
924                          GList *filters)
925 {
926   GdkEventFilter *filter;
927   GList *tmp_list;
928   GdkFilterReturn result;
929   
930   tmp_list = filters;
931   
932   while (tmp_list)
933     {
934       filter = (GdkEventFilter*) tmp_list->data;
935       
936       result = (*filter->function) (xevent, event, filter->data);
937       if (result !=  GDK_FILTER_CONTINUE)
938         return result;
939       
940       tmp_list = tmp_list->next;
941     }
942   
943   return GDK_FILTER_CONTINUE;
944 }
945
946 void 
947 gdk_add_client_message_filter (GdkAtom       message_type,
948                                GdkFilterFunc func,
949                                gpointer      data)
950 {
951   GdkClientFilter *filter = g_new (GdkClientFilter, 1);
952
953   filter->type = message_type;
954   filter->function = func;
955   filter->data = data;
956   
957   client_filters = g_list_prepend (client_filters, filter);
958 }
959
960 static gint
961 gdk_event_translate (GdkEvent *event,
962                      XEvent   *xevent)
963 {
964   
965   GdkWindow *window;
966   GdkWindowPrivate *window_private;
967   static XComposeStatus compose;
968   KeySym keysym;
969   int charcount;
970 #ifdef USE_XIM
971   static gchar* buf = NULL;
972   static gint buf_len= 0;
973 #else
974   char buf[16];
975 #endif
976   gint return_val;
977   
978   return_val = FALSE;
979   
980   /* Find the GdkWindow that this event occurred in.
981    * 
982    * We handle events with window=None
983    *  specially - they are generated by XFree86's XInput under
984    *  some circumstances.
985    */
986   
987   if ((xevent->xany.window == None) &&
988       gdk_input_vtable.window_none_event)
989     {
990       return_val = gdk_input_vtable.window_none_event (event,xevent);
991       
992       if (return_val >= 0)      /* was handled */
993         return return_val;
994       else
995         return_val = FALSE;
996     }
997   
998   window = gdk_window_lookup (xevent->xany.window);
999   window_private = (GdkWindowPrivate *) window;
1000   
1001   if (window != NULL)
1002     gdk_window_ref (window);
1003   
1004   event->any.window = window;
1005   event->any.send_event = xevent->xany.send_event;
1006   
1007   if (window_private && window_private->destroyed)
1008     {
1009       if (xevent->type != DestroyNotify)
1010         return FALSE;
1011     }
1012   else
1013     {
1014       /* Check for filters for this window
1015        */
1016       GdkFilterReturn result;
1017       result = gdk_event_apply_filters (xevent, event,
1018                                         window_private
1019                                         ?window_private->filters
1020                                         :gdk_default_filters);
1021       
1022       if (result != GDK_FILTER_CONTINUE)
1023         {
1024           return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
1025         }
1026     }
1027
1028 #ifdef USE_XIM
1029   if (window == NULL && gdk_xim_window && xevent->type == KeyPress &&
1030       !((GdkWindowPrivate *) gdk_xim_window)->destroyed)
1031     {
1032       /*
1033        * If user presses a key in Preedit or Status window, keypress event
1034        * is sometimes sent to these windows. These windows are not managed
1035        * by GDK, so we redirect KeyPress event to xim_window.
1036        *
1037        * If someone want to use the window whitch is not managed by GDK
1038        * and want to get KeyPress event, he/she must register the filter
1039        * function to gdk_default_filters to intercept the event.
1040        */
1041
1042       GdkFilterReturn result;
1043
1044       window = gdk_xim_window;
1045       window_private = (GdkWindowPrivate *) window;
1046       gdk_window_ref (window);
1047       event->any.window = window;
1048
1049       GDK_NOTE (XIM,
1050         g_message ("KeyPress event is redirected to xim_window: %#lx",
1051                    xevent->xany.window));
1052
1053       result = gdk_event_apply_filters (xevent, event,
1054                                         window_private->filters);
1055       if (result != GDK_FILTER_CONTINUE)
1056         return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
1057     }
1058 #endif
1059
1060   if (window == NULL)
1061     g_message ("Got event for unknown window: %#lx\n", xevent->xany.window);
1062
1063   /* We do a "manual" conversion of the XEvent to a
1064    *  GdkEvent. The structures are mostly the same so
1065    *  the conversion is fairly straightforward. We also
1066    *  optionally print debugging info regarding events
1067    *  received.
1068    */
1069
1070   return_val = TRUE;
1071
1072   switch (xevent->type)
1073     {
1074     case KeyPress:
1075       /* Lookup the string corresponding to the given keysym.
1076        */
1077       
1078 #ifdef USE_XIM
1079       if (buf_len == 0) 
1080         {
1081           buf_len = 128;
1082           buf = g_new (gchar, buf_len);
1083         }
1084       keysym = GDK_VoidSymbol;
1085       
1086       if (gdk_xim_ic && gdk_xim_ic->xic)
1087         {
1088           Status status;
1089           
1090           /* Clear keyval. Depending on status, may not be set */
1091           charcount = XmbLookupString(gdk_xim_ic->xic,
1092                                       &xevent->xkey, buf, buf_len-1,
1093                                       &keysym, &status);
1094           if (status == XBufferOverflow)
1095             {                     /* retry */
1096               /* alloc adequate size of buffer */
1097               GDK_NOTE (XIM,
1098                         g_message("XIM: overflow (required %i)", charcount));
1099               
1100               while (buf_len <= charcount)
1101                 buf_len *= 2;
1102               buf = (gchar *) g_realloc (buf, buf_len);
1103               
1104               charcount = XmbLookupString (gdk_xim_ic->xic,
1105                                            &xevent->xkey, buf, buf_len-1,
1106                                            &keysym, &status);
1107             }
1108           if (status == XLookupNone)
1109             {
1110               return_val = FALSE;
1111               break;
1112             }
1113         }
1114       else
1115         charcount = XLookupString (&xevent->xkey, buf, buf_len,
1116                                    &keysym, &compose);
1117 #else
1118       charcount = XLookupString (&xevent->xkey, buf, 16,
1119                                  &keysym, &compose);
1120 #endif
1121       event->key.keyval = keysym;
1122       
1123       if (charcount > 0 && buf[charcount-1] == '\0')
1124         charcount --;
1125       else
1126         buf[charcount] = '\0';
1127       
1128       /* Print debugging info. */
1129       
1130 #ifdef G_ENABLE_DEBUG
1131       if (gdk_debug_flags & GDK_DEBUG_EVENTS)
1132         {
1133           g_message ("key press:\twindow: %ld  key: %12s  %d",
1134                      xevent->xkey.window,
1135                      event->key.keyval ? XKeysymToString (event->key.keyval) : "(none)",
1136                      event->key.keyval);
1137           if (charcount > 0)
1138             g_message ("\t\tlength: %4d string: \"%s\"",
1139                        charcount, buf);
1140         }
1141 #endif /* G_ENABLE_DEBUG */
1142       
1143       event->key.type = GDK_KEY_PRESS;
1144       event->key.window = window;
1145       event->key.time = xevent->xkey.time;
1146       event->key.state = (GdkModifierType) xevent->xkey.state;
1147       event->key.string = g_strdup (buf);
1148       event->key.length = charcount;
1149       
1150       break;
1151       
1152     case KeyRelease:
1153       /* Lookup the string corresponding to the given keysym.
1154        */
1155 #ifdef USE_XIM
1156       if (buf_len == 0) 
1157         {
1158           buf_len = 128;
1159           buf = g_new (gchar, buf_len);
1160         }
1161 #endif
1162       keysym = GDK_VoidSymbol;
1163       charcount = XLookupString (&xevent->xkey, buf, 16,
1164                                  &keysym, &compose);
1165       event->key.keyval = keysym;      
1166       
1167       /* Print debugging info.
1168        */
1169       GDK_NOTE (EVENTS, 
1170                 g_message ("key release:\t\twindow: %ld  key: %12s  %d",
1171                            xevent->xkey.window,
1172                            XKeysymToString (event->key.keyval),
1173                            event->key.keyval));
1174       
1175       event->key.type = GDK_KEY_RELEASE;
1176       event->key.window = window;
1177       event->key.time = xevent->xkey.time;
1178       event->key.state = (GdkModifierType) xevent->xkey.state;
1179       event->key.length = 0;
1180       event->key.string = NULL;
1181       
1182       break;
1183       
1184     case ButtonPress:
1185       /* Print debugging info.
1186        */
1187       GDK_NOTE (EVENTS, 
1188                 g_message ("button press:\t\twindow: %ld  x,y: %d %d  button: %d",
1189                            xevent->xbutton.window,
1190                            xevent->xbutton.x, xevent->xbutton.y,
1191                            xevent->xbutton.button));
1192       
1193       if (window_private &&
1194           (window_private->extension_events != 0) &&
1195           gdk_input_ignore_core)
1196         {
1197           return_val = FALSE;
1198           break;
1199         }
1200       
1201       event->button.type = GDK_BUTTON_PRESS;
1202       event->button.window = window;
1203       event->button.time = xevent->xbutton.time;
1204       event->button.x = xevent->xbutton.x;
1205       event->button.y = xevent->xbutton.y;
1206       event->button.x_root = (gfloat)xevent->xbutton.x_root;
1207       event->button.y_root = (gfloat)xevent->xbutton.y_root;
1208       event->button.pressure = 0.5;
1209       event->button.xtilt = 0;
1210       event->button.ytilt = 0;
1211       event->button.state = (GdkModifierType) xevent->xbutton.state;
1212       event->button.button = xevent->xbutton.button;
1213       event->button.source = GDK_SOURCE_MOUSE;
1214       event->button.deviceid = GDK_CORE_POINTER;
1215       
1216       if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) &&
1217           (event->button.window == button_window[1]) &&
1218           (event->button.button == button_number[1]))
1219         {
1220           gdk_synthesize_click (event, 3);
1221           
1222           button_click_time[1] = 0;
1223           button_click_time[0] = 0;
1224           button_window[1] = NULL;
1225           button_window[0] = 0;
1226           button_number[1] = -1;
1227           button_number[0] = -1;
1228         }
1229       else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) &&
1230                (event->button.window == button_window[0]) &&
1231                (event->button.button == button_number[0]))
1232         {
1233           gdk_synthesize_click (event, 2);
1234           
1235           button_click_time[1] = button_click_time[0];
1236           button_click_time[0] = event->button.time;
1237           button_window[1] = button_window[0];
1238           button_window[0] = event->button.window;
1239           button_number[1] = button_number[0];
1240           button_number[0] = event->button.button;
1241         }
1242       else
1243         {
1244           button_click_time[1] = 0;
1245           button_click_time[0] = event->button.time;
1246           button_window[1] = NULL;
1247           button_window[0] = event->button.window;
1248           button_number[1] = -1;
1249           button_number[0] = event->button.button;
1250         }
1251
1252       break;
1253       
1254     case ButtonRelease:
1255       /* Print debugging info.
1256        */
1257       GDK_NOTE (EVENTS, 
1258                 g_message ("button release:\twindow: %ld  x,y: %d %d  button: %d",
1259                            xevent->xbutton.window,
1260                            xevent->xbutton.x, xevent->xbutton.y,
1261                            xevent->xbutton.button));
1262       
1263       if (window_private &&
1264           (window_private->extension_events != 0) &&
1265           gdk_input_ignore_core)
1266         {
1267           return_val = FALSE;
1268           break;
1269         }
1270       
1271       event->button.type = GDK_BUTTON_RELEASE;
1272       event->button.window = window;
1273       event->button.time = xevent->xbutton.time;
1274       event->button.x = xevent->xbutton.x;
1275       event->button.y = xevent->xbutton.y;
1276       event->button.x_root = (gfloat)xevent->xbutton.x_root;
1277       event->button.y_root = (gfloat)xevent->xbutton.y_root;
1278       event->button.pressure = 0.5;
1279       event->button.xtilt = 0;
1280       event->button.ytilt = 0;
1281       event->button.state = (GdkModifierType) xevent->xbutton.state;
1282       event->button.button = xevent->xbutton.button;
1283       event->button.source = GDK_SOURCE_MOUSE;
1284       event->button.deviceid = GDK_CORE_POINTER;
1285       
1286       break;
1287       
1288     case MotionNotify:
1289       /* Print debugging info.
1290        */
1291       GDK_NOTE (EVENTS,
1292                 g_message ("motion notify:\t\twindow: %ld  x,y: %d %d  hint: %s", 
1293                            xevent->xmotion.window,
1294                            xevent->xmotion.x, xevent->xmotion.y,
1295                            (xevent->xmotion.is_hint) ? "true" : "false"));
1296       
1297       if (window_private &&
1298           (window_private->extension_events != 0) &&
1299           gdk_input_ignore_core)
1300         {
1301           return_val = FALSE;
1302           break;
1303         }
1304       
1305       event->motion.type = GDK_MOTION_NOTIFY;
1306       event->motion.window = window;
1307       event->motion.time = xevent->xmotion.time;
1308       event->motion.x = xevent->xmotion.x;
1309       event->motion.y = xevent->xmotion.y;
1310       event->motion.x_root = (gfloat)xevent->xmotion.x_root;
1311       event->motion.y_root = (gfloat)xevent->xmotion.y_root;
1312       event->motion.pressure = 0.5;
1313       event->motion.xtilt = 0;
1314       event->motion.ytilt = 0;
1315       event->motion.state = (GdkModifierType) xevent->xmotion.state;
1316       event->motion.is_hint = xevent->xmotion.is_hint;
1317       event->motion.source = GDK_SOURCE_MOUSE;
1318       event->motion.deviceid = GDK_CORE_POINTER;
1319       
1320       break;
1321       
1322     case EnterNotify:
1323       /* Print debugging info.
1324        */
1325       GDK_NOTE (EVENTS,
1326                 g_message ("enter notify:\t\twindow: %ld  detail: %d subwin: %ld",
1327                            xevent->xcrossing.window,
1328                            xevent->xcrossing.detail,
1329                            xevent->xcrossing.subwindow));
1330       
1331       /* Tell XInput stuff about it if appropriate */
1332       if (window_private &&
1333           !window_private->destroyed &&
1334           (window_private->extension_events != 0) &&
1335           gdk_input_vtable.enter_event)
1336         gdk_input_vtable.enter_event (&xevent->xcrossing, window);
1337       
1338       event->crossing.type = GDK_ENTER_NOTIFY;
1339       event->crossing.window = window;
1340       
1341       /* If the subwindow field of the XEvent is non-NULL, then
1342        *  lookup the corresponding GdkWindow.
1343        */
1344       if (xevent->xcrossing.subwindow != None)
1345         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
1346       else
1347         event->crossing.subwindow = NULL;
1348       
1349       event->crossing.time = xevent->xcrossing.time;
1350       event->crossing.x = xevent->xcrossing.x;
1351       event->crossing.y = xevent->xcrossing.y;
1352       event->crossing.x_root = xevent->xcrossing.x_root;
1353       event->crossing.y_root = xevent->xcrossing.y_root;
1354       
1355       /* Translate the crossing mode into Gdk terms.
1356        */
1357       switch (xevent->xcrossing.mode)
1358         {
1359         case NotifyNormal:
1360           event->crossing.mode = GDK_CROSSING_NORMAL;
1361           break;
1362         case NotifyGrab:
1363           event->crossing.mode = GDK_CROSSING_GRAB;
1364           break;
1365         case NotifyUngrab:
1366           event->crossing.mode = GDK_CROSSING_UNGRAB;
1367           break;
1368         };
1369       
1370       /* Translate the crossing detail into Gdk terms.
1371        */
1372       switch (xevent->xcrossing.detail)
1373         {
1374         case NotifyInferior:
1375           event->crossing.detail = GDK_NOTIFY_INFERIOR;
1376           break;
1377         case NotifyAncestor:
1378           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
1379           break;
1380         case NotifyVirtual:
1381           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
1382           break;
1383         case NotifyNonlinear:
1384           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
1385           break;
1386         case NotifyNonlinearVirtual:
1387           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
1388           break;
1389         default:
1390           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
1391           break;
1392         }
1393       
1394       event->crossing.focus = xevent->xcrossing.focus;
1395       event->crossing.state = xevent->xcrossing.state;
1396   
1397       break;
1398       
1399     case LeaveNotify:
1400       /* Print debugging info.
1401        */
1402       GDK_NOTE (EVENTS, 
1403                 g_message ("leave notify:\t\twindow: %ld  detail: %d subwin: %ld",
1404                            xevent->xcrossing.window,
1405                            xevent->xcrossing.detail, xevent->xcrossing.subwindow));
1406       
1407       event->crossing.type = GDK_LEAVE_NOTIFY;
1408       event->crossing.window = window;
1409       
1410       /* If the subwindow field of the XEvent is non-NULL, then
1411        *  lookup the corresponding GdkWindow.
1412        */
1413       if (xevent->xcrossing.subwindow != None)
1414         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
1415       else
1416         event->crossing.subwindow = NULL;
1417       
1418       event->crossing.time = xevent->xcrossing.time;
1419       event->crossing.x = xevent->xcrossing.x;
1420       event->crossing.y = xevent->xcrossing.y;
1421       event->crossing.x_root = xevent->xcrossing.x_root;
1422       event->crossing.y_root = xevent->xcrossing.y_root;
1423       
1424       /* Translate the crossing mode into Gdk terms.
1425        */
1426       switch (xevent->xcrossing.mode)
1427         {
1428         case NotifyNormal:
1429           event->crossing.mode = GDK_CROSSING_NORMAL;
1430           break;
1431         case NotifyGrab:
1432           event->crossing.mode = GDK_CROSSING_GRAB;
1433           break;
1434         case NotifyUngrab:
1435           event->crossing.mode = GDK_CROSSING_UNGRAB;
1436           break;
1437         };
1438       
1439       /* Translate the crossing detail into Gdk terms.
1440        */
1441       switch (xevent->xcrossing.detail)
1442         {
1443         case NotifyInferior:
1444           event->crossing.detail = GDK_NOTIFY_INFERIOR;
1445           break;
1446         case NotifyAncestor:
1447           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
1448           break;
1449         case NotifyVirtual:
1450           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
1451           break;
1452         case NotifyNonlinear:
1453           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
1454           break;
1455         case NotifyNonlinearVirtual:
1456           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
1457           break;
1458         default:
1459           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
1460           break;
1461         }
1462       
1463       event->crossing.focus = xevent->xcrossing.focus;
1464       event->crossing.state = xevent->xcrossing.state;
1465       
1466       break;
1467       
1468     case FocusIn:
1469     case FocusOut:
1470       /* We only care about focus events that indicate that _this_
1471        * window (not a ancestor or child) got or lost the focus
1472        */
1473       switch (xevent->xfocus.detail)
1474         {
1475         case NotifyAncestor:
1476         case NotifyInferior:
1477         case NotifyNonlinear:
1478           /* Print debugging info.
1479            */
1480           GDK_NOTE (EVENTS,
1481                     g_message ("focus %s:\t\twindow: %ld",
1482                                (xevent->xany.type == FocusIn) ? "in" : "out",
1483                                xevent->xfocus.window));
1484           
1485           /* gdk_keyboard_grab() causes following events. These events confuse
1486            * the XIM focus, so ignore them.
1487            */
1488           if (xevent->xfocus.mode == NotifyGrab ||
1489               xevent->xfocus.mode == NotifyUngrab)
1490             break;
1491           
1492           event->focus_change.type = GDK_FOCUS_CHANGE;
1493           event->focus_change.window = window;
1494           event->focus_change.in = (xevent->xany.type == FocusIn);
1495
1496           break;
1497         default:
1498           return_val = FALSE;
1499         }
1500       break;
1501       
1502     case KeymapNotify:
1503       /* Print debugging info.
1504        */
1505       GDK_NOTE (EVENTS,
1506                 g_message ("keymap notify"));
1507
1508       /* Not currently handled */
1509       return_val = FALSE;
1510       break;
1511       
1512     case Expose:
1513       /* Print debugging info.
1514        */
1515       GDK_NOTE (EVENTS,
1516                 g_message ("expose:\t\twindow: %ld  %d  x,y: %d %d  w,h: %d %d",
1517                            xevent->xexpose.window, xevent->xexpose.count,
1518                            xevent->xexpose.x, xevent->xexpose.y,
1519                            xevent->xexpose.width, xevent->xexpose.height));
1520       gdk_compress_exposures (xevent, window);
1521       
1522       event->expose.type = GDK_EXPOSE;
1523       event->expose.window = window;
1524       event->expose.area.x = xevent->xexpose.x;
1525       event->expose.area.y = xevent->xexpose.y;
1526       event->expose.area.width = xevent->xexpose.width;
1527       event->expose.area.height = xevent->xexpose.height;
1528       event->expose.count = xevent->xexpose.count;
1529       
1530       break;
1531       
1532     case GraphicsExpose:
1533       /* Print debugging info.
1534        */
1535       GDK_NOTE (EVENTS,
1536                 g_message ("graphics expose:\tdrawable: %ld",
1537                            xevent->xgraphicsexpose.drawable));
1538       
1539       event->expose.type = GDK_EXPOSE;
1540       event->expose.window = window;
1541       event->expose.area.x = xevent->xgraphicsexpose.x;
1542       event->expose.area.y = xevent->xgraphicsexpose.y;
1543       event->expose.area.width = xevent->xgraphicsexpose.width;
1544       event->expose.area.height = xevent->xgraphicsexpose.height;
1545       event->expose.count = xevent->xexpose.count;
1546       
1547       break;
1548       
1549     case NoExpose:
1550       /* Print debugging info.
1551        */
1552       GDK_NOTE (EVENTS,
1553                 g_message ("no expose:\t\tdrawable: %ld",
1554                            xevent->xnoexpose.drawable));
1555       
1556       event->no_expose.type = GDK_NO_EXPOSE;
1557       event->no_expose.window = window;
1558       
1559       break;
1560       
1561     case VisibilityNotify:
1562       /* Print debugging info.
1563        */
1564 #ifdef G_ENABLE_DEBUG
1565       if (gdk_debug_flags & GDK_DEBUG_EVENTS)
1566         switch (xevent->xvisibility.state)
1567           {
1568           case VisibilityFullyObscured:
1569             g_message ("visibility notify:\twindow: %ld  none",
1570                        xevent->xvisibility.window);
1571             break;
1572           case VisibilityPartiallyObscured:
1573             g_message ("visibility notify:\twindow: %ld  partial",
1574                        xevent->xvisibility.window);
1575             break;
1576           case VisibilityUnobscured:
1577             g_message ("visibility notify:\twindow: %ld  full",
1578                        xevent->xvisibility.window);
1579             break;
1580           }
1581 #endif /* G_ENABLE_DEBUG */
1582       
1583       event->visibility.type = GDK_VISIBILITY_NOTIFY;
1584       event->visibility.window = window;
1585       
1586       switch (xevent->xvisibility.state)
1587         {
1588         case VisibilityFullyObscured:
1589           event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED;
1590           break;
1591           
1592         case VisibilityPartiallyObscured:
1593           event->visibility.state = GDK_VISIBILITY_PARTIAL;
1594           break;
1595           
1596         case VisibilityUnobscured:
1597           event->visibility.state = GDK_VISIBILITY_UNOBSCURED;
1598           break;
1599         }
1600       
1601       break;
1602       
1603     case CreateNotify:
1604       /* Not currently handled */
1605       break;
1606       
1607     case DestroyNotify:
1608       /* Print debugging info.
1609        */
1610       GDK_NOTE (EVENTS,
1611                 g_message ("destroy notify:\twindow: %ld",
1612                            xevent->xdestroywindow.window));
1613       
1614       event->any.type = GDK_DESTROY;
1615       event->any.window = window;
1616       
1617       return_val = window_private && !window_private->destroyed;
1618       
1619       if(window && window_private->xwindow != GDK_ROOT_WINDOW())
1620         gdk_window_destroy_notify (window);
1621       break;
1622       
1623     case UnmapNotify:
1624       /* Print debugging info.
1625        */
1626       GDK_NOTE (EVENTS,
1627                 g_message ("unmap notify:\t\twindow: %ld",
1628                            xevent->xmap.window));
1629       
1630       event->any.type = GDK_UNMAP;
1631       event->any.window = window;
1632       
1633       if (gdk_xgrab_window == window_private)
1634         gdk_xgrab_window = NULL;
1635       
1636       break;
1637       
1638     case MapNotify:
1639       /* Print debugging info.
1640        */
1641       GDK_NOTE (EVENTS,
1642                 g_message ("map notify:\t\twindow: %ld",
1643                            xevent->xmap.window));
1644       
1645       event->any.type = GDK_MAP;
1646       event->any.window = window;
1647       
1648       break;
1649       
1650     case ReparentNotify:
1651       /* Print debugging info.
1652        */
1653       GDK_NOTE (EVENTS,
1654                 g_message ("reparent notify:\twindow: %ld",
1655                            xevent->xreparent.window));
1656
1657       /* Not currently handled */
1658       return_val = FALSE;
1659       break;
1660       
1661     case ConfigureNotify:
1662       /* Print debugging info.
1663        */
1664       while ((XPending (gdk_display) > 0) &&
1665              XCheckTypedWindowEvent(gdk_display, xevent->xany.window,
1666                                     ConfigureNotify, xevent))
1667         {
1668           GdkFilterReturn result;
1669           
1670           GDK_NOTE (EVENTS, 
1671                     g_message ("configure notify discarded:\twindow: %ld",
1672                                xevent->xconfigure.window));
1673           
1674           result = gdk_event_apply_filters (xevent, event,
1675                                             window_private
1676                                             ?window_private->filters
1677                                             :gdk_default_filters);
1678           
1679           /* If the result is GDK_FILTER_REMOVE, there will be
1680            * trouble, but anybody who filtering the Configure events
1681            * better know what they are doing
1682            */
1683           if (result != GDK_FILTER_CONTINUE)
1684             {
1685               return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
1686             }
1687           
1688           /*XSync (gdk_display, 0);*/
1689         }
1690       
1691       
1692       GDK_NOTE (EVENTS,
1693                 g_message ("configure notify:\twindow: %ld  x,y: %d %d  w,h: %d %d  b-w: %d  above: %ld  ovr: %d",
1694                            xevent->xconfigure.window,
1695                            xevent->xconfigure.x,
1696                            xevent->xconfigure.y,
1697                            xevent->xconfigure.width,
1698                            xevent->xconfigure.height,
1699                            xevent->xconfigure.border_width,
1700                            xevent->xconfigure.above,
1701                            xevent->xconfigure.override_redirect));
1702       
1703       if (!window_private->destroyed &&
1704           (window_private->extension_events != 0) &&
1705           gdk_input_vtable.configure_event)
1706         gdk_input_vtable.configure_event (&xevent->xconfigure, window);
1707
1708       if (window_private->window_type == GDK_WINDOW_CHILD)
1709         return_val = FALSE;
1710       else
1711         {
1712           event->configure.type = GDK_CONFIGURE;
1713           event->configure.window = window;
1714           event->configure.width = xevent->xconfigure.width;
1715           event->configure.height = xevent->xconfigure.height;
1716           
1717           if (!xevent->xconfigure.x &&
1718               !xevent->xconfigure.y &&
1719               !window_private->destroyed)
1720             {
1721               gint tx = 0;
1722               gint ty = 0;
1723               Window child_window = 0;
1724               
1725               if (!XTranslateCoordinates (window_private->xdisplay,
1726                                           window_private->xwindow,
1727                                           gdk_root_window,
1728                                           0, 0,
1729                                           &tx, &ty,
1730                                           &child_window))
1731                 g_warning ("GdkWindow %ld doesn't share root windows display?",
1732                            window_private->xwindow);
1733               event->configure.x = tx;
1734               event->configure.y = ty;
1735             }
1736           else
1737             {
1738               event->configure.x = xevent->xconfigure.x;
1739               event->configure.y = xevent->xconfigure.y;
1740             }
1741           window_private->x = event->configure.x;
1742           window_private->y = event->configure.y;
1743           window_private->width = xevent->xconfigure.width;
1744           window_private->height = xevent->xconfigure.height;
1745           if (window_private->resize_count > 1)
1746             window_private->resize_count -= 1;
1747         }
1748       break;
1749       
1750     case PropertyNotify:
1751       /* Print debugging info.
1752        */
1753       GDK_NOTE (EVENTS,
1754                 g_message ("property notify:\twindow: %ld",
1755                            xevent->xproperty.window));
1756       
1757       event->property.type = GDK_PROPERTY_NOTIFY;
1758       event->property.window = window;
1759       event->property.atom = xevent->xproperty.atom;
1760       event->property.time = xevent->xproperty.time;
1761       event->property.state = xevent->xproperty.state;
1762       
1763       break;
1764       
1765     case SelectionClear:
1766       GDK_NOTE (EVENTS,
1767                 g_message ("selection clear:\twindow: %ld",
1768                            xevent->xproperty.window));
1769       
1770       event->selection.type = GDK_SELECTION_CLEAR;
1771       event->selection.window = window;
1772       event->selection.selection = xevent->xselectionclear.selection;
1773       event->selection.time = xevent->xselectionclear.time;
1774       
1775       break;
1776       
1777     case SelectionRequest:
1778       GDK_NOTE (EVENTS,
1779                 g_message ("selection request:\twindow: %ld",
1780                            xevent->xproperty.window));
1781       
1782       event->selection.type = GDK_SELECTION_REQUEST;
1783       event->selection.window = window;
1784       event->selection.selection = xevent->xselectionrequest.selection;
1785       event->selection.target = xevent->xselectionrequest.target;
1786       event->selection.property = xevent->xselectionrequest.property;
1787       event->selection.requestor = xevent->xselectionrequest.requestor;
1788       event->selection.time = xevent->xselectionrequest.time;
1789       
1790       break;
1791       
1792     case SelectionNotify:
1793       GDK_NOTE (EVENTS,
1794                 g_message ("selection notify:\twindow: %ld",
1795                            xevent->xproperty.window));
1796       
1797       
1798       event->selection.type = GDK_SELECTION_NOTIFY;
1799       event->selection.window = window;
1800       event->selection.selection = xevent->xselection.selection;
1801       event->selection.target = xevent->xselection.target;
1802       event->selection.property = xevent->xselection.property;
1803       event->selection.time = xevent->xselection.time;
1804       
1805       break;
1806       
1807     case ColormapNotify:
1808       /* Print debugging info.
1809        */
1810       GDK_NOTE (EVENTS,
1811                 g_message ("colormap notify:\twindow: %ld",
1812                            xevent->xcolormap.window));
1813       
1814       /* Not currently handled */
1815       return_val = FALSE;
1816       break;
1817       
1818     case ClientMessage:
1819       {
1820         GList *tmp_list;
1821         GdkFilterReturn result = GDK_FILTER_CONTINUE;
1822
1823         /* Print debugging info.
1824          */
1825         GDK_NOTE (EVENTS,
1826                   g_message ("client message:\twindow: %ld",
1827                              xevent->xclient.window));
1828         
1829         tmp_list = client_filters;
1830         while (tmp_list)
1831           {
1832             GdkClientFilter *filter = tmp_list->data;
1833             if (filter->type == xevent->xclient.message_type)
1834               {
1835                 result = (*filter->function) (xevent, event, filter->data);
1836                 break;
1837               }
1838             
1839             tmp_list = tmp_list->next;
1840           }
1841
1842         switch (result)
1843           {
1844           case GDK_FILTER_REMOVE:
1845             return_val = FALSE;
1846             break;
1847           case GDK_FILTER_TRANSLATE:
1848             return_val = TRUE;
1849             break;
1850           case GDK_FILTER_CONTINUE:
1851             /* Send unknown ClientMessage's on to Gtk for it to use */
1852             event->client.type = GDK_CLIENT_EVENT;
1853             event->client.window = window;
1854             event->client.message_type = xevent->xclient.message_type;
1855             event->client.data_format = xevent->xclient.format;
1856             memcpy(&event->client.data, &xevent->xclient.data,
1857                    sizeof(event->client.data));
1858           }
1859       }
1860       
1861       break;
1862       
1863     case MappingNotify:
1864       /* Print debugging info.
1865        */
1866       GDK_NOTE (EVENTS,
1867                 g_message ("mapping notify"));
1868       
1869       /* Let XLib know that there is a new keyboard mapping.
1870        */
1871       XRefreshKeyboardMapping (&xevent->xmapping);
1872       return_val = FALSE;
1873       break;
1874       
1875     default:
1876       /* something else - (e.g., a Xinput event) */
1877       
1878       if (window_private &&
1879           !window_private->destroyed &&
1880           (window_private->extension_events != 0) &&
1881           gdk_input_vtable.other_event)
1882         return_val = gdk_input_vtable.other_event(event, xevent, window);
1883       else
1884         return_val = FALSE;
1885       
1886       break;
1887     }
1888   
1889   if (return_val)
1890     {
1891       if (event->any.window)
1892         gdk_window_ref (event->any.window);
1893       if (((event->any.type == GDK_ENTER_NOTIFY) ||
1894            (event->any.type == GDK_LEAVE_NOTIFY)) &&
1895           (event->crossing.subwindow != NULL))
1896         gdk_window_ref (event->crossing.subwindow);
1897     }
1898   else
1899     {
1900       /* Mark this event as having no resources to be freed */
1901       event->any.window = NULL;
1902       event->any.type = GDK_NOTHING;
1903     }
1904   
1905   if (window)
1906     gdk_window_unref (window);
1907   
1908   return return_val;
1909 }
1910
1911 GdkFilterReturn
1912 gdk_wm_protocols_filter (GdkXEvent *xev,
1913                      GdkEvent  *event,
1914                      gpointer data)
1915 {
1916   XEvent *xevent = (XEvent *)xev;
1917
1918   if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window)
1919     {
1920   /* The delete window request specifies a window
1921    *  to delete. We don't actually destroy the
1922    *  window because "it is only a request". (The
1923    *  window might contain vital data that the
1924    *  program does not want destroyed). Instead
1925    *  the event is passed along to the program,
1926    *  which should then destroy the window.
1927    */
1928       GDK_NOTE (EVENTS,
1929                 g_message ("delete window:\t\twindow: %ld",
1930                            xevent->xclient.window));
1931       
1932       event->any.type = GDK_DELETE;
1933
1934       return GDK_FILTER_TRANSLATE;
1935     }
1936   else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
1937     {
1938     }
1939
1940   return GDK_FILTER_REMOVE;
1941 }
1942
1943 #if 0
1944 static Bool
1945 gdk_event_get_type (Display  *display,
1946                     XEvent   *xevent,
1947                     XPointer  arg)
1948 {
1949   GdkEvent event;
1950   GdkPredicate *pred;
1951   
1952   if (gdk_event_translate (&event, xevent))
1953     {
1954       pred = (GdkPredicate*) arg;
1955       return (* pred->func) (&event, pred->data);
1956     }
1957   
1958   return FALSE;
1959 }
1960 #endif
1961
1962 static void
1963 gdk_events_queue (void)
1964 {
1965   GList *node;
1966   GdkEvent *event;
1967   XEvent xevent;
1968
1969   while (!gdk_event_queue_find_first() && XPending (gdk_display))
1970     {
1971 #ifdef USE_XIM
1972       Window w = None;
1973       
1974       XNextEvent (gdk_display, &xevent);
1975       if (gdk_xim_window)
1976         switch (xevent.type)
1977           {
1978           case KeyPress:
1979           case KeyRelease:
1980           case ButtonPress:
1981           case ButtonRelease:
1982             w = GDK_WINDOW_XWINDOW (gdk_xim_window);
1983             break;
1984           }
1985       
1986       if (XFilterEvent (&xevent, w))
1987         continue;
1988 #else
1989       XNextEvent (gdk_display, &xevent);
1990 #endif
1991       
1992       event = gdk_event_new ();
1993       
1994       event->any.type = GDK_NOTHING;
1995       event->any.window = NULL;
1996       event->any.send_event = FALSE;
1997       event->any.send_event = xevent.xany.send_event;
1998
1999       ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
2000
2001       gdk_event_queue_append (event);
2002       node = queued_tail;
2003
2004       if (gdk_event_translate (event, &xevent))
2005         {
2006           ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
2007         }
2008       else
2009         {
2010           gdk_event_queue_remove_link (node);
2011           g_list_free_1 (node);
2012           gdk_event_free (event);
2013         }
2014     }
2015 }
2016
2017 static gboolean  
2018 gdk_event_prepare (gpointer  source_data, 
2019                    GTimeVal *current_time,
2020                    gint     *timeout)
2021 {
2022   gboolean retval;
2023   
2024   GDK_THREADS_ENTER ();
2025
2026   *timeout = -1;
2027
2028   retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
2029
2030   GDK_THREADS_LEAVE ();
2031
2032   return retval;
2033 }
2034
2035 static gboolean  
2036 gdk_event_check (gpointer  source_data,
2037                  GTimeVal *current_time)
2038 {
2039   gboolean retval;
2040   
2041   GDK_THREADS_ENTER ();
2042
2043   if (event_poll_fd.revents & G_IO_IN)
2044     retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
2045   else
2046     retval = FALSE;
2047
2048   GDK_THREADS_LEAVE ();
2049
2050   return retval;
2051 }
2052
2053 static GdkEvent*
2054 gdk_event_unqueue (void)
2055 {
2056   GdkEvent *event = NULL;
2057   GList *tmp_list;
2058
2059   tmp_list = gdk_event_queue_find_first ();
2060
2061   if (tmp_list)
2062     {
2063       event = tmp_list->data;
2064       gdk_event_queue_remove_link (tmp_list);
2065       g_list_free_1 (tmp_list);
2066     }
2067
2068   return event;
2069 }
2070
2071 static gboolean  
2072 gdk_event_dispatch (gpointer  source_data,
2073                     GTimeVal *current_time,
2074                     gpointer  user_data)
2075 {
2076   GdkEvent *event;
2077  
2078   GDK_THREADS_ENTER ();
2079
2080   gdk_events_queue();
2081   event = gdk_event_unqueue();
2082
2083   if (event)
2084     {
2085       if (event_func)
2086         (*event_func) (event, event_data);
2087       
2088       gdk_event_free (event);
2089     }
2090   
2091   GDK_THREADS_LEAVE ();
2092
2093   return TRUE;
2094 }
2095
2096 static void
2097 gdk_synthesize_click (GdkEvent *event,
2098                       gint      nclicks)
2099 {
2100   GdkEvent temp_event;
2101   
2102   g_return_if_fail (event != NULL);
2103   
2104   temp_event = *event;
2105   temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
2106   
2107   gdk_event_put (&temp_event);
2108 }
2109
2110 /* Sends a ClientMessage to all toplevel client windows */
2111 gboolean
2112 gdk_event_send_client_message (GdkEvent *event, guint32 xid)
2113 {
2114   XEvent sev;
2115   
2116   g_return_val_if_fail(event != NULL, FALSE);
2117   
2118   /* Set up our event to send, with the exception of its target window */
2119   sev.xclient.type = ClientMessage;
2120   sev.xclient.display = gdk_display;
2121   sev.xclient.format = event->client.data_format;
2122   sev.xclient.window = xid;
2123   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
2124   sev.xclient.message_type = event->client.message_type;
2125   
2126   return gdk_send_xevent (xid, False, NoEventMask, &sev);
2127 }
2128
2129 /* Sends a ClientMessage to all toplevel client windows */
2130 gboolean
2131 gdk_event_send_client_message_to_all_recurse (XEvent  *xev, 
2132                                               guint32  xid,
2133                                               guint    level)
2134 {
2135   static GdkAtom wm_state_atom = GDK_NONE;
2136
2137   Atom type = None;
2138   int format;
2139   unsigned long nitems, after;
2140   unsigned char *data;
2141   
2142   Window *ret_children, ret_root, ret_parent;
2143   unsigned int ret_nchildren;
2144   int i;
2145   
2146   gboolean send = FALSE;
2147   gboolean found = FALSE;
2148
2149   if (!wm_state_atom)
2150     wm_state_atom = gdk_atom_intern ("WM_STATE", FALSE);
2151
2152   gdk_error_code = 0;
2153   XGetWindowProperty (gdk_display, xid, wm_state_atom, 0, 0, False, AnyPropertyType,
2154                       &type, &format, &nitems, &after, &data);
2155
2156   if (gdk_error_code)
2157     {
2158       gdk_error_code = 0;
2159       return FALSE;
2160     }
2161
2162   if (type)
2163     {
2164       send = TRUE;
2165       XFree (data);
2166     }
2167   else
2168     {
2169       /* OK, we're all set, now let's find some windows to send this to */
2170       if (XQueryTree(gdk_display, xid, &ret_root, &ret_parent,
2171                      &ret_children, &ret_nchildren) != True)
2172         return FALSE;
2173       
2174       if (gdk_error_code)
2175         return FALSE;
2176
2177       for(i = 0; i < ret_nchildren; i++)
2178         if (gdk_event_send_client_message_to_all_recurse(xev, ret_children[i], level + 1))
2179           found = TRUE;
2180
2181       XFree(ret_children);
2182     }
2183
2184   if (send || (!found && (level == 1)))
2185     {
2186       xev->xclient.window = xid;
2187       gdk_send_xevent (xid, False, NoEventMask, xev);
2188     }
2189
2190   return (send || found);
2191 }
2192
2193 void
2194 gdk_event_send_clientmessage_toall (GdkEvent *event)
2195 {
2196   XEvent sev;
2197   gint old_warnings = gdk_error_warnings;
2198
2199   g_return_if_fail(event != NULL);
2200   
2201   /* Set up our event to send, with the exception of its target window */
2202   sev.xclient.type = ClientMessage;
2203   sev.xclient.display = gdk_display;
2204   sev.xclient.format = event->client.data_format;
2205   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
2206   sev.xclient.message_type = event->client.message_type;
2207
2208   gdk_event_send_client_message_to_all_recurse(&sev, gdk_root_window, 0);
2209
2210   gdk_error_warnings = old_warnings;
2211 }
2212
2213 /*
2214  *--------------------------------------------------------------
2215  * gdk_flush
2216  *
2217  *   Flushes the Xlib output buffer and then waits
2218  *   until all requests have been received and processed
2219  *   by the X server. The only real use for this function
2220  *   is in dealing with XShm.
2221  *
2222  * Arguments:
2223  *
2224  * Results:
2225  *
2226  * Side effects:
2227  *
2228  *--------------------------------------------------------------
2229  */
2230
2231 void
2232 gdk_flush (void)
2233 {
2234   XSync (gdk_display, False);
2235 }
2236
2237