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