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