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