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