]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkevents-x11.c
Switch motion hint emulation to be serial based.
[~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 is_parent_of (GdkWindow *parent,
872               GdkWindow *child)
873 {
874   GdkWindow *w;
875
876   w = child;
877   while (w != NULL)
878     {
879       if (w == parent)
880         return TRUE;
881
882       w = gdk_window_get_parent (w);
883     }
884
885   return FALSE;
886 }
887
888 static gboolean
889 gdk_event_translate (GdkDisplay *display,
890                      GdkEvent   *event,
891                      XEvent     *xevent,
892                      gboolean    return_exposes)
893 {
894   
895   GdkWindow *window;
896   GdkWindowObject *window_private;
897   GdkWindow *filter_window;
898   GdkWindowImplX11 *window_impl = NULL;
899   gboolean return_val;
900   GdkScreen *screen = NULL;
901   GdkScreenX11 *screen_x11 = NULL;
902   GdkToplevelX11 *toplevel = NULL;
903   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (display);
904   Window xwindow, filter_xwindow;
905   int exposure_x_offset = 0;
906   int exposure_y_offset = 0;
907   GdkWindow *unref_pixmap = NULL;
908   
909   return_val = FALSE;
910
911   /* init these, since the done: block uses them */
912   window = NULL;
913   window_private = NULL;
914   event->any.window = NULL;
915
916   if (_gdk_default_filters)
917     {
918       /* Apply global filters */
919       GdkFilterReturn result;
920       result = gdk_event_apply_filters (xevent, event,
921                                         _gdk_default_filters);
922       
923       if (result != GDK_FILTER_CONTINUE)
924         {
925           return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
926           goto done;
927         }
928     }  
929
930   /* Find the GdkWindow that this event relates to.
931    * Basically this means substructure events
932    * are reported same as structure events
933    */
934   get_real_window (display, xevent, &xwindow, &filter_xwindow);
935
936   window = gdk_window_lookup_for_display (display, xwindow);
937   
938   /* We may receive events such as NoExpose/GraphicsExpose
939    * and ShmCompletion for pixmaps
940    */
941   if (window && !GDK_IS_WINDOW (window))
942     {
943       GdkPixmapObject *pixmap = (GdkPixmapObject *)window;
944       if ((xevent->type == GraphicsExpose ||
945            xevent->type == NoExpose) &&
946           GDK_IS_PIXMAP (window) &&
947           pixmap->backing_for != NULL)
948         {
949           /* Unref the pixmap once for each finished set of GraphicsExposes */
950           if (xevent->type == NoExpose ||
951               xevent->xgraphicsexpose.count == 0)
952             unref_pixmap = window;
953           window = g_object_ref (pixmap->backing_for);
954           exposure_x_offset = pixmap->backing_x_offset;
955           exposure_y_offset = pixmap->backing_y_offset;
956         }
957       else
958         window = NULL;
959     }
960   window_private = (GdkWindowObject *) window;
961
962   /* We always run the filters for the window where the event
963    * is delivered, not the window that it relates to
964    */
965   if (filter_xwindow == xwindow)
966     filter_window = window;
967   else
968     {
969       filter_window = gdk_window_lookup_for_display (display, filter_xwindow);
970       if (filter_window && !GDK_IS_WINDOW (filter_window))
971         filter_window = NULL;
972     }
973
974   if (window)
975     {
976       screen = GDK_WINDOW_SCREEN (window);
977       screen_x11 = GDK_SCREEN_X11 (screen);
978       toplevel = _gdk_x11_window_get_toplevel (window);
979     }
980     
981   if (window != NULL)
982     {
983       /* Apply keyboard grabs to non-native windows */
984       if (/* Is key event */
985           (xevent->type == KeyPress || xevent->type == KeyRelease) &&
986           /* And we have a grab */
987           display->keyboard_grab.window != NULL &&
988           (
989            /* The window is not a descendant of the grabbed window */
990            !is_parent_of ((GdkWindow *)display->keyboard_grab.window, window) ||
991            /* Or owner event is false */
992            !display->keyboard_grab.owner_events
993            )
994           )
995         {
996           /* Report key event against grab window */
997           window_private = display->keyboard_grab.window;
998           window = (GdkWindow *) window_private;
999         }
1000
1001       window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
1002       
1003       /* Move key events on focus window to the real toplevel, and
1004        * filter out all other events on focus window
1005        */          
1006       if (toplevel && xwindow == toplevel->focus_window)
1007         {
1008           switch (xevent->type)
1009             {
1010             case KeyPress:
1011             case KeyRelease:
1012               xwindow = GDK_WINDOW_XID (window);
1013               xevent->xany.window = xwindow;
1014               break;
1015             default:
1016               return FALSE;
1017             }
1018         }
1019
1020       g_object_ref (window);
1021     }
1022
1023   event->any.window = window;
1024   event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
1025   
1026   if (window_private && GDK_WINDOW_DESTROYED (window))
1027     {
1028       if (xevent->type != DestroyNotify)
1029         {
1030           return_val = FALSE;
1031           goto done;
1032         }
1033     }
1034   else if (filter_window)
1035     {
1036       /* Apply per-window filters */
1037       GdkWindowObject *filter_private = (GdkWindowObject *) filter_window;
1038       GdkFilterReturn result;
1039
1040       if (filter_private->filters)
1041         {
1042           g_object_ref (filter_window);
1043           
1044           result = gdk_event_apply_filters (xevent, event,
1045                                             filter_private->filters);
1046           
1047           g_object_unref (filter_window);
1048       
1049           if (result != GDK_FILTER_CONTINUE)
1050             {
1051               return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
1052               goto done;
1053             }
1054         }
1055     }
1056       
1057   if (screen_x11 && screen_x11->wmspec_check_window != None &&
1058       xwindow == screen_x11->wmspec_check_window)
1059     {
1060       if (xevent->type == DestroyNotify)
1061         {
1062           screen_x11->wmspec_check_window = None;
1063           g_free (screen_x11->window_manager_name);
1064           screen_x11->window_manager_name = g_strdup ("unknown");
1065
1066           /* careful, reentrancy */
1067           _gdk_x11_screen_window_manager_changed (GDK_SCREEN (screen_x11));
1068         }
1069       
1070       /* Eat events on this window unless someone had wrapped
1071        * it as a foreign window
1072        */
1073       if (window == NULL)
1074         {
1075           return_val = FALSE;
1076           goto done;
1077         }
1078     }
1079
1080   if (window &&
1081       (xevent->xany.type == MotionNotify ||
1082        xevent->xany.type == ButtonRelease))
1083     {
1084       if (_gdk_moveresize_handle_event (xevent))
1085         {
1086           return_val = FALSE;
1087           goto done;
1088         }
1089     }
1090   
1091   /* We do a "manual" conversion of the XEvent to a
1092    *  GdkEvent. The structures are mostly the same so
1093    *  the conversion is fairly straightforward. We also
1094    *  optionally print debugging info regarding events
1095    *  received.
1096    */
1097
1098   return_val = TRUE;
1099
1100   switch (xevent->type)
1101     {
1102     case KeyPress:
1103       if (window_private == NULL)
1104         {
1105           return_val = FALSE;
1106           break;
1107         }
1108       translate_key_event (display, event, xevent);
1109       set_user_time (window, event);
1110       break;
1111
1112     case KeyRelease:
1113       if (window_private == NULL)
1114         {
1115           return_val = FALSE;
1116           break;
1117         }
1118       
1119       /* Emulate detectable auto-repeat by checking to see
1120        * if the next event is a key press with the same
1121        * keycode and timestamp, and if so, ignoring the event.
1122        */
1123
1124       if (!display_x11->have_xkb_autorepeat && XPending (xevent->xkey.display))
1125         {
1126           XEvent next_event;
1127
1128           XPeekEvent (xevent->xkey.display, &next_event);
1129
1130           if (next_event.type == KeyPress &&
1131               next_event.xkey.keycode == xevent->xkey.keycode &&
1132               next_event.xkey.time == xevent->xkey.time)
1133             {
1134               return_val = FALSE;
1135               break;
1136             }
1137         }
1138
1139       translate_key_event (display, event, xevent);
1140       break;
1141       
1142     case ButtonPress:
1143       GDK_NOTE (EVENTS, 
1144                 g_message ("button press:\t\twindow: %ld  x,y: %d %d  button: %d",
1145                            xevent->xbutton.window,
1146                            xevent->xbutton.x, xevent->xbutton.y,
1147                            xevent->xbutton.button));
1148       
1149       if (window_private == NULL || 
1150           ((window_private->extension_events != 0) &&
1151            display_x11->input_ignore_core))
1152         {
1153           return_val = FALSE;
1154           break;
1155         }
1156       
1157       /* If we get a ButtonPress event where the button is 4 or 5,
1158          it's a Scroll event */
1159       switch (xevent->xbutton.button)
1160         {
1161         case 4: /* up */
1162         case 5: /* down */
1163         case 6: /* left */
1164         case 7: /* right */
1165           event->scroll.type = GDK_SCROLL;
1166
1167           if (xevent->xbutton.button == 4)
1168             event->scroll.direction = GDK_SCROLL_UP;
1169           else if (xevent->xbutton.button == 5)
1170             event->scroll.direction = GDK_SCROLL_DOWN;
1171           else if (xevent->xbutton.button == 6)
1172             event->scroll.direction = GDK_SCROLL_LEFT;
1173           else
1174             event->scroll.direction = GDK_SCROLL_RIGHT;
1175
1176           event->scroll.window = window;
1177           event->scroll.time = xevent->xbutton.time;
1178           event->scroll.x = xevent->xbutton.x;
1179           event->scroll.y = xevent->xbutton.y;
1180           event->scroll.x_root = (gfloat)xevent->xbutton.x_root;
1181           event->scroll.y_root = (gfloat)xevent->xbutton.y_root;
1182           event->scroll.state = (GdkModifierType) xevent->xbutton.state;
1183           event->scroll.device = display->core_pointer;
1184           
1185           if (!set_screen_from_root (display, event, xevent->xbutton.root))
1186             {
1187               return_val = FALSE;
1188               break;
1189             }
1190           
1191           break;
1192           
1193         default:
1194           event->button.type = GDK_BUTTON_PRESS;
1195           event->button.window = window;
1196           event->button.time = xevent->xbutton.time;
1197           event->button.x = xevent->xbutton.x;
1198           event->button.y = xevent->xbutton.y;
1199           event->button.x_root = (gfloat)xevent->xbutton.x_root;
1200           event->button.y_root = (gfloat)xevent->xbutton.y_root;
1201           event->button.axes = NULL;
1202           event->button.state = (GdkModifierType) xevent->xbutton.state;
1203           event->button.button = xevent->xbutton.button;
1204           event->button.device = display->core_pointer;
1205           
1206           if (!set_screen_from_root (display, event, xevent->xbutton.root))
1207             {
1208               return_val = FALSE;
1209               break;
1210             }
1211           break;
1212         }
1213
1214       set_user_time (window, event);
1215
1216       /* We treat button presses as scroll wheel events, so don't expose
1217        * this grab to gtk, as it will be immediately released. If we do
1218        * expose it there is a short time before we receive the Release
1219        * where a client-side generated pointer motion event could be handled
1220        * as if the grab was effect.
1221        */
1222       if (!(xevent->xbutton.button == 4 || xevent->xbutton.button == 5 ||
1223             xevent->xbutton.button == 6 || xevent->xbutton.button == 7))
1224         _gdk_xgrab_check_button_event (window, xevent);
1225       break;
1226       
1227     case ButtonRelease:
1228       GDK_NOTE (EVENTS, 
1229                 g_message ("button release:\twindow: %ld  x,y: %d %d  button: %d",
1230                            xevent->xbutton.window,
1231                            xevent->xbutton.x, xevent->xbutton.y,
1232                            xevent->xbutton.button));
1233       
1234       if (window_private == NULL ||
1235           ((window_private->extension_events != 0) &&
1236            display_x11->input_ignore_core))
1237         {
1238           return_val = FALSE;
1239           break;
1240         }
1241       
1242       /* We treat button presses as scroll wheel events, so ignore the release */
1243       if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5 ||
1244           xevent->xbutton.button == 6 || xevent->xbutton.button ==7)
1245         {
1246           return_val = FALSE;
1247           break;
1248         }
1249
1250       event->button.type = GDK_BUTTON_RELEASE;
1251       event->button.window = window;
1252       event->button.time = xevent->xbutton.time;
1253       event->button.x = xevent->xbutton.x;
1254       event->button.y = xevent->xbutton.y;
1255       event->button.x_root = (gfloat)xevent->xbutton.x_root;
1256       event->button.y_root = (gfloat)xevent->xbutton.y_root;
1257       event->button.axes = NULL;
1258       event->button.state = (GdkModifierType) xevent->xbutton.state;
1259       event->button.button = xevent->xbutton.button;
1260       event->button.device = display->core_pointer;
1261
1262       if (!set_screen_from_root (display, event, xevent->xbutton.root))
1263         return_val = FALSE;
1264       
1265       _gdk_xgrab_check_button_event (window, xevent);
1266       
1267       break;
1268       
1269     case MotionNotify:
1270       GDK_NOTE (EVENTS,
1271                 g_message ("motion notify:\t\twindow: %ld  x,y: %d %d  hint: %s", 
1272                            xevent->xmotion.window,
1273                            xevent->xmotion.x, xevent->xmotion.y,
1274                            (xevent->xmotion.is_hint) ? "true" : "false"));
1275       
1276       if (window_private == NULL ||
1277           ((window_private->extension_events != 0) &&
1278            display_x11->input_ignore_core))
1279         {
1280           return_val = FALSE;
1281           break;
1282         }
1283
1284       event->motion.type = GDK_MOTION_NOTIFY;
1285       event->motion.window = window;
1286       event->motion.time = xevent->xmotion.time;
1287       event->motion.x = xevent->xmotion.x;
1288       event->motion.y = xevent->xmotion.y;
1289       event->motion.x_root = (gfloat)xevent->xmotion.x_root;
1290       event->motion.y_root = (gfloat)xevent->xmotion.y_root;
1291       event->motion.axes = NULL;
1292       event->motion.state = (GdkModifierType) xevent->xmotion.state;
1293       event->motion.is_hint = xevent->xmotion.is_hint;
1294       event->motion.device = display->core_pointer;
1295       
1296       if (!set_screen_from_root (display, event, xevent->xbutton.root))
1297         {
1298           return_val = FALSE;
1299           break;
1300         }
1301             
1302       break;
1303       
1304     case EnterNotify:
1305       GDK_NOTE (EVENTS,
1306                 g_message ("enter notify:\t\twindow: %ld  detail: %d subwin: %ld",
1307                            xevent->xcrossing.window,
1308                            xevent->xcrossing.detail,
1309                            xevent->xcrossing.subwindow));
1310  
1311       if (window_private == NULL)
1312         {
1313           return_val = FALSE;
1314           break;
1315         }
1316       
1317       if (!set_screen_from_root (display, event, xevent->xbutton.root))
1318         {
1319           return_val = FALSE;
1320           break;
1321         }
1322       
1323       /* Handle focusing (in the case where no window manager is running */
1324       if (toplevel && xevent->xcrossing.detail != NotifyInferior)
1325         {
1326           toplevel->has_pointer = TRUE;
1327
1328           if (xevent->xcrossing.focus && !toplevel->has_focus_window)
1329             {
1330               gboolean had_focus = HAS_FOCUS (toplevel);
1331               
1332               toplevel->has_pointer_focus = TRUE;
1333               
1334               if (HAS_FOCUS (toplevel) != had_focus)
1335                 generate_focus_event (window, TRUE);
1336             }
1337         }
1338
1339       /* Tell XInput stuff about it if appropriate */
1340       if (window_private &&
1341           !GDK_WINDOW_DESTROYED (window) &&
1342           window_private->extension_events != 0)
1343         _gdk_input_enter_event (&xevent->xcrossing, window);
1344       
1345       event->crossing.type = GDK_ENTER_NOTIFY;
1346       event->crossing.window = window;
1347       
1348       /* If the subwindow field of the XEvent is non-NULL, then
1349        *  lookup the corresponding GdkWindow.
1350        */
1351       if (xevent->xcrossing.subwindow != None)
1352         event->crossing.subwindow = gdk_window_lookup_for_display (display, xevent->xcrossing.subwindow);
1353       else
1354         event->crossing.subwindow = NULL;
1355       
1356       event->crossing.time = xevent->xcrossing.time;
1357       event->crossing.x = xevent->xcrossing.x;
1358       event->crossing.y = xevent->xcrossing.y;
1359       event->crossing.x_root = xevent->xcrossing.x_root;
1360       event->crossing.y_root = xevent->xcrossing.y_root;
1361       
1362       /* Translate the crossing mode into Gdk terms.
1363        */
1364       switch (xevent->xcrossing.mode)
1365         {
1366         case NotifyNormal:
1367           event->crossing.mode = GDK_CROSSING_NORMAL;
1368           break;
1369         case NotifyGrab:
1370           event->crossing.mode = GDK_CROSSING_GRAB;
1371           break;
1372         case NotifyUngrab:
1373           event->crossing.mode = GDK_CROSSING_UNGRAB;
1374           break;
1375         };
1376       
1377       /* Translate the crossing detail into Gdk terms.
1378        */
1379       switch (xevent->xcrossing.detail)
1380         {
1381         case NotifyInferior:
1382           event->crossing.detail = GDK_NOTIFY_INFERIOR;
1383           break;
1384         case NotifyAncestor:
1385           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
1386           break;
1387         case NotifyVirtual:
1388           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
1389           break;
1390         case NotifyNonlinear:
1391           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
1392           break;
1393         case NotifyNonlinearVirtual:
1394           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
1395           break;
1396         default:
1397           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
1398           break;
1399         }
1400       
1401       event->crossing.focus = xevent->xcrossing.focus;
1402       event->crossing.state = xevent->xcrossing.state;
1403   
1404       break;
1405       
1406     case LeaveNotify:
1407       GDK_NOTE (EVENTS, 
1408                 g_message ("leave notify:\t\twindow: %ld  detail: %d subwin: %ld",
1409                            xevent->xcrossing.window,
1410                            xevent->xcrossing.detail, xevent->xcrossing.subwindow));
1411
1412       if (window_private == NULL)
1413         {
1414           return_val = FALSE;
1415           break;
1416         }
1417
1418       if (!set_screen_from_root (display, event, xevent->xbutton.root))
1419         {
1420           return_val = FALSE;
1421           break;
1422         }
1423                   
1424       /* Handle focusing (in the case where no window manager is running */
1425       if (toplevel && xevent->xcrossing.detail != NotifyInferior)
1426         {
1427           toplevel->has_pointer = FALSE;
1428
1429           if (xevent->xcrossing.focus && !toplevel->has_focus_window)
1430             {
1431               gboolean had_focus = HAS_FOCUS (toplevel);
1432               
1433               toplevel->has_pointer_focus = FALSE;
1434               
1435               if (HAS_FOCUS (toplevel) != had_focus)
1436                 generate_focus_event (window, FALSE);
1437             }
1438         }
1439
1440       event->crossing.type = GDK_LEAVE_NOTIFY;
1441       event->crossing.window = window;
1442       
1443       /* If the subwindow field of the XEvent is non-NULL, then
1444        *  lookup the corresponding GdkWindow.
1445        */
1446       if (xevent->xcrossing.subwindow != None)
1447         event->crossing.subwindow = gdk_window_lookup_for_display (display, xevent->xcrossing.subwindow);
1448       else
1449         event->crossing.subwindow = NULL;
1450       
1451       event->crossing.time = xevent->xcrossing.time;
1452       event->crossing.x = xevent->xcrossing.x;
1453       event->crossing.y = xevent->xcrossing.y;
1454       event->crossing.x_root = xevent->xcrossing.x_root;
1455       event->crossing.y_root = xevent->xcrossing.y_root;
1456       
1457       /* Translate the crossing mode into Gdk terms.
1458        */
1459       switch (xevent->xcrossing.mode)
1460         {
1461         case NotifyNormal:
1462           event->crossing.mode = GDK_CROSSING_NORMAL;
1463           break;
1464         case NotifyGrab:
1465           event->crossing.mode = GDK_CROSSING_GRAB;
1466           break;
1467         case NotifyUngrab:
1468           event->crossing.mode = GDK_CROSSING_UNGRAB;
1469           break;
1470         };
1471       
1472       /* Translate the crossing detail into Gdk terms.
1473        */
1474       switch (xevent->xcrossing.detail)
1475         {
1476         case NotifyInferior:
1477           event->crossing.detail = GDK_NOTIFY_INFERIOR;
1478           break;
1479         case NotifyAncestor:
1480           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
1481           break;
1482         case NotifyVirtual:
1483           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
1484           break;
1485         case NotifyNonlinear:
1486           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
1487           break;
1488         case NotifyNonlinearVirtual:
1489           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
1490           break;
1491         default:
1492           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
1493           break;
1494         }
1495       
1496       event->crossing.focus = xevent->xcrossing.focus;
1497       event->crossing.state = xevent->xcrossing.state;
1498       
1499       break;
1500       
1501       /* We only care about focus events that indicate that _this_
1502        * window (not a ancestor or child) got or lost the focus
1503        */
1504     case FocusIn:
1505       GDK_NOTE (EVENTS,
1506                 g_message ("focus in:\t\twindow: %ld, detail: %s, mode: %s",
1507                            xevent->xfocus.window,
1508                            notify_details[xevent->xfocus.detail],
1509                            notify_modes[xevent->xfocus.mode]));
1510       
1511       if (toplevel)
1512         {
1513           gboolean had_focus = HAS_FOCUS (toplevel);
1514           
1515           switch (xevent->xfocus.detail)
1516             {
1517             case NotifyAncestor:
1518             case NotifyVirtual:
1519               /* When the focus moves from an ancestor of the window to
1520                * the window or a descendent of the window, *and* the
1521                * pointer is inside the window, then we were previously
1522                * receiving keystroke events in the has_pointer_focus
1523                * case and are now receiving them in the
1524                * has_focus_window case.
1525                */
1526               if (toplevel->has_pointer &&
1527                   xevent->xfocus.mode != NotifyGrab &&
1528                   xevent->xfocus.mode != NotifyUngrab)
1529                 toplevel->has_pointer_focus = FALSE;
1530               
1531               /* fall through */
1532             case NotifyNonlinear:
1533             case NotifyNonlinearVirtual:
1534               if (xevent->xfocus.mode != NotifyGrab &&
1535                   xevent->xfocus.mode != NotifyUngrab)
1536                 toplevel->has_focus_window = TRUE;
1537               /* We pretend that the focus moves to the grab
1538                * window, so we pay attention to NotifyGrab
1539                * NotifyUngrab, and ignore NotifyWhileGrabbed
1540                */
1541               if (xevent->xfocus.mode != NotifyWhileGrabbed)
1542                 toplevel->has_focus = TRUE;
1543               break;
1544             case NotifyPointer:
1545               /* The X server sends NotifyPointer/NotifyGrab,
1546                * but the pointer focus is ignored while a
1547                * grab is in effect
1548                */
1549               if (xevent->xfocus.mode != NotifyGrab &&
1550                   xevent->xfocus.mode != NotifyUngrab)
1551                 toplevel->has_pointer_focus = TRUE;
1552               break;
1553             case NotifyInferior:
1554             case NotifyPointerRoot:
1555             case NotifyDetailNone:
1556               break;
1557             }
1558
1559           if (HAS_FOCUS (toplevel) != had_focus)
1560             generate_focus_event (window, TRUE);
1561         }
1562       break;
1563     case FocusOut:
1564       GDK_NOTE (EVENTS,
1565                 g_message ("focus out:\t\twindow: %ld, detail: %s, mode: %s",
1566                            xevent->xfocus.window,
1567                            notify_details[xevent->xfocus.detail],
1568                            notify_modes[xevent->xfocus.mode]));
1569       
1570       if (toplevel)
1571         {
1572           gboolean had_focus = HAS_FOCUS (toplevel);
1573             
1574           switch (xevent->xfocus.detail)
1575             {
1576             case NotifyAncestor:
1577             case NotifyVirtual:
1578               /* When the focus moves from the window or a descendent
1579                * of the window to an ancestor of the window, *and* the
1580                * pointer is inside the window, then we were previously
1581                * receiving keystroke events in the has_focus_window
1582                * case and are now receiving them in the
1583                * has_pointer_focus case.
1584                */
1585               if (toplevel->has_pointer &&
1586                   xevent->xfocus.mode != NotifyGrab &&
1587                   xevent->xfocus.mode != NotifyUngrab)
1588                 toplevel->has_pointer_focus = TRUE;
1589
1590               /* fall through */
1591             case NotifyNonlinear:
1592             case NotifyNonlinearVirtual:
1593               if (xevent->xfocus.mode != NotifyGrab &&
1594                   xevent->xfocus.mode != NotifyUngrab)
1595                 toplevel->has_focus_window = FALSE;
1596               if (xevent->xfocus.mode != NotifyWhileGrabbed)
1597                 toplevel->has_focus = FALSE;
1598               break;
1599             case NotifyPointer:
1600               if (xevent->xfocus.mode != NotifyGrab &&
1601                   xevent->xfocus.mode != NotifyUngrab)
1602                 toplevel->has_pointer_focus = FALSE;
1603             break;
1604             case NotifyInferior:
1605             case NotifyPointerRoot:
1606             case NotifyDetailNone:
1607               break;
1608             }
1609
1610           if (HAS_FOCUS (toplevel) != had_focus)
1611             generate_focus_event (window, FALSE);
1612         }
1613       break;
1614
1615 #if 0      
1616           /* gdk_keyboard_grab() causes following events. These events confuse
1617            * the XIM focus, so ignore them.
1618            */
1619           if (xevent->xfocus.mode == NotifyGrab ||
1620               xevent->xfocus.mode == NotifyUngrab)
1621             break;
1622 #endif
1623
1624     case KeymapNotify:
1625       GDK_NOTE (EVENTS,
1626                 g_message ("keymap notify"));
1627
1628       /* Not currently handled */
1629       return_val = FALSE;
1630       break;
1631       
1632     case Expose:
1633       GDK_NOTE (EVENTS,
1634                 g_message ("expose:\t\twindow: %ld  %d  x,y: %d %d  w,h: %d %d%s",
1635                            xevent->xexpose.window, xevent->xexpose.count,
1636                            xevent->xexpose.x, xevent->xexpose.y,
1637                            xevent->xexpose.width, xevent->xexpose.height,
1638                            event->any.send_event ? " (send)" : ""));
1639       
1640       if (window_private == NULL)
1641         {
1642           return_val = FALSE;
1643           break;
1644         }
1645       
1646       {
1647         GdkRectangle expose_rect;
1648
1649         expose_rect.x = xevent->xexpose.x;
1650         expose_rect.y = xevent->xexpose.y;
1651         expose_rect.width = xevent->xexpose.width;
1652         expose_rect.height = xevent->xexpose.height;
1653
1654         if (return_exposes)
1655           {
1656             event->expose.type = GDK_EXPOSE;
1657             event->expose.area = expose_rect;
1658             event->expose.region = gdk_region_rectangle (&expose_rect);
1659             event->expose.window = window;
1660             event->expose.count = xevent->xexpose.count;
1661
1662             return_val = TRUE;
1663           }
1664         else
1665           {
1666             _gdk_window_process_expose (window, xevent->xexpose.serial, &expose_rect);
1667             return_val = FALSE;
1668           }
1669         
1670         return_val = FALSE;
1671       }
1672         
1673       break;
1674       
1675     case GraphicsExpose:
1676       {
1677         GdkRectangle expose_rect;
1678
1679         GDK_NOTE (EVENTS,
1680                   g_message ("graphics expose:\tdrawable: %ld",
1681                              xevent->xgraphicsexpose.drawable));
1682  
1683         if (window_private == NULL)
1684           {
1685             return_val = FALSE;
1686             break;
1687           }
1688         
1689         expose_rect.x = xevent->xgraphicsexpose.x + exposure_x_offset;
1690         expose_rect.y = xevent->xgraphicsexpose.y + exposure_y_offset;
1691         expose_rect.width = xevent->xgraphicsexpose.width;
1692         expose_rect.height = xevent->xgraphicsexpose.height;
1693             
1694         if (return_exposes)
1695           {
1696             event->expose.type = GDK_EXPOSE;
1697             event->expose.area = expose_rect;
1698             event->expose.region = gdk_region_rectangle (&expose_rect);
1699             event->expose.window = window;
1700             event->expose.count = xevent->xgraphicsexpose.count;
1701
1702             return_val = TRUE;
1703           }
1704         else
1705           {
1706             _gdk_window_process_expose (window, xevent->xgraphicsexpose.serial, &expose_rect);
1707             
1708             return_val = FALSE;
1709           }
1710         
1711       }
1712       break;
1713       
1714     case NoExpose:
1715       GDK_NOTE (EVENTS,
1716                 g_message ("no expose:\t\tdrawable: %ld",
1717                            xevent->xnoexpose.drawable));
1718       
1719       event->no_expose.type = GDK_NO_EXPOSE;
1720       event->no_expose.window = window;
1721       
1722       break;
1723       
1724     case VisibilityNotify:
1725 #ifdef G_ENABLE_DEBUG
1726       if (_gdk_debug_flags & GDK_DEBUG_EVENTS)
1727         switch (xevent->xvisibility.state)
1728           {
1729           case VisibilityFullyObscured:
1730             g_message ("visibility notify:\twindow: %ld  none",
1731                        xevent->xvisibility.window);
1732             break;
1733           case VisibilityPartiallyObscured:
1734             g_message ("visibility notify:\twindow: %ld  partial",
1735                        xevent->xvisibility.window);
1736             break;
1737           case VisibilityUnobscured:
1738             g_message ("visibility notify:\twindow: %ld  full",
1739                        xevent->xvisibility.window);
1740             break;
1741           }
1742 #endif /* G_ENABLE_DEBUG */
1743       
1744       if (window_private == NULL)
1745         {
1746           return_val = FALSE;
1747           break;
1748         }
1749       
1750       event->visibility.type = GDK_VISIBILITY_NOTIFY;
1751       event->visibility.window = window;
1752       
1753       switch (xevent->xvisibility.state)
1754         {
1755         case VisibilityFullyObscured:
1756           event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED;
1757           break;
1758           
1759         case VisibilityPartiallyObscured:
1760           event->visibility.state = GDK_VISIBILITY_PARTIAL;
1761           break;
1762           
1763         case VisibilityUnobscured:
1764           event->visibility.state = GDK_VISIBILITY_UNOBSCURED;
1765           break;
1766         }
1767       
1768       break;
1769       
1770     case CreateNotify:
1771       GDK_NOTE (EVENTS,
1772                 g_message ("create notify:\twindow: %ld  x,y: %d %d     w,h: %d %d  b-w: %d  parent: %ld         ovr: %d",
1773                            xevent->xcreatewindow.window,
1774                            xevent->xcreatewindow.x,
1775                            xevent->xcreatewindow.y,
1776                            xevent->xcreatewindow.width,
1777                            xevent->xcreatewindow.height,
1778                            xevent->xcreatewindow.border_width,
1779                            xevent->xcreatewindow.parent,
1780                            xevent->xcreatewindow.override_redirect));
1781       /* not really handled */
1782       break;
1783       
1784     case DestroyNotify:
1785       GDK_NOTE (EVENTS,
1786                 g_message ("destroy notify:\twindow: %ld",
1787                            xevent->xdestroywindow.window));
1788
1789       /* Ignore DestroyNotify from SubstructureNotifyMask */
1790       if (xevent->xdestroywindow.window == xevent->xdestroywindow.event)
1791         {
1792           event->any.type = GDK_DESTROY;
1793           event->any.window = window;
1794           
1795           return_val = window_private && !GDK_WINDOW_DESTROYED (window);
1796           
1797           if (window && GDK_WINDOW_XID (window) != screen_x11->xroot_window)
1798             gdk_window_destroy_notify (window);
1799         }
1800       else
1801         return_val = FALSE;
1802       
1803       break;
1804       
1805     case UnmapNotify:
1806       GDK_NOTE (EVENTS,
1807                 g_message ("unmap notify:\t\twindow: %ld",
1808                            xevent->xmap.window));
1809       
1810       event->any.type = GDK_UNMAP;
1811       event->any.window = window;      
1812
1813       /* If we are shown (not withdrawn) and get an unmap, it means we
1814        * were iconified in the X sense. If we are withdrawn, and get
1815        * an unmap, it means we hid the window ourselves, so we
1816        * will have already flipped the iconified bit off.
1817        */
1818       if (window)
1819         {
1820           if (GDK_WINDOW_IS_MAPPED (window))
1821             gdk_synthesize_window_state (window,
1822                                          0,
1823                                          GDK_WINDOW_STATE_ICONIFIED);
1824
1825           _gdk_xgrab_check_unmap (window, xevent->xany.serial);
1826         }
1827       
1828       break;
1829       
1830     case MapNotify:
1831       GDK_NOTE (EVENTS,
1832                 g_message ("map notify:\t\twindow: %ld",
1833                            xevent->xmap.window));
1834       
1835       event->any.type = GDK_MAP;
1836       event->any.window = window;
1837
1838       /* Unset iconified if it was set */
1839       if (window && (((GdkWindowObject*)window)->state & GDK_WINDOW_STATE_ICONIFIED))
1840         gdk_synthesize_window_state (window,
1841                                      GDK_WINDOW_STATE_ICONIFIED,
1842                                      0);
1843       
1844       break;
1845       
1846     case ReparentNotify:
1847       GDK_NOTE (EVENTS,
1848                 g_message ("reparent notify:\twindow: %ld  x,y: %d %d  parent: %ld      ovr: %d",
1849                            xevent->xreparent.window,
1850                            xevent->xreparent.x,
1851                            xevent->xreparent.y,
1852                            xevent->xreparent.parent,
1853                            xevent->xreparent.override_redirect));
1854
1855       /* Not currently handled */
1856       return_val = FALSE;
1857       break;
1858       
1859     case ConfigureNotify:
1860       GDK_NOTE (EVENTS,
1861                 g_message ("configure notify:\twindow: %ld  x,y: %d %d  w,h: %d %d  b-w: %d  above: %ld  ovr: %d%s",
1862                            xevent->xconfigure.window,
1863                            xevent->xconfigure.x,
1864                            xevent->xconfigure.y,
1865                            xevent->xconfigure.width,
1866                            xevent->xconfigure.height,
1867                            xevent->xconfigure.border_width,
1868                            xevent->xconfigure.above,
1869                            xevent->xconfigure.override_redirect,
1870                            !window
1871                            ? " (discarding)"
1872                            : GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD
1873                            ? " (discarding child)"
1874                            : xevent->xconfigure.event != xevent->xconfigure.window
1875                            ? " (discarding substructure)"
1876                            : ""));
1877       if (window && GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT)
1878         { 
1879           window_private->width = xevent->xconfigure.width;
1880           window_private->height = xevent->xconfigure.height;
1881
1882           _gdk_x11_drawable_update_size (window_private->impl);
1883           _gdk_x11_screen_size_changed (screen, xevent);
1884         }
1885
1886       if (window &&
1887           xevent->xconfigure.event == xevent->xconfigure.window &&
1888           !GDK_WINDOW_DESTROYED (window) &&
1889           (window_private->extension_events != 0))
1890         _gdk_input_configure_event (&xevent->xconfigure, window);
1891       
1892 #ifdef HAVE_XSYNC
1893       if (toplevel && display_x11->use_sync && !XSyncValueIsZero (toplevel->pending_counter_value))
1894         {
1895           toplevel->current_counter_value = toplevel->pending_counter_value;
1896           XSyncIntToValue (&toplevel->pending_counter_value, 0);
1897         }
1898 #endif
1899
1900     if (!window ||
1901           xevent->xconfigure.event != xevent->xconfigure.window ||
1902           GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD ||
1903           GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT)
1904         return_val = FALSE;
1905       else
1906         {
1907           event->configure.type = GDK_CONFIGURE;
1908           event->configure.window = window;
1909           event->configure.width = xevent->xconfigure.width;
1910           event->configure.height = xevent->xconfigure.height;
1911           
1912           if (!xevent->xconfigure.send_event &&
1913               !xevent->xconfigure.override_redirect &&
1914               !GDK_WINDOW_DESTROYED (window))
1915             {
1916               gint tx = 0;
1917               gint ty = 0;
1918               Window child_window = 0;
1919
1920               gdk_error_trap_push ();
1921               if (XTranslateCoordinates (GDK_DRAWABLE_XDISPLAY (window),
1922                                          GDK_DRAWABLE_XID (window),
1923                                          screen_x11->xroot_window,
1924                                          0, 0,
1925                                          &tx, &ty,
1926                                          &child_window))
1927                 {
1928                   event->configure.x = tx;
1929                   event->configure.y = ty;
1930                 }
1931               gdk_error_trap_pop ();
1932             }
1933           else
1934             {
1935               event->configure.x = xevent->xconfigure.x;
1936               event->configure.y = xevent->xconfigure.y;
1937             }
1938           window_private->x = event->configure.x;
1939           window_private->y = event->configure.y;
1940           window_private->width = xevent->xconfigure.width;
1941           window_private->height = xevent->xconfigure.height;
1942           
1943           _gdk_window_update_size (window);
1944           _gdk_x11_drawable_update_size (window_private->impl);
1945           
1946           if (window_private->resize_count >= 1)
1947             {
1948               window_private->resize_count -= 1;
1949
1950               if (window_private->resize_count == 0)
1951                 _gdk_moveresize_configure_done (display, window);
1952             }
1953         }
1954       break;
1955       
1956     case PropertyNotify:
1957       GDK_NOTE (EVENTS,
1958                 g_message ("property notify:\twindow: %ld, atom(%ld): %s%s%s",
1959                            xevent->xproperty.window,
1960                            xevent->xproperty.atom,
1961                            "\"",
1962                            gdk_x11_get_xatom_name_for_display (display, xevent->xproperty.atom),
1963                            "\""));
1964
1965       if (window_private == NULL)
1966         {
1967           return_val = FALSE;
1968           break;
1969         }
1970
1971       /* We compare with the serial of the last time we mapped the
1972        * window to avoid refetching properties that we set ourselves
1973        */
1974       if (toplevel &&
1975           xevent->xproperty.serial >= toplevel->map_serial)
1976         {
1977           if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"))
1978             gdk_check_wm_state_changed (window);
1979           
1980           if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"))
1981             gdk_check_wm_desktop_changed (window);
1982         }
1983       
1984       if (window_private->event_mask & GDK_PROPERTY_CHANGE_MASK) 
1985         {
1986           event->property.type = GDK_PROPERTY_NOTIFY;
1987           event->property.window = window;
1988           event->property.atom = gdk_x11_xatom_to_atom_for_display (display, xevent->xproperty.atom);
1989           event->property.time = xevent->xproperty.time;
1990           event->property.state = xevent->xproperty.state;
1991         }
1992       else
1993         return_val = FALSE;
1994
1995       break;
1996       
1997     case SelectionClear:
1998       GDK_NOTE (EVENTS,
1999                 g_message ("selection clear:\twindow: %ld",
2000                            xevent->xproperty.window));
2001
2002       if (_gdk_selection_filter_clear_event (&xevent->xselectionclear))
2003         {
2004           event->selection.type = GDK_SELECTION_CLEAR;
2005           event->selection.window = window;
2006           event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionclear.selection);
2007           event->selection.time = xevent->xselectionclear.time;
2008         }
2009       else
2010         return_val = FALSE;
2011           
2012       break;
2013       
2014     case SelectionRequest:
2015       GDK_NOTE (EVENTS,
2016                 g_message ("selection request:\twindow: %ld",
2017                            xevent->xproperty.window));
2018       
2019       event->selection.type = GDK_SELECTION_REQUEST;
2020       event->selection.window = window;
2021       event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.selection);
2022       event->selection.target = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.target);
2023       event->selection.property = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.property);
2024       event->selection.requestor = xevent->xselectionrequest.requestor;
2025       event->selection.time = xevent->xselectionrequest.time;
2026       
2027       break;
2028       
2029     case SelectionNotify:
2030       GDK_NOTE (EVENTS,
2031                 g_message ("selection notify:\twindow: %ld",
2032                            xevent->xproperty.window));
2033       
2034       
2035       event->selection.type = GDK_SELECTION_NOTIFY;
2036       event->selection.window = window;
2037       event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.selection);
2038       event->selection.target = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.target);
2039       event->selection.property = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.property);
2040       event->selection.time = xevent->xselection.time;
2041       
2042       break;
2043       
2044     case ColormapNotify:
2045       GDK_NOTE (EVENTS,
2046                 g_message ("colormap notify:\twindow: %ld",
2047                            xevent->xcolormap.window));
2048       
2049       /* Not currently handled */
2050       return_val = FALSE;
2051       break;
2052       
2053     case ClientMessage:
2054       {
2055         GList *tmp_list;
2056         GdkFilterReturn result = GDK_FILTER_CONTINUE;
2057         GdkAtom message_type = gdk_x11_xatom_to_atom_for_display (display, xevent->xclient.message_type);
2058
2059         GDK_NOTE (EVENTS,
2060                   g_message ("client message:\twindow: %ld",
2061                              xevent->xclient.window));
2062         
2063         tmp_list = display_x11->client_filters;
2064         while (tmp_list)
2065           {
2066             GdkClientFilter *filter = tmp_list->data;
2067             tmp_list = tmp_list->next;
2068             
2069             if (filter->type == message_type)
2070               {
2071                 result = (*filter->function) (xevent, event, filter->data);
2072                 if (result != GDK_FILTER_CONTINUE)
2073                   break;
2074               }
2075           }
2076
2077         switch (result)
2078           {
2079           case GDK_FILTER_REMOVE:
2080             return_val = FALSE;
2081             break;
2082           case GDK_FILTER_TRANSLATE:
2083             return_val = TRUE;
2084             break;
2085           case GDK_FILTER_CONTINUE:
2086             /* Send unknown ClientMessage's on to Gtk for it to use */
2087             if (window_private == NULL)
2088               {
2089                 return_val = FALSE;
2090               }
2091             else
2092               {
2093                 event->client.type = GDK_CLIENT_EVENT;
2094                 event->client.window = window;
2095                 event->client.message_type = message_type;
2096                 event->client.data_format = xevent->xclient.format;
2097                 memcpy(&event->client.data, &xevent->xclient.data,
2098                        sizeof(event->client.data));
2099               }
2100             break;
2101           }
2102       }
2103       
2104       break;
2105       
2106     case MappingNotify:
2107       GDK_NOTE (EVENTS,
2108                 g_message ("mapping notify"));
2109       
2110       /* Let XLib know that there is a new keyboard mapping.
2111        */
2112       XRefreshKeyboardMapping (&xevent->xmapping);
2113       _gdk_keymap_keys_changed (display);
2114       return_val = FALSE;
2115       break;
2116
2117     default:
2118 #ifdef HAVE_XKB
2119       if (xevent->type == display_x11->xkb_event_type)
2120         {
2121           XkbEvent *xkb_event = (XkbEvent *)xevent;
2122
2123           switch (xkb_event->any.xkb_type)
2124             {
2125             case XkbNewKeyboardNotify:
2126             case XkbMapNotify:
2127               _gdk_keymap_keys_changed (display);
2128
2129               return_val = FALSE;
2130               break;
2131               
2132             case XkbStateNotify:
2133               _gdk_keymap_state_changed (display, xevent);
2134               break;
2135             }
2136         }
2137       else
2138 #endif
2139 #ifdef HAVE_XFIXES
2140       if (xevent->type - display_x11->xfixes_event_base == XFixesSelectionNotify)
2141         {
2142           XFixesSelectionNotifyEvent *selection_notify = (XFixesSelectionNotifyEvent *)xevent;
2143
2144           _gdk_x11_screen_process_owner_change (screen, xevent);
2145           
2146           event->owner_change.type = GDK_OWNER_CHANGE;
2147           event->owner_change.window = window;
2148           event->owner_change.owner = selection_notify->owner;
2149           event->owner_change.reason = selection_notify->subtype;
2150           event->owner_change.selection = 
2151             gdk_x11_xatom_to_atom_for_display (display, 
2152                                                selection_notify->selection);
2153           event->owner_change.time = selection_notify->timestamp;
2154           event->owner_change.selection_time = selection_notify->selection_timestamp;
2155           
2156           return_val = TRUE;
2157         }
2158       else
2159 #endif
2160 #ifdef HAVE_RANDR
2161       if (xevent->type - display_x11->xrandr_event_base == RRScreenChangeNotify ||
2162           xevent->type - display_x11->xrandr_event_base == RRNotify)
2163         {
2164           if (screen)
2165             _gdk_x11_screen_size_changed (screen, xevent);
2166         }
2167       else
2168 #endif
2169 #if defined(HAVE_XCOMPOSITE) && defined (HAVE_XDAMAGE) && defined (HAVE_XFIXES)
2170       if (display_x11->have_xdamage && window_private && window_private->composited &&
2171           xevent->type == display_x11->xdamage_event_base + XDamageNotify &&
2172           ((XDamageNotifyEvent *) xevent)->damage == window_impl->damage)
2173         {
2174           XDamageNotifyEvent *damage_event = (XDamageNotifyEvent *) xevent;
2175           XserverRegion repair;
2176           GdkRectangle rect;
2177
2178           rect.x = window_private->x + damage_event->area.x;
2179           rect.y = window_private->y + damage_event->area.y;
2180           rect.width = damage_event->area.width;
2181           rect.height = damage_event->area.height;
2182
2183           repair = XFixesCreateRegion (display_x11->xdisplay,
2184                                        &damage_event->area, 1);
2185           XDamageSubtract (display_x11->xdisplay,
2186                            window_impl->damage,
2187                            repair, None);
2188           XFixesDestroyRegion (display_x11->xdisplay, repair);
2189
2190           if (window_private->parent != NULL)
2191             _gdk_window_process_expose (GDK_WINDOW (window_private->parent),
2192                                         damage_event->serial, &rect);
2193
2194           return_val = TRUE;
2195         }
2196       else
2197 #endif
2198         {
2199           /* something else - (e.g., a Xinput event) */
2200           
2201           if (window_private &&
2202               !GDK_WINDOW_DESTROYED (window_private) &&
2203               (window_private->extension_events != 0))
2204             return_val = _gdk_input_other_event(event, xevent, window);
2205           else
2206             return_val = FALSE;
2207           
2208           break;
2209         }
2210     }
2211
2212  done:
2213   if (return_val)
2214     {
2215       if (event->any.window)
2216         g_object_ref (event->any.window);
2217       if (((event->any.type == GDK_ENTER_NOTIFY) ||
2218            (event->any.type == GDK_LEAVE_NOTIFY)) &&
2219           (event->crossing.subwindow != NULL))
2220         g_object_ref (event->crossing.subwindow);
2221     }
2222   else
2223     {
2224       /* Mark this event as having no resources to be freed */
2225       event->any.window = NULL;
2226       event->any.type = GDK_NOTHING;
2227     }
2228   
2229   if (window)
2230     g_object_unref (window);
2231
2232   if (unref_pixmap)
2233     g_object_unref (unref_pixmap);
2234   
2235   return return_val;
2236 }
2237
2238 static GdkFilterReturn
2239 gdk_wm_protocols_filter (GdkXEvent *xev,
2240                          GdkEvent  *event,
2241                          gpointer data)
2242 {
2243   XEvent *xevent = (XEvent *)xev;
2244   GdkWindow *win = event->any.window;
2245   GdkDisplay *display;
2246   Atom atom;
2247
2248   if (!win)
2249       return GDK_FILTER_REMOVE;    
2250
2251   display = GDK_WINDOW_DISPLAY (win);
2252   atom = (Atom)xevent->xclient.data.l[0];
2253
2254   if (atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_DELETE_WINDOW"))
2255     {
2256   /* The delete window request specifies a window
2257    *  to delete. We don't actually destroy the
2258    *  window because "it is only a request". (The
2259    *  window might contain vital data that the
2260    *  program does not want destroyed). Instead
2261    *  the event is passed along to the program,
2262    *  which should then destroy the window.
2263    */
2264       GDK_NOTE (EVENTS,
2265                 g_message ("delete window:\t\twindow: %ld",
2266                            xevent->xclient.window));
2267       
2268       event->any.type = GDK_DELETE;
2269
2270       gdk_x11_window_set_user_time (win, xevent->xclient.data.l[1]);
2271
2272       return GDK_FILTER_TRANSLATE;
2273     }
2274   else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_TAKE_FOCUS"))
2275     {
2276       GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (event->any.window);
2277       GdkWindowObject *private = (GdkWindowObject *)win;
2278
2279       /* There is no way of knowing reliably whether we are viewable;
2280        * _gdk_x11_set_input_focus_safe() traps errors asynchronously.
2281        */
2282       if (toplevel && private->accept_focus)
2283         _gdk_x11_set_input_focus_safe (display, toplevel->focus_window,
2284                                        RevertToParent,
2285                                        xevent->xclient.data.l[1]);
2286
2287       return GDK_FILTER_REMOVE;
2288     }
2289   else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PING") &&
2290            !_gdk_x11_display_is_root_window (display,
2291                                              xevent->xclient.window))
2292     {
2293       XClientMessageEvent xclient = xevent->xclient;
2294       
2295       xclient.window = GDK_WINDOW_XROOTWIN (win);
2296       XSendEvent (GDK_WINDOW_XDISPLAY (win), 
2297                   xclient.window,
2298                   False, 
2299                   SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xclient);
2300
2301       return GDK_FILTER_REMOVE;
2302     }
2303   else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_SYNC_REQUEST") &&
2304            GDK_DISPLAY_X11 (display)->use_sync)
2305     {
2306       GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (event->any.window);
2307       if (toplevel)
2308         {
2309 #ifdef HAVE_XSYNC
2310           XSyncIntsToValue (&toplevel->pending_counter_value, 
2311                             xevent->xclient.data.l[2], 
2312                             xevent->xclient.data.l[3]);
2313 #endif
2314         }
2315       return GDK_FILTER_REMOVE;
2316     }
2317   
2318   return GDK_FILTER_CONTINUE;
2319 }
2320
2321 void
2322 _gdk_events_queue (GdkDisplay *display)
2323 {
2324   GList *node;
2325   GdkEvent *event;
2326   XEvent xevent;
2327   Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
2328
2329   while (!_gdk_event_queue_find_first(display) && XPending (xdisplay))
2330     {
2331       XNextEvent (xdisplay, &xevent);
2332
2333       switch (xevent.type)
2334         {
2335         case KeyPress:
2336         case KeyRelease:
2337           break;
2338         default:
2339           if (XFilterEvent (&xevent, None))
2340             continue;
2341         }
2342       
2343       event = gdk_event_new (GDK_NOTHING);
2344       
2345       event->any.window = NULL;
2346       event->any.send_event = xevent.xany.send_event ? TRUE : FALSE;
2347
2348       ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
2349
2350       node = _gdk_event_queue_append (display, event);
2351
2352       if (gdk_event_translate (display, event, &xevent, FALSE))
2353         {
2354           ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
2355           _gdk_windowing_got_event (display, node, event, xevent.xany.serial);
2356         }
2357       else
2358         {
2359           _gdk_event_queue_remove_link (display, node);
2360           g_list_free_1 (node);
2361           gdk_event_free (event);
2362         }
2363     }
2364 }
2365
2366 static gboolean  
2367 gdk_event_prepare (GSource  *source,
2368                    gint     *timeout)
2369 {
2370   GdkDisplay *display = ((GdkDisplaySource*)source)->display;
2371   gboolean retval;
2372   
2373   GDK_THREADS_ENTER ();
2374
2375   *timeout = -1;
2376   retval = (_gdk_event_queue_find_first (display) != NULL || 
2377             gdk_check_xpending (display));
2378   
2379   GDK_THREADS_LEAVE ();
2380
2381   return retval;
2382 }
2383
2384 static gboolean  
2385 gdk_event_check (GSource *source) 
2386 {
2387   GdkDisplaySource *display_source = (GdkDisplaySource*)source;
2388   gboolean retval;
2389
2390   GDK_THREADS_ENTER ();
2391
2392   if (display_source->event_poll_fd.revents & G_IO_IN)
2393     retval = (_gdk_event_queue_find_first (display_source->display) != NULL || 
2394               gdk_check_xpending (display_source->display));
2395   else
2396     retval = FALSE;
2397
2398   GDK_THREADS_LEAVE ();
2399
2400   return retval;
2401 }
2402
2403 static gboolean  
2404 gdk_event_dispatch (GSource    *source,
2405                     GSourceFunc callback,
2406                     gpointer    user_data)
2407 {
2408   GdkDisplay *display = ((GdkDisplaySource*)source)->display;
2409   GdkEvent *event;
2410  
2411   GDK_THREADS_ENTER ();
2412
2413   _gdk_events_queue (display);
2414   event = _gdk_event_unqueue (display);
2415
2416   if (event)
2417     {
2418       if (_gdk_event_func)
2419         (*_gdk_event_func) (event, _gdk_event_data);
2420       
2421       gdk_event_free (event);
2422     }
2423   
2424   GDK_THREADS_LEAVE ();
2425
2426   return TRUE;
2427 }
2428
2429 /**
2430  * gdk_event_send_client_message_for_display:
2431  * @display: the #GdkDisplay for the window where the message is to be sent.
2432  * @event: the #GdkEvent to send, which should be a #GdkEventClient.
2433  * @winid: the window to send the client message to.
2434  *
2435  * On X11, sends an X ClientMessage event to a given window. On
2436  * Windows, sends a message registered with the name
2437  * GDK_WIN32_CLIENT_MESSAGE.
2438  *
2439  * This could be used for communicating between different
2440  * applications, though the amount of data is limited to 20 bytes on
2441  * X11, and to just four bytes on Windows.
2442  *
2443  * Returns: non-zero on success.
2444  *
2445  * Since: 2.2
2446  */
2447 gboolean
2448 gdk_event_send_client_message_for_display (GdkDisplay     *display,
2449                                            GdkEvent       *event,
2450                                            GdkNativeWindow winid)
2451 {
2452   XEvent sev;
2453   
2454   g_return_val_if_fail(event != NULL, FALSE);
2455
2456   /* Set up our event to send, with the exception of its target window */
2457   sev.xclient.type = ClientMessage;
2458   sev.xclient.display = GDK_DISPLAY_XDISPLAY (display);
2459   sev.xclient.format = event->client.data_format;
2460   sev.xclient.window = winid;
2461   memcpy(&sev.xclient.data, &event->client.data, sizeof (sev.xclient.data));
2462   sev.xclient.message_type = gdk_x11_atom_to_xatom_for_display (display, event->client.message_type);
2463   
2464   return _gdk_send_xevent (display, winid, False, NoEventMask, &sev);
2465 }
2466
2467
2468
2469 /* Sends a ClientMessage to all toplevel client windows */
2470 static gboolean
2471 gdk_event_send_client_message_to_all_recurse (GdkDisplay *display,
2472                                               XEvent     *xev, 
2473                                               guint32     xid,
2474                                               guint       level)
2475 {
2476   Atom type = None;
2477   int format;
2478   unsigned long nitems, after;
2479   unsigned char *data;
2480   Window *ret_children, ret_root, ret_parent;
2481   unsigned int ret_nchildren;
2482   gboolean send = FALSE;
2483   gboolean found = FALSE;
2484   gboolean result = FALSE;
2485   int i;
2486   
2487   gdk_error_trap_push ();
2488   
2489   if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), xid, 
2490                           gdk_x11_get_xatom_by_name_for_display (display, "WM_STATE"),
2491                           0, 0, False, AnyPropertyType,
2492                           &type, &format, &nitems, &after, &data) != Success)
2493     goto out;
2494   
2495   if (type)
2496     {
2497       send = TRUE;
2498       XFree (data);
2499     }
2500   else
2501     {
2502       /* OK, we're all set, now let's find some windows to send this to */
2503       if (!XQueryTree (GDK_DISPLAY_XDISPLAY (display), xid,
2504                       &ret_root, &ret_parent,
2505                       &ret_children, &ret_nchildren))   
2506         goto out;
2507
2508       for(i = 0; i < ret_nchildren; i++)
2509         if (gdk_event_send_client_message_to_all_recurse (display, xev, ret_children[i], level + 1))
2510           found = TRUE;
2511
2512       XFree (ret_children);
2513     }
2514
2515   if (send || (!found && (level == 1)))
2516     {
2517       xev->xclient.window = xid;
2518       _gdk_send_xevent (display, xid, False, NoEventMask, xev);
2519     }
2520
2521   result = send || found;
2522
2523  out:
2524   gdk_error_trap_pop ();
2525
2526   return result;
2527 }
2528
2529 /**
2530  * gdk_screen_broadcast_client_message:
2531  * @screen: the #GdkScreen where the event will be broadcasted.
2532  * @event: the #GdkEvent.
2533  *
2534  * On X11, sends an X ClientMessage event to all toplevel windows on
2535  * @screen. 
2536  *
2537  * Toplevel windows are determined by checking for the WM_STATE property, 
2538  * as described in the Inter-Client Communication Conventions Manual (ICCCM).
2539  * If no windows are found with the WM_STATE property set, the message is 
2540  * sent to all children of the root window.
2541  *
2542  * On Windows, broadcasts a message registered with the name
2543  * GDK_WIN32_CLIENT_MESSAGE to all top-level windows. The amount of
2544  * data is limited to one long, i.e. four bytes.
2545  *
2546  * Since: 2.2
2547  */
2548
2549 void
2550 gdk_screen_broadcast_client_message (GdkScreen *screen, 
2551                                      GdkEvent  *event)
2552 {
2553   XEvent sev;
2554   GdkWindow *root_window;
2555
2556   g_return_if_fail (event != NULL);
2557   
2558   root_window = gdk_screen_get_root_window (screen);
2559   
2560   /* Set up our event to send, with the exception of its target window */
2561   sev.xclient.type = ClientMessage;
2562   sev.xclient.display = GDK_WINDOW_XDISPLAY (root_window);
2563   sev.xclient.format = event->client.data_format;
2564   memcpy(&sev.xclient.data, &event->client.data, sizeof (sev.xclient.data));
2565   sev.xclient.message_type = 
2566     gdk_x11_atom_to_xatom_for_display (GDK_WINDOW_DISPLAY (root_window),
2567                                        event->client.message_type);
2568
2569   gdk_event_send_client_message_to_all_recurse (gdk_screen_get_display (screen),
2570                                                 &sev, 
2571                                                 GDK_WINDOW_XID (root_window), 
2572                                                 0);
2573 }
2574
2575 /*
2576  *--------------------------------------------------------------
2577  * gdk_flush
2578  *
2579  *   Flushes the Xlib output buffer and then waits
2580  *   until all requests have been received and processed
2581  *   by the X server. The only real use for this function
2582  *   is in dealing with XShm.
2583  *
2584  * Arguments:
2585  *
2586  * Results:
2587  *
2588  * Side effects:
2589  *
2590  *--------------------------------------------------------------
2591  */
2592
2593 void
2594 gdk_flush (void)
2595 {
2596   GSList *tmp_list = _gdk_displays;
2597   
2598   while (tmp_list)
2599     {
2600       XSync (GDK_DISPLAY_XDISPLAY (tmp_list->data), False);
2601       tmp_list = tmp_list->next;
2602     }
2603 }
2604
2605 static Bool
2606 timestamp_predicate (Display *display,
2607                      XEvent  *xevent,
2608                      XPointer arg)
2609 {
2610   Window xwindow = GPOINTER_TO_UINT (arg);
2611   GdkDisplay *gdk_display = gdk_x11_lookup_xdisplay (display);
2612
2613   if (xevent->type == PropertyNotify &&
2614       xevent->xproperty.window == xwindow &&
2615       xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (gdk_display,
2616                                                                        "GDK_TIMESTAMP_PROP"))
2617     return True;
2618
2619   return False;
2620 }
2621
2622 /**
2623  * gdk_x11_get_server_time:
2624  * @window: a #GdkWindow, used for communication with the server.
2625  *          The window must have GDK_PROPERTY_CHANGE_MASK in its
2626  *          events mask or a hang will result.
2627  * 
2628  * Routine to get the current X server time stamp. 
2629  * 
2630  * Return value: the time stamp.
2631  **/
2632 guint32
2633 gdk_x11_get_server_time (GdkWindow *window)
2634 {
2635   Display *xdisplay;
2636   Window   xwindow;
2637   guchar c = 'a';
2638   XEvent xevent;
2639   Atom timestamp_prop_atom;
2640
2641   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
2642   g_return_val_if_fail (!GDK_WINDOW_DESTROYED (window), 0);
2643
2644   xdisplay = GDK_WINDOW_XDISPLAY (window);
2645   xwindow = GDK_WINDOW_XWINDOW (window);
2646   timestamp_prop_atom = 
2647     gdk_x11_get_xatom_by_name_for_display (GDK_WINDOW_DISPLAY (window),
2648                                            "GDK_TIMESTAMP_PROP");
2649   
2650   XChangeProperty (xdisplay, xwindow, timestamp_prop_atom,
2651                    timestamp_prop_atom,
2652                    8, PropModeReplace, &c, 1);
2653
2654   XIfEvent (xdisplay, &xevent,
2655             timestamp_predicate, GUINT_TO_POINTER(xwindow));
2656
2657   return xevent.xproperty.time;
2658 }
2659
2660 static void
2661 fetch_net_wm_check_window (GdkScreen *screen)
2662 {
2663   GdkScreenX11 *screen_x11;
2664   GdkDisplay *display;
2665   Atom type;
2666   gint format;
2667   gulong n_items;
2668   gulong bytes_after;
2669   guchar *data;
2670   Window *xwindow;
2671   GTimeVal tv;
2672   
2673   screen_x11 = GDK_SCREEN_X11 (screen);
2674   display = screen_x11->display;
2675
2676   g_return_if_fail (GDK_DISPLAY_X11 (display)->trusted_client);
2677   
2678   g_get_current_time (&tv);
2679       
2680   if (ABS  (tv.tv_sec - screen_x11->last_wmspec_check_time) < 15)
2681     return; /* we've checked recently */
2682
2683   screen_x11->last_wmspec_check_time = tv.tv_sec;
2684
2685   data = NULL;
2686   XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), screen_x11->xroot_window,
2687                       gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTING_WM_CHECK"),
2688                       0, G_MAXLONG, False, XA_WINDOW, &type, &format, 
2689                       &n_items, &bytes_after, &data);
2690   
2691   if (type != XA_WINDOW)
2692     {
2693       if (data)
2694         XFree (data);
2695       return;
2696     }
2697
2698   xwindow = (Window *)data;
2699
2700   if (screen_x11->wmspec_check_window == *xwindow)
2701     {
2702       XFree (xwindow);
2703       return;
2704     }
2705
2706   gdk_error_trap_push ();
2707   
2708   /* Find out if this WM goes away, so we can reset everything. */
2709   XSelectInput (screen_x11->xdisplay, *xwindow, StructureNotifyMask);
2710   gdk_display_sync (display);
2711
2712   if (gdk_error_trap_pop () == Success)
2713     {
2714       screen_x11->wmspec_check_window = *xwindow;
2715       screen_x11->need_refetch_net_supported = TRUE;
2716       screen_x11->need_refetch_wm_name = TRUE;
2717       
2718       /* Careful, reentrancy */
2719       _gdk_x11_screen_window_manager_changed (GDK_SCREEN (screen_x11));
2720     }
2721
2722   XFree (xwindow);    
2723 }
2724
2725 /**
2726  * gdk_x11_screen_get_window_manager_name:
2727  * @screen: a #GdkScreen 
2728  * 
2729  * Returns the name of the window manager for @screen. 
2730  * 
2731  * Return value: the name of the window manager screen @screen, or 
2732  * "unknown" if the window manager is unknown. The string is owned by GDK
2733  * and should not be freed.
2734  *
2735  * Since: 2.2
2736  **/
2737 const char*
2738 gdk_x11_screen_get_window_manager_name (GdkScreen *screen)
2739 {
2740   GdkScreenX11 *screen_x11;
2741
2742   screen_x11 = GDK_SCREEN_X11 (screen);
2743   
2744   if (!G_LIKELY (GDK_DISPLAY_X11 (screen_x11->display)->trusted_client))
2745     return screen_x11->window_manager_name;
2746
2747   fetch_net_wm_check_window (screen);
2748
2749   if (screen_x11->need_refetch_wm_name)
2750     {
2751       /* Get the name of the window manager */
2752       screen_x11->need_refetch_wm_name = FALSE;
2753
2754       g_free (screen_x11->window_manager_name);
2755       screen_x11->window_manager_name = g_strdup ("unknown");
2756       
2757       if (screen_x11->wmspec_check_window != None)
2758         {
2759           Atom type;
2760           gint format;
2761           gulong n_items;
2762           gulong bytes_after;
2763           gchar *name;
2764           
2765           name = NULL;
2766
2767           gdk_error_trap_push ();
2768           
2769           XGetWindowProperty (GDK_DISPLAY_XDISPLAY (screen_x11->display),
2770                               screen_x11->wmspec_check_window,
2771                               gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
2772                                                                      "_NET_WM_NAME"),
2773                               0, G_MAXLONG, False,
2774                               gdk_x11_get_xatom_by_name_for_display (screen_x11->display,
2775                                                                      "UTF8_STRING"),
2776                               &type, &format, 
2777                               &n_items, &bytes_after,
2778                               (guchar **)&name);
2779           
2780           gdk_display_sync (screen_x11->display);
2781           
2782           gdk_error_trap_pop ();
2783           
2784           if (name != NULL)
2785             {
2786               g_free (screen_x11->window_manager_name);
2787               screen_x11->window_manager_name = g_strdup (name);
2788               XFree (name);
2789             }
2790         }
2791     }
2792   
2793   return GDK_SCREEN_X11 (screen)->window_manager_name;
2794 }
2795
2796 typedef struct _NetWmSupportedAtoms NetWmSupportedAtoms;
2797
2798 struct _NetWmSupportedAtoms
2799 {
2800   Atom *atoms;
2801   gulong n_atoms;
2802 };
2803
2804 static void
2805 cleanup_atoms(gpointer data)
2806 {
2807   NetWmSupportedAtoms *supported_atoms = data;
2808   if (supported_atoms->atoms)
2809       XFree (supported_atoms->atoms);
2810   g_free (supported_atoms);
2811 }
2812
2813 /**
2814  * gdk_x11_screen_supports_net_wm_hint:
2815  * @screen: the relevant #GdkScreen.
2816  * @property: a property atom.
2817  * 
2818  * This function is specific to the X11 backend of GDK, and indicates
2819  * whether the window manager supports a certain hint from the
2820  * Extended Window Manager Hints Specification. You can find this
2821  * specification on 
2822  * <ulink url="http://www.freedesktop.org">http://www.freedesktop.org</ulink>.
2823  *
2824  * When using this function, keep in mind that the window manager
2825  * can change over time; so you shouldn't use this function in
2826  * a way that impacts persistent application state. A common bug
2827  * is that your application can start up before the window manager
2828  * does when the user logs in, and before the window manager starts
2829  * gdk_x11_screen_supports_net_wm_hint() will return %FALSE for every property.
2830  * You can monitor the window_manager_changed signal on #GdkScreen to detect
2831  * a window manager change.
2832  * 
2833  * Return value: %TRUE if the window manager supports @property
2834  *
2835  * Since: 2.2
2836  **/
2837 gboolean
2838 gdk_x11_screen_supports_net_wm_hint (GdkScreen *screen,
2839                                      GdkAtom    property)
2840 {
2841   gulong i;
2842   GdkScreenX11 *screen_x11;
2843   NetWmSupportedAtoms *supported_atoms;
2844   GdkDisplay *display;
2845
2846   g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
2847   
2848   screen_x11 = GDK_SCREEN_X11 (screen);
2849   display = screen_x11->display;
2850
2851   if (!G_LIKELY (GDK_DISPLAY_X11 (display)->trusted_client))
2852     return FALSE;
2853
2854   supported_atoms = g_object_get_data (G_OBJECT (screen), "gdk-net-wm-supported-atoms");
2855   if (!supported_atoms)
2856     {
2857       supported_atoms = g_new0 (NetWmSupportedAtoms, 1);
2858       g_object_set_data_full (G_OBJECT (screen), "gdk-net-wm-supported-atoms", supported_atoms, cleanup_atoms);
2859     }
2860
2861   fetch_net_wm_check_window (screen);
2862
2863   if (screen_x11->wmspec_check_window == None)
2864     return FALSE;
2865   
2866   if (screen_x11->need_refetch_net_supported)
2867     {
2868       /* WM has changed since we last got the supported list,
2869        * refetch it.
2870        */
2871       Atom type;
2872       gint format;
2873       gulong bytes_after;
2874
2875       screen_x11->need_refetch_net_supported = FALSE;
2876       
2877       if (supported_atoms->atoms)
2878         XFree (supported_atoms->atoms);
2879       
2880       supported_atoms->atoms = NULL;
2881       supported_atoms->n_atoms = 0;
2882       
2883       XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), screen_x11->xroot_window,
2884                           gdk_x11_get_xatom_by_name_for_display (display, "_NET_SUPPORTED"),
2885                           0, G_MAXLONG, False, XA_ATOM, &type, &format, 
2886                           &supported_atoms->n_atoms, &bytes_after,
2887                           (guchar **)&supported_atoms->atoms);
2888       
2889       if (type != XA_ATOM)
2890         return FALSE;
2891     }
2892   
2893   if (supported_atoms->atoms == NULL)
2894     return FALSE;
2895   
2896   i = 0;
2897   while (i < supported_atoms->n_atoms)
2898     {
2899       if (supported_atoms->atoms[i] == gdk_x11_atom_to_xatom_for_display (display, property))
2900         return TRUE;
2901       
2902       ++i;
2903     }
2904   
2905   return FALSE;
2906 }
2907
2908 /**
2909  * gdk_net_wm_supports:
2910  * @property: a property atom.
2911  * 
2912  * This function is specific to the X11 backend of GDK, and indicates
2913  * whether the window manager for the default screen supports a certain
2914  * hint from the Extended Window Manager Hints Specification. See
2915  * gdk_x11_screen_supports_net_wm_hint() for complete details.
2916  * 
2917  * Return value: %TRUE if the window manager supports @property
2918  **/
2919 gboolean
2920 gdk_net_wm_supports (GdkAtom property)
2921 {
2922   return gdk_x11_screen_supports_net_wm_hint (gdk_screen_get_default (), property);
2923 }
2924
2925
2926 static void
2927 gdk_xsettings_notify_cb (const char       *name,
2928                          XSettingsAction   action,
2929                          XSettingsSetting *setting,
2930                          void             *data)
2931 {
2932   GdkEvent new_event;
2933   GdkScreen *screen = data;
2934   GdkScreenX11 *screen_x11 = data;
2935   int i;
2936
2937   if (screen_x11->xsettings_in_init)
2938     return;
2939   
2940   new_event.type = GDK_SETTING;
2941   new_event.setting.window = gdk_screen_get_root_window (screen);
2942   new_event.setting.send_event = FALSE;
2943   new_event.setting.name = NULL;
2944
2945   for (i = 0; i < GDK_SETTINGS_N_ELEMENTS() ; i++)
2946     if (strcmp (GDK_SETTINGS_X_NAME (i), name) == 0)
2947       {
2948         new_event.setting.name = (char*) GDK_SETTINGS_GDK_NAME (i);
2949         break;
2950       }
2951   
2952   if (!new_event.setting.name)
2953     return;
2954   
2955   switch (action)
2956     {
2957     case XSETTINGS_ACTION_NEW:
2958       new_event.setting.action = GDK_SETTING_ACTION_NEW;
2959       break;
2960     case XSETTINGS_ACTION_CHANGED:
2961       new_event.setting.action = GDK_SETTING_ACTION_CHANGED;
2962       break;
2963     case XSETTINGS_ACTION_DELETED:
2964       new_event.setting.action = GDK_SETTING_ACTION_DELETED;
2965       break;
2966     }
2967
2968   gdk_event_put (&new_event);
2969 }
2970
2971 static gboolean
2972 check_transform (const gchar *xsettings_name,
2973                  GType        src_type,
2974                  GType        dest_type)
2975 {
2976   if (!g_value_type_transformable (src_type, dest_type))
2977     {
2978       g_warning ("Cannot transform xsetting %s of type %s to type %s\n",
2979                  xsettings_name,
2980                  g_type_name (src_type),
2981                  g_type_name (dest_type));
2982       return FALSE;
2983     }
2984   else
2985     return TRUE;
2986 }
2987
2988 /**
2989  * gdk_screen_get_setting:
2990  * @screen: the #GdkScreen where the setting is located
2991  * @name: the name of the setting
2992  * @value: location to store the value of the setting
2993  *
2994  * Retrieves a desktop-wide setting such as double-click time
2995  * for the #GdkScreen @screen. 
2996  *
2997  * FIXME needs a list of valid settings here, or a link to 
2998  * more information.
2999  * 
3000  * Returns: %TRUE if the setting existed and a value was stored
3001  *   in @value, %FALSE otherwise.
3002  *
3003  * Since: 2.2
3004  **/
3005 gboolean
3006 gdk_screen_get_setting (GdkScreen   *screen,
3007                         const gchar *name,
3008                         GValue      *value)
3009 {
3010
3011   const char *xsettings_name = NULL;
3012   XSettingsResult result;
3013   XSettingsSetting *setting = NULL;
3014   GdkScreenX11 *screen_x11;
3015   gboolean success = FALSE;
3016   gint i;
3017   GValue tmp_val = { 0, };
3018   
3019   g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
3020   
3021   screen_x11 = GDK_SCREEN_X11 (screen);
3022
3023   for (i = 0; i < GDK_SETTINGS_N_ELEMENTS(); i++)
3024     if (strcmp (GDK_SETTINGS_GDK_NAME (i), name) == 0)
3025       {
3026         xsettings_name = GDK_SETTINGS_X_NAME (i);
3027         break;
3028       }
3029
3030   if (!xsettings_name)
3031     goto out;
3032
3033   result = xsettings_client_get_setting (screen_x11->xsettings_client, 
3034                                          xsettings_name, &setting);
3035   if (result != XSETTINGS_SUCCESS)
3036     goto out;
3037
3038   switch (setting->type)
3039     {
3040     case XSETTINGS_TYPE_INT:
3041       if (check_transform (xsettings_name, G_TYPE_INT, G_VALUE_TYPE (value)))
3042         {
3043           g_value_init (&tmp_val, G_TYPE_INT);
3044           g_value_set_int (&tmp_val, setting->data.v_int);
3045           g_value_transform (&tmp_val, value);
3046
3047           success = TRUE;
3048         }
3049       break;
3050     case XSETTINGS_TYPE_STRING:
3051       if (check_transform (xsettings_name, G_TYPE_STRING, G_VALUE_TYPE (value)))
3052         {
3053           g_value_init (&tmp_val, G_TYPE_STRING);
3054           g_value_set_string (&tmp_val, setting->data.v_string);
3055           g_value_transform (&tmp_val, value);
3056
3057           success = TRUE;
3058         }
3059       break;
3060     case XSETTINGS_TYPE_COLOR:
3061       if (!check_transform (xsettings_name, GDK_TYPE_COLOR, G_VALUE_TYPE (value)))
3062         {
3063           GdkColor color;
3064           
3065           g_value_init (&tmp_val, GDK_TYPE_COLOR);
3066
3067           color.pixel = 0;
3068           color.red = setting->data.v_color.red;
3069           color.green = setting->data.v_color.green;
3070           color.blue = setting->data.v_color.blue;
3071           
3072           g_value_set_boxed (&tmp_val, &color);
3073           
3074           g_value_transform (&tmp_val, value);
3075           
3076           success = TRUE;
3077         }
3078       break;
3079     }
3080   
3081   g_value_unset (&tmp_val);
3082
3083  out:
3084   if (setting)
3085     xsettings_setting_free (setting);
3086
3087   if (success)
3088     return TRUE;
3089   else
3090     return _gdk_x11_get_xft_setting (screen, name, value);
3091 }
3092
3093 static GdkFilterReturn 
3094 gdk_xsettings_client_event_filter (GdkXEvent *xevent,
3095                                    GdkEvent  *event,
3096                                    gpointer   data)
3097 {
3098   GdkScreenX11 *screen = data;
3099   
3100   if (xsettings_client_process_event (screen->xsettings_client, (XEvent *)xevent))
3101     return GDK_FILTER_REMOVE;
3102   else
3103     return GDK_FILTER_CONTINUE;
3104 }
3105
3106 static Bool
3107 gdk_xsettings_watch_cb (Window   window,
3108                         Bool     is_start,
3109                         long     mask,
3110                         void    *cb_data)
3111 {
3112   GdkWindow *gdkwin;
3113   GdkScreen *screen = cb_data;
3114
3115   gdkwin = gdk_window_lookup_for_display (gdk_screen_get_display (screen), window);
3116
3117   if (is_start)
3118     {
3119       if (gdkwin)
3120         g_object_ref (gdkwin);
3121       else
3122         {
3123           gdkwin = gdk_window_foreign_new_for_display (gdk_screen_get_display (screen), window);
3124           
3125           /* gdk_window_foreign_new_for_display() can fail and return NULL if the
3126            * window has already been destroyed.
3127            */
3128           if (!gdkwin)
3129             return False;
3130         }
3131
3132       gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
3133     }
3134   else
3135     {
3136       if (!gdkwin)
3137         {
3138           /* gdkwin should not be NULL here, since if starting the watch succeeded
3139            * we have a reference on the window. It might mean that the caller didn't
3140            * remove the watch when it got a DestroyNotify event. Or maybe the
3141            * caller ignored the return value when starting the watch failed.
3142            */
3143           g_warning ("gdk_xsettings_watch_cb(): Couldn't find window to unwatch");
3144           return False;
3145         }
3146       
3147       gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, screen);
3148       g_object_unref (gdkwin);
3149     }
3150
3151   return True;
3152 }
3153
3154 void
3155 _gdk_windowing_event_data_copy (const GdkEvent *src,
3156                                 GdkEvent       *dst)
3157 {
3158 }
3159
3160 void
3161 _gdk_windowing_event_data_free (GdkEvent *event)
3162 {
3163 }
3164
3165 #define __GDK_EVENTS_X11_C__
3166 #include "gdkaliasdef.c"