]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkevents-x11.c
Test for window == NULL in a number of cases.
[~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
32 #include "gdkkeysyms.h"
33
34 #include "xsettings-client.h"
35
36 #if HAVE_CONFIG_H
37 #  include <config.h>
38 #  if STDC_HEADERS
39 #    include <string.h>
40 #  endif
41 #endif
42
43 #include "gdkinputprivate.h"
44
45 #ifdef HAVE_XKB
46 #include <X11/XKBlib.h>
47 #endif
48
49 #include <X11/Xatom.h>
50
51 typedef struct _GdkIOClosure GdkIOClosure;
52 typedef struct _GdkEventPrivate GdkEventPrivate;
53
54 #define DOUBLE_CLICK_TIME      250
55 #define TRIPLE_CLICK_TIME      500
56 #define DOUBLE_CLICK_DIST      5
57 #define TRIPLE_CLICK_DIST      5
58
59 typedef enum
60 {
61   /* Following flag is set for events on the event queue during
62    * translation and cleared afterwards.
63    */
64   GDK_EVENT_PENDING = 1 << 0
65 } GdkEventFlags;
66
67 struct _GdkIOClosure
68 {
69   GdkInputFunction function;
70   GdkInputCondition condition;
71   GdkDestroyNotify notify;
72   gpointer data;
73 };
74
75 struct _GdkEventPrivate
76 {
77   GdkEvent event;
78   guint    flags;
79 };
80
81 /* 
82  * Private function declarations
83  */
84
85 static gint      gdk_event_apply_filters (XEvent   *xevent,
86                                           GdkEvent *event,
87                                           GList    *filters);
88 static gint      gdk_event_translate     (GdkEvent *event, 
89                                           XEvent   *xevent,
90                                           gboolean  return_exposes);
91 #if 0
92 static Bool      gdk_event_get_type     (Display   *display, 
93                                          XEvent    *xevent, 
94                                          XPointer   arg);
95 #endif
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 GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev,
105                                          GdkEvent  *event,
106                                          gpointer   data);
107
108 static void gdk_xsettings_watch_cb  (Window            window,
109                                      Bool              is_start,
110                                      long              mask,
111                                      void             *cb_data);
112 static void gdk_xsettings_notify_cb (const char       *name,
113                                      XSettingsAction   action,
114                                      XSettingsSetting *setting,
115                                      void             *data);
116
117 /* Private variable declarations
118  */
119
120 static int connection_number = 0;           /* The file descriptor number of our
121                                              *  connection to the X server. This
122                                              *  is used so that we may determine
123                                              *  when events are pending by using
124                                              *  the "select" system call.
125                                              */
126 static GList *client_filters;               /* Filters for client messages */
127
128 static GSourceFuncs event_funcs = {
129   gdk_event_prepare,
130   gdk_event_check,
131   gdk_event_dispatch,
132   NULL
133 };
134
135 static GPollFD event_poll_fd;
136
137 static Window wmspec_check_window = None;
138
139 static XSettingsClient *xsettings_client;
140
141 /*********************************************
142  * Functions for maintaining the event queue *
143  *********************************************/
144
145 void 
146 gdk_events_init (void)
147 {
148   GSource *source;
149   
150   connection_number = ConnectionNumber (gdk_display);
151   GDK_NOTE (MISC,
152             g_message ("connection number: %d", connection_number));
153
154
155   source = g_source_new (&event_funcs, sizeof (GSource));
156   g_source_set_priority (source, GDK_PRIORITY_EVENTS);
157   
158   event_poll_fd.fd = connection_number;
159   event_poll_fd.events = G_IO_IN;
160   
161   g_source_add_poll (source, &event_poll_fd);
162   g_source_set_can_recurse (source, TRUE);
163   g_source_attach (source, NULL);
164
165   gdk_add_client_message_filter (gdk_wm_protocols, 
166                                  gdk_wm_protocols_filter, NULL);
167
168   xsettings_client = xsettings_client_new (gdk_display, DefaultScreen (gdk_display),
169                                            gdk_xsettings_notify_cb,
170                                            gdk_xsettings_watch_cb,
171                                            NULL);
172 }
173
174 /*
175  *--------------------------------------------------------------
176  * gdk_events_pending
177  *
178  *   Returns if events are pending on the queue.
179  *
180  * Arguments:
181  *
182  * Results:
183  *   Returns TRUE if events are pending
184  *
185  * Side effects:
186  *
187  *--------------------------------------------------------------
188  */
189
190 gboolean
191 gdk_events_pending (void)
192 {
193   return (gdk_event_queue_find_first() || XPending (gdk_display));
194 }
195
196 /*
197  *--------------------------------------------------------------
198  * gdk_event_get_graphics_expose
199  *
200  *   Waits for a GraphicsExpose or NoExpose event
201  *
202  * Arguments:
203  *
204  * Results: 
205  *   For GraphicsExpose events, returns a pointer to the event
206  *   converted into a GdkEvent Otherwise, returns NULL.
207  *
208  * Side effects:
209  *
210  *-------------------------------------------------------------- */
211
212 static Bool
213 graphics_expose_predicate (Display  *display,
214                            XEvent   *xevent,
215                            XPointer  arg)
216 {
217   if (xevent->xany.window == GDK_DRAWABLE_XID (arg) &&
218       (xevent->xany.type == GraphicsExpose ||
219        xevent->xany.type == NoExpose))
220     return True;
221   else
222     return False;
223 }
224
225 GdkEvent*
226 gdk_event_get_graphics_expose (GdkWindow *window)
227 {
228   XEvent xevent;
229   GdkEvent *event;
230   
231   g_return_val_if_fail (window != NULL, NULL);
232   
233   XIfEvent (gdk_display, &xevent, graphics_expose_predicate, (XPointer) window);
234   
235   if (xevent.xany.type == GraphicsExpose)
236     {
237       event = gdk_event_new ();
238       
239       if (gdk_event_translate (event, &xevent, TRUE))
240         return event;
241       else
242         gdk_event_free (event);
243     }
244   
245   return NULL;  
246 }
247
248 static gint
249 gdk_event_apply_filters (XEvent *xevent,
250                          GdkEvent *event,
251                          GList *filters)
252 {
253   GList *tmp_list;
254   GdkFilterReturn result;
255   
256   tmp_list = filters;
257   
258   while (tmp_list)
259     {
260       GdkEventFilter *filter = (GdkEventFilter*) tmp_list->data;
261       
262       tmp_list = tmp_list->next;
263       result = filter->function (xevent, event, filter->data);
264       if (result !=  GDK_FILTER_CONTINUE)
265         return result;
266     }
267   
268   return GDK_FILTER_CONTINUE;
269 }
270
271 void 
272 gdk_add_client_message_filter (GdkAtom       message_type,
273                                GdkFilterFunc func,
274                                gpointer      data)
275 {
276   GdkClientFilter *filter = g_new (GdkClientFilter, 1);
277
278   filter->type = message_type;
279   filter->function = func;
280   filter->data = data;
281   
282   client_filters = g_list_prepend (client_filters, filter);
283 }
284
285 static GdkAtom wm_state_atom = 0;
286 static GdkAtom wm_desktop_atom = 0;
287
288 static void
289 gdk_check_wm_state_changed (GdkWindow *window)
290 {  
291   Atom type;
292   gint format;
293   gulong nitems;
294   gulong bytes_after;
295   GdkAtom *atoms = NULL;
296   gulong i;
297   GdkAtom sticky_atom;
298   GdkAtom maxvert_atom;
299   GdkAtom maxhorz_atom;
300   gboolean found_sticky, found_maxvert, found_maxhorz;
301   GdkWindowState old_state;
302   
303   if (GDK_WINDOW_DESTROYED (window))
304     return;
305   
306   if (wm_state_atom == 0)
307     wm_state_atom = gdk_atom_intern ("_NET_WM_STATE", FALSE);
308
309   if (wm_desktop_atom == 0)
310     wm_desktop_atom = gdk_atom_intern ("_NET_WM_DESKTOP", FALSE);
311   
312   XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
313                       wm_state_atom, 0, G_MAXLONG,
314                       False, XA_ATOM, &type, &format, &nitems,
315                       &bytes_after, (guchar **)&atoms);
316
317   if (type != None)
318     {
319
320       sticky_atom = gdk_atom_intern ("_NET_WM_STATE_STICKY", FALSE);
321       maxvert_atom = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_VERT", FALSE);
322       maxhorz_atom = gdk_atom_intern ("_NET_WM_STATE_MAXIMIZED_HORZ", FALSE);    
323
324       found_sticky = FALSE;
325       found_maxvert = FALSE;
326       found_maxhorz = FALSE;
327   
328       i = 0;
329       while (i < nitems)
330         {
331           if (atoms[i] == sticky_atom)
332             found_sticky = TRUE;
333           else if (atoms[i] == maxvert_atom)
334             found_maxvert = TRUE;
335           else if (atoms[i] == maxhorz_atom)
336             found_maxhorz = TRUE;
337
338           ++i;
339         }
340
341       XFree (atoms);
342     }
343   else
344     {
345       found_sticky = FALSE;
346       found_maxvert = FALSE;
347       found_maxhorz = FALSE;
348     }
349
350   /* For found_sticky to remain TRUE, we have to also be on desktop
351    * 0xFFFFFFFF
352    */
353
354   if (found_sticky)
355     {
356       gulong *desktop;
357       
358       XGetWindowProperty (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window),
359                           wm_desktop_atom, 0, G_MAXLONG,
360                           False, XA_CARDINAL, &type, &format, &nitems,
361                           &bytes_after, (guchar **)&desktop);
362
363       if (type != None)
364         {
365           if (*desktop != 0xFFFFFFFF)
366             found_sticky = FALSE;
367           XFree (desktop);
368         }
369     }
370           
371   old_state = gdk_window_get_state (window);
372
373   if (old_state & GDK_WINDOW_STATE_STICKY)
374     {
375       if (!found_sticky)
376         gdk_synthesize_window_state (window,
377                                      GDK_WINDOW_STATE_STICKY,
378                                      0);
379     }
380   else
381     {
382       if (found_sticky)
383         gdk_synthesize_window_state (window,
384                                      0,
385                                      GDK_WINDOW_STATE_STICKY);
386     }
387
388   /* Our "maximized" means both vertical and horizontal; if only one,
389    * we don't expose that via GDK
390    */
391   if (old_state & GDK_WINDOW_STATE_MAXIMIZED)
392     {
393       if (!(found_maxvert && found_maxhorz))
394         gdk_synthesize_window_state (window,
395                                      GDK_WINDOW_STATE_MAXIMIZED,
396                                      0);
397     }
398   else
399     {
400       if (found_maxvert && found_maxhorz)
401         gdk_synthesize_window_state (window,
402                                      0,
403                                      GDK_WINDOW_STATE_MAXIMIZED);
404     }
405 }
406
407 #define HAS_FOCUS(window_impl)                           \
408   ((window_impl)->has_focus || (window_impl)->has_pointer_focus)
409
410 static void
411 generate_focus_event (GdkWindow *window,
412                       gboolean   in)
413 {
414   GdkEvent event;
415   
416   event.type = GDK_FOCUS_CHANGE;
417   event.focus_change.window = window;
418   event.focus_change.send_event = FALSE;
419   event.focus_change.in = in;
420   
421   gdk_event_put (&event);
422 }
423
424 static gint
425 gdk_event_translate (GdkEvent *event,
426                      XEvent   *xevent,
427                      gboolean  return_exposes)
428 {
429   
430   GdkWindow *window;
431   GdkWindowObject *window_private;
432   GdkWindowImplX11 *window_impl = NULL;
433   static XComposeStatus compose;
434   KeySym keysym;
435   int charcount;
436   char buf[16];
437   gint return_val;
438   gint xoffset, yoffset;
439   
440   return_val = FALSE;
441   
442   /* Find the GdkWindow that this event occurred in.
443    * 
444    * We handle events with window=None
445    *  specially - they are generated by XFree86's XInput under
446    *  some circumstances.
447    */
448   
449   if (xevent->xany.window == None)
450     {
451       return_val = _gdk_input_window_none_event (event, xevent);
452       
453       if (return_val >= 0)      /* was handled */
454         return return_val;
455       else
456         return_val = FALSE;
457     }
458   
459   window = gdk_window_lookup (xevent->xany.window);
460   window_private = (GdkWindowObject *) window;
461
462   if (_gdk_moveresize_window &&
463       (xevent->xany.type == MotionNotify ||
464        xevent->xany.type == ButtonRelease))
465     {
466       _gdk_moveresize_handle_event (xevent);
467       gdk_window_unref (window);
468       return FALSE;
469     }
470     
471   if (wmspec_check_window != None &&
472       xevent->xany.window == wmspec_check_window)
473     {
474       if (xevent->type == DestroyNotify)
475         wmspec_check_window = None;
476       
477       /* Eat events on this window unless someone had wrapped
478        * it as a foreign window
479        */
480       if (window == NULL)
481         return FALSE;
482     }
483   
484   /* FIXME: window might be a GdkPixmap!!! */
485   if (window != NULL)
486     {
487       window_impl = GDK_WINDOW_IMPL_X11 (window_private->impl);
488           
489       if (xevent->xany.window != GDK_WINDOW_XID (window))
490         {
491           g_assert (xevent->xany.window == window_impl->focus_window);
492
493           switch (xevent->type)
494             {
495             case KeyPress:
496             case KeyRelease:
497               xevent->xany.window = GDK_WINDOW_XID (window);
498               break;
499             default:
500               return False;
501             }
502         }
503
504       gdk_window_ref (window);
505     }
506
507   event->any.window = window;
508   event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
509   
510   if (window_private && GDK_WINDOW_DESTROYED (window))
511     {
512       if (xevent->type != DestroyNotify)
513         return FALSE;
514     }
515   else
516     {
517       /* Check for filters for this window
518        */
519       GdkFilterReturn result;
520       result = gdk_event_apply_filters (xevent, event,
521                                         window_private
522                                         ?window_private->filters
523                                         :gdk_default_filters);
524       
525       if (result != GDK_FILTER_CONTINUE)
526         {
527           return_val = (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
528           goto done;
529         }
530     }
531
532   /* We do a "manual" conversion of the XEvent to a
533    *  GdkEvent. The structures are mostly the same so
534    *  the conversion is fairly straightforward. We also
535    *  optionally print debugging info regarding events
536    *  received.
537    */
538
539   return_val = TRUE;
540
541   if (window)
542     {
543       _gdk_windowing_window_get_offsets (window, &xoffset, &yoffset);
544     }
545   else
546     {
547       xoffset = 0;
548       yoffset = 0;
549     }
550
551   switch (xevent->type)
552     {
553     case KeyPress:
554       /* Lookup the string corresponding to the given keysym.
555        */
556
557       charcount = XLookupString (&xevent->xkey, buf, 16,
558                                  &keysym, &compose);
559       event->key.keyval = keysym;
560       event->key.hardware_keycode = xevent->xkey.keycode;
561       
562       if (charcount > 0 && buf[charcount-1] == '\0')
563         charcount --;
564       else
565         buf[charcount] = '\0';
566       
567 #ifdef G_ENABLE_DEBUG
568       if (gdk_debug_flags & GDK_DEBUG_EVENTS)
569         {
570           g_message ("key press:\twindow: %ld  key: %12s  %d",
571                      xevent->xkey.window,
572                      event->key.keyval ? XKeysymToString (event->key.keyval) : "(none)",
573                      event->key.keyval);
574           if (charcount > 0)
575             g_message ("\t\tlength: %4d string: \"%s\"",
576                        charcount, buf);
577         }
578 #endif /* G_ENABLE_DEBUG */
579
580       /* bits 13 and 14 in the "state" field are the keyboard group */
581 #define KEYBOARD_GROUP_SHIFT 13
582 #define KEYBOARD_GROUP_MASK ((1 << 13) | (1 << 14))
583       
584       event->key.type = GDK_KEY_PRESS;
585       event->key.window = window;
586       event->key.time = xevent->xkey.time;
587       event->key.state = (GdkModifierType) xevent->xkey.state;
588       event->key.string = g_strdup (buf);
589       event->key.length = charcount;
590
591       event->key.group = (xevent->xkey.state & KEYBOARD_GROUP_MASK) >> KEYBOARD_GROUP_SHIFT;
592       
593       break;
594       
595     case KeyRelease:
596       /* Lookup the string corresponding to the given keysym.
597        */
598
599       /* Emulate detectable auto-repeat by checking to see
600        * if the next event is a key press with the same
601        * keycode and timestamp, and if so, ignoring the event.
602        */
603
604       if (!_gdk_have_xkb_autorepeat && XPending (gdk_display))
605         {
606           XEvent next_event;
607
608           XPeekEvent (gdk_display, &next_event);
609
610           if (next_event.type == KeyPress &&
611               next_event.xkey.keycode == xevent->xkey.keycode &&
612               next_event.xkey.time == xevent->xkey.time)
613             break;
614         }
615       
616       keysym = GDK_VoidSymbol;
617       charcount = XLookupString (&xevent->xkey, buf, 16,
618                                  &keysym, &compose);
619       event->key.keyval = keysym;      
620       
621       GDK_NOTE (EVENTS, 
622                 g_message ("key release:\t\twindow: %ld  key: %12s  %d",
623                            xevent->xkey.window,
624                            XKeysymToString (event->key.keyval),
625                            event->key.keyval));
626       
627       event->key.type = GDK_KEY_RELEASE;
628       event->key.window = window;
629       event->key.time = xevent->xkey.time;
630       event->key.state = (GdkModifierType) xevent->xkey.state;
631       event->key.length = 0;
632       event->key.string = NULL;
633       
634       break;
635       
636     case ButtonPress:
637       GDK_NOTE (EVENTS, 
638                 g_message ("button press:\t\twindow: %ld  x,y: %d %d  button: %d",
639                            xevent->xbutton.window,
640                            xevent->xbutton.x, xevent->xbutton.y,
641                            xevent->xbutton.button));
642       
643       if (window_private &&
644           (window_private->extension_events != 0) &&
645           gdk_input_ignore_core)
646         {
647           return_val = FALSE;
648           break;
649         }
650       
651       /* If we get a ButtonPress event where the button is 4 or 5,
652          it's a Scroll event */
653       if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5)
654         {
655           event->scroll.type = GDK_SCROLL;
656           event->scroll.direction = (xevent->xbutton.button == 4) ? 
657             GDK_SCROLL_UP : GDK_SCROLL_DOWN;
658           event->scroll.window = window;
659           event->scroll.time = xevent->xbutton.x;
660           event->scroll.x = xevent->xbutton.x + xoffset;
661           event->scroll.y = xevent->xbutton.y + yoffset;
662           event->scroll.x_root = (gfloat)xevent->xbutton.x_root;
663           event->scroll.y_root = (gfloat)xevent->xbutton.y_root;
664           event->scroll.state = (GdkModifierType) xevent->xbutton.state;
665           event->scroll.device = gdk_core_pointer;
666         }
667       else
668         {
669           event->button.type = GDK_BUTTON_PRESS;
670           event->button.window = window;
671           event->button.time = xevent->xbutton.time;
672           event->button.x = xevent->xbutton.x + xoffset;
673           event->button.y = xevent->xbutton.y + yoffset;
674           event->button.x_root = (gfloat)xevent->xbutton.x_root;
675           event->button.y_root = (gfloat)xevent->xbutton.y_root;
676           event->button.axes = NULL;
677           event->button.state = (GdkModifierType) xevent->xbutton.state;
678           event->button.button = xevent->xbutton.button;
679           event->button.device = gdk_core_pointer;
680           
681           gdk_event_button_generate (event);
682         }
683
684       break;
685       
686     case ButtonRelease:
687       GDK_NOTE (EVENTS, 
688                 g_message ("button release:\twindow: %ld  x,y: %d %d  button: %d",
689                            xevent->xbutton.window,
690                            xevent->xbutton.x, xevent->xbutton.y,
691                            xevent->xbutton.button));
692       
693       if (window_private &&
694           (window_private->extension_events != 0) &&
695           gdk_input_ignore_core)
696         {
697           return_val = FALSE;
698           break;
699         }
700       
701       /* We treat button presses as scroll wheel events, so ignore the release */
702       if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5)
703         {
704           return_val = FALSE;
705           break;
706         }
707
708       event->button.type = GDK_BUTTON_RELEASE;
709       event->button.window = window;
710       event->button.time = xevent->xbutton.time;
711       event->button.x = xevent->xbutton.x + xoffset;
712       event->button.y = xevent->xbutton.y + yoffset;
713       event->button.x_root = (gfloat)xevent->xbutton.x_root;
714       event->button.y_root = (gfloat)xevent->xbutton.y_root;
715       event->button.axes = NULL;
716       event->button.state = (GdkModifierType) xevent->xbutton.state;
717       event->button.button = xevent->xbutton.button;
718       event->button.device = gdk_core_pointer;
719       
720       break;
721       
722     case MotionNotify:
723       GDK_NOTE (EVENTS,
724                 g_message ("motion notify:\t\twindow: %ld  x,y: %d %d  hint: %s", 
725                            xevent->xmotion.window,
726                            xevent->xmotion.x, xevent->xmotion.y,
727                            (xevent->xmotion.is_hint) ? "true" : "false"));
728       
729       if (window_private &&
730           (window_private->extension_events != 0) &&
731           gdk_input_ignore_core)
732         {
733           return_val = FALSE;
734           break;
735         }
736       
737       event->motion.type = GDK_MOTION_NOTIFY;
738       event->motion.window = window;
739       event->motion.time = xevent->xmotion.time;
740       event->motion.x = xevent->xmotion.x + xoffset;
741       event->motion.y = xevent->xmotion.y + yoffset;
742       event->motion.x_root = (gfloat)xevent->xmotion.x_root;
743       event->motion.y_root = (gfloat)xevent->xmotion.y_root;
744       event->motion.axes = NULL;
745       event->motion.state = (GdkModifierType) xevent->xmotion.state;
746       event->motion.is_hint = xevent->xmotion.is_hint;
747       event->motion.device = gdk_core_pointer;
748       
749       break;
750       
751     case EnterNotify:
752       GDK_NOTE (EVENTS,
753                 g_message ("enter notify:\t\twindow: %ld  detail: %d subwin: %ld",
754                            xevent->xcrossing.window,
755                            xevent->xcrossing.detail,
756                            xevent->xcrossing.subwindow));
757
758       /* Handle focusing (in the case where no window manager is running */
759       if (window &&
760           GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
761           xevent->xcrossing.detail != NotifyInferior &&
762           xevent->xcrossing.focus && !window_impl->has_focus)
763         {
764           gboolean had_focus = HAS_FOCUS (window_impl);
765           
766           window_impl->has_pointer_focus = TRUE;
767
768           if (HAS_FOCUS (window_impl) != had_focus)
769             generate_focus_event (window, TRUE);
770         }
771
772       /* Tell XInput stuff about it if appropriate */
773       if (window_private &&
774           !GDK_WINDOW_DESTROYED (window) &&
775           window_private->extension_events != 0)
776         _gdk_input_enter_event (&xevent->xcrossing, window);
777       
778       event->crossing.type = GDK_ENTER_NOTIFY;
779       event->crossing.window = window;
780       
781       /* If the subwindow field of the XEvent is non-NULL, then
782        *  lookup the corresponding GdkWindow.
783        */
784       if (xevent->xcrossing.subwindow != None)
785         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
786       else
787         event->crossing.subwindow = NULL;
788       
789       event->crossing.time = xevent->xcrossing.time;
790       event->crossing.x = xevent->xcrossing.x + xoffset;
791       event->crossing.y = xevent->xcrossing.y + yoffset;
792       event->crossing.x_root = xevent->xcrossing.x_root;
793       event->crossing.y_root = xevent->xcrossing.y_root;
794       
795       /* Translate the crossing mode into Gdk terms.
796        */
797       switch (xevent->xcrossing.mode)
798         {
799         case NotifyNormal:
800           event->crossing.mode = GDK_CROSSING_NORMAL;
801           break;
802         case NotifyGrab:
803           event->crossing.mode = GDK_CROSSING_GRAB;
804           break;
805         case NotifyUngrab:
806           event->crossing.mode = GDK_CROSSING_UNGRAB;
807           break;
808         };
809       
810       /* Translate the crossing detail into Gdk terms.
811        */
812       switch (xevent->xcrossing.detail)
813         {
814         case NotifyInferior:
815           event->crossing.detail = GDK_NOTIFY_INFERIOR;
816           break;
817         case NotifyAncestor:
818           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
819           break;
820         case NotifyVirtual:
821           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
822           break;
823         case NotifyNonlinear:
824           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
825           break;
826         case NotifyNonlinearVirtual:
827           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
828           break;
829         default:
830           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
831           break;
832         }
833       
834       event->crossing.focus = xevent->xcrossing.focus;
835       event->crossing.state = xevent->xcrossing.state;
836   
837       break;
838       
839     case LeaveNotify:
840       GDK_NOTE (EVENTS, 
841                 g_message ("leave notify:\t\twindow: %ld  detail: %d subwin: %ld",
842                            xevent->xcrossing.window,
843                            xevent->xcrossing.detail, xevent->xcrossing.subwindow));
844       
845       /* Handle focusing (in the case where no window manager is running */
846       if (window &&
847           GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
848           xevent->xcrossing.detail != NotifyInferior &&
849           xevent->xcrossing.focus && !window_impl->has_focus)
850         {
851           gboolean had_focus = HAS_FOCUS (window_impl);
852           
853           window_impl->has_pointer_focus = FALSE;
854
855           if (HAS_FOCUS (window_impl) != had_focus)
856             generate_focus_event (window, FALSE);
857         }
858
859       event->crossing.type = GDK_LEAVE_NOTIFY;
860       event->crossing.window = window;
861       
862       /* If the subwindow field of the XEvent is non-NULL, then
863        *  lookup the corresponding GdkWindow.
864        */
865       if (xevent->xcrossing.subwindow != None)
866         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
867       else
868         event->crossing.subwindow = NULL;
869       
870       event->crossing.time = xevent->xcrossing.time;
871       event->crossing.x = xevent->xcrossing.x + xoffset;
872       event->crossing.y = xevent->xcrossing.y + yoffset;
873       event->crossing.x_root = xevent->xcrossing.x_root;
874       event->crossing.y_root = xevent->xcrossing.y_root;
875       
876       /* Translate the crossing mode into Gdk terms.
877        */
878       switch (xevent->xcrossing.mode)
879         {
880         case NotifyNormal:
881           event->crossing.mode = GDK_CROSSING_NORMAL;
882           break;
883         case NotifyGrab:
884           event->crossing.mode = GDK_CROSSING_GRAB;
885           break;
886         case NotifyUngrab:
887           event->crossing.mode = GDK_CROSSING_UNGRAB;
888           break;
889         };
890       
891       /* Translate the crossing detail into Gdk terms.
892        */
893       switch (xevent->xcrossing.detail)
894         {
895         case NotifyInferior:
896           event->crossing.detail = GDK_NOTIFY_INFERIOR;
897           break;
898         case NotifyAncestor:
899           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
900           break;
901         case NotifyVirtual:
902           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
903           break;
904         case NotifyNonlinear:
905           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
906           break;
907         case NotifyNonlinearVirtual:
908           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
909           break;
910         default:
911           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
912           break;
913         }
914       
915       event->crossing.focus = xevent->xcrossing.focus;
916       event->crossing.state = xevent->xcrossing.state;
917       
918       break;
919       
920       /* We only care about focus events that indicate that _this_
921        * window (not a ancestor or child) got or lost the focus
922        */
923     case FocusIn:
924       GDK_NOTE (EVENTS,
925                 g_message ("focus in:\t\twindow: %ld", xevent->xfocus.window));
926       
927       if (window && GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD)
928         {
929           gboolean had_focus = HAS_FOCUS (window_impl);
930           
931           switch (xevent->xfocus.detail)
932             {
933             case NotifyAncestor:
934             case NotifyNonlinear:
935             case NotifyVirtual:
936             case NotifyNonlinearVirtual:
937               window_impl->has_focus = TRUE;
938               break;
939             case NotifyPointer:
940               window_impl->has_pointer_focus = TRUE;
941               break;
942             case NotifyInferior:
943             case NotifyPointerRoot:
944             case NotifyDetailNone:
945               break;
946             }
947
948           if (HAS_FOCUS (window_impl) != had_focus)
949             generate_focus_event (window, TRUE);
950         }
951       break;
952     case FocusOut:
953       GDK_NOTE (EVENTS,
954                 g_message ("focus out:\t\twindow: %ld", xevent->xfocus.window));
955
956       if (window && GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD)
957         {
958           gboolean had_focus = HAS_FOCUS (window_impl);
959             
960           switch (xevent->xfocus.detail)
961             {
962             case NotifyAncestor:
963             case NotifyNonlinear:
964             case NotifyVirtual:
965             case NotifyNonlinearVirtual:
966               window_impl->has_focus = FALSE;
967               break;
968             case NotifyPointer:
969               window_impl->has_pointer_focus = FALSE;
970             break;
971             case NotifyInferior:
972             case NotifyPointerRoot:
973             case NotifyDetailNone:
974               break;
975             }
976
977           if (HAS_FOCUS (window_impl) != had_focus)
978             generate_focus_event (window, FALSE);
979         }
980       break;
981
982 #if 0      
983           /* gdk_keyboard_grab() causes following events. These events confuse
984            * the XIM focus, so ignore them.
985            */
986           if (xevent->xfocus.mode == NotifyGrab ||
987               xevent->xfocus.mode == NotifyUngrab)
988             break;
989 #endif
990
991     case KeymapNotify:
992       GDK_NOTE (EVENTS,
993                 g_message ("keymap notify"));
994
995       /* Not currently handled */
996       return_val = FALSE;
997       break;
998       
999     case Expose:
1000       GDK_NOTE (EVENTS,
1001                 g_message ("expose:\t\twindow: %ld  %d  x,y: %d %d  w,h: %d %d%s",
1002                            xevent->xexpose.window, xevent->xexpose.count,
1003                            xevent->xexpose.x, xevent->xexpose.y,
1004                            xevent->xexpose.width, xevent->xexpose.height,
1005                            event->any.send_event ? " (send)" : ""));
1006       {
1007         GdkRectangle expose_rect;
1008
1009         expose_rect.x = xevent->xexpose.x + xoffset;
1010         expose_rect.y = xevent->xexpose.y + yoffset;
1011         expose_rect.width = xevent->xexpose.width;
1012         expose_rect.height = xevent->xexpose.height;
1013
1014         if (return_exposes)
1015           {
1016             event->expose.type = GDK_EXPOSE;
1017             event->expose.area = expose_rect;
1018             event->expose.region = gdk_region_rectangle (&expose_rect);
1019             event->expose.window = window;
1020             event->expose.count = xevent->xexpose.count;
1021
1022             return_val = TRUE;
1023           }
1024         else
1025           {
1026             _gdk_window_process_expose (window, xevent->xexpose.serial, &expose_rect);
1027
1028             return_val = FALSE;
1029           }
1030         
1031         return_val = FALSE;
1032       }
1033         
1034       break;
1035       
1036     case GraphicsExpose:
1037       {
1038         GdkRectangle expose_rect;
1039
1040         GDK_NOTE (EVENTS,
1041                   g_message ("graphics expose:\tdrawable: %ld",
1042                              xevent->xgraphicsexpose.drawable));
1043
1044         expose_rect.x = xevent->xgraphicsexpose.x + xoffset;
1045         expose_rect.y = xevent->xgraphicsexpose.y + yoffset;
1046         expose_rect.width = xevent->xgraphicsexpose.width;
1047         expose_rect.height = xevent->xgraphicsexpose.height;
1048             
1049         if (return_exposes)
1050           {
1051             event->expose.type = GDK_EXPOSE;
1052             event->expose.area = expose_rect;
1053             event->expose.region = gdk_region_rectangle (&expose_rect);
1054             event->expose.window = window;
1055             event->expose.count = xevent->xgraphicsexpose.count;
1056
1057             return_val = TRUE;
1058           }
1059         else
1060           {
1061             _gdk_window_process_expose (window, xevent->xgraphicsexpose.serial, &expose_rect);
1062             
1063             return_val = FALSE;
1064           }
1065         
1066       }
1067       break;
1068       
1069     case NoExpose:
1070       GDK_NOTE (EVENTS,
1071                 g_message ("no expose:\t\tdrawable: %ld",
1072                            xevent->xnoexpose.drawable));
1073       
1074       event->no_expose.type = GDK_NO_EXPOSE;
1075       event->no_expose.window = window;
1076       
1077       break;
1078       
1079     case VisibilityNotify:
1080 #ifdef G_ENABLE_DEBUG
1081       if (gdk_debug_flags & GDK_DEBUG_EVENTS)
1082         switch (xevent->xvisibility.state)
1083           {
1084           case VisibilityFullyObscured:
1085             g_message ("visibility notify:\twindow: %ld  none",
1086                        xevent->xvisibility.window);
1087             break;
1088           case VisibilityPartiallyObscured:
1089             g_message ("visibility notify:\twindow: %ld  partial",
1090                        xevent->xvisibility.window);
1091             break;
1092           case VisibilityUnobscured:
1093             g_message ("visibility notify:\twindow: %ld  full",
1094                        xevent->xvisibility.window);
1095             break;
1096           }
1097 #endif /* G_ENABLE_DEBUG */
1098       
1099       event->visibility.type = GDK_VISIBILITY_NOTIFY;
1100       event->visibility.window = window;
1101       
1102       switch (xevent->xvisibility.state)
1103         {
1104         case VisibilityFullyObscured:
1105           event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED;
1106           break;
1107           
1108         case VisibilityPartiallyObscured:
1109           event->visibility.state = GDK_VISIBILITY_PARTIAL;
1110           break;
1111           
1112         case VisibilityUnobscured:
1113           event->visibility.state = GDK_VISIBILITY_UNOBSCURED;
1114           break;
1115         }
1116       
1117       break;
1118       
1119     case CreateNotify:
1120       GDK_NOTE (EVENTS,
1121                 g_message ("create notify:\twindow: %ld  x,y: %d %d     w,h: %d %d  b-w: %d  parent: %ld         ovr: %d",
1122                            xevent->xcreatewindow.window,
1123                            xevent->xcreatewindow.x,
1124                            xevent->xcreatewindow.y,
1125                            xevent->xcreatewindow.width,
1126                            xevent->xcreatewindow.height,
1127                            xevent->xcreatewindow.border_width,
1128                            xevent->xcreatewindow.parent,
1129                            xevent->xcreatewindow.override_redirect));
1130       /* not really handled */
1131       break;
1132       
1133     case DestroyNotify:
1134       GDK_NOTE (EVENTS,
1135                 g_message ("destroy notify:\twindow: %ld",
1136                            xevent->xdestroywindow.window));
1137       
1138       event->any.type = GDK_DESTROY;
1139       event->any.window = window;
1140       
1141       return_val = window_private && !GDK_WINDOW_DESTROYED (window);
1142       
1143       if (window && GDK_WINDOW_XID (window) != GDK_ROOT_WINDOW())
1144         gdk_window_destroy_notify (window);
1145       break;
1146       
1147     case UnmapNotify:
1148       GDK_NOTE (EVENTS,
1149                 g_message ("unmap notify:\t\twindow: %ld",
1150                            xevent->xmap.window));
1151       
1152       event->any.type = GDK_UNMAP;
1153       event->any.window = window;      
1154
1155       /* If we are shown (not withdrawn) and get an unmap, it means we
1156        * were iconified in the X sense. If we are withdrawn, and get
1157        * an unmap, it means we hid the window ourselves, so we
1158        * will have already flipped the iconified bit off.
1159        */
1160       if (window && GDK_WINDOW_IS_MAPPED (window))
1161         gdk_synthesize_window_state (window,
1162                                      0,
1163                                      GDK_WINDOW_STATE_ICONIFIED);
1164       
1165       if (gdk_xgrab_window == window_private)
1166         gdk_xgrab_window = NULL;
1167       
1168       break;
1169       
1170     case MapNotify:
1171       GDK_NOTE (EVENTS,
1172                 g_message ("map notify:\t\twindow: %ld",
1173                            xevent->xmap.window));
1174       
1175       event->any.type = GDK_MAP;
1176       event->any.window = window;
1177
1178       /* Unset iconified if it was set */
1179       if (window && (((GdkWindowObject*)window)->state & GDK_WINDOW_STATE_ICONIFIED))
1180         gdk_synthesize_window_state (window,
1181                                      GDK_WINDOW_STATE_ICONIFIED,
1182                                      0);
1183       
1184       break;
1185       
1186     case ReparentNotify:
1187       GDK_NOTE (EVENTS,
1188                 g_message ("reparent notify:\twindow: %ld  x,y: %d %d  parent: %ld      ovr: %d",
1189                            xevent->xreparent.window,
1190                            xevent->xreparent.x,
1191                            xevent->xreparent.y,
1192                            xevent->xreparent.parent,
1193                            xevent->xreparent.override_redirect));
1194
1195       /* Not currently handled */
1196       return_val = FALSE;
1197       break;
1198       
1199     case ConfigureNotify:
1200       GDK_NOTE (EVENTS,
1201                 g_message ("configure notify:\twindow: %ld  x,y: %d %d  w,h: %d %d  b-w: %d  above: %ld  ovr: %d%s",
1202                            xevent->xconfigure.window,
1203                            xevent->xconfigure.x,
1204                            xevent->xconfigure.y,
1205                            xevent->xconfigure.width,
1206                            xevent->xconfigure.height,
1207                            xevent->xconfigure.border_width,
1208                            xevent->xconfigure.above,
1209                            xevent->xconfigure.override_redirect,
1210                            !window
1211                            ? " (discarding)"
1212                            : GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD
1213                            ? " (discarding child)"
1214                            : ""));
1215       if (window &&
1216           !GDK_WINDOW_DESTROYED (window) &&
1217           (window_private->extension_events != 0))
1218         _gdk_input_configure_event (&xevent->xconfigure, window);
1219
1220       if (!window || GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
1221         return_val = FALSE;
1222       else
1223         {
1224           event->configure.type = GDK_CONFIGURE;
1225           event->configure.window = window;
1226           event->configure.width = xevent->xconfigure.width;
1227           event->configure.height = xevent->xconfigure.height;
1228           
1229           if (!xevent->xconfigure.x &&
1230               !xevent->xconfigure.y &&
1231               !GDK_WINDOW_DESTROYED (window))
1232             {
1233               gint tx = 0;
1234               gint ty = 0;
1235               Window child_window = 0;
1236
1237               gdk_error_trap_push ();
1238               if (XTranslateCoordinates (GDK_DRAWABLE_XDISPLAY (window),
1239                                          GDK_DRAWABLE_XID (window),
1240                                          gdk_root_window,
1241                                          0, 0,
1242                                          &tx, &ty,
1243                                          &child_window))
1244                 {
1245                   if (!gdk_error_trap_pop ())
1246                     {
1247                       event->configure.x = tx;
1248                       event->configure.y = ty;
1249                     }
1250                 }
1251               else
1252                 gdk_error_trap_pop ();
1253             }
1254           else
1255             {
1256               event->configure.x = xevent->xconfigure.x;
1257               event->configure.y = xevent->xconfigure.y;
1258             }
1259           window_private->x = event->configure.x;
1260           window_private->y = event->configure.y;
1261           GDK_WINDOW_IMPL_X11 (window_private->impl)->width = xevent->xconfigure.width;
1262           GDK_WINDOW_IMPL_X11 (window_private->impl)->height = xevent->xconfigure.height;
1263           if (window_private->resize_count >= 1)
1264             {
1265               window_private->resize_count -= 1;
1266
1267               if (window_private->resize_count == 0 &&
1268                   window == _gdk_moveresize_window)
1269                 _gdk_moveresize_configure_done ();
1270             }
1271         }
1272       break;
1273       
1274     case PropertyNotify:
1275       GDK_NOTE (EVENTS,
1276                 gchar *atom = gdk_atom_name (xevent->xproperty.atom);
1277                 g_message ("property notify:\twindow: %ld, atom(%ld): %s%s%s",
1278                            xevent->xproperty.window,
1279                            xevent->xproperty.atom,
1280                            atom ? "\"" : "",
1281                            atom ? atom : "unknown",
1282                            atom ? "\"" : "");
1283                 g_free (atom);
1284                 );
1285       
1286       event->property.type = GDK_PROPERTY_NOTIFY;
1287       event->property.window = window;
1288       event->property.atom = xevent->xproperty.atom;
1289       event->property.time = xevent->xproperty.time;
1290       event->property.state = xevent->xproperty.state;
1291
1292       if (wm_state_atom == 0)
1293         wm_state_atom = gdk_atom_intern ("_NET_WM_STATE", FALSE);
1294
1295       if (wm_desktop_atom == 0)
1296         wm_desktop_atom = gdk_atom_intern ("_NET_WM_DESKTOP", FALSE);
1297       
1298       if (event->property.atom == wm_state_atom ||
1299           event->property.atom == wm_desktop_atom)
1300         {
1301           /* If window state changed, then synthesize those events. */
1302           gdk_check_wm_state_changed (event->property.window);
1303         }
1304       
1305       break;
1306       
1307     case SelectionClear:
1308       GDK_NOTE (EVENTS,
1309                 g_message ("selection clear:\twindow: %ld",
1310                            xevent->xproperty.window));
1311
1312       if (_gdk_selection_filter_clear_event (&xevent->xselectionclear))
1313         {
1314           event->selection.type = GDK_SELECTION_CLEAR;
1315           event->selection.window = window;
1316           event->selection.selection = xevent->xselectionclear.selection;
1317           event->selection.time = xevent->xselectionclear.time;
1318         }
1319       else
1320         return_val = FALSE;
1321           
1322       break;
1323       
1324     case SelectionRequest:
1325       GDK_NOTE (EVENTS,
1326                 g_message ("selection request:\twindow: %ld",
1327                            xevent->xproperty.window));
1328       
1329       event->selection.type = GDK_SELECTION_REQUEST;
1330       event->selection.window = window;
1331       event->selection.selection = xevent->xselectionrequest.selection;
1332       event->selection.target = xevent->xselectionrequest.target;
1333       event->selection.property = xevent->xselectionrequest.property;
1334       event->selection.requestor = xevent->xselectionrequest.requestor;
1335       event->selection.time = xevent->xselectionrequest.time;
1336       
1337       break;
1338       
1339     case SelectionNotify:
1340       GDK_NOTE (EVENTS,
1341                 g_message ("selection notify:\twindow: %ld",
1342                            xevent->xproperty.window));
1343       
1344       
1345       event->selection.type = GDK_SELECTION_NOTIFY;
1346       event->selection.window = window;
1347       event->selection.selection = xevent->xselection.selection;
1348       event->selection.target = xevent->xselection.target;
1349       event->selection.property = xevent->xselection.property;
1350       event->selection.time = xevent->xselection.time;
1351       
1352       break;
1353       
1354     case ColormapNotify:
1355       GDK_NOTE (EVENTS,
1356                 g_message ("colormap notify:\twindow: %ld",
1357                            xevent->xcolormap.window));
1358       
1359       /* Not currently handled */
1360       return_val = FALSE;
1361       break;
1362       
1363     case ClientMessage:
1364       {
1365         GList *tmp_list;
1366         GdkFilterReturn result = GDK_FILTER_CONTINUE;
1367
1368         GDK_NOTE (EVENTS,
1369                   g_message ("client message:\twindow: %ld",
1370                              xevent->xclient.window));
1371         
1372         tmp_list = client_filters;
1373         while (tmp_list)
1374           {
1375             GdkClientFilter *filter = tmp_list->data;
1376             if (filter->type == xevent->xclient.message_type)
1377               {
1378                 result = (*filter->function) (xevent, event, filter->data);
1379                 break;
1380               }
1381             
1382             tmp_list = tmp_list->next;
1383           }
1384
1385         switch (result)
1386           {
1387           case GDK_FILTER_REMOVE:
1388             return_val = FALSE;
1389             break;
1390           case GDK_FILTER_TRANSLATE:
1391             return_val = TRUE;
1392             break;
1393           case GDK_FILTER_CONTINUE:
1394             /* Send unknown ClientMessage's on to Gtk for it to use */
1395             event->client.type = GDK_CLIENT_EVENT;
1396             event->client.window = window;
1397             event->client.message_type = xevent->xclient.message_type;
1398             event->client.data_format = xevent->xclient.format;
1399             memcpy(&event->client.data, &xevent->xclient.data,
1400                    sizeof(event->client.data));
1401           }
1402       }
1403       
1404       break;
1405       
1406     case MappingNotify:
1407       GDK_NOTE (EVENTS,
1408                 g_message ("mapping notify"));
1409       
1410       /* Let XLib know that there is a new keyboard mapping.
1411        */
1412       XRefreshKeyboardMapping (&xevent->xmapping);
1413       ++_gdk_keymap_serial;
1414       return_val = FALSE;
1415       break;
1416
1417 #ifdef HAVE_XKB
1418     case XkbMapNotify:
1419       ++_gdk_keymap_serial;
1420       return_val = FALSE;
1421       break;
1422 #endif
1423       
1424     default:
1425       /* something else - (e.g., a Xinput event) */
1426       
1427       if (window_private &&
1428           !GDK_WINDOW_DESTROYED (window_private) &&
1429           (window_private->extension_events != 0))
1430         return_val = _gdk_input_other_event(event, xevent, window);
1431       else
1432         return_val = FALSE;
1433       
1434       break;
1435     }
1436
1437  done:
1438   if (return_val)
1439     {
1440       if (event->any.window)
1441         gdk_window_ref (event->any.window);
1442       if (((event->any.type == GDK_ENTER_NOTIFY) ||
1443            (event->any.type == GDK_LEAVE_NOTIFY)) &&
1444           (event->crossing.subwindow != NULL))
1445         gdk_window_ref (event->crossing.subwindow);
1446     }
1447   else
1448     {
1449       /* Mark this event as having no resources to be freed */
1450       event->any.window = NULL;
1451       event->any.type = GDK_NOTHING;
1452     }
1453   
1454   if (window)
1455     gdk_window_unref (window);
1456   
1457   return return_val;
1458 }
1459
1460 GdkFilterReturn
1461 gdk_wm_protocols_filter (GdkXEvent *xev,
1462                          GdkEvent  *event,
1463                          gpointer data)
1464 {
1465   XEvent *xevent = (XEvent *)xev;
1466
1467   if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window)
1468     {
1469   /* The delete window request specifies a window
1470    *  to delete. We don't actually destroy the
1471    *  window because "it is only a request". (The
1472    *  window might contain vital data that the
1473    *  program does not want destroyed). Instead
1474    *  the event is passed along to the program,
1475    *  which should then destroy the window.
1476    */
1477       GDK_NOTE (EVENTS,
1478                 g_message ("delete window:\t\twindow: %ld",
1479                            xevent->xclient.window));
1480       
1481       event->any.type = GDK_DELETE;
1482
1483       return GDK_FILTER_TRANSLATE;
1484     }
1485   else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
1486     {
1487       GdkWindow *win = event->any.window;
1488       Window focus_win = GDK_WINDOW_IMPL_X11(((GdkWindowObject *)win)->impl)->focus_window;
1489
1490       XSetInputFocus (GDK_WINDOW_XDISPLAY (win), focus_win,
1491                       RevertToParent, xevent->xclient.data.l[1]);
1492     }
1493   else if ((Atom) xevent->xclient.data.l[0] == gdk_atom_intern ("_NET_WM_PING", FALSE))
1494     {
1495       XEvent xev = *xevent;
1496       
1497       xev.xclient.window = gdk_root_window;
1498       XSendEvent (gdk_display, gdk_root_window, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
1499     }
1500
1501   return GDK_FILTER_REMOVE;
1502 }
1503
1504 #if 0
1505 static Bool
1506 gdk_event_get_type (Display  *display,
1507                     XEvent   *xevent,
1508                     XPointer  arg)
1509 {
1510   GdkEvent event;
1511   GdkPredicate *pred;
1512   
1513   if (gdk_event_translate (&event, xevent, FALSE))
1514     {
1515       pred = (GdkPredicate*) arg;
1516       return (* pred->func) (&event, pred->data);
1517     }
1518   
1519   return FALSE;
1520 }
1521 #endif
1522
1523 void
1524 gdk_events_queue (void)
1525 {
1526   GList *node;
1527   GdkEvent *event;
1528   XEvent xevent;
1529
1530   while (!gdk_event_queue_find_first() && XPending (gdk_display))
1531     {
1532       XNextEvent (gdk_display, &xevent);
1533
1534       switch (xevent.type)
1535         {
1536         case KeyPress:
1537         case KeyRelease:
1538           break;
1539         default:
1540           if (XFilterEvent (&xevent, None))
1541             continue;
1542         }
1543       
1544       event = gdk_event_new ();
1545       
1546       event->any.type = GDK_NOTHING;
1547       event->any.window = NULL;
1548       event->any.send_event = xevent.xany.send_event ? TRUE : FALSE;
1549
1550       ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
1551
1552       gdk_event_queue_append (event);
1553       node = gdk_queued_tail;
1554
1555       if (gdk_event_translate (event, &xevent, FALSE))
1556         {
1557           ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
1558         }
1559       else
1560         {
1561           gdk_event_queue_remove_link (node);
1562           g_list_free_1 (node);
1563           gdk_event_free (event);
1564         }
1565     }
1566 }
1567
1568 static gboolean  
1569 gdk_event_prepare (GSource  *source,
1570                    gint     *timeout)
1571 {
1572   gboolean retval;
1573   
1574   GDK_THREADS_ENTER ();
1575
1576   *timeout = -1;
1577
1578   retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
1579
1580   GDK_THREADS_LEAVE ();
1581
1582   return retval;
1583 }
1584
1585 static gboolean  
1586 gdk_event_check (GSource  *source) 
1587 {
1588   gboolean retval;
1589   
1590   GDK_THREADS_ENTER ();
1591
1592   if (event_poll_fd.revents & G_IO_IN)
1593     retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
1594   else
1595     retval = FALSE;
1596
1597   GDK_THREADS_LEAVE ();
1598
1599   return retval;
1600 }
1601
1602 static gboolean  
1603 gdk_event_dispatch (GSource    *source,
1604                     GSourceFunc callback,
1605                     gpointer    user_data)
1606 {
1607   GdkEvent *event;
1608  
1609   GDK_THREADS_ENTER ();
1610
1611   gdk_events_queue();
1612   event = gdk_event_unqueue();
1613
1614   if (event)
1615     {
1616       if (gdk_event_func)
1617         (*gdk_event_func) (event, gdk_event_data);
1618       
1619       gdk_event_free (event);
1620     }
1621   
1622   GDK_THREADS_LEAVE ();
1623
1624   return TRUE;
1625 }
1626
1627 /* Sends a ClientMessage to all toplevel client windows */
1628 gboolean
1629 gdk_event_send_client_message (GdkEvent *event, guint32 xid)
1630 {
1631   XEvent sev;
1632   
1633   g_return_val_if_fail(event != NULL, FALSE);
1634   
1635   /* Set up our event to send, with the exception of its target window */
1636   sev.xclient.type = ClientMessage;
1637   sev.xclient.display = gdk_display;
1638   sev.xclient.format = event->client.data_format;
1639   sev.xclient.window = xid;
1640   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
1641   sev.xclient.message_type = event->client.message_type;
1642   
1643   return gdk_send_xevent (xid, False, NoEventMask, &sev);
1644 }
1645
1646 /* Sends a ClientMessage to all toplevel client windows */
1647 gboolean
1648 gdk_event_send_client_message_to_all_recurse (XEvent  *xev, 
1649                                               guint32  xid,
1650                                               guint    level)
1651 {
1652   static GdkAtom wm_state_atom = GDK_NONE;
1653   Atom type = None;
1654   int format;
1655   unsigned long nitems, after;
1656   unsigned char *data;
1657   Window *ret_children, ret_root, ret_parent;
1658   unsigned int ret_nchildren;
1659   gint old_warnings = gdk_error_warnings;
1660   gboolean send = FALSE;
1661   gboolean found = FALSE;
1662   int i;
1663
1664   if (!wm_state_atom)
1665     wm_state_atom = gdk_atom_intern ("WM_STATE", FALSE);
1666
1667   gdk_error_warnings = FALSE;
1668   gdk_error_code = 0;
1669   XGetWindowProperty (gdk_display, xid, wm_state_atom, 0, 0, False, AnyPropertyType,
1670                       &type, &format, &nitems, &after, &data);
1671
1672   if (gdk_error_code)
1673     {
1674       gdk_error_warnings = old_warnings;
1675
1676       return FALSE;
1677     }
1678
1679   if (type)
1680     {
1681       send = TRUE;
1682       XFree (data);
1683     }
1684   else
1685     {
1686       /* OK, we're all set, now let's find some windows to send this to */
1687       if (XQueryTree (gdk_display, xid, &ret_root, &ret_parent,
1688                       &ret_children, &ret_nchildren) != True ||
1689           gdk_error_code)
1690         {
1691           gdk_error_warnings = old_warnings;
1692
1693           return FALSE;
1694         }
1695
1696       for(i = 0; i < ret_nchildren; i++)
1697         if (gdk_event_send_client_message_to_all_recurse (xev, ret_children[i], level + 1))
1698           found = TRUE;
1699
1700       XFree (ret_children);
1701     }
1702
1703   if (send || (!found && (level == 1)))
1704     {
1705       xev->xclient.window = xid;
1706       gdk_send_xevent (xid, False, NoEventMask, xev);
1707     }
1708
1709   gdk_error_warnings = old_warnings;
1710
1711   return (send || found);
1712 }
1713
1714 void
1715 gdk_event_send_clientmessage_toall (GdkEvent *event)
1716 {
1717   XEvent sev;
1718   gint old_warnings = gdk_error_warnings;
1719
1720   g_return_if_fail(event != NULL);
1721   
1722   /* Set up our event to send, with the exception of its target window */
1723   sev.xclient.type = ClientMessage;
1724   sev.xclient.display = gdk_display;
1725   sev.xclient.format = event->client.data_format;
1726   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
1727   sev.xclient.message_type = event->client.message_type;
1728
1729   gdk_event_send_client_message_to_all_recurse(&sev, gdk_root_window, 0);
1730
1731   gdk_error_warnings = old_warnings;
1732 }
1733
1734 /*
1735  *--------------------------------------------------------------
1736  * gdk_flush
1737  *
1738  *   Flushes the Xlib output buffer and then waits
1739  *   until all requests have been received and processed
1740  *   by the X server. The only real use for this function
1741  *   is in dealing with XShm.
1742  *
1743  * Arguments:
1744  *
1745  * Results:
1746  *
1747  * Side effects:
1748  *
1749  *--------------------------------------------------------------
1750  */
1751
1752 void
1753 gdk_flush (void)
1754 {
1755   XSync (gdk_display, False);
1756 }
1757
1758 static GdkAtom timestamp_prop_atom = 0;
1759
1760 static Bool
1761 timestamp_predicate (Display *display,
1762                      XEvent  *xevent,
1763                      XPointer arg)
1764 {
1765   Window xwindow = GPOINTER_TO_UINT (arg);
1766
1767   if (xevent->type == PropertyNotify &&
1768       xevent->xproperty.window == xwindow &&
1769       xevent->xproperty.atom == timestamp_prop_atom)
1770     return True;
1771
1772   return False;
1773 }
1774
1775 /**
1776  * gdk_x11_get_server_time:
1777  * @window: a #GdkWindow, used for communication with the server.
1778  *          The window must have GDK_PROPERTY_CHANGE_MASK in its
1779  *          events mask or a hang will result.
1780  * 
1781  * Routine to get the current X server time stamp. 
1782  * 
1783  * Return value: the time stamp.
1784  **/
1785 guint32
1786 gdk_x11_get_server_time (GdkWindow *window)
1787 {
1788   Display *xdisplay;
1789   Window   xwindow;
1790   guchar c = 'a';
1791   XEvent xevent;
1792
1793   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
1794   g_return_val_if_fail (!GDK_WINDOW_DESTROYED (window), 0);
1795
1796   if (!timestamp_prop_atom)
1797     timestamp_prop_atom = gdk_atom_intern ("GDK_TIMESTAMP_PROP", FALSE);
1798
1799   xdisplay = GDK_WINDOW_XDISPLAY (window);
1800   xwindow = GDK_WINDOW_XWINDOW (window);
1801   
1802   XChangeProperty (xdisplay, xwindow,
1803                    timestamp_prop_atom, timestamp_prop_atom,
1804                    8, PropModeReplace, &c, 1);
1805
1806   XIfEvent (xdisplay, &xevent,
1807             timestamp_predicate, GUINT_TO_POINTER(xwindow));
1808
1809   return xevent.xproperty.time;
1810 }
1811
1812
1813 gboolean
1814 gdk_net_wm_supports (GdkAtom property)
1815 {
1816   static GdkAtom wmspec_check_atom = 0;
1817   static GdkAtom wmspec_supported_atom = 0;
1818   static GdkAtom *atoms = NULL;
1819   static gulong n_atoms = 0;
1820   Atom type;
1821   gint format;
1822   gulong nitems;
1823   gulong bytes_after;
1824   Window *xwindow;
1825   gulong i;
1826
1827   if (wmspec_check_window != None)
1828     {
1829       if (atoms == NULL)
1830         return FALSE;
1831
1832       i = 0;
1833       while (i < n_atoms)
1834         {
1835           if (atoms[i] == property)
1836             return TRUE;
1837           
1838           ++i;
1839         }
1840
1841       return FALSE;
1842     }
1843
1844   if (atoms)
1845     XFree (atoms);
1846
1847   atoms = NULL;
1848   n_atoms = 0;
1849   
1850   /* This function is very slow on every call if you are not running a
1851    * spec-supporting WM. For now not optimized, because it isn't in
1852    * any critical code paths, but if you used it somewhere that had to
1853    * be fast you want to avoid "GTK is slow with old WMs" complaints.
1854    * Probably at that point the function should be changed to query
1855    * _NET_SUPPORTING_WM_CHECK only once every 10 seconds or something.
1856    */
1857   
1858   if (wmspec_check_atom == 0)
1859     wmspec_check_atom = gdk_atom_intern ("_NET_SUPPORTING_WM_CHECK", FALSE);
1860       
1861   if (wmspec_supported_atom == 0)
1862     wmspec_supported_atom = gdk_atom_intern ("_NET_SUPPORTED", FALSE);
1863   
1864   XGetWindowProperty (gdk_display, gdk_root_window,
1865                       wmspec_check_atom, 0, G_MAXLONG,
1866                       False, XA_WINDOW, &type, &format, &nitems,
1867                       &bytes_after, (guchar **)&xwindow);
1868
1869   if (type != XA_WINDOW)
1870     return FALSE;
1871
1872   gdk_error_trap_push ();
1873
1874   /* Find out if this WM goes away, so we can reset everything. */
1875   XSelectInput (gdk_display, *xwindow,
1876                 StructureNotifyMask);
1877   
1878   gdk_flush ();
1879   
1880   if (gdk_error_trap_pop ())
1881     {
1882       XFree (xwindow);
1883       return FALSE;
1884     }
1885
1886   XGetWindowProperty (gdk_display, gdk_root_window,
1887                       wmspec_supported_atom, 0, G_MAXLONG,
1888                       False, XA_ATOM, &type, &format, &n_atoms,
1889                       &bytes_after, (guchar **)&atoms);
1890   
1891   if (type != XA_ATOM)
1892     return FALSE;
1893   
1894   wmspec_check_window = *xwindow;
1895   XFree (xwindow);
1896   
1897   /* since wmspec_check_window != None this isn't infinite. ;-) */
1898   return gdk_net_wm_supports (property);
1899 }
1900
1901 static struct
1902 {
1903   const char *xsettings_name;
1904   const char *gdk_name;
1905 } settings_map[] = {
1906   { "Net/DoubleClickTime", "double-click-timeout" },
1907   { "Net/DragThreshold", "drag-threshold" }
1908 };
1909
1910 static void
1911 gdk_xsettings_notify_cb (const char       *name,
1912                          XSettingsAction   action,
1913                          XSettingsSetting *setting,
1914                          void             *data)
1915 {
1916   GdkEvent new_event;
1917   int i;
1918
1919   new_event.type = GDK_SETTING;
1920   new_event.setting.window = NULL;
1921   new_event.setting.send_event = FALSE;
1922   new_event.setting.name = NULL;
1923
1924   for (i = 0; i < G_N_ELEMENTS (settings_map) ; i++)
1925     if (strcmp (settings_map[i].xsettings_name, name) == 0)
1926       {
1927         new_event.setting.name = g_strdup (settings_map[i].gdk_name);
1928         break;
1929       }
1930
1931   if (!new_event.setting.name)
1932     return;
1933   
1934   switch (action)
1935     {
1936     case XSETTINGS_ACTION_NEW:
1937       new_event.setting.action = GDK_SETTING_ACTION_NEW;
1938       break;
1939     case XSETTINGS_ACTION_CHANGED:
1940       new_event.setting.action = GDK_SETTING_ACTION_CHANGED;
1941       break;
1942     case XSETTINGS_ACTION_DELETED:
1943       new_event.setting.action = GDK_SETTING_ACTION_DELETED;
1944       break;
1945     }
1946
1947   gdk_event_put (&new_event);
1948 }
1949
1950 static gboolean
1951 check_transform (const gchar *xsettings_name,
1952                  GType        src_type,
1953                  GType        dest_type)
1954 {
1955   if (!g_value_type_transformable (src_type, dest_type))
1956     {
1957       g_warning ("Cannot tranform xsetting %s of type %s to type %s\n",
1958                  xsettings_name,
1959                  g_type_name (src_type),
1960                  g_type_name (dest_type));
1961       return FALSE;
1962     }
1963   else
1964     return TRUE;
1965 }
1966
1967 gboolean
1968 gdk_setting_get (const gchar *name,
1969                  GValue      *value)
1970 {
1971   const char *xsettings_name = NULL;
1972   XSettingsResult result;
1973   XSettingsSetting *setting;
1974   gboolean success = FALSE;
1975   gint i;
1976
1977   for (i = 0; i < G_N_ELEMENTS (settings_map) ; i++)
1978     if (strcmp (settings_map[i].gdk_name, name) == 0)
1979       {
1980         xsettings_name = settings_map[i].xsettings_name;
1981         break;
1982       }
1983
1984   if (!xsettings_name)
1985     return FALSE;
1986
1987   result = xsettings_client_get_setting (xsettings_client, xsettings_name, &setting);
1988   if (result != XSETTINGS_SUCCESS)
1989     return FALSE;
1990
1991   switch (setting->type)
1992     {
1993     case XSETTINGS_TYPE_INT:
1994       if (check_transform (xsettings_name, G_TYPE_INT, G_VALUE_TYPE (value)))
1995         {
1996           g_value_set_int (value, setting->data.v_int);
1997           success = TRUE;
1998         }
1999       break;
2000     case XSETTINGS_TYPE_STRING:
2001       if (check_transform (xsettings_name, G_TYPE_STRING, G_VALUE_TYPE (value)))
2002         {
2003           g_value_set_string (value, setting->data.v_string);
2004           success = TRUE;
2005         }
2006       break;
2007     case XSETTINGS_TYPE_COLOR:
2008       if (!check_transform (xsettings_name, GDK_TYPE_COLOR, G_VALUE_TYPE (value)))
2009         {
2010           GdkColor color;
2011           
2012           color.pixel = 0;
2013           color.red = setting->data.v_color.red;
2014           color.green = setting->data.v_color.green;
2015           color.blue = setting->data.v_color.blue;
2016           
2017           g_value_set_boxed (value, &color);
2018           
2019           success = TRUE;
2020         }
2021       break;
2022     }
2023
2024   xsettings_setting_free (setting);
2025
2026   return success;
2027 }
2028
2029 GdkFilterReturn 
2030 gdk_xsettings_client_event_filter (GdkXEvent *xevent,
2031                                    GdkEvent  *event,
2032                                    gpointer   data)
2033 {
2034   if (xsettings_client_process_event (xsettings_client, (XEvent *)xevent))
2035     return GDK_FILTER_REMOVE;
2036   else
2037     return GDK_FILTER_CONTINUE;
2038 }
2039
2040 static void 
2041 gdk_xsettings_watch_cb (Window window,
2042                         Bool   is_start,
2043                         long   mask,
2044                         void  *cb_data)
2045 {
2046   GdkWindow *gdkwin;
2047
2048   gdkwin = gdk_window_lookup (window);
2049   if (is_start)
2050     gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, NULL);
2051   else
2052     gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, NULL);
2053 }