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