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