]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkevents-x11.c
Add a direction-changed signal, and gdk_keymap_get_current_direction().
[~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       switch (xevent->xbutton.button)
654         {
655         case 4: /* up */
656         case 5: /* down */
657         case 6: /* left */
658         case 7: /* right */
659           event->scroll.type = GDK_SCROLL;
660
661           if (xevent->xbutton.button == 4)
662             event->scroll.direction = GDK_SCROLL_UP;
663           else if (xevent->xbutton.button == 5)
664             event->scroll.direction = GDK_SCROLL_DOWN;
665           else if (xevent->xbutton.button == 6)
666             event->scroll.direction = GDK_SCROLL_LEFT;
667           else
668             event->scroll.direction = GDK_SCROLL_RIGHT;
669
670           event->scroll.window = window;
671           event->scroll.time = xevent->xbutton.x;
672           event->scroll.x = xevent->xbutton.x + xoffset;
673           event->scroll.y = xevent->xbutton.y + yoffset;
674           event->scroll.x_root = (gfloat)xevent->xbutton.x_root;
675           event->scroll.y_root = (gfloat)xevent->xbutton.y_root;
676           event->scroll.state = (GdkModifierType) xevent->xbutton.state;
677           event->scroll.device = gdk_core_pointer;
678           break;
679           
680         default:
681           event->button.type = GDK_BUTTON_PRESS;
682           event->button.window = window;
683           event->button.time = xevent->xbutton.time;
684           event->button.x = xevent->xbutton.x + xoffset;
685           event->button.y = xevent->xbutton.y + yoffset;
686           event->button.x_root = (gfloat)xevent->xbutton.x_root;
687           event->button.y_root = (gfloat)xevent->xbutton.y_root;
688           event->button.axes = NULL;
689           event->button.state = (GdkModifierType) xevent->xbutton.state;
690           event->button.button = xevent->xbutton.button;
691           event->button.device = gdk_core_pointer;
692           
693           gdk_event_button_generate (event);
694           break;
695         }
696
697       break;
698       
699     case ButtonRelease:
700       GDK_NOTE (EVENTS, 
701                 g_message ("button release:\twindow: %ld  x,y: %d %d  button: %d",
702                            xevent->xbutton.window,
703                            xevent->xbutton.x, xevent->xbutton.y,
704                            xevent->xbutton.button));
705       
706       if (window_private &&
707           (window_private->extension_events != 0) &&
708           gdk_input_ignore_core)
709         {
710           return_val = FALSE;
711           break;
712         }
713       
714       /* We treat button presses as scroll wheel events, so ignore the release */
715       if (xevent->xbutton.button == 4 || xevent->xbutton.button == 5 ||
716           xevent->xbutton.button == 6 || xevent->xbutton.button ==7)
717         {
718           return_val = FALSE;
719           break;
720         }
721
722       event->button.type = GDK_BUTTON_RELEASE;
723       event->button.window = window;
724       event->button.time = xevent->xbutton.time;
725       event->button.x = xevent->xbutton.x + xoffset;
726       event->button.y = xevent->xbutton.y + yoffset;
727       event->button.x_root = (gfloat)xevent->xbutton.x_root;
728       event->button.y_root = (gfloat)xevent->xbutton.y_root;
729       event->button.axes = NULL;
730       event->button.state = (GdkModifierType) xevent->xbutton.state;
731       event->button.button = xevent->xbutton.button;
732       event->button.device = gdk_core_pointer;
733       
734       break;
735       
736     case MotionNotify:
737       GDK_NOTE (EVENTS,
738                 g_message ("motion notify:\t\twindow: %ld  x,y: %d %d  hint: %s", 
739                            xevent->xmotion.window,
740                            xevent->xmotion.x, xevent->xmotion.y,
741                            (xevent->xmotion.is_hint) ? "true" : "false"));
742       
743       if (window_private &&
744           (window_private->extension_events != 0) &&
745           gdk_input_ignore_core)
746         {
747           return_val = FALSE;
748           break;
749         }
750       
751       event->motion.type = GDK_MOTION_NOTIFY;
752       event->motion.window = window;
753       event->motion.time = xevent->xmotion.time;
754       event->motion.x = xevent->xmotion.x + xoffset;
755       event->motion.y = xevent->xmotion.y + yoffset;
756       event->motion.x_root = (gfloat)xevent->xmotion.x_root;
757       event->motion.y_root = (gfloat)xevent->xmotion.y_root;
758       event->motion.axes = NULL;
759       event->motion.state = (GdkModifierType) xevent->xmotion.state;
760       event->motion.is_hint = xevent->xmotion.is_hint;
761       event->motion.device = gdk_core_pointer;
762       
763       break;
764       
765     case EnterNotify:
766       GDK_NOTE (EVENTS,
767                 g_message ("enter notify:\t\twindow: %ld  detail: %d subwin: %ld",
768                            xevent->xcrossing.window,
769                            xevent->xcrossing.detail,
770                            xevent->xcrossing.subwindow));
771
772       /* Handle focusing (in the case where no window manager is running */
773       if (window &&
774           GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
775           xevent->xcrossing.detail != NotifyInferior &&
776           xevent->xcrossing.focus && !window_impl->has_focus)
777         {
778           gboolean had_focus = HAS_FOCUS (window_impl);
779           
780           window_impl->has_pointer_focus = TRUE;
781
782           if (HAS_FOCUS (window_impl) != had_focus)
783             generate_focus_event (window, TRUE);
784         }
785
786       /* Tell XInput stuff about it if appropriate */
787       if (window_private &&
788           !GDK_WINDOW_DESTROYED (window) &&
789           window_private->extension_events != 0)
790         _gdk_input_enter_event (&xevent->xcrossing, window);
791       
792       event->crossing.type = GDK_ENTER_NOTIFY;
793       event->crossing.window = window;
794       
795       /* If the subwindow field of the XEvent is non-NULL, then
796        *  lookup the corresponding GdkWindow.
797        */
798       if (xevent->xcrossing.subwindow != None)
799         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
800       else
801         event->crossing.subwindow = NULL;
802       
803       event->crossing.time = xevent->xcrossing.time;
804       event->crossing.x = xevent->xcrossing.x + xoffset;
805       event->crossing.y = xevent->xcrossing.y + yoffset;
806       event->crossing.x_root = xevent->xcrossing.x_root;
807       event->crossing.y_root = xevent->xcrossing.y_root;
808       
809       /* Translate the crossing mode into Gdk terms.
810        */
811       switch (xevent->xcrossing.mode)
812         {
813         case NotifyNormal:
814           event->crossing.mode = GDK_CROSSING_NORMAL;
815           break;
816         case NotifyGrab:
817           event->crossing.mode = GDK_CROSSING_GRAB;
818           break;
819         case NotifyUngrab:
820           event->crossing.mode = GDK_CROSSING_UNGRAB;
821           break;
822         };
823       
824       /* Translate the crossing detail into Gdk terms.
825        */
826       switch (xevent->xcrossing.detail)
827         {
828         case NotifyInferior:
829           event->crossing.detail = GDK_NOTIFY_INFERIOR;
830           break;
831         case NotifyAncestor:
832           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
833           break;
834         case NotifyVirtual:
835           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
836           break;
837         case NotifyNonlinear:
838           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
839           break;
840         case NotifyNonlinearVirtual:
841           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
842           break;
843         default:
844           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
845           break;
846         }
847       
848       event->crossing.focus = xevent->xcrossing.focus;
849       event->crossing.state = xevent->xcrossing.state;
850   
851       break;
852       
853     case LeaveNotify:
854       GDK_NOTE (EVENTS, 
855                 g_message ("leave notify:\t\twindow: %ld  detail: %d subwin: %ld",
856                            xevent->xcrossing.window,
857                            xevent->xcrossing.detail, xevent->xcrossing.subwindow));
858       
859       /* Handle focusing (in the case where no window manager is running */
860       if (window &&
861           GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD &&
862           xevent->xcrossing.detail != NotifyInferior &&
863           xevent->xcrossing.focus && !window_impl->has_focus)
864         {
865           gboolean had_focus = HAS_FOCUS (window_impl);
866           
867           window_impl->has_pointer_focus = FALSE;
868
869           if (HAS_FOCUS (window_impl) != had_focus)
870             generate_focus_event (window, FALSE);
871         }
872
873       event->crossing.type = GDK_LEAVE_NOTIFY;
874       event->crossing.window = window;
875       
876       /* If the subwindow field of the XEvent is non-NULL, then
877        *  lookup the corresponding GdkWindow.
878        */
879       if (xevent->xcrossing.subwindow != None)
880         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
881       else
882         event->crossing.subwindow = NULL;
883       
884       event->crossing.time = xevent->xcrossing.time;
885       event->crossing.x = xevent->xcrossing.x + xoffset;
886       event->crossing.y = xevent->xcrossing.y + yoffset;
887       event->crossing.x_root = xevent->xcrossing.x_root;
888       event->crossing.y_root = xevent->xcrossing.y_root;
889       
890       /* Translate the crossing mode into Gdk terms.
891        */
892       switch (xevent->xcrossing.mode)
893         {
894         case NotifyNormal:
895           event->crossing.mode = GDK_CROSSING_NORMAL;
896           break;
897         case NotifyGrab:
898           event->crossing.mode = GDK_CROSSING_GRAB;
899           break;
900         case NotifyUngrab:
901           event->crossing.mode = GDK_CROSSING_UNGRAB;
902           break;
903         };
904       
905       /* Translate the crossing detail into Gdk terms.
906        */
907       switch (xevent->xcrossing.detail)
908         {
909         case NotifyInferior:
910           event->crossing.detail = GDK_NOTIFY_INFERIOR;
911           break;
912         case NotifyAncestor:
913           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
914           break;
915         case NotifyVirtual:
916           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
917           break;
918         case NotifyNonlinear:
919           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
920           break;
921         case NotifyNonlinearVirtual:
922           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
923           break;
924         default:
925           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
926           break;
927         }
928       
929       event->crossing.focus = xevent->xcrossing.focus;
930       event->crossing.state = xevent->xcrossing.state;
931       
932       break;
933       
934       /* We only care about focus events that indicate that _this_
935        * window (not a ancestor or child) got or lost the focus
936        */
937     case FocusIn:
938       GDK_NOTE (EVENTS,
939                 g_message ("focus in:\t\twindow: %ld", xevent->xfocus.window));
940       
941       if (window && GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD)
942         {
943           gboolean had_focus = HAS_FOCUS (window_impl);
944           
945           switch (xevent->xfocus.detail)
946             {
947             case NotifyAncestor:
948             case NotifyNonlinear:
949             case NotifyVirtual:
950             case NotifyNonlinearVirtual:
951               window_impl->has_focus = TRUE;
952               break;
953             case NotifyPointer:
954               window_impl->has_pointer_focus = TRUE;
955               break;
956             case NotifyInferior:
957             case NotifyPointerRoot:
958             case NotifyDetailNone:
959               break;
960             }
961
962           if (HAS_FOCUS (window_impl) != had_focus)
963             generate_focus_event (window, TRUE);
964         }
965       break;
966     case FocusOut:
967       GDK_NOTE (EVENTS,
968                 g_message ("focus out:\t\twindow: %ld", xevent->xfocus.window));
969
970       if (window && GDK_WINDOW_TYPE (window) != GDK_WINDOW_CHILD)
971         {
972           gboolean had_focus = HAS_FOCUS (window_impl);
973             
974           switch (xevent->xfocus.detail)
975             {
976             case NotifyAncestor:
977             case NotifyNonlinear:
978             case NotifyVirtual:
979             case NotifyNonlinearVirtual:
980               window_impl->has_focus = FALSE;
981               break;
982             case NotifyPointer:
983               window_impl->has_pointer_focus = FALSE;
984             break;
985             case NotifyInferior:
986             case NotifyPointerRoot:
987             case NotifyDetailNone:
988               break;
989             }
990
991           if (HAS_FOCUS (window_impl) != had_focus)
992             generate_focus_event (window, FALSE);
993         }
994       break;
995
996 #if 0      
997           /* gdk_keyboard_grab() causes following events. These events confuse
998            * the XIM focus, so ignore them.
999            */
1000           if (xevent->xfocus.mode == NotifyGrab ||
1001               xevent->xfocus.mode == NotifyUngrab)
1002             break;
1003 #endif
1004
1005     case KeymapNotify:
1006       GDK_NOTE (EVENTS,
1007                 g_message ("keymap notify"));
1008
1009       /* Not currently handled */
1010       return_val = FALSE;
1011       break;
1012       
1013     case Expose:
1014       GDK_NOTE (EVENTS,
1015                 g_message ("expose:\t\twindow: %ld  %d  x,y: %d %d  w,h: %d %d%s",
1016                            xevent->xexpose.window, xevent->xexpose.count,
1017                            xevent->xexpose.x, xevent->xexpose.y,
1018                            xevent->xexpose.width, xevent->xexpose.height,
1019                            event->any.send_event ? " (send)" : ""));
1020       {
1021         GdkRectangle expose_rect;
1022
1023         expose_rect.x = xevent->xexpose.x + xoffset;
1024         expose_rect.y = xevent->xexpose.y + yoffset;
1025         expose_rect.width = xevent->xexpose.width;
1026         expose_rect.height = xevent->xexpose.height;
1027
1028         if (return_exposes)
1029           {
1030             event->expose.type = GDK_EXPOSE;
1031             event->expose.area = expose_rect;
1032             event->expose.region = gdk_region_rectangle (&expose_rect);
1033             event->expose.window = window;
1034             event->expose.count = xevent->xexpose.count;
1035
1036             return_val = TRUE;
1037           }
1038         else
1039           {
1040             _gdk_window_process_expose (window, xevent->xexpose.serial, &expose_rect);
1041
1042             return_val = FALSE;
1043           }
1044         
1045         return_val = FALSE;
1046       }
1047         
1048       break;
1049       
1050     case GraphicsExpose:
1051       {
1052         GdkRectangle expose_rect;
1053
1054         GDK_NOTE (EVENTS,
1055                   g_message ("graphics expose:\tdrawable: %ld",
1056                              xevent->xgraphicsexpose.drawable));
1057
1058         expose_rect.x = xevent->xgraphicsexpose.x + xoffset;
1059         expose_rect.y = xevent->xgraphicsexpose.y + yoffset;
1060         expose_rect.width = xevent->xgraphicsexpose.width;
1061         expose_rect.height = xevent->xgraphicsexpose.height;
1062             
1063         if (return_exposes)
1064           {
1065             event->expose.type = GDK_EXPOSE;
1066             event->expose.area = expose_rect;
1067             event->expose.region = gdk_region_rectangle (&expose_rect);
1068             event->expose.window = window;
1069             event->expose.count = xevent->xgraphicsexpose.count;
1070
1071             return_val = TRUE;
1072           }
1073         else
1074           {
1075             _gdk_window_process_expose (window, xevent->xgraphicsexpose.serial, &expose_rect);
1076             
1077             return_val = FALSE;
1078           }
1079         
1080       }
1081       break;
1082       
1083     case NoExpose:
1084       GDK_NOTE (EVENTS,
1085                 g_message ("no expose:\t\tdrawable: %ld",
1086                            xevent->xnoexpose.drawable));
1087       
1088       event->no_expose.type = GDK_NO_EXPOSE;
1089       event->no_expose.window = window;
1090       
1091       break;
1092       
1093     case VisibilityNotify:
1094 #ifdef G_ENABLE_DEBUG
1095       if (gdk_debug_flags & GDK_DEBUG_EVENTS)
1096         switch (xevent->xvisibility.state)
1097           {
1098           case VisibilityFullyObscured:
1099             g_message ("visibility notify:\twindow: %ld  none",
1100                        xevent->xvisibility.window);
1101             break;
1102           case VisibilityPartiallyObscured:
1103             g_message ("visibility notify:\twindow: %ld  partial",
1104                        xevent->xvisibility.window);
1105             break;
1106           case VisibilityUnobscured:
1107             g_message ("visibility notify:\twindow: %ld  full",
1108                        xevent->xvisibility.window);
1109             break;
1110           }
1111 #endif /* G_ENABLE_DEBUG */
1112       
1113       event->visibility.type = GDK_VISIBILITY_NOTIFY;
1114       event->visibility.window = window;
1115       
1116       switch (xevent->xvisibility.state)
1117         {
1118         case VisibilityFullyObscured:
1119           event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED;
1120           break;
1121           
1122         case VisibilityPartiallyObscured:
1123           event->visibility.state = GDK_VISIBILITY_PARTIAL;
1124           break;
1125           
1126         case VisibilityUnobscured:
1127           event->visibility.state = GDK_VISIBILITY_UNOBSCURED;
1128           break;
1129         }
1130       
1131       break;
1132       
1133     case CreateNotify:
1134       GDK_NOTE (EVENTS,
1135                 g_message ("create notify:\twindow: %ld  x,y: %d %d     w,h: %d %d  b-w: %d  parent: %ld         ovr: %d",
1136                            xevent->xcreatewindow.window,
1137                            xevent->xcreatewindow.x,
1138                            xevent->xcreatewindow.y,
1139                            xevent->xcreatewindow.width,
1140                            xevent->xcreatewindow.height,
1141                            xevent->xcreatewindow.border_width,
1142                            xevent->xcreatewindow.parent,
1143                            xevent->xcreatewindow.override_redirect));
1144       /* not really handled */
1145       break;
1146       
1147     case DestroyNotify:
1148       GDK_NOTE (EVENTS,
1149                 g_message ("destroy notify:\twindow: %ld",
1150                            xevent->xdestroywindow.window));
1151       
1152       event->any.type = GDK_DESTROY;
1153       event->any.window = window;
1154       
1155       return_val = window_private && !GDK_WINDOW_DESTROYED (window);
1156       
1157       if (window && GDK_WINDOW_XID (window) != GDK_ROOT_WINDOW())
1158         gdk_window_destroy_notify (window);
1159       break;
1160       
1161     case UnmapNotify:
1162       GDK_NOTE (EVENTS,
1163                 g_message ("unmap notify:\t\twindow: %ld",
1164                            xevent->xmap.window));
1165       
1166       event->any.type = GDK_UNMAP;
1167       event->any.window = window;      
1168
1169       /* If we are shown (not withdrawn) and get an unmap, it means we
1170        * were iconified in the X sense. If we are withdrawn, and get
1171        * an unmap, it means we hid the window ourselves, so we
1172        * will have already flipped the iconified bit off.
1173        */
1174       if (window && GDK_WINDOW_IS_MAPPED (window))
1175         gdk_synthesize_window_state (window,
1176                                      0,
1177                                      GDK_WINDOW_STATE_ICONIFIED);
1178       
1179       if (gdk_xgrab_window == window_private)
1180         gdk_xgrab_window = NULL;
1181       
1182       break;
1183       
1184     case MapNotify:
1185       GDK_NOTE (EVENTS,
1186                 g_message ("map notify:\t\twindow: %ld",
1187                            xevent->xmap.window));
1188       
1189       event->any.type = GDK_MAP;
1190       event->any.window = window;
1191
1192       /* Unset iconified if it was set */
1193       if (window && (((GdkWindowObject*)window)->state & GDK_WINDOW_STATE_ICONIFIED))
1194         gdk_synthesize_window_state (window,
1195                                      GDK_WINDOW_STATE_ICONIFIED,
1196                                      0);
1197       
1198       break;
1199       
1200     case ReparentNotify:
1201       GDK_NOTE (EVENTS,
1202                 g_message ("reparent notify:\twindow: %ld  x,y: %d %d  parent: %ld      ovr: %d",
1203                            xevent->xreparent.window,
1204                            xevent->xreparent.x,
1205                            xevent->xreparent.y,
1206                            xevent->xreparent.parent,
1207                            xevent->xreparent.override_redirect));
1208
1209       /* Not currently handled */
1210       return_val = FALSE;
1211       break;
1212       
1213     case ConfigureNotify:
1214       GDK_NOTE (EVENTS,
1215                 g_message ("configure notify:\twindow: %ld  x,y: %d %d  w,h: %d %d  b-w: %d  above: %ld  ovr: %d%s",
1216                            xevent->xconfigure.window,
1217                            xevent->xconfigure.x,
1218                            xevent->xconfigure.y,
1219                            xevent->xconfigure.width,
1220                            xevent->xconfigure.height,
1221                            xevent->xconfigure.border_width,
1222                            xevent->xconfigure.above,
1223                            xevent->xconfigure.override_redirect,
1224                            !window
1225                            ? " (discarding)"
1226                            : GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD
1227                            ? " (discarding child)"
1228                            : ""));
1229       if (window &&
1230           !GDK_WINDOW_DESTROYED (window) &&
1231           (window_private->extension_events != 0))
1232         _gdk_input_configure_event (&xevent->xconfigure, window);
1233
1234       if (!window || GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
1235         return_val = FALSE;
1236       else
1237         {
1238           event->configure.type = GDK_CONFIGURE;
1239           event->configure.window = window;
1240           event->configure.width = xevent->xconfigure.width;
1241           event->configure.height = xevent->xconfigure.height;
1242           
1243           if (!xevent->xconfigure.x &&
1244               !xevent->xconfigure.y &&
1245               !GDK_WINDOW_DESTROYED (window))
1246             {
1247               gint tx = 0;
1248               gint ty = 0;
1249               Window child_window = 0;
1250
1251               gdk_error_trap_push ();
1252               if (XTranslateCoordinates (GDK_DRAWABLE_XDISPLAY (window),
1253                                          GDK_DRAWABLE_XID (window),
1254                                          gdk_root_window,
1255                                          0, 0,
1256                                          &tx, &ty,
1257                                          &child_window))
1258                 {
1259                   if (!gdk_error_trap_pop ())
1260                     {
1261                       event->configure.x = tx;
1262                       event->configure.y = ty;
1263                     }
1264                 }
1265               else
1266                 gdk_error_trap_pop ();
1267             }
1268           else
1269             {
1270               event->configure.x = xevent->xconfigure.x;
1271               event->configure.y = xevent->xconfigure.y;
1272             }
1273           window_private->x = event->configure.x;
1274           window_private->y = event->configure.y;
1275           GDK_WINDOW_IMPL_X11 (window_private->impl)->width = xevent->xconfigure.width;
1276           GDK_WINDOW_IMPL_X11 (window_private->impl)->height = xevent->xconfigure.height;
1277           if (window_private->resize_count >= 1)
1278             {
1279               window_private->resize_count -= 1;
1280
1281               if (window_private->resize_count == 0 &&
1282                   window == _gdk_moveresize_window)
1283                 _gdk_moveresize_configure_done ();
1284             }
1285         }
1286       break;
1287       
1288     case PropertyNotify:
1289       GDK_NOTE (EVENTS,
1290                 gchar *atom = gdk_atom_name (xevent->xproperty.atom);
1291                 g_message ("property notify:\twindow: %ld, atom(%ld): %s%s%s",
1292                            xevent->xproperty.window,
1293                            xevent->xproperty.atom,
1294                            atom ? "\"" : "",
1295                            atom ? atom : "unknown",
1296                            atom ? "\"" : "");
1297                 g_free (atom);
1298                 );
1299       
1300       event->property.type = GDK_PROPERTY_NOTIFY;
1301       event->property.window = window;
1302       event->property.atom = xevent->xproperty.atom;
1303       event->property.time = xevent->xproperty.time;
1304       event->property.state = xevent->xproperty.state;
1305
1306       if (wm_state_atom == 0)
1307         wm_state_atom = gdk_atom_intern ("_NET_WM_STATE", FALSE);
1308
1309       if (wm_desktop_atom == 0)
1310         wm_desktop_atom = gdk_atom_intern ("_NET_WM_DESKTOP", FALSE);
1311       
1312       if (event->property.atom == wm_state_atom ||
1313           event->property.atom == wm_desktop_atom)
1314         {
1315           /* If window state changed, then synthesize those events. */
1316           gdk_check_wm_state_changed (event->property.window);
1317         }
1318       
1319       break;
1320       
1321     case SelectionClear:
1322       GDK_NOTE (EVENTS,
1323                 g_message ("selection clear:\twindow: %ld",
1324                            xevent->xproperty.window));
1325
1326       if (_gdk_selection_filter_clear_event (&xevent->xselectionclear))
1327         {
1328           event->selection.type = GDK_SELECTION_CLEAR;
1329           event->selection.window = window;
1330           event->selection.selection = xevent->xselectionclear.selection;
1331           event->selection.time = xevent->xselectionclear.time;
1332         }
1333       else
1334         return_val = FALSE;
1335           
1336       break;
1337       
1338     case SelectionRequest:
1339       GDK_NOTE (EVENTS,
1340                 g_message ("selection request:\twindow: %ld",
1341                            xevent->xproperty.window));
1342       
1343       event->selection.type = GDK_SELECTION_REQUEST;
1344       event->selection.window = window;
1345       event->selection.selection = xevent->xselectionrequest.selection;
1346       event->selection.target = xevent->xselectionrequest.target;
1347       event->selection.property = xevent->xselectionrequest.property;
1348       event->selection.requestor = xevent->xselectionrequest.requestor;
1349       event->selection.time = xevent->xselectionrequest.time;
1350       
1351       break;
1352       
1353     case SelectionNotify:
1354       GDK_NOTE (EVENTS,
1355                 g_message ("selection notify:\twindow: %ld",
1356                            xevent->xproperty.window));
1357       
1358       
1359       event->selection.type = GDK_SELECTION_NOTIFY;
1360       event->selection.window = window;
1361       event->selection.selection = xevent->xselection.selection;
1362       event->selection.target = xevent->xselection.target;
1363       event->selection.property = xevent->xselection.property;
1364       event->selection.time = xevent->xselection.time;
1365       
1366       break;
1367       
1368     case ColormapNotify:
1369       GDK_NOTE (EVENTS,
1370                 g_message ("colormap notify:\twindow: %ld",
1371                            xevent->xcolormap.window));
1372       
1373       /* Not currently handled */
1374       return_val = FALSE;
1375       break;
1376       
1377     case ClientMessage:
1378       {
1379         GList *tmp_list;
1380         GdkFilterReturn result = GDK_FILTER_CONTINUE;
1381
1382         GDK_NOTE (EVENTS,
1383                   g_message ("client message:\twindow: %ld",
1384                              xevent->xclient.window));
1385         
1386         tmp_list = client_filters;
1387         while (tmp_list)
1388           {
1389             GdkClientFilter *filter = tmp_list->data;
1390             if (filter->type == xevent->xclient.message_type)
1391               {
1392                 result = (*filter->function) (xevent, event, filter->data);
1393                 break;
1394               }
1395             
1396             tmp_list = tmp_list->next;
1397           }
1398
1399         switch (result)
1400           {
1401           case GDK_FILTER_REMOVE:
1402             return_val = FALSE;
1403             break;
1404           case GDK_FILTER_TRANSLATE:
1405             return_val = TRUE;
1406             break;
1407           case GDK_FILTER_CONTINUE:
1408             /* Send unknown ClientMessage's on to Gtk for it to use */
1409             event->client.type = GDK_CLIENT_EVENT;
1410             event->client.window = window;
1411             event->client.message_type = xevent->xclient.message_type;
1412             event->client.data_format = xevent->xclient.format;
1413             memcpy(&event->client.data, &xevent->xclient.data,
1414                    sizeof(event->client.data));
1415           }
1416       }
1417       
1418       break;
1419       
1420     case MappingNotify:
1421       GDK_NOTE (EVENTS,
1422                 g_message ("mapping notify"));
1423       
1424       /* Let XLib know that there is a new keyboard mapping.
1425        */
1426       XRefreshKeyboardMapping (&xevent->xmapping);
1427       ++_gdk_keymap_serial;
1428       return_val = FALSE;
1429       break;
1430
1431     default:
1432 #ifdef HAVE_XKB
1433       if (xevent->type == _gdk_xkb_event_type)
1434         {
1435           XkbEvent *xkb_event = (XkbEvent *)xevent;
1436
1437           switch (xkb_event->any.xkb_type)
1438             {
1439             case XkbMapNotify:
1440               ++_gdk_keymap_serial;
1441               return_val = FALSE;
1442               break;
1443               
1444             case XkbStateNotify:
1445               _gdk_keymap_state_changed ();
1446               break;
1447             }
1448         }
1449       else
1450 #endif
1451         {
1452           /* something else - (e.g., a Xinput event) */
1453           
1454           if (window_private &&
1455               !GDK_WINDOW_DESTROYED (window_private) &&
1456               (window_private->extension_events != 0))
1457             return_val = _gdk_input_other_event(event, xevent, window);
1458           else
1459             return_val = FALSE;
1460           
1461           break;
1462         }
1463     }
1464
1465  done:
1466   if (return_val)
1467     {
1468       if (event->any.window)
1469         gdk_window_ref (event->any.window);
1470       if (((event->any.type == GDK_ENTER_NOTIFY) ||
1471            (event->any.type == GDK_LEAVE_NOTIFY)) &&
1472           (event->crossing.subwindow != NULL))
1473         gdk_window_ref (event->crossing.subwindow);
1474     }
1475   else
1476     {
1477       /* Mark this event as having no resources to be freed */
1478       event->any.window = NULL;
1479       event->any.type = GDK_NOTHING;
1480     }
1481   
1482   if (window)
1483     gdk_window_unref (window);
1484   
1485   return return_val;
1486 }
1487
1488 GdkFilterReturn
1489 gdk_wm_protocols_filter (GdkXEvent *xev,
1490                          GdkEvent  *event,
1491                          gpointer data)
1492 {
1493   XEvent *xevent = (XEvent *)xev;
1494
1495   if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window)
1496     {
1497   /* The delete window request specifies a window
1498    *  to delete. We don't actually destroy the
1499    *  window because "it is only a request". (The
1500    *  window might contain vital data that the
1501    *  program does not want destroyed). Instead
1502    *  the event is passed along to the program,
1503    *  which should then destroy the window.
1504    */
1505       GDK_NOTE (EVENTS,
1506                 g_message ("delete window:\t\twindow: %ld",
1507                            xevent->xclient.window));
1508       
1509       event->any.type = GDK_DELETE;
1510
1511       return GDK_FILTER_TRANSLATE;
1512     }
1513   else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
1514     {
1515       GdkWindow *win = event->any.window;
1516       Window focus_win = GDK_WINDOW_IMPL_X11(((GdkWindowObject *)win)->impl)->focus_window;
1517
1518       /* There is no way of knowing reliably whether we are viewable so we need
1519        * to trap errors so we don't cause a BadMatch.
1520        */
1521       gdk_error_trap_push ();
1522       XSetInputFocus (GDK_WINDOW_XDISPLAY (win),
1523                       focus_win,
1524                       RevertToParent,
1525                       xevent->xclient.data.l[1]);
1526       XSync (GDK_WINDOW_XDISPLAY (win), False);
1527       gdk_error_trap_pop ();
1528     }
1529   else if ((Atom) xevent->xclient.data.l[0] == gdk_atom_intern ("_NET_WM_PING", FALSE))
1530     {
1531       XEvent xev = *xevent;
1532       
1533       xev.xclient.window = gdk_root_window;
1534       XSendEvent (gdk_display, gdk_root_window, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
1535     }
1536
1537   return GDK_FILTER_REMOVE;
1538 }
1539
1540 #if 0
1541 static Bool
1542 gdk_event_get_type (Display  *display,
1543                     XEvent   *xevent,
1544                     XPointer  arg)
1545 {
1546   GdkEvent event;
1547   GdkPredicate *pred;
1548   
1549   if (gdk_event_translate (&event, xevent, FALSE))
1550     {
1551       pred = (GdkPredicate*) arg;
1552       return (* pred->func) (&event, pred->data);
1553     }
1554   
1555   return FALSE;
1556 }
1557 #endif
1558
1559 void
1560 gdk_events_queue (void)
1561 {
1562   GList *node;
1563   GdkEvent *event;
1564   XEvent xevent;
1565
1566   while (!gdk_event_queue_find_first() && XPending (gdk_display))
1567     {
1568       XNextEvent (gdk_display, &xevent);
1569
1570       switch (xevent.type)
1571         {
1572         case KeyPress:
1573         case KeyRelease:
1574           break;
1575         default:
1576           if (XFilterEvent (&xevent, None))
1577             continue;
1578         }
1579       
1580       event = gdk_event_new ();
1581       
1582       event->any.type = GDK_NOTHING;
1583       event->any.window = NULL;
1584       event->any.send_event = xevent.xany.send_event ? TRUE : FALSE;
1585
1586       ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
1587
1588       gdk_event_queue_append (event);
1589       node = gdk_queued_tail;
1590
1591       if (gdk_event_translate (event, &xevent, FALSE))
1592         {
1593           ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
1594         }
1595       else
1596         {
1597           gdk_event_queue_remove_link (node);
1598           g_list_free_1 (node);
1599           gdk_event_free (event);
1600         }
1601     }
1602 }
1603
1604 static gboolean  
1605 gdk_event_prepare (GSource  *source,
1606                    gint     *timeout)
1607 {
1608   gboolean retval;
1609   
1610   GDK_THREADS_ENTER ();
1611
1612   *timeout = -1;
1613
1614   retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
1615
1616   GDK_THREADS_LEAVE ();
1617
1618   return retval;
1619 }
1620
1621 static gboolean  
1622 gdk_event_check (GSource  *source) 
1623 {
1624   gboolean retval;
1625   
1626   GDK_THREADS_ENTER ();
1627
1628   if (event_poll_fd.revents & G_IO_IN)
1629     retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
1630   else
1631     retval = FALSE;
1632
1633   GDK_THREADS_LEAVE ();
1634
1635   return retval;
1636 }
1637
1638 static gboolean  
1639 gdk_event_dispatch (GSource    *source,
1640                     GSourceFunc callback,
1641                     gpointer    user_data)
1642 {
1643   GdkEvent *event;
1644  
1645   GDK_THREADS_ENTER ();
1646
1647   gdk_events_queue();
1648   event = gdk_event_unqueue();
1649
1650   if (event)
1651     {
1652       if (gdk_event_func)
1653         (*gdk_event_func) (event, gdk_event_data);
1654       
1655       gdk_event_free (event);
1656     }
1657   
1658   GDK_THREADS_LEAVE ();
1659
1660   return TRUE;
1661 }
1662
1663 /* Sends a ClientMessage to all toplevel client windows */
1664 gboolean
1665 gdk_event_send_client_message (GdkEvent *event, guint32 xid)
1666 {
1667   XEvent sev;
1668   
1669   g_return_val_if_fail(event != NULL, FALSE);
1670   
1671   /* Set up our event to send, with the exception of its target window */
1672   sev.xclient.type = ClientMessage;
1673   sev.xclient.display = gdk_display;
1674   sev.xclient.format = event->client.data_format;
1675   sev.xclient.window = xid;
1676   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
1677   sev.xclient.message_type = event->client.message_type;
1678   
1679   return gdk_send_xevent (xid, False, NoEventMask, &sev);
1680 }
1681
1682 /* Sends a ClientMessage to all toplevel client windows */
1683 gboolean
1684 gdk_event_send_client_message_to_all_recurse (XEvent  *xev, 
1685                                               guint32  xid,
1686                                               guint    level)
1687 {
1688   static GdkAtom wm_state_atom = GDK_NONE;
1689   Atom type = None;
1690   int format;
1691   unsigned long nitems, after;
1692   unsigned char *data;
1693   Window *ret_children, ret_root, ret_parent;
1694   unsigned int ret_nchildren;
1695   gint old_warnings = gdk_error_warnings;
1696   gboolean send = FALSE;
1697   gboolean found = FALSE;
1698   int i;
1699
1700   if (!wm_state_atom)
1701     wm_state_atom = gdk_atom_intern ("WM_STATE", FALSE);
1702
1703   gdk_error_warnings = FALSE;
1704   gdk_error_code = 0;
1705   XGetWindowProperty (gdk_display, xid, wm_state_atom, 0, 0, False, AnyPropertyType,
1706                       &type, &format, &nitems, &after, &data);
1707
1708   if (gdk_error_code)
1709     {
1710       gdk_error_warnings = old_warnings;
1711
1712       return FALSE;
1713     }
1714
1715   if (type)
1716     {
1717       send = TRUE;
1718       XFree (data);
1719     }
1720   else
1721     {
1722       /* OK, we're all set, now let's find some windows to send this to */
1723       if (XQueryTree (gdk_display, xid, &ret_root, &ret_parent,
1724                       &ret_children, &ret_nchildren) != True ||
1725           gdk_error_code)
1726         {
1727           gdk_error_warnings = old_warnings;
1728
1729           return FALSE;
1730         }
1731
1732       for(i = 0; i < ret_nchildren; i++)
1733         if (gdk_event_send_client_message_to_all_recurse (xev, ret_children[i], level + 1))
1734           found = TRUE;
1735
1736       XFree (ret_children);
1737     }
1738
1739   if (send || (!found && (level == 1)))
1740     {
1741       xev->xclient.window = xid;
1742       gdk_send_xevent (xid, False, NoEventMask, xev);
1743     }
1744
1745   gdk_error_warnings = old_warnings;
1746
1747   return (send || found);
1748 }
1749
1750 void
1751 gdk_event_send_clientmessage_toall (GdkEvent *event)
1752 {
1753   XEvent sev;
1754   gint old_warnings = gdk_error_warnings;
1755
1756   g_return_if_fail(event != NULL);
1757   
1758   /* Set up our event to send, with the exception of its target window */
1759   sev.xclient.type = ClientMessage;
1760   sev.xclient.display = gdk_display;
1761   sev.xclient.format = event->client.data_format;
1762   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
1763   sev.xclient.message_type = event->client.message_type;
1764
1765   gdk_event_send_client_message_to_all_recurse(&sev, gdk_root_window, 0);
1766
1767   gdk_error_warnings = old_warnings;
1768 }
1769
1770 /*
1771  *--------------------------------------------------------------
1772  * gdk_flush
1773  *
1774  *   Flushes the Xlib output buffer and then waits
1775  *   until all requests have been received and processed
1776  *   by the X server. The only real use for this function
1777  *   is in dealing with XShm.
1778  *
1779  * Arguments:
1780  *
1781  * Results:
1782  *
1783  * Side effects:
1784  *
1785  *--------------------------------------------------------------
1786  */
1787
1788 void
1789 gdk_flush (void)
1790 {
1791   XSync (gdk_display, False);
1792 }
1793
1794 static GdkAtom timestamp_prop_atom = 0;
1795
1796 static Bool
1797 timestamp_predicate (Display *display,
1798                      XEvent  *xevent,
1799                      XPointer arg)
1800 {
1801   Window xwindow = GPOINTER_TO_UINT (arg);
1802
1803   if (xevent->type == PropertyNotify &&
1804       xevent->xproperty.window == xwindow &&
1805       xevent->xproperty.atom == timestamp_prop_atom)
1806     return True;
1807
1808   return False;
1809 }
1810
1811 /**
1812  * gdk_x11_get_server_time:
1813  * @window: a #GdkWindow, used for communication with the server.
1814  *          The window must have GDK_PROPERTY_CHANGE_MASK in its
1815  *          events mask or a hang will result.
1816  * 
1817  * Routine to get the current X server time stamp. 
1818  * 
1819  * Return value: the time stamp.
1820  **/
1821 guint32
1822 gdk_x11_get_server_time (GdkWindow *window)
1823 {
1824   Display *xdisplay;
1825   Window   xwindow;
1826   guchar c = 'a';
1827   XEvent xevent;
1828
1829   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
1830   g_return_val_if_fail (!GDK_WINDOW_DESTROYED (window), 0);
1831
1832   if (!timestamp_prop_atom)
1833     timestamp_prop_atom = gdk_atom_intern ("GDK_TIMESTAMP_PROP", FALSE);
1834
1835   xdisplay = GDK_WINDOW_XDISPLAY (window);
1836   xwindow = GDK_WINDOW_XWINDOW (window);
1837   
1838   XChangeProperty (xdisplay, xwindow,
1839                    timestamp_prop_atom, timestamp_prop_atom,
1840                    8, PropModeReplace, &c, 1);
1841
1842   XIfEvent (xdisplay, &xevent,
1843             timestamp_predicate, GUINT_TO_POINTER(xwindow));
1844
1845   return xevent.xproperty.time;
1846 }
1847
1848
1849 gboolean
1850 gdk_net_wm_supports (GdkAtom property)
1851 {
1852   static GdkAtom wmspec_check_atom = 0;
1853   static GdkAtom wmspec_supported_atom = 0;
1854   static GdkAtom *atoms = NULL;
1855   static gulong n_atoms = 0;
1856   Atom type;
1857   gint format;
1858   gulong nitems;
1859   gulong bytes_after;
1860   Window *xwindow;
1861   gulong i;
1862
1863   if (wmspec_check_window != None)
1864     {
1865       if (atoms == NULL)
1866         return FALSE;
1867
1868       i = 0;
1869       while (i < n_atoms)
1870         {
1871           if (atoms[i] == property)
1872             return TRUE;
1873           
1874           ++i;
1875         }
1876
1877       return FALSE;
1878     }
1879
1880   if (atoms)
1881     XFree (atoms);
1882
1883   atoms = NULL;
1884   n_atoms = 0;
1885   
1886   /* This function is very slow on every call if you are not running a
1887    * spec-supporting WM. For now not optimized, because it isn't in
1888    * any critical code paths, but if you used it somewhere that had to
1889    * be fast you want to avoid "GTK is slow with old WMs" complaints.
1890    * Probably at that point the function should be changed to query
1891    * _NET_SUPPORTING_WM_CHECK only once every 10 seconds or something.
1892    */
1893   
1894   if (wmspec_check_atom == 0)
1895     wmspec_check_atom = gdk_atom_intern ("_NET_SUPPORTING_WM_CHECK", FALSE);
1896       
1897   if (wmspec_supported_atom == 0)
1898     wmspec_supported_atom = gdk_atom_intern ("_NET_SUPPORTED", FALSE);
1899   
1900   XGetWindowProperty (gdk_display, gdk_root_window,
1901                       wmspec_check_atom, 0, G_MAXLONG,
1902                       False, XA_WINDOW, &type, &format, &nitems,
1903                       &bytes_after, (guchar **)&xwindow);
1904
1905   if (type != XA_WINDOW)
1906     return FALSE;
1907
1908   gdk_error_trap_push ();
1909
1910   /* Find out if this WM goes away, so we can reset everything. */
1911   XSelectInput (gdk_display, *xwindow,
1912                 StructureNotifyMask);
1913   
1914   gdk_flush ();
1915   
1916   if (gdk_error_trap_pop ())
1917     {
1918       XFree (xwindow);
1919       return FALSE;
1920     }
1921
1922   XGetWindowProperty (gdk_display, gdk_root_window,
1923                       wmspec_supported_atom, 0, G_MAXLONG,
1924                       False, XA_ATOM, &type, &format, &n_atoms,
1925                       &bytes_after, (guchar **)&atoms);
1926   
1927   if (type != XA_ATOM)
1928     return FALSE;
1929   
1930   wmspec_check_window = *xwindow;
1931   XFree (xwindow);
1932   
1933   /* since wmspec_check_window != None this isn't infinite. ;-) */
1934   return gdk_net_wm_supports (property);
1935 }
1936
1937 static struct
1938 {
1939   const char *xsettings_name;
1940   const char *gdk_name;
1941 } settings_map[] = {
1942   { "Net/DoubleClickTime", "gtk-double-click-timeout" },
1943   { "Net/DragThreshold", "gtk-drag-threshold" },
1944   { "Gtk/ColorPalette", "gtk-color-palette" },
1945   { "Gtk/ToolbarStyle", "gtk-toolbar-style" },
1946   { "Gtk/ToolbarIconSize", "gtk-toolbar-icon-size" },
1947   { "Net/CursorBlink", "gtk-cursor-blink" },
1948   { "Net/CursorBlinkTime", "gtk-cursor-blink-time" }
1949 };
1950
1951 static void
1952 gdk_xsettings_notify_cb (const char       *name,
1953                          XSettingsAction   action,
1954                          XSettingsSetting *setting,
1955                          void             *data)
1956 {
1957   GdkEvent new_event;
1958   int i;
1959
1960   new_event.type = GDK_SETTING;
1961   new_event.setting.window = NULL;
1962   new_event.setting.send_event = FALSE;
1963   new_event.setting.name = NULL;
1964
1965   for (i = 0; i < G_N_ELEMENTS (settings_map) ; i++)
1966     if (strcmp (settings_map[i].xsettings_name, name) == 0)
1967       {
1968         new_event.setting.name = g_strdup (settings_map[i].gdk_name);
1969         break;
1970       }
1971
1972   if (!new_event.setting.name)
1973     return;
1974   
1975   switch (action)
1976     {
1977     case XSETTINGS_ACTION_NEW:
1978       new_event.setting.action = GDK_SETTING_ACTION_NEW;
1979       break;
1980     case XSETTINGS_ACTION_CHANGED:
1981       new_event.setting.action = GDK_SETTING_ACTION_CHANGED;
1982       break;
1983     case XSETTINGS_ACTION_DELETED:
1984       new_event.setting.action = GDK_SETTING_ACTION_DELETED;
1985       break;
1986     }
1987
1988   gdk_event_put (&new_event);
1989 }
1990
1991 static gboolean
1992 check_transform (const gchar *xsettings_name,
1993                  GType        src_type,
1994                  GType        dest_type)
1995 {
1996   if (!g_value_type_transformable (src_type, dest_type))
1997     {
1998       g_warning ("Cannot tranform xsetting %s of type %s to type %s\n",
1999                  xsettings_name,
2000                  g_type_name (src_type),
2001                  g_type_name (dest_type));
2002       return FALSE;
2003     }
2004   else
2005     return TRUE;
2006 }
2007
2008 gboolean
2009 gdk_setting_get (const gchar *name,
2010                  GValue      *value)
2011 {
2012   const char *xsettings_name = NULL;
2013   XSettingsResult result;
2014   XSettingsSetting *setting;
2015   gboolean success = FALSE;
2016   gint i;
2017   GValue tmp_val = { 0, };
2018
2019   for (i = 0; i < G_N_ELEMENTS (settings_map) ; i++)
2020     if (strcmp (settings_map[i].gdk_name, name) == 0)
2021       {
2022         xsettings_name = settings_map[i].xsettings_name;
2023         break;
2024       }
2025
2026   if (!xsettings_name)
2027     return FALSE;
2028
2029   result = xsettings_client_get_setting (xsettings_client, xsettings_name, &setting);
2030   if (result != XSETTINGS_SUCCESS)
2031     return FALSE;
2032
2033   switch (setting->type)
2034     {
2035     case XSETTINGS_TYPE_INT:
2036       if (check_transform (xsettings_name, G_TYPE_INT, G_VALUE_TYPE (value)))
2037         {
2038           g_value_init (&tmp_val, G_TYPE_INT);
2039           g_value_set_int (&tmp_val, setting->data.v_int);
2040           g_value_transform (&tmp_val, value);
2041
2042           success = TRUE;
2043         }
2044       break;
2045     case XSETTINGS_TYPE_STRING:
2046       if (check_transform (xsettings_name, G_TYPE_STRING, G_VALUE_TYPE (value)))
2047         {
2048           g_value_init (&tmp_val, G_TYPE_STRING);
2049           g_value_set_string (&tmp_val, setting->data.v_string);
2050           g_value_transform (&tmp_val, value);
2051
2052           success = TRUE;
2053         }
2054       break;
2055     case XSETTINGS_TYPE_COLOR:
2056       if (!check_transform (xsettings_name, GDK_TYPE_COLOR, G_VALUE_TYPE (value)))
2057         {
2058           GdkColor color;
2059           
2060           g_value_init (&tmp_val, GDK_TYPE_COLOR);
2061
2062           color.pixel = 0;
2063           color.red = setting->data.v_color.red;
2064           color.green = setting->data.v_color.green;
2065           color.blue = setting->data.v_color.blue;
2066           
2067           g_value_set_boxed (&tmp_val, &color);
2068           
2069           g_value_transform (&tmp_val, value);
2070           
2071           success = TRUE;
2072         }
2073       break;
2074     }
2075   
2076   g_value_unset (&tmp_val);
2077
2078   xsettings_setting_free (setting);
2079
2080   return success;
2081 }
2082
2083 GdkFilterReturn 
2084 gdk_xsettings_client_event_filter (GdkXEvent *xevent,
2085                                    GdkEvent  *event,
2086                                    gpointer   data)
2087 {
2088   if (xsettings_client_process_event (xsettings_client, (XEvent *)xevent))
2089     return GDK_FILTER_REMOVE;
2090   else
2091     return GDK_FILTER_CONTINUE;
2092 }
2093
2094 static void 
2095 gdk_xsettings_watch_cb (Window window,
2096                         Bool   is_start,
2097                         long   mask,
2098                         void  *cb_data)
2099 {
2100   GdkWindow *gdkwin;
2101
2102   gdkwin = gdk_window_lookup (window);
2103   if (is_start)
2104     gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, NULL);
2105   else
2106     gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, NULL);
2107 }