]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkevents-x11.c
test the window state stuff
[~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 Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "gdk.h"
28 #include "gdkprivate-x11.h"
29 #include "gdkinternals.h"
30 #include "gdkx.h"
31
32 #include "gdkkeysyms.h"
33
34 #if HAVE_CONFIG_H
35 #  include <config.h>
36 #  if STDC_HEADERS
37 #    include <string.h>
38 #  endif
39 #endif
40
41 #include "gdkinputprivate.h"
42
43 #ifdef HAVE_XKB
44 #include <X11/XKBlib.h>
45 #endif
46
47 #include <X11/Xatom.h>
48
49 typedef struct _GdkIOClosure GdkIOClosure;
50 typedef struct _GdkEventPrivate GdkEventPrivate;
51
52 #define DOUBLE_CLICK_TIME      250
53 #define TRIPLE_CLICK_TIME      500
54 #define DOUBLE_CLICK_DIST      5
55 #define TRIPLE_CLICK_DIST      5
56
57 typedef enum
58 {
59   /* Following flag is set for events on the event queue during
60    * translation and cleared afterwards.
61    */
62   GDK_EVENT_PENDING = 1 << 0
63 } GdkEventFlags;
64
65 struct _GdkIOClosure
66 {
67   GdkInputFunction function;
68   GdkInputCondition condition;
69   GdkDestroyNotify notify;
70   gpointer data;
71 };
72
73 struct _GdkEventPrivate
74 {
75   GdkEvent event;
76   guint    flags;
77 };
78
79 /* 
80  * Private function declarations
81  */
82
83 static gint      gdk_event_apply_filters (XEvent   *xevent,
84                                           GdkEvent *event,
85                                           GList    *filters);
86 static gint      gdk_event_translate     (GdkEvent *event, 
87                                           XEvent   *xevent,
88                                           gboolean  return_exposes);
89 #if 0
90 static Bool      gdk_event_get_type     (Display   *display, 
91                                          XEvent    *xevent, 
92                                          XPointer   arg);
93 #endif
94
95 static gboolean gdk_event_prepare  (GSource     *source,
96                                     gint        *timeout);
97 static gboolean gdk_event_check    (GSource     *source);
98 static gboolean gdk_event_dispatch (GSource     *source,
99                                     GSourceFunc  callback,
100                                     gpointer     user_data);
101
102 GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev,
103                                          GdkEvent  *event,
104                                          gpointer   data);
105
106 /* Private variable declarations
107  */
108
109 static int connection_number = 0;           /* The file descriptor number of our
110                                              *  connection to the X server. This
111                                              *  is used so that we may determine
112                                              *  when events are pending by using
113                                              *  the "select" system call.
114                                              */
115 static GList *client_filters;               /* Filters for client messages */
116
117 static GSourceFuncs event_funcs = {
118   gdk_event_prepare,
119   gdk_event_check,
120   gdk_event_dispatch,
121   NULL
122 };
123
124 static GPollFD event_poll_fd;
125
126 static Window wmspec_check_window = None;
127
128 /*********************************************
129  * Functions for maintaining the event queue *
130  *********************************************/
131
132 void 
133 gdk_events_init (void)
134 {
135   GSource *source;
136   
137   connection_number = ConnectionNumber (gdk_display);
138   GDK_NOTE (MISC,
139             g_message ("connection number: %d", connection_number));
140
141
142   source = g_source_new (&event_funcs, sizeof (GSource));
143   g_source_set_priority (source, GDK_PRIORITY_EVENTS);
144   
145   event_poll_fd.fd = connection_number;
146   event_poll_fd.events = G_IO_IN;
147   
148   g_source_add_poll (source, &event_poll_fd);
149   g_source_set_can_recurse (source, TRUE);
150   g_source_attach (source, NULL);
151
152   gdk_add_client_message_filter (gdk_wm_protocols, 
153                                  gdk_wm_protocols_filter, NULL);
154 }
155
156 /*
157  *--------------------------------------------------------------
158  * gdk_events_pending
159  *
160  *   Returns if events are pending on the queue.
161  *
162  * Arguments:
163  *
164  * Results:
165  *   Returns TRUE if events are pending
166  *
167  * Side effects:
168  *
169  *--------------------------------------------------------------
170  */
171
172 gboolean
173 gdk_events_pending (void)
174 {
175   return (gdk_event_queue_find_first() || XPending (gdk_display));
176 }
177
178 /*
179  *--------------------------------------------------------------
180  * gdk_event_get_graphics_expose
181  *
182  *   Waits for a GraphicsExpose or NoExpose event
183  *
184  * Arguments:
185  *
186  * Results: 
187  *   For GraphicsExpose events, returns a pointer to the event
188  *   converted into a GdkEvent Otherwise, returns NULL.
189  *
190  * Side effects:
191  *
192  *-------------------------------------------------------------- */
193
194 static Bool
195 graphics_expose_predicate (Display  *display,
196                            XEvent   *xevent,
197                            XPointer  arg)
198 {
199   if (xevent->xany.window == GDK_DRAWABLE_XID (arg) &&
200       (xevent->xany.type == GraphicsExpose ||
201        xevent->xany.type == NoExpose))
202     return True;
203   else
204     return False;
205 }
206
207 GdkEvent*
208 gdk_event_get_graphics_expose (GdkWindow *window)
209 {
210   XEvent xevent;
211   GdkEvent *event;
212   
213   g_return_val_if_fail (window != NULL, NULL);
214   
215   XIfEvent (gdk_display, &xevent, graphics_expose_predicate, (XPointer) window);
216   
217   if (xevent.xany.type == GraphicsExpose)
218     {
219       event = gdk_event_new ();
220       
221       if (gdk_event_translate (event, &xevent, TRUE))
222         return event;
223       else
224         gdk_event_free (event);
225     }
226   
227   return NULL;  
228 }
229
230 static gint
231 gdk_event_apply_filters (XEvent *xevent,
232                          GdkEvent *event,
233                          GList *filters)
234 {
235   GList *tmp_list;
236   GdkFilterReturn result;
237   
238   tmp_list = filters;
239   
240   while (tmp_list)
241     {
242       GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data;
243       
244       tmp_list = tmp_list->next;
245       result = filter->function (xevent, event, filter->data);
246       if (result !=  GDK_FILTER_CONTINUE)
247         return result;
248     }
249   
250   return GDK_FILTER_CONTINUE;
251 }
252
253 void 
254 gdk_add_client_message_filter (GdkAtom       message_type,
255                                GdkFilterFunc func,
256                                gpointer      data)
257 {
258   GdkClientFilter *filter = g_new (GdkClientFilter, 1);
259
260   filter->type = message_type;
261   filter->function = func;
262   filter->data = data;
263   
264   client_filters = g_list_prepend (client_filters, filter);
265 }
266
267 static GdkAtom wm_state_atom = 0;
268 static GdkAtom wm_desktop_atom = 0;
269
270 static void
271 gdk_check_wm_state_changed (GdkWindow *window)
272 {  
273   Atom type;
274   gint format;
275   gulong nitems;
276   gulong bytes_after;
277   GdkAtom *atoms = NULL;
278   gulong i;
279   GdkAtom sticky_atom;
280   GdkAtom maxvert_atom;
281   GdkAtom maxhorz_atom;
282   gboolean found_sticky, found_maxvert, found_maxhorz;
283   GdkWindowState old_state;
284   
285   if (GDK_WINDOW_DESTROYED (window))
286     return;
287   
288   if (wm_state_atom == 0)
289     wm_state_atom = gdk_atom_intern ("_NET_WM_STATE", FALSE);
290
291   if (wm_desktop_atom == 0)
292     wm_desktop_atom = gdk_atom_intern ("_NET_WM_DESKTOP", FALSE);
293   
294   XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
295                       wm_state_atom, 0, G_MAXLONG,
296                       False, XA_ATOM, &type, &format, &nitems,
297                       &bytes_after, (guchar **)&atoms);
298
299   if (type != None)
300     {
301
302       sticky_atom = gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE);
303       maxvert_atom = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE);
304       maxhorz_atom = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE);    
305
306       found_sticky = FALSE;
307       found_maxvert = FALSE;
308       found_maxhorz = FALSE;
309   
310       i = 0;
311       while (i < nitems)
312         {
313           if (atoms[i] == sticky_atom)
314             found_sticky = TRUE;
315           else if (atoms[i] == maxvert_atom)
316             found_maxvert = TRUE;
317           else if (atoms[i] == maxhorz_atom)
318             found_maxhorz = TRUE;
319
320           ++i;
321         }
322
323       XFree (atoms);
324     }
325   else
326     {
327       found_sticky = FALSE;
328       found_maxvert = FALSE;
329       found_maxhorz = FALSE;
330     }
331
332   /* For found_sticky to remain TRUE, we have to also be on desktop
333    * 0xFFFFFFFF
334    */
335
336   if (found_sticky)
337     {
338       gulong *desktop;
339       
340       XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
341                           wm_desktop_atom, 0, G_MAXLONG,
342                           False, XA_CARDINAL, &type, &format, &nitems,
343                           &bytes_after, (guchar **)&desktop);
344
345       if (type != None)
346         {
347           if (*desktop != 0xFFFFFFFF)
348             found_sticky = FALSE;
349           XFree (desktop);
350         }
351     }
352           
353   old_state = gdk_window_get_state (window);
354
355   if (old_state & GDK_WINDOW_STATE_STICKY)
356     {
357       if (!found_sticky)
358         gdk_synthesize_window_state (window,
359                                      GDK_WINDOW_STATE_STICKY,
360                                      0);
361     }
362   else
363     {
364       if (found_sticky)
365         gdk_synthesize_window_state (window,
366                                      0,
367                                      GDK_WINDOW_STATE_STICKY);
368     }
369
370   /* Our "maximized" means both vertical and horizontal; if only one,
371    * we don't expose that via GDK
372    */
373   if (old_state & GDK_WINDOW_STATE_MAXIMIZED)
374     {
375       if (!(found_maxvert && found_maxhorz))
376         gdk_synthesize_window_state (window,
377                                      GDK_WINDOW_STATE_MAXIMIZED,
378                                      0);
379     }
380   else
381     {
382       if (found_maxvert && found_maxhorz)
383         gdk_synthesize_window_state (window,
384                                      0,
385                                      GDK_WINDOW_STATE_MAXIMIZED);
386     }
387 }
388
389 static gint
390 gdk_event_translate (GdkEvent *event,
391                      XEvent   *xevent,
392                      gboolean  return_exposes)
393 {
394   
395   GdkWindow *window;
396   GdkWindowObject *window_private;
397   static XComposeStatus compose;
398   KeySym keysym;
399   int charcount;
400 #ifdef USE_XIM
401   static gchar* buf = NULL;
402   static gint buf_len= 0;
403 #else
404   char buf[16];
405 #endif
406   gint return_val;
407   gint xoffset, yoffset;
408   
409   return_val = FALSE;
410   
411   /* Find the GdkWindow that this event occurred in.
412    * 
413    * We handle events with window=None
414    *  specially - they are generated by XFree86's XInput under
415    *  some circumstances.
416    */
417   
418   if (xevent->xany.window == None)
419     {
420       return_val = _gdk_input_window_none_event (event, xevent);
421       
422       if (return_val >= 0)      /* was handled */
423         return return_val;
424       else
425         return_val = FALSE;
426     }
427   
428   window = gdk_window_lookup (xevent->xany.window);
429   /* FIXME: window might be a GdkPixmap!!! */
430   
431   window_private = (GdkWindowObject *) window;
432   
433   if (window != NULL)
434     gdk_window_ref (window);
435
436   if (wmspec_check_window != None &&
437       xevent->xany.window == wmspec_check_window)
438     {
439       if (xevent->type == DestroyNotify)
440         wmspec_check_window = None;
441       
442       /* Eat events on this window unless someone had wrapped
443        * it as a foreign window
444        */
445       if (window == NULL)
446         return FALSE;
447     }
448   
449   event->any.window = window;
450   event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
451   
452   if (window_private && GDK_WINDOW_DESTROYED (window))
453     {
454       if (xevent->type != DestroyNotify)
455         return FALSE;
456     }
457   else
458     {
459       /* Check for filters for this window
460        */
461       GdkFilterReturn result;
462       result = gdk_event_apply_filters (xevent, event,
463                                         window_private
464                                         ?window_private->filters
465                                         :gdk_default_filters);
466       
467       if (result != GDK_FILTER_CONTINUE)
468         {
469           return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
470           goto done;
471         }
472     }
473
474 #ifdef USE_XIM
475   if (window == NULL && gdk_xim_window && xevent->type == KeyPress &&
476       !GDK_WINDOW_DESTROYED (gdk_xim_window))
477     {
478       /*
479        * If user presses a key in Preedit or Status window, keypress event
480        * is sometimes sent to these windows. These windows are not managed
481        * by GDK, so we redirect KeyPress event to xim_window.
482        *
483        * If someone want to use the window whitch is not managed by GDK
484        * and want to get KeyPress event, he/she must register the filter
485        * function to gdk_default_filters to intercept the event.
486        */
487
488       GdkFilterReturn result;
489
490       window = gdk_xim_window;
491       window_private = (GdkWindowObject *) window;
492       gdk_window_ref (window);
493       event->any.window = window;
494
495       GDK_NOTE (XIM,
496         g_message ("KeyPress event is redirected to xim_window: %#lx",
497                    xevent->xany.window));
498
499       result = gdk_event_apply_filters (xevent, event,
500                                         window_private->filters);
501       if (result != GDK_FILTER_CONTINUE)
502         {
503           return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
504           goto done;
505         }
506     }
507 #endif
508
509   /* We do a "manual" conversion of the XEvent to a
510    *  GdkEvent. The structures are mostly the same so
511    *  the conversion is fairly straightforward. We also
512    *  optionally print debugging info regarding events
513    *  received.
514    */
515
516   return_val = TRUE;
517
518   if (window)
519     {
520       _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
521     }
522   else
523     {
524       xoffset = 0;
525       yoffset = 0;
526     }
527
528   switch (xevent->type)
529     {
530     case KeyPress:
531       /* Lookup the string corresponding to the given keysym.
532        */
533       
534 #ifdef USE_XIM
535       if (buf_len == 0) 
536         {
537           buf_len = 128;
538           buf = g_new (gchar, buf_len);
539         }
540       keysym = GDK_VoidSymbol;
541       
542       if (gdk_xim_ic && gdk_xim_ic->xic)
543         {
544           Status status;
545           
546           /* Clear keyval. Depending on status, may not be set */
547           charcount = XmbLookupString(gdk_xim_ic->xic,
548                                       &xevent->xkey, buf, buf_len-1,
549                                       &keysym, &status);
550           if (status == XBufferOverflow)
551             {                     /* retry */
552               /* alloc adequate size of buffer */
553               GDK_NOTE (XIM,
554                         g_message("XIM: overflow (required %i)", charcount));
555               
556               while (buf_len <= charcount)
557                 buf_len *= 2;
558               buf = (gchar *) g_realloc (buf, buf_len);
559               
560               charcount = XmbLookupString (gdk_xim_ic->xic,
561                                            &xevent->xkey, buf, buf_len-1,
562                                            &keysym, &status);
563             }
564           if (status == XLookupNone)
565             {
566               return_val = FALSE;
567               break;
568             }
569         }
570       else
571         charcount = XLookupString (&xevent->xkey, buf, buf_len,
572                                    &keysym, &compose);
573 #else
574       charcount = XLookupString (&xevent->xkey, buf, 16,
575                                  &keysym, &compose);
576 #endif
577       event->key.keyval = keysym;
578       event->key.hardware_keycode = xevent->xkey.keycode;
579       
580       if (charcount > 0 && buf[charcount-1] == '\0')
581         charcount --;
582       else
583         buf[charcount] = '\0';
584       
585 #ifdef G_ENABLE_DEBUG
586       if (gdk_debug_flags & GDK_DEBUG_EVENTS)
587         {
588           g_message ("key press:\twindow: %ld  key: %12s  %d",
589                      xevent->xkey.window,
590                      event->key.keyval ? XKeysymToString (event->key.keyval) : "(none)",
591                      event->key.keyval);
592           if (charcount > 0)
593             g_message ("\t\tlength: %4d string: \"%s\"",
594                        charcount, buf);
595         }
596 #endif /* G_ENABLE_DEBUG */
597
598       /* bits 13 and 14 in the "state" field are the keyboard group */
599 #define KEYBOARD_GROUP_MASK ((1 << 13) | (1 << 14))
600       
601       event->key.type = GDK_KEY_PRESS;
602       event->key.window = window;
603       event->key.time = xevent->xkey.time;
604       event->key.state = (GdkModifierType) xevent->xkey.state;
605       event->key.string = g_strdup (buf);
606       event->key.length = charcount;
607
608       event->key.group = xevent->xkey.state & KEYBOARD_GROUP_MASK;
609       
610       break;
611       
612     case KeyRelease:
613       /* Lookup the string corresponding to the given keysym.
614        */
615 #ifdef USE_XIM
616       if (buf_len == 0) 
617         {
618           buf_len = 128;
619           buf = g_new (gchar, buf_len);
620         }
621 #endif
622       keysym = GDK_VoidSymbol;
623       charcount = XLookupString (&xevent->xkey, buf, 16,
624                                  &keysym, &compose);
625       event->key.keyval = keysym;      
626       
627       GDK_NOTE (EVENTS, 
628                 g_message ("key release:\t\twindow: %ld  key: %12s  %d",
629                            xevent->xkey.window,
630                            XKeysymToString (event->key.keyval),
631                            event->key.keyval));
632       
633       event->key.type = GDK_KEY_RELEASE;
634       event->key.window = window;
635       event->key.time = xevent->xkey.time;
636       event->key.state = (GdkModifierType) xevent->xkey.state;
637       event->key.length = 0;
638       event->key.string = NULL;
639       
640       break;
641       
642     case ButtonPress:
643       GDK_NOTE (EVENTS, 
644                 g_message ("button press:\t\twindow: %ld  x,y: %d %d  button: %d",
645                            xevent->xbutton.window,
646                            xevent->xbutton.x, xevent->xbutton.y,
647                            xevent->xbutton.button));
648       
649       if (window_private &&
650           (window_private->extension_events != 0) &&
651           gdk_input_ignore_core)
652         {
653           return_val = FALSE;
654           break;
655         }
656       
657       /* If we get a ButtonPress event where the button is 4 or 5,
658          it's a Scroll event */
659       if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5)
660         {
661           event->scroll.type = GDK_SCROLL;
662           event->scroll.direction = (xevent->xbutton.button == 4) ? 
663             GDK_SCROLL_UP : GDK_SCROLL_DOWN;
664           event->scroll.window = window;
665           event->scroll.time = xevent->xbutton.x;
666           event->scroll.x = xevent->xbutton.x + xoffset;
667           event->scroll.y = xevent->xbutton.y + yoffset;
668           event->scroll.x_root = (gfloat)xevent->xbutton.x_root;
669           event->scroll.y_root = (gfloat)xevent->xbutton.y_root;
670           event->scroll.state = (GdkModifierType) xevent->xbutton.state;
671           event->scroll.device = gdk_core_pointer;
672         }
673       else
674         {
675           event->button.type = GDK_BUTTON_PRESS;
676           event->button.window = window;
677           event->button.time = xevent->xbutton.time;
678           event->button.x = xevent->xbutton.x + xoffset;
679           event->button.y = xevent->xbutton.y + yoffset;
680           event->button.x_root = (gfloat)xevent->xbutton.x_root;
681           event->button.y_root = (gfloat)xevent->xbutton.y_root;
682           event->button.axes = NULL;
683           event->button.state = (GdkModifierType) xevent->xbutton.state;
684           event->button.button = xevent->xbutton.button;
685           event->button.device = gdk_core_pointer;
686           
687           gdk_event_button_generate (event);
688         }
689
690       break;
691       
692     case ButtonRelease:
693       GDK_NOTE (EVENTS, 
694                 g_message ("button release:\twindow: %ld  x,y: %d %d  button: %d",
695                            xevent->xbutton.window,
696                            xevent->xbutton.x, xevent->xbutton.y,
697                            xevent->xbutton.button));
698       
699       if (window_private &&
700           (window_private->extension_events != 0) &&
701           gdk_input_ignore_core)
702         {
703           return_val = FALSE;
704           break;
705         }
706       
707       /* We treat button presses as scroll wheel events, so ignore the release */
708       if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5)
709         {
710           return_val = FALSE;
711           break;
712         }
713
714       event->button.type = GDK_BUTTON_RELEASE;
715       event->button.window = window;
716       event->button.time = xevent->xbutton.time;
717       event->button.x = xevent->xbutton.x + xoffset;
718       event->button.y = xevent->xbutton.y + yoffset;
719       event->button.x_root = (gfloat)xevent->xbutton.x_root;
720       event->button.y_root = (gfloat)xevent->xbutton.y_root;
721       event->button.axes = NULL;
722       event->button.state = (GdkModifierType) xevent->xbutton.state;
723       event->button.button = xevent->xbutton.button;
724       event->button.device = gdk_core_pointer;
725       
726       break;
727       
728     case MotionNotify:
729       GDK_NOTE (EVENTS,
730                 g_message ("motion notify:\t\twindow: %ld  x,y: %d %d  hint: %s", 
731                            xevent->xmotion.window,
732                            xevent->xmotion.x, xevent->xmotion.y,
733                            (xevent->xmotion.is_hint) ? "true" : "false"));
734       
735       if (window_private &&
736           (window_private->extension_events != 0) &&
737           gdk_input_ignore_core)
738         {
739           return_val = FALSE;
740           break;
741         }
742       
743       event->motion.type = GDK_MOTION_NOTIFY;
744       event->motion.window = window;
745       event->motion.time = xevent->xmotion.time;
746       event->motion.x = xevent->xmotion.x + xoffset;
747       event->motion.y = xevent->xmotion.y + yoffset;
748       event->motion.x_root = (gfloat)xevent->xmotion.x_root;
749       event->motion.y_root = (gfloat)xevent->xmotion.y_root;
750       event->motion.axes = NULL;
751       event->motion.state = (GdkModifierType) xevent->xmotion.state;
752       event->motion.is_hint = xevent->xmotion.is_hint;
753       event->motion.device = gdk_core_pointer;
754       
755       break;
756       
757     case EnterNotify:
758       GDK_NOTE (EVENTS,
759                 g_message ("enter notify:\t\twindow: %ld  detail: %d subwin: %ld",
760                            xevent->xcrossing.window,
761                            xevent->xcrossing.detail,
762                            xevent->xcrossing.subwindow));
763       
764       /* Tell XInput stuff about it if appropriate */
765       if (window_private &&
766           !GDK_WINDOW_DESTROYED (window) &&
767           window_private->extension_events != 0)
768         _gdk_input_enter_event (&xevent->xcrossing, window);
769       
770       event->crossing.type = GDK_ENTER_NOTIFY;
771       event->crossing.window = window;
772       
773       /* If the subwindow field of the XEvent is non-NULL, then
774        *  lookup the corresponding GdkWindow.
775        */
776       if (xevent->xcrossing.subwindow != None)
777         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
778       else
779         event->crossing.subwindow = NULL;
780       
781       event->crossing.time = xevent->xcrossing.time;
782       event->crossing.x = xevent->xcrossing.x + xoffset;
783       event->crossing.y = xevent->xcrossing.y + yoffset;
784       event->crossing.x_root = xevent->xcrossing.x_root;
785       event->crossing.y_root = xevent->xcrossing.y_root;
786       
787       /* Translate the crossing mode into Gdk terms.
788        */
789       switch (xevent->xcrossing.mode)
790         {
791         case NotifyNormal:
792           event->crossing.mode = GDK_CROSSING_NORMAL;
793           break;
794         case NotifyGrab:
795           event->crossing.mode = GDK_CROSSING_GRAB;
796           break;
797         case NotifyUngrab:
798           event->crossing.mode = GDK_CROSSING_UNGRAB;
799           break;
800         };
801       
802       /* Translate the crossing detail into Gdk terms.
803        */
804       switch (xevent->xcrossing.detail)
805         {
806         case NotifyInferior:
807           event->crossing.detail = GDK_NOTIFY_INFERIOR;
808           break;
809         case NotifyAncestor:
810           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
811           break;
812         case NotifyVirtual:
813           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
814           break;
815         case NotifyNonlinear:
816           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
817           break;
818         case NotifyNonlinearVirtual:
819           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
820           break;
821         default:
822           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
823           break;
824         }
825       
826       event->crossing.focus = xevent->xcrossing.focus;
827       event->crossing.state = xevent->xcrossing.state;
828   
829       break;
830       
831     case LeaveNotify:
832       GDK_NOTE (EVENTS, 
833                 g_message ("leave notify:\t\twindow: %ld  detail: %d subwin: %ld",
834                            xevent->xcrossing.window,
835                            xevent->xcrossing.detail, xevent->xcrossing.subwindow));
836       
837       event->crossing.type = GDK_LEAVE_NOTIFY;
838       event->crossing.window = window;
839       
840       /* If the subwindow field of the XEvent is non-NULL, then
841        *  lookup the corresponding GdkWindow.
842        */
843       if (xevent->xcrossing.subwindow != None)
844         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
845       else
846         event->crossing.subwindow = NULL;
847       
848       event->crossing.time = xevent->xcrossing.time;
849       event->crossing.x = xevent->xcrossing.x + xoffset;
850       event->crossing.y = xevent->xcrossing.y + yoffset;
851       event->crossing.x_root = xevent->xcrossing.x_root;
852       event->crossing.y_root = xevent->xcrossing.y_root;
853       
854       /* Translate the crossing mode into Gdk terms.
855        */
856       switch (xevent->xcrossing.mode)
857         {
858         case NotifyNormal:
859           event->crossing.mode = GDK_CROSSING_NORMAL;
860           break;
861         case NotifyGrab:
862           event->crossing.mode = GDK_CROSSING_GRAB;
863           break;
864         case NotifyUngrab:
865           event->crossing.mode = GDK_CROSSING_UNGRAB;
866           break;
867         };
868       
869       /* Translate the crossing detail into Gdk terms.
870        */
871       switch (xevent->xcrossing.detail)
872         {
873         case NotifyInferior:
874           event->crossing.detail = GDK_NOTIFY_INFERIOR;
875           break;
876         case NotifyAncestor:
877           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
878           break;
879         case NotifyVirtual:
880           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
881           break;
882         case NotifyNonlinear:
883           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
884           break;
885         case NotifyNonlinearVirtual:
886           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
887           break;
888         default:
889           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
890           break;
891         }
892       
893       event->crossing.focus = xevent->xcrossing.focus;
894       event->crossing.state = xevent->xcrossing.state;
895       
896       break;
897       
898     case FocusIn:
899     case FocusOut:
900       /* We only care about focus events that indicate that _this_
901        * window (not a ancestor or child) got or lost the focus
902        */
903       switch (xevent->xfocus.detail)
904         {
905         case NotifyAncestor:
906         case NotifyInferior:
907         case NotifyNonlinear:
908           GDK_NOTE (EVENTS,
909                     g_message ("focus %s:\t\twindow: %ld",
910                                (xevent->xany.type == FocusIn) ? "in" : "out",
911                                xevent->xfocus.window));
912           
913           /* gdk_keyboard_grab() causes following events. These events confuse
914            * the XIM focus, so ignore them.
915            */
916           if (xevent->xfocus.mode == NotifyGrab ||
917               xevent->xfocus.mode == NotifyUngrab)
918             break;
919           
920           event->focus_change.type = GDK_FOCUS_CHANGE;
921           event->focus_change.window = window;
922           event->focus_change.in = (xevent->xany.type == FocusIn);
923
924           break;
925         default:
926           return_val = FALSE;
927         }
928       break;
929       
930     case KeymapNotify:
931       GDK_NOTE (EVENTS,
932                 g_message ("keymap notify"));
933
934       /* Not currently handled */
935       return_val = FALSE;
936       break;
937       
938     case Expose:
939       GDK_NOTE (EVENTS,
940                 g_message ("expose:\t\twindow: %ld  %d  x,y: %d %d  w,h: %d %d%s",
941                            xevent->xexpose.window, xevent->xexpose.count,
942                            xevent->xexpose.x, xevent->xexpose.y,
943                            xevent->xexpose.width, xevent->xexpose.height,
944                            event->any.send_event ? " (send)" : ""));
945       {
946         GdkRectangle expose_rect;
947
948         expose_rect.x = xevent->xexpose.x + xoffset;
949         expose_rect.y = xevent->xexpose.y + yoffset;
950         expose_rect.width = xevent->xexpose.width;
951         expose_rect.height = xevent->xexpose.height;
952
953         if (return_exposes)
954           {
955             event->expose.type = GDK_EXPOSE;
956             event->expose.area = expose_rect;
957             event->expose.window = window;
958             event->expose.count = xevent->xexpose.count;
959
960             return_val = TRUE;
961           }
962         else
963           {
964             _gdk_window_process_expose (window, xevent->xexpose.serial, &expose_rect);
965
966             return_val = FALSE;
967           }
968         
969         return_val = FALSE;
970       }
971         
972       break;
973       
974     case GraphicsExpose:
975       {
976         GdkRectangle expose_rect;
977
978         GDK_NOTE (EVENTS,
979                   g_message ("graphics expose:\tdrawable: %ld",
980                              xevent->xgraphicsexpose.drawable));
981
982         expose_rect.x = xevent->xgraphicsexpose.x + xoffset;
983         expose_rect.y = xevent->xgraphicsexpose.y + yoffset;
984         expose_rect.width = xevent->xgraphicsexpose.width;
985         expose_rect.height = xevent->xgraphicsexpose.height;
986             
987         if (return_exposes)
988           {
989             event->expose.type = GDK_EXPOSE;
990             event->expose.area = expose_rect;
991             event->expose.window = window;
992             event->expose.count = xevent->xgraphicsexpose.count;
993
994             return_val = TRUE;
995           }
996         else
997           {
998             _gdk_window_process_expose (window, xevent->xgraphicsexpose.serial, &expose_rect);
999             
1000             return_val = FALSE;
1001           }
1002         
1003       }
1004       break;
1005       
1006     case NoExpose:
1007       GDK_NOTE (EVENTS,
1008                 g_message ("no expose:\t\tdrawable: %ld",
1009                            xevent->xnoexpose.drawable));
1010       
1011       event->no_expose.type = GDK_NO_EXPOSE;
1012       event->no_expose.window = window;
1013       
1014       break;
1015       
1016     case VisibilityNotify:
1017 #ifdef G_ENABLE_DEBUG
1018       if (gdk_debug_flags & GDK_DEBUG_EVENTS)
1019         switch (xevent->xvisibility.state)
1020           {
1021           case VisibilityFullyObscured:
1022             g_message ("visibility notify:\twindow: %ld  none",
1023                        xevent->xvisibility.window);
1024             break;
1025           case VisibilityPartiallyObscured:
1026             g_message ("visibility notify:\twindow: %ld  partial",
1027                        xevent->xvisibility.window);
1028             break;
1029           case VisibilityUnobscured:
1030             g_message ("visibility notify:\twindow: %ld  full",
1031                        xevent->xvisibility.window);
1032             break;
1033           }
1034 #endif /* G_ENABLE_DEBUG */
1035       
1036       event->visibility.type = GDK_VISIBILITY_NOTIFY;
1037       event->visibility.window = window;
1038       
1039       switch (xevent->xvisibility.state)
1040         {
1041         case VisibilityFullyObscured:
1042           event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED;
1043           break;
1044           
1045         case VisibilityPartiallyObscured:
1046           event->visibility.state = GDK_VISIBILITY_PARTIAL;
1047           break;
1048           
1049         case VisibilityUnobscured:
1050           event->visibility.state = GDK_VISIBILITY_UNOBSCURED;
1051           break;
1052         }
1053       
1054       break;
1055       
1056     case CreateNotify:
1057       GDK_NOTE (EVENTS,
1058                 g_message ("create notify:\twindow: %ld  x,y: %d %d     w,h: %d %d  b-w: %d  parent: %ld         ovr: %d",
1059                            xevent->xcreatewindow.window,
1060                            xevent->xcreatewindow.x,
1061                            xevent->xcreatewindow.y,
1062                            xevent->xcreatewindow.width,
1063                            xevent->xcreatewindow.height,
1064                            xevent->xcreatewindow.border_width,
1065                            xevent->xcreatewindow.parent,
1066                            xevent->xcreatewindow.override_redirect));
1067       /* not really handled */
1068       break;
1069       
1070     case DestroyNotify:
1071       GDK_NOTE (EVENTS,
1072                 g_message ("destroy notify:\twindow: %ld",
1073                            xevent->xdestroywindow.window));
1074       
1075       event->any.type = GDK_DESTROY;
1076       event->any.window = window;
1077       
1078       return_val = window_private && !GDK_WINDOW_DESTROYED (window);
1079       
1080       if (window && GDK_WINDOW_XID (window) != GDK_ROOT_WINDOW())
1081         gdk_window_destroy_notify (window);
1082       break;
1083       
1084     case UnmapNotify:
1085       GDK_NOTE (EVENTS,
1086                 g_message ("unmap notify:\t\twindow: %ld",
1087                            xevent->xmap.window));
1088       
1089       event->any.type = GDK_UNMAP;
1090       event->any.window = window;      
1091
1092       /* If we are shown (not withdrawn) and get an unmap, it means we
1093        * were iconified in the X sense. If we are withdrawn, and get
1094        * an unmap, it means we hid the window ourselves, so we
1095        * will have already flipped the iconified bit off.
1096        */
1097       if (GDK_WINDOW_IS_MAPPED (window))
1098         gdk_synthesize_window_state (window,
1099                                      0,
1100                                      GDK_WINDOW_STATE_ICONIFIED);
1101       
1102       if (gdk_xgrab_window == window_private)
1103         gdk_xgrab_window = NULL;
1104       
1105       break;
1106       
1107     case MapNotify:
1108       GDK_NOTE (EVENTS,
1109                 g_message ("map notify:\t\twindow: %ld",
1110                            xevent->xmap.window));
1111       
1112       event->any.type = GDK_MAP;
1113       event->any.window = window;
1114
1115       /* Unset iconified if it was set */
1116       if (((GdkWindowObject*)window)->state & GDK_WINDOW_STATE_ICONIFIED)
1117         gdk_synthesize_window_state (window,
1118                                      GDK_WINDOW_STATE_ICONIFIED,
1119                                      0);
1120       
1121       break;
1122       
1123     case ReparentNotify:
1124       GDK_NOTE (EVENTS,
1125                 g_message ("reparent notify:\twindow: %ld  x,y: %d %d  parent: %ld      ovr: %d",
1126                            xevent->xreparent.window,
1127                            xevent->xreparent.x,
1128                            xevent->xreparent.y,
1129                            xevent->xreparent.parent,
1130                            xevent->xreparent.override_redirect));
1131
1132       /* Not currently handled */
1133       return_val = FALSE;
1134       break;
1135       
1136     case ConfigureNotify:
1137       GDK_NOTE (EVENTS,
1138                 g_message ("configure notify:\twindow: %ld  x,y: %d %d  w,h: %d %d  b-w: %d  above: %ld  ovr: %d%s",
1139                            xevent->xconfigure.window,
1140                            xevent->xconfigure.x,
1141                            xevent->xconfigure.y,
1142                            xevent->xconfigure.width,
1143                            xevent->xconfigure.height,
1144                            xevent->xconfigure.border_width,
1145                            xevent->xconfigure.above,
1146                            xevent->xconfigure.override_redirect,
1147                            !window
1148                            ? " (discarding)"
1149                            : GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD
1150                            ? " (discarding child)"
1151                            : ""));
1152       if (window &&
1153           !GDK_WINDOW_DESTROYED (window) &&
1154           (window_private->extension_events != 0))
1155         _gdk_input_configure_event (&xevent->xconfigure, window);
1156
1157       if (!window || GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
1158         return_val = FALSE;
1159       else
1160         {
1161           event->configure.type = GDK_CONFIGURE;
1162           event->configure.window = window;
1163           event->configure.width = xevent->xconfigure.width;
1164           event->configure.height = xevent->xconfigure.height;
1165           
1166           if (!xevent->xconfigure.x &&
1167               !xevent->xconfigure.y &&
1168               !GDK_WINDOW_DESTROYED (window))
1169             {
1170               gint tx = 0;
1171               gint ty = 0;
1172               Window child_window = 0;
1173
1174               gdk_error_trap_push ();
1175               if (XTranslateCoordinates (GDK_DRAWABLE_XDISPLAY (window),
1176                                          GDK_DRAWABLE_XID (window),
1177                                          gdk_root_window,
1178                                          0, 0,
1179                                          &tx, &ty,
1180                                          &child_window))
1181                 {
1182                   if (!gdk_error_trap_pop ())
1183                     {
1184                       event->configure.x = tx;
1185                       event->configure.y = ty;
1186                     }
1187                 }
1188               else
1189                 gdk_error_trap_pop ();
1190             }
1191           else
1192             {
1193               event->configure.x = xevent->xconfigure.x;
1194               event->configure.y = xevent->xconfigure.y;
1195             }
1196           window_private->x = event->configure.x;
1197           window_private->y = event->configure.y;
1198           GDK_WINDOW_IMPL_X11 (window_private->impl)->width = xevent->xconfigure.width;
1199           GDK_WINDOW_IMPL_X11 (window_private->impl)->height = xevent->xconfigure.height;
1200           if (window_private->resize_count > 1)
1201             window_private->resize_count -= 1;
1202         }
1203       break;
1204       
1205     case PropertyNotify:
1206       GDK_NOTE (EVENTS,
1207                 gchar *atom = gdk_atom_name (xevent->xproperty.atom);
1208                 g_message ("property notify:\twindow: %ld, atom(%ld): %s%s%s",
1209                            xevent->xproperty.window,
1210                            xevent->xproperty.atom,
1211                            atom ? "\"" : "",
1212                            atom ? atom : "unknown",
1213                            atom ? "\"" : "");
1214                 g_free (atom);
1215                 );
1216       
1217       event->property.type = GDK_PROPERTY_NOTIFY;
1218       event->property.window = window;
1219       event->property.atom = xevent->xproperty.atom;
1220       event->property.time = xevent->xproperty.time;
1221       event->property.state = xevent->xproperty.state;
1222
1223       if (wm_state_atom == 0)
1224         wm_state_atom = gdk_atom_intern ("_NET_WM_STATE", FALSE);
1225
1226       if (wm_desktop_atom == 0)
1227         wm_desktop_atom = gdk_atom_intern ("_NET_WM_DESKTOP", FALSE);
1228       
1229       if (event->property.atom == wm_state_atom ||
1230           event->property.atom == wm_desktop_atom)
1231         {
1232           /* If window state changed, then synthesize those events. */
1233           gdk_check_wm_state_changed (event->property.window);
1234         }
1235       
1236       break;
1237       
1238     case SelectionClear:
1239       GDK_NOTE (EVENTS,
1240                 g_message ("selection clear:\twindow: %ld",
1241                            xevent->xproperty.window));
1242
1243       if (_gdk_selection_filter_clear_event (&xevent->xselectionclear))
1244         {
1245           event->selection.type = GDK_SELECTION_CLEAR;
1246           event->selection.window = window;
1247           event->selection.selection = xevent->xselectionclear.selection;
1248           event->selection.time = xevent->xselectionclear.time;
1249         }
1250       else
1251         return_val = FALSE;
1252           
1253       break;
1254       
1255     case SelectionRequest:
1256       GDK_NOTE (EVENTS,
1257                 g_message ("selection request:\twindow: %ld",
1258                            xevent->xproperty.window));
1259       
1260       event->selection.type = GDK_SELECTION_REQUEST;
1261       event->selection.window = window;
1262       event->selection.selection = xevent->xselectionrequest.selection;
1263       event->selection.target = xevent->xselectionrequest.target;
1264       event->selection.property = xevent->xselectionrequest.property;
1265       event->selection.requestor = xevent->xselectionrequest.requestor;
1266       event->selection.time = xevent->xselectionrequest.time;
1267       
1268       break;
1269       
1270     case SelectionNotify:
1271       GDK_NOTE (EVENTS,
1272                 g_message ("selection notify:\twindow: %ld",
1273                            xevent->xproperty.window));
1274       
1275       
1276       event->selection.type = GDK_SELECTION_NOTIFY;
1277       event->selection.window = window;
1278       event->selection.selection = xevent->xselection.selection;
1279       event->selection.target = xevent->xselection.target;
1280       event->selection.property = xevent->xselection.property;
1281       event->selection.time = xevent->xselection.time;
1282       
1283       break;
1284       
1285     case ColormapNotify:
1286       GDK_NOTE (EVENTS,
1287                 g_message ("colormap notify:\twindow: %ld",
1288                            xevent->xcolormap.window));
1289       
1290       /* Not currently handled */
1291       return_val = FALSE;
1292       break;
1293       
1294     case ClientMessage:
1295       {
1296         GList *tmp_list;
1297         GdkFilterReturn result = GDK_FILTER_CONTINUE;
1298
1299         GDK_NOTE (EVENTS,
1300                   g_message ("client message:\twindow: %ld",
1301                              xevent->xclient.window));
1302         
1303         tmp_list = client_filters;
1304         while (tmp_list)
1305           {
1306             GdkClientFilter *filter = tmp_list->data;
1307             if (filter->type == xevent->xclient.message_type)
1308               {
1309                 result = (*filter->function) (xevent, event, filter->data);
1310                 break;
1311               }
1312             
1313             tmp_list = tmp_list->next;
1314           }
1315
1316         switch (result)
1317           {
1318           case GDK_FILTER_REMOVE:
1319             return_val = FALSE;
1320             break;
1321           case GDK_FILTER_TRANSLATE:
1322             return_val = TRUE;
1323             break;
1324           case GDK_FILTER_CONTINUE:
1325             /* Send unknown ClientMessage's on to Gtk for it to use */
1326             event->client.type = GDK_CLIENT_EVENT;
1327             event->client.window = window;
1328             event->client.message_type = xevent->xclient.message_type;
1329             event->client.data_format = xevent->xclient.format;
1330             memcpy(&event->client.data, &xevent->xclient.data,
1331                    sizeof(event->client.data));
1332           }
1333       }
1334       
1335       break;
1336       
1337     case MappingNotify:
1338       GDK_NOTE (EVENTS,
1339                 g_message ("mapping notify"));
1340       
1341       /* Let XLib know that there is a new keyboard mapping.
1342        */
1343       XRefreshKeyboardMapping (&xevent->xmapping);
1344       ++_gdk_keymap_serial;
1345       return_val = FALSE;
1346       break;
1347
1348 #ifdef HAVE_XKB
1349     case XkbMapNotify:
1350       ++_gdk_keymap_serial;
1351       return_val = FALSE;
1352       break;
1353 #endif
1354       
1355     default:
1356       /* something else - (e.g., a Xinput event) */
1357       
1358       if (window_private &&
1359           !GDK_WINDOW_DESTROYED (window_private) &&
1360           (window_private->extension_events != 0))
1361         return_val = _gdk_input_other_event(event, xevent, window);
1362       else
1363         return_val = FALSE;
1364       
1365       break;
1366     }
1367
1368  done:
1369   if (return_val)
1370     {
1371       if (event->any.window)
1372         gdk_window_ref (event->any.window);
1373       if (((event->any.type == GDK_ENTER_NOTIFY) ||
1374            (event->any.type == GDK_LEAVE_NOTIFY)) &&
1375           (event->crossing.subwindow != NULL))
1376         gdk_window_ref (event->crossing.subwindow);
1377     }
1378   else
1379     {
1380       /* Mark this event as having no resources to be freed */
1381       event->any.window = NULL;
1382       event->any.type = GDK_NOTHING;
1383     }
1384   
1385   if (window)
1386     gdk_window_unref (window);
1387   
1388   return return_val;
1389 }
1390
1391 GdkFilterReturn
1392 gdk_wm_protocols_filter (GdkXEvent *xev,
1393                          GdkEvent  *event,
1394                          gpointer data)
1395 {
1396   XEvent *xevent = (XEvent *)xev;
1397
1398   if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window)
1399     {
1400   /* The delete window request specifies a window
1401    *  to delete. We don't actually destroy the
1402    *  window because "it is only a request". (The
1403    *  window might contain vital data that the
1404    *  program does not want destroyed). Instead
1405    *  the event is passed along to the program,
1406    *  which should then destroy the window.
1407    */
1408       GDK_NOTE (EVENTS,
1409                 g_message ("delete window:\t\twindow: %ld",
1410                            xevent->xclient.window));
1411       
1412       event->any.type = GDK_DELETE;
1413
1414       return GDK_FILTER_TRANSLATE;
1415     }
1416   else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
1417     {
1418     }
1419   else if ((Atom) xevent->xclient.data.l[0] == gdk_atom_intern ("_NET_WM_PING", FALSE))
1420     {
1421       XEvent xev = *xevent;
1422       
1423       xev.xclient.window = gdk_root_window;
1424       XSendEvent (gdk_display, gdk_root_window, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
1425     }
1426
1427   return GDK_FILTER_REMOVE;
1428 }
1429
1430 #if 0
1431 static Bool
1432 gdk_event_get_type (Display  *display,
1433                     XEvent   *xevent,
1434                     XPointer  arg)
1435 {
1436   GdkEvent event;
1437   GdkPredicate *pred;
1438   
1439   if (gdk_event_translate (&event, xevent, FALSE))
1440     {
1441       pred = (GdkPredicate*) arg;
1442       return (* pred->func) (&event, pred->data);
1443     }
1444   
1445   return FALSE;
1446 }
1447 #endif
1448
1449 void
1450 gdk_events_queue (void)
1451 {
1452   GList *node;
1453   GdkEvent *event;
1454   XEvent xevent;
1455
1456   while (!gdk_event_queue_find_first() && XPending (gdk_display))
1457     {
1458 #ifdef USE_XIM
1459       Window w = None;
1460       
1461       XNextEvent (gdk_display, &xevent);
1462       if (gdk_xim_window)
1463         switch (xevent.type)
1464           {
1465           case KeyPress:
1466           case KeyRelease:
1467           case ButtonPress:
1468           case ButtonRelease:
1469             w = GDK_WINDOW_XWINDOW (gdk_xim_window);
1470             break;
1471           }
1472
1473       if (XFilterEvent (&xevent, w))
1474         continue;
1475 #else
1476       XNextEvent (gdk_display, &xevent);
1477 #endif
1478
1479       switch (xevent.type)
1480         {
1481         case KeyPress:
1482         case KeyRelease:
1483           break;
1484         default:
1485           if (XFilterEvent (&xevent, None))
1486             continue;
1487         }
1488       
1489       event = gdk_event_new ();
1490       
1491       event->any.type = GDK_NOTHING;
1492       event->any.window = NULL;
1493       event->any.send_event = xevent.xany.send_event ? TRUE : FALSE;
1494
1495       ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
1496
1497       gdk_event_queue_append (event);
1498       node = gdk_queued_tail;
1499
1500       if (gdk_event_translate (event, &xevent, FALSE))
1501         {
1502           ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
1503         }
1504       else
1505         {
1506           gdk_event_queue_remove_link (node);
1507           g_list_free_1 (node);
1508           gdk_event_free (event);
1509         }
1510     }
1511 }
1512
1513 static gboolean  
1514 gdk_event_prepare (GSource  *source,
1515                    gint     *timeout)
1516 {
1517   gboolean retval;
1518   
1519   GDK_THREADS_ENTER ();
1520
1521   *timeout = -1;
1522
1523   retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
1524
1525   GDK_THREADS_LEAVE ();
1526
1527   return retval;
1528 }
1529
1530 static gboolean  
1531 gdk_event_check (GSource  *source) 
1532 {
1533   gboolean retval;
1534   
1535   GDK_THREADS_ENTER ();
1536
1537   if (event_poll_fd.revents & G_IO_IN)
1538     retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
1539   else
1540     retval = FALSE;
1541
1542   GDK_THREADS_LEAVE ();
1543
1544   return retval;
1545 }
1546
1547 static gboolean  
1548 gdk_event_dispatch (GSource    *source,
1549                     GSourceFunc callback,
1550                     gpointer    user_data)
1551 {
1552   GdkEvent *event;
1553  
1554   GDK_THREADS_ENTER ();
1555
1556   gdk_events_queue();
1557   event = gdk_event_unqueue();
1558
1559   if (event)
1560     {
1561       if (gdk_event_func)
1562         (*gdk_event_func) (event, gdk_event_data);
1563       
1564       gdk_event_free (event);
1565     }
1566   
1567   GDK_THREADS_LEAVE ();
1568
1569   return TRUE;
1570 }
1571
1572 /* Sends a ClientMessage to all toplevel client windows */
1573 gboolean
1574 gdk_event_send_client_message (GdkEvent *event, guint32 xid)
1575 {
1576   XEvent sev;
1577   
1578   g_return_val_if_fail(event != NULL, FALSE);
1579   
1580   /* Set up our event to send, with the exception of its target window */
1581   sev.xclient.type = ClientMessage;
1582   sev.xclient.display = gdk_display;
1583   sev.xclient.format = event->client.data_format;
1584   sev.xclient.window = xid;
1585   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
1586   sev.xclient.message_type = event->client.message_type;
1587   
1588   return gdk_send_xevent (xid, False, NoEventMask, &sev);
1589 }
1590
1591 /* Sends a ClientMessage to all toplevel client windows */
1592 gboolean
1593 gdk_event_send_client_message_to_all_recurse (XEvent  *xev, 
1594                                               guint32  xid,
1595                                               guint    level)
1596 {
1597   static GdkAtom wm_state_atom = GDK_NONE;
1598   Atom type = None;
1599   int format;
1600   unsigned long nitems, after;
1601   unsigned char *data;
1602   Window *ret_children, ret_root, ret_parent;
1603   unsigned int ret_nchildren;
1604   gint old_warnings = gdk_error_warnings;
1605   gboolean send = FALSE;
1606   gboolean found = FALSE;
1607   int i;
1608
1609   if (!wm_state_atom)
1610     wm_state_atom = gdk_atom_intern ("WM_STATE", FALSE);
1611
1612   gdk_error_warnings = FALSE;
1613   gdk_error_code = 0;
1614   XGetWindowProperty (gdk_display, xid, wm_state_atom, 0, 0, False, AnyPropertyType,
1615                       &type, &format, &nitems, &after, &data);
1616
1617   if (gdk_error_code)
1618     {
1619       gdk_error_warnings = old_warnings;
1620
1621       return FALSE;
1622     }
1623
1624   if (type)
1625     {
1626       send = TRUE;
1627       XFree (data);
1628     }
1629   else
1630     {
1631       /* OK, we're all set, now let's find some windows to send this to */
1632       if (XQueryTree (gdk_display, xid, &ret_root, &ret_parent,
1633                       &ret_children, &ret_nchildren) != True ||
1634           gdk_error_code)
1635         {
1636           gdk_error_warnings = old_warnings;
1637
1638           return FALSE;
1639         }
1640
1641       for(i = 0; i < ret_nchildren; i++)
1642         if (gdk_event_send_client_message_to_all_recurse (xev, ret_children[i], level + 1))
1643           found = TRUE;
1644
1645       XFree (ret_children);
1646     }
1647
1648   if (send || (!found && (level == 1)))
1649     {
1650       xev->xclient.window = xid;
1651       gdk_send_xevent (xid, False, NoEventMask, xev);
1652     }
1653
1654   gdk_error_warnings = old_warnings;
1655
1656   return (send || found);
1657 }
1658
1659 void
1660 gdk_event_send_clientmessage_toall (GdkEvent *event)
1661 {
1662   XEvent sev;
1663   gint old_warnings = gdk_error_warnings;
1664
1665   g_return_if_fail(event != NULL);
1666   
1667   /* Set up our event to send, with the exception of its target window */
1668   sev.xclient.type = ClientMessage;
1669   sev.xclient.display = gdk_display;
1670   sev.xclient.format = event->client.data_format;
1671   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
1672   sev.xclient.message_type = event->client.message_type;
1673
1674   gdk_event_send_client_message_to_all_recurse(&sev, gdk_root_window, 0);
1675
1676   gdk_error_warnings = old_warnings;
1677 }
1678
1679 /*
1680  *--------------------------------------------------------------
1681  * gdk_flush
1682  *
1683  *   Flushes the Xlib output buffer and then waits
1684  *   until all requests have been received and processed
1685  *   by the X server. The only real use for this function
1686  *   is in dealing with XShm.
1687  *
1688  * Arguments:
1689  *
1690  * Results:
1691  *
1692  * Side effects:
1693  *
1694  *--------------------------------------------------------------
1695  */
1696
1697 void
1698 gdk_flush (void)
1699 {
1700   XSync (gdk_display, False);
1701 }
1702
1703 static GdkAtom timestamp_prop_atom = 0;
1704
1705 static Bool
1706 timestamp_predicate (Display *display,
1707                      XEvent  *xevent,
1708                      XPointer arg)
1709 {
1710   Window xwindow = GPOINTER_TO_UINT (arg);
1711
1712   if (xevent->type == PropertyNotify &&
1713       xevent->xproperty.window == xwindow &&
1714       xevent->xproperty.atom == timestamp_prop_atom)
1715     return True;
1716
1717   return False;
1718 }
1719
1720 /**
1721  * gdk_x11_get_server_time:
1722  * @window: a #GdkWindow, used for communication with the server.
1723  *          The window must have GDK_PROPERTY_CHANGE_MASK in its
1724  *          events mask or a hang will result.
1725  * 
1726  * Routine to get the current X server time stamp. 
1727  * 
1728  * Return value: the time stamp.
1729  **/
1730 guint32
1731 gdk_x11_get_server_time (GdkWindow *window)
1732 {
1733   Display *xdisplay;
1734   Window   xwindow;
1735   guchar c = 'a';
1736   XEvent xevent;
1737
1738   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
1739   g_return_val_if_fail (!GDK_WINDOW_DESTROYED (window), 0);
1740
1741   if (!timestamp_prop_atom)
1742     timestamp_prop_atom = gdk_atom_intern ("GDK_TIMESTAMP_PROP", FALSE);
1743
1744   xdisplay = GDK_WINDOW_XDISPLAY (window);
1745   xwindow = GDK_WINDOW_XWINDOW (window);
1746   
1747   XChangeProperty (xdisplay, xwindow,
1748                    timestamp_prop_atom, timestamp_prop_atom,
1749                    8, PropModeReplace, &c, 1);
1750
1751   XIfEvent (xdisplay, &xevent,
1752             timestamp_predicate, GUINT_TO_POINTER(xwindow));
1753
1754   return xevent.xproperty.time;
1755 }
1756
1757
1758 gboolean
1759 gdk_wmspec_supported (GdkAtom property)
1760 {
1761   static GdkAtom wmspec_check_atom = 0;
1762   static GdkAtom wmspec_supported_atom = 0;
1763   static GdkAtom *atoms = NULL;
1764   static gulong n_atoms = 0;
1765   Atom type;
1766   gint format;
1767   gulong nitems;
1768   gulong bytes_after;
1769   Window *xwindow;
1770   gulong i;
1771
1772   if (wmspec_check_window != None)
1773     {
1774       if (atoms == NULL)
1775         return FALSE;
1776
1777       i = 0;
1778       while (i < n_atoms)
1779         {
1780           if (atoms[i] == property)
1781             return TRUE;
1782           
1783           ++i;
1784         }
1785
1786       return FALSE;
1787     }
1788
1789   if (atoms)
1790     XFree (atoms);
1791
1792   atoms = NULL;
1793   n_atoms = 0;
1794   
1795   /* This function is very slow on every call if you are not running a
1796    * spec-supporting WM. For now not optimized, because it isn't in
1797    * any critical code paths, but if you used it somewhere that had to
1798    * be fast you want to avoid "GTK is slow with old WMs" complaints.
1799    * Probably at that point the function should be changed to query
1800    * _NET_SUPPORTING_WM_CHECK only once every 10 seconds or something.
1801    */
1802   
1803   if (wmspec_check_atom == 0)
1804     wmspec_check_atom = gdk_atom_intern ("_NET_SUPPORTING_WM_CHECK", FALSE);
1805       
1806   if (wmspec_supported_atom == 0)
1807     wmspec_supported_atom = gdk_atom_intern ("_NET_SUPPORTED", FALSE);
1808   
1809   XGetWindowProperty (gdk_display, gdk_root_window,
1810                       wmspec_check_atom, 0, G_MAXLONG,
1811                       False, XA_WINDOW, &type, &format, &nitems,
1812                       &bytes_after, (guchar **)&xwindow);
1813
1814   if (type != XA_WINDOW)
1815     return FALSE;
1816
1817   gdk_error_trap_push ();
1818
1819   /* Find out if this WM goes away, so we can reset everything. */
1820   XSelectInput (gdk_display, *xwindow,
1821                 StructureNotifyMask);
1822   
1823   gdk_flush ();
1824   
1825   if (gdk_error_trap_pop ())
1826     {
1827       XFree (xwindow);
1828       return FALSE;
1829     }
1830
1831   XGetWindowProperty (gdk_display, gdk_root_window,
1832                       wmspec_supported_atom, 0, G_MAXLONG,
1833                       False, XA_ATOM, &type, &format, &n_atoms,
1834                       &bytes_after, (guchar **)&atoms);
1835   
1836   if (type != XA_ATOM)
1837     return FALSE;
1838   
1839   wmspec_check_window = *xwindow;
1840   XFree (xwindow);
1841   
1842   /* since wmspec_check_window != None this isn't infinite. ;-) */
1843   return gdk_wmspec_supported (property);
1844 }
1845
1846
1847