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