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