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