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