]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkevents-x11.c
Ignore releases for buttons 6, 7
[~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 #ifdef HAVE_XKB
1432     case XkbMapNotify:
1433       ++_gdk_keymap_serial;
1434       return_val = FALSE;
1435       break;
1436 #endif
1437       
1438     default:
1439       /* something else - (e.g., a Xinput event) */
1440       
1441       if (window_private &&
1442           !GDK_WINDOW_DESTROYED (window_private) &&
1443           (window_private->extension_events != 0))
1444         return_val = _gdk_input_other_event(event, xevent, window);
1445       else
1446         return_val = FALSE;
1447       
1448       break;
1449     }
1450
1451  done:
1452   if (return_val)
1453     {
1454       if (event->any.window)
1455         gdk_window_ref (event->any.window);
1456       if (((event->any.type == GDK_ENTER_NOTIFY) ||
1457            (event->any.type == GDK_LEAVE_NOTIFY)) &&
1458           (event->crossing.subwindow != NULL))
1459         gdk_window_ref (event->crossing.subwindow);
1460     }
1461   else
1462     {
1463       /* Mark this event as having no resources to be freed */
1464       event->any.window = NULL;
1465       event->any.type = GDK_NOTHING;
1466     }
1467   
1468   if (window)
1469     gdk_window_unref (window);
1470   
1471   return return_val;
1472 }
1473
1474 GdkFilterReturn
1475 gdk_wm_protocols_filter (GdkXEvent *xev,
1476                          GdkEvent  *event,
1477                          gpointer data)
1478 {
1479   XEvent *xevent = (XEvent *)xev;
1480
1481   if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window)
1482     {
1483   /* The delete window request specifies a window
1484    *  to delete. We don't actually destroy the
1485    *  window because "it is only a request". (The
1486    *  window might contain vital data that the
1487    *  program does not want destroyed). Instead
1488    *  the event is passed along to the program,
1489    *  which should then destroy the window.
1490    */
1491       GDK_NOTE (EVENTS,
1492                 g_message ("delete window:\t\twindow: %ld",
1493                            xevent->xclient.window));
1494       
1495       event->any.type = GDK_DELETE;
1496
1497       return GDK_FILTER_TRANSLATE;
1498     }
1499   else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
1500     {
1501       GdkWindow *win = event->any.window;
1502       Window focus_win = GDK_WINDOW_IMPL_X11(((GdkWindowObject *)win)->impl)->focus_window;
1503
1504       /* There is no way of knowing reliably whether we are viewable so we need
1505        * to trap errors so we don't cause a BadMatch.
1506        */
1507       gdk_error_trap_push ();
1508       XSetInputFocus (GDK_WINDOW_XDISPLAY (win),
1509                       focus_win,
1510                       RevertToParent,
1511                       xevent->xclient.data.l[1]);
1512       XSync (GDK_WINDOW_XDISPLAY (win), False);
1513       gdk_error_trap_pop ();
1514     }
1515   else if ((Atom) xevent->xclient.data.l[0] == gdk_atom_intern ("_NET_WM_PING", FALSE))
1516     {
1517       XEvent xev = *xevent;
1518       
1519       xev.xclient.window = gdk_root_window;
1520       XSendEvent (gdk_display, gdk_root_window, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
1521     }
1522
1523   return GDK_FILTER_REMOVE;
1524 }
1525
1526 #if 0
1527 static Bool
1528 gdk_event_get_type (Display  *display,
1529                     XEvent   *xevent,
1530                     XPointer  arg)
1531 {
1532   GdkEvent event;
1533   GdkPredicate *pred;
1534   
1535   if (gdk_event_translate (&event, xevent, FALSE))
1536     {
1537       pred = (GdkPredicate*) arg;
1538       return (* pred->func) (&event, pred->data);
1539     }
1540   
1541   return FALSE;
1542 }
1543 #endif
1544
1545 void
1546 gdk_events_queue (void)
1547 {
1548   GList *node;
1549   GdkEvent *event;
1550   XEvent xevent;
1551
1552   while (!gdk_event_queue_find_first() && XPending (gdk_display))
1553     {
1554       XNextEvent (gdk_display, &xevent);
1555
1556       switch (xevent.type)
1557         {
1558         case KeyPress:
1559         case KeyRelease:
1560           break;
1561         default:
1562           if (XFilterEvent (&xevent, None))
1563             continue;
1564         }
1565       
1566       event = gdk_event_new ();
1567       
1568       event->any.type = GDK_NOTHING;
1569       event->any.window = NULL;
1570       event->any.send_event = xevent.xany.send_event ? TRUE : FALSE;
1571
1572       ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
1573
1574       gdk_event_queue_append (event);
1575       node = gdk_queued_tail;
1576
1577       if (gdk_event_translate (event, &xevent, FALSE))
1578         {
1579           ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
1580         }
1581       else
1582         {
1583           gdk_event_queue_remove_link (node);
1584           g_list_free_1 (node);
1585           gdk_event_free (event);
1586         }
1587     }
1588 }
1589
1590 static gboolean  
1591 gdk_event_prepare (GSource  *source,
1592                    gint     *timeout)
1593 {
1594   gboolean retval;
1595   
1596   GDK_THREADS_ENTER ();
1597
1598   *timeout = -1;
1599
1600   retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
1601
1602   GDK_THREADS_LEAVE ();
1603
1604   return retval;
1605 }
1606
1607 static gboolean  
1608 gdk_event_check (GSource  *source) 
1609 {
1610   gboolean retval;
1611   
1612   GDK_THREADS_ENTER ();
1613
1614   if (event_poll_fd.revents & G_IO_IN)
1615     retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
1616   else
1617     retval = FALSE;
1618
1619   GDK_THREADS_LEAVE ();
1620
1621   return retval;
1622 }
1623
1624 static gboolean  
1625 gdk_event_dispatch (GSource    *source,
1626                     GSourceFunc callback,
1627                     gpointer    user_data)
1628 {
1629   GdkEvent *event;
1630  
1631   GDK_THREADS_ENTER ();
1632
1633   gdk_events_queue();
1634   event = gdk_event_unqueue();
1635
1636   if (event)
1637     {
1638       if (gdk_event_func)
1639         (*gdk_event_func) (event, gdk_event_data);
1640       
1641       gdk_event_free (event);
1642     }
1643   
1644   GDK_THREADS_LEAVE ();
1645
1646   return TRUE;
1647 }
1648
1649 /* Sends a ClientMessage to all toplevel client windows */
1650 gboolean
1651 gdk_event_send_client_message (GdkEvent *event, guint32 xid)
1652 {
1653   XEvent sev;
1654   
1655   g_return_val_if_fail(event != NULL, FALSE);
1656   
1657   /* Set up our event to send, with the exception of its target window */
1658   sev.xclient.type = ClientMessage;
1659   sev.xclient.display = gdk_display;
1660   sev.xclient.format = event->client.data_format;
1661   sev.xclient.window = xid;
1662   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
1663   sev.xclient.message_type = event->client.message_type;
1664   
1665   return gdk_send_xevent (xid, False, NoEventMask, &sev);
1666 }
1667
1668 /* Sends a ClientMessage to all toplevel client windows */
1669 gboolean
1670 gdk_event_send_client_message_to_all_recurse (XEvent  *xev, 
1671                                               guint32  xid,
1672                                               guint    level)
1673 {
1674   static GdkAtom wm_state_atom = GDK_NONE;
1675   Atom type = None;
1676   int format;
1677   unsigned long nitems, after;
1678   unsigned char *data;
1679   Window *ret_children, ret_root, ret_parent;
1680   unsigned int ret_nchildren;
1681   gint old_warnings = gdk_error_warnings;
1682   gboolean send = FALSE;
1683   gboolean found = FALSE;
1684   int i;
1685
1686   if (!wm_state_atom)
1687     wm_state_atom = gdk_atom_intern ("WM_STATE", FALSE);
1688
1689   gdk_error_warnings = FALSE;
1690   gdk_error_code = 0;
1691   XGetWindowProperty (gdk_display, xid, wm_state_atom, 0, 0, False, AnyPropertyType,
1692                       &type, &format, &nitems, &after, &data);
1693
1694   if (gdk_error_code)
1695     {
1696       gdk_error_warnings = old_warnings;
1697
1698       return FALSE;
1699     }
1700
1701   if (type)
1702     {
1703       send = TRUE;
1704       XFree (data);
1705     }
1706   else
1707     {
1708       /* OK, we're all set, now let's find some windows to send this to */
1709       if (XQueryTree (gdk_display, xid, &ret_root, &ret_parent,
1710                       &ret_children, &ret_nchildren) != True ||
1711           gdk_error_code)
1712         {
1713           gdk_error_warnings = old_warnings;
1714
1715           return FALSE;
1716         }
1717
1718       for(i = 0; i < ret_nchildren; i++)
1719         if (gdk_event_send_client_message_to_all_recurse (xev, ret_children[i], level + 1))
1720           found = TRUE;
1721
1722       XFree (ret_children);
1723     }
1724
1725   if (send || (!found && (level == 1)))
1726     {
1727       xev->xclient.window = xid;
1728       gdk_send_xevent (xid, False, NoEventMask, xev);
1729     }
1730
1731   gdk_error_warnings = old_warnings;
1732
1733   return (send || found);
1734 }
1735
1736 void
1737 gdk_event_send_clientmessage_toall (GdkEvent *event)
1738 {
1739   XEvent sev;
1740   gint old_warnings = gdk_error_warnings;
1741
1742   g_return_if_fail(event != NULL);
1743   
1744   /* Set up our event to send, with the exception of its target window */
1745   sev.xclient.type = ClientMessage;
1746   sev.xclient.display = gdk_display;
1747   sev.xclient.format = event->client.data_format;
1748   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
1749   sev.xclient.message_type = event->client.message_type;
1750
1751   gdk_event_send_client_message_to_all_recurse(&sev, gdk_root_window, 0);
1752
1753   gdk_error_warnings = old_warnings;
1754 }
1755
1756 /*
1757  *--------------------------------------------------------------
1758  * gdk_flush
1759  *
1760  *   Flushes the Xlib output buffer and then waits
1761  *   until all requests have been received and processed
1762  *   by the X server. The only real use for this function
1763  *   is in dealing with XShm.
1764  *
1765  * Arguments:
1766  *
1767  * Results:
1768  *
1769  * Side effects:
1770  *
1771  *--------------------------------------------------------------
1772  */
1773
1774 void
1775 gdk_flush (void)
1776 {
1777   XSync (gdk_display, False);
1778 }
1779
1780 static GdkAtom timestamp_prop_atom = 0;
1781
1782 static Bool
1783 timestamp_predicate (Display *display,
1784                      XEvent  *xevent,
1785                      XPointer arg)
1786 {
1787   Window xwindow = GPOINTER_TO_UINT (arg);
1788
1789   if (xevent->type == PropertyNotify &&
1790       xevent->xproperty.window == xwindow &&
1791       xevent->xproperty.atom == timestamp_prop_atom)
1792     return True;
1793
1794   return False;
1795 }
1796
1797 /**
1798  * gdk_x11_get_server_time:
1799  * @window: a #GdkWindow, used for communication with the server.
1800  *          The window must have GDK_PROPERTY_CHANGE_MASK in its
1801  *          events mask or a hang will result.
1802  * 
1803  * Routine to get the current X server time stamp. 
1804  * 
1805  * Return value: the time stamp.
1806  **/
1807 guint32
1808 gdk_x11_get_server_time (GdkWindow *window)
1809 {
1810   Display *xdisplay;
1811   Window   xwindow;
1812   guchar c = 'a';
1813   XEvent xevent;
1814
1815   g_return_val_if_fail (GDK_IS_WINDOW (window), 0);
1816   g_return_val_if_fail (!GDK_WINDOW_DESTROYED (window), 0);
1817
1818   if (!timestamp_prop_atom)
1819     timestamp_prop_atom = gdk_atom_intern ("GDK_TIMESTAMP_PROP", FALSE);
1820
1821   xdisplay = GDK_WINDOW_XDISPLAY (window);
1822   xwindow = GDK_WINDOW_XWINDOW (window);
1823   
1824   XChangeProperty (xdisplay, xwindow,
1825                    timestamp_prop_atom, timestamp_prop_atom,
1826                    8, PropModeReplace, &c, 1);
1827
1828   XIfEvent (xdisplay, &xevent,
1829             timestamp_predicate, GUINT_TO_POINTER(xwindow));
1830
1831   return xevent.xproperty.time;
1832 }
1833
1834
1835 gboolean
1836 gdk_net_wm_supports (GdkAtom property)
1837 {
1838   static GdkAtom wmspec_check_atom = 0;
1839   static GdkAtom wmspec_supported_atom = 0;
1840   static GdkAtom *atoms = NULL;
1841   static gulong n_atoms = 0;
1842   Atom type;
1843   gint format;
1844   gulong nitems;
1845   gulong bytes_after;
1846   Window *xwindow;
1847   gulong i;
1848
1849   if (wmspec_check_window != None)
1850     {
1851       if (atoms == NULL)
1852         return FALSE;
1853
1854       i = 0;
1855       while (i < n_atoms)
1856         {
1857           if (atoms[i] == property)
1858             return TRUE;
1859           
1860           ++i;
1861         }
1862
1863       return FALSE;
1864     }
1865
1866   if (atoms)
1867     XFree (atoms);
1868
1869   atoms = NULL;
1870   n_atoms = 0;
1871   
1872   /* This function is very slow on every call if you are not running a
1873    * spec-supporting WM. For now not optimized, because it isn't in
1874    * any critical code paths, but if you used it somewhere that had to
1875    * be fast you want to avoid "GTK is slow with old WMs" complaints.
1876    * Probably at that point the function should be changed to query
1877    * _NET_SUPPORTING_WM_CHECK only once every 10 seconds or something.
1878    */
1879   
1880   if (wmspec_check_atom == 0)
1881     wmspec_check_atom = gdk_atom_intern ("_NET_SUPPORTING_WM_CHECK", FALSE);
1882       
1883   if (wmspec_supported_atom == 0)
1884     wmspec_supported_atom = gdk_atom_intern ("_NET_SUPPORTED", FALSE);
1885   
1886   XGetWindowProperty (gdk_display, gdk_root_window,
1887                       wmspec_check_atom, 0, G_MAXLONG,
1888                       False, XA_WINDOW, &type, &format, &nitems,
1889                       &bytes_after, (guchar **)&xwindow);
1890
1891   if (type != XA_WINDOW)
1892     return FALSE;
1893
1894   gdk_error_trap_push ();
1895
1896   /* Find out if this WM goes away, so we can reset everything. */
1897   XSelectInput (gdk_display, *xwindow,
1898                 StructureNotifyMask);
1899   
1900   gdk_flush ();
1901   
1902   if (gdk_error_trap_pop ())
1903     {
1904       XFree (xwindow);
1905       return FALSE;
1906     }
1907
1908   XGetWindowProperty (gdk_display, gdk_root_window,
1909                       wmspec_supported_atom, 0, G_MAXLONG,
1910                       False, XA_ATOM, &type, &format, &n_atoms,
1911                       &bytes_after, (guchar **)&atoms);
1912   
1913   if (type != XA_ATOM)
1914     return FALSE;
1915   
1916   wmspec_check_window = *xwindow;
1917   XFree (xwindow);
1918   
1919   /* since wmspec_check_window != None this isn't infinite. ;-) */
1920   return gdk_net_wm_supports (property);
1921 }
1922
1923 static struct
1924 {
1925   const char *xsettings_name;
1926   const char *gdk_name;
1927 } settings_map[] = {
1928   { "Net/DoubleClickTime", "gtk-double-click-timeout" },
1929   { "Net/DragThreshold", "gtk-drag-threshold" },
1930   { "Gtk/ColorPalette", "gtk-color-palette" },
1931   { "Gtk/ToolbarStyle", "gtk-toolbar-style" },
1932   { "Gtk/ToolbarIconSize", "gtk-toolbar-icon-size" },
1933   { "Net/CursorBlink", "gtk-cursor-blink" },
1934   { "Net/CursorBlinkTime", "gtk-cursor-blink-time" }
1935 };
1936
1937 static void
1938 gdk_xsettings_notify_cb (const char       *name,
1939                          XSettingsAction   action,
1940                          XSettingsSetting *setting,
1941                          void             *data)
1942 {
1943   GdkEvent new_event;
1944   int i;
1945
1946   new_event.type = GDK_SETTING;
1947   new_event.setting.window = NULL;
1948   new_event.setting.send_event = FALSE;
1949   new_event.setting.name = NULL;
1950
1951   for (i = 0; i < G_N_ELEMENTS (settings_map) ; i++)
1952     if (strcmp (settings_map[i].xsettings_name, name) == 0)
1953       {
1954         new_event.setting.name = g_strdup (settings_map[i].gdk_name);
1955         break;
1956       }
1957
1958   if (!new_event.setting.name)
1959     return;
1960   
1961   switch (action)
1962     {
1963     case XSETTINGS_ACTION_NEW:
1964       new_event.setting.action = GDK_SETTING_ACTION_NEW;
1965       break;
1966     case XSETTINGS_ACTION_CHANGED:
1967       new_event.setting.action = GDK_SETTING_ACTION_CHANGED;
1968       break;
1969     case XSETTINGS_ACTION_DELETED:
1970       new_event.setting.action = GDK_SETTING_ACTION_DELETED;
1971       break;
1972     }
1973
1974   gdk_event_put (&new_event);
1975 }
1976
1977 static gboolean
1978 check_transform (const gchar *xsettings_name,
1979                  GType        src_type,
1980                  GType        dest_type)
1981 {
1982   if (!g_value_type_transformable (src_type, dest_type))
1983     {
1984       g_warning ("Cannot tranform xsetting %s of type %s to type %s\n",
1985                  xsettings_name,
1986                  g_type_name (src_type),
1987                  g_type_name (dest_type));
1988       return FALSE;
1989     }
1990   else
1991     return TRUE;
1992 }
1993
1994 gboolean
1995 gdk_setting_get (const gchar *name,
1996                  GValue      *value)
1997 {
1998   const char *xsettings_name = NULL;
1999   XSettingsResult result;
2000   XSettingsSetting *setting;
2001   gboolean success = FALSE;
2002   gint i;
2003   GValue tmp_val = { 0, };
2004
2005   for (i = 0; i < G_N_ELEMENTS (settings_map) ; i++)
2006     if (strcmp (settings_map[i].gdk_name, name) == 0)
2007       {
2008         xsettings_name = settings_map[i].xsettings_name;
2009         break;
2010       }
2011
2012   if (!xsettings_name)
2013     return FALSE;
2014
2015   result = xsettings_client_get_setting (xsettings_client, xsettings_name, &setting);
2016   if (result != XSETTINGS_SUCCESS)
2017     return FALSE;
2018
2019   switch (setting->type)
2020     {
2021     case XSETTINGS_TYPE_INT:
2022       if (check_transform (xsettings_name, G_TYPE_INT, G_VALUE_TYPE (value)))
2023         {
2024           g_value_init (&tmp_val, G_TYPE_INT);
2025           g_value_set_int (&tmp_val, setting->data.v_int);
2026           g_value_transform (&tmp_val, value);
2027
2028           success = TRUE;
2029         }
2030       break;
2031     case XSETTINGS_TYPE_STRING:
2032       if (check_transform (xsettings_name, G_TYPE_STRING, G_VALUE_TYPE (value)))
2033         {
2034           g_value_init (&tmp_val, G_TYPE_STRING);
2035           g_value_set_string (&tmp_val, setting->data.v_string);
2036           g_value_transform (&tmp_val, value);
2037
2038           success = TRUE;
2039         }
2040       break;
2041     case XSETTINGS_TYPE_COLOR:
2042       if (!check_transform (xsettings_name, GDK_TYPE_COLOR, G_VALUE_TYPE (value)))
2043         {
2044           GdkColor color;
2045           
2046           g_value_init (&tmp_val, GDK_TYPE_COLOR);
2047
2048           color.pixel = 0;
2049           color.red = setting->data.v_color.red;
2050           color.green = setting->data.v_color.green;
2051           color.blue = setting->data.v_color.blue;
2052           
2053           g_value_set_boxed (&tmp_val, &color);
2054           
2055           g_value_transform (&tmp_val, value);
2056           
2057           success = TRUE;
2058         }
2059       break;
2060     }
2061   
2062   g_value_unset (&tmp_val);
2063
2064   xsettings_setting_free (setting);
2065
2066   return success;
2067 }
2068
2069 GdkFilterReturn 
2070 gdk_xsettings_client_event_filter (GdkXEvent *xevent,
2071                                    GdkEvent  *event,
2072                                    gpointer   data)
2073 {
2074   if (xsettings_client_process_event (xsettings_client, (XEvent *)xevent))
2075     return GDK_FILTER_REMOVE;
2076   else
2077     return GDK_FILTER_CONTINUE;
2078 }
2079
2080 static void 
2081 gdk_xsettings_watch_cb (Window window,
2082                         Bool   is_start,
2083                         long   mask,
2084                         void  *cb_data)
2085 {
2086   GdkWindow *gdkwin;
2087
2088   gdkwin = gdk_window_lookup (window);
2089   if (is_start)
2090     gdk_window_add_filter (gdkwin, gdk_xsettings_client_event_filter, NULL);
2091   else
2092     gdk_window_remove_filter (gdkwin, gdk_xsettings_client_event_filter, NULL);
2093 }