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