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