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