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