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