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