]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkmain-x11.c
A couple of compiler warning fixes, GtkCList signal changes, changed
[~andy/gtk] / gdk / x11 / gdkmain-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 Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 #include "../config.h"
19
20 /* #define DEBUG_DND 1 */ /* Shouldn't be needed much these days */
21
22 /* If you don't want to use gdk's signal handlers define this */
23 /* #define I_NEED_TO_ACTUALLY_DEBUG_MY_PROGRAMS 1 */
24
25 #include <X11/Xlocale.h>
26 #include <ctype.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <limits.h>
32 #ifdef USE_XIM
33 #include <stdarg.h>
34 #endif
35
36 #ifdef HAVE_SYS_SELECT_H
37 #include <sys/select.h>
38 #endif /* HAVE_SYS_SELECT_H_ */
39
40 #define XLIB_ILLEGAL_ACCESS
41 #include <X11/Xatom.h>
42 #include <X11/Xlib.h>
43 #include <X11/Xos.h>
44 #include <X11/Xutil.h>
45 #include <X11/Xmu/WinUtil.h>
46 #ifdef USE_XIM
47 #include <X11/Xresource.h>
48 #endif
49 #include <X11/cursorfont.h>
50 #include "gdk.h"
51 #include "gdkprivate.h"
52 #include "gdkinput.h"
53 #ifdef USE_XIM
54 #include "gdkx.h"
55 #include "gdkkeysyms.h"
56 #endif
57 #include "gdki18n.h"
58
59 #ifndef X_GETTIMEOFDAY
60 #define X_GETTIMEOFDAY(tv)  gettimeofday (tv, NULL)
61 #endif /* X_GETTIMEOFDAY */
62
63
64 #define DOUBLE_CLICK_TIME      250
65 #define TRIPLE_CLICK_TIME      500
66 #define DOUBLE_CLICK_DIST      5
67 #define TRIPLE_CLICK_DIST      5
68
69
70 #ifndef NO_FD_SET
71 #  define SELECT_MASK fd_set
72 #else
73 #  ifndef _AIX
74      typedef long fd_mask;
75 #  endif
76 #  if defined(_IBMR2)
77 #    define SELECT_MASK void
78 #  else
79 #    define SELECT_MASK int
80 #  endif
81 #endif
82
83
84 typedef struct _GdkInput      GdkInput;
85 typedef struct _GdkPredicate  GdkPredicate;
86
87 struct _GdkInput
88 {
89   gint tag;
90   gint source;
91   GdkInputCondition condition;
92   GdkInputFunction function;
93   gpointer data;
94   GdkDestroyNotify destroy;
95 };
96
97 struct _GdkPredicate
98 {
99   GdkEventFunc func;
100   gpointer data;
101 };
102
103 /* 
104  * Private function declarations
105  */
106
107 static GdkEvent *gdk_event_new          (void);
108 static gint      gdk_event_wait         (void);
109 static gint      gdk_event_apply_filters (XEvent *xevent,
110                                           GdkEvent *event,
111                                           GList *filters);
112 static gint      gdk_event_translate    (GdkEvent     *event, 
113                                          XEvent       *xevent);
114 #if 0
115 static Bool      gdk_event_get_type     (Display      *display, 
116                                          XEvent       *xevent, 
117                                          XPointer      arg);
118 #endif
119 static void      gdk_synthesize_click   (GdkEvent     *event, 
120                                          gint          nclicks);
121
122 static void      gdk_dnd_drag_begin     (GdkWindow    *initial_window);
123 static void      gdk_dnd_drag_enter     (Window        dest);
124 static void      gdk_dnd_drag_leave     (Window        dest);
125 static void      gdk_dnd_drag_end       (Window        dest,
126                                          GdkPoint      coords);
127 static GdkAtom   gdk_dnd_check_types    (GdkWindow    *window,
128                                          XEvent       *xevent);
129 #ifdef DEBUG_DND
130 static void      gdk_print_atom         (GdkAtom       anatom);
131 #endif
132
133 /* 
134  * old junk from offix, we might use it though so leave it 
135  */
136 Window       gdk_get_client_window   (Display     *dpy, 
137                                       Window       win);
138 #ifdef WE_HAVE_MOTIF_DROPS_DONE
139 static GdkWindow *  gdk_drop_get_real_window     (GdkWindow   *w, 
140                                                   guint16     *x,
141                                                   guint16     *y);
142 #endif
143 static void         gdk_exit_func                (void);
144 static int          gdk_x_error                  (Display     *display, 
145                                                   XErrorEvent *error);
146 static int          gdk_x_io_error               (Display     *display);
147 static RETSIGTYPE   gdk_signal                   (int          signum);
148
149
150 #ifdef USE_XIM
151 static GdkIM  gdk_im_get                (void);
152 static gint   gdk_im_open               (XrmDatabase db,
153                                          gchar* res_name,
154                                          gchar* rec_class);
155 static void   gdk_im_close              (void);
156 static void   gdk_ic_cleanup            (void);
157 #endif /* USE_XIM */
158
159 /* Private variable declarations
160  */
161 static int initialized = 0;                         /* 1 if the library is initialized,
162                                                      * 0 otherwise.
163                                                      */
164 static int connection_number = 0;                   /* The file descriptor number of our
165                                                      *  connection to the X server. This
166                                                      *  is used so that we may determine
167                                                      *  when events are pending by using
168                                                      *  the "select" system call.
169                                                      */
170
171
172 static struct timeval start;                        /* The time at which the library was
173                                                      *  last initialized.
174                                                      */
175 static struct timeval timer;                        /* Timeout interval to use in the call
176                                                      *  to "select". This is used in
177                                                      *  conjunction with "timerp" to create
178                                                      *  a maximum time to wait for an event
179                                                      *  to arrive.
180                                                      */
181 static struct timeval *timerp;                      /* The actual timer passed to "select"
182                                                      *  This may be NULL, in which case
183                                                      *  "select" will block until an event
184                                                      *  arrives.
185                                                      */
186 static guint32 timer_val;                           /* The timeout length as specified by
187                                                      *  the user in milliseconds.
188                                                      */
189 static GList *inputs;                               /* A list of the input file descriptors
190                                                      *  that we care about. Each list node
191                                                      *  contains a GdkInput struct that describes
192                                                      *  when we are interested in the specified
193                                                      *  file descriptor. That is, when it is
194                                                      *  available for read, write or has an
195                                                      *  exception pending.
196                                                      */
197 static guint32 button_click_time[2];                /* The last 2 button click times. Used
198                                                      *  to determine if the latest button click
199                                                      *  is part of a double or triple click.
200                                                      */
201 static GdkWindow *button_window[2];                 /* The last 2 windows to receive button presses.
202                                                      *  Also used to determine if the latest button
203                                                      *  click is part of a double or triple click.
204                                                      */
205 static guint button_number[2];                      /* The last 2 buttons to be pressed.
206                                                      */
207 static GdkWindowPrivate *xgrab_window = NULL;       /* Window that currently holds the
208                                                      *  x pointer grab
209                                                      */
210
211 #ifdef USE_XIM
212 static gint xim_using;                          /* using XIM Protocol if TRUE */
213 static GdkIM xim_im;                            /* global IM */
214 static XIMStyles* xim_styles;                   /* im supports these styles */
215 static XIMStyle xim_best_allowed_style;
216 static GdkICPrivate *xim_ic;                    /* currently using IC */
217 static GdkWindow* xim_window;                   /* currently using Widow */
218 static GList* xim_ic_list;
219
220 #endif
221
222 #define OTHER_XEVENT_BUFSIZE 4
223 static XEvent other_xevent[OTHER_XEVENT_BUFSIZE];   /* XEvents passed along to user  */
224 static int other_xevent_i = 0;
225 static GList *putback_events = NULL;
226
227 static gulong base_id;
228 static gint autorepeat;
229
230
231 /*
232  *--------------------------------------------------------------
233  * gdk_init
234  *
235  *   Initialize the library for use.
236  *
237  * Arguments:
238  *   "argc" is the number of arguments.
239  *   "argv" is an array of strings.
240  *
241  * Results:
242  *   "argc" and "argv" are modified to reflect any arguments
243  *   which were not handled. (Such arguments should either
244  *   be handled by the application or dismissed).
245  *
246  * Side effects:
247  *   The library is initialized.
248  *
249  *--------------------------------------------------------------
250  */
251
252 void
253 gdk_init (int    *argc,
254           char ***argv)
255 {
256   XKeyboardState keyboard_state;
257   int synchronize;
258   int i, j, k;
259   XClassHint *class_hint;
260   int argc_orig = *argc;
261   char **argv_orig;
262
263   argv_orig = malloc ((argc_orig + 1) * sizeof (char*));
264   for (i = 0; i < argc_orig; i++)
265     argv_orig[i] = g_strdup ((*argv)[i]);
266   argv_orig[argc_orig] = NULL;
267
268   X_GETTIMEOFDAY (&start);
269
270 #ifndef I_NEED_TO_ACTUALLY_DEBUG_MY_PROGRAMS
271   signal (SIGHUP, gdk_signal);
272   signal (SIGINT, gdk_signal);
273   signal (SIGQUIT, gdk_signal);
274   signal (SIGBUS, gdk_signal);
275   signal (SIGSEGV, gdk_signal);
276   signal (SIGPIPE, gdk_signal);
277   signal (SIGTERM, gdk_signal);
278 #endif
279
280   gdk_display_name = NULL;
281
282   XSetErrorHandler (gdk_x_error);
283   XSetIOErrorHandler (gdk_x_io_error);
284
285   synchronize = FALSE;
286
287   if (argc && argv)
288     {
289       if (*argc > 0)
290         gdk_progname = (*argv)[0];
291
292       for (i = 1; i < *argc;)
293         {
294           if (strcmp ("--display", (*argv)[i]) == 0)
295             {
296               (*argv)[i] = NULL;
297
298               if ((i + 1) < *argc)
299                 {
300                   gdk_display_name = g_strdup ((*argv)[i + 1]);
301                   (*argv)[i + 1] = NULL;
302                   i += 1;
303                 }
304             }
305           else if (strcmp ("--sync", (*argv)[i]) == 0)
306             {
307               (*argv)[i] = NULL;
308               synchronize = TRUE;
309             }
310           else if (strcmp ("--show-events", (*argv)[i]) == 0)
311             {
312               (*argv)[i] = NULL;
313               gdk_show_events = TRUE;
314             }
315           else if (strcmp ("--no-show-events", (*argv)[i]) == 0)
316             {
317               (*argv)[i] = NULL;
318               gdk_show_events = FALSE;
319             }
320           else if (strcmp ("--no-xshm", (*argv)[i]) == 0)
321             {
322               (*argv)[i] = NULL;
323               gdk_use_xshm = FALSE;
324             }
325           else if (strcmp ("--debug-level", (*argv)[i]) == 0)
326             {
327               if ((i + 1) < *argc)
328                 {
329                   (*argv)[i++] = NULL;
330                   gdk_debug_level = atoi ((*argv)[i]);
331                   (*argv)[i] = NULL;
332                 }
333             }
334           else if (strcmp ("--name", (*argv)[i]) == 0)
335             {
336               if ((i + 1) < *argc)
337                 {
338                   (*argv)[i++] = NULL;
339                   gdk_progname = (*argv)[i];
340                   (*argv)[i] = NULL;
341                 }
342             }
343           else if (strcmp ("--class", (*argv)[i]) == 0)
344             {
345               if ((i + 1) < *argc)
346                 {
347                   (*argv)[i++] = NULL;
348                   gdk_progclass = (*argv)[i];
349                   (*argv)[i] = NULL;
350                 }
351             }
352 #ifdef XINPUT_GXI
353           else if (strcmp ("--gxid_host", (*argv)[i]) == 0)
354             {
355               if ((i + 1) < *argc)
356                 {
357                   (*argv)[i++] = NULL;
358                   gdk_input_gxid_host = ((*argv)[i]);
359                   (*argv)[i] = NULL;
360                 }
361             }
362           else if (strcmp ("--gxid_port", (*argv)[i]) == 0)
363             {
364               if ((i + 1) < *argc)
365                 {
366                   (*argv)[i++] = NULL;
367                   gdk_input_gxid_port = atoi ((*argv)[i]);
368                   (*argv)[i] = NULL;
369                 }
370             }
371 #endif
372 #ifdef USE_XIM
373           else if (strcmp ("--xim-preedit", (*argv)[i]) == 0)
374             {
375               if ((i + 1) < *argc)
376                 {
377                   (*argv)[i++] = NULL;
378                   if (strcmp ("none", (*argv)[i]) == 0)
379                     gdk_im_set_best_style (GdkIMPreeditNone);
380                   else if (strcmp ("nothing", (*argv)[i]) == 0)
381                     gdk_im_set_best_style (GdkIMPreeditNothing);
382                   else if (strcmp ("area", (*argv)[i]) == 0)
383                     gdk_im_set_best_style (GdkIMPreeditArea);
384                   else if (strcmp ("position", (*argv)[i]) == 0)
385                     gdk_im_set_best_style (GdkIMPreeditPosition);
386                   else if (strcmp ("callbacks", (*argv)[i]) == 0)
387                     gdk_im_set_best_style (GdkIMPreeditCallbacks);
388                 }
389             }
390           else if (strcmp ("--xim-status", (*argv)[i]) == 0)
391             {
392               if ((i + 1) < *argc)
393                 {
394                   (*argv)[i++] = NULL;
395                   if (strcmp ("none", (*argv)[i]) == 0)
396                     gdk_im_set_best_style (GdkIMStatusNone);
397                   else if (strcmp ("nothing", (*argv)[i]) == 0)
398                     gdk_im_set_best_style (GdkIMStatusNothing);
399                   else if (strcmp ("area", (*argv)[i]) == 0)
400                     gdk_im_set_best_style (GdkIMStatusArea);
401                   else if (strcmp ("callbacks", (*argv)[i]) == 0)
402                     gdk_im_set_best_style (GdkIMStatusCallbacks);
403                 }
404             }
405 #endif
406
407           i += 1;
408         }
409
410       for (i = 1; i < *argc; i++)
411         {
412           for (k = i; k < *argc; k++)
413             if ((*argv)[k] != NULL)
414               break;
415
416           if (k > i)
417             {
418               k -= i;
419               for (j = i + k; j < *argc; j++)
420                 (*argv)[j-k] = (*argv)[j];
421               *argc -= k;
422             }
423         }
424     }
425   else
426     {
427       gdk_progname = "<unknown>";
428     }
429
430   gdk_display = XOpenDisplay (gdk_display_name);
431   if (!gdk_display)
432     {
433       g_warning ("cannot open display: %s", XDisplayName (gdk_display_name));
434       exit(1);
435     }
436
437   /* This is really crappy. We have to look into the display structure
438    *  to find the base resource id. This is only needed for recording
439    *  and playback of events.
440    */
441   /* base_id = RESOURCE_BASE; */
442   base_id = 0;
443   if (gdk_show_events)
444     g_print ("base id: %lu\n", base_id);
445
446   connection_number = ConnectionNumber (gdk_display);
447   if (gdk_debug_level >= 1)
448     g_print ("connection number: %d\n", connection_number);
449
450   if (synchronize)
451     XSynchronize (gdk_display, True);
452
453   gdk_screen = DefaultScreen (gdk_display);
454   gdk_root_window = RootWindow (gdk_display, gdk_screen);
455
456   gdk_leader_window = XCreateSimpleWindow(gdk_display, gdk_root_window,
457                                           10, 10, 10, 10, 0, 0 , 0);
458   class_hint = XAllocClassHint();
459   class_hint->res_name = gdk_progname;
460   if (gdk_progclass == NULL)
461     {
462       gdk_progclass = g_strdup (gdk_progname);
463       gdk_progclass[0] = toupper (gdk_progclass[0]);
464     }
465   class_hint->res_class = gdk_progclass;
466   XSetClassHint(gdk_display, gdk_leader_window, class_hint);
467   XSetCommand(gdk_display, gdk_leader_window, argv_orig, argc_orig);
468   XFree (class_hint);
469
470   gdk_wm_delete_window = XInternAtom (gdk_display, "WM_DELETE_WINDOW", True);
471   gdk_wm_take_focus = XInternAtom (gdk_display, "WM_TAKE_FOCUS", True);
472   gdk_wm_protocols = XInternAtom (gdk_display, "WM_PROTOCOLS", True);
473   gdk_wm_window_protocols[0] = gdk_wm_delete_window;
474   gdk_wm_window_protocols[1] = gdk_wm_take_focus;
475   gdk_selection_property = XInternAtom (gdk_display, "GDK_SELECTION", False);
476
477   gdk_dnd.gdk_XdeEnter = gdk_atom_intern("_XDE_ENTER", FALSE);
478   gdk_dnd.gdk_XdeLeave = gdk_atom_intern("_XDE_LEAVE", FALSE);
479   gdk_dnd.gdk_XdeRequest = gdk_atom_intern("_XDE_REQUEST", FALSE);
480   gdk_dnd.gdk_XdeDataAvailable = gdk_atom_intern("_XDE_DATA_AVAILABLE", FALSE);
481   gdk_dnd.gdk_XdeTypelist = gdk_atom_intern("_XDE_TYPELIST", FALSE);
482   gdk_dnd.gdk_cursor_dragdefault = XCreateFontCursor(gdk_display, XC_bogosity);
483   gdk_dnd.gdk_cursor_dragok = XCreateFontCursor(gdk_display, XC_heart);
484
485   XGetKeyboardControl (gdk_display, &keyboard_state);
486   autorepeat = keyboard_state.global_auto_repeat;
487
488   timer.tv_sec = 0;
489   timer.tv_usec = 0;
490   timerp = NULL;
491
492   button_click_time[0] = 0;
493   button_click_time[1] = 0;
494   button_window[0] = NULL;
495   button_window[1] = NULL;
496   button_number[0] = -1;
497   button_number[1] = -1;
498
499   if (ATEXIT (gdk_exit_func))
500     g_warning ("unable to register exit function");
501
502   gdk_visual_init ();
503   gdk_window_init ();
504   gdk_image_init ();
505   gdk_input_init ();
506
507 #ifdef USE_XIM
508   /* initialize XIM Protocol variables */
509   xim_using = FALSE;
510   xim_im = NULL;
511   xim_styles = NULL;
512   if (!(xim_best_allowed_style & GdkIMPreeditMask))
513     gdk_im_set_best_style (GdkIMPreeditCallbacks);
514   if (!(xim_best_allowed_style & GdkIMStatusMask))
515     gdk_im_set_best_style (GdkIMStatusCallbacks);
516   xim_ic = NULL;
517   xim_window = (GdkWindow*)NULL;
518
519   gdk_im_open (NULL, NULL, NULL);
520   if (gdk_im_get () == NULL)
521     g_warning ("unable to open input method.");
522 #endif
523
524   initialized = 1;
525 }
526
527 /*
528  *--------------------------------------------------------------
529  * gdk_exit
530  *
531  *   Restores the library to an un-itialized state and exits
532  *   the program using the "exit" system call.
533  *
534  * Arguments:
535  *   "errorcode" is the error value to pass to "exit".
536  *
537  * Results:
538  *   Allocated structures are freed and the program exits
539  *   cleanly.
540  *
541  * Side effects:
542  *
543  *--------------------------------------------------------------
544  */
545
546 void
547 gdk_exit (int errorcode)
548 {
549  /* de-initialisation is done by the gdk_exit_funct(),
550     no need to do this here (Alex J.) */
551  exit (errorcode);
552 }
553
554 /*
555  *--------------------------------------------------------------
556  * gdk_set_locale
557  *
558  * Arguments:
559  *
560  * Results:
561  *
562  * Side effects:
563  *
564  *--------------------------------------------------------------
565  */
566
567 gchar*
568 gdk_set_locale ()
569 {
570   if (!setlocale (LC_ALL,""))
571     g_print ("locale not supported by C library\n");
572
573   if (!XSupportsLocale ())
574     {
575       g_print ("locale not supported by Xlib, locale set to C\n");
576       setlocale (LC_ALL, "C");
577     }
578
579   if (!XSetLocaleModifiers (""))
580     {
581       g_print ("can not set locale modifiers\n");
582     }
583
584   return setlocale (LC_ALL,NULL);
585 }
586
587 /*
588  *--------------------------------------------------------------
589  * gdk_events_pending
590  *
591  *   Returns the number of events pending on the queue.
592  *   These events have already been read from the server
593  *   connection.
594  *
595  * Arguments:
596  *
597  * Results:
598  *   Returns the number of events on XLib's event queue.
599  *
600  * Side effects:
601  *
602  *--------------------------------------------------------------
603  */
604
605 gint
606 gdk_events_pending ()
607 {
608   gint result;
609   GList *tmp_list;
610
611   result = XPending (gdk_display);
612
613   tmp_list = putback_events;
614   while (tmp_list)
615     {
616       result++;
617       tmp_list = tmp_list->next;
618     }
619   
620   return result;
621 }
622
623 /*
624  *--------------------------------------------------------------
625  * gdk_event_get_graphics_expose
626  *
627  *   Waits for a GraphicsExpose or NoExpose event
628  *
629  * Arguments:
630  *
631  * Results: 
632  *   For GraphicsExpose events, returns a pointer to the event
633  *   converted into a GdkEvent Otherwise, returns NULL.
634  *
635  * Side effects:
636  *
637  *-------------------------------------------------------------- */
638
639 static Bool
640 graphics_expose_predicate  (Display  *display,
641                             XEvent   *xevent,
642                             XPointer  arg)
643 {
644   GdkWindowPrivate *private = (GdkWindowPrivate *)arg;
645   
646   g_return_val_if_fail (private != NULL, False);
647
648   if ((xevent->xany.window == private->xwindow) &&
649       ((xevent->xany.type == GraphicsExpose) ||
650        (xevent->xany.type == NoExpose)))
651     return True;
652   else
653     return False;
654 }
655
656 GdkEvent *
657 gdk_event_get_graphics_expose (GdkWindow *window)
658 {
659   XEvent xevent;
660   GdkEvent *event;
661   
662   g_return_val_if_fail (window != NULL, NULL);
663
664   XIfEvent (gdk_display, &xevent, graphics_expose_predicate, (XPointer)window);
665
666   if (xevent.xany.type == GraphicsExpose)
667     {
668       event = gdk_event_new ();
669
670       if (gdk_event_translate (event, &xevent))
671         return event;
672       else
673         gdk_event_free (event);
674     }
675   
676   return NULL;  
677 }
678
679 /*
680  *--------------------------------------------------------------
681  * gdk_event_get
682  *
683  *   Gets the next event.
684  *
685  * Arguments:
686  *
687  * Results:
688  *   If an event was received that we care about, returns 
689  *   a pointer to that event, to be freed with gdk_event_free.
690  *   Otherwise, returns NULL. This function will also return
691  *   before an event is received if the timeout interval
692  *   runs out.
693  *
694  * Side effects:
695  *
696  *--------------------------------------------------------------
697  */
698
699 GdkEvent *
700 gdk_event_get (void)
701 {
702   GdkEvent *event;
703   GList *temp_list;
704   XEvent xevent;
705
706 #if 0
707   if (pred)
708     {
709       temp_list = putback_events;
710       while (temp_list)
711         {
712           temp_event = temp_list->data;
713
714           if ((* pred) (temp_event, data))
715             {
716               if (event)
717                 *event = *temp_event;
718               putback_events = g_list_remove_link (putback_events, temp_list);
719               g_list_free (temp_list);
720               return TRUE;
721             }
722
723           temp_list = temp_list->next;
724         }
725
726       event_pred.func = pred;
727       event_pred.data = data;
728
729       if (XCheckIfEvent (gdk_display, &xevent, gdk_event_get_type, (XPointer) & event_pred))
730         if (event)
731           return gdk_event_translate (event, &xevent);
732     }
733   else
734 #endif
735   if (putback_events)
736     {
737       event = putback_events->data;
738       
739       temp_list = putback_events;
740       putback_events = g_list_remove_link (putback_events, temp_list);
741       g_list_free_1 (temp_list);
742       
743       return event;
744     }
745   
746   /* Wait for an event to occur or the timeout to elapse.
747    * If an event occurs "gdk_event_wait" will return TRUE.
748    *  If the timeout elapses "gdk_event_wait" will return
749    *  FALSE.
750    */
751   if (gdk_event_wait ())
752     {
753       /* If we get here we can rest assurred that an event
754        *  has occurred. Read it.
755        */
756 #ifdef USE_XIM
757       gint filter_status;
758       if (xim_using && xim_window)
759         do
760           {             /* don't dispatch events used by IM */
761             XNextEvent (gdk_display, &xevent);
762             filter_status = XFilterEvent (&xevent, 
763                                           GDK_WINDOW_XWINDOW (xim_window));
764           } while (filter_status == True);
765       else
766         XNextEvent (gdk_display, &xevent);
767 #else
768       XNextEvent (gdk_display, &xevent);
769 #endif
770       event = gdk_event_new ();
771
772       event->any.type = GDK_NOTHING;
773       event->any.window = NULL;
774       event->any.send_event = FALSE;
775       event->any.send_event = xevent.xany.send_event;
776       
777       if (gdk_event_translate (event, &xevent))
778         return event;
779       else
780         gdk_event_free (event);
781     }
782
783   return NULL;
784 }
785
786 void
787 gdk_event_put (GdkEvent *event)
788 {
789   GdkEvent *new_event;
790
791   g_return_if_fail (event != NULL);
792
793   new_event = gdk_event_copy (event);
794
795   putback_events = g_list_prepend (putback_events, new_event);
796 }
797
798 /*
799  *--------------------------------------------------------------
800  * gdk_event_copy
801  *
802  *   Copy a event structure into new storage.
803  *
804  * Arguments:
805  *   "event" is the event struct to copy.
806  *
807  * Results:
808  *   A new event structure.  Free it with gdk_event_free.
809  *
810  * Side effects:
811  *   The reference count of the window in the event is increased.
812  *
813  *--------------------------------------------------------------
814  */
815
816 static GMemChunk *event_chunk;
817
818 static GdkEvent*
819 gdk_event_new (void)
820 {
821   GdkEvent *new_event;
822   
823   if (event_chunk == NULL)
824     event_chunk = g_mem_chunk_new ("events",
825                                    sizeof (GdkEvent),
826                                    4096,
827                                    G_ALLOC_AND_FREE);
828
829   new_event = g_chunk_new (GdkEvent, event_chunk);
830
831   return new_event;
832 }
833
834 GdkEvent*
835 gdk_event_copy (GdkEvent *event)
836 {
837   GdkEvent *new_event;
838   
839   g_return_val_if_fail (event != NULL, NULL);
840
841   new_event = gdk_event_new ();
842
843   *new_event = *event;
844   gdk_window_ref (new_event->any.window);
845
846   switch (event->any.type)
847     {
848     case GDK_KEY_PRESS:
849     case GDK_KEY_RELEASE:
850       new_event->key.string = g_strdup (event->key.string);
851       break;
852
853     case GDK_ENTER_NOTIFY:
854     case GDK_LEAVE_NOTIFY:
855       if (event->crossing.subwindow != NULL)
856         gdk_window_ref (event->crossing.subwindow);
857       break;
858
859     case GDK_DROP_DATA_AVAIL:
860       new_event->dropdataavailable.data_type = g_strdup (event->dropdataavailable.data_type);
861       new_event->dropdataavailable.data = g_malloc (event->dropdataavailable.data_numbytes);
862       memcpy (new_event->dropdataavailable.data,
863               event->dropdataavailable.data, 
864               event->dropdataavailable.data_numbytes);
865       break;
866
867     default:
868       break;
869     }
870
871   return new_event;
872 }
873
874 /*
875  *--------------------------------------------------------------
876  * gdk_event_free
877  *
878  *   Free a event structure obtained from gdk_event_copy.  Do not use
879  *   with other event structures.
880  *
881  * Arguments:
882  *   "event" is the event struct to free.
883  *
884  * Results:
885  *
886  * Side effects:
887  *   The reference count of the window in the event is decreased and
888  *   might be freed, too.
889  *
890  *-------------------------------------------------------------- */
891
892 void
893 gdk_event_free (GdkEvent *event)
894 {
895   g_assert (event_chunk != NULL);
896   g_return_if_fail (event != NULL);
897
898   if (event->any.window)
899     gdk_window_unref (event->any.window);
900
901   switch (event->any.type)
902     {
903     case GDK_KEY_PRESS:
904     case GDK_KEY_RELEASE:
905       g_free (event->key.string);
906       break;
907
908     case GDK_ENTER_NOTIFY:
909     case GDK_LEAVE_NOTIFY:
910       if (event->crossing.subwindow != NULL)
911         gdk_window_unref (event->crossing.subwindow);
912       break;
913
914     case GDK_DROP_DATA_AVAIL:
915       g_free (event->dropdataavailable.data_type);
916       g_free (event->dropdataavailable.data);
917       break;
918
919     case GDK_DRAG_REQUEST:
920       g_free (event->dragrequest.data_type);
921       break;
922
923     default:
924       break;
925     }
926
927   g_mem_chunk_free (event_chunk, event);
928 }
929
930 /*
931  *--------------------------------------------------------------
932  * gdk_set_debug_level
933  *
934  *   Sets the debugging level.
935  *
936  * Arguments:
937  *   "level" is the new debugging level.
938  *
939  * Results:
940  *
941  * Side effects:
942  *   Other function calls to "gdk" use the debugging
943  *   level to determine what kind of debugging information
944  *   to print out.
945  *
946  *--------------------------------------------------------------
947  */
948
949 void
950 gdk_set_debug_level (int level)
951 {
952   gdk_debug_level = level;
953 }
954
955 /*
956  *--------------------------------------------------------------
957  * gdk_set_show_events
958  *
959  *   Turns on/off the showing of events.
960  *
961  * Arguments:
962  *   "show_events" is a boolean describing whether or
963  *   not to show the events gdk receives.
964  *
965  * Results:
966  *
967  * Side effects:
968  *   When "show_events" is TRUE, calls to "gdk_event_get"
969  *   will output debugging informatin regarding the event
970  *   received to stdout.
971  *
972  *--------------------------------------------------------------
973  */
974
975 void
976 gdk_set_show_events (int show_events)
977 {
978   gdk_show_events = show_events;
979 }
980
981 void
982 gdk_set_use_xshm (gint use_xshm)
983 {
984   gdk_use_xshm = use_xshm;
985 }
986
987 gint
988 gdk_get_debug_level ()
989 {
990   return gdk_debug_level;
991 }
992
993 gint
994 gdk_get_show_events ()
995 {
996   return gdk_show_events;
997 }
998
999 gint
1000 gdk_get_use_xshm ()
1001 {
1002   return gdk_use_xshm;
1003 }
1004
1005 /*
1006  *--------------------------------------------------------------
1007  * gdk_time_get
1008  *
1009  *   Get the number of milliseconds since the library was
1010  *   initialized.
1011  *
1012  * Arguments:
1013  *
1014  * Results:
1015  *   The time since the library was initialized is returned.
1016  *   This time value is accurate to milliseconds even though
1017  *   a more accurate time down to the microsecond could be
1018  *   returned.
1019  *
1020  * Side effects:
1021  *
1022  *--------------------------------------------------------------
1023  */
1024
1025 guint32
1026 gdk_time_get ()
1027 {
1028   struct timeval end;
1029   struct timeval elapsed;
1030   guint32 milliseconds;
1031
1032   X_GETTIMEOFDAY (&end);
1033
1034   if (start.tv_usec > end.tv_usec)
1035     {
1036       end.tv_usec += 1000000;
1037       end.tv_sec--;
1038     }
1039   elapsed.tv_sec = end.tv_sec - start.tv_sec;
1040   elapsed.tv_usec = end.tv_usec - start.tv_usec;
1041
1042   milliseconds = (elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000);
1043
1044   return milliseconds;
1045 }
1046
1047 /*
1048  *--------------------------------------------------------------
1049  * gdk_timer_get
1050  *
1051  *   Returns the current timer.
1052  *
1053  * Arguments:
1054  *
1055  * Results:
1056  *   Returns the current timer interval. This interval is
1057  *   in units of milliseconds.
1058  *
1059  * Side effects:
1060  *
1061  *--------------------------------------------------------------
1062  */
1063
1064 guint32
1065 gdk_timer_get ()
1066 {
1067   return timer_val;
1068 }
1069
1070 /*
1071  *--------------------------------------------------------------
1072  * gdk_timer_set
1073  *
1074  *   Sets the timer interval.
1075  *
1076  * Arguments:
1077  *   "milliseconds" is the new value for the timer.
1078  *
1079  * Results:
1080  *
1081  * Side effects:
1082  *   Calls to "gdk_event_get" will last for a maximum
1083  *   of time of "milliseconds". However, a value of 0
1084  *   milliseconds will cause "gdk_event_get" to block
1085  *   indefinately until an event is received.
1086  *
1087  *--------------------------------------------------------------
1088  */
1089
1090 void
1091 gdk_timer_set (guint32 milliseconds)
1092 {
1093   timer_val = milliseconds;
1094   timer.tv_sec = milliseconds / 1000;
1095   timer.tv_usec = (milliseconds % 1000) * 1000;
1096
1097 }
1098
1099 void
1100 gdk_timer_enable ()
1101 {
1102   timerp = &timer;
1103 }
1104
1105 void
1106 gdk_timer_disable ()
1107 {
1108   timerp = NULL;
1109 }
1110
1111 gint
1112 gdk_input_add_full (gint              source,
1113                     GdkInputCondition condition,
1114                     GdkInputFunction  function,
1115                     gpointer          data,
1116                     GdkDestroyNotify  destroy)
1117 {
1118   static gint next_tag = 1;
1119   GList *list;
1120   GdkInput *input;
1121   gint tag;
1122
1123   tag = 0;
1124   list = inputs;
1125
1126   while (list)
1127     {
1128       input = list->data;
1129       list = list->next;
1130
1131       if ((input->source == source) && (input->condition == condition))
1132         {
1133           if (input->destroy)
1134             (input->destroy) (input->data);
1135           input->function = function;
1136           input->data = data;
1137           input->destroy = destroy;
1138           tag = input->tag;
1139         }
1140     }
1141
1142   if (!tag)
1143     {
1144       input = g_new (GdkInput, 1);
1145       input->tag = next_tag++;
1146       input->source = source;
1147       input->condition = condition;
1148       input->function = function;
1149       input->data = data;
1150       input->destroy = destroy;
1151       tag = input->tag;
1152
1153       inputs = g_list_prepend (inputs, input);
1154     }
1155
1156   return tag;
1157 }
1158
1159 gint
1160 gdk_input_add (gint              source,
1161                GdkInputCondition condition,
1162                GdkInputFunction  function,
1163                gpointer          data)
1164 {
1165   return gdk_input_add_interp (source, condition, function, data, NULL);
1166 }
1167
1168 void
1169 gdk_input_remove (gint tag)
1170 {
1171   GList *list;
1172   GList *temp_list;
1173   GdkInput *input;
1174
1175   list = inputs;
1176   while (list)
1177     {
1178       input = list->data;
1179
1180       if (input->tag == tag)
1181         {
1182           if (input->destroy)
1183             (input->destroy) (input->data);
1184
1185           temp_list = list;
1186
1187           if (list->next)
1188             list->next->prev = list->prev;
1189           if (list->prev)
1190             list->prev->next = list->next;
1191           if (inputs == list)
1192             inputs = list->next;
1193
1194           temp_list->next = NULL;
1195           temp_list->prev = NULL;
1196
1197           g_free (temp_list->data);
1198           g_list_free (temp_list);
1199           break;
1200         }
1201
1202       list = list->next;
1203     }
1204 }
1205
1206 /*
1207  *--------------------------------------------------------------
1208  * gdk_pointer_grab
1209  *
1210  *   Grabs the pointer to a specific window
1211  *
1212  * Arguments:
1213  *   "window" is the window which will receive the grab
1214  *   "owner_events" specifies whether events will be reported as is,
1215  *     or relative to "window"
1216  *   "event_mask" masks only interesting events
1217  *   "confine_to" limits the cursor movement to the specified window
1218  *   "cursor" changes the cursor for the duration of the grab
1219  *   "time" specifies the time
1220  *
1221  * Results:
1222  *
1223  * Side effects:
1224  *   requires a corresponding call to gdk_pointer_ungrab
1225  *
1226  *--------------------------------------------------------------
1227  */
1228
1229 gint
1230 gdk_pointer_grab (GdkWindow *     window,
1231                   gint            owner_events,
1232                   GdkEventMask    event_mask,
1233                   GdkWindow *     confine_to,
1234                   GdkCursor *     cursor,
1235                   guint32         time)
1236 {
1237   /*  From gdkwindow.c  */
1238   extern int nevent_masks;
1239   extern int event_mask_table[];
1240
1241   gint return_val;
1242   GdkWindowPrivate *window_private;
1243   GdkWindowPrivate *confine_to_private;
1244   GdkCursorPrivate *cursor_private;
1245   guint xevent_mask;
1246   Window xwindow;
1247   Window xconfine_to;
1248   Cursor xcursor;
1249   int i;
1250
1251   g_return_val_if_fail (window != NULL, 0);
1252
1253   window_private = (GdkWindowPrivate*) window;
1254   confine_to_private = (GdkWindowPrivate*) confine_to;
1255   cursor_private = (GdkCursorPrivate*) cursor;
1256
1257   xwindow = window_private->xwindow;
1258
1259   if (!confine_to || confine_to_private->destroyed)
1260     xconfine_to = None;
1261   else
1262     xconfine_to = confine_to_private->xwindow;
1263
1264   if (!cursor)
1265     xcursor = None;
1266   else
1267     xcursor = cursor_private->xcursor;
1268
1269
1270   xevent_mask = 0;
1271   for (i = 0; i < nevent_masks; i++)
1272     {
1273       if (event_mask & (1 << (i + 1)))
1274         xevent_mask |= event_mask_table[i];
1275     }
1276
1277   if (((GdkWindowPrivate *)window)->extension_events &&
1278       gdk_input_vtable.grab_pointer)
1279     return_val = gdk_input_vtable.grab_pointer (window,
1280                                                 owner_events,
1281                                                 event_mask,
1282                                                 confine_to,
1283                                                 time);
1284   else
1285     return_val = Success;
1286   
1287   if (return_val == Success)
1288     {
1289       if (!window_private->destroyed)
1290         return_val = XGrabPointer (window_private->xdisplay,
1291                                    xwindow,
1292                                    owner_events,
1293                                    xevent_mask,
1294                                    GrabModeAsync, GrabModeAsync,
1295                                    xconfine_to,
1296                                    xcursor,
1297                                    time);
1298       else
1299         return_val = AlreadyGrabbed;
1300     }
1301
1302   if (return_val == GrabSuccess)
1303     xgrab_window = window_private;
1304   
1305   return return_val;
1306 }
1307
1308 /*
1309  *--------------------------------------------------------------
1310  * gdk_pointer_ungrab
1311  *
1312  *   Releases any pointer grab
1313  *
1314  * Arguments:
1315  *
1316  * Results:
1317  *
1318  * Side effects:
1319  *
1320  *--------------------------------------------------------------
1321  */
1322
1323 void
1324 gdk_pointer_ungrab (guint32 time)
1325 {
1326   if (gdk_input_vtable.ungrab_pointer)
1327     gdk_input_vtable.ungrab_pointer (time);
1328
1329   XUngrabPointer (gdk_display, time);
1330   xgrab_window = NULL;
1331 }
1332
1333 /*
1334  *--------------------------------------------------------------
1335  * gdk_pointer_is_grabbed
1336  *
1337  *   Tell wether there is an active x pointer grab in effect
1338  *
1339  * Arguments:
1340  *
1341  * Results:
1342  *
1343  * Side effects:
1344  *
1345  *--------------------------------------------------------------
1346  */
1347
1348 gint
1349 gdk_pointer_is_grabbed (void)
1350 {
1351   return xgrab_window != NULL;
1352 }
1353
1354 /*
1355  *--------------------------------------------------------------
1356  * gdk_keyboard_grab
1357  *
1358  *   Grabs the keyboard to a specific window
1359  *
1360  * Arguments:
1361  *   "window" is the window which will receive the grab
1362  *   "owner_events" specifies whether events will be reported as is,
1363  *     or relative to "window"
1364  *   "time" specifies the time
1365  *
1366  * Results:
1367  *
1368  * Side effects:
1369  *   requires a corresponding call to gdk_keyboard_ungrab
1370  *
1371  *--------------------------------------------------------------
1372  */
1373
1374 gint
1375 gdk_keyboard_grab (GdkWindow *     window,
1376                    gint            owner_events,
1377                    guint32         time)
1378 {
1379   GdkWindowPrivate *window_private;
1380   Window xwindow;
1381
1382   g_return_val_if_fail (window != NULL, 0);
1383
1384   window_private = (GdkWindowPrivate*) window;
1385   xwindow = window_private->xwindow;
1386
1387   if (!window_private->destroyed)
1388     return XGrabKeyboard (window_private->xdisplay,
1389                           xwindow,
1390                           owner_events,
1391                           GrabModeAsync, GrabModeAsync,
1392                           time);
1393   else
1394     return AlreadyGrabbed;
1395 }
1396
1397 /*
1398  *--------------------------------------------------------------
1399  * gdk_keyboard_ungrab
1400  *
1401  *   Releases any keyboard grab
1402  *
1403  * Arguments:
1404  *
1405  * Results:
1406  *
1407  * Side effects:
1408  *
1409  *--------------------------------------------------------------
1410  */
1411
1412 void
1413 gdk_keyboard_ungrab (guint32 time)
1414 {
1415   XUngrabKeyboard (gdk_display, time);
1416 }
1417
1418 /*
1419  *--------------------------------------------------------------
1420  * gdk_screen_width
1421  *
1422  *   Return the width of the screen.
1423  *
1424  * Arguments:
1425  *
1426  * Results:
1427  *
1428  * Side effects:
1429  *
1430  *--------------------------------------------------------------
1431  */
1432
1433 gint
1434 gdk_screen_width ()
1435 {
1436   gint return_val;
1437
1438   return_val = DisplayWidth (gdk_display, gdk_screen);
1439
1440   return return_val;
1441 }
1442
1443 /*
1444  *--------------------------------------------------------------
1445  * gdk_screen_height
1446  *
1447  *   Return the height of the screen.
1448  *
1449  * Arguments:
1450  *
1451  * Results:
1452  *
1453  * Side effects:
1454  *
1455  *--------------------------------------------------------------
1456  */
1457
1458 gint
1459 gdk_screen_height ()
1460 {
1461   gint return_val;
1462
1463   return_val = DisplayHeight (gdk_display, gdk_screen);
1464
1465   return return_val;
1466 }
1467
1468 void
1469 gdk_key_repeat_disable ()
1470 {
1471   XAutoRepeatOff (gdk_display);
1472 }
1473
1474 void
1475 gdk_key_repeat_restore ()
1476 {
1477   if (autorepeat)
1478     XAutoRepeatOn (gdk_display);
1479   else
1480     XAutoRepeatOff (gdk_display);
1481 }
1482
1483
1484 /*
1485  *--------------------------------------------------------------
1486  * gdk_flush
1487  *
1488  *   Flushes the Xlib output buffer and then waits
1489  *   until all requests have been received and processed
1490  *   by the X server. The only real use for this function
1491  *   is in dealing with XShm.
1492  *
1493  * Arguments:
1494  *
1495  * Results:
1496  *
1497  * Side effects:
1498  *
1499  *--------------------------------------------------------------
1500  */
1501
1502 void gdk_flush ()
1503 {
1504   XSync (gdk_display, False);
1505 }
1506
1507
1508 void
1509 gdk_beep ()
1510 {
1511   XBell(gdk_display, 100);
1512 }
1513
1514
1515 /*
1516  *--------------------------------------------------------------
1517  * gdk_event_wait
1518  *
1519  *   Waits until an event occurs or the timer runs out.
1520  *
1521  * Arguments:
1522  *
1523  * Results:
1524  *   Returns TRUE if an event is ready to be read and FALSE
1525  *   if the timer ran out.
1526  *
1527  * Side effects:
1528  *
1529  *--------------------------------------------------------------
1530  */
1531
1532 static gint
1533 gdk_event_wait ()
1534 {
1535   GList *list;
1536   GdkInput *input;
1537   GdkInputCondition condition;
1538   SELECT_MASK readfds;
1539   SELECT_MASK writefds;
1540   SELECT_MASK exceptfds;
1541   int max_input;
1542   int nfd;
1543
1544   /* If there are no events pending we will wait for an event.
1545    * The time we wait is dependant on the "timer". If no timer
1546    *  has been specified then we'll block until an event arrives.
1547    *  If a timer has been specified we'll block until an event
1548    *  arrives or the timer expires. (This is all done using the
1549    *  "select" system call).
1550    */
1551
1552   if (XPending (gdk_display) == 0)
1553     {
1554       FD_ZERO (&readfds);
1555       FD_ZERO (&writefds);
1556       FD_ZERO (&exceptfds);
1557
1558       FD_SET (connection_number, &readfds);
1559       max_input = connection_number;
1560
1561       list = inputs;
1562       while (list)
1563         {
1564           input = list->data;
1565           list = list->next;
1566
1567           if (input->condition & GDK_INPUT_READ)
1568             FD_SET (input->source, &readfds);
1569           if (input->condition & GDK_INPUT_WRITE)
1570             FD_SET (input->source, &writefds);
1571           if (input->condition & GDK_INPUT_EXCEPTION)
1572             FD_SET (input->source, &exceptfds);
1573
1574           max_input = MAX (max_input, input->source);
1575         }
1576
1577       nfd = select (max_input+1, &readfds, &writefds, &exceptfds, timerp);
1578
1579       timerp = NULL;
1580       timer_val = 0;
1581
1582       if (nfd > 0)
1583         {
1584           if (FD_ISSET (connection_number, &readfds))
1585             {
1586               if (XPending (gdk_display) == 0)
1587                 {
1588                   if (nfd == 1)
1589                     {
1590                       XNoOp (gdk_display);
1591                       XFlush (gdk_display);
1592                     }
1593                   return FALSE;
1594                 }
1595               else
1596                 return TRUE;
1597             }
1598
1599           list = inputs;
1600           while (list)
1601             {
1602               input = list->data;
1603               list = list->next;
1604
1605               condition = 0;
1606               if (FD_ISSET (input->source, &readfds))
1607                 condition |= GDK_INPUT_READ;
1608               if (FD_ISSET (input->source, &writefds))
1609                 condition |= GDK_INPUT_WRITE;
1610               if (FD_ISSET (input->source, &exceptfds))
1611                 condition |= GDK_INPUT_EXCEPTION;
1612
1613               if (condition && input->function)
1614                 (* input->function) (input->data, input->source, condition);
1615             }
1616         }
1617     }
1618   else
1619     return TRUE;
1620
1621   return FALSE;
1622 }
1623
1624 static gint
1625 gdk_event_apply_filters (XEvent *xevent,
1626                          GdkEvent *event,
1627                          GList *filters)
1628 {
1629   GdkEventFilter *filter;
1630   GList *tmp_list;
1631   GdkFilterReturn result;
1632
1633   tmp_list = filters;
1634   
1635   while (tmp_list)
1636     {
1637       filter = (GdkEventFilter *)tmp_list->data;
1638
1639       result = (*filter->function)(xevent, event, filter->data);
1640       if (result !=  GDK_FILTER_CONTINUE)
1641         return result;
1642         
1643       tmp_list = tmp_list->next;
1644     }
1645
1646   return GDK_FILTER_CONTINUE;
1647 }
1648
1649 static gint
1650 gdk_event_translate (GdkEvent *event,
1651                      XEvent   *xevent)
1652 {
1653
1654   GdkWindow *window;
1655   GdkWindowPrivate *window_private;
1656   XComposeStatus compose;
1657   int charcount;
1658 #ifdef USE_XIM
1659   static gchar* buf = NULL;
1660   static gint buf_len= 0;
1661 #else
1662   char buf[16];
1663 #endif
1664   gint return_val;
1665
1666   /* Are static variables used for this purpose thread-safe? */
1667   static GdkPoint dnd_drag_start = {0,0},
1668                   dnd_drag_oldpos = {0,0};
1669   static GdkRectangle dnd_drag_dropzone = {0,0,0,0};
1670   static gint dnd_drag_perhaps = 0;
1671   static gboolean dnd_grabbed = FALSE;
1672   static GdkWindowPrivate *real_sw = NULL;
1673   static Window dnd_drag_curwin = None, dnd_drag_target = None;
1674
1675   return_val = FALSE;
1676
1677   /* Find the GdkWindow that this event occurred in.
1678    * All events occur in some GdkWindow (otherwise, why
1679    *  would we be receiving them). It really is an error
1680    *  to receive an event for which we cannot find the
1681    *  corresponding GdkWindow. We handle events with window=None
1682    *  specially - they are generated by XFree86's XInput under
1683    *  some circumstances.
1684    */
1685
1686   if ((xevent->xany.window == None) &&
1687       gdk_input_vtable.window_none_event)
1688     {
1689       return_val = gdk_input_vtable.window_none_event (event,xevent);
1690
1691       if (return_val >= 0)      /* was handled */
1692         return return_val;
1693       else
1694         return_val = FALSE;
1695     }
1696
1697   window = gdk_window_lookup (xevent->xany.window);
1698   window_private = (GdkWindowPrivate *) window;
1699
1700   if (window == NULL)
1701     g_warning ("%#lx -> NULL\n", xevent->xany.window);
1702   else
1703     gdk_window_ref (window);
1704
1705
1706   /* Check for filters for this window */
1707
1708   if (window_private)
1709     {
1710       GdkFilterReturn result;
1711       result = gdk_event_apply_filters (xevent, event, window_private->filters);
1712
1713       if (result != GDK_FILTER_CONTINUE)
1714         {
1715           return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
1716         }
1717     }
1718
1719   /* We do a "manual" conversion of the XEvent to a
1720    *  GdkEvent. The structures are mostly the same so
1721    *  the conversion is fairly straightforward. We also
1722    *  optionally print debugging info regarding events
1723    *  received.
1724    */
1725   /* Addendum:
1726    * During drag & drop you get events where the pointer is
1727    * in other windows. Need to just do finer-grained checking
1728    */
1729   switch (xevent->type)
1730     {
1731     case KeyPress:
1732       /* Lookup the string corresponding to the given keysym.
1733        */
1734 #ifdef USE_XIM
1735       if (buf_len == 0) 
1736         {
1737           buf_len = 128;
1738           buf = g_new (gchar, buf_len);
1739         }
1740       if (xim_using == TRUE && xim_ic)
1741         {
1742           Status status;
1743           
1744           /* Clear keyval. Depending on status, may not be set */
1745           event->key.keyval = GDK_VoidSymbol;
1746           charcount = XmbLookupString(xim_ic->xic,
1747                                       &xevent->xkey, buf, buf_len-1,
1748                                       (KeySym*) &event->key.keyval,
1749                                       &status);
1750           if (status == XBufferOverflow)
1751             {                     /* retry */
1752               /* alloc adequate size of buffer */
1753               if (gdk_debug_level >= 1)
1754                 g_print("XIM: overflow (required %i)\n", charcount);
1755
1756               while (buf_len <= charcount)
1757                 buf_len *= 2;
1758               buf = (gchar *) g_realloc (buf, buf_len);
1759              
1760               charcount = XmbLookupString (xim_ic->xic,
1761                                            &xevent->xkey, buf, buf_len-1,
1762                                            (KeySym*) &event->key.keyval,
1763                                            &status);
1764             }
1765           if (status == XLookupNone)
1766             {
1767               return_val = FALSE;
1768               break;
1769             }
1770         }
1771       else
1772         charcount = XLookupString (&xevent->xkey, buf, buf_len,
1773                                    (KeySym*) &event->key.keyval,
1774                                    &compose);
1775 #else
1776       charcount = XLookupString (&xevent->xkey, buf, 16,
1777                                  (KeySym*) &event->key.keyval,
1778                                  &compose);
1779 #endif
1780       if (charcount > 0 && buf[charcount-1] == '\0')
1781         charcount --;
1782       else
1783         buf[charcount] = '\0';
1784
1785       /* Print debugging info.
1786        */
1787       if (gdk_show_events)
1788         {
1789           g_print ("key press:\twindow: %ld  key: %12s  %d\n",
1790                    xevent->xkey.window - base_id,
1791                    event->key.keyval ? XKeysymToString (event->key.keyval) : "(none)",
1792                    event->key.keyval);
1793           if (charcount > 0)
1794             g_print ("\t\tlength: %4d string: \"%s\"\n",
1795                      charcount, buf);
1796         }
1797
1798       event->key.type = GDK_KEY_PRESS;
1799       event->key.window = window;
1800       event->key.time = xevent->xkey.time;
1801       event->key.state = (GdkModifierType) xevent->xkey.state;
1802       event->key.string = g_strdup (buf);
1803       event->key.length = charcount;
1804
1805       return_val = window_private && !window_private->destroyed;
1806       
1807       if (!return_val)
1808         g_free (event->key.string);
1809       
1810       break;
1811
1812     case KeyRelease:
1813       /* Lookup the string corresponding to the given keysym.
1814        */
1815       charcount = XLookupString (&xevent->xkey, buf, 16,
1816                                  (KeySym*) &event->key.keyval,
1817                                  &compose);
1818
1819       /* Print debugging info.
1820        */
1821       if (gdk_show_events)
1822         g_print ("key release:\t\twindow: %ld  key: %12s  %d\n",
1823                  xevent->xkey.window - base_id,
1824                  XKeysymToString (event->key.keyval),
1825                  event->key.keyval);
1826
1827       event->key.type = GDK_KEY_RELEASE;
1828       event->key.window = window;
1829       event->key.time = xevent->xkey.time;
1830       event->key.state = (GdkModifierType) xevent->xkey.state;
1831       event->key.length = 0;
1832       event->key.string = NULL;
1833
1834       return_val = window_private && !window_private->destroyed;
1835       break;
1836
1837     case ButtonPress:
1838       /* Print debugging info.
1839        */
1840       if (gdk_show_events)
1841         g_print ("button press[%d]:\t\twindow: %ld  x,y: %d %d  button: %d\n",
1842                  window_private?window_private->dnd_drag_enabled:0,
1843                  xevent->xbutton.window - base_id,
1844                  xevent->xbutton.x, xevent->xbutton.y,
1845                  xevent->xbutton.button);
1846
1847       if (window_private &&
1848           (window_private->extension_events != 0) &&
1849           gdk_input_ignore_core)
1850         break;
1851
1852       event->button.type = GDK_BUTTON_PRESS;
1853       event->button.window = window;
1854       event->button.time = xevent->xbutton.time;
1855       event->button.x = xevent->xbutton.x;
1856       event->button.y = xevent->xbutton.y;
1857       event->button.x_root = (gfloat)xevent->xbutton.x_root;
1858       event->button.y_root = (gfloat)xevent->xbutton.y_root;
1859       event->button.pressure = 0.5;
1860       event->button.xtilt = 0;
1861       event->button.ytilt = 0;
1862       event->button.state = (GdkModifierType) xevent->xbutton.state;
1863       event->button.button = xevent->xbutton.button;
1864       event->button.source = GDK_SOURCE_MOUSE;
1865       event->button.deviceid = GDK_CORE_POINTER;
1866
1867       if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) &&
1868           (event->button.window == button_window[1]) &&
1869           (event->button.button == button_number[1]))
1870         {
1871           gdk_synthesize_click (event, 3);
1872
1873           button_click_time[1] = 0;
1874           button_click_time[0] = 0;
1875           button_window[1] = NULL;
1876           button_window[0] = 0;
1877           button_number[1] = -1;
1878           button_number[0] = -1;
1879         }
1880       else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) &&
1881                (event->button.window == button_window[0]) &&
1882                (event->button.button == button_number[0]))
1883         {
1884           gdk_synthesize_click (event, 2);
1885
1886           button_click_time[1] = button_click_time[0];
1887           button_click_time[0] = event->button.time;
1888           button_window[1] = button_window[0];
1889           button_window[0] = event->button.window;
1890           button_number[1] = button_number[0];
1891           button_number[0] = event->button.button;
1892         }
1893       else
1894         {
1895           button_click_time[1] = 0;
1896           button_click_time[0] = event->button.time;
1897           button_window[1] = NULL;
1898           button_window[0] = event->button.window;
1899           button_number[1] = -1;
1900           button_number[0] = event->button.button;
1901         }
1902       if(window_private
1903          && window_private->dnd_drag_enabled
1904          && !dnd_drag_perhaps
1905          && !gdk_dnd.drag_really)
1906         {
1907           dnd_drag_perhaps = 1;
1908           dnd_drag_start.x = xevent->xbutton.x_root;
1909           dnd_drag_start.y = xevent->xbutton.y_root;
1910           real_sw = window_private;
1911           
1912           if(gdk_dnd.drag_startwindows)
1913             {
1914               g_free(gdk_dnd.drag_startwindows);
1915               gdk_dnd.drag_startwindows = NULL;
1916             }
1917           gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0;
1918           dnd_grabbed = FALSE;
1919
1920           {
1921             /* Set motion mask for first DnD'd window, since it
1922                will be the one that is actually dragged */
1923             XWindowAttributes dnd_winattr;
1924             XSetWindowAttributes dnd_setwinattr;
1925
1926             /* We need to get motion events while the button is down, so
1927                we can know whether to really start dragging or not... */
1928             XGetWindowAttributes(gdk_display, (Window)window_private->xwindow,
1929                                  &dnd_winattr);
1930             
1931             window_private->dnd_drag_savedeventmask = dnd_winattr.your_event_mask;
1932             dnd_setwinattr.event_mask = 
1933               window_private->dnd_drag_eventmask = ButtonMotionMask | EnterWindowMask | LeaveWindowMask;
1934             XChangeWindowAttributes(gdk_display, window_private->xwindow,
1935                                     CWEventMask, &dnd_setwinattr);
1936         }
1937       }
1938       return_val = window_private && !window_private->destroyed;
1939       break;
1940
1941     case ButtonRelease:
1942       /* Print debugging info.
1943        */
1944       if (gdk_show_events)
1945         g_print ("button release[%d]:\twindow: %ld  x,y: %d %d  button: %d\n",
1946                  window_private?window_private->dnd_drag_enabled:0,
1947                  xevent->xbutton.window - base_id,
1948                  xevent->xbutton.x, xevent->xbutton.y,
1949                  xevent->xbutton.button);
1950
1951       if (window_private &&
1952           (window_private->extension_events != 0) &&
1953           gdk_input_ignore_core)
1954         break;
1955
1956       event->button.type = GDK_BUTTON_RELEASE;
1957       event->button.window = window;
1958       event->button.time = xevent->xbutton.time;
1959       event->button.x = xevent->xbutton.x;
1960       event->button.y = xevent->xbutton.y;
1961       event->button.x_root = (gfloat)xevent->xbutton.x_root;
1962       event->button.y_root = (gfloat)xevent->xbutton.y_root;
1963       event->button.pressure = 0.5;
1964       event->button.xtilt = 0;
1965       event->button.ytilt = 0;
1966       event->button.state = (GdkModifierType) xevent->xbutton.state;
1967       event->button.button = xevent->xbutton.button;
1968       event->button.source = GDK_SOURCE_MOUSE;
1969       event->button.deviceid = GDK_CORE_POINTER;
1970
1971       if(dnd_drag_perhaps)
1972         {
1973           {
1974             XSetWindowAttributes attrs;
1975             /* Reset event mask to pre-drag value, assuming event_mask
1976                doesn't change during drag */
1977             attrs.event_mask = real_sw->dnd_drag_savedeventmask;
1978             XChangeWindowAttributes(gdk_display, real_sw->xwindow,
1979                                       CWEventMask, &attrs);
1980           }
1981           
1982           if (dnd_grabbed) 
1983             {
1984               XUngrabPointer(gdk_display, CurrentTime);
1985               dnd_grabbed = FALSE;
1986             }
1987           
1988         if(gdk_dnd.drag_really)
1989           {
1990           GdkPoint foo;
1991           foo.x = xevent->xbutton.x_root;
1992           foo.y = xevent->xbutton.y_root;
1993                           
1994           if(dnd_drag_target != None)
1995             gdk_dnd_drag_end(dnd_drag_target, foo);
1996           gdk_dnd.drag_really = 0;
1997
1998           gdk_dnd.drag_numwindows = 0;
1999           if(gdk_dnd.drag_startwindows)
2000             {
2001             g_free(gdk_dnd.drag_startwindows);
2002             gdk_dnd.drag_startwindows = NULL;
2003             }
2004
2005           real_sw = NULL;
2006           }
2007
2008         dnd_drag_perhaps = 0;
2009         dnd_drag_start.x = dnd_drag_start.y = 0;
2010         dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0;
2011         dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0;
2012         dnd_drag_curwin = None;
2013         return_val = window_private?TRUE:FALSE;
2014       } else
2015         return_val = window_private && !window_private->destroyed;
2016       break;
2017
2018     case MotionNotify:
2019       /* Print debugging info.
2020        */
2021       if (gdk_show_events)
2022         g_print ("motion notify:\t\twindow: %ld  x,y: %d %d  hint: %s d:%d r%d\n",
2023                  xevent->xmotion.window - base_id,
2024                  xevent->xmotion.x, xevent->xmotion.y,
2025                  (xevent->xmotion.is_hint) ? "true" : "false",
2026                  dnd_drag_perhaps, gdk_dnd.drag_really);
2027
2028       if (window_private &&
2029           (window_private->extension_events != 0) &&
2030           gdk_input_ignore_core)
2031         break;
2032
2033       event->motion.type = GDK_MOTION_NOTIFY;
2034       event->motion.window = window;
2035       event->motion.time = xevent->xmotion.time;
2036       event->motion.x = xevent->xmotion.x;
2037       event->motion.y = xevent->xmotion.y;
2038       event->motion.x_root = (gfloat)xevent->xmotion.x_root;
2039       event->motion.y_root = (gfloat)xevent->xmotion.y_root;
2040       event->motion.pressure = 0.5;
2041       event->motion.xtilt = 0;
2042       event->motion.ytilt = 0;
2043       event->motion.state = (GdkModifierType) xevent->xmotion.state;
2044       event->motion.is_hint = xevent->xmotion.is_hint;
2045       event->motion.source = GDK_SOURCE_MOUSE;
2046       event->motion.deviceid = GDK_CORE_POINTER;
2047
2048 #define IS_IN_ZONE(cx, cy) (cx >= dnd_drag_dropzone.x \
2049      && cy >= dnd_drag_dropzone.y \
2050      && cx < (dnd_drag_dropzone.x + dnd_drag_dropzone.width) \
2051      && cy < (dnd_drag_dropzone.y + dnd_drag_dropzone.height))
2052
2053       if(dnd_drag_perhaps && gdk_dnd.drag_really)
2054         {
2055           /* First, we have to find what window the motion was in... */
2056           /* XXX there has to be a better way to do this, perhaps with
2057              XTranslateCoordinates or XQueryTree - I don't know how,
2058              and this sort of works */
2059           static Window lastwin = None, curwin = None, twin;
2060           Window childwin = gdk_root_window;
2061           int x, y, ox, oy;
2062           lastwin = curwin;
2063           curwin = gdk_root_window;
2064           ox = x = xevent->xmotion.x_root;
2065           oy = y = xevent->xmotion.y_root;
2066           while(childwin != None)
2067             {
2068               ox = x; oy = y;
2069               curwin = childwin;
2070               XTranslateCoordinates(gdk_display, curwin, curwin,
2071                                     x, y, &x, &y, &childwin);
2072               if(childwin != None) 
2073                 {
2074                   XTranslateCoordinates(gdk_display, curwin, childwin,
2075                                         x, y, &x, &y, &twin);
2076                 }
2077             }
2078 #if defined(DEBUG_DND) /* && defined(DEBUG_DND_MORE_DETAILS) */
2079           g_print("Drag is now in window %#x, lastwin was %#x, ddc = %#x\n",
2080                 curwin, lastwin, dnd_drag_curwin);
2081 #endif
2082           if(curwin != dnd_drag_curwin && curwin != lastwin)
2083             {
2084               /* We have left one window and entered another
2085                  (do leave & enter bits) */
2086               if(dnd_drag_curwin != None)
2087                   gdk_dnd_drag_leave(dnd_drag_curwin);
2088               dnd_drag_curwin = curwin;
2089               gdk_dnd_drag_enter(dnd_drag_curwin);
2090               dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0;
2091               dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0;
2092               dnd_drag_target = None;
2093 #ifdef DEBUG_DND
2094               g_print("curwin = %#x, lastwin = %#x, dnd_drag_curwin = %#x\n",
2095                       curwin, lastwin, dnd_drag_curwin);
2096 #endif
2097               XChangeActivePointerGrab(gdk_display,
2098                                        ButtonMotionMask |
2099                                        ButtonPressMask | ButtonReleaseMask,
2100                                        gdk_dnd.gdk_cursor_dragdefault,
2101                                        CurrentTime);
2102             }
2103           else if(dnd_drag_dropzone.width > 0
2104                   && dnd_drag_dropzone.height > 0
2105                   && curwin == dnd_drag_curwin)
2106             {
2107               /* Handle all that dropzone stuff - thanks John ;-) */
2108               if (dnd_drag_target != None)
2109                 {
2110                   gboolean in_zone = IS_IN_ZONE(xevent->xmotion.x_root,
2111                                                 xevent->xmotion.y_root);
2112                   gboolean old_in_zone = IS_IN_ZONE(dnd_drag_oldpos.x, 
2113                                                     dnd_drag_oldpos.y);
2114
2115                   if (!in_zone && old_in_zone)
2116                     {
2117                       /* We were in the drop zone and moved out */
2118                       dnd_drag_target = None;
2119                       gdk_dnd_drag_leave(curwin);
2120                     }
2121                   else if (!in_zone && !old_in_zone)
2122                     {
2123                       /* We were outside drop zone but in the window
2124                          - have to send enter events */
2125                       gdk_dnd_drag_enter(curwin);
2126                       dnd_drag_curwin = curwin;
2127                       dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0;
2128                       dnd_drag_target = None;
2129                     }
2130                 }
2131             } /* else
2132               dnd_drag_curwin = None; */
2133           return_val = FALSE;
2134         }
2135       else
2136         return_val = window_private && !window_private->destroyed;
2137       break;
2138
2139     case EnterNotify:
2140       /* Print debugging info.
2141        */
2142 #if !(defined(DEBUG_DND) && defined(DEBUG_DND_MORE_DETAILS))
2143       if (gdk_show_events)
2144 #endif
2145         g_print ("enter notify:\t\twindow: %ld  detail: %d subwin: %ld\n",
2146                  xevent->xcrossing.window - base_id,
2147                  xevent->xcrossing.detail,
2148                  xevent->xcrossing.subwindow - base_id);
2149
2150       /* Tell XInput stuff about it if appropriate */
2151       if (window_private &&
2152           (window_private->extension_events != 0) &&
2153           gdk_input_vtable.enter_event)
2154         gdk_input_vtable.enter_event (&xevent->xcrossing, window);
2155
2156       event->crossing.type = GDK_ENTER_NOTIFY;
2157       event->crossing.window = window;
2158
2159       /* If the subwindow field of the XEvent is non-NULL, then
2160        *  lookup the corresponding GdkWindow.
2161        */
2162       if (xevent->xcrossing.subwindow != None)
2163         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
2164       else
2165         event->crossing.subwindow = NULL;
2166
2167       /* Translate the crossing detail into Gdk terms.
2168        */
2169       switch (xevent->xcrossing.detail)
2170         {
2171         case NotifyInferior:
2172           event->crossing.detail = GDK_NOTIFY_INFERIOR;
2173           break;
2174         case NotifyAncestor:
2175           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
2176           break;
2177         case NotifyVirtual:
2178           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
2179           break;
2180         case NotifyNonlinear:
2181           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
2182           break;
2183         case NotifyNonlinearVirtual:
2184           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
2185           break;
2186         default:
2187           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
2188           break;
2189         }
2190
2191 #ifdef DEBUG_DND
2192         if(dnd_drag_perhaps)
2193         {
2194           g_print("We may[%d] have a drag into %#x = %#x\n",
2195                   gdk_dnd.drag_really,
2196                   xevent->xcrossing.window, real_sw->xwindow);
2197         }
2198 #endif
2199         if (dnd_drag_perhaps && gdk_dnd.drag_really && 
2200             (xevent->xcrossing.window == real_sw->xwindow))
2201           {
2202             gdk_dnd.drag_really = 0;
2203 #ifdef DEBUG_DND
2204             g_print("Ungrabbed\n");
2205 #endif
2206             gdk_dnd.drag_numwindows = 0;
2207             g_free(gdk_dnd.drag_startwindows);
2208             gdk_dnd.drag_startwindows = NULL;
2209             /* We don't want to ungrab the pointer here, or we'll
2210              * start getting spurious enter/leave events */
2211             XChangeActivePointerGrab (gdk_display, 0, None, CurrentTime);
2212           }
2213         
2214         return_val = window_private && !window_private->destroyed;
2215         break;
2216
2217     case LeaveNotify:
2218       /* Print debugging info.
2219        */
2220 #if !(defined(DEBUG_DND) && defined(DEBUG_DND_MORE_DETAILS))
2221       if (gdk_show_events)
2222 #endif
2223         g_print ("leave notify:\t\twindow: %ld  detail: %d subwin: %ld\n",
2224                  xevent->xcrossing.window - base_id,
2225                  xevent->xcrossing.detail, xevent->xcrossing.subwindow - base_id);
2226
2227       event->crossing.type = GDK_LEAVE_NOTIFY;
2228       event->crossing.window = window;
2229
2230       /* If the subwindow field of the XEvent is non-NULL, then
2231        *  lookup the corresponding GdkWindow.
2232        */
2233       if (xevent->xcrossing.subwindow != None)
2234         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
2235       else
2236         event->crossing.subwindow = NULL;
2237
2238       /* Translate the crossing detail into Gdk terms.
2239        */
2240       switch (xevent->xcrossing.detail)
2241         {
2242         case NotifyInferior:
2243           event->crossing.detail = GDK_NOTIFY_INFERIOR;
2244           break;
2245         case NotifyAncestor:
2246           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
2247           break;
2248         case NotifyVirtual:
2249           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
2250           break;
2251         case NotifyNonlinear:
2252           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
2253           break;
2254         case NotifyNonlinearVirtual:
2255           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
2256           break;
2257         default:
2258           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
2259           break;
2260         }
2261 #ifdef DEBUG_DND
2262       if(dnd_drag_perhaps)
2263         {
2264           g_print("We may[%d] have a drag out of %#x = %#x\n",
2265                   gdk_dnd.drag_really,
2266                   xevent->xcrossing.window, real_sw->xwindow);
2267         }
2268 #endif
2269       if (dnd_drag_perhaps && !gdk_dnd.drag_really &&
2270           (xevent->xcrossing.window == real_sw->xwindow))
2271         {
2272           gdk_dnd_drag_addwindow((GdkWindow *) real_sw);
2273           gdk_dnd_drag_begin((GdkWindow *) real_sw);
2274           XGrabPointer(gdk_display, real_sw->xwindow, False,
2275                        ButtonMotionMask |
2276                        ButtonPressMask | ButtonReleaseMask,
2277                        GrabModeAsync, GrabModeAsync, gdk_root_window,
2278                        gdk_dnd.gdk_cursor_dragdefault, CurrentTime);
2279           dnd_grabbed = TRUE;
2280           gdk_dnd.drag_really = 1;
2281         }
2282
2283       return_val = window_private && !window_private->destroyed;
2284       break;
2285
2286     case FocusIn:
2287     case FocusOut:
2288       /* We only care about focus events that indicate that _this_
2289        * window (not a ancestor or child) got or lost the focus
2290        */
2291       switch (xevent->xfocus.detail)
2292         {
2293         case NotifyAncestor:
2294         case NotifyInferior:
2295         case NotifyNonlinear:
2296           /* Print debugging info.
2297            */
2298           if (gdk_show_events)
2299             g_print ("focus %s:\t\twindow: %ld\n",
2300                      (xevent->xany.type == FocusIn) ? "in" : "out",
2301                      xevent->xfocus.window - base_id);
2302           
2303           event->focus_change.type = GDK_FOCUS_CHANGE;
2304           event->focus_change.window = window;
2305           event->focus_change.in = (xevent->xany.type == FocusIn);
2306           
2307           return_val = window_private && !window_private->destroyed;
2308           break;
2309         default:
2310           ;
2311         }
2312       break;
2313
2314     case KeymapNotify:
2315       /* Print debugging info.
2316        */
2317       if (gdk_show_events)
2318         g_print ("keymap notify\n");
2319
2320       /* Not currently handled */
2321       break;
2322
2323     case Expose:
2324       /* Print debugging info.
2325        */
2326       if (gdk_show_events)
2327         g_print ("expose:\t\twindow: %ld  %d  x,y: %d %d  w,h: %d %d\n",
2328                  xevent->xexpose.window - base_id, xevent->xexpose.count,
2329                  xevent->xexpose.x, xevent->xexpose.y,
2330                  xevent->xexpose.width, xevent->xexpose.height);
2331
2332       event->expose.type = GDK_EXPOSE;
2333       event->expose.window = window;
2334       event->expose.area.x = xevent->xexpose.x;
2335       event->expose.area.y = xevent->xexpose.y;
2336       event->expose.area.width = xevent->xexpose.width;
2337       event->expose.area.height = xevent->xexpose.height;
2338       event->expose.count = xevent->xexpose.count;
2339
2340       return_val = window_private && !window_private->destroyed;
2341       break;
2342
2343     case GraphicsExpose:
2344       /* Print debugging info.
2345        */
2346       if (gdk_show_events)
2347         g_print ("graphics expose:\tdrawable: %ld\n",
2348                  xevent->xgraphicsexpose.drawable - base_id);
2349
2350       event->expose.type = GDK_EXPOSE;
2351       event->expose.window = window;
2352       event->expose.area.x = xevent->xgraphicsexpose.x;
2353       event->expose.area.y = xevent->xgraphicsexpose.y;
2354       event->expose.area.width = xevent->xgraphicsexpose.width;
2355       event->expose.area.height = xevent->xgraphicsexpose.height;
2356       event->expose.count = xevent->xexpose.count;
2357
2358       return_val = window_private && !window_private->destroyed;
2359       break;
2360
2361     case NoExpose:
2362       /* Print debugging info.
2363        */
2364       if (gdk_show_events)
2365         g_print ("no expose:\t\tdrawable: %ld\n",
2366                  xevent->xnoexpose.drawable - base_id);
2367
2368       event->no_expose.type = GDK_NO_EXPOSE;
2369       event->no_expose.window = window;
2370
2371       return_val = window_private && !window_private->destroyed;
2372       break;
2373
2374     case VisibilityNotify:
2375       /* Print debugging info.
2376        */
2377       if (gdk_show_events)
2378         switch (xevent->xvisibility.state)
2379           {
2380           case VisibilityFullyObscured:
2381             g_print ("visibility notify:\twindow: %ld  none\n",
2382                      xevent->xvisibility.window - base_id);
2383             break;
2384           case VisibilityPartiallyObscured:
2385             g_print ("visibility notify:\twindow: %ld  partial\n",
2386                      xevent->xvisibility.window - base_id);
2387             break;
2388           case VisibilityUnobscured:
2389             g_print ("visibility notify:\twindow: %ld  full\n",
2390                      xevent->xvisibility.window - base_id);
2391             break;
2392           }
2393
2394       event->visibility.type = GDK_VISIBILITY_NOTIFY;
2395       event->visibility.window = window;
2396
2397       switch (xevent->xvisibility.state)
2398         {
2399         case VisibilityFullyObscured:
2400           event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED;
2401           break;
2402
2403         case VisibilityPartiallyObscured:
2404           event->visibility.state = GDK_VISIBILITY_PARTIAL;
2405           break;
2406
2407         case VisibilityUnobscured:
2408           event->visibility.state = GDK_VISIBILITY_UNOBSCURED;
2409           break;
2410         }
2411       
2412       return_val = window_private && !window_private->destroyed;
2413       break;
2414
2415     case CreateNotify:
2416       /* Not currently handled */
2417       break;
2418
2419     case DestroyNotify:
2420       /* Print debugging info.
2421        */
2422       if (gdk_show_events)
2423         g_print ("destroy notify:\twindow: %ld\n",
2424                  xevent->xdestroywindow.window - base_id);
2425
2426       event->any.type = GDK_DESTROY;
2427       event->any.window = window;
2428
2429       return_val = window_private && !window_private->destroyed;
2430
2431       gdk_window_destroy_notify (window);
2432       break;
2433
2434     case UnmapNotify:
2435       /* Print debugging info.
2436        */
2437       if (gdk_show_events)
2438         g_print ("unmap notify:\t\twindow: %ld\n",
2439                  xevent->xmap.window - base_id);
2440
2441       event->any.type = GDK_UNMAP;
2442       event->any.window = window;
2443
2444       if (xgrab_window == window_private)
2445         xgrab_window = NULL;
2446
2447       return_val = window_private && !window_private->destroyed;
2448       break;
2449
2450     case MapNotify:
2451       /* Print debugging info.
2452        */
2453       if (gdk_show_events)
2454         g_print ("map notify:\t\twindow: %ld\n",
2455                  xevent->xmap.window - base_id);
2456
2457       event->any.type = GDK_MAP;
2458       event->any.window = window;
2459
2460       return_val = window_private && !window_private->destroyed;
2461       break;
2462
2463     case ReparentNotify:
2464       /* Print debugging info.
2465        */
2466       if (gdk_show_events)
2467         g_print ("reparent notify:\twindow: %ld\n",
2468                  xevent->xreparent.window - base_id);
2469
2470       /* Not currently handled */
2471       break;
2472
2473     case ConfigureNotify:
2474       /* Print debugging info.
2475        */
2476       while ((XPending (gdk_display) > 0) &&
2477              XCheckTypedWindowEvent(gdk_display, xevent->xany.window,
2478                                     ConfigureNotify, xevent))
2479         /*XSync (gdk_display, 0)*/;
2480       
2481       if (gdk_show_events)
2482         g_print ("configure notify:\twindow: %ld  x,y: %d %d  w,h: %d %d  b-w: %d  above: %ld  ovr: %d\n",
2483                  xevent->xconfigure.window - base_id,
2484                  xevent->xconfigure.x,
2485                  xevent->xconfigure.y,
2486                  xevent->xconfigure.width,
2487                  xevent->xconfigure.height,
2488                  xevent->xconfigure.border_width,
2489                  xevent->xconfigure.above - base_id,
2490                  xevent->xconfigure.override_redirect);
2491       
2492       if (window_private)
2493         {
2494           if ((window_private->extension_events != 0) &&
2495               gdk_input_vtable.configure_event)
2496             gdk_input_vtable.configure_event (&xevent->xconfigure, window);
2497           
2498           if (window_private->window_type != GDK_WINDOW_CHILD)
2499             {
2500               event->configure.type = GDK_CONFIGURE;
2501               event->configure.window = window;
2502               event->configure.width = xevent->xconfigure.width;
2503               event->configure.height = xevent->xconfigure.height;
2504               
2505               if (!xevent->xconfigure.x &&
2506                   !xevent->xconfigure.y)
2507                 {
2508                   gint tx = 0;
2509                   gint ty = 0;
2510                   Window child_window = 0;
2511
2512                   if (!XTranslateCoordinates (window_private->xdisplay,
2513                                               window_private->xwindow,
2514                                               gdk_root_window,
2515                                               0, 0,
2516                                               &tx, &ty,
2517                                               &child_window))
2518                     g_warning ("GdkWindow %ld doesn't share root windows display?",
2519                                window_private->xwindow - base_id);
2520                   event->configure.x = tx;
2521                   event->configure.y = ty;
2522                 }
2523               else
2524                 {
2525                   event->configure.x = xevent->xconfigure.x;
2526                   event->configure.y = xevent->xconfigure.y;
2527                 }
2528               window_private->x = event->configure.x;
2529               window_private->y = event->configure.y;
2530               window_private->width = xevent->xconfigure.width;
2531               window_private->height = xevent->xconfigure.height;
2532               if (window_private->resize_count > 1)
2533                 window_private->resize_count -= 1;
2534               
2535               return_val = !window_private->destroyed;
2536             }
2537         }
2538       break;
2539       
2540     case PropertyNotify:
2541       /* Print debugging info.
2542        */
2543       if (gdk_show_events)
2544         g_print ("property notify:\twindow: %ld\n",
2545                  xevent->xproperty.window - base_id);
2546
2547       event->property.type = GDK_PROPERTY_NOTIFY;
2548       event->property.window = window;
2549       event->property.atom = xevent->xproperty.atom;
2550       event->property.time = xevent->xproperty.time;
2551       event->property.state = xevent->xproperty.state;
2552
2553       return_val = window_private && !window_private->destroyed;
2554       break;
2555
2556     case SelectionClear:
2557       if (gdk_show_events)
2558         g_print ("selection clear:\twindow: %ld\n",
2559                  xevent->xproperty.window - base_id);
2560
2561       event->selection.type = GDK_SELECTION_CLEAR;
2562       event->selection.window = window;
2563       event->selection.selection = xevent->xselectionclear.selection;
2564       event->selection.time = xevent->xselectionclear.time;
2565
2566       return_val = window_private && !window_private->destroyed;
2567       break;
2568
2569     case SelectionRequest:
2570       if (gdk_show_events)
2571         g_print ("selection request:\twindow: %ld\n",
2572                  xevent->xproperty.window - base_id);
2573
2574       event->selection.type = GDK_SELECTION_REQUEST;
2575       event->selection.window = window;
2576       event->selection.selection = xevent->xselectionrequest.selection;
2577       event->selection.target = xevent->xselectionrequest.target;
2578       event->selection.property = xevent->xselectionrequest.property;
2579       event->selection.requestor = xevent->xselectionrequest.requestor;
2580       event->selection.time = xevent->xselectionrequest.time;
2581
2582       return_val = window_private && !window_private->destroyed;
2583       break;
2584
2585     case SelectionNotify:
2586       if (gdk_show_events)
2587         g_print ("selection notify:\twindow: %ld\n",
2588                  xevent->xproperty.window - base_id);
2589
2590
2591       event->selection.type = GDK_SELECTION_NOTIFY;
2592       event->selection.window = window;
2593       event->selection.selection = xevent->xselection.selection;
2594       event->selection.target = xevent->xselection.target;
2595       event->selection.property = xevent->xselection.property;
2596       event->selection.time = xevent->xselection.time;
2597
2598       return_val = window_private && !window_private->destroyed;
2599       break;
2600
2601     case ColormapNotify:
2602       /* Print debugging info.
2603        */
2604       if (gdk_show_events)
2605         g_print ("colormap notify:\twindow: %ld\n",
2606                  xevent->xcolormap.window - base_id);
2607
2608       /* Not currently handled */
2609       break;
2610
2611     case ClientMessage:
2612       /* Print debugging info.
2613        */
2614       if (gdk_show_events)
2615         g_print ("client message:\twindow: %ld\n",
2616                  xevent->xclient.window - base_id);
2617
2618       /* Client messages are the means of the window manager
2619        *  communicating with a program. We'll first check to
2620        *  see if this is really the window manager talking
2621        *  to us.
2622        */
2623       if (xevent->xclient.message_type == gdk_wm_protocols)
2624         {
2625           if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window)
2626             {
2627               /* The delete window request specifies a window
2628                *  to delete. We don't actually destroy the
2629                *  window because "it is only a request". (The
2630                *  window might contain vital data that the
2631                *  program does not want destroyed). Instead
2632                *  the event is passed along to the program,
2633                *  which should then destroy the window.
2634                */
2635
2636               /* Print debugging info.
2637                */
2638               if (gdk_show_events)
2639                 g_print ("delete window:\t\twindow: %ld\n",
2640                          xevent->xclient.window - base_id);
2641
2642               event->any.type = GDK_DELETE;
2643               event->any.window = window;
2644
2645               return_val = window_private && !window_private->destroyed;
2646             }
2647           else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
2648             {
2649             }
2650         }
2651       else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter)
2652         {
2653           Atom reptype = 0;
2654
2655           event->dropenter.u.allflags = xevent->xclient.data.l[1];
2656 #ifndef DEBUG_DND
2657           if (gdk_show_events)
2658 #endif
2659             g_print ("GDK_DROP_ENTER [%d][%d]\n",
2660                 window_private->dnd_drop_enabled, event->dropenter.u.flags.sendreply);
2661           return_val = FALSE;
2662
2663           /* Now figure out if we really want this drop...
2664            * If someone is trying funky clipboard stuff, ignore 
2665            */
2666           if (window_private
2667               && window_private->dnd_drop_enabled
2668               && event->dropenter.u.flags.sendreply
2669               && (reptype = gdk_dnd_check_types (window, xevent)))
2670             {
2671               XEvent replyev;
2672
2673               replyev.xclient.type = ClientMessage;
2674               replyev.xclient.window = xevent->xclient.data.l[0];
2675               replyev.xclient.format = 32;
2676               replyev.xclient.message_type = gdk_dnd.gdk_XdeRequest;
2677               replyev.xclient.data.l[0] = window_private->xwindow;
2678
2679               event->dragrequest.u.allflags = 0;
2680               event->dragrequest.u.flags.protocol_version =
2681                 DND_PROTOCOL_VERSION;
2682               event->dragrequest.u.flags.willaccept = 1;
2683               event->dragrequest.u.flags.delete_data =
2684                 (window_private->dnd_drop_destructive_op) ? 1 : 0;
2685
2686               replyev.xclient.data.l[1] = event->dragrequest.u.allflags;
2687               replyev.xclient.data.l[2] = replyev.xclient.data.l[3] = 0;
2688               replyev.xclient.data.l[4] = reptype;
2689
2690               XSendEvent (gdk_display, replyev.xclient.window,
2691                           False, NoEventMask, &replyev);
2692
2693               event->any.type = GDK_DROP_ENTER;
2694               event->any.window = window;
2695               event->dropenter.requestor = replyev.xclient.window;
2696               event->dropenter.u.allflags = xevent->xclient.data.l[1];
2697 #ifdef DEBUG_DND
2698               g_print("We sent a GDK_DROP_ENTER on to Gtk\n");
2699 #endif
2700               return_val = TRUE;
2701             }
2702         }
2703       else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeLeave)
2704         {
2705 #ifndef DEBUG_DND
2706           if (gdk_show_events)
2707 #endif
2708             g_print ("GDK_DROP_LEAVE\n");
2709           if (window_private && window_private->dnd_drop_enabled)
2710             {
2711               event->dropleave.type = GDK_DROP_LEAVE;
2712               event->dropleave.window = window;
2713               event->dropleave.requestor = xevent->xclient.data.l[0];
2714               event->dropleave.u.allflags = xevent->xclient.data.l[1];
2715               return_val = TRUE;
2716             }
2717           else
2718             return_val = FALSE;
2719         }
2720       else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeRequest)
2721         {
2722           /* 
2723            * make sure to only handle requests from the window the cursor is
2724            * over 
2725            */
2726 #ifndef DEBUG_DND
2727           if (gdk_show_events)
2728 #endif
2729             g_print ("GDK_DRAG_REQUEST\n");
2730           event->dragrequest.u.allflags = xevent->xclient.data.l[1];
2731           return_val = FALSE;
2732
2733           if (window && gdk_dnd.drag_really &&
2734               xevent->xclient.data.l[0] == dnd_drag_curwin &&
2735               event->dragrequest.u.flags.sendreply == 0)
2736             {
2737               /* Got request - do we need to ask user? */
2738               if (!event->dragrequest.u.flags.willaccept
2739                   && event->dragrequest.u.flags.senddata)
2740                 {
2741                   /* Yes we do :) */
2742                   event->dragrequest.type = GDK_DRAG_REQUEST;
2743                   event->dragrequest.window = window;
2744                   event->dragrequest.requestor = xevent->xclient.data.l[0];
2745                   event->dragrequest.isdrop = 0;
2746                   event->dragrequest.drop_coords.x =
2747                     event->dragrequest.drop_coords.y = 0;
2748                   return_val = TRUE;
2749                 }
2750               else if (event->dragrequest.u.flags.willaccept)
2751                 {
2752                   window_private->dnd_drag_destructive_op =
2753                     event->dragrequest.u.flags.delete_data;
2754                   window_private->dnd_drag_accepted = 1;
2755                   window_private->dnd_drag_data_type =
2756                     xevent->xclient.data.l[4];
2757
2758                   dnd_drag_target = dnd_drag_curwin;
2759                   XChangeActivePointerGrab (gdk_display,
2760                                             ButtonMotionMask |
2761                                             ButtonPressMask |
2762                                             ButtonReleaseMask |
2763                                             EnterWindowMask | LeaveWindowMask,
2764                                             gdk_dnd.gdk_cursor_dragok,
2765                                             CurrentTime);
2766                 }
2767               dnd_drag_dropzone.x = xevent->xclient.data.l[2] & 65535;
2768               dnd_drag_dropzone.y =
2769                 (xevent->xclient.data.l[2] >> 16) & 65535;
2770               dnd_drag_dropzone.width = xevent->xclient.data.l[3] & 65535;
2771               dnd_drag_dropzone.height =
2772                 (xevent->xclient.data.l[3] >> 16) & 65535;
2773             }
2774         }
2775       else if(xevent->xclient.message_type == gdk_dnd.gdk_XdeDataAvailable)
2776           {
2777             gint tmp_int; Atom tmp_atom;
2778             gulong tmp_long;
2779             guchar *tmp_charptr;
2780
2781 #ifndef DEBUG_DND
2782             if(gdk_show_events)
2783 #endif
2784               g_print("GDK_DROP_DATA_AVAIL\n");
2785             event->dropdataavailable.u.allflags = xevent->xclient.data.l[1];
2786             if(window
2787                /* No preview of data ATM */
2788                && event->dropdataavailable.u.flags.isdrop)
2789               {
2790                 event->dropdataavailable.type = GDK_DROP_DATA_AVAIL;
2791                 event->dropdataavailable.window = window;
2792                 event->dropdataavailable.requestor = xevent->xclient.data.l[0];
2793                 event->dropdataavailable.data_type =
2794                         gdk_atom_name(xevent->xclient.data.l[2]);
2795                 if(XGetWindowProperty (gdk_display,
2796                                     event->dropdataavailable.requestor,
2797                                     xevent->xclient.data.l[2],
2798                                     0, LONG_MAX - 1,
2799                                     False, XA_PRIMARY, &tmp_atom,
2800                                     &tmp_int,
2801                                     &event->dropdataavailable.data_numbytes,
2802                                     &tmp_long,
2803                                     &tmp_charptr)
2804                    != Success)
2805                   {
2806                     g_warning("XGetWindowProperty on %#x may have failed\n",
2807                             event->dropdataavailable.requestor);
2808                             event->dropdataavailable.data = NULL;
2809                   }
2810                 else
2811                   {
2812 #ifdef DEBUG_DND
2813                     g_print("XGetWindowProperty got us %d bytes\n",
2814                             event->dropdataavailable.data_numbytes);
2815 #endif
2816                     event->dropdataavailable.data =
2817                         g_malloc (event->dropdataavailable.data_numbytes);
2818                     memcpy (event->dropdataavailable.data,
2819                         tmp_charptr, event->dropdataavailable.data_numbytes);
2820                     XFree(tmp_charptr);
2821                     return_val = TRUE;
2822                   }
2823               return_val = TRUE;
2824             }
2825         }
2826       else
2827         {
2828           /* Send unknown ClientMessage's on to Gtk for it to use */
2829           event->client.type = GDK_CLIENT_EVENT;
2830           event->client.window = window;
2831           event->client.message_type = xevent->xclient.message_type;
2832           event->client.data_format = xevent->xclient.format;
2833           memcpy(&event->client.data, &xevent->xclient.data,
2834                  sizeof(event->client.data));
2835           if(window)
2836             return_val = TRUE;
2837           else  
2838             return_val = FALSE;
2839         }
2840       if(window_private)
2841         return_val = return_val && !window_private->destroyed;
2842       break;
2843       
2844     case MappingNotify:
2845       /* Print debugging info.
2846        */
2847       if (gdk_show_events)
2848         g_print ("mapping notify\n");
2849
2850       /* Let XLib know that there is a new keyboard mapping.
2851        */
2852       XRefreshKeyboardMapping (&xevent->xmapping);
2853       break;
2854
2855     default:
2856       /* something else - (e.g., a Xinput event) */
2857
2858       if (window_private &&
2859           (window_private->extension_events != 0) &&
2860           gdk_input_vtable.other_event)
2861         return_val = gdk_input_vtable.other_event(event, xevent, window);
2862       else
2863         return_val = -1;
2864
2865       if (return_val < 0)       /* not an XInput event, convert */
2866         {
2867           event->other.type = GDK_OTHER_EVENT;
2868           event->other.window = window;
2869           event->other.xevent = (GdkXEvent *)&other_xevent[other_xevent_i];
2870           memcpy (&other_xevent[other_xevent_i], xevent, sizeof (XEvent));
2871           other_xevent_i = (other_xevent_i+1) % OTHER_XEVENT_BUFSIZE;
2872           return_val = TRUE;
2873         }
2874       else
2875         return_val = return_val && !window_private->destroyed;
2876
2877       break;
2878     }
2879
2880   if (return_val)
2881     {
2882       if (event->any.window)
2883         gdk_window_ref (event->any.window);
2884       if (((event->any.type == GDK_ENTER_NOTIFY) ||
2885            (event->any.type == GDK_LEAVE_NOTIFY)) &&
2886           (event->crossing.subwindow != NULL))
2887         gdk_window_ref (event->crossing.subwindow);
2888     }
2889   else
2890     {
2891       /* Mark this event as having no resources to be freed */
2892       event->any.window = NULL;
2893       event->any.type = GDK_NOTHING;
2894     }
2895
2896   if (window)
2897     gdk_window_unref (window);
2898
2899   return return_val;
2900 }
2901
2902 #if 0
2903 static Bool
2904 gdk_event_get_type (Display  *display,
2905                     XEvent   *xevent,
2906                     XPointer  arg)
2907 {
2908   GdkEvent event;
2909   GdkPredicate *pred;
2910
2911   if (gdk_event_translate (&event, xevent))
2912     {
2913       pred = (GdkPredicate*) arg;
2914       return (* pred->func) (&event, pred->data);
2915     }
2916
2917   return FALSE;
2918 }
2919 #endif
2920
2921 static void
2922 gdk_synthesize_click (GdkEvent *event,
2923                       gint      nclicks)
2924 {
2925   GdkEvent temp_event;
2926
2927   g_return_if_fail (event != NULL);
2928
2929   temp_event = *event;
2930   temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
2931
2932   gdk_event_put (&temp_event);
2933 }
2934
2935 /*
2936  *--------------------------------------------------------------
2937  * gdk_exit_func
2938  *
2939  *   This is the "atexit" function that makes sure the
2940  *   library gets a chance to cleanup.
2941  *
2942  * Arguments:
2943  *
2944  * Results:
2945  *
2946  * Side effects:
2947  *   The library is un-initialized and the program exits.
2948  *
2949  *--------------------------------------------------------------
2950  */
2951
2952 static void
2953 gdk_exit_func ()
2954 {
2955   static gboolean in_gdk_exit_func = FALSE;
2956
2957   /* This is to avoid an infinite loop if a program segfaults in
2958      an atexit() handler (and yes, it does happen, especially if a program
2959      has trounced over memory too badly for even g_print to work) */
2960   if(in_gdk_exit_func == TRUE) return;
2961   in_gdk_exit_func = TRUE;
2962
2963   if (initialized)
2964     {
2965 #ifdef USE_XIM
2966       /* cleanup IC */
2967       gdk_ic_cleanup ();
2968       /* close IM */
2969       gdk_im_close ();
2970 #endif
2971       gdk_image_exit ();
2972       gdk_input_exit ();
2973       gdk_key_repeat_restore ();
2974
2975       XCloseDisplay (gdk_display);
2976       initialized = 0;
2977     }
2978 }
2979
2980 /*
2981  *--------------------------------------------------------------
2982  * gdk_x_error
2983  *
2984  *   The X error handling routine.
2985  *
2986  * Arguments:
2987  *   "display" is the X display the error orignated from.
2988  *   "error" is the XErrorEvent that we are handling.
2989  *
2990  * Results:
2991  *   Either we were expecting some sort of error to occur,
2992  *   in which case we set the "gdk_error_code" flag, or this
2993  *   error was unexpected, in which case we will print an
2994  *   error message and exit. (Since trying to continue will
2995  *   most likely simply lead to more errors).
2996  *
2997  * Side effects:
2998  *
2999  *--------------------------------------------------------------
3000  */
3001
3002 static int
3003 gdk_x_error (Display     *display,
3004              XErrorEvent *error)
3005 {
3006   char buf[64];
3007
3008   if (gdk_error_warnings)
3009     {
3010       XGetErrorText (display, error->error_code, buf, 63);
3011       g_error ("%s", buf);
3012     }
3013
3014   gdk_error_code = -1;
3015   return 0;
3016 }
3017
3018 /*
3019  *--------------------------------------------------------------
3020  * gdk_x_io_error
3021  *
3022  *   The X I/O error handling routine.
3023  *
3024  * Arguments:
3025  *   "display" is the X display the error orignated from.
3026  *
3027  * Results:
3028  *   An X I/O error basically means we lost our connection
3029  *   to the X server. There is not much we can do to
3030  *   continue, so simply print an error message and exit.
3031  *
3032  * Side effects:
3033  *
3034  *--------------------------------------------------------------
3035  */
3036
3037 static int
3038 gdk_x_io_error (Display *display)
3039 {
3040   g_error ("an x io error occurred");
3041   return 0;
3042 }
3043
3044 /*
3045  *--------------------------------------------------------------
3046  * gdk_signal
3047  *
3048  *   The signal handler.
3049  *
3050  * Arguments:
3051  *   "sig_num" is the number of the signal we received.
3052  *
3053  * Results:
3054  *   The signals we catch are all fatal. So we simply build
3055  *   up a nice little error message and print it and exit.
3056  *   If in the process of doing so another signal is received
3057  *   we notice that we are already exiting and simply kill
3058  *   our process.
3059  *
3060  * Side effects:
3061  *
3062  *--------------------------------------------------------------
3063  */
3064
3065 static RETSIGTYPE
3066 gdk_signal (int sig_num)
3067 {
3068   static int caught_fatal_sig = 0;
3069   char *sig;
3070
3071   if (caught_fatal_sig)
3072     kill (getpid (), sig_num);
3073   caught_fatal_sig = 1;
3074
3075   switch (sig_num)
3076     {
3077     case SIGHUP:
3078       sig = "sighup";
3079       break;
3080     case SIGINT:
3081       sig = "sigint";
3082       break;
3083     case SIGQUIT:
3084       sig = "sigquit";
3085       break;
3086     case SIGBUS:
3087       sig = "sigbus";
3088       break;
3089     case SIGSEGV:
3090       sig = "sigsegv";
3091       break;
3092     case SIGPIPE:
3093       sig = "sigpipe";
3094       break;
3095     case SIGTERM:
3096       sig = "sigterm";
3097       break;
3098     default:
3099       sig = "unknown signal";
3100       break;
3101     }
3102
3103   g_print ("\n** ERROR **: %s caught\n", sig);
3104   gdk_exit (1);
3105 }
3106
3107 static void
3108 gdk_dnd_drag_begin (GdkWindow *initial_window)
3109 {
3110   GdkEventDragBegin tev;
3111   tev.type = GDK_DRAG_BEGIN;
3112   tev.window = initial_window;
3113   tev.u.allflags = 0;
3114   tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
3115
3116   gdk_event_put ((GdkEvent *) &tev);
3117 }
3118
3119 static void
3120 gdk_dnd_drag_enter (Window dest)
3121 {
3122   XEvent sev;
3123   GdkEventDropEnter tev;
3124   int i;
3125   GdkWindowPrivate *wp;
3126   
3127   sev.xclient.type = ClientMessage;
3128   sev.xclient.format = 32;
3129   sev.xclient.message_type = gdk_dnd.gdk_XdeEnter;
3130   sev.xclient.window = dest;
3131
3132   tev.u.allflags = 0;
3133   tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
3134   tev.u.flags.sendreply = 1;
3135   for (i = 0; i < gdk_dnd.drag_numwindows; i++)
3136     {
3137       wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i];
3138       if (wp->dnd_drag_data_numtypesavail)
3139         {
3140           sev.xclient.data.l[0] = wp->xwindow;
3141           tev.u.flags.extended_typelist = (wp->dnd_drag_data_numtypesavail > 3)?1:0;
3142           sev.xclient.data.l[1] = tev.u.allflags;
3143           sev.xclient.data.l[2] = wp->dnd_drag_data_typesavail[0];
3144           if (wp->dnd_drag_data_numtypesavail > 1)
3145             {
3146               sev.xclient.data.l[3] = wp->dnd_drag_data_typesavail[1];
3147               if (wp->dnd_drag_data_numtypesavail > 2)
3148                 {
3149                   sev.xclient.data.l[4] = wp->dnd_drag_data_typesavail[2];
3150                 }
3151               else
3152                 sev.xclient.data.l[4] = None;
3153             }
3154           else
3155             sev.xclient.data.l[3] = sev.xclient.data.l[4] = None;
3156           XSendEvent (gdk_display, dest, False, NoEventMask, &sev);
3157         }
3158
3159     }
3160 }
3161
3162
3163 #ifdef USE_XIM
3164
3165 /*
3166  *--------------------------------------------------------------
3167  * gdk_im_begin
3168  *
3169  *   Begin using input method with XIM Protocol(X11R6 standard)
3170  *
3171  * Arguments:
3172  *   "ic" is the "Input Context" which is created by gtk_ic_new.
3173  *   The input area is specified with "window".
3174  *
3175  * Results:
3176  *   The gdk's event handling routine is switched to XIM based routine.
3177  *   XIM based routine uses XFilterEvent to get rid of events used by IM,
3178  *   and uses XmbLookupString instead of XLookupString.
3179  *
3180  * Side effects:
3181  *
3182  *--------------------------------------------------------------
3183  */
3184
3185 void 
3186 gdk_im_begin (GdkIC ic, GdkWindow* window)
3187 {
3188   GdkICPrivate *private;
3189   Window xwin;
3190
3191   g_return_if_fail (ic != NULL);
3192   g_return_if_fail (window);
3193
3194   private = (GdkICPrivate *) ic;
3195
3196   xim_using = TRUE;
3197   xim_ic = private;
3198   xim_window = window;
3199   if (gdk_im_ready())
3200     {
3201       XGetICValues (private->xic, XNFocusWindow, &xwin, NULL);
3202       if (xwin != GDK_WINDOW_XWINDOW(window))
3203         XSetICValues (private->xic, XNFocusWindow, 
3204                       GDK_WINDOW_XWINDOW(window), NULL);
3205       if (private != xim_ic)
3206         XSetICFocus (private->xic);
3207     }
3208 }
3209
3210 /*
3211  *--------------------------------------------------------------
3212  * gdk_im_end
3213  *
3214  *   End using input method with XIM Protocol(X11R6 standard)
3215  *
3216  * Arguments:
3217  *
3218  * Results:
3219  *   The gdk's event handling routine is switched to normal routine.
3220  *   User should call this function before ic and window will be destroyed.
3221  *
3222  * Side effects:
3223  *
3224  *--------------------------------------------------------------
3225  */
3226
3227 void 
3228 gdk_im_end (void)
3229 {
3230   xim_using = FALSE;
3231   xim_ic = NULL;
3232   xim_window = NULL;
3233 }
3234
3235 static GdkIM 
3236 gdk_im_get (void)
3237 {
3238   return xim_im;
3239 }
3240
3241 static GdkIMStyle 
3242 gdk_im_choose_better_style (GdkIMStyle style1, GdkIMStyle style2) 
3243 {
3244   GdkIMStyle s1, s2, u;
3245
3246   if (style1 == 0) return style2;
3247   if (style2 == 0) return style1;
3248   if ((style1 & (GdkIMPreeditMask | GdkIMStatusMask))
3249         == (style2 & (GdkIMPreeditMask | GdkIMStatusMask)))
3250     return style1;
3251
3252   s1 = style1 & GdkIMPreeditMask;
3253   s2 = style2 & GdkIMPreeditMask;
3254   u = s1 | s2;
3255   if (s1 != s2) {
3256     if (u & GdkIMPreeditCallbacks)
3257       return (s1 == GdkIMPreeditCallbacks)? style1:style2;
3258     else if (u & GdkIMPreeditPosition)
3259       return (s1 == GdkIMPreeditPosition)? style1:style2;
3260     else if (u & GdkIMPreeditArea)
3261       return (s1 == GdkIMPreeditArea)? style1:style2;
3262     else if (u & GdkIMPreeditNothing)
3263       return (s1 == GdkIMPreeditNothing)? style1:style2;
3264   } else {
3265     s1 = style1 & GdkIMStatusMask;
3266     s2 = style2 & GdkIMStatusMask;
3267     u = s1 | s2;
3268     if ( u & GdkIMStatusCallbacks)
3269       return (s1 == GdkIMStatusCallbacks)? style1:style2;
3270     else if ( u & GdkIMStatusArea)
3271       return (s1 == GdkIMStatusArea)? style1:style2;
3272     else if ( u & GdkIMStatusNothing)
3273       return (s1 == GdkIMStatusNothing)? style1:style2;
3274     else if ( u & GdkIMStatusNone)
3275       return (s1 == GdkIMStatusNone)? style1:style2;
3276   }
3277   return 0; /* Get rid of stupid warning */
3278 }
3279
3280 GdkIMStyle
3281 gdk_im_decide_style (GdkIMStyle supported_style)
3282 {
3283   gint i;
3284   GdkIMStyle style, tmp;
3285
3286   g_return_val_if_fail (xim_styles != NULL, 0);
3287
3288   style = 0;
3289   for (i=0; i<xim_styles->count_styles; i++)
3290     {
3291       tmp = xim_styles->supported_styles[i];
3292       if (tmp == (tmp & supported_style & xim_best_allowed_style))
3293         style = gdk_im_choose_better_style (style, tmp);
3294     }
3295   return style;
3296 }
3297
3298 GdkIMStyle
3299 gdk_im_set_best_style (GdkIMStyle style)
3300 {
3301   if (style & GdkIMPreeditMask)
3302     {
3303       xim_best_allowed_style &= ~GdkIMPreeditMask;
3304
3305       xim_best_allowed_style |= GdkIMPreeditNone;
3306       if (!(style & GdkIMPreeditNone))
3307         {
3308           xim_best_allowed_style |= GdkIMPreeditNothing;
3309           if (!(style & GdkIMPreeditNothing))
3310             {
3311               xim_best_allowed_style |= GdkIMPreeditArea;
3312               if (!(style & GdkIMPreeditArea))
3313                 {
3314                   xim_best_allowed_style |= GdkIMPreeditPosition;
3315                   if (!(style & GdkIMPreeditPosition))
3316                     xim_best_allowed_style |= GdkIMPreeditCallbacks;
3317                 }
3318             }
3319         }
3320     }
3321   if (style & GdkIMStatusMask)
3322     {
3323       xim_best_allowed_style &= ~GdkIMStatusMask;
3324
3325       xim_best_allowed_style |= GdkIMStatusNone;
3326       if (!(style & GdkIMStatusNone))
3327         {
3328           xim_best_allowed_style |= GdkIMStatusNothing;
3329           if (!(style & GdkIMStatusNothing))
3330             {
3331               xim_best_allowed_style |= GdkIMStatusArea;
3332               if (!(style & GdkIMStatusArea))
3333                 xim_best_allowed_style |= GdkIMStatusCallbacks;
3334             }
3335         }
3336     }
3337   
3338   return xim_best_allowed_style;
3339 }
3340
3341 static gint 
3342 gdk_im_open (XrmDatabase db, gchar* res_name, gchar* res_class)
3343 {
3344   xim_im = XOpenIM (GDK_DISPLAY(), db, res_name, res_class);
3345   if (xim_im == NULL)
3346     {
3347       g_warning ("Don\'t open IM.");
3348       return FALSE;
3349     }
3350   XGetIMValues (xim_im, XNQueryInputStyle, &xim_styles, NULL, NULL);
3351
3352   return TRUE;
3353 }
3354
3355 static void 
3356 gdk_im_close (void)
3357 {
3358   if (xim_im)
3359     {
3360       XCloseIM (xim_im);
3361       xim_im = NULL;
3362     }
3363   if (xim_styles)
3364     {
3365       XFree (xim_styles);
3366       xim_styles = NULL;
3367     }
3368 }
3369
3370 gint 
3371 gdk_im_ready (void)
3372 {
3373   return (xim_im != NULL);
3374 }
3375
3376 GdkIC 
3377 gdk_ic_new (GdkWindow* client_window,
3378             GdkWindow* focus_window,
3379             GdkIMStyle style, ...)
3380 {
3381   va_list list;
3382   GdkICPrivate *private;
3383   XVaNestedList preedit_attr;
3384
3385   g_return_val_if_fail (client_window != NULL, NULL);
3386   g_return_val_if_fail (focus_window != NULL, NULL);
3387   g_return_val_if_fail (gdk_im_ready(), NULL);
3388
3389   private = g_new (GdkICPrivate, 1);
3390
3391   va_start (list, style);
3392   preedit_attr =  (XVaNestedList) & (va_arg (list, void *));
3393   va_end (list);
3394
3395   private->style = gdk_im_decide_style (style);
3396   if (private->style != style)
3397     {
3398       g_warning ("can not create input context with specified input style.");
3399       g_free (private);
3400       return NULL;
3401     }
3402
3403   private->xic = XCreateIC(gdk_im_get (),
3404                         XNInputStyle,   style,
3405                         XNClientWindow, GDK_WINDOW_XWINDOW (client_window),
3406                         XNFocusWindow,  GDK_WINDOW_XWINDOW (focus_window),
3407                         preedit_attr? XNPreeditAttributes : NULL, preedit_attr,
3408                         NULL);
3409   if (!private->xic)
3410     {
3411       g_free (private);
3412       return NULL;
3413     }
3414
3415   xim_ic_list = g_list_append (xim_ic_list, private);
3416   return private;
3417 }
3418
3419 void 
3420 gdk_ic_destroy (GdkIC ic)
3421 {
3422   GdkICPrivate *private;
3423
3424   g_return_if_fail (ic != NULL);
3425   
3426   private = (GdkICPrivate *) ic;
3427
3428   if (xim_ic == private)
3429     gdk_im_end ();
3430
3431   XDestroyIC (private->xic);
3432   xim_ic_list = g_list_remove (xim_ic_list, private);
3433 }
3434
3435 GdkIMStyle
3436 gdk_ic_get_style (GdkIC ic)
3437 {
3438   GdkICPrivate *private;
3439
3440   g_return_val_if_fail (ic != NULL, 0);
3441
3442   private = (GdkICPrivate *) ic;
3443
3444   return private->style;
3445 }
3446
3447 void 
3448 gdk_ic_set_values (GdkIC ic, ...)
3449 {
3450   va_list list;
3451   XVaNestedList args;
3452   GdkICPrivate *private;
3453
3454   g_return_if_fail (ic != NULL);
3455
3456   private = (GdkICPrivate *) ic;
3457
3458   va_start (list, ic);
3459   args =  (XVaNestedList) & (va_arg (list, void *));
3460   va_end (list);
3461
3462   XSetICValues (private->xic, XNVaNestedList, args, NULL);
3463 }
3464
3465 void 
3466 gdk_ic_get_values (GdkIC ic, ...)
3467 {
3468   va_list list;
3469   XVaNestedList args;
3470   GdkICPrivate *private;
3471
3472   g_return_if_fail (ic != NULL);
3473
3474   private = (GdkICPrivate *) ic;
3475
3476   va_start (list, ic);
3477   args =  (XVaNestedList) & (va_arg (list, void *));
3478   va_end (list);
3479
3480   XGetICValues (private->xic, XNVaNestedList, args, NULL);
3481 }
3482
3483 void 
3484 gdk_ic_set_attr (GdkIC ic, const char *target, ...)
3485 {
3486   va_list list;
3487   XVaNestedList attr;
3488   GdkICPrivate *private;
3489
3490   g_return_if_fail (ic != NULL);
3491   g_return_if_fail (target != NULL);
3492
3493   private = (GdkICPrivate *) ic;
3494
3495   va_start (list, target);
3496   attr =  (XVaNestedList) & (va_arg (list, void *));
3497   va_end (list);
3498
3499   XSetICValues (private->xic, target, attr, NULL);
3500 }
3501
3502 void 
3503 gdk_ic_get_attr (GdkIC ic, const char *target, ...)
3504 {
3505   va_list list;
3506   XVaNestedList attr;
3507   GdkICPrivate *private;
3508
3509   g_return_if_fail (ic != NULL);
3510   g_return_if_fail (target != NULL);
3511
3512   private = (GdkICPrivate *) ic;
3513
3514   va_start (list, target);
3515   attr =  (XVaNestedList) & (va_arg (list, void *));
3516   va_end (list);
3517
3518   XGetICValues (private->xic, target, attr, NULL);
3519 }
3520
3521 GdkEventMask 
3522 gdk_ic_get_events (GdkIC ic)
3523 {
3524   GdkEventMask mask;
3525   glong xmask;
3526   glong bit;
3527   GdkICPrivate *private;
3528   gint i;
3529
3530   /*  From gdkwindow.c  */
3531   extern int nevent_masks;
3532   extern int event_mask_table[];
3533
3534   g_return_val_if_fail (ic != NULL, 0);
3535
3536   private = (GdkICPrivate *) ic;
3537
3538   XGetICValues (private->xic, XNFilterEvents, &xmask, NULL);
3539
3540   mask = 0;
3541   for (i=0, bit=2; i < nevent_masks; i++, bit <<= 1)
3542     if (xmask & event_mask_table [i])
3543       {
3544         mask |= bit;
3545         xmask &= ~ event_mask_table [i];
3546       }
3547
3548   if (xmask)
3549     g_warning ("ic requires the events not supported by the application (%04lx)", xmask);
3550   
3551   return mask;
3552 }
3553
3554 static void 
3555 gdk_ic_cleanup (void)
3556 {
3557   GList* node;
3558   gint destroyed;
3559   GdkICPrivate *private;
3560
3561   destroyed = 0;
3562   for (node = xim_ic_list; node != NULL; node = node->next)
3563     {
3564       if (node->data)
3565        {
3566          private = (GdkICPrivate *) (node->data);
3567          XDestroyIC (private->xic);
3568          g_free (private);
3569          destroyed++;
3570        }
3571     }
3572   if (gdk_debug_level >= 1 && destroyed > 0)
3573     {
3574       g_warning ("Cleanuped %i IC\n", destroyed);
3575     }
3576   g_list_free(xim_ic_list);
3577   xim_ic_list = NULL;
3578 }
3579
3580 #else /* !USE_XIM */
3581
3582 void 
3583 gdk_im_begin (GdkIC ic, GdkWindow* window)
3584 {
3585 }
3586
3587 void 
3588 gdk_im_end (void)
3589 {
3590 }
3591
3592 GdkIMStyle
3593 gdk_im_decide_style (GdkIMStyle supported_style)
3594 {
3595   return GdkIMPreeditNone | GdkIMStatusNone;
3596 }
3597
3598 GdkIMStyle
3599 gdk_im_set_best_style (GdkIMStyle style)
3600 {
3601   return GdkIMPreeditNone | GdkIMStatusNone;
3602 }
3603
3604 gint 
3605 gdk_im_ready (void)
3606 {
3607   return FALSE;
3608 }
3609
3610 GdkIC 
3611 gdk_ic_new (GdkWindow* client_window,
3612             GdkWindow* focus_window,
3613             GdkIMStyle style, ...)
3614 {
3615   return NULL;
3616 }
3617
3618 void 
3619 gdk_ic_destroy (GdkIC ic)
3620 {
3621 }
3622
3623 GdkIMStyle
3624 gdk_ic_get_style (GdkIC ic)
3625 {
3626   return GdkIMPreeditNone | GdkIMStatusNone;
3627 }
3628
3629 void 
3630 gdk_ic_set_values (GdkIC ic, ...)
3631 {
3632 }
3633
3634 void 
3635 gdk_ic_get_values (GdkIC ic, ...)
3636 {
3637 }
3638
3639 void 
3640 gdk_ic_set_attr (GdkIC ic, const char *target, ...)
3641 {
3642 }
3643
3644 void 
3645 gdk_ic_get_attr (GdkIC ic, const char *target, ...)
3646 {
3647 }
3648
3649 GdkEventMask 
3650 gdk_ic_get_events (GdkIC ic)
3651 {
3652   return 0;
3653 }
3654
3655 #endif /* USE_XIM */
3656
3657 #ifdef X_LOCALE
3658
3659 gint
3660 _g_mbtowc (wchar_t *wstr, const char *str, size_t len)
3661 {
3662   static wchar_t wcs[MB_CUR_MAX + 1];
3663   static gchar mbs[MB_CUR_MAX + 1];
3664
3665   wcs[0] = (wchar_t) NULL;
3666   mbs[0] = '\0';
3667
3668   len = _Xmbstowcs (wcs, str, (len<MB_CUR_MAX)? len:MB_CUR_MAX);
3669   if (len < 1)
3670     return len;
3671   else if (wcs[0] == (wchar_t) NULL)
3672     return -1;
3673
3674   len = _Xwctomb (mbs, wcs[0]);
3675   if (mbs[0] == '\0')
3676     return -1;
3677   if (wstr)
3678     *wstr = wcs[0];
3679
3680   return len;
3681 }
3682
3683 #endif /* X_LOCALE */
3684
3685 static void
3686 gdk_dnd_drag_leave (Window dest)
3687 {
3688   XEvent sev;
3689   GdkEventDropLeave tev;
3690   int i;
3691   GdkWindowPrivate *wp;
3692
3693   tev.u.allflags = 0;
3694
3695   tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
3696   sev.xclient.type = ClientMessage;
3697   sev.xclient.window = dest;
3698   sev.xclient.format = 32;
3699   sev.xclient.message_type = gdk_dnd.gdk_XdeLeave;
3700   sev.xclient.data.l[1] = tev.u.allflags;
3701   for (i = 0; i < gdk_dnd.drag_numwindows; i++)
3702     {
3703       wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i];
3704       sev.xclient.data.l[0] = wp->xwindow;
3705       XSendEvent(gdk_display, dest, False, NoEventMask, &sev);
3706       wp->dnd_drag_accepted = 0;
3707     }
3708 }
3709
3710 /* 
3711  * when a drop occurs, we go through the list of windows being dragged and
3712  * tell them that it has occurred, so that they can set things up and reply
3713  * to 'dest' window 
3714  */
3715 static void
3716 gdk_dnd_drag_end (Window     dest, 
3717                   GdkPoint   coords)
3718 {
3719   GdkWindowPrivate *wp;
3720   GdkEventDragRequest tev;
3721   int i;
3722
3723   tev.type = GDK_DRAG_REQUEST;
3724   tev.drop_coords = coords;
3725   tev.requestor = dest;
3726   tev.u.allflags = 0;
3727   tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
3728   tev.isdrop = 1;
3729
3730   for (i = 0; i < gdk_dnd.drag_numwindows; i++)
3731     {
3732       wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i];
3733       if (wp->dnd_drag_accepted)
3734         {
3735           tev.window = (GdkWindow *) wp;
3736           tev.u.flags.delete_data = wp->dnd_drag_destructive_op;
3737           tev.data_type = 
3738                 gdk_atom_name(wp->dnd_drag_data_type);
3739
3740           gdk_event_put((GdkEvent *) &tev);
3741         }
3742     }
3743 }
3744
3745 static GdkAtom
3746 gdk_dnd_check_types (GdkWindow   *window, 
3747                      XEvent      *xevent)
3748 {
3749   GdkWindowPrivate *wp = (GdkWindowPrivate *) window;
3750   int i, j;
3751   GdkEventDropEnter event;
3752
3753   g_return_val_if_fail(window != NULL, 0);
3754   g_return_val_if_fail(xevent != NULL, 0);
3755   g_return_val_if_fail(xevent->type == ClientMessage, 0);
3756   g_return_val_if_fail(xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter, 0);
3757
3758   if(wp->dnd_drop_data_numtypesavail <= 0 ||
3759      !wp->dnd_drop_data_typesavail)
3760     return 0;
3761
3762   for (i = 2; i <= 4; i++)
3763     {
3764       for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++)
3765         {
3766           if (xevent->xclient.data.l[i] == wp->dnd_drop_data_typesavail[j])
3767             return xevent->xclient.data.l[i];
3768         }
3769     }
3770
3771   /* Now we get the extended type list if it's available */
3772   event.u.allflags = xevent->xclient.data.l[1];
3773   if (event.u.flags.extended_typelist)
3774     {
3775       Atom *exttypes, realtype;
3776       gulong nitems, nbar;
3777       gint realfmt;
3778
3779       if (XGetWindowProperty(gdk_display, xevent->xclient.data.l[0],
3780                              gdk_dnd.gdk_XdeTypelist, 0L, LONG_MAX - 1,
3781                              False, AnyPropertyType, &realtype, &realfmt,
3782                              &nitems, &nbar, (unsigned char **) &exttypes)
3783          != Success)
3784         return 0;
3785
3786       if (realfmt != (sizeof(Atom) * 8))
3787         {
3788           g_warning("XdeTypelist property had format of %d instead of the expected %d, on window %#lx\n",
3789                     realfmt, sizeof(Atom) * 8, xevent->xclient.data.l[0]);
3790           return 0;
3791         }
3792
3793       for (i = 0; i <= nitems; i++)
3794         {
3795           for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++)
3796             {
3797               if (exttypes[i] == wp->dnd_drop_data_typesavail[j])
3798                 {
3799                   XFree (exttypes);
3800                   return exttypes[i];
3801                 }
3802             }
3803         }
3804       XFree (exttypes);
3805     }
3806   return 0;
3807 }
3808
3809 /* 
3810  * used for debugging only 
3811  */
3812 #ifdef DEBUG_DND
3813 static void
3814 gdk_print_atom (GdkAtom anatom)
3815 {
3816   gchar *tmpstr = NULL;
3817   tmpstr = (anatom!=None)?gdk_atom_name(anatom):"(none)";
3818   g_print("Atom %lu has name %s\n", anatom, tmpstr);
3819   if(tmpstr)
3820     g_free(tmpstr);
3821 }
3822 #endif
3823
3824 /* 
3825  * used only by below routine and itself 
3826  */
3827 static Window 
3828 getchildren (Display     *dpy, 
3829              Window       win, 
3830              Atom         WM_STATE)
3831 {
3832   Window root, parent, *children, inf = 0;
3833   Atom type = None;
3834   unsigned int nchildren, i;
3835   int format;
3836   unsigned long nitems, after;
3837   unsigned char *data;
3838
3839   if (XQueryTree(dpy, win, &root, &parent, &children, &nchildren) == 0)
3840     return 0;
3841
3842   for (i = 0; !inf && (i < nchildren); i++)
3843     {
3844       XGetWindowProperty (dpy, children[i], WM_STATE, 0, 0, False,
3845                           AnyPropertyType, &type, &format, &nitems,
3846                           &after, &data);
3847       if (type != 0)
3848         inf = children[i];
3849       XFree(data);
3850     }
3851
3852   for (i = 0; !inf && (i < nchildren); i++)
3853     inf = getchildren (dpy, children[i], WM_STATE);
3854
3855   if (children != None)
3856     XFree ((char *) children);
3857
3858   return inf;
3859 }
3860
3861 /* 
3862  * find a window with WM_STATE, else return win itself, as per ICCCM
3863  *
3864  * modification of the XmuClientWindow() routine from X11R6.3
3865  */
3866 Window
3867 gdk_get_client_window (Display  *dpy, 
3868                        Window    win)
3869 {
3870   Atom WM_STATE;
3871   Atom type = None;
3872   int format;
3873   unsigned long nitems, after;
3874   unsigned char *data;
3875   Window inf;
3876
3877   if (win == 0)
3878     return DefaultRootWindow(dpy);
3879
3880   if ((WM_STATE = XInternAtom (dpy, "WM_STATE", True)) == 0)
3881     return win;
3882
3883   XGetWindowProperty (dpy, win, WM_STATE, 0, 0, False, AnyPropertyType,
3884                       &type, &format, &nitems, &after, &data);
3885   if (type)
3886     return win;
3887
3888   inf = getchildren (dpy, win, WM_STATE);
3889
3890   if (inf == 0)
3891     return win;
3892   else
3893     return inf;
3894 }
3895
3896 #ifdef WE_HAVE_MOTIF_DROPS_DONE
3897 static GdkWindow *
3898 gdk_drop_get_real_window (GdkWindow   *w, 
3899                           guint16     *x, 
3900                           guint16     *y)
3901 {
3902   GdkWindow *retval = w;
3903   GdkWindowPrivate *awin;
3904   GList *children;
3905   gint16 myx = *x, myy = *y;
3906
3907   g_return_val_if_fail(w != NULL && x != NULL && y != NULL, NULL);
3908
3909   myx = *x; 
3910   myy = *y;
3911
3912 descend:
3913   for (children = gdk_window_get_children(retval); 
3914        children && children->next;
3915        children = children->next)
3916     {
3917       awin = (GdkWindowPrivate *) children->data;
3918       if ((myx >= awin->x) && (myy >= awin->y)
3919           && (myx < (awin->x + awin->width))
3920           && (myy < (awin->y + awin->height)))
3921         {
3922           retval = (GdkWindow *) awin;
3923           myx -= awin->x;
3924           myy -= awin->y;
3925           goto descend;
3926         }
3927     }
3928
3929   *x = myx; 
3930   *y = myy;
3931
3932   return retval;
3933 }
3934 #endif
3935
3936 /* Sends a ClientMessage to all toplevel client windows */
3937 void
3938 gdk_event_send_clientmessage_toall(GdkEvent *event)
3939 {
3940   XEvent sev;
3941   Window *ret_children, ret_root, ret_parent, curwin;
3942   unsigned int ret_nchildren;
3943   int i;
3944
3945   g_return_if_fail(event != NULL);
3946
3947   /* Set up our event to send, with the exception of its target window */
3948   sev.xclient.type = ClientMessage;
3949   sev.xclient.display = gdk_display;
3950   sev.xclient.format = event->client.data_format;
3951   sev.xclient.serial = CurrentTime;
3952   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
3953   sev.xclient.message_type = event->client.message_type;
3954
3955   /* OK, we're all set, now let's find some windows to send this to */
3956   if(XQueryTree(gdk_display, gdk_root_window, &ret_root, &ret_parent,
3957                 &ret_children, &ret_nchildren) != True)
3958     return;
3959
3960   /* foreach true child window of the root window, send an event to it */
3961   for(i = 0; i < ret_nchildren; i++) {
3962     curwin = gdk_get_client_window(gdk_display, ret_children[i]);
3963     sev.xclient.window = curwin;
3964     XSendEvent(gdk_display, curwin, False, NoEventMask, &sev);
3965   }
3966
3967   XFree(ret_children);
3968 }
3969
3970 gchar *
3971 gdk_get_display(void)
3972 {
3973   return (gchar *)XDisplayName (gdk_display_name);
3974 }