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