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