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