]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkevents-x11.c
Move all X specific code into the x11/ directory. Aside from shuffling
[~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 /*
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 "gdkprivate.h"
29 #include "gdkx.h"
30
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 #include "gdkinputprivate.h"
41
42 typedef struct _GdkIOClosure GdkIOClosure;
43 typedef struct _GdkEventPrivate GdkEventPrivate;
44
45 #define DOUBLE_CLICK_TIME      250
46 #define TRIPLE_CLICK_TIME      500
47 #define DOUBLE_CLICK_DIST      5
48 #define TRIPLE_CLICK_DIST      5
49
50 typedef enum
51 {
52   /* Following flag is set for events on the event queue during
53    * translation and cleared afterwards.
54    */
55   GDK_EVENT_PENDING = 1 << 0
56 } GdkEventFlags;
57
58 struct _GdkIOClosure
59 {
60   GdkInputFunction function;
61   GdkInputCondition condition;
62   GdkDestroyNotify notify;
63   gpointer data;
64 };
65
66 struct _GdkEventPrivate
67 {
68   GdkEvent event;
69   guint    flags;
70 };
71
72 /* 
73  * Private function declarations
74  */
75
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
87 static gboolean  gdk_event_prepare      (gpointer   source_data, 
88                                          GTimeVal  *current_time,
89                                          gint      *timeout,
90                                          gpointer   user_data);
91 static gboolean  gdk_event_check        (gpointer   source_data,
92                                          GTimeVal  *current_time,
93                                          gpointer   user_data);
94 static gboolean  gdk_event_dispatch     (gpointer   source_data,
95                                          GTimeVal  *current_time,
96                                          gpointer   user_data);
97
98 GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev,
99                                          GdkEvent  *event,
100                                          gpointer   data);
101
102 /* Private variable declarations
103  */
104
105 static int connection_number = 0;           /* The file descriptor number of our
106                                              *  connection to the X server. This
107                                              *  is used so that we may determine
108                                              *  when events are pending by using
109                                              *  the "select" system call.
110                                              */
111 static GList *client_filters;               /* Filters for client messages */
112
113 static GSourceFuncs event_funcs = {
114   gdk_event_prepare,
115   gdk_event_check,
116   gdk_event_dispatch,
117   (GDestroyNotify)g_free
118 };
119
120 GPollFD event_poll_fd;
121
122 /*********************************************
123  * Functions for maintaining the event queue *
124  *********************************************/
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 (GDK_PRIORITY_EVENTS, 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   gdk_add_client_message_filter (gdk_wm_protocols, 
141                                  gdk_wm_protocols_filter, NULL);
142 }
143
144 /*
145  *--------------------------------------------------------------
146  * gdk_events_pending
147  *
148  *   Returns if events are pending on the queue.
149  *
150  * Arguments:
151  *
152  * Results:
153  *   Returns TRUE if events are pending
154  *
155  * Side effects:
156  *
157  *--------------------------------------------------------------
158  */
159
160 gboolean
161 gdk_events_pending (void)
162 {
163   return (gdk_event_queue_find_first() || XPending (gdk_display));
164 }
165
166 /*
167  *--------------------------------------------------------------
168  * gdk_event_get_graphics_expose
169  *
170  *   Waits for a GraphicsExpose or NoExpose event
171  *
172  * Arguments:
173  *
174  * Results: 
175  *   For GraphicsExpose events, returns a pointer to the event
176  *   converted into a GdkEvent Otherwise, returns NULL.
177  *
178  * Side effects:
179  *
180  *-------------------------------------------------------------- */
181
182 static Bool
183 graphics_expose_predicate (Display  *display,
184                            XEvent   *xevent,
185                            XPointer  arg)
186 {
187   if (xevent->xany.window == GDK_DRAWABLE_XID (arg) &&
188       (xevent->xany.type == GraphicsExpose ||
189        xevent->xany.type == NoExpose))
190     return True;
191   else
192     return False;
193 }
194
195 GdkEvent*
196 gdk_event_get_graphics_expose (GdkWindow *window)
197 {
198   XEvent xevent;
199   GdkEvent *event;
200   
201   g_return_val_if_fail (window != NULL, NULL);
202   
203   XIfEvent (gdk_display, &xevent, graphics_expose_predicate, (XPointer) window);
204   
205   if (xevent.xany.type == GraphicsExpose)
206     {
207       event = gdk_event_new ();
208       
209       if (gdk_event_translate (event, &xevent))
210         return event;
211       else
212         gdk_event_free (event);
213     }
214   
215   return NULL;  
216 }
217
218 /************************
219  * Exposure compression *
220  ************************/
221
222 /*
223  * The following implements simple exposure compression. It is
224  * modelled after the way Xt does exposure compression - in
225  * particular compress_expose = XtExposeCompressMultiple.
226  * It compress consecutive sequences of exposure events,
227  * but not sequences that cross other events. (This is because
228  * if it crosses a ConfigureNotify, we could screw up and
229  * mistakenly compress the exposures generated for the new
230  * size - could we just check for ConfigureNotify?)
231  *
232  * Xt compresses to a region / bounding rectangle, we compress
233  * to two rectangles, and try find the two rectangles of minimal
234  * area for this - this is supposed to handle the typical
235  * L-shaped regions generated by OpaqueMove.
236  */
237
238 /* Given three rectangles, find the two rectangles that cover
239  * them with the smallest area.
240  */
241 static void
242 gdk_add_rect_to_rects (GdkRectangle *rect1,
243                        GdkRectangle *rect2, 
244                        GdkRectangle *new_rect)
245 {
246   GdkRectangle t1, t2, t3;
247   gint size1, size2, size3;
248
249   gdk_rectangle_union (rect1, rect2, &t1);
250   gdk_rectangle_union (rect1, new_rect, &t2);
251   gdk_rectangle_union (rect2, new_rect, &t3);
252
253   size1 = t1.width * t1.height + new_rect->width * new_rect->height;
254   size2 = t2.width * t2.height + rect2->width * rect2->height;
255   size3 = t1.width * t1.height + rect1->width * rect1->height;
256
257   if (size1 < size2)
258     {
259       if (size1 < size3)
260         {
261           *rect1 = t1;
262           *rect2 = *new_rect;
263         }
264       else
265         *rect2 = t3;
266     }
267   else
268     {
269       if (size2 < size3)
270         *rect1 = t2;
271       else
272         *rect2 = t3;
273     }
274 }
275
276 typedef struct _GdkExposeInfo GdkExposeInfo;
277
278 struct _GdkExposeInfo
279 {
280   Window window;
281   gboolean seen_nonmatching;
282 };
283
284 static Bool
285 expose_predicate (Display *display,
286                   XEvent  *xevent,
287                   XPointer arg)
288 {
289   GdkExposeInfo *info = (GdkExposeInfo*) arg;
290
291   /* Compressing across GravityNotify events is safe, because
292    * we completely ignore them, so they can't change what
293    * we are going to draw. Compressing across GravityNotify
294    * events is necessay because during window-unshading animation
295    * we'll get a whole bunch of them interspersed with
296    * expose events.
297    */
298   if (xevent->xany.type != Expose && 
299       xevent->xany.type != GravityNotify)
300     {
301       info->seen_nonmatching = TRUE;
302     }
303
304   if (info->seen_nonmatching ||
305       xevent->xany.type != Expose ||
306       xevent->xany.window != info->window)
307     return FALSE;
308   else
309     return TRUE;
310 }
311
312 void
313 gdk_compress_exposures (XEvent    *xevent,
314                         GdkWindow *window)
315 {
316   gint nrects = 1;
317   gint count = 0;
318   GdkRectangle rect1;
319   GdkRectangle rect2;
320   GdkRectangle tmp_rect;
321   XEvent tmp_event;
322   GdkFilterReturn result;
323   GdkExposeInfo info;
324   GdkEvent event;
325
326   info.window = xevent->xany.window;
327   info.seen_nonmatching = FALSE;
328   
329   rect1.x = xevent->xexpose.x;
330   rect1.y = xevent->xexpose.y;
331   rect1.width = xevent->xexpose.width;
332   rect1.height = xevent->xexpose.height;
333
334   event.any.type = GDK_EXPOSE;
335   event.any.window = None;
336   event.any.send_event = FALSE;
337   
338   while (1)
339     {
340       if (count == 0)
341         {
342           if (!XCheckIfEvent (gdk_display, 
343                               &tmp_event, 
344                               expose_predicate, 
345                               (XPointer)&info))
346             break;
347         }
348       else
349         XIfEvent (gdk_display, 
350                   &tmp_event, 
351                   expose_predicate, 
352                   (XPointer)&info);
353
354       event.any.window = window;
355       
356       /* We apply filters here, and if it was filtered, completely
357        * ignore the return
358        */
359       result = gdk_event_apply_filters (xevent, &event,
360                                         window ? 
361                                           ((GdkWindowPrivate *)window)->filters
362                                           : gdk_default_filters);
363       
364       if (result != GDK_FILTER_CONTINUE)
365         {
366           if (result == GDK_FILTER_TRANSLATE)
367             gdk_event_put (&event);
368           continue;
369         }
370
371       if (nrects == 1)
372         {
373           rect2.x = tmp_event.xexpose.x;
374           rect2.y = tmp_event.xexpose.y;
375           rect2.width = tmp_event.xexpose.width;
376           rect2.height = tmp_event.xexpose.height;
377
378           nrects++;
379         }
380       else
381         {
382           tmp_rect.x = tmp_event.xexpose.x;
383           tmp_rect.y = tmp_event.xexpose.y;
384           tmp_rect.width = tmp_event.xexpose.width;
385           tmp_rect.height = tmp_event.xexpose.height;
386
387           gdk_add_rect_to_rects (&rect1, &rect2, &tmp_rect);
388         }
389
390       count = tmp_event.xexpose.count;
391     }
392
393   if (nrects == 2)
394     {
395       gdk_rectangle_union (&rect1, &rect2, &tmp_rect);
396
397       if ((tmp_rect.width * tmp_rect.height) <
398           2 * (rect1.height * rect1.width +
399                rect2.height * rect2.width))
400         {
401           rect1 = tmp_rect;
402           nrects = 1;
403         }
404     }
405
406   if (nrects == 2)
407     {
408       event.expose.type = GDK_EXPOSE;
409       event.expose.window = window;
410       event.expose.area.x = rect2.x;
411       event.expose.area.y = rect2.y;
412       event.expose.area.width = rect2.width;
413       event.expose.area.height = rect2.height;
414       event.expose.count = 0;
415
416       gdk_event_put (&event);
417     }
418
419   xevent->xexpose.count = nrects - 1;
420   xevent->xexpose.x = rect1.x;
421   xevent->xexpose.y = rect1.y;
422   xevent->xexpose.width = rect1.width;
423   xevent->xexpose.height = rect1.height;
424 }
425
426 static gint
427 gdk_event_apply_filters (XEvent *xevent,
428                          GdkEvent *event,
429                          GList *filters)
430 {
431   GList *tmp_list;
432   GdkFilterReturn result;
433   
434   tmp_list = filters;
435   
436   while (tmp_list)
437     {
438       GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data;
439       
440       tmp_list = tmp_list->next;
441       result = filter->function (xevent, event, filter->data);
442       if (result !=  GDK_FILTER_CONTINUE)
443         return result;
444     }
445   
446   return GDK_FILTER_CONTINUE;
447 }
448
449 void 
450 gdk_add_client_message_filter (GdkAtom       message_type,
451                                GdkFilterFunc func,
452                                gpointer      data)
453 {
454   GdkClientFilter *filter = g_new (GdkClientFilter, 1);
455
456   filter->type = message_type;
457   filter->function = func;
458   filter->data = data;
459   
460   client_filters = g_list_prepend (client_filters, filter);
461 }
462
463 static gint
464 gdk_event_translate (GdkEvent *event,
465                      XEvent   *xevent)
466 {
467   
468   GdkWindow *window;
469   GdkWindowPrivate *window_private;
470   static XComposeStatus compose;
471   KeySym keysym;
472   int charcount;
473 #ifdef USE_XIM
474   static gchar* buf = NULL;
475   static gint buf_len= 0;
476 #else
477   char buf[16];
478 #endif
479   gint return_val;
480   
481   return_val = FALSE;
482   
483   /* Find the GdkWindow that this event occurred in.
484    * 
485    * We handle events with window=None
486    *  specially - they are generated by XFree86's XInput under
487    *  some circumstances.
488    */
489   
490   if ((xevent->xany.window == None) &&
491       gdk_input_vtable.window_none_event)
492     {
493       return_val = gdk_input_vtable.window_none_event (event,xevent);
494       
495       if (return_val >= 0)      /* was handled */
496         return return_val;
497       else
498         return_val = FALSE;
499     }
500   
501   window = gdk_window_lookup (xevent->xany.window);
502   /* FIXME: window might be a GdkPixmap!!! */
503   
504   window_private = (GdkWindowPrivate *) window;
505   
506   if (window != NULL)
507     gdk_window_ref (window);
508   
509   event->any.window = window;
510   event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
511   
512   if (window_private && GDK_DRAWABLE_DESTROYED (window))
513     {
514       if (xevent->type != DestroyNotify)
515         return FALSE;
516     }
517   else
518     {
519       /* Check for filters for this window
520        */
521       GdkFilterReturn result;
522       result = gdk_event_apply_filters (xevent, event,
523                                         window_private
524                                         ?window_private->filters
525                                         :gdk_default_filters);
526       
527       if (result != GDK_FILTER_CONTINUE)
528         {
529           return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
530         }
531     }
532
533 #ifdef USE_XIM
534   if (window == NULL && gdk_xim_window && xevent->type == KeyPress &&
535       !GDK_DRAWABLE_DESTROYED (gdk_xim_window))
536     {
537       /*
538        * If user presses a key in Preedit or Status window, keypress event
539        * is sometimes sent to these windows. These windows are not managed
540        * by GDK, so we redirect KeyPress event to xim_window.
541        *
542        * If someone want to use the window whitch is not managed by GDK
543        * and want to get KeyPress event, he/she must register the filter
544        * function to gdk_default_filters to intercept the event.
545        */
546
547       GdkFilterReturn result;
548
549       window = gdk_xim_window;
550       window_private = (GdkWindowPrivate *) window;
551       gdk_window_ref (window);
552       event->any.window = window;
553
554       GDK_NOTE (XIM,
555         g_message ("KeyPress event is redirected to xim_window: %#lx",
556                    xevent->xany.window));
557
558       result = gdk_event_apply_filters (xevent, event,
559                                         window_private->filters);
560       if (result != GDK_FILTER_CONTINUE)
561         return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
562     }
563 #endif
564
565   /* We do a "manual" conversion of the XEvent to a
566    *  GdkEvent. The structures are mostly the same so
567    *  the conversion is fairly straightforward. We also
568    *  optionally print debugging info regarding events
569    *  received.
570    */
571
572   return_val = TRUE;
573
574   switch (xevent->type)
575     {
576     case KeyPress:
577       /* Lookup the string corresponding to the given keysym.
578        */
579       
580 #ifdef USE_XIM
581       if (buf_len == 0) 
582         {
583           buf_len = 128;
584           buf = g_new (gchar, buf_len);
585         }
586       keysym = GDK_VoidSymbol;
587       
588       if (gdk_xim_ic && gdk_xim_ic->xic)
589         {
590           Status status;
591           
592           /* Clear keyval. Depending on status, may not be set */
593           charcount = XmbLookupString(gdk_xim_ic->xic,
594                                       &xevent->xkey, buf, buf_len-1,
595                                       &keysym, &status);
596           if (status == XBufferOverflow)
597             {                     /* retry */
598               /* alloc adequate size of buffer */
599               GDK_NOTE (XIM,
600                         g_message("XIM: overflow (required %i)", charcount));
601               
602               while (buf_len <= charcount)
603                 buf_len *= 2;
604               buf = (gchar *) g_realloc (buf, buf_len);
605               
606               charcount = XmbLookupString (gdk_xim_ic->xic,
607                                            &xevent->xkey, buf, buf_len-1,
608                                            &keysym, &status);
609             }
610           if (status == XLookupNone)
611             {
612               return_val = FALSE;
613               break;
614             }
615         }
616       else
617         charcount = XLookupString (&xevent->xkey, buf, buf_len,
618                                    &keysym, &compose);
619 #else
620       charcount = XLookupString (&xevent->xkey, buf, 16,
621                                  &keysym, &compose);
622 #endif
623       event->key.keyval = keysym;
624       
625       if (charcount > 0 && buf[charcount-1] == '\0')
626         charcount --;
627       else
628         buf[charcount] = '\0';
629       
630       /* Print debugging info. */
631       
632 #ifdef G_ENABLE_DEBUG
633       if (gdk_debug_flags & GDK_DEBUG_EVENTS)
634         {
635           g_message ("key press:\twindow: %ld  key: %12s  %d",
636                      xevent->xkey.window,
637                      event->key.keyval ? XKeysymToString (event->key.keyval) : "(none)",
638                      event->key.keyval);
639           if (charcount > 0)
640             g_message ("\t\tlength: %4d string: \"%s\"",
641                        charcount, buf);
642         }
643 #endif /* G_ENABLE_DEBUG */
644       
645       event->key.type = GDK_KEY_PRESS;
646       event->key.window = window;
647       event->key.time = xevent->xkey.time;
648       event->key.state = (GdkModifierType) xevent->xkey.state;
649       event->key.string = g_strdup (buf);
650       event->key.length = charcount;
651       
652       break;
653       
654     case KeyRelease:
655       /* Lookup the string corresponding to the given keysym.
656        */
657 #ifdef USE_XIM
658       if (buf_len == 0) 
659         {
660           buf_len = 128;
661           buf = g_new (gchar, buf_len);
662         }
663 #endif
664       keysym = GDK_VoidSymbol;
665       charcount = XLookupString (&xevent->xkey, buf, 16,
666                                  &keysym, &compose);
667       event->key.keyval = keysym;      
668       
669       /* Print debugging info.
670        */
671       GDK_NOTE (EVENTS, 
672                 g_message ("key release:\t\twindow: %ld  key: %12s  %d",
673                            xevent->xkey.window,
674                            XKeysymToString (event->key.keyval),
675                            event->key.keyval));
676       
677       event->key.type = GDK_KEY_RELEASE;
678       event->key.window = window;
679       event->key.time = xevent->xkey.time;
680       event->key.state = (GdkModifierType) xevent->xkey.state;
681       event->key.length = 0;
682       event->key.string = NULL;
683       
684       break;
685       
686     case ButtonPress:
687       /* Print debugging info.
688        */
689       GDK_NOTE (EVENTS, 
690                 g_message ("button press:\t\twindow: %ld  x,y: %d %d  button: %d",
691                            xevent->xbutton.window,
692                            xevent->xbutton.x, xevent->xbutton.y,
693                            xevent->xbutton.button));
694       
695       if (window_private &&
696           (window_private->extension_events != 0) &&
697           gdk_input_ignore_core)
698         {
699           return_val = FALSE;
700           break;
701         }
702       
703       event->button.type = GDK_BUTTON_PRESS;
704       event->button.window = window;
705       event->button.time = xevent->xbutton.time;
706       event->button.x = xevent->xbutton.x;
707       event->button.y = xevent->xbutton.y;
708       event->button.x_root = (gfloat)xevent->xbutton.x_root;
709       event->button.y_root = (gfloat)xevent->xbutton.y_root;
710       event->button.pressure = 0.5;
711       event->button.xtilt = 0;
712       event->button.ytilt = 0;
713       event->button.state = (GdkModifierType) xevent->xbutton.state;
714       event->button.button = xevent->xbutton.button;
715       event->button.source = GDK_SOURCE_MOUSE;
716       event->button.deviceid = GDK_CORE_POINTER;
717
718       gdk_event_button_generate (event);
719       
720       break;
721       
722     case ButtonRelease:
723       /* Print debugging info.
724        */
725       GDK_NOTE (EVENTS, 
726                 g_message ("button release:\twindow: %ld  x,y: %d %d  button: %d",
727                            xevent->xbutton.window,
728                            xevent->xbutton.x, xevent->xbutton.y,
729                            xevent->xbutton.button));
730       
731       if (window_private &&
732           (window_private->extension_events != 0) &&
733           gdk_input_ignore_core)
734         {
735           return_val = FALSE;
736           break;
737         }
738       
739       event->button.type = GDK_BUTTON_RELEASE;
740       event->button.window = window;
741       event->button.time = xevent->xbutton.time;
742       event->button.x = xevent->xbutton.x;
743       event->button.y = xevent->xbutton.y;
744       event->button.x_root = (gfloat)xevent->xbutton.x_root;
745       event->button.y_root = (gfloat)xevent->xbutton.y_root;
746       event->button.pressure = 0.5;
747       event->button.xtilt = 0;
748       event->button.ytilt = 0;
749       event->button.state = (GdkModifierType) xevent->xbutton.state;
750       event->button.button = xevent->xbutton.button;
751       event->button.source = GDK_SOURCE_MOUSE;
752       event->button.deviceid = GDK_CORE_POINTER;
753       
754       break;
755       
756     case MotionNotify:
757       /* Print debugging info.
758        */
759       GDK_NOTE (EVENTS,
760                 g_message ("motion notify:\t\twindow: %ld  x,y: %d %d  hint: %s", 
761                            xevent->xmotion.window,
762                            xevent->xmotion.x, xevent->xmotion.y,
763                            (xevent->xmotion.is_hint) ? "true" : "false"));
764       
765       if (window_private &&
766           (window_private->extension_events != 0) &&
767           gdk_input_ignore_core)
768         {
769           return_val = FALSE;
770           break;
771         }
772       
773       event->motion.type = GDK_MOTION_NOTIFY;
774       event->motion.window = window;
775       event->motion.time = xevent->xmotion.time;
776       event->motion.x = xevent->xmotion.x;
777       event->motion.y = xevent->xmotion.y;
778       event->motion.x_root = (gfloat)xevent->xmotion.x_root;
779       event->motion.y_root = (gfloat)xevent->xmotion.y_root;
780       event->motion.pressure = 0.5;
781       event->motion.xtilt = 0;
782       event->motion.ytilt = 0;
783       event->motion.state = (GdkModifierType) xevent->xmotion.state;
784       event->motion.is_hint = xevent->xmotion.is_hint;
785       event->motion.source = GDK_SOURCE_MOUSE;
786       event->motion.deviceid = GDK_CORE_POINTER;
787       
788       break;
789       
790     case EnterNotify:
791       /* Print debugging info.
792        */
793       GDK_NOTE (EVENTS,
794                 g_message ("enter notify:\t\twindow: %ld  detail: %d subwin: %ld",
795                            xevent->xcrossing.window,
796                            xevent->xcrossing.detail,
797                            xevent->xcrossing.subwindow));
798       
799       /* Tell XInput stuff about it if appropriate */
800       if (window_private &&
801           !GDK_DRAWABLE_DESTROYED (window) &&
802           (window_private->extension_events != 0) &&
803           gdk_input_vtable.enter_event)
804         gdk_input_vtable.enter_event (&xevent->xcrossing, window);
805       
806       event->crossing.type = GDK_ENTER_NOTIFY;
807       event->crossing.window = window;
808       
809       /* If the subwindow field of the XEvent is non-NULL, then
810        *  lookup the corresponding GdkWindow.
811        */
812       if (xevent->xcrossing.subwindow != None)
813         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
814       else
815         event->crossing.subwindow = NULL;
816       
817       event->crossing.time = xevent->xcrossing.time;
818       event->crossing.x = xevent->xcrossing.x;
819       event->crossing.y = xevent->xcrossing.y;
820       event->crossing.x_root = xevent->xcrossing.x_root;
821       event->crossing.y_root = xevent->xcrossing.y_root;
822       
823       /* Translate the crossing mode into Gdk terms.
824        */
825       switch (xevent->xcrossing.mode)
826         {
827         case NotifyNormal:
828           event->crossing.mode = GDK_CROSSING_NORMAL;
829           break;
830         case NotifyGrab:
831           event->crossing.mode = GDK_CROSSING_GRAB;
832           break;
833         case NotifyUngrab:
834           event->crossing.mode = GDK_CROSSING_UNGRAB;
835           break;
836         };
837       
838       /* Translate the crossing detail into Gdk terms.
839        */
840       switch (xevent->xcrossing.detail)
841         {
842         case NotifyInferior:
843           event->crossing.detail = GDK_NOTIFY_INFERIOR;
844           break;
845         case NotifyAncestor:
846           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
847           break;
848         case NotifyVirtual:
849           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
850           break;
851         case NotifyNonlinear:
852           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
853           break;
854         case NotifyNonlinearVirtual:
855           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
856           break;
857         default:
858           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
859           break;
860         }
861       
862       event->crossing.focus = xevent->xcrossing.focus;
863       event->crossing.state = xevent->xcrossing.state;
864   
865       break;
866       
867     case LeaveNotify:
868       /* Print debugging info.
869        */
870       GDK_NOTE (EVENTS, 
871                 g_message ("leave notify:\t\twindow: %ld  detail: %d subwin: %ld",
872                            xevent->xcrossing.window,
873                            xevent->xcrossing.detail, xevent->xcrossing.subwindow));
874       
875       event->crossing.type = GDK_LEAVE_NOTIFY;
876       event->crossing.window = window;
877       
878       /* If the subwindow field of the XEvent is non-NULL, then
879        *  lookup the corresponding GdkWindow.
880        */
881       if (xevent->xcrossing.subwindow != None)
882         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
883       else
884         event->crossing.subwindow = NULL;
885       
886       event->crossing.time = xevent->xcrossing.time;
887       event->crossing.x = xevent->xcrossing.x;
888       event->crossing.y = xevent->xcrossing.y;
889       event->crossing.x_root = xevent->xcrossing.x_root;
890       event->crossing.y_root = xevent->xcrossing.y_root;
891       
892       /* Translate the crossing mode into Gdk terms.
893        */
894       switch (xevent->xcrossing.mode)
895         {
896         case NotifyNormal:
897           event->crossing.mode = GDK_CROSSING_NORMAL;
898           break;
899         case NotifyGrab:
900           event->crossing.mode = GDK_CROSSING_GRAB;
901           break;
902         case NotifyUngrab:
903           event->crossing.mode = GDK_CROSSING_UNGRAB;
904           break;
905         };
906       
907       /* Translate the crossing detail into Gdk terms.
908        */
909       switch (xevent->xcrossing.detail)
910         {
911         case NotifyInferior:
912           event->crossing.detail = GDK_NOTIFY_INFERIOR;
913           break;
914         case NotifyAncestor:
915           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
916           break;
917         case NotifyVirtual:
918           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
919           break;
920         case NotifyNonlinear:
921           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
922           break;
923         case NotifyNonlinearVirtual:
924           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
925           break;
926         default:
927           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
928           break;
929         }
930       
931       event->crossing.focus = xevent->xcrossing.focus;
932       event->crossing.state = xevent->xcrossing.state;
933       
934       break;
935       
936     case FocusIn:
937     case FocusOut:
938       /* We only care about focus events that indicate that _this_
939        * window (not a ancestor or child) got or lost the focus
940        */
941       switch (xevent->xfocus.detail)
942         {
943         case NotifyAncestor:
944         case NotifyInferior:
945         case NotifyNonlinear:
946           /* Print debugging info.
947            */
948           GDK_NOTE (EVENTS,
949                     g_message ("focus %s:\t\twindow: %ld",
950                                (xevent->xany.type == FocusIn) ? "in" : "out",
951                                xevent->xfocus.window));
952           
953           /* gdk_keyboard_grab() causes following events. These events confuse
954            * the XIM focus, so ignore them.
955            */
956           if (xevent->xfocus.mode == NotifyGrab ||
957               xevent->xfocus.mode == NotifyUngrab)
958             break;
959           
960           event->focus_change.type = GDK_FOCUS_CHANGE;
961           event->focus_change.window = window;
962           event->focus_change.in = (xevent->xany.type == FocusIn);
963
964           break;
965         default:
966           return_val = FALSE;
967         }
968       break;
969       
970     case KeymapNotify:
971       /* Print debugging info.
972        */
973       GDK_NOTE (EVENTS,
974                 g_message ("keymap notify"));
975
976       /* Not currently handled */
977       return_val = FALSE;
978       break;
979       
980     case Expose:
981       /* Print debugging info.
982        */
983       GDK_NOTE (EVENTS,
984                 g_message ("expose:\t\twindow: %ld  %d  x,y: %d %d  w,h: %d %d%s",
985                            xevent->xexpose.window, xevent->xexpose.count,
986                            xevent->xexpose.x, xevent->xexpose.y,
987                            xevent->xexpose.width, xevent->xexpose.height,
988                            event->any.send_event ? " (send)" : ""));
989       gdk_compress_exposures (xevent, window);
990       
991       event->expose.type = GDK_EXPOSE;
992       event->expose.window = window;
993       event->expose.area.x = xevent->xexpose.x;
994       event->expose.area.y = xevent->xexpose.y;
995       event->expose.area.width = xevent->xexpose.width;
996       event->expose.area.height = xevent->xexpose.height;
997       event->expose.count = xevent->xexpose.count;
998       
999       break;
1000       
1001     case GraphicsExpose:
1002       /* Print debugging info.
1003        */
1004       GDK_NOTE (EVENTS,
1005                 g_message ("graphics expose:\tdrawable: %ld",
1006                            xevent->xgraphicsexpose.drawable));
1007       
1008       event->expose.type = GDK_EXPOSE;
1009       event->expose.window = window;
1010       event->expose.area.x = xevent->xgraphicsexpose.x;
1011       event->expose.area.y = xevent->xgraphicsexpose.y;
1012       event->expose.area.width = xevent->xgraphicsexpose.width;
1013       event->expose.area.height = xevent->xgraphicsexpose.height;
1014       event->expose.count = xevent->xexpose.count;
1015       
1016       break;
1017       
1018     case NoExpose:
1019       /* Print debugging info.
1020        */
1021       GDK_NOTE (EVENTS,
1022                 g_message ("no expose:\t\tdrawable: %ld",
1023                            xevent->xnoexpose.drawable));
1024       
1025       event->no_expose.type = GDK_NO_EXPOSE;
1026       event->no_expose.window = window;
1027       
1028       break;
1029       
1030     case VisibilityNotify:
1031       /* Print debugging info.
1032        */
1033 #ifdef G_ENABLE_DEBUG
1034       if (gdk_debug_flags & GDK_DEBUG_EVENTS)
1035         switch (xevent->xvisibility.state)
1036           {
1037           case VisibilityFullyObscured:
1038             g_message ("visibility notify:\twindow: %ld  none",
1039                        xevent->xvisibility.window);
1040             break;
1041           case VisibilityPartiallyObscured:
1042             g_message ("visibility notify:\twindow: %ld  partial",
1043                        xevent->xvisibility.window);
1044             break;
1045           case VisibilityUnobscured:
1046             g_message ("visibility notify:\twindow: %ld  full",
1047                        xevent->xvisibility.window);
1048             break;
1049           }
1050 #endif /* G_ENABLE_DEBUG */
1051       
1052       event->visibility.type = GDK_VISIBILITY_NOTIFY;
1053       event->visibility.window = window;
1054       
1055       switch (xevent->xvisibility.state)
1056         {
1057         case VisibilityFullyObscured:
1058           event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED;
1059           break;
1060           
1061         case VisibilityPartiallyObscured:
1062           event->visibility.state = GDK_VISIBILITY_PARTIAL;
1063           break;
1064           
1065         case VisibilityUnobscured:
1066           event->visibility.state = GDK_VISIBILITY_UNOBSCURED;
1067           break;
1068         }
1069       
1070       break;
1071       
1072     case CreateNotify:
1073       GDK_NOTE (EVENTS,
1074                 g_message ("create notify:\twindow: %ld  x,y: %d %d     w,h: %d %d  b-w: %d  parent: %ld         ovr: %d",
1075                            xevent->xcreatewindow.window,
1076                            xevent->xcreatewindow.x,
1077                            xevent->xcreatewindow.y,
1078                            xevent->xcreatewindow.width,
1079                            xevent->xcreatewindow.height,
1080                            xevent->xcreatewindow.border_width,
1081                            xevent->xcreatewindow.parent,
1082                            xevent->xcreatewindow.override_redirect));
1083       /* not really handled */
1084       break;
1085       
1086     case DestroyNotify:
1087       /* Print debugging info.
1088        */
1089       GDK_NOTE (EVENTS,
1090                 g_message ("destroy notify:\twindow: %ld",
1091                            xevent->xdestroywindow.window));
1092       
1093       event->any.type = GDK_DESTROY;
1094       event->any.window = window;
1095       
1096       return_val = window_private && !GDK_DRAWABLE_DESTROYED (window);
1097       
1098       if (window && GDK_DRAWABLE_XID (window) != GDK_ROOT_WINDOW())
1099         gdk_window_destroy_notify (window);
1100       break;
1101       
1102     case UnmapNotify:
1103       /* Print debugging info.
1104        */
1105       GDK_NOTE (EVENTS,
1106                 g_message ("unmap notify:\t\twindow: %ld",
1107                            xevent->xmap.window));
1108       
1109       event->any.type = GDK_UNMAP;
1110       event->any.window = window;
1111       
1112       if (gdk_xgrab_window == window_private)
1113         gdk_xgrab_window = NULL;
1114       
1115       break;
1116       
1117     case MapNotify:
1118       /* Print debugging info.
1119        */
1120       GDK_NOTE (EVENTS,
1121                 g_message ("map notify:\t\twindow: %ld",
1122                            xevent->xmap.window));
1123       
1124       event->any.type = GDK_MAP;
1125       event->any.window = window;
1126       
1127       break;
1128       
1129     case ReparentNotify:
1130       /* Print debugging info.
1131        */
1132       GDK_NOTE (EVENTS,
1133                 g_message ("reparent notify:\twindow: %ld  x,y: %d %d  parent: %ld      ovr: %d",
1134                            xevent->xreparent.window,
1135                            xevent->xreparent.x,
1136                            xevent->xreparent.y,
1137                            xevent->xreparent.parent,
1138                            xevent->xreparent.override_redirect));
1139
1140       /* Not currently handled */
1141       return_val = FALSE;
1142       break;
1143       
1144     case ConfigureNotify:
1145       /* Print debugging info.
1146        */
1147       GDK_NOTE (EVENTS,
1148                 g_message ("configure notify:\twindow: %ld  x,y: %d %d  w,h: %d %d  b-w: %d  above: %ld  ovr: %d%s",
1149                            xevent->xconfigure.window,
1150                            xevent->xconfigure.x,
1151                            xevent->xconfigure.y,
1152                            xevent->xconfigure.width,
1153                            xevent->xconfigure.height,
1154                            xevent->xconfigure.border_width,
1155                            xevent->xconfigure.above,
1156                            xevent->xconfigure.override_redirect,
1157                            !window
1158                            ? " (discarding)"
1159                            : GDK_DRAWABLE_TYPE (window) == GDK_WINDOW_CHILD
1160                            ? " (discarding child)"
1161                            : ""));
1162       if (window &&
1163           !GDK_DRAWABLE_DESTROYED (window) &&
1164           (window_private->extension_events != 0) &&
1165           gdk_input_vtable.configure_event)
1166         gdk_input_vtable.configure_event (&xevent->xconfigure, window);
1167
1168       if (!window || GDK_DRAWABLE_TYPE (window) == GDK_WINDOW_CHILD)
1169         return_val = FALSE;
1170       else
1171         {
1172           event->configure.type = GDK_CONFIGURE;
1173           event->configure.window = window;
1174           event->configure.width = xevent->xconfigure.width;
1175           event->configure.height = xevent->xconfigure.height;
1176           
1177           if (!xevent->xconfigure.x &&
1178               !xevent->xconfigure.y &&
1179               !GDK_DRAWABLE_DESTROYED (window))
1180             {
1181               gint tx = 0;
1182               gint ty = 0;
1183               Window child_window = 0;
1184
1185               gdk_error_trap_push ();
1186               if (XTranslateCoordinates (GDK_DRAWABLE_XDISPLAY (window),
1187                                          GDK_DRAWABLE_XID (window),
1188                                          gdk_root_window,
1189                                          0, 0,
1190                                          &tx, &ty,
1191                                          &child_window))
1192                 {
1193                   if (!gdk_error_trap_pop ())
1194                     {
1195                       event->configure.x = tx;
1196                       event->configure.y = ty;
1197                     }
1198                 }
1199               else
1200                 gdk_error_trap_pop ();
1201             }
1202           else
1203             {
1204               event->configure.x = xevent->xconfigure.x;
1205               event->configure.y = xevent->xconfigure.y;
1206             }
1207           window_private->x = event->configure.x;
1208           window_private->y = event->configure.y;
1209           window_private->drawable.width = xevent->xconfigure.width;
1210           window_private->drawable.height = xevent->xconfigure.height;
1211           if (window_private->resize_count > 1)
1212             window_private->resize_count -= 1;
1213         }
1214       break;
1215       
1216     case PropertyNotify:
1217       /* Print debugging info.
1218        */
1219       GDK_NOTE (EVENTS,
1220                 gchar *atom = gdk_atom_name (xevent->xproperty.atom);
1221                 g_message ("property notify:\twindow: %ld, atom(%ld): %s%s%s",
1222                            xevent->xproperty.window,
1223                            xevent->xproperty.atom,
1224                            atom ? "\"" : "",
1225                            atom ? atom : "unknown",
1226                            atom ? "\"" : "");
1227                 g_free (atom);
1228                 );
1229       
1230       event->property.type = GDK_PROPERTY_NOTIFY;
1231       event->property.window = window;
1232       event->property.atom = xevent->xproperty.atom;
1233       event->property.time = xevent->xproperty.time;
1234       event->property.state = xevent->xproperty.state;
1235       
1236       break;
1237       
1238     case SelectionClear:
1239       GDK_NOTE (EVENTS,
1240                 g_message ("selection clear:\twindow: %ld",
1241                            xevent->xproperty.window));
1242       
1243       event->selection.type = GDK_SELECTION_CLEAR;
1244       event->selection.window = window;
1245       event->selection.selection = xevent->xselectionclear.selection;
1246       event->selection.time = xevent->xselectionclear.time;
1247       
1248       break;
1249       
1250     case SelectionRequest:
1251       GDK_NOTE (EVENTS,
1252                 g_message ("selection request:\twindow: %ld",
1253                            xevent->xproperty.window));
1254       
1255       event->selection.type = GDK_SELECTION_REQUEST;
1256       event->selection.window = window;
1257       event->selection.selection = xevent->xselectionrequest.selection;
1258       event->selection.target = xevent->xselectionrequest.target;
1259       event->selection.property = xevent->xselectionrequest.property;
1260       event->selection.requestor = xevent->xselectionrequest.requestor;
1261       event->selection.time = xevent->xselectionrequest.time;
1262       
1263       break;
1264       
1265     case SelectionNotify:
1266       GDK_NOTE (EVENTS,
1267                 g_message ("selection notify:\twindow: %ld",
1268                            xevent->xproperty.window));
1269       
1270       
1271       event->selection.type = GDK_SELECTION_NOTIFY;
1272       event->selection.window = window;
1273       event->selection.selection = xevent->xselection.selection;
1274       event->selection.target = xevent->xselection.target;
1275       event->selection.property = xevent->xselection.property;
1276       event->selection.time = xevent->xselection.time;
1277       
1278       break;
1279       
1280     case ColormapNotify:
1281       /* Print debugging info.
1282        */
1283       GDK_NOTE (EVENTS,
1284                 g_message ("colormap notify:\twindow: %ld",
1285                            xevent->xcolormap.window));
1286       
1287       /* Not currently handled */
1288       return_val = FALSE;
1289       break;
1290       
1291     case ClientMessage:
1292       {
1293         GList *tmp_list;
1294         GdkFilterReturn result = GDK_FILTER_CONTINUE;
1295
1296         /* Print debugging info.
1297          */
1298         GDK_NOTE (EVENTS,
1299                   g_message ("client message:\twindow: %ld",
1300                              xevent->xclient.window));
1301         
1302         tmp_list = client_filters;
1303         while (tmp_list)
1304           {
1305             GdkClientFilter *filter = tmp_list->data;
1306             if (filter->type == xevent->xclient.message_type)
1307               {
1308                 result = (*filter->function) (xevent, event, filter->data);
1309                 break;
1310               }
1311             
1312             tmp_list = tmp_list->next;
1313           }
1314
1315         switch (result)
1316           {
1317           case GDK_FILTER_REMOVE:
1318             return_val = FALSE;
1319             break;
1320           case GDK_FILTER_TRANSLATE:
1321             return_val = TRUE;
1322             break;
1323           case GDK_FILTER_CONTINUE:
1324             /* Send unknown ClientMessage's on to Gtk for it to use */
1325             event->client.type = GDK_CLIENT_EVENT;
1326             event->client.window = window;
1327             event->client.message_type = xevent->xclient.message_type;
1328             event->client.data_format = xevent->xclient.format;
1329             memcpy(&event->client.data, &xevent->xclient.data,
1330                    sizeof(event->client.data));
1331           }
1332       }
1333       
1334       break;
1335       
1336     case MappingNotify:
1337       /* Print debugging info.
1338        */
1339       GDK_NOTE (EVENTS,
1340                 g_message ("mapping notify"));
1341       
1342       /* Let XLib know that there is a new keyboard mapping.
1343        */
1344       XRefreshKeyboardMapping (&xevent->xmapping);
1345       return_val = FALSE;
1346       break;
1347       
1348     default:
1349       /* something else - (e.g., a Xinput event) */
1350       
1351       if (window_private &&
1352           !window_private->drawable.destroyed &&
1353           (window_private->extension_events != 0) &&
1354           gdk_input_vtable.other_event)
1355         return_val = gdk_input_vtable.other_event(event, xevent, window);
1356       else
1357         return_val = FALSE;
1358       
1359       break;
1360     }
1361   
1362   if (return_val)
1363     {
1364       if (event->any.window)
1365         gdk_window_ref (event->any.window);
1366       if (((event->any.type == GDK_ENTER_NOTIFY) ||
1367            (event->any.type == GDK_LEAVE_NOTIFY)) &&
1368           (event->crossing.subwindow != NULL))
1369         gdk_window_ref (event->crossing.subwindow);
1370     }
1371   else
1372     {
1373       /* Mark this event as having no resources to be freed */
1374       event->any.window = NULL;
1375       event->any.type = GDK_NOTHING;
1376     }
1377   
1378   if (window)
1379     gdk_window_unref (window);
1380   
1381   return return_val;
1382 }
1383
1384 GdkFilterReturn
1385 gdk_wm_protocols_filter (GdkXEvent *xev,
1386                          GdkEvent  *event,
1387                          gpointer data)
1388 {
1389   XEvent *xevent = (XEvent *)xev;
1390
1391   if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window)
1392     {
1393   /* The delete window request specifies a window
1394    *  to delete. We don't actually destroy the
1395    *  window because "it is only a request". (The
1396    *  window might contain vital data that the
1397    *  program does not want destroyed). Instead
1398    *  the event is passed along to the program,
1399    *  which should then destroy the window.
1400    */
1401       GDK_NOTE (EVENTS,
1402                 g_message ("delete window:\t\twindow: %ld",
1403                            xevent->xclient.window));
1404       
1405       event->any.type = GDK_DELETE;
1406
1407       return GDK_FILTER_TRANSLATE;
1408     }
1409   else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
1410     {
1411     }
1412
1413   return GDK_FILTER_REMOVE;
1414 }
1415
1416 #if 0
1417 static Bool
1418 gdk_event_get_type (Display  *display,
1419                     XEvent   *xevent,
1420                     XPointer  arg)
1421 {
1422   GdkEvent event;
1423   GdkPredicate *pred;
1424   
1425   if (gdk_event_translate (&event, xevent))
1426     {
1427       pred = (GdkPredicate*) arg;
1428       return (* pred->func) (&event, pred->data);
1429     }
1430   
1431   return FALSE;
1432 }
1433 #endif
1434
1435 void
1436 gdk_events_queue (void)
1437 {
1438   GList *node;
1439   GdkEvent *event;
1440   XEvent xevent;
1441
1442   while (!gdk_event_queue_find_first() && XPending (gdk_display))
1443     {
1444 #ifdef USE_XIM
1445       Window w = None;
1446       
1447       XNextEvent (gdk_display, &xevent);
1448       if (gdk_xim_window)
1449         switch (xevent.type)
1450           {
1451           case KeyPress:
1452           case KeyRelease:
1453           case ButtonPress:
1454           case ButtonRelease:
1455             w = GDK_WINDOW_XWINDOW (gdk_xim_window);
1456             break;
1457           }
1458       
1459       if (XFilterEvent (&xevent, w))
1460         continue;
1461 #else
1462       XNextEvent (gdk_display, &xevent);
1463 #endif
1464       
1465       event = gdk_event_new ();
1466       
1467       event->any.type = GDK_NOTHING;
1468       event->any.window = NULL;
1469       event->any.send_event = xevent.xany.send_event ? TRUE : FALSE;
1470
1471       ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
1472
1473       gdk_event_queue_append (event);
1474       node = gdk_queued_tail;
1475
1476       if (gdk_event_translate (event, &xevent))
1477         {
1478           ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
1479         }
1480       else
1481         {
1482           gdk_event_queue_remove_link (node);
1483           g_list_free_1 (node);
1484           gdk_event_free (event);
1485         }
1486     }
1487 }
1488
1489 static gboolean  
1490 gdk_event_prepare (gpointer  source_data, 
1491                    GTimeVal *current_time,
1492                    gint     *timeout,
1493                    gpointer  user_data)
1494 {
1495   gboolean retval;
1496   
1497   GDK_THREADS_ENTER ();
1498
1499   *timeout = -1;
1500
1501   retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
1502
1503   GDK_THREADS_LEAVE ();
1504
1505   return retval;
1506 }
1507
1508 static gboolean  
1509 gdk_event_check (gpointer  source_data,
1510                  GTimeVal *current_time,
1511                  gpointer  user_data)
1512 {
1513   gboolean retval;
1514   
1515   GDK_THREADS_ENTER ();
1516
1517   if (event_poll_fd.revents & G_IO_IN)
1518     retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
1519   else
1520     retval = FALSE;
1521
1522   GDK_THREADS_LEAVE ();
1523
1524   return retval;
1525 }
1526
1527 static gboolean  
1528 gdk_event_dispatch (gpointer  source_data,
1529                     GTimeVal *current_time,
1530                     gpointer  user_data)
1531 {
1532   GdkEvent *event;
1533  
1534   GDK_THREADS_ENTER ();
1535
1536   gdk_events_queue();
1537   event = gdk_event_unqueue();
1538
1539   if (event)
1540     {
1541       if (gdk_event_func)
1542         (*gdk_event_func) (event, gdk_event_data);
1543       
1544       gdk_event_free (event);
1545     }
1546   
1547   GDK_THREADS_LEAVE ();
1548
1549   return TRUE;
1550 }
1551
1552 /* Sends a ClientMessage to all toplevel client windows */
1553 gboolean
1554 gdk_event_send_client_message (GdkEvent *event, guint32 xid)
1555 {
1556   XEvent sev;
1557   
1558   g_return_val_if_fail(event != NULL, FALSE);
1559   
1560   /* Set up our event to send, with the exception of its target window */
1561   sev.xclient.type = ClientMessage;
1562   sev.xclient.display = gdk_display;
1563   sev.xclient.format = event->client.data_format;
1564   sev.xclient.window = xid;
1565   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
1566   sev.xclient.message_type = event->client.message_type;
1567   
1568   return gdk_send_xevent (xid, False, NoEventMask, &sev);
1569 }
1570
1571 /* Sends a ClientMessage to all toplevel client windows */
1572 gboolean
1573 gdk_event_send_client_message_to_all_recurse (XEvent  *xev, 
1574                                               guint32  xid,
1575                                               guint    level)
1576 {
1577   static GdkAtom wm_state_atom = GDK_NONE;
1578   Atom type = None;
1579   int format;
1580   unsigned long nitems, after;
1581   unsigned char *data;
1582   Window *ret_children, ret_root, ret_parent;
1583   unsigned int ret_nchildren;
1584   gint old_warnings = gdk_error_warnings;
1585   gboolean send = FALSE;
1586   gboolean found = FALSE;
1587   int i;
1588
1589   if (!wm_state_atom)
1590     wm_state_atom = gdk_atom_intern ("WM_STATE", FALSE);
1591
1592   gdk_error_warnings = FALSE;
1593   gdk_error_code = 0;
1594   XGetWindowProperty (gdk_display, xid, wm_state_atom, 0, 0, False, AnyPropertyType,
1595                       &type, &format, &nitems, &after, &data);
1596
1597   if (gdk_error_code)
1598     {
1599       gdk_error_warnings = old_warnings;
1600
1601       return FALSE;
1602     }
1603
1604   if (type)
1605     {
1606       send = TRUE;
1607       XFree (data);
1608     }
1609   else
1610     {
1611       /* OK, we're all set, now let's find some windows to send this to */
1612       if (XQueryTree (gdk_display, xid, &ret_root, &ret_parent,
1613                       &ret_children, &ret_nchildren) != True ||
1614           gdk_error_code)
1615         {
1616           gdk_error_warnings = old_warnings;
1617
1618           return FALSE;
1619         }
1620
1621       for(i = 0; i < ret_nchildren; i++)
1622         if (gdk_event_send_client_message_to_all_recurse (xev, ret_children[i], level + 1))
1623           found = TRUE;
1624
1625       XFree (ret_children);
1626     }
1627
1628   if (send || (!found && (level == 1)))
1629     {
1630       xev->xclient.window = xid;
1631       gdk_send_xevent (xid, False, NoEventMask, xev);
1632     }
1633
1634   gdk_error_warnings = old_warnings;
1635
1636   return (send || found);
1637 }
1638
1639 void
1640 gdk_event_send_clientmessage_toall (GdkEvent *event)
1641 {
1642   XEvent sev;
1643   gint old_warnings = gdk_error_warnings;
1644
1645   g_return_if_fail(event != NULL);
1646   
1647   /* Set up our event to send, with the exception of its target window */
1648   sev.xclient.type = ClientMessage;
1649   sev.xclient.display = gdk_display;
1650   sev.xclient.format = event->client.data_format;
1651   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
1652   sev.xclient.message_type = event->client.message_type;
1653
1654   gdk_event_send_client_message_to_all_recurse(&sev, gdk_root_window, 0);
1655
1656   gdk_error_warnings = old_warnings;
1657 }
1658
1659 /*
1660  *--------------------------------------------------------------
1661  * gdk_flush
1662  *
1663  *   Flushes the Xlib output buffer and then waits
1664  *   until all requests have been received and processed
1665  *   by the X server. The only real use for this function
1666  *   is in dealing with XShm.
1667  *
1668  * Arguments:
1669  *
1670  * Results:
1671  *
1672  * Side effects:
1673  *
1674  *--------------------------------------------------------------
1675  */
1676
1677 void
1678 gdk_flush (void)
1679 {
1680   XSync (gdk_display, False);
1681 }
1682
1683