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