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