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