]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkevents-x11.c
75dd891ddd23246cbb881c778b07fb2ea7b79c09
[~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 Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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 #include "gdk.h"
21 #include "gdkx.h"
22 #include "gdkprivate.h"
23 #include "gdkinput.h"
24 #include "gdkkeysyms.h"
25
26 #if HAVE_CONFIG_H
27 #  include <config.h>
28 #  if STDC_HEADERS
29 #    include <string.h>
30 #  endif
31 #endif
32
33
34 typedef struct _GdkIOClosure GdkIOClosure;
35 typedef struct _GdkEventPrivate GdkEventPrivate;
36
37 #define DOUBLE_CLICK_TIME      250
38 #define TRIPLE_CLICK_TIME      500
39 #define DOUBLE_CLICK_DIST      5
40 #define TRIPLE_CLICK_DIST      5
41
42 typedef enum {
43   /* Following flag is set for events on the event queue during
44    * translation and cleared afterwards.
45    */
46   GDK_EVENT_PENDING = 1 << 0
47 } GdkEventFlags;
48
49 struct _GdkIOClosure {
50   GdkInputFunction function;
51   GdkInputCondition condition;
52   GdkDestroyNotify notify;
53   gpointer data;
54 };
55
56 struct _GdkEventPrivate {
57   GdkEvent event;
58   guint    flags;
59 };
60
61 /* 
62  * Private function declarations
63  */
64
65 static GdkEvent *gdk_event_new          (void);
66 static gint      gdk_event_apply_filters (XEvent *xevent,
67                                           GdkEvent *event,
68                                           GList *filters);
69 static gint      gdk_event_translate     (GdkEvent *event, 
70                                           XEvent   *xevent);
71 #if 0
72 static Bool      gdk_event_get_type     (Display      *display, 
73                                          XEvent       *xevent, 
74                                          XPointer      arg);
75 #endif
76 static void      gdk_events_queue       (void);
77 static GdkEvent *gdk_event_unqueue      (void);
78
79 static gboolean  gdk_event_prepare      (gpointer  source_data, 
80                                          GTimeVal *current_time,
81                                          gint     *timeout);
82 static gboolean  gdk_event_check        (gpointer  source_data,
83                                          GTimeVal *current_time);
84 static gboolean  gdk_event_dispatch     (gpointer  source_data,
85                                          GTimeVal *current_time,
86                                          gpointer  user_data);
87
88 static void      gdk_synthesize_click   (GdkEvent     *event, 
89                                          gint          nclicks);
90
91 GdkFilterReturn gdk_wm_protocols_filter (GdkXEvent *xev,
92                                          GdkEvent  *event,
93                                          gpointer   data);
94
95 /* Private variable declarations
96  */
97
98 static int connection_number = 0;           /* The file descriptor number of our
99                                              *  connection to the X server. This
100                                              *  is used so that we may determine
101                                              *  when events are pending by using
102                                              *  the "select" system call.
103                                              */
104 static guint32 button_click_time[2];        /* The last 2 button click times. Used
105                                              *  to determine if the latest button click
106                                              *  is part of a double or triple click.
107                                              */
108 static GdkWindow *button_window[2];         /* The last 2 windows to receive button presses.
109                                              *  Also used to determine if the latest button
110                                              *  click is part of a double or triple click.
111                                              */
112 static guint button_number[2];              /* The last 2 buttons to be pressed.
113                                              */
114 static GdkEventFunc   event_func;           /* Callback for events */
115 static gpointer       event_data;
116 static GDestroyNotify event_notify;
117
118 static GList *client_filters;                       /* Filters for client messages */
119
120 /* FIFO's for event queue, and for events put back using
121  * gdk_event_put().
122  */
123 static GList *queued_events = NULL;
124 static GList *queued_tail = NULL;
125
126 static GSourceFuncs event_funcs = {
127   gdk_event_prepare,
128   gdk_event_check,
129   gdk_event_dispatch,
130   (GDestroyNotify)g_free
131 };
132
133 GPollFD event_poll_fd;
134
135 /*********************************************
136  * Functions for maintaining the event queue *
137  *********************************************/
138
139 /*************************************************************
140  * gdk_event_queue_find_first:
141  *     Find the first event on the queue that is not still
142  *     being filled in.
143  *   arguments:
144  *     
145  *   results:
146  *     Pointer to the list node for that event, or NULL
147  *************************************************************/
148
149 static GList *
150 gdk_event_queue_find_first (void)
151 {
152   GList *tmp_list = queued_events;
153
154   while (tmp_list)
155     {
156       GdkEventPrivate *event = tmp_list->data;
157       if (!(event->flags & GDK_EVENT_PENDING))
158         return tmp_list;
159
160       tmp_list = g_list_next (tmp_list);
161     }
162
163   return NULL;
164 }
165
166 /*************************************************************
167  * gdk_event_queue_remove_link:
168  *     Remove a specified list node from the event queue.
169  *   arguments:
170  *     node: Node to remove.
171  *   results:
172  *************************************************************/
173
174 static void
175 gdk_event_queue_remove_link (GList *node)
176 {
177   if (node->prev)
178     node->prev->next = node->next;
179   else
180     queued_events = node->next;
181   
182   if (node->next)
183     node->next->prev = node->prev;
184   else
185     queued_tail = node->prev;
186   
187 }
188
189 /*************************************************************
190  * gdk_event_queue_append:
191  *     Append an event onto the tail of the event queue.
192  *   arguments:
193  *     event: Event to append.
194  *   results:
195  *************************************************************/
196
197 static void
198 gdk_event_queue_append (GdkEvent *event)
199 {
200   queued_tail = g_list_append(queued_tail, event);
201   
202   if (!queued_events)
203     queued_events = queued_tail;
204   else
205     queued_tail = queued_tail->next;
206 }
207
208 void 
209 gdk_events_init (void)
210 {
211   connection_number = ConnectionNumber (gdk_display);
212   GDK_NOTE (MISC,
213             g_message ("connection number: %d", connection_number));
214
215   g_source_add (GDK_PRIORITY_EVENTS, TRUE, &event_funcs, NULL, NULL, NULL);
216
217   event_poll_fd.fd = connection_number;
218   event_poll_fd.events = G_IO_IN;
219   
220   g_main_add_poll (&event_poll_fd, GDK_PRIORITY_EVENTS);
221
222   button_click_time[0] = 0;
223   button_click_time[1] = 0;
224   button_window[0] = NULL;
225   button_window[1] = NULL;
226   button_number[0] = -1;
227   button_number[1] = -1;
228
229   gdk_add_client_message_filter (gdk_wm_protocols, 
230                                  gdk_wm_protocols_filter, NULL);
231 }
232
233 /*
234  *--------------------------------------------------------------
235  * gdk_events_pending
236  *
237  *   Returns if events are pending on the queue.
238  *
239  * Arguments:
240  *
241  * Results:
242  *   Returns TRUE if events are pending
243  *
244  * Side effects:
245  *
246  *--------------------------------------------------------------
247  */
248
249 gboolean
250 gdk_events_pending (void)
251 {
252   return (gdk_event_queue_find_first() || XPending (gdk_display));
253 }
254
255 /*
256  *--------------------------------------------------------------
257  * gdk_event_get_graphics_expose
258  *
259  *   Waits for a GraphicsExpose or NoExpose event
260  *
261  * Arguments:
262  *
263  * Results: 
264  *   For GraphicsExpose events, returns a pointer to the event
265  *   converted into a GdkEvent Otherwise, returns NULL.
266  *
267  * Side effects:
268  *
269  *-------------------------------------------------------------- */
270
271 static Bool
272 graphics_expose_predicate  (Display  *display,
273                             XEvent   *xevent,
274                             XPointer  arg)
275 {
276   GdkWindowPrivate *private = (GdkWindowPrivate *)arg;
277   
278   g_return_val_if_fail (private != NULL, False);
279   
280   if ((xevent->xany.window == private->xwindow) &&
281       ((xevent->xany.type == GraphicsExpose) ||
282        (xevent->xany.type == NoExpose)))
283     return True;
284   else
285     return False;
286 }
287
288 GdkEvent *
289 gdk_event_get_graphics_expose (GdkWindow *window)
290 {
291   XEvent xevent;
292   GdkEvent *event;
293   
294   g_return_val_if_fail (window != NULL, NULL);
295   
296   XIfEvent (gdk_display, &xevent, graphics_expose_predicate, (XPointer)window);
297   
298   if (xevent.xany.type == GraphicsExpose)
299     {
300       event = gdk_event_new ();
301       
302       if (gdk_event_translate (event, &xevent))
303         return event;
304       else
305         gdk_event_free (event);
306     }
307   
308   return NULL;  
309 }
310
311 /************************
312  * Exposure compression *
313  ************************/
314
315 /*
316  * The following implements simple exposure compression. It is
317  * modelled after the way Xt does exposure compression - in
318  * particular compress_expose = XtExposeCompressMultiple.
319  * It compress consecutive sequences of exposure events,
320  * but not sequences that cross other events. (This is because
321  * if it crosses a ConfigureNotify, we could screw up and
322  * mistakenly compress the exposures generated for the new
323  * size - could we just check for ConfigureNotify?)
324  *
325  * Xt compresses to a region / bounding rectangle, we compress
326  * to two rectangles, and try find the two rectangles of minimal
327  * area for this - this is supposed to handle the typical
328  * L-shaped regions generated by OpaqueMove.
329  */
330
331 /* Given three rectangles, find the two rectangles that cover
332  * them with the smallest area.
333  */
334 static void
335 gdk_add_rect_to_rects (GdkRectangle *rect1,
336                        GdkRectangle *rect2, 
337                        GdkRectangle *new_rect)
338 {
339   GdkRectangle t1, t2, t3;
340   gint size1, size2, size3;
341
342   gdk_rectangle_union (rect1, rect2, &t1);
343   gdk_rectangle_union (rect1, new_rect, &t2);
344   gdk_rectangle_union (rect2, new_rect, &t3);
345
346   size1 = t1.width * t1.height + new_rect->width * new_rect->height;
347   size2 = t2.width * t2.height + rect2->width * rect2->height;
348   size3 = t1.width * t1.height + rect1->width * rect1->height;
349
350   if (size1 < size2)
351     {
352       if (size1 < size3)
353         {
354           *rect1 = t1;
355           *rect2 = *new_rect;
356         }
357       else
358         *rect2 = t3;
359     }
360   else
361     {
362       if (size2 < size3)
363         *rect1 = t2;
364       else
365         *rect2 = t3;
366     }
367 }
368
369 typedef struct _GdkExposeInfo GdkExposeInfo;
370
371 struct _GdkExposeInfo {
372   Window window;
373   gboolean seen_nonmatching;
374 };
375
376 Bool
377 expose_predicate (Display *display, XEvent *xevent, XPointer arg)
378 {
379   GdkExposeInfo *info = (GdkExposeInfo *)arg;
380
381   if (xevent->xany.type != Expose)
382     {
383       info->seen_nonmatching = TRUE;
384     }
385
386   if (info->seen_nonmatching || (xevent->xany.window != info->window))
387     return FALSE;
388   else
389     return TRUE;
390 }
391
392 void
393 gdk_compress_exposures (XEvent *xevent, GdkWindow *window)
394 {
395   gint nrects = 1;
396   gint count = 0;
397   GdkRectangle rect1;
398   GdkRectangle rect2;
399   GdkRectangle tmp_rect;
400   XEvent tmp_event;
401   GdkFilterReturn result;
402   GdkExposeInfo info;
403   GdkEvent event;
404
405   info.window = xevent->xany.window;
406   info.seen_nonmatching = FALSE;
407   
408   rect1.x = xevent->xexpose.x;
409   rect1.y = xevent->xexpose.y;
410   rect1.width = xevent->xexpose.width;
411   rect1.height = xevent->xexpose.height;
412
413   while (1)
414     {
415       if (count == 0)
416         {
417           if (!XCheckIfEvent (gdk_display, 
418                               &tmp_event, 
419                               expose_predicate, 
420                               (XPointer)&info))
421             break;
422         }
423       else
424         XIfEvent (gdk_display, 
425                   &tmp_event, 
426                   expose_predicate, 
427                   (XPointer)&info);
428       
429       /* We apply filters here, and if it was filtered, completely
430        * ignore the return
431        */
432       result = gdk_event_apply_filters (xevent, &event,
433                                         window ? 
434                                           ((GdkWindowPrivate *)window)->filters
435                                           : gdk_default_filters);
436       
437       if (result != GDK_FILTER_CONTINUE)
438         {
439           if (result == GDK_FILTER_TRANSLATE)
440             gdk_event_put (&event);
441           continue;
442         }
443
444       if (nrects == 1)
445         {
446           rect2.x = tmp_event.xexpose.x;
447           rect2.y = tmp_event.xexpose.y;
448           rect2.width = tmp_event.xexpose.width;
449           rect2.height = tmp_event.xexpose.height;
450
451           nrects++;
452         }
453       else
454         {
455           tmp_rect.x = tmp_event.xexpose.x;
456           tmp_rect.y = tmp_event.xexpose.y;
457           tmp_rect.width = tmp_event.xexpose.width;
458           tmp_rect.height = tmp_event.xexpose.height;
459
460           gdk_add_rect_to_rects (&rect1, &rect2, &tmp_rect);
461         }
462
463       count = tmp_event.xexpose.count;
464     }
465
466   if (nrects == 2)
467     {
468       gdk_rectangle_union (&rect1, &rect2, &tmp_rect);
469
470       if ((tmp_rect.width * tmp_rect.height) <
471           2 * (rect1.height * rect1.width +
472                rect2.height * rect2.width))
473         {
474           rect1 = tmp_rect;
475           nrects = 1;
476         }
477     }
478
479   if (nrects == 2)
480     {
481       event.expose.type = GDK_EXPOSE;
482       event.expose.window = window;
483       event.expose.area.x = rect2.x;
484       event.expose.area.y = rect2.y;
485       event.expose.area.width = rect2.width;
486       event.expose.area.height = rect2.height;
487       event.expose.count = 0;
488
489       gdk_event_put (&event);
490     }
491
492   xevent->xexpose.count = nrects - 1;
493   xevent->xexpose.x = rect1.x;
494   xevent->xexpose.y = rect1.y;
495   xevent->xexpose.width = rect1.width;
496   xevent->xexpose.height = rect1.height;
497 }
498
499 /*************************************************************
500  * gdk_event_handler_set:
501  *     
502  *   arguments:
503  *     func: Callback function to be called for each event.
504  *     data: Data supplied to the function
505  *     notify: function called when function is no longer needed
506  * 
507  *   results:
508  *************************************************************/
509
510 void 
511 gdk_event_handler_set (GdkEventFunc   func,
512                        gpointer       data,
513                        GDestroyNotify notify)
514 {
515   if (event_func && event_notify)
516     (*event_notify) (event_data);
517
518   event_func = func;
519   event_data = data;
520   event_notify = notify;
521 }
522
523 /*
524  *--------------------------------------------------------------
525  * gdk_event_get
526  *
527  *   Gets the next event.
528  *
529  * Arguments:
530  *
531  * Results:
532  *   If an event is waiting that we care about, returns 
533  *   a pointer to that event, to be freed with gdk_event_free.
534  *   Otherwise, returns NULL.
535  *
536  * Side effects:
537  *
538  *--------------------------------------------------------------
539  */
540
541 GdkEvent *
542 gdk_event_get (void)
543 {
544   gdk_events_queue();
545
546   return gdk_event_unqueue();
547 }
548
549 /*
550  *--------------------------------------------------------------
551  * gdk_event_peek
552  *
553  *   Gets the next event.
554  *
555  * Arguments:
556  *
557  * Results:
558  *   If an event is waiting that we care about, returns 
559  *   a copy of that event, but does not remove it from
560  *   the queue. The pointer is to be freed with gdk_event_free.
561  *   Otherwise, returns NULL.
562  *
563  * Side effects:
564  *
565  *--------------------------------------------------------------
566  */
567
568 GdkEvent *
569 gdk_event_peek (void)
570 {
571   GList *tmp_list;
572
573   tmp_list = gdk_event_queue_find_first ();
574   
575   if (tmp_list)
576     return gdk_event_copy (tmp_list->data);
577   else
578     return NULL;
579 }
580
581 void
582 gdk_event_put (GdkEvent *event)
583 {
584   GdkEvent *new_event;
585   
586   g_return_if_fail (event != NULL);
587   
588   new_event = gdk_event_copy (event);
589
590   gdk_event_queue_append (new_event);
591 }
592
593 /*
594  *--------------------------------------------------------------
595  * gdk_event_copy
596  *
597  *   Copy a event structure into new storage.
598  *
599  * Arguments:
600  *   "event" is the event struct to copy.
601  *
602  * Results:
603  *   A new event structure.  Free it with gdk_event_free.
604  *
605  * Side effects:
606  *   The reference count of the window in the event is increased.
607  *
608  *--------------------------------------------------------------
609  */
610
611 static GMemChunk *event_chunk;
612
613 static GdkEvent*
614 gdk_event_new (void)
615 {
616   GdkEventPrivate *new_event;
617   
618   if (event_chunk == NULL)
619     event_chunk = g_mem_chunk_new ("events",
620                                    sizeof (GdkEventPrivate),
621                                    4096,
622                                    G_ALLOC_AND_FREE);
623   
624   new_event = g_chunk_new (GdkEventPrivate, event_chunk);
625   new_event->flags = 0;
626   
627   return (GdkEvent *)new_event;
628 }
629
630 GdkEvent*
631 gdk_event_copy (GdkEvent *event)
632 {
633   GdkEvent *new_event;
634   
635   g_return_val_if_fail (event != NULL, NULL);
636   
637   new_event = gdk_event_new ();
638   
639   *new_event = *event;
640   gdk_window_ref (new_event->any.window);
641   
642   switch (event->any.type)
643     {
644     case GDK_KEY_PRESS:
645     case GDK_KEY_RELEASE:
646       new_event->key.string = g_strdup (event->key.string);
647       break;
648       
649     case GDK_ENTER_NOTIFY:
650     case GDK_LEAVE_NOTIFY:
651       if (event->crossing.subwindow != NULL)
652         gdk_window_ref (event->crossing.subwindow);
653       break;
654       
655     case GDK_DRAG_ENTER:
656     case GDK_DRAG_LEAVE:
657     case GDK_DRAG_MOTION:
658     case GDK_DRAG_STATUS:
659     case GDK_DROP_START:
660     case GDK_DROP_FINISHED:
661       gdk_drag_context_ref (event->dnd.context);
662       break;
663
664       
665     default:
666       break;
667     }
668   
669   return new_event;
670 }
671
672 /*
673  *--------------------------------------------------------------
674  * gdk_event_free
675  *
676  *   Free a event structure obtained from gdk_event_copy.  Do not use
677  *   with other event structures.
678  *
679  * Arguments:
680  *   "event" is the event struct to free.
681  *
682  * Results:
683  *
684  * Side effects:
685  *   The reference count of the window in the event is decreased and
686  *   might be freed, too.
687  *
688  *-------------------------------------------------------------- */
689
690 void
691 gdk_event_free (GdkEvent *event)
692 {
693   g_assert (event_chunk != NULL);
694   g_return_if_fail (event != NULL);
695   
696   if (event->any.window)
697     gdk_window_unref (event->any.window);
698   
699   switch (event->any.type)
700     {
701     case GDK_KEY_PRESS:
702     case GDK_KEY_RELEASE:
703       g_free (event->key.string);
704       break;
705       
706     case GDK_ENTER_NOTIFY:
707     case GDK_LEAVE_NOTIFY:
708       if (event->crossing.subwindow != NULL)
709         gdk_window_unref (event->crossing.subwindow);
710       break;
711       
712     case GDK_DRAG_ENTER:
713     case GDK_DRAG_LEAVE:
714     case GDK_DRAG_MOTION:
715     case GDK_DRAG_STATUS:
716     case GDK_DROP_START:
717     case GDK_DROP_FINISHED:
718       gdk_drag_context_unref (event->dnd.context);
719       break;
720
721       
722     default:
723       break;
724     }
725   
726   g_mem_chunk_free (event_chunk, event);
727 }
728
729 /*
730  *--------------------------------------------------------------
731  * gdk_event_get_time:
732  *    Get the timestamp from an event.
733  *   arguments:
734  *     event:
735  *   results:
736  *    The event's time stamp, if it has one, otherwise
737  *    GDK_CURRENT_TIME.
738  *--------------------------------------------------------------
739  */
740
741 guint32
742 gdk_event_get_time (GdkEvent *event)
743 {
744   if (event)
745     switch (event->type)
746       {
747       case GDK_MOTION_NOTIFY:
748         return event->motion.time;
749       case GDK_BUTTON_PRESS:
750       case GDK_2BUTTON_PRESS:
751       case GDK_3BUTTON_PRESS:
752       case GDK_BUTTON_RELEASE:
753         return event->button.time;
754       case GDK_KEY_PRESS:
755       case GDK_KEY_RELEASE:
756         return event->key.time;
757       case GDK_ENTER_NOTIFY:
758       case GDK_LEAVE_NOTIFY:
759         return event->crossing.time;
760       case GDK_PROPERTY_NOTIFY:
761         return event->property.time;
762       case GDK_SELECTION_CLEAR:
763       case GDK_SELECTION_REQUEST:
764       case GDK_SELECTION_NOTIFY:
765         return event->selection.time;
766       case GDK_PROXIMITY_IN:
767       case GDK_PROXIMITY_OUT:
768         return event->proximity.time;
769       case GDK_DRAG_ENTER:
770       case GDK_DRAG_LEAVE:
771       case GDK_DRAG_MOTION:
772       case GDK_DRAG_STATUS:
773       case GDK_DROP_START:
774       case GDK_DROP_FINISHED:
775         return event->dnd.time;
776       default:                  /* use current time */
777         break;
778       }
779   
780   return GDK_CURRENT_TIME;
781 }
782
783 /*
784  *--------------------------------------------------------------
785  * gdk_set_show_events
786  *
787  *   Turns on/off the showing of events.
788  *
789  * Arguments:
790  *   "show_events" is a boolean describing whether or
791  *   not to show the events gdk receives.
792  *
793  * Results:
794  *
795  * Side effects:
796  *   When "show_events" is TRUE, calls to "gdk_event_get"
797  *   will output debugging informatin regarding the event
798  *   received to stdout.
799  *
800  *--------------------------------------------------------------
801  */
802
803 void
804 gdk_set_show_events (int show_events)
805 {
806   if (show_events)
807     gdk_debug_flags |= GDK_DEBUG_EVENTS;
808   else
809     gdk_debug_flags &= ~GDK_DEBUG_EVENTS;
810 }
811
812 gint
813 gdk_get_show_events (void)
814 {
815   return gdk_debug_flags & GDK_DEBUG_EVENTS;
816 }
817
818 static void
819 gdk_io_destroy (gpointer data)
820 {
821   GdkIOClosure *closure = data;
822
823   if (closure->notify)
824     closure->notify (closure->data);
825
826   g_free (closure);
827 }
828
829 static gboolean  
830 gdk_io_invoke (GIOChannel   *source,
831                GIOCondition  condition,
832                gpointer      data)
833 {
834   GdkIOClosure *closure = data;
835   GdkInputCondition gdk_cond = 0;
836
837   if (condition & (G_IO_IN | G_IO_PRI))
838     gdk_cond |= GDK_INPUT_READ;
839   if (condition & G_IO_OUT)
840     gdk_cond |= GDK_INPUT_WRITE;
841   if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
842     gdk_cond |= GDK_INPUT_EXCEPTION;
843
844   if (closure->condition & gdk_cond)
845     closure->function (closure->data, g_io_channel_unix_get_fd (source), gdk_cond);
846
847   return TRUE;
848 }
849
850 gint
851 gdk_input_add_full (gint              source,
852                     GdkInputCondition condition,
853                     GdkInputFunction  function,
854                     gpointer          data,
855                     GdkDestroyNotify  destroy)
856 {
857   guint result;
858   GdkIOClosure *closure = g_new (GdkIOClosure, 1);
859   GIOChannel *channel;
860   GIOCondition cond = 0;
861
862   closure->function = function;
863   closure->condition = condition;
864   closure->notify = destroy;
865   closure->data = data;
866
867   if (condition & GDK_INPUT_READ)
868     cond |= (G_IO_IN | G_IO_PRI);
869   if (condition & GDK_INPUT_WRITE)
870     cond |= G_IO_OUT;
871   if (condition & GDK_INPUT_EXCEPTION)
872     cond |= G_IO_ERR|G_IO_HUP|G_IO_NVAL;
873
874   channel = g_io_channel_unix_new (source);
875   result = g_io_add_watch_full   (channel, G_PRIORITY_DEFAULT, cond, 
876                                   gdk_io_invoke,
877                                   closure, gdk_io_destroy);
878   g_io_channel_unref (channel);
879
880   return result;
881 }
882
883 gint
884 gdk_input_add (gint              source,
885                GdkInputCondition condition,
886                GdkInputFunction  function,
887                gpointer          data)
888 {
889   return gdk_input_add_full (source, condition, function, data, NULL);
890 }
891
892 void
893 gdk_input_remove (gint tag)
894 {
895   g_source_remove (tag);
896 }
897
898 static gint
899 gdk_event_apply_filters (XEvent *xevent,
900                          GdkEvent *event,
901                          GList *filters)
902 {
903   GdkEventFilter *filter;
904   GList *tmp_list;
905   GdkFilterReturn result;
906   
907   tmp_list = filters;
908   
909   while (tmp_list)
910     {
911       filter = (GdkEventFilter *)tmp_list->data;
912       
913       result = (*filter->function)(xevent, event, filter->data);
914       if (result !=  GDK_FILTER_CONTINUE)
915         return result;
916       
917       tmp_list = tmp_list->next;
918     }
919   
920   return GDK_FILTER_CONTINUE;
921 }
922
923 void 
924 gdk_add_client_message_filter (GdkAtom       message_type,
925                                GdkFilterFunc func,
926                                gpointer      data)
927 {
928   GdkClientFilter *filter = g_new (GdkClientFilter, 1);
929
930   filter->type = message_type;
931   filter->function = func;
932   filter->data = data;
933   
934   client_filters = g_list_prepend (client_filters, filter);
935 }
936
937 static gint
938 gdk_event_translate (GdkEvent *event,
939                      XEvent   *xevent)
940 {
941   
942   GdkWindow *window;
943   GdkWindowPrivate *window_private;
944   static XComposeStatus compose;
945   KeySym keysym;
946   int charcount;
947 #ifdef USE_XIM
948   static gchar* buf = NULL;
949   static gint buf_len= 0;
950 #else
951   char buf[16];
952 #endif
953   gint return_val;
954   
955   return_val = FALSE;
956   
957   /* Find the GdkWindow that this event occurred in.
958    * 
959    * We handle events with window=None
960    *  specially - they are generated by XFree86's XInput under
961    *  some circumstances.
962    */
963   
964   if ((xevent->xany.window == None) &&
965       gdk_input_vtable.window_none_event)
966     {
967       return_val = gdk_input_vtable.window_none_event (event,xevent);
968       
969       if (return_val >= 0)      /* was handled */
970         return return_val;
971       else
972         return_val = FALSE;
973     }
974   
975   window = gdk_window_lookup (xevent->xany.window);
976   window_private = (GdkWindowPrivate *) window;
977   
978   if (window != NULL)
979     gdk_window_ref (window);
980   
981   event->any.window = window;
982   event->any.send_event = xevent->xany.send_event;
983   
984   if (window_private && window_private->destroyed)
985     {
986       if (xevent->type != DestroyNotify)
987         return FALSE;
988     }
989   else
990     {
991       /* Check for filters for this window
992        */
993       GdkFilterReturn result;
994       result = gdk_event_apply_filters (xevent, event,
995                                         window_private
996                                         ?window_private->filters
997                                         :gdk_default_filters);
998       
999       if (result != GDK_FILTER_CONTINUE)
1000         {
1001           return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
1002         }
1003     }
1004
1005 #ifdef USE_XIM
1006   if (window == NULL && gdk_xim_window && xevent->type == KeyPress &&
1007       !((GdkWindowPrivate *) gdk_xim_window)->destroyed)
1008     {
1009       /*
1010        * If user presses a key in Preedit or Status window, keypress event
1011        * is sometimes sent to these windows. These windows are not managed
1012        * by GDK, so we redirect KeyPress event to xim_window.
1013        *
1014        * If someone want to use the window whitch is not managed by GDK
1015        * and want to get KeyPress event, he/she must register the filter
1016        * function to gdk_default_filters to intercept the event.
1017        */
1018
1019       GdkFilterReturn result;
1020
1021       window = gdk_xim_window;
1022       window_private = (GdkWindowPrivate *) window;
1023       gdk_window_ref (window);
1024       event->any.window = window;
1025
1026       GDK_NOTE (XIM,
1027         g_message ("KeyPress event is redirected to xim_window: %#lx",
1028                    xevent->xany.window));
1029
1030       result = gdk_event_apply_filters (xevent, event,
1031                                         window_private->filters);
1032       if (result != GDK_FILTER_CONTINUE)
1033         return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
1034     }
1035 #endif
1036
1037   if (window == NULL)
1038     g_message ("Got event for unknown window: %#lx\n", xevent->xany.window);
1039
1040   /* We do a "manual" conversion of the XEvent to a
1041    *  GdkEvent. The structures are mostly the same so
1042    *  the conversion is fairly straightforward. We also
1043    *  optionally print debugging info regarding events
1044    *  received.
1045    */
1046
1047   return_val = TRUE;
1048
1049   switch (xevent->type)
1050     {
1051     case KeyPress:
1052       /* Lookup the string corresponding to the given keysym.
1053        */
1054       
1055 #ifdef USE_XIM
1056       if (buf_len == 0) 
1057         {
1058           buf_len = 128;
1059           buf = g_new (gchar, buf_len);
1060         }
1061       keysym = GDK_VoidSymbol;
1062       
1063       if (gdk_xim_ic && gdk_xim_ic->xic)
1064         {
1065           Status status;
1066           
1067           /* Clear keyval. Depending on status, may not be set */
1068           charcount = XmbLookupString(gdk_xim_ic->xic,
1069                                       &xevent->xkey, buf, buf_len-1,
1070                                       &keysym, &status);
1071           if (status == XBufferOverflow)
1072             {                     /* retry */
1073               /* alloc adequate size of buffer */
1074               GDK_NOTE (XIM,
1075                         g_message("XIM: overflow (required %i)", charcount));
1076               
1077               while (buf_len <= charcount)
1078                 buf_len *= 2;
1079               buf = (gchar *) g_realloc (buf, buf_len);
1080               
1081               charcount = XmbLookupString (gdk_xim_ic->xic,
1082                                            &xevent->xkey, buf, buf_len-1,
1083                                            &keysym, &status);
1084             }
1085           if (status == XLookupNone)
1086             {
1087               return_val = FALSE;
1088               break;
1089             }
1090         }
1091       else
1092         charcount = XLookupString (&xevent->xkey, buf, buf_len,
1093                                    &keysym, &compose);
1094 #else
1095       charcount = XLookupString (&xevent->xkey, buf, 16,
1096                                  &keysym, &compose);
1097 #endif
1098       event->key.keyval = keysym;
1099       
1100       if (charcount > 0 && buf[charcount-1] == '\0')
1101         charcount --;
1102       else
1103         buf[charcount] = '\0';
1104       
1105       /* Print debugging info. */
1106       
1107 #ifdef G_ENABLE_DEBUG
1108       if (gdk_debug_flags & GDK_DEBUG_EVENTS)
1109         {
1110           g_message ("key press:\twindow: %ld  key: %12s  %d",
1111                      xevent->xkey.window,
1112                      event->key.keyval ? XKeysymToString (event->key.keyval) : "(none)",
1113                      event->key.keyval);
1114           if (charcount > 0)
1115             g_message ("\t\tlength: %4d string: \"%s\"",
1116                        charcount, buf);
1117         }
1118 #endif /* G_ENABLE_DEBUG */
1119       
1120       event->key.type = GDK_KEY_PRESS;
1121       event->key.window = window;
1122       event->key.time = xevent->xkey.time;
1123       event->key.state = (GdkModifierType) xevent->xkey.state;
1124       event->key.string = g_strdup (buf);
1125       event->key.length = charcount;
1126       
1127       break;
1128       
1129     case KeyRelease:
1130       /* Lookup the string corresponding to the given keysym.
1131        */
1132 #ifdef USE_XIM
1133       if (buf_len == 0) 
1134         {
1135           buf_len = 128;
1136           buf = g_new (gchar, buf_len);
1137         }
1138 #endif
1139       keysym = GDK_VoidSymbol;
1140       charcount = XLookupString (&xevent->xkey, buf, 16,
1141                                  &keysym, &compose);
1142       event->key.keyval = keysym;      
1143       
1144       /* Print debugging info.
1145        */
1146       GDK_NOTE (EVENTS, 
1147                 g_message ("key release:\t\twindow: %ld  key: %12s  %d",
1148                            xevent->xkey.window,
1149                            XKeysymToString (event->key.keyval),
1150                            event->key.keyval));
1151       
1152       event->key.type = GDK_KEY_RELEASE;
1153       event->key.window = window;
1154       event->key.time = xevent->xkey.time;
1155       event->key.state = (GdkModifierType) xevent->xkey.state;
1156       event->key.length = 0;
1157       event->key.string = NULL;
1158       
1159       break;
1160       
1161     case ButtonPress:
1162       /* Print debugging info.
1163        */
1164       GDK_NOTE (EVENTS, 
1165                 g_message ("button press:\t\twindow: %ld  x,y: %d %d  button: %d",
1166                            xevent->xbutton.window,
1167                            xevent->xbutton.x, xevent->xbutton.y,
1168                            xevent->xbutton.button));
1169       
1170       if (window_private &&
1171           (window_private->extension_events != 0) &&
1172           gdk_input_ignore_core)
1173         {
1174           return_val = FALSE;
1175           break;
1176         }
1177       
1178       event->button.type = GDK_BUTTON_PRESS;
1179       event->button.window = window;
1180       event->button.time = xevent->xbutton.time;
1181       event->button.x = xevent->xbutton.x;
1182       event->button.y = xevent->xbutton.y;
1183       event->button.x_root = (gfloat)xevent->xbutton.x_root;
1184       event->button.y_root = (gfloat)xevent->xbutton.y_root;
1185       event->button.pressure = 0.5;
1186       event->button.xtilt = 0;
1187       event->button.ytilt = 0;
1188       event->button.state = (GdkModifierType) xevent->xbutton.state;
1189       event->button.button = xevent->xbutton.button;
1190       event->button.source = GDK_SOURCE_MOUSE;
1191       event->button.deviceid = GDK_CORE_POINTER;
1192       
1193       if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) &&
1194           (event->button.window == button_window[1]) &&
1195           (event->button.button == button_number[1]))
1196         {
1197           gdk_synthesize_click (event, 3);
1198           
1199           button_click_time[1] = 0;
1200           button_click_time[0] = 0;
1201           button_window[1] = NULL;
1202           button_window[0] = 0;
1203           button_number[1] = -1;
1204           button_number[0] = -1;
1205         }
1206       else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) &&
1207                (event->button.window == button_window[0]) &&
1208                (event->button.button == button_number[0]))
1209         {
1210           gdk_synthesize_click (event, 2);
1211           
1212           button_click_time[1] = button_click_time[0];
1213           button_click_time[0] = event->button.time;
1214           button_window[1] = button_window[0];
1215           button_window[0] = event->button.window;
1216           button_number[1] = button_number[0];
1217           button_number[0] = event->button.button;
1218         }
1219       else
1220         {
1221           button_click_time[1] = 0;
1222           button_click_time[0] = event->button.time;
1223           button_window[1] = NULL;
1224           button_window[0] = event->button.window;
1225           button_number[1] = -1;
1226           button_number[0] = event->button.button;
1227         }
1228
1229       break;
1230       
1231     case ButtonRelease:
1232       /* Print debugging info.
1233        */
1234       GDK_NOTE (EVENTS, 
1235                 g_message ("button release:\twindow: %ld  x,y: %d %d  button: %d",
1236                            xevent->xbutton.window,
1237                            xevent->xbutton.x, xevent->xbutton.y,
1238                            xevent->xbutton.button));
1239       
1240       if (window_private &&
1241           (window_private->extension_events != 0) &&
1242           gdk_input_ignore_core)
1243         {
1244           return_val = FALSE;
1245           break;
1246         }
1247       
1248       event->button.type = GDK_BUTTON_RELEASE;
1249       event->button.window = window;
1250       event->button.time = xevent->xbutton.time;
1251       event->button.x = xevent->xbutton.x;
1252       event->button.y = xevent->xbutton.y;
1253       event->button.x_root = (gfloat)xevent->xbutton.x_root;
1254       event->button.y_root = (gfloat)xevent->xbutton.y_root;
1255       event->button.pressure = 0.5;
1256       event->button.xtilt = 0;
1257       event->button.ytilt = 0;
1258       event->button.state = (GdkModifierType) xevent->xbutton.state;
1259       event->button.button = xevent->xbutton.button;
1260       event->button.source = GDK_SOURCE_MOUSE;
1261       event->button.deviceid = GDK_CORE_POINTER;
1262       
1263       break;
1264       
1265     case MotionNotify:
1266       /* Print debugging info.
1267        */
1268       GDK_NOTE (EVENTS,
1269                 g_message ("motion notify:\t\twindow: %ld  x,y: %d %d  hint: %s", 
1270                            xevent->xmotion.window,
1271                            xevent->xmotion.x, xevent->xmotion.y,
1272                            (xevent->xmotion.is_hint) ? "true" : "false"));
1273       
1274       if (window_private &&
1275           (window_private->extension_events != 0) &&
1276           gdk_input_ignore_core)
1277         {
1278           return_val = FALSE;
1279           break;
1280         }
1281       
1282       event->motion.type = GDK_MOTION_NOTIFY;
1283       event->motion.window = window;
1284       event->motion.time = xevent->xmotion.time;
1285       event->motion.x = xevent->xmotion.x;
1286       event->motion.y = xevent->xmotion.y;
1287       event->motion.x_root = (gfloat)xevent->xmotion.x_root;
1288       event->motion.y_root = (gfloat)xevent->xmotion.y_root;
1289       event->motion.pressure = 0.5;
1290       event->motion.xtilt = 0;
1291       event->motion.ytilt = 0;
1292       event->motion.state = (GdkModifierType) xevent->xmotion.state;
1293       event->motion.is_hint = xevent->xmotion.is_hint;
1294       event->motion.source = GDK_SOURCE_MOUSE;
1295       event->motion.deviceid = GDK_CORE_POINTER;
1296       
1297       break;
1298       
1299     case EnterNotify:
1300       /* Print debugging info.
1301        */
1302       GDK_NOTE (EVENTS,
1303                 g_message ("enter notify:\t\twindow: %ld  detail: %d subwin: %ld",
1304                            xevent->xcrossing.window,
1305                            xevent->xcrossing.detail,
1306                            xevent->xcrossing.subwindow));
1307       
1308       /* Tell XInput stuff about it if appropriate */
1309       if (window_private &&
1310           !window_private->destroyed &&
1311           (window_private->extension_events != 0) &&
1312           gdk_input_vtable.enter_event)
1313         gdk_input_vtable.enter_event (&xevent->xcrossing, window);
1314       
1315       event->crossing.type = GDK_ENTER_NOTIFY;
1316       event->crossing.window = window;
1317       
1318       /* If the subwindow field of the XEvent is non-NULL, then
1319        *  lookup the corresponding GdkWindow.
1320        */
1321       if (xevent->xcrossing.subwindow != None)
1322         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
1323       else
1324         event->crossing.subwindow = NULL;
1325       
1326       event->crossing.time = xevent->xcrossing.time;
1327       event->crossing.x = xevent->xcrossing.x;
1328       event->crossing.y = xevent->xcrossing.y;
1329       event->crossing.x_root = xevent->xcrossing.x_root;
1330       event->crossing.y_root = xevent->xcrossing.y_root;
1331       
1332       /* Translate the crossing mode into Gdk terms.
1333        */
1334       switch (xevent->xcrossing.mode)
1335         {
1336         case NotifyNormal:
1337           event->crossing.mode = GDK_CROSSING_NORMAL;
1338           break;
1339         case NotifyGrab:
1340           event->crossing.mode = GDK_CROSSING_GRAB;
1341           break;
1342         case NotifyUngrab:
1343           event->crossing.mode = GDK_CROSSING_UNGRAB;
1344           break;
1345         };
1346       
1347       /* Translate the crossing detail into Gdk terms.
1348        */
1349       switch (xevent->xcrossing.detail)
1350         {
1351         case NotifyInferior:
1352           event->crossing.detail = GDK_NOTIFY_INFERIOR;
1353           break;
1354         case NotifyAncestor:
1355           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
1356           break;
1357         case NotifyVirtual:
1358           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
1359           break;
1360         case NotifyNonlinear:
1361           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
1362           break;
1363         case NotifyNonlinearVirtual:
1364           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
1365           break;
1366         default:
1367           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
1368           break;
1369         }
1370       
1371       event->crossing.focus = xevent->xcrossing.focus;
1372       event->crossing.state = xevent->xcrossing.state;
1373   
1374       break;
1375       
1376     case LeaveNotify:
1377       /* Print debugging info.
1378        */
1379       GDK_NOTE (EVENTS, 
1380                 g_message ("leave notify:\t\twindow: %ld  detail: %d subwin: %ld",
1381                            xevent->xcrossing.window,
1382                            xevent->xcrossing.detail, xevent->xcrossing.subwindow));
1383       
1384       event->crossing.type = GDK_LEAVE_NOTIFY;
1385       event->crossing.window = window;
1386       
1387       /* If the subwindow field of the XEvent is non-NULL, then
1388        *  lookup the corresponding GdkWindow.
1389        */
1390       if (xevent->xcrossing.subwindow != None)
1391         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
1392       else
1393         event->crossing.subwindow = NULL;
1394       
1395       event->crossing.time = xevent->xcrossing.time;
1396       event->crossing.x = xevent->xcrossing.x;
1397       event->crossing.y = xevent->xcrossing.y;
1398       event->crossing.x_root = xevent->xcrossing.x_root;
1399       event->crossing.y_root = xevent->xcrossing.y_root;
1400       
1401       /* Translate the crossing mode into Gdk terms.
1402        */
1403       switch (xevent->xcrossing.mode)
1404         {
1405         case NotifyNormal:
1406           event->crossing.mode = GDK_CROSSING_NORMAL;
1407           break;
1408         case NotifyGrab:
1409           event->crossing.mode = GDK_CROSSING_GRAB;
1410           break;
1411         case NotifyUngrab:
1412           event->crossing.mode = GDK_CROSSING_UNGRAB;
1413           break;
1414         };
1415       
1416       /* Translate the crossing detail into Gdk terms.
1417        */
1418       switch (xevent->xcrossing.detail)
1419         {
1420         case NotifyInferior:
1421           event->crossing.detail = GDK_NOTIFY_INFERIOR;
1422           break;
1423         case NotifyAncestor:
1424           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
1425           break;
1426         case NotifyVirtual:
1427           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
1428           break;
1429         case NotifyNonlinear:
1430           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
1431           break;
1432         case NotifyNonlinearVirtual:
1433           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
1434           break;
1435         default:
1436           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
1437           break;
1438         }
1439       
1440       event->crossing.focus = xevent->xcrossing.focus;
1441       event->crossing.state = xevent->xcrossing.state;
1442       
1443       break;
1444       
1445     case FocusIn:
1446     case FocusOut:
1447       /* We only care about focus events that indicate that _this_
1448        * window (not a ancestor or child) got or lost the focus
1449        */
1450       switch (xevent->xfocus.detail)
1451         {
1452         case NotifyAncestor:
1453         case NotifyInferior:
1454         case NotifyNonlinear:
1455           /* Print debugging info.
1456            */
1457           GDK_NOTE (EVENTS,
1458                     g_message ("focus %s:\t\twindow: %ld",
1459                                (xevent->xany.type == FocusIn) ? "in" : "out",
1460                                xevent->xfocus.window));
1461           
1462           /* gdk_keyboard_grab() causes following events. These events confuse
1463            * the XIM focus, so ignore them.
1464            */
1465           if (xevent->xfocus.mode == NotifyGrab ||
1466               xevent->xfocus.mode == NotifyUngrab)
1467             break;
1468           
1469           event->focus_change.type = GDK_FOCUS_CHANGE;
1470           event->focus_change.window = window;
1471           event->focus_change.in = (xevent->xany.type == FocusIn);
1472
1473           break;
1474         default:
1475           return_val = FALSE;
1476         }
1477       break;
1478       
1479     case KeymapNotify:
1480       /* Print debugging info.
1481        */
1482       GDK_NOTE (EVENTS,
1483                 g_message ("keymap notify"));
1484
1485       /* Not currently handled */
1486       return_val = FALSE;
1487       break;
1488       
1489     case Expose:
1490       /* Print debugging info.
1491        */
1492       GDK_NOTE (EVENTS,
1493                 g_message ("expose:\t\twindow: %ld  %d  x,y: %d %d  w,h: %d %d",
1494                            xevent->xexpose.window, xevent->xexpose.count,
1495                            xevent->xexpose.x, xevent->xexpose.y,
1496                            xevent->xexpose.width, xevent->xexpose.height));
1497       gdk_compress_exposures (xevent, window);
1498       
1499       event->expose.type = GDK_EXPOSE;
1500       event->expose.window = window;
1501       event->expose.area.x = xevent->xexpose.x;
1502       event->expose.area.y = xevent->xexpose.y;
1503       event->expose.area.width = xevent->xexpose.width;
1504       event->expose.area.height = xevent->xexpose.height;
1505       event->expose.count = xevent->xexpose.count;
1506       
1507       break;
1508       
1509     case GraphicsExpose:
1510       /* Print debugging info.
1511        */
1512       GDK_NOTE (EVENTS,
1513                 g_message ("graphics expose:\tdrawable: %ld",
1514                            xevent->xgraphicsexpose.drawable));
1515       
1516       event->expose.type = GDK_EXPOSE;
1517       event->expose.window = window;
1518       event->expose.area.x = xevent->xgraphicsexpose.x;
1519       event->expose.area.y = xevent->xgraphicsexpose.y;
1520       event->expose.area.width = xevent->xgraphicsexpose.width;
1521       event->expose.area.height = xevent->xgraphicsexpose.height;
1522       event->expose.count = xevent->xexpose.count;
1523       
1524       break;
1525       
1526     case NoExpose:
1527       /* Print debugging info.
1528        */
1529       GDK_NOTE (EVENTS,
1530                 g_message ("no expose:\t\tdrawable: %ld",
1531                            xevent->xnoexpose.drawable));
1532       
1533       event->no_expose.type = GDK_NO_EXPOSE;
1534       event->no_expose.window = window;
1535       
1536       break;
1537       
1538     case VisibilityNotify:
1539       /* Print debugging info.
1540        */
1541 #ifdef G_ENABLE_DEBUG
1542       if (gdk_debug_flags & GDK_DEBUG_EVENTS)
1543         switch (xevent->xvisibility.state)
1544           {
1545           case VisibilityFullyObscured:
1546             g_message ("visibility notify:\twindow: %ld  none",
1547                        xevent->xvisibility.window);
1548             break;
1549           case VisibilityPartiallyObscured:
1550             g_message ("visibility notify:\twindow: %ld  partial",
1551                        xevent->xvisibility.window);
1552             break;
1553           case VisibilityUnobscured:
1554             g_message ("visibility notify:\twindow: %ld  full",
1555                        xevent->xvisibility.window);
1556             break;
1557           }
1558 #endif /* G_ENABLE_DEBUG */
1559       
1560       event->visibility.type = GDK_VISIBILITY_NOTIFY;
1561       event->visibility.window = window;
1562       
1563       switch (xevent->xvisibility.state)
1564         {
1565         case VisibilityFullyObscured:
1566           event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED;
1567           break;
1568           
1569         case VisibilityPartiallyObscured:
1570           event->visibility.state = GDK_VISIBILITY_PARTIAL;
1571           break;
1572           
1573         case VisibilityUnobscured:
1574           event->visibility.state = GDK_VISIBILITY_UNOBSCURED;
1575           break;
1576         }
1577       
1578       break;
1579       
1580     case CreateNotify:
1581       /* Not currently handled */
1582       break;
1583       
1584     case DestroyNotify:
1585       /* Print debugging info.
1586        */
1587       GDK_NOTE (EVENTS,
1588                 g_message ("destroy notify:\twindow: %ld",
1589                            xevent->xdestroywindow.window));
1590       
1591       event->any.type = GDK_DESTROY;
1592       event->any.window = window;
1593       
1594       return_val = window_private && !window_private->destroyed;
1595       
1596       if(window && window_private->xwindow != GDK_ROOT_WINDOW())
1597         gdk_window_destroy_notify (window);
1598       break;
1599       
1600     case UnmapNotify:
1601       /* Print debugging info.
1602        */
1603       GDK_NOTE (EVENTS,
1604                 g_message ("unmap notify:\t\twindow: %ld",
1605                            xevent->xmap.window));
1606       
1607       event->any.type = GDK_UNMAP;
1608       event->any.window = window;
1609       
1610       if (gdk_xgrab_window == window_private)
1611         gdk_xgrab_window = NULL;
1612       
1613       break;
1614       
1615     case MapNotify:
1616       /* Print debugging info.
1617        */
1618       GDK_NOTE (EVENTS,
1619                 g_message ("map notify:\t\twindow: %ld",
1620                            xevent->xmap.window));
1621       
1622       event->any.type = GDK_MAP;
1623       event->any.window = window;
1624       
1625       break;
1626       
1627     case ReparentNotify:
1628       /* Print debugging info.
1629        */
1630       GDK_NOTE (EVENTS,
1631                 g_message ("reparent notify:\twindow: %ld",
1632                            xevent->xreparent.window));
1633
1634       /* Not currently handled */
1635       return_val = FALSE;
1636       break;
1637       
1638     case ConfigureNotify:
1639       /* Print debugging info.
1640        */
1641       while ((XPending (gdk_display) > 0) &&
1642              XCheckTypedWindowEvent(gdk_display, xevent->xany.window,
1643                                     ConfigureNotify, xevent))
1644         {
1645           GdkFilterReturn result;
1646           
1647           GDK_NOTE (EVENTS, 
1648                     g_message ("configure notify discarded:\twindow: %ld",
1649                                xevent->xconfigure.window));
1650           
1651           result = gdk_event_apply_filters (xevent, event,
1652                                             window_private
1653                                             ?window_private->filters
1654                                             :gdk_default_filters);
1655           
1656           /* If the result is GDK_FILTER_REMOVE, there will be
1657            * trouble, but anybody who filtering the Configure events
1658            * better know what they are doing
1659            */
1660           if (result != GDK_FILTER_CONTINUE)
1661             {
1662               return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
1663             }
1664           
1665           /*XSync (gdk_display, 0);*/
1666         }
1667       
1668       
1669       GDK_NOTE (EVENTS,
1670                 g_message ("configure notify:\twindow: %ld  x,y: %d %d  w,h: %d %d  b-w: %d  above: %ld  ovr: %d",
1671                            xevent->xconfigure.window,
1672                            xevent->xconfigure.x,
1673                            xevent->xconfigure.y,
1674                            xevent->xconfigure.width,
1675                            xevent->xconfigure.height,
1676                            xevent->xconfigure.border_width,
1677                            xevent->xconfigure.above,
1678                            xevent->xconfigure.override_redirect));
1679       
1680       if (!window_private->destroyed &&
1681           (window_private->extension_events != 0) &&
1682           gdk_input_vtable.configure_event)
1683         gdk_input_vtable.configure_event (&xevent->xconfigure, window);
1684
1685       if (window_private->window_type == GDK_WINDOW_CHILD)
1686         return_val = FALSE;
1687       else
1688         {
1689           event->configure.type = GDK_CONFIGURE;
1690           event->configure.window = window;
1691           event->configure.width = xevent->xconfigure.width;
1692           event->configure.height = xevent->xconfigure.height;
1693           
1694           if (!xevent->xconfigure.x &&
1695               !xevent->xconfigure.y &&
1696               !window_private->destroyed)
1697             {
1698               gint tx = 0;
1699               gint ty = 0;
1700               Window child_window = 0;
1701               
1702               if (!XTranslateCoordinates (window_private->xdisplay,
1703                                           window_private->xwindow,
1704                                           gdk_root_window,
1705                                           0, 0,
1706                                           &tx, &ty,
1707                                           &child_window))
1708                 g_warning ("GdkWindow %ld doesn't share root windows display?",
1709                            window_private->xwindow);
1710               event->configure.x = tx;
1711               event->configure.y = ty;
1712             }
1713           else
1714             {
1715               event->configure.x = xevent->xconfigure.x;
1716               event->configure.y = xevent->xconfigure.y;
1717             }
1718           window_private->x = event->configure.x;
1719           window_private->y = event->configure.y;
1720           window_private->width = xevent->xconfigure.width;
1721           window_private->height = xevent->xconfigure.height;
1722           if (window_private->resize_count > 1)
1723             window_private->resize_count -= 1;
1724         }
1725       break;
1726       
1727     case PropertyNotify:
1728       /* Print debugging info.
1729        */
1730       GDK_NOTE (EVENTS,
1731                 g_message ("property notify:\twindow: %ld",
1732                            xevent->xproperty.window));
1733       
1734       event->property.type = GDK_PROPERTY_NOTIFY;
1735       event->property.window = window;
1736       event->property.atom = xevent->xproperty.atom;
1737       event->property.time = xevent->xproperty.time;
1738       event->property.state = xevent->xproperty.state;
1739       
1740       break;
1741       
1742     case SelectionClear:
1743       GDK_NOTE (EVENTS,
1744                 g_message ("selection clear:\twindow: %ld",
1745                            xevent->xproperty.window));
1746       
1747       event->selection.type = GDK_SELECTION_CLEAR;
1748       event->selection.window = window;
1749       event->selection.selection = xevent->xselectionclear.selection;
1750       event->selection.time = xevent->xselectionclear.time;
1751       
1752       break;
1753       
1754     case SelectionRequest:
1755       GDK_NOTE (EVENTS,
1756                 g_message ("selection request:\twindow: %ld",
1757                            xevent->xproperty.window));
1758       
1759       event->selection.type = GDK_SELECTION_REQUEST;
1760       event->selection.window = window;
1761       event->selection.selection = xevent->xselectionrequest.selection;
1762       event->selection.target = xevent->xselectionrequest.target;
1763       event->selection.property = xevent->xselectionrequest.property;
1764       event->selection.requestor = xevent->xselectionrequest.requestor;
1765       event->selection.time = xevent->xselectionrequest.time;
1766       
1767       break;
1768       
1769     case SelectionNotify:
1770       GDK_NOTE (EVENTS,
1771                 g_message ("selection notify:\twindow: %ld",
1772                            xevent->xproperty.window));
1773       
1774       
1775       event->selection.type = GDK_SELECTION_NOTIFY;
1776       event->selection.window = window;
1777       event->selection.selection = xevent->xselection.selection;
1778       event->selection.target = xevent->xselection.target;
1779       event->selection.property = xevent->xselection.property;
1780       event->selection.time = xevent->xselection.time;
1781       
1782       break;
1783       
1784     case ColormapNotify:
1785       /* Print debugging info.
1786        */
1787       GDK_NOTE (EVENTS,
1788                 g_message ("colormap notify:\twindow: %ld",
1789                            xevent->xcolormap.window));
1790       
1791       /* Not currently handled */
1792       return_val = FALSE;
1793       break;
1794       
1795     case ClientMessage:
1796       {
1797         GList *tmp_list;
1798         GdkFilterReturn result = GDK_FILTER_CONTINUE;
1799
1800         /* Print debugging info.
1801          */
1802         GDK_NOTE (EVENTS,
1803                   g_message ("client message:\twindow: %ld",
1804                              xevent->xclient.window));
1805         
1806         tmp_list = client_filters;
1807         while (tmp_list)
1808           {
1809             GdkClientFilter *filter = tmp_list->data;
1810             if (filter->type == xevent->xclient.message_type)
1811               {
1812                 result = (*filter->function) (xevent, event, filter->data);
1813                 break;
1814               }
1815             
1816             tmp_list = tmp_list->next;
1817           }
1818
1819         switch (result)
1820           {
1821           case GDK_FILTER_REMOVE:
1822             return_val = FALSE;
1823             break;
1824           case GDK_FILTER_TRANSLATE:
1825             return_val = TRUE;
1826             break;
1827           case GDK_FILTER_CONTINUE:
1828             /* Send unknown ClientMessage's on to Gtk for it to use */
1829             event->client.type = GDK_CLIENT_EVENT;
1830             event->client.window = window;
1831             event->client.message_type = xevent->xclient.message_type;
1832             event->client.data_format = xevent->xclient.format;
1833             memcpy(&event->client.data, &xevent->xclient.data,
1834                    sizeof(event->client.data));
1835           }
1836       }
1837       
1838       break;
1839       
1840     case MappingNotify:
1841       /* Print debugging info.
1842        */
1843       GDK_NOTE (EVENTS,
1844                 g_message ("mapping notify"));
1845       
1846       /* Let XLib know that there is a new keyboard mapping.
1847        */
1848       XRefreshKeyboardMapping (&xevent->xmapping);
1849       return_val = FALSE;
1850       break;
1851       
1852     default:
1853       /* something else - (e.g., a Xinput event) */
1854       
1855       if (window_private &&
1856           !window_private->destroyed &&
1857           (window_private->extension_events != 0) &&
1858           gdk_input_vtable.other_event)
1859         return_val = gdk_input_vtable.other_event(event, xevent, window);
1860       else
1861         return_val = FALSE;
1862       
1863       break;
1864     }
1865   
1866   if (return_val)
1867     {
1868       if (event->any.window)
1869         gdk_window_ref (event->any.window);
1870       if (((event->any.type == GDK_ENTER_NOTIFY) ||
1871            (event->any.type == GDK_LEAVE_NOTIFY)) &&
1872           (event->crossing.subwindow != NULL))
1873         gdk_window_ref (event->crossing.subwindow);
1874     }
1875   else
1876     {
1877       /* Mark this event as having no resources to be freed */
1878       event->any.window = NULL;
1879       event->any.type = GDK_NOTHING;
1880     }
1881   
1882   if (window)
1883     gdk_window_unref (window);
1884   
1885   return return_val;
1886 }
1887
1888 GdkFilterReturn
1889 gdk_wm_protocols_filter (GdkXEvent *xev,
1890                      GdkEvent  *event,
1891                      gpointer data)
1892 {
1893   XEvent *xevent = (XEvent *)xev;
1894
1895   if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window)
1896     {
1897   /* The delete window request specifies a window
1898    *  to delete. We don't actually destroy the
1899    *  window because "it is only a request". (The
1900    *  window might contain vital data that the
1901    *  program does not want destroyed). Instead
1902    *  the event is passed along to the program,
1903    *  which should then destroy the window.
1904    */
1905       GDK_NOTE (EVENTS,
1906                 g_message ("delete window:\t\twindow: %ld",
1907                            xevent->xclient.window));
1908       
1909       event->any.type = GDK_DELETE;
1910
1911       return GDK_FILTER_TRANSLATE;
1912     }
1913   else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
1914     {
1915     }
1916
1917   return GDK_FILTER_REMOVE;
1918 }
1919
1920 #if 0
1921 static Bool
1922 gdk_event_get_type (Display  *display,
1923                     XEvent   *xevent,
1924                     XPointer  arg)
1925 {
1926   GdkEvent event;
1927   GdkPredicate *pred;
1928   
1929   if (gdk_event_translate (&event, xevent))
1930     {
1931       pred = (GdkPredicate*) arg;
1932       return (* pred->func) (&event, pred->data);
1933     }
1934   
1935   return FALSE;
1936 }
1937 #endif
1938
1939 static void
1940 gdk_events_queue (void)
1941 {
1942   GList *node;
1943   GdkEvent *event;
1944   XEvent xevent;
1945
1946   while (!gdk_event_queue_find_first() && XPending (gdk_display))
1947     {
1948   #ifdef USE_XIM
1949       Window w = None;
1950       
1951       XNextEvent (gdk_display, &xevent);
1952       if (gdk_xim_window)
1953         switch (xevent.type)
1954           {
1955           case KeyPress:
1956           case KeyRelease:
1957           case ButtonPress:
1958           case ButtonRelease:
1959             w = GDK_WINDOW_XWINDOW (gdk_xim_window);
1960             break;
1961           }
1962       
1963       if (XFilterEvent (&xevent, w))
1964         continue;
1965 #else
1966       XNextEvent (gdk_display, &xevent);
1967 #endif
1968       
1969       event = gdk_event_new ();
1970       
1971       event->any.type = GDK_NOTHING;
1972       event->any.window = NULL;
1973       event->any.send_event = FALSE;
1974       event->any.send_event = xevent.xany.send_event;
1975
1976       ((GdkEventPrivate *)event)->flags |= GDK_EVENT_PENDING;
1977
1978       gdk_event_queue_append (event);
1979       node = queued_tail;
1980
1981       if (gdk_event_translate (event, &xevent))
1982         {
1983           ((GdkEventPrivate *)event)->flags &= ~GDK_EVENT_PENDING;
1984         }
1985       else
1986         {
1987           gdk_event_queue_remove_link (node);
1988           g_list_free_1 (node);
1989           gdk_event_free (event);
1990         }
1991     }
1992 }
1993
1994 static gboolean  
1995 gdk_event_prepare (gpointer  source_data, 
1996                    GTimeVal *current_time,
1997                    gint     *timeout)
1998 {
1999   gboolean retval;
2000   
2001   GDK_THREADS_ENTER ();
2002
2003   *timeout = -1;
2004
2005   retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
2006
2007   GDK_THREADS_LEAVE ();
2008
2009   return retval;
2010 }
2011
2012 static gboolean  
2013 gdk_event_check   (gpointer  source_data,
2014                    GTimeVal *current_time)
2015 {
2016   gboolean retval;
2017   
2018   GDK_THREADS_ENTER ();
2019
2020   if (event_poll_fd.revents & G_IO_IN)
2021     retval = (gdk_event_queue_find_first () != NULL) || XPending (gdk_display);
2022   else
2023     retval = FALSE;
2024
2025   GDK_THREADS_LEAVE ();
2026
2027   return retval;
2028 }
2029
2030 static GdkEvent *
2031 gdk_event_unqueue (void)
2032 {
2033   GdkEvent *event = NULL;
2034   GList *tmp_list;
2035
2036   tmp_list = gdk_event_queue_find_first ();
2037
2038   if (tmp_list)
2039     {
2040       event = tmp_list->data;
2041       gdk_event_queue_remove_link (tmp_list);
2042       g_list_free_1 (tmp_list);
2043     }
2044
2045   return event;
2046 }
2047
2048 static gboolean  
2049 gdk_event_dispatch (gpointer  source_data,
2050                     GTimeVal *current_time,
2051                     gpointer  user_data)
2052 {
2053   GdkEvent *event;
2054  
2055   GDK_THREADS_ENTER ();
2056
2057   gdk_events_queue();
2058   event = gdk_event_unqueue();
2059
2060   if (event)
2061     {
2062       if (event_func)
2063         (*event_func) (event, event_data);
2064       
2065       gdk_event_free (event);
2066     }
2067   
2068   GDK_THREADS_LEAVE ();
2069
2070   return TRUE;
2071 }
2072
2073 static void
2074 gdk_synthesize_click (GdkEvent *event,
2075                       gint      nclicks)
2076 {
2077   GdkEvent temp_event;
2078   
2079   g_return_if_fail (event != NULL);
2080   
2081   temp_event = *event;
2082   temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
2083   
2084   gdk_event_put (&temp_event);
2085 }
2086
2087 /* Sends a ClientMessage to all toplevel client windows */
2088 gboolean
2089 gdk_event_send_client_message (GdkEvent *event, guint32 xid)
2090 {
2091   XEvent sev;
2092   
2093   g_return_val_if_fail(event != NULL, FALSE);
2094   
2095   /* Set up our event to send, with the exception of its target window */
2096   sev.xclient.type = ClientMessage;
2097   sev.xclient.display = gdk_display;
2098   sev.xclient.format = event->client.data_format;
2099   sev.xclient.window = xid;
2100   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
2101   sev.xclient.message_type = event->client.message_type;
2102   
2103   return gdk_send_xevent (xid, False, NoEventMask, &sev);
2104 }
2105
2106 /* Sends a ClientMessage to all toplevel client windows */
2107 gboolean
2108 gdk_event_send_client_message_to_all_recurse (XEvent  *xev, 
2109                                               guint32  xid,
2110                                               guint    level)
2111 {
2112   static GdkAtom wm_state_atom = GDK_NONE;
2113
2114   Atom type = None;
2115   int format;
2116   unsigned long nitems, after;
2117   unsigned char *data;
2118   
2119   Window *ret_children, ret_root, ret_parent;
2120   unsigned int ret_nchildren;
2121   int i;
2122   
2123   gboolean send = FALSE;
2124   gboolean found = FALSE;
2125
2126   if (!wm_state_atom)
2127     wm_state_atom = gdk_atom_intern ("WM_STATE", FALSE);
2128
2129   gdk_error_code = 0;
2130   XGetWindowProperty (gdk_display, xid, wm_state_atom, 0, 0, False, AnyPropertyType,
2131                       &type, &format, &nitems, &after, &data);
2132
2133   if (gdk_error_code)
2134     {
2135       gdk_error_code = 0;
2136       return FALSE;
2137     }
2138
2139   if (type)
2140     {
2141       send = TRUE;
2142       XFree (data);
2143     }
2144   else
2145     {
2146       /* OK, we're all set, now let's find some windows to send this to */
2147       if (XQueryTree(gdk_display, xid, &ret_root, &ret_parent,
2148                      &ret_children, &ret_nchildren) != True)
2149         return FALSE;
2150       
2151       if (gdk_error_code)
2152         return FALSE;
2153
2154       for(i = 0; i < ret_nchildren; i++)
2155         if (gdk_event_send_client_message_to_all_recurse(xev, ret_children[i], level + 1))
2156           found = TRUE;
2157
2158       XFree(ret_children);
2159     }
2160
2161   if (send || (!found && (level == 1)))
2162     {
2163       xev->xclient.window = xid;
2164       gdk_send_xevent (xid, False, NoEventMask, xev);
2165     }
2166
2167   return (send || found);
2168 }
2169
2170 void
2171 gdk_event_send_clientmessage_toall (GdkEvent *event)
2172 {
2173   XEvent sev;
2174   gint old_warnings = gdk_error_warnings;
2175
2176   g_return_if_fail(event != NULL);
2177   
2178   /* Set up our event to send, with the exception of its target window */
2179   sev.xclient.type = ClientMessage;
2180   sev.xclient.display = gdk_display;
2181   sev.xclient.format = event->client.data_format;
2182   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
2183   sev.xclient.message_type = event->client.message_type;
2184
2185   gdk_event_send_client_message_to_all_recurse(&sev, gdk_root_window, 0);
2186
2187   gdk_error_warnings = old_warnings;
2188 }
2189
2190 /*
2191  *--------------------------------------------------------------
2192  * gdk_flush
2193  *
2194  *   Flushes the Xlib output buffer and then waits
2195  *   until all requests have been received and processed
2196  *   by the X server. The only real use for this function
2197  *   is in dealing with XShm.
2198  *
2199  * Arguments:
2200  *
2201  * Results:
2202  *
2203  * Side effects:
2204  *
2205  *--------------------------------------------------------------
2206  */
2207
2208 void gdk_flush (void)
2209 {
2210   XSync (gdk_display, False);
2211 }
2212
2213