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