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