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