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