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