]> Pileus Git - ~andy/gtk/blob - gdk/gdk.c
Add GDK_SUBSTRUCTURE_NOTIFY_MASK
[~andy/gtk] / gdk / gdk.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
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 #endif
55 #include "gdkkeysyms.h"
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 #ifdef USE_PTHREADS
1610       if (gdk_using_threads)
1611         {
1612           gdk_select_waiting = TRUE;
1613
1614           FD_SET (gdk_threads_pipe[0], &readfds);
1615           max_input = MAX (max_input, gdk_threads_pipe[0]);
1616           gdk_threads_leave ();
1617         }
1618 #endif
1619
1620       nfd = select (max_input+1, &readfds, &writefds, &exceptfds, timerp);
1621
1622 #ifdef USE_PTHREADS
1623       if (gdk_using_threads)
1624         {
1625           gchar c;
1626           gdk_threads_enter ();
1627           gdk_select_waiting = FALSE;
1628           
1629           if (FD_ISSET (gdk_threads_pipe[0], &readfds))
1630             read (gdk_threads_pipe[0], &c, 1);
1631         }
1632 #endif
1633
1634       timerp = NULL;
1635       timer_val = 0;
1636
1637       if (nfd > 0)
1638         {
1639           if (FD_ISSET (connection_number, &readfds))
1640             {
1641               if (XPending (gdk_display) == 0)
1642                 {
1643                   if (nfd == 1)
1644                     {
1645                       XNoOp (gdk_display);
1646                       XFlush (gdk_display);
1647                     }
1648                   return FALSE;
1649                 }
1650               else
1651                 return TRUE;
1652             }
1653
1654           list = inputs;
1655           while (list)
1656             {
1657               input = list->data;
1658               list = list->next;
1659
1660               condition = 0;
1661               if (FD_ISSET (input->source, &readfds))
1662                 condition |= GDK_INPUT_READ;
1663               if (FD_ISSET (input->source, &writefds))
1664                 condition |= GDK_INPUT_WRITE;
1665               if (FD_ISSET (input->source, &exceptfds))
1666                 condition |= GDK_INPUT_EXCEPTION;
1667
1668               if (condition && input->function)
1669                 (* input->function) (input->data, input->source, condition);
1670             }
1671         }
1672     }
1673   else
1674     return TRUE;
1675
1676   return FALSE;
1677 }
1678
1679 static gint
1680 gdk_event_apply_filters (XEvent *xevent,
1681                          GdkEvent *event,
1682                          GList *filters)
1683 {
1684   GdkEventFilter *filter;
1685   GList *tmp_list;
1686   GdkFilterReturn result;
1687
1688   tmp_list = filters;
1689   
1690   while (tmp_list)
1691     {
1692       filter = (GdkEventFilter *)tmp_list->data;
1693
1694       result = (*filter->function)(xevent, event, filter->data);
1695       if (result !=  GDK_FILTER_CONTINUE)
1696         return result;
1697         
1698       tmp_list = tmp_list->next;
1699     }
1700
1701   return GDK_FILTER_CONTINUE;
1702 }
1703
1704 static gint
1705 gdk_event_translate (GdkEvent *event,
1706                      XEvent   *xevent)
1707 {
1708
1709   GdkWindow *window;
1710   GdkWindowPrivate *window_private;
1711   static XComposeStatus compose;
1712   KeySym keysym;
1713   int charcount;
1714 #ifdef USE_XIM
1715   static gchar* buf = NULL;
1716   static gint buf_len= 0;
1717 #else
1718   char buf[16];
1719 #endif
1720   gint return_val;
1721
1722   return_val = FALSE;
1723
1724   /* We need to play catch-up with the dnd motion events */
1725   if(gdk_dnd.drag_really && xevent->type == MotionNotify)
1726         while (XCheckTypedEvent(xevent->xany.display,MotionNotify,xevent));
1727
1728   /* Find the GdkWindow that this event occurred in.
1729    * All events occur in some GdkWindow (otherwise, why
1730    *  would we be receiving them). It really is an error
1731    *  to receive an event for which we cannot find the
1732    *  corresponding GdkWindow. We handle events with window=None
1733    *  specially - they are generated by XFree86's XInput under
1734    *  some circumstances.
1735    */
1736
1737   if ((xevent->xany.window == None) &&
1738       gdk_input_vtable.window_none_event)
1739     {
1740       return_val = gdk_input_vtable.window_none_event (event,xevent);
1741
1742       if (return_val >= 0)      /* was handled */
1743         return return_val;
1744       else
1745         return_val = FALSE;
1746     }
1747
1748   window = gdk_window_lookup (xevent->xany.window);
1749   window_private = (GdkWindowPrivate *) window;
1750
1751   if (window != NULL)
1752     gdk_window_ref (window);
1753   else if(gdk_null_window_warnings) /* Special purpose programs that
1754                                        get events for other windows may
1755                                        want to disable this */
1756     g_warning ("%#lx -> NULL\n", xevent->xany.window);
1757
1758   /* Check for filters for this window */
1759
1760   {
1761     GdkFilterReturn result;
1762     result = gdk_event_apply_filters (xevent, event,
1763                                       window_private
1764                                       ?window_private->filters
1765                                       :gdk_default_filters);
1766     
1767     if (result != GDK_FILTER_CONTINUE)
1768       {
1769         return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
1770       }
1771   }
1772
1773   /* We do a "manual" conversion of the XEvent to a
1774    *  GdkEvent. The structures are mostly the same so
1775    *  the conversion is fairly straightforward. We also
1776    *  optionally print debugging info regarding events
1777    *  received.
1778    */
1779   /* Addendum:
1780    * During drag & drop you get events where the pointer is
1781    * in other windows. Need to just do finer-grained checking
1782    */
1783   switch (xevent->type)
1784     {
1785     case KeyPress:
1786       /* Lookup the string corresponding to the given keysym.
1787        */
1788 #ifdef USE_XIM
1789       if (buf_len == 0) 
1790         {
1791           buf_len = 128;
1792           buf = g_new (gchar, buf_len);
1793         }
1794       keysym = GDK_VoidSymbol;
1795
1796       if (xim_using == TRUE && xim_ic)
1797         {
1798           Status status;
1799           
1800           /* Clear keyval. Depending on status, may not be set */
1801           charcount = XmbLookupString(xim_ic->xic,
1802                                       &xevent->xkey, buf, buf_len-1,
1803                                       &keysym, &status);
1804           if (status == XBufferOverflow)
1805             {                     /* retry */
1806               /* alloc adequate size of buffer */
1807               GDK_NOTE (XIM,
1808                 g_print("XIM: overflow (required %i)\n", charcount));
1809
1810               while (buf_len <= charcount)
1811                 buf_len *= 2;
1812               buf = (gchar *) g_realloc (buf, buf_len);
1813              
1814               charcount = XmbLookupString (xim_ic->xic,
1815                                            &xevent->xkey, buf, buf_len-1,
1816                                            &keysym, &status);
1817             }
1818           if (status == XLookupNone)
1819             {
1820               return_val = FALSE;
1821               break;
1822             }
1823         }
1824       else
1825         charcount = XLookupString (&xevent->xkey, buf, buf_len,
1826                                    &keysym, &compose);
1827 #else
1828       charcount = XLookupString (&xevent->xkey, buf, 16,
1829                                  &keysym, &compose);
1830 #endif
1831       event->key.keyval = keysym;
1832
1833       if (charcount > 0 && buf[charcount-1] == '\0')
1834         charcount --;
1835       else
1836         buf[charcount] = '\0';
1837
1838       /* Print debugging info.
1839        */
1840 #ifdef G_ENABLE_DEBUG
1841       if (gdk_debug_flags & GDK_DEBUG_EVENTS)
1842         {
1843           g_print ("key press:\twindow: %ld  key: %12s  %d\n",
1844                    xevent->xkey.window - base_id,
1845                    event->key.keyval ? XKeysymToString (event->key.keyval) : "(none)",
1846                    event->key.keyval);
1847           if (charcount > 0)
1848             g_print ("\t\tlength: %4d string: \"%s\"\n",
1849                      charcount, buf);
1850         }
1851 #endif /* G_ENABLE_DEBUG */
1852
1853       event->key.type = GDK_KEY_PRESS;
1854       event->key.window = window;
1855       event->key.time = xevent->xkey.time;
1856       event->key.state = (GdkModifierType) xevent->xkey.state;
1857       event->key.string = g_strdup (buf);
1858       event->key.length = charcount;
1859
1860       return_val = window_private && !window_private->destroyed;
1861       
1862       if (!return_val)
1863         g_free (event->key.string);
1864       
1865       break;
1866
1867     case KeyRelease:
1868       /* Lookup the string corresponding to the given keysym.
1869        */
1870       keysym = GDK_VoidSymbol;
1871       charcount = XLookupString (&xevent->xkey, buf, 16,
1872                                  &keysym, &compose);
1873       event->key.keyval = keysym;      
1874
1875       /* Print debugging info.
1876        */
1877       GDK_NOTE (EVENTS, 
1878         g_print ("key release:\t\twindow: %ld  key: %12s  %d\n",
1879                  xevent->xkey.window - base_id,
1880                  XKeysymToString (event->key.keyval),
1881                  event->key.keyval));
1882
1883       event->key.type = GDK_KEY_RELEASE;
1884       event->key.window = window;
1885       event->key.time = xevent->xkey.time;
1886       event->key.state = (GdkModifierType) xevent->xkey.state;
1887       event->key.length = 0;
1888       event->key.string = NULL;
1889
1890       return_val = window_private && !window_private->destroyed;
1891       break;
1892
1893     case ButtonPress:
1894       /* Print debugging info.
1895        */
1896       GDK_NOTE (EVENTS, 
1897         g_print ("button press[%d]:\t\twindow: %ld  x,y: %d %d  button: %d\n",
1898                  window_private?window_private->dnd_drag_enabled:0,
1899                  xevent->xbutton.window - base_id,
1900                  xevent->xbutton.x, xevent->xbutton.y,
1901                  xevent->xbutton.button));
1902
1903       if (window_private &&
1904           (window_private->extension_events != 0) &&
1905           gdk_input_ignore_core)
1906         break;
1907
1908       event->button.type = GDK_BUTTON_PRESS;
1909       event->button.window = window;
1910       event->button.time = xevent->xbutton.time;
1911       event->button.x = xevent->xbutton.x;
1912       event->button.y = xevent->xbutton.y;
1913       event->button.x_root = (gfloat)xevent->xbutton.x_root;
1914       event->button.y_root = (gfloat)xevent->xbutton.y_root;
1915       event->button.pressure = 0.5;
1916       event->button.xtilt = 0;
1917       event->button.ytilt = 0;
1918       event->button.state = (GdkModifierType) xevent->xbutton.state;
1919       event->button.button = xevent->xbutton.button;
1920       event->button.source = GDK_SOURCE_MOUSE;
1921       event->button.deviceid = GDK_CORE_POINTER;
1922
1923       if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) &&
1924           (event->button.window == button_window[1]) &&
1925           (event->button.button == button_number[1]))
1926         {
1927           gdk_synthesize_click (event, 3);
1928
1929           button_click_time[1] = 0;
1930           button_click_time[0] = 0;
1931           button_window[1] = NULL;
1932           button_window[0] = 0;
1933           button_number[1] = -1;
1934           button_number[0] = -1;
1935         }
1936       else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) &&
1937                (event->button.window == button_window[0]) &&
1938                (event->button.button == button_number[0]))
1939         {
1940           gdk_synthesize_click (event, 2);
1941
1942           button_click_time[1] = button_click_time[0];
1943           button_click_time[0] = event->button.time;
1944           button_window[1] = button_window[0];
1945           button_window[0] = event->button.window;
1946           button_number[1] = button_number[0];
1947           button_number[0] = event->button.button;
1948         }
1949       else
1950         {
1951           button_click_time[1] = 0;
1952           button_click_time[0] = event->button.time;
1953           button_window[1] = NULL;
1954           button_window[0] = event->button.window;
1955           button_number[1] = -1;
1956           button_number[0] = event->button.button;
1957         }
1958       if(window_private
1959          && window_private->dnd_drag_enabled
1960          && !gdk_dnd.drag_perhaps
1961          && event->button.button == 1
1962          && !gdk_dnd.drag_really)
1963         {
1964           gdk_dnd.drag_perhaps = 1;
1965           gdk_dnd.dnd_drag_start.x = xevent->xbutton.x_root;
1966           gdk_dnd.dnd_drag_start.y = xevent->xbutton.y_root;
1967           gdk_dnd.real_sw = window_private;
1968           
1969           if(gdk_dnd.drag_startwindows)
1970             {
1971               g_free(gdk_dnd.drag_startwindows);
1972               gdk_dnd.drag_startwindows = NULL;
1973             }
1974           gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0;
1975           gdk_dnd.dnd_grabbed = FALSE;
1976
1977           {
1978             /* Set motion mask for first DnD'd window, since it
1979                will be the one that is actually dragged */
1980             XWindowAttributes dnd_winattr;
1981             XSetWindowAttributes dnd_setwinattr;
1982
1983             /* We need to get motion events while the button is down, so
1984                we can know whether to really start dragging or not... */
1985             XGetWindowAttributes(gdk_display, (Window)window_private->xwindow,
1986                                  &dnd_winattr);
1987             
1988             window_private->dnd_drag_savedeventmask = dnd_winattr.your_event_mask;
1989             dnd_setwinattr.event_mask = 
1990               window_private->dnd_drag_eventmask = ButtonMotionMask | ButtonPressMask | ButtonReleaseMask |
1991                         EnterWindowMask | LeaveWindowMask | ExposureMask;
1992             XChangeWindowAttributes(gdk_display, window_private->xwindow,
1993                                     CWEventMask, &dnd_setwinattr);
1994         }
1995       }
1996       return_val = window_private && !window_private->destroyed;
1997       break;
1998
1999     case ButtonRelease:
2000       /* Print debugging info.
2001        */
2002       GDK_NOTE (EVENTS, 
2003         g_print ("button release[%d]:\twindow: %ld  x,y: %d %d  button: %d\n",
2004                  window_private?window_private->dnd_drag_enabled:0,
2005                  xevent->xbutton.window - base_id,
2006                  xevent->xbutton.x, xevent->xbutton.y,
2007                  xevent->xbutton.button));
2008
2009       if (window_private &&
2010           (window_private->extension_events != 0) &&
2011           gdk_input_ignore_core)
2012         break;
2013
2014       event->button.type = GDK_BUTTON_RELEASE;
2015       event->button.window = window;
2016       event->button.time = xevent->xbutton.time;
2017       event->button.x = xevent->xbutton.x;
2018       event->button.y = xevent->xbutton.y;
2019       event->button.x_root = (gfloat)xevent->xbutton.x_root;
2020       event->button.y_root = (gfloat)xevent->xbutton.y_root;
2021       event->button.pressure = 0.5;
2022       event->button.xtilt = 0;
2023       event->button.ytilt = 0;
2024       event->button.state = (GdkModifierType) xevent->xbutton.state;
2025       event->button.button = xevent->xbutton.button;
2026       event->button.source = GDK_SOURCE_MOUSE;
2027       event->button.deviceid = GDK_CORE_POINTER;
2028
2029       gdk_dnd.last_drop_time = xevent->xbutton.time;
2030       if(gdk_dnd.drag_perhaps)
2031         {
2032           {
2033             XSetWindowAttributes attrs;
2034             /* Reset event mask to pre-drag value, assuming event_mask
2035                doesn't change during drag */
2036             attrs.event_mask = gdk_dnd.real_sw->dnd_drag_savedeventmask;
2037             XChangeWindowAttributes(gdk_display, gdk_dnd.real_sw->xwindow,
2038                                       CWEventMask, &attrs);
2039           }
2040           
2041           if (gdk_dnd.dnd_grabbed) 
2042             {
2043               gdk_dnd_display_drag_cursor(-2,
2044                                           -2,
2045                                           FALSE, TRUE);
2046               XUngrabPointer(gdk_display, CurrentTime);
2047               gdk_dnd.dnd_grabbed = FALSE;
2048             }
2049           
2050         if(gdk_dnd.drag_really)
2051           {
2052           GdkPoint foo;
2053           foo.x = xevent->xbutton.x_root;
2054           foo.y = xevent->xbutton.y_root;
2055                           
2056           if(gdk_dnd.dnd_drag_target != None)
2057             gdk_dnd_drag_end(gdk_dnd.dnd_drag_target, foo);
2058           gdk_dnd.drag_really = 0;
2059
2060           gdk_dnd.drag_numwindows = 0;
2061           if(gdk_dnd.drag_startwindows)
2062             {
2063             g_free(gdk_dnd.drag_startwindows);
2064             gdk_dnd.drag_startwindows = NULL;
2065             }
2066
2067           gdk_dnd.real_sw = NULL;
2068           }
2069
2070         gdk_dnd.drag_perhaps = 0;
2071         gdk_dnd.dnd_drag_start.x = gdk_dnd.dnd_drag_start.y = 0;
2072         gdk_dnd.dnd_drag_dropzone.x = gdk_dnd.dnd_drag_dropzone.y = 0;
2073         gdk_dnd.dnd_drag_dropzone.width = gdk_dnd.dnd_drag_dropzone.height = 0;
2074         gdk_dnd.dnd_drag_curwin = None;
2075         return_val = window_private?TRUE:FALSE;
2076       } else
2077         return_val = window_private && !window_private->destroyed;
2078       break;
2079
2080     case MotionNotify:
2081       /* Print debugging info.
2082        */
2083       GDK_NOTE (EVENTS,
2084         g_print ("motion notify:\t\twindow: %ld  x,y: %d %d  hint: %s d:%d r%d\n",
2085                  xevent->xmotion.window - base_id,
2086                  xevent->xmotion.x, xevent->xmotion.y,
2087                  (xevent->xmotion.is_hint) ? "true" : "false",
2088                  gdk_dnd.drag_perhaps, gdk_dnd.drag_really));
2089
2090       if (window_private &&
2091           (window_private->extension_events != 0) &&
2092           gdk_input_ignore_core)
2093         break;
2094
2095       event->motion.type = GDK_MOTION_NOTIFY;
2096       event->motion.window = window;
2097       event->motion.time = xevent->xmotion.time;
2098       event->motion.x = xevent->xmotion.x;
2099       event->motion.y = xevent->xmotion.y;
2100       event->motion.x_root = (gfloat)xevent->xmotion.x_root;
2101       event->motion.y_root = (gfloat)xevent->xmotion.y_root;
2102       event->motion.pressure = 0.5;
2103       event->motion.xtilt = 0;
2104       event->motion.ytilt = 0;
2105       event->motion.state = (GdkModifierType) xevent->xmotion.state;
2106       event->motion.is_hint = xevent->xmotion.is_hint;
2107       event->motion.source = GDK_SOURCE_MOUSE;
2108       event->motion.deviceid = GDK_CORE_POINTER;
2109
2110 #define IS_IN_ZONE(cx, cy) (cx >= gdk_dnd.dnd_drag_dropzone.x \
2111      && cy >= gdk_dnd.dnd_drag_dropzone.y \
2112      && cx < (gdk_dnd.dnd_drag_dropzone.x + gdk_dnd.dnd_drag_dropzone.width) \
2113      && cy < (gdk_dnd.dnd_drag_dropzone.y + gdk_dnd.dnd_drag_dropzone.height))
2114
2115       if(gdk_dnd.drag_perhaps && gdk_dnd.drag_really
2116          /* && event->motion.is_hint */ /* HINTME */)
2117         {
2118           /* First, we have to find what window the motion was in... */
2119           /* XXX there has to be a better way to do this, perhaps with
2120              XTranslateCoordinates or XQueryTree - I don't know how,
2121              and this sort of works */
2122           static Window lastwin = None, curwin = None;
2123 #if 0
2124           Window twin;
2125 #endif
2126           Window childwin = gdk_root_window;
2127           int x, y, ox, oy;
2128
2129           /* Interlude - display cursor for the drag ASAP */
2130           gdk_dnd_display_drag_cursor(xevent->xmotion.x_root,
2131                                       xevent->xmotion.y_root,
2132                                       gdk_dnd.dnd_drag_target?TRUE:FALSE,
2133                                       FALSE);
2134
2135           lastwin = curwin;
2136           curwin = gdk_root_window;
2137           ox = x = xevent->xmotion.x_root;
2138           oy = y = xevent->xmotion.y_root;
2139 #if 1
2140           curwin = gdk_window_xid_at_coords(xevent->xmotion.x_root,
2141                                             xevent->xmotion.y_root,
2142                                             gdk_dnd.c->xids,TRUE);
2143           XTranslateCoordinates(gdk_display, gdk_root_window, curwin,
2144                                 x, y, &x, &y, &childwin);
2145 #else
2146           while(childwin != None)
2147             {
2148               ox = x; oy = y;
2149               curwin = childwin;
2150               XTranslateCoordinates(gdk_display, curwin, curwin,
2151                                     x, y, &x, &y, &childwin);
2152               if(childwin != None) 
2153                 {
2154                   XTranslateCoordinates(gdk_display, curwin, childwin,
2155                                         x, y, &x, &y, &twin);
2156                 }
2157             }
2158 #endif
2159           GDK_NOTE (DND,
2160             g_print("Drag is now in window %#lx, lastwin was %#lx, ddc = %#lx\n",
2161                     curwin, lastwin, gdk_dnd.dnd_drag_curwin));
2162           if(curwin != gdk_dnd.dnd_drag_curwin && curwin != lastwin)
2163             {
2164               /* We have left one window and entered another
2165                  (do leave & enter bits) */
2166               if(gdk_dnd.dnd_drag_curwin != None)
2167                   gdk_dnd_drag_leave(gdk_dnd.dnd_drag_curwin);
2168               gdk_dnd.dnd_drag_curwin = curwin;
2169               gdk_dnd_drag_enter(gdk_dnd.dnd_drag_curwin);
2170               gdk_dnd.dnd_drag_dropzone.x = gdk_dnd.dnd_drag_dropzone.y = 0;
2171               gdk_dnd.dnd_drag_dropzone.width = gdk_dnd.dnd_drag_dropzone.height = 0;
2172               gdk_dnd.dnd_drag_target = None;
2173               GDK_NOTE (DND,
2174                 g_print("curwin = %#lx, lastwin = %#lx, dnd_drag_curwin = %#lx\n",
2175                         curwin, lastwin, gdk_dnd.dnd_drag_curwin));
2176
2177               gdk_dnd_display_drag_cursor(xevent->xmotion.x_root,
2178                                           xevent->xmotion.y_root,
2179                                           FALSE, TRUE);
2180             }
2181           else if(gdk_dnd.dnd_drag_dropzone.width > 0
2182                   && gdk_dnd.dnd_drag_dropzone.height > 0
2183                   && curwin == gdk_dnd.dnd_drag_curwin)
2184             {
2185               /* Handle all that dropzone stuff - thanks John ;-) */
2186               if (gdk_dnd.dnd_drag_target != None)
2187                 {
2188                   gboolean in_zone = IS_IN_ZONE(xevent->xmotion.x_root,
2189                                                 xevent->xmotion.y_root);
2190                   gboolean old_in_zone = IS_IN_ZONE(gdk_dnd.dnd_drag_oldpos.x, 
2191                                                     gdk_dnd.dnd_drag_oldpos.y);
2192
2193                   if (!in_zone && old_in_zone)
2194                     {
2195                       /* We were in the drop zone and moved out */
2196                       gdk_dnd.dnd_drag_target = None;
2197                       gdk_dnd_drag_leave(curwin);
2198                       gdk_dnd_display_drag_cursor(xevent->xmotion.x_root,
2199                                                   xevent->xmotion.y_root,
2200                                                   FALSE, TRUE);
2201                     }
2202                   else if (!in_zone && !old_in_zone)
2203                     {
2204                       /* We were outside drop zone but in the window
2205                          - have to send enter events */
2206                       gdk_dnd_drag_enter(curwin);
2207                       gdk_dnd.dnd_drag_curwin = curwin;
2208                       gdk_dnd.dnd_drag_dropzone.x = gdk_dnd.dnd_drag_dropzone.y = 0;
2209                       gdk_dnd.dnd_drag_target = None;
2210                     }
2211                 }
2212             } /* else
2213               dnd_drag_curwin = None; */
2214           return_val = FALSE;
2215         }
2216       else
2217         return_val = window_private && !window_private->destroyed;
2218       break;
2219
2220     case EnterNotify:
2221       /* Print debugging info.
2222        */
2223       GDK_NOTE (EVENTS,
2224         g_print ("enter notify:\t\twindow: %ld  detail: %d subwin: %ld\n",
2225                  xevent->xcrossing.window - base_id,
2226                  xevent->xcrossing.detail,
2227                  xevent->xcrossing.subwindow - base_id));
2228
2229       /* Tell XInput stuff about it if appropriate */
2230       if (window_private &&
2231           (window_private->extension_events != 0) &&
2232           gdk_input_vtable.enter_event)
2233         gdk_input_vtable.enter_event (&xevent->xcrossing, window);
2234
2235       event->crossing.type = GDK_ENTER_NOTIFY;
2236       event->crossing.window = window;
2237
2238       /* If the subwindow field of the XEvent is non-NULL, then
2239        *  lookup the corresponding GdkWindow.
2240        */
2241       if (xevent->xcrossing.subwindow != None)
2242         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
2243       else
2244         event->crossing.subwindow = NULL;
2245
2246       /* Translate the crossing detail into Gdk terms.
2247        */
2248       switch (xevent->xcrossing.detail)
2249         {
2250         case NotifyInferior:
2251           event->crossing.detail = GDK_NOTIFY_INFERIOR;
2252           break;
2253         case NotifyAncestor:
2254           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
2255           break;
2256         case NotifyVirtual:
2257           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
2258           break;
2259         case NotifyNonlinear:
2260           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
2261           break;
2262         case NotifyNonlinearVirtual:
2263           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
2264           break;
2265         default:
2266           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
2267           break;
2268         }
2269
2270 #ifdef G_ENABLE_DEBUG
2271         if ((gdk_debug_flags & GDK_DEBUG_DND) & gdk_dnd.drag_perhaps)
2272           {
2273             g_print("We may[%d] have a drag into %#lx = %#lx\n",
2274                     gdk_dnd.drag_really,
2275                     xevent->xcrossing.window, gdk_dnd.real_sw->xwindow);
2276           }
2277 #endif /* G_ENABLE_DEBUG */
2278
2279         if (gdk_dnd.drag_perhaps && gdk_dnd.drag_really && 
2280             (xevent->xcrossing.window == gdk_dnd.real_sw->xwindow))
2281           {
2282 #if 0
2283             gdk_dnd.drag_really = 0;
2284
2285             GDK_NOTE (DND, g_print("Ungrabbed\n"));
2286
2287             gdk_dnd.drag_numwindows = 0;
2288             g_free(gdk_dnd.drag_startwindows);
2289             gdk_dnd.drag_startwindows = NULL;
2290             /* We don't want to ungrab the pointer here, or we'll
2291              * start getting spurious enter/leave events */
2292 #endif
2293 #if 0
2294             XChangeActivePointerGrab (gdk_display, 0, None, CurrentTime);
2295 #endif
2296           }
2297         
2298         return_val = window_private && !window_private->destroyed;
2299         break;
2300
2301     case LeaveNotify:
2302       /* Print debugging info.
2303        */
2304       GDK_NOTE (EVENTS, 
2305         g_print ("leave notify:\t\twindow: %ld  detail: %d subwin: %ld\n",
2306                  xevent->xcrossing.window - base_id,
2307                  xevent->xcrossing.detail, xevent->xcrossing.subwindow - base_id));
2308
2309       event->crossing.type = GDK_LEAVE_NOTIFY;
2310       event->crossing.window = window;
2311
2312       /* If the subwindow field of the XEvent is non-NULL, then
2313        *  lookup the corresponding GdkWindow.
2314        */
2315       if (xevent->xcrossing.subwindow != None)
2316         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
2317       else
2318         event->crossing.subwindow = NULL;
2319
2320       /* Translate the crossing detail into Gdk terms.
2321        */
2322       switch (xevent->xcrossing.detail)
2323         {
2324         case NotifyInferior:
2325           event->crossing.detail = GDK_NOTIFY_INFERIOR;
2326           break;
2327         case NotifyAncestor:
2328           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
2329           break;
2330         case NotifyVirtual:
2331           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
2332           break;
2333         case NotifyNonlinear:
2334           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
2335           break;
2336         case NotifyNonlinearVirtual:
2337           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
2338           break;
2339         default:
2340           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
2341           break;
2342         }
2343 #ifdef G_ENABLE_DEBUG
2344       if ((gdk_debug_flags & GDK_DEBUG_DND) & gdk_dnd.drag_perhaps)
2345         {
2346           g_print("We may[%d] have a drag out of %#lx = %#lx\n",
2347                   gdk_dnd.drag_really,
2348                   xevent->xcrossing.window, gdk_dnd.real_sw->xwindow);
2349         }
2350 #endif /* G_ENABLE_DEBUG */
2351       if (gdk_dnd.drag_perhaps && !gdk_dnd.drag_really &&
2352           (xevent->xcrossing.window == gdk_dnd.real_sw->xwindow))
2353         {
2354           gboolean xgpret;
2355           gdk_dnd_drag_addwindow((GdkWindow *) gdk_dnd.real_sw);
2356           gdk_dnd_drag_begin((GdkWindow *) gdk_dnd.real_sw);
2357           xgpret = 
2358           XGrabPointer(gdk_display, gdk_dnd.real_sw->xwindow, False,
2359                        ButtonMotionMask | PointerMotionMask |
2360                        /* PointerMotionHintMask | */ /* HINTME */
2361                        ButtonPressMask | ButtonReleaseMask,
2362                        GrabModeAsync, GrabModeAsync, None,
2363                        None, CurrentTime);
2364 #ifdef G_ENABLE_DEBUG
2365           GDK_NOTE(DND, g_print("xgpret = %d\n", xgpret));
2366 #endif
2367           gdk_dnd.dnd_grabbed = TRUE;
2368           gdk_dnd.drag_really = 1;
2369           gdk_dnd_display_drag_cursor(xevent->xmotion.x_root,
2370                                       xevent->xmotion.y_root,
2371                                       FALSE, TRUE);
2372         }
2373
2374       return_val = window_private && !window_private->destroyed;
2375       break;
2376
2377     case FocusIn:
2378     case FocusOut:
2379       /* We only care about focus events that indicate that _this_
2380        * window (not a ancestor or child) got or lost the focus
2381        */
2382       switch (xevent->xfocus.detail)
2383         {
2384         case NotifyAncestor:
2385         case NotifyInferior:
2386         case NotifyNonlinear:
2387           /* Print debugging info.
2388            */
2389           GDK_NOTE (EVENTS,
2390             g_print ("focus %s:\t\twindow: %ld\n",
2391                      (xevent->xany.type == FocusIn) ? "in" : "out",
2392                      xevent->xfocus.window - base_id));
2393           
2394           event->focus_change.type = GDK_FOCUS_CHANGE;
2395           event->focus_change.window = window;
2396           event->focus_change.in = (xevent->xany.type == FocusIn);
2397           
2398           return_val = window_private && !window_private->destroyed;
2399           break;
2400         default:
2401           ;
2402         }
2403       break;
2404
2405     case KeymapNotify:
2406       /* Print debugging info.
2407        */
2408       GDK_NOTE (EVENTS,
2409         g_print ("keymap notify\n"));
2410
2411       /* Not currently handled */
2412       break;
2413
2414     case Expose:
2415       /* Print debugging info.
2416        */
2417       GDK_NOTE (EVENTS,
2418         g_print ("expose:\t\twindow: %ld  %d  x,y: %d %d  w,h: %d %d\n",
2419                  xevent->xexpose.window - base_id, xevent->xexpose.count,
2420                  xevent->xexpose.x, xevent->xexpose.y,
2421                  xevent->xexpose.width, xevent->xexpose.height));
2422
2423       event->expose.type = GDK_EXPOSE;
2424       event->expose.window = window;
2425       event->expose.area.x = xevent->xexpose.x;
2426       event->expose.area.y = xevent->xexpose.y;
2427       event->expose.area.width = xevent->xexpose.width;
2428       event->expose.area.height = xevent->xexpose.height;
2429       event->expose.count = xevent->xexpose.count;
2430
2431       return_val = window_private && !window_private->destroyed;
2432       break;
2433
2434     case GraphicsExpose:
2435       /* Print debugging info.
2436        */
2437       GDK_NOTE (EVENTS,
2438         g_print ("graphics expose:\tdrawable: %ld\n",
2439                  xevent->xgraphicsexpose.drawable - base_id));
2440
2441       event->expose.type = GDK_EXPOSE;
2442       event->expose.window = window;
2443       event->expose.area.x = xevent->xgraphicsexpose.x;
2444       event->expose.area.y = xevent->xgraphicsexpose.y;
2445       event->expose.area.width = xevent->xgraphicsexpose.width;
2446       event->expose.area.height = xevent->xgraphicsexpose.height;
2447       event->expose.count = xevent->xexpose.count;
2448
2449       return_val = window_private && !window_private->destroyed;
2450       break;
2451
2452     case NoExpose:
2453       /* Print debugging info.
2454        */
2455       GDK_NOTE (EVENTS,
2456         g_print ("no expose:\t\tdrawable: %ld\n",
2457                  xevent->xnoexpose.drawable - base_id));
2458
2459       event->no_expose.type = GDK_NO_EXPOSE;
2460       event->no_expose.window = window;
2461
2462       return_val = window_private && !window_private->destroyed;
2463       break;
2464
2465     case VisibilityNotify:
2466       /* Print debugging info.
2467        */
2468 #ifdef G_ENABLE_DEBUG
2469       if (gdk_debug_flags & GDK_DEBUG_EVENTS)
2470         switch (xevent->xvisibility.state)
2471           {
2472           case VisibilityFullyObscured:
2473             g_print ("visibility notify:\twindow: %ld  none\n",
2474                      xevent->xvisibility.window - base_id);
2475             break;
2476           case VisibilityPartiallyObscured:
2477             g_print ("visibility notify:\twindow: %ld  partial\n",
2478                      xevent->xvisibility.window - base_id);
2479             break;
2480           case VisibilityUnobscured:
2481             g_print ("visibility notify:\twindow: %ld  full\n",
2482                      xevent->xvisibility.window - base_id);
2483             break;
2484           }
2485 #endif /* G_ENABLE_DEBUG */
2486
2487       event->visibility.type = GDK_VISIBILITY_NOTIFY;
2488       event->visibility.window = window;
2489
2490       switch (xevent->xvisibility.state)
2491         {
2492         case VisibilityFullyObscured:
2493           event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED;
2494           break;
2495
2496         case VisibilityPartiallyObscured:
2497           event->visibility.state = GDK_VISIBILITY_PARTIAL;
2498           break;
2499
2500         case VisibilityUnobscured:
2501           event->visibility.state = GDK_VISIBILITY_UNOBSCURED;
2502           break;
2503         }
2504       
2505       return_val = window_private && !window_private->destroyed;
2506       break;
2507
2508     case CreateNotify:
2509       /* Not currently handled */
2510       break;
2511
2512     case DestroyNotify:
2513       /* Print debugging info.
2514        */
2515       GDK_NOTE (EVENTS,
2516         g_print ("destroy notify:\twindow: %ld\n",
2517                  xevent->xdestroywindow.window - base_id));
2518
2519       event->any.type = GDK_DESTROY;
2520       event->any.window = window;
2521
2522       return_val = window_private && !window_private->destroyed;
2523
2524       if(window && window_private->xwindow != GDK_ROOT_WINDOW())
2525         gdk_window_destroy_notify (window);
2526       break;
2527
2528     case UnmapNotify:
2529       /* Print debugging info.
2530        */
2531       GDK_NOTE (EVENTS,
2532         g_print ("unmap notify:\t\twindow: %ld\n",
2533                  xevent->xmap.window - base_id));
2534
2535       event->any.type = GDK_UNMAP;
2536       event->any.window = window;
2537
2538       if (xgrab_window == window_private)
2539         xgrab_window = NULL;
2540
2541       return_val = window_private && !window_private->destroyed;
2542       break;
2543
2544     case MapNotify:
2545       /* Print debugging info.
2546        */
2547       GDK_NOTE (EVENTS,
2548         g_print ("map notify:\t\twindow: %ld\n",
2549                  xevent->xmap.window - base_id));
2550
2551       event->any.type = GDK_MAP;
2552       event->any.window = window;
2553
2554       return_val = window_private && !window_private->destroyed;
2555       break;
2556
2557     case ReparentNotify:
2558       /* Print debugging info.
2559        */
2560       GDK_NOTE (EVENTS,
2561         g_print ("reparent notify:\twindow: %ld\n",
2562                  xevent->xreparent.window - base_id));
2563
2564       /* Not currently handled */
2565       break;
2566
2567     case ConfigureNotify:
2568       /* Print debugging info.
2569        */
2570       while ((XPending (gdk_display) > 0) &&
2571              XCheckTypedWindowEvent(gdk_display, xevent->xany.window,
2572                                     ConfigureNotify, xevent))
2573         {
2574           GdkFilterReturn result;
2575
2576           GDK_NOTE (EVENTS, 
2577                     g_print ("configure notify discarded:\twindow: %ld\n",
2578                              xevent->xconfigure.window - base_id));
2579
2580           result = gdk_event_apply_filters (xevent, event,
2581                                             window_private
2582                                             ?window_private->filters
2583                                             :gdk_default_filters);
2584
2585           /* If the result is GDK_FILTER_REMOVE, there will be
2586            * trouble, but anybody who filtering the Configure events
2587            * better know what they are doing
2588            */
2589           if (result != GDK_FILTER_CONTINUE)
2590             {
2591               return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
2592             }
2593
2594             /*XSync (gdk_display, 0);*/
2595         }
2596
2597       
2598       GDK_NOTE (EVENTS,
2599         g_print ("configure notify:\twindow: %ld  x,y: %d %d  w,h: %d %d  b-w: %d  above: %ld  ovr: %d\n",
2600                  xevent->xconfigure.window - base_id,
2601                  xevent->xconfigure.x,
2602                  xevent->xconfigure.y,
2603                  xevent->xconfigure.width,
2604                  xevent->xconfigure.height,
2605                  xevent->xconfigure.border_width,
2606                  xevent->xconfigure.above - base_id,
2607                  xevent->xconfigure.override_redirect));
2608       
2609       if (window_private)
2610         {
2611           if ((window_private->extension_events != 0) &&
2612               gdk_input_vtable.configure_event)
2613             gdk_input_vtable.configure_event (&xevent->xconfigure, window);
2614           
2615           if (window_private->window_type != GDK_WINDOW_CHILD)
2616             {
2617               event->configure.type = GDK_CONFIGURE;
2618               event->configure.window = window;
2619               event->configure.width = xevent->xconfigure.width;
2620               event->configure.height = xevent->xconfigure.height;
2621               
2622               if (!xevent->xconfigure.x &&
2623                   !xevent->xconfigure.y &&
2624                   !window_private->destroyed)
2625                 {
2626                   gint tx = 0;
2627                   gint ty = 0;
2628                   Window child_window = 0;
2629
2630                   if (!XTranslateCoordinates (window_private->xdisplay,
2631                                               window_private->xwindow,
2632                                               gdk_root_window,
2633                                               0, 0,
2634                                               &tx, &ty,
2635                                               &child_window))
2636                     g_warning ("GdkWindow %ld doesn't share root windows display?",
2637                                window_private->xwindow - base_id);
2638                   event->configure.x = tx;
2639                   event->configure.y = ty;
2640                 }
2641               else
2642                 {
2643                   event->configure.x = xevent->xconfigure.x;
2644                   event->configure.y = xevent->xconfigure.y;
2645                 }
2646               window_private->x = event->configure.x;
2647               window_private->y = event->configure.y;
2648               window_private->width = xevent->xconfigure.width;
2649               window_private->height = xevent->xconfigure.height;
2650               if (window_private->resize_count > 1)
2651                 window_private->resize_count -= 1;
2652               
2653               return_val = !window_private->destroyed;
2654             }
2655         }
2656       break;
2657       
2658     case PropertyNotify:
2659       /* Print debugging info.
2660        */
2661       GDK_NOTE (EVENTS,
2662         g_print ("property notify:\twindow: %ld\n",
2663                  xevent->xproperty.window - base_id));
2664
2665       event->property.type = GDK_PROPERTY_NOTIFY;
2666       event->property.window = window;
2667       event->property.atom = xevent->xproperty.atom;
2668       event->property.time = xevent->xproperty.time;
2669       event->property.state = xevent->xproperty.state;
2670
2671       return_val = window_private && !window_private->destroyed;
2672       break;
2673
2674     case SelectionClear:
2675       GDK_NOTE (EVENTS,
2676         g_print ("selection clear:\twindow: %ld\n",
2677                  xevent->xproperty.window - base_id));
2678
2679       event->selection.type = GDK_SELECTION_CLEAR;
2680       event->selection.window = window;
2681       event->selection.selection = xevent->xselectionclear.selection;
2682       event->selection.time = xevent->xselectionclear.time;
2683
2684       return_val = window_private && !window_private->destroyed;
2685       break;
2686
2687     case SelectionRequest:
2688       GDK_NOTE (EVENTS,
2689         g_print ("selection request:\twindow: %ld\n",
2690                  xevent->xproperty.window - base_id));
2691
2692       event->selection.type = GDK_SELECTION_REQUEST;
2693       event->selection.window = window;
2694       event->selection.selection = xevent->xselectionrequest.selection;
2695       event->selection.target = xevent->xselectionrequest.target;
2696       event->selection.property = xevent->xselectionrequest.property;
2697       event->selection.requestor = xevent->xselectionrequest.requestor;
2698       event->selection.time = xevent->xselectionrequest.time;
2699
2700       return_val = window_private && !window_private->destroyed;
2701       break;
2702
2703     case SelectionNotify:
2704       GDK_NOTE (EVENTS,
2705         g_print ("selection notify:\twindow: %ld\n",
2706                  xevent->xproperty.window - base_id));
2707
2708
2709       event->selection.type = GDK_SELECTION_NOTIFY;
2710       event->selection.window = window;
2711       event->selection.selection = xevent->xselection.selection;
2712       event->selection.target = xevent->xselection.target;
2713       event->selection.property = xevent->xselection.property;
2714       event->selection.time = xevent->xselection.time;
2715
2716       return_val = window_private && !window_private->destroyed;
2717       break;
2718
2719     case ColormapNotify:
2720       /* Print debugging info.
2721        */
2722       GDK_NOTE (EVENTS,
2723         g_print ("colormap notify:\twindow: %ld\n",
2724                  xevent->xcolormap.window - base_id));
2725
2726       /* Not currently handled */
2727       break;
2728
2729     case ClientMessage:
2730       /* Print debugging info.
2731        */
2732       GDK_NOTE (EVENTS,
2733         g_print ("client message:\twindow: %ld\n",
2734                  xevent->xclient.window - base_id));
2735
2736       /* Client messages are the means of the window manager
2737        *  communicating with a program. We'll first check to
2738        *  see if this is really the window manager talking
2739        *  to us.
2740        */
2741       if (xevent->xclient.message_type == gdk_wm_protocols)
2742         {
2743           if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window)
2744             {
2745               /* The delete window request specifies a window
2746                *  to delete. We don't actually destroy the
2747                *  window because "it is only a request". (The
2748                *  window might contain vital data that the
2749                *  program does not want destroyed). Instead
2750                *  the event is passed along to the program,
2751                *  which should then destroy the window.
2752                */
2753
2754               /* Print debugging info.
2755                */
2756               GDK_NOTE (EVENTS,
2757                 g_print ("delete window:\t\twindow: %ld\n",
2758                          xevent->xclient.window - base_id));
2759
2760               event->any.type = GDK_DELETE;
2761               event->any.window = window;
2762
2763               return_val = window_private && !window_private->destroyed;
2764             }
2765           else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
2766             {
2767             }
2768         }
2769       else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter)
2770         {
2771           Atom reptype = 0;
2772
2773           event->dropenter.u.allflags = xevent->xclient.data.l[1];
2774
2775           GDK_NOTE (DND, g_print ("GDK_DROP_ENTER [%d][%d]\n",
2776                 window_private->dnd_drop_enabled, event->dropenter.u.flags.sendreply));
2777           return_val = FALSE;
2778
2779           /* Now figure out if we really want this drop...
2780            * If someone is trying funky clipboard stuff, ignore 
2781            */
2782           if (window_private
2783               && window_private->dnd_drop_enabled
2784               && event->dropenter.u.flags.sendreply
2785               && (reptype = gdk_dnd_check_types (window, xevent)))
2786             {
2787               XEvent replyev;
2788
2789               replyev.xclient.type = ClientMessage;
2790               replyev.xclient.window = xevent->xclient.data.l[0];
2791               replyev.xclient.format = 32;
2792               replyev.xclient.message_type = gdk_dnd.gdk_XdeRequest;
2793               replyev.xclient.data.l[0] = window_private->xwindow;
2794
2795               event->dragrequest.u.allflags = 0;
2796               event->dragrequest.u.flags.protocol_version =
2797                 DND_PROTOCOL_VERSION;
2798               event->dragrequest.u.flags.willaccept = 1;
2799               event->dragrequest.u.flags.delete_data =
2800                 (window_private->dnd_drop_destructive_op) ? 1 : 0;
2801
2802               replyev.xclient.data.l[1] = event->dragrequest.u.allflags;
2803               replyev.xclient.data.l[2] = replyev.xclient.data.l[3] = 0;
2804               replyev.xclient.data.l[4] = reptype;
2805
2806               if (!gdk_send_xevent (replyev.xclient.window, False, 
2807                                     NoEventMask, &replyev))
2808                 GDK_NOTE (DND, g_print("Sending XdeRequest to %#lx failed\n",
2809                                        replyev.xclient.window));
2810
2811               event->any.type = GDK_DROP_ENTER;
2812               event->any.window = window;
2813               event->dropenter.requestor = replyev.xclient.window;
2814               event->dropenter.u.allflags = xevent->xclient.data.l[1];
2815
2816               GDK_NOTE (DND, g_print("We sent a GDK_DROP_ENTER on to Gtk\n"));
2817               return_val = TRUE;
2818             }
2819         }
2820       else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeLeave)
2821         {
2822 #ifdef G_ENABLE_DEBUG     
2823           if (gdk_debug_flags & (GDK_DEBUG_EVENTS | GDK_DEBUG_DND))
2824             g_print ("GDK_DROP_LEAVE\n");
2825 #endif    
2826
2827           if (window_private && window_private->dnd_drop_enabled)
2828             {
2829               event->dropleave.type = GDK_DROP_LEAVE;
2830               event->dropleave.window = window;
2831               event->dropleave.requestor = xevent->xclient.data.l[0];
2832               event->dropleave.u.allflags = xevent->xclient.data.l[1];
2833               return_val = TRUE;
2834             }
2835           else
2836             return_val = FALSE;
2837         }
2838       else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeRequest)
2839         {
2840           /* 
2841            * make sure to only handle requests from the window the cursor is
2842            * over 
2843            */
2844 #ifdef G_ENABLE_DEBUG     
2845           if (gdk_debug_flags & (GDK_DEBUG_EVENTS | GDK_DEBUG_DND))
2846             g_print ("GDK_DRAG_REQUEST\n");
2847 #endif    
2848           event->dragrequest.u.allflags = xevent->xclient.data.l[1];
2849           return_val = FALSE;
2850
2851           if (window && gdk_dnd.drag_really &&
2852               xevent->xclient.data.l[0] == gdk_dnd.dnd_drag_curwin &&
2853               event->dragrequest.u.flags.sendreply == 0)
2854             {
2855               /* Got request - do we need to ask user? */
2856               if (!event->dragrequest.u.flags.willaccept
2857                   && event->dragrequest.u.flags.senddata)
2858                 {
2859                   /* Yes we do :) */
2860                   event->dragrequest.type = GDK_DRAG_REQUEST;
2861                   event->dragrequest.window = window;
2862                   event->dragrequest.requestor = xevent->xclient.data.l[0];
2863                   event->dragrequest.isdrop = 0;
2864                   event->dragrequest.drop_coords.x =
2865                     event->dragrequest.drop_coords.y = 0;
2866                   return_val = TRUE;
2867                 }
2868               else if (event->dragrequest.u.flags.willaccept)
2869                 {
2870                   window_private->dnd_drag_destructive_op =
2871                     event->dragrequest.u.flags.delete_data;
2872                   window_private->dnd_drag_accepted = 1;
2873                   window_private->dnd_drag_data_type =
2874                     xevent->xclient.data.l[4];
2875
2876                   gdk_dnd.dnd_drag_target = gdk_dnd.dnd_drag_curwin;
2877                   gdk_dnd_display_drag_cursor(-1, -1, TRUE, TRUE);
2878                 }
2879               gdk_dnd.dnd_drag_dropzone.x = xevent->xclient.data.l[2] & 65535;
2880               gdk_dnd.dnd_drag_dropzone.y =
2881                 (xevent->xclient.data.l[2] >> 16) & 65535;
2882               gdk_dnd.dnd_drag_dropzone.width = xevent->xclient.data.l[3] & 65535;
2883               gdk_dnd.dnd_drag_dropzone.height =
2884                 (xevent->xclient.data.l[3] >> 16) & 65535;
2885             }
2886         }
2887       else if(xevent->xclient.message_type == gdk_dnd.gdk_XdeDataAvailable)
2888           {
2889             gint tmp_int; Atom tmp_atom;
2890             gulong tmp_long;
2891             guchar *tmp_charptr;
2892
2893 #ifdef G_ENABLE_DEBUG     
2894           if (gdk_debug_flags & (GDK_DEBUG_EVENTS | GDK_DEBUG_DND))
2895             g_print("GDK_DROP_DATA_AVAIL\n");
2896 #endif    
2897             event->dropdataavailable.u.allflags = xevent->xclient.data.l[1];
2898             event->dropdataavailable.timestamp = xevent->xclient.data.l[4];
2899             event->dropdataavailable.coords.x =
2900                         xevent->xclient.data.l[3] & 0xffff;
2901             event->dropdataavailable.coords.y =
2902                         (xevent->xclient.data.l[3] >> 16) & 0xffff;
2903             if(window
2904                /* No preview of data ATM */
2905                && event->dropdataavailable.u.flags.isdrop)
2906               {
2907                 event->dropdataavailable.type = GDK_DROP_DATA_AVAIL;
2908                 event->dropdataavailable.window = window;
2909                 event->dropdataavailable.requestor = xevent->xclient.data.l[0];
2910                 event->dropdataavailable.data_type =
2911                         gdk_atom_name(xevent->xclient.data.l[2]);
2912                 if(XGetWindowProperty (gdk_display,
2913                                     event->dropdataavailable.requestor,
2914                                     xevent->xclient.data.l[2],
2915                                     0, LONG_MAX - 1,
2916                                     False, XA_PRIMARY, &tmp_atom,
2917                                     &tmp_int,
2918                                     &event->dropdataavailable.data_numbytes,
2919                                     &tmp_long,
2920                                     &tmp_charptr)
2921                    != Success)
2922                   {
2923                     g_warning("XGetWindowProperty on %#x may have failed\n",
2924                             event->dropdataavailable.requestor);
2925                             event->dropdataavailable.data = NULL;
2926                   }
2927                 else
2928                   {
2929                     GDK_NOTE (DND, g_print("XGetWindowProperty got us %ld bytes\n",
2930                             event->dropdataavailable.data_numbytes));
2931                     event->dropdataavailable.data =
2932                         g_malloc (event->dropdataavailable.data_numbytes);
2933                     memcpy (event->dropdataavailable.data,
2934                         tmp_charptr, event->dropdataavailable.data_numbytes);
2935                     XFree(tmp_charptr);
2936                     return_val = TRUE;
2937                   }
2938               return_val = TRUE;
2939             }
2940         }
2941       else
2942         {
2943           /* Send unknown ClientMessage's on to Gtk for it to use */
2944           event->client.type = GDK_CLIENT_EVENT;
2945           event->client.window = window;
2946           event->client.message_type = xevent->xclient.message_type;
2947           event->client.data_format = xevent->xclient.format;
2948           memcpy(&event->client.data, &xevent->xclient.data,
2949                  sizeof(event->client.data));
2950           if(window)
2951             return_val = TRUE;
2952           else  
2953             return_val = FALSE;
2954         }
2955       if(window_private)
2956         return_val = return_val && !window_private->destroyed;
2957       break;
2958       
2959     case MappingNotify:
2960       /* Print debugging info.
2961        */
2962       GDK_NOTE (EVENTS,
2963         g_print ("mapping notify\n"));
2964
2965       /* Let XLib know that there is a new keyboard mapping.
2966        */
2967       XRefreshKeyboardMapping (&xevent->xmapping);
2968       break;
2969
2970     default:
2971       /* something else - (e.g., a Xinput event) */
2972
2973       if (window_private &&
2974           (window_private->extension_events != 0) &&
2975           gdk_input_vtable.other_event)
2976         return_val = gdk_input_vtable.other_event(event, xevent, window);
2977       else
2978         return_val = FALSE;
2979
2980       return_val = return_val && !window_private->destroyed;
2981
2982       break;
2983     }
2984
2985   if (return_val)
2986     {
2987       if (event->any.window)
2988         gdk_window_ref (event->any.window);
2989       if (((event->any.type == GDK_ENTER_NOTIFY) ||
2990            (event->any.type == GDK_LEAVE_NOTIFY)) &&
2991           (event->crossing.subwindow != NULL))
2992         gdk_window_ref (event->crossing.subwindow);
2993     }
2994   else
2995     {
2996       /* Mark this event as having no resources to be freed */
2997       event->any.window = NULL;
2998       event->any.type = GDK_NOTHING;
2999     }
3000
3001   if (window)
3002     gdk_window_unref (window);
3003
3004   return return_val;
3005 }
3006
3007 #if 0
3008 static Bool
3009 gdk_event_get_type (Display  *display,
3010                     XEvent   *xevent,
3011                     XPointer  arg)
3012 {
3013   GdkEvent event;
3014   GdkPredicate *pred;
3015
3016   if (gdk_event_translate (&event, xevent))
3017     {
3018       pred = (GdkPredicate*) arg;
3019       return (* pred->func) (&event, pred->data);
3020     }
3021
3022   return FALSE;
3023 }
3024 #endif
3025
3026 static void
3027 gdk_synthesize_click (GdkEvent *event,
3028                       gint      nclicks)
3029 {
3030   GdkEvent temp_event;
3031
3032   g_return_if_fail (event != NULL);
3033
3034   temp_event = *event;
3035   temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
3036
3037   gdk_event_put (&temp_event);
3038 }
3039
3040 /*
3041  *--------------------------------------------------------------
3042  * gdk_exit_func
3043  *
3044  *   This is the "atexit" function that makes sure the
3045  *   library gets a chance to cleanup.
3046  *
3047  * Arguments:
3048  *
3049  * Results:
3050  *
3051  * Side effects:
3052  *   The library is un-initialized and the program exits.
3053  *
3054  *--------------------------------------------------------------
3055  */
3056
3057 static void
3058 gdk_exit_func (void)
3059 {
3060   static gboolean in_gdk_exit_func = FALSE;
3061
3062   /* This is to avoid an infinite loop if a program segfaults in
3063      an atexit() handler (and yes, it does happen, especially if a program
3064      has trounced over memory too badly for even g_print to work) */
3065   if(in_gdk_exit_func == TRUE) return;
3066   in_gdk_exit_func = TRUE;
3067
3068   if (initialized)
3069     {
3070 #ifdef USE_XIM
3071       /* cleanup IC */
3072       gdk_ic_cleanup ();
3073       /* close IM */
3074       gdk_im_close ();
3075 #endif
3076       gdk_image_exit ();
3077       gdk_input_exit ();
3078       gdk_key_repeat_restore ();
3079
3080       XCloseDisplay (gdk_display);
3081       initialized = 0;
3082     }
3083 }
3084
3085 /*
3086  *--------------------------------------------------------------
3087  * gdk_x_error
3088  *
3089  *   The X error handling routine.
3090  *
3091  * Arguments:
3092  *   "display" is the X display the error orignated from.
3093  *   "error" is the XErrorEvent that we are handling.
3094  *
3095  * Results:
3096  *   Either we were expecting some sort of error to occur,
3097  *   in which case we set the "gdk_error_code" flag, or this
3098  *   error was unexpected, in which case we will print an
3099  *   error message and exit. (Since trying to continue will
3100  *   most likely simply lead to more errors).
3101  *
3102  * Side effects:
3103  *
3104  *--------------------------------------------------------------
3105  */
3106
3107 static int
3108 gdk_x_error (Display     *display,
3109              XErrorEvent *error)
3110 {
3111   char buf[64];
3112
3113   if (gdk_error_warnings)
3114     {
3115       XGetErrorText (display, error->error_code, buf, 63);
3116       g_error ("%s\n  serial %ld error_code %d request_code %d minor_code %d\n", 
3117                buf, 
3118                error->serial, 
3119                error->error_code, 
3120                error->request_code,
3121                error->minor_code);
3122     }
3123
3124   gdk_error_code = -1;
3125   return 0;
3126 }
3127
3128 /*
3129  *--------------------------------------------------------------
3130  * gdk_x_io_error
3131  *
3132  *   The X I/O error handling routine.
3133  *
3134  * Arguments:
3135  *   "display" is the X display the error orignated from.
3136  *
3137  * Results:
3138  *   An X I/O error basically means we lost our connection
3139  *   to the X server. There is not much we can do to
3140  *   continue, so simply print an error message and exit.
3141  *
3142  * Side effects:
3143  *
3144  *--------------------------------------------------------------
3145  */
3146
3147 static int
3148 gdk_x_io_error (Display *display)
3149 {
3150   g_error ("an x io error occurred");
3151   return 0;
3152 }
3153
3154 /*
3155  *--------------------------------------------------------------
3156  * gdk_signal
3157  *
3158  *   The signal handler.
3159  *
3160  * Arguments:
3161  *   "sig_num" is the number of the signal we received.
3162  *
3163  * Results:
3164  *   The signals we catch are all fatal. So we simply build
3165  *   up a nice little error message and print it and exit.
3166  *   If in the process of doing so another signal is received
3167  *   we notice that we are already exiting and simply kill
3168  *   our process.
3169  *
3170  * Side effects:
3171  *
3172  *--------------------------------------------------------------
3173  */
3174
3175 static RETSIGTYPE
3176 gdk_signal (int sig_num)
3177 {
3178   static int caught_fatal_sig = 0;
3179   char *sig;
3180
3181   if (caught_fatal_sig)
3182     kill (getpid (), sig_num);
3183   caught_fatal_sig = 1;
3184
3185   switch (sig_num)
3186     {
3187     case SIGHUP:
3188       sig = "sighup";
3189       break;
3190     case SIGINT:
3191       sig = "sigint";
3192       break;
3193     case SIGQUIT:
3194       sig = "sigquit";
3195       break;
3196     case SIGBUS:
3197       sig = "sigbus";
3198       break;
3199     case SIGSEGV:
3200       sig = "sigsegv";
3201       break;
3202     case SIGPIPE:
3203       sig = "sigpipe";
3204       break;
3205     case SIGTERM:
3206       sig = "sigterm";
3207       break;
3208     default:
3209       sig = "unknown signal";
3210       break;
3211     }
3212
3213   g_print ("\n** ERROR **: %s caught\n", sig);
3214 #ifdef G_ENABLE_DEBUG
3215   abort ();
3216 #else /* !G_ENABLE_DEBUG */
3217   gdk_exit (1);
3218 #endif /* !G_ENABLE_DEBUG */
3219 }
3220
3221 static void
3222 gdk_dnd_drag_begin (GdkWindow *initial_window)
3223 {
3224   GdkEvent tev;
3225
3226   GDK_NOTE(DND, g_print("------- STARTING DRAG from %p\n", initial_window));
3227
3228   tev.type = GDK_DRAG_BEGIN;
3229   tev.dragbegin.window = initial_window;
3230   tev.dragbegin.u.allflags = 0;
3231   tev.dragbegin.u.flags.protocol_version = DND_PROTOCOL_VERSION;
3232
3233   gdk_event_put (&tev);
3234 }
3235
3236 static void
3237 gdk_dnd_drag_enter (Window dest)
3238 {
3239   XEvent sev;
3240   GdkEventDropEnter tev;
3241   int i;
3242   GdkWindowPrivate *wp;
3243   
3244   sev.xclient.type = ClientMessage;
3245   sev.xclient.format = 32;
3246   sev.xclient.message_type = gdk_dnd.gdk_XdeEnter;
3247   sev.xclient.window = dest;
3248
3249   tev.u.allflags = 0;
3250   tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
3251   tev.u.flags.sendreply = 1;
3252   for (i = 0; i < gdk_dnd.drag_numwindows; i++)
3253     {
3254       wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i];
3255       if (wp->dnd_drag_data_numtypesavail)
3256         {
3257           sev.xclient.data.l[0] = wp->xwindow;
3258           tev.u.flags.extended_typelist = (wp->dnd_drag_data_numtypesavail > 3)?1:0;
3259           sev.xclient.data.l[1] = tev.u.allflags;
3260           sev.xclient.data.l[2] = wp->dnd_drag_data_typesavail[0];
3261           if (wp->dnd_drag_data_numtypesavail > 1)
3262             {
3263               sev.xclient.data.l[3] = wp->dnd_drag_data_typesavail[1];
3264               if (wp->dnd_drag_data_numtypesavail > 2)
3265                 {
3266                   sev.xclient.data.l[4] = wp->dnd_drag_data_typesavail[2];
3267                 }
3268               else
3269                 sev.xclient.data.l[4] = None;
3270             }
3271           else
3272             sev.xclient.data.l[3] = sev.xclient.data.l[4] = None;
3273           if (!gdk_send_xevent (dest, False, StructureNotifyMask, &sev))
3274                 GDK_NOTE (DND, g_print("Sending XdeEnter to %#lx failed\n",
3275                                        dest));
3276         }
3277
3278     }
3279 }
3280
3281
3282 #ifdef USE_XIM
3283
3284 /* The following routines duplicate functionality in Xlib to
3285  * translate from varargs to X's internal opaque XVaNestedList.
3286  * 
3287  * If all vendors have stuck close to the reference implementation,
3288  * then we should hopefully be OK. 
3289  */
3290
3291 /* This needs to match XIMArg as defined in Xlcint.h exactly */
3292   
3293 typedef struct {
3294   gchar   *name;
3295   gpointer value;
3296 } GdkImArg;
3297
3298 /*************************************************************
3299  * gdk_im_va_count:
3300  *    Counts the number of name/value pairs in the vararg list
3301  *
3302  *   arguments:
3303  *     
3304  *   results:
3305  *************************************************************/
3306
3307 static guint 
3308 gdk_im_va_count (va_list list)
3309 {
3310   gint count = 0;
3311   gchar *name;
3312
3313   name = va_arg (list, gchar *);
3314   while (name)
3315     {
3316       count++;
3317       (void)va_arg (list, gpointer);
3318       name = va_arg (list, gchar *);
3319     }
3320
3321   return count;
3322 }
3323
3324 /*************************************************************
3325  * gdk_im_va_to_nested:
3326  *     Given a varargs list and the result of gdk_im_va_count,
3327  *     create a XVaNestedList.
3328  *
3329  *   arguments:
3330  *     
3331  *   results:
3332  *************************************************************/
3333
3334 static XVaNestedList
3335 gdk_im_va_to_nested (va_list list, guint count)
3336 {
3337   GdkImArg *result;
3338   GdkImArg *arg;
3339
3340   gchar *name;
3341
3342   if (count == 0)
3343     return NULL;
3344
3345   result = g_new (GdkImArg, count+1);
3346   arg = result;
3347
3348   name = va_arg (list, gchar *);
3349   while (name)
3350     {
3351       arg->name = name;
3352       arg->value = va_arg (list, gpointer);
3353       arg++;
3354       name = va_arg (list, gchar *);
3355     }
3356
3357   arg->name = NULL;
3358
3359   return (XVaNestedList)result;
3360 }
3361
3362 /*
3363  *--------------------------------------------------------------
3364  * gdk_im_begin
3365  *
3366  *   Begin using input method with XIM Protocol(X11R6 standard)
3367  *
3368  * Arguments:
3369  *   "ic" is the "Input Context" which is created by gtk_ic_new.
3370  *   The input area is specified with "window".
3371  *
3372  * Results:
3373  *   The gdk's event handling routine is switched to XIM based routine.
3374  *   XIM based routine uses XFilterEvent to get rid of events used by IM,
3375  *   and uses XmbLookupString instead of XLookupString.
3376  *
3377  * Side effects:
3378  *
3379  *--------------------------------------------------------------
3380  */
3381
3382 void 
3383 gdk_im_begin (GdkIC ic, GdkWindow* window)
3384 {
3385   GdkICPrivate *private;
3386   Window xwin;
3387
3388   g_return_if_fail (ic != NULL);
3389   g_return_if_fail (window);
3390
3391   private = (GdkICPrivate *) ic;
3392
3393   xim_using = TRUE;
3394   xim_ic = private;
3395   xim_window = window;
3396   if (gdk_im_ready())
3397     {
3398       XGetICValues (private->xic, XNFocusWindow, &xwin, NULL);
3399       if (xwin != GDK_WINDOW_XWINDOW(window))
3400         XSetICValues (private->xic, XNFocusWindow, 
3401                       GDK_WINDOW_XWINDOW(window), NULL);
3402       if (private != xim_ic)
3403         XSetICFocus (private->xic);
3404     }
3405 }
3406
3407 /*
3408  *--------------------------------------------------------------
3409  * gdk_im_end
3410  *
3411  *   End using input method with XIM Protocol(X11R6 standard)
3412  *
3413  * Arguments:
3414  *
3415  * Results:
3416  *   The gdk's event handling routine is switched to normal routine.
3417  *   User should call this function before ic and window will be destroyed.
3418  *
3419  * Side effects:
3420  *
3421  *--------------------------------------------------------------
3422  */
3423
3424 void 
3425 gdk_im_end (void)
3426 {
3427   xim_using = FALSE;
3428   xim_ic = NULL;
3429   xim_window = NULL;
3430 }
3431
3432 static GdkIM 
3433 gdk_im_get (void)
3434 {
3435   return xim_im;
3436 }
3437
3438 static GdkIMStyle 
3439 gdk_im_choose_better_style (GdkIMStyle style1, GdkIMStyle style2) 
3440 {
3441   GdkIMStyle s1, s2, u;
3442
3443   if (style1 == 0) return style2;
3444   if (style2 == 0) return style1;
3445   if ((style1 & (GdkIMPreeditMask | GdkIMStatusMask))
3446         == (style2 & (GdkIMPreeditMask | GdkIMStatusMask)))
3447     return style1;
3448
3449   s1 = style1 & GdkIMPreeditMask;
3450   s2 = style2 & GdkIMPreeditMask;
3451   u = s1 | s2;
3452   if (s1 != s2) {
3453     if (u & GdkIMPreeditCallbacks)
3454       return (s1 == GdkIMPreeditCallbacks)? style1:style2;
3455     else if (u & GdkIMPreeditPosition)
3456       return (s1 == GdkIMPreeditPosition)? style1:style2;
3457     else if (u & GdkIMPreeditArea)
3458       return (s1 == GdkIMPreeditArea)? style1:style2;
3459     else if (u & GdkIMPreeditNothing)
3460       return (s1 == GdkIMPreeditNothing)? style1:style2;
3461   } else {
3462     s1 = style1 & GdkIMStatusMask;
3463     s2 = style2 & GdkIMStatusMask;
3464     u = s1 | s2;
3465     if ( u & GdkIMStatusCallbacks)
3466       return (s1 == GdkIMStatusCallbacks)? style1:style2;
3467     else if ( u & GdkIMStatusArea)
3468       return (s1 == GdkIMStatusArea)? style1:style2;
3469     else if ( u & GdkIMStatusNothing)
3470       return (s1 == GdkIMStatusNothing)? style1:style2;
3471     else if ( u & GdkIMStatusNone)
3472       return (s1 == GdkIMStatusNone)? style1:style2;
3473   }
3474   return 0; /* Get rid of stupid warning */
3475 }
3476
3477 GdkIMStyle
3478 gdk_im_decide_style (GdkIMStyle supported_style)
3479 {
3480   gint i;
3481   GdkIMStyle style, tmp;
3482
3483   g_return_val_if_fail (xim_styles != NULL, 0);
3484
3485   style = 0;
3486   for (i=0; i<xim_styles->count_styles; i++)
3487     {
3488       tmp = xim_styles->supported_styles[i];
3489       if (tmp == (tmp & supported_style & xim_best_allowed_style))
3490         style = gdk_im_choose_better_style (style, tmp);
3491     }
3492   return style;
3493 }
3494
3495 GdkIMStyle
3496 gdk_im_set_best_style (GdkIMStyle style)
3497 {
3498   if (style & GdkIMPreeditMask)
3499     {
3500       xim_best_allowed_style &= ~GdkIMPreeditMask;
3501
3502       xim_best_allowed_style |= GdkIMPreeditNone;
3503       if (!(style & GdkIMPreeditNone))
3504         {
3505           xim_best_allowed_style |= GdkIMPreeditNothing;
3506           if (!(style & GdkIMPreeditNothing))
3507             {
3508               xim_best_allowed_style |= GdkIMPreeditArea;
3509               if (!(style & GdkIMPreeditArea))
3510                 {
3511                   xim_best_allowed_style |= GdkIMPreeditPosition;
3512                   if (!(style & GdkIMPreeditPosition))
3513                     xim_best_allowed_style |= GdkIMPreeditCallbacks;
3514                 }
3515             }
3516         }
3517     }
3518   if (style & GdkIMStatusMask)
3519     {
3520       xim_best_allowed_style &= ~GdkIMStatusMask;
3521
3522       xim_best_allowed_style |= GdkIMStatusNone;
3523       if (!(style & GdkIMStatusNone))
3524         {
3525           xim_best_allowed_style |= GdkIMStatusNothing;
3526           if (!(style & GdkIMStatusNothing))
3527             {
3528               xim_best_allowed_style |= GdkIMStatusArea;
3529               if (!(style & GdkIMStatusArea))
3530                 xim_best_allowed_style |= GdkIMStatusCallbacks;
3531             }
3532         }
3533     }
3534   
3535   return xim_best_allowed_style;
3536 }
3537
3538 static gint 
3539 gdk_im_open (XrmDatabase db, gchar* res_name, gchar* res_class)
3540 {
3541   xim_im = XOpenIM (GDK_DISPLAY(), db, res_name, res_class);
3542   if (xim_im == NULL)
3543     {
3544       GDK_NOTE (XIM, g_warning ("Unable to open open IM."));
3545       return FALSE;
3546     }
3547   XGetIMValues (xim_im, XNQueryInputStyle, &xim_styles, NULL, NULL);
3548
3549   return TRUE;
3550 }
3551
3552 static void 
3553 gdk_im_close (void)
3554 {
3555   if (xim_im)
3556     {
3557       XCloseIM (xim_im);
3558       xim_im = NULL;
3559     }
3560   if (xim_styles)
3561     {
3562       XFree (xim_styles);
3563       xim_styles = NULL;
3564     }
3565 }
3566
3567 gint 
3568 gdk_im_ready (void)
3569 {
3570   return (xim_im != NULL);
3571 }
3572
3573 GdkIC 
3574 gdk_ic_new (GdkWindow* client_window,
3575             GdkWindow* focus_window,
3576             GdkIMStyle style, ...)
3577 {
3578   va_list list;
3579   GdkICPrivate *private;
3580   XVaNestedList preedit_attr = NULL;
3581   guint count;
3582
3583   g_return_val_if_fail (client_window != NULL, NULL);
3584   g_return_val_if_fail (focus_window != NULL, NULL);
3585   g_return_val_if_fail (gdk_im_ready(), NULL);
3586
3587   private = g_new (GdkICPrivate, 1);
3588
3589   va_start (list, style);
3590   count = gdk_im_va_count (list);
3591   va_end (list);
3592
3593   va_start (list, style);
3594   preedit_attr = gdk_im_va_to_nested (list, count);
3595   va_end (list);
3596   
3597   private->style = gdk_im_decide_style (style);
3598   if (private->style != style)
3599     {
3600       g_warning ("can not create input context with specified input style.");
3601       g_free (private);
3602       return NULL;
3603     }
3604
3605   private->xic = XCreateIC(gdk_im_get (),
3606                         XNInputStyle,   style,
3607                         XNClientWindow, GDK_WINDOW_XWINDOW (client_window),
3608                         XNFocusWindow,  GDK_WINDOW_XWINDOW (focus_window),
3609                         preedit_attr? XNPreeditAttributes : NULL, preedit_attr,
3610                         NULL);
3611
3612   g_free (preedit_attr);
3613   
3614   if (!private->xic)
3615     {
3616       g_free (private);
3617       return NULL;
3618     }
3619
3620   xim_ic_list = g_list_append (xim_ic_list, private);
3621   return private;
3622 }
3623
3624 void 
3625 gdk_ic_destroy (GdkIC ic)
3626 {
3627   GdkICPrivate *private;
3628
3629   g_return_if_fail (ic != NULL);
3630   
3631   private = (GdkICPrivate *) ic;
3632
3633   if (xim_ic == private)
3634     gdk_im_end ();
3635
3636   XDestroyIC (private->xic);
3637   xim_ic_list = g_list_remove (xim_ic_list, private);
3638   g_free (private);
3639 }
3640
3641 GdkIMStyle
3642 gdk_ic_get_style (GdkIC ic)
3643 {
3644   GdkICPrivate *private;
3645
3646   g_return_val_if_fail (ic != NULL, 0);
3647
3648   private = (GdkICPrivate *) ic;
3649
3650   return private->style;
3651 }
3652
3653 void 
3654 gdk_ic_set_values (GdkIC ic, ...)
3655 {
3656   va_list list;
3657   XVaNestedList args;
3658   GdkICPrivate *private;
3659   guint count;
3660
3661   g_return_if_fail (ic != NULL);
3662
3663   private = (GdkICPrivate *) ic;
3664
3665   va_start (list, ic);
3666   count = gdk_im_va_count (list);
3667   va_end (list);
3668
3669   va_start (list, ic);
3670   args = gdk_im_va_to_nested (list, count);
3671   va_end (list);
3672
3673   XSetICValues (private->xic, XNVaNestedList, args, NULL);
3674
3675   g_free (args);
3676 }
3677
3678 void 
3679 gdk_ic_get_values (GdkIC ic, ...)
3680 {
3681   va_list list;
3682   XVaNestedList args;
3683   GdkICPrivate *private;
3684   guint count;
3685
3686   g_return_if_fail (ic != NULL);
3687
3688   private = (GdkICPrivate *) ic;
3689
3690   va_start (list, ic);
3691   count = gdk_im_va_count (list);
3692   va_end (list);
3693
3694   va_start (list, ic);
3695   args = gdk_im_va_to_nested (list, count);
3696   va_end (list);
3697
3698   XGetICValues (private->xic, XNVaNestedList, args, NULL);
3699
3700   g_free (args);
3701 }
3702
3703 void 
3704 gdk_ic_set_attr (GdkIC ic, const char *target, ...)
3705 {
3706   va_list list;
3707   XVaNestedList attr;
3708   GdkICPrivate *private;
3709   guint count;
3710
3711   g_return_if_fail (ic != NULL);
3712   g_return_if_fail (target != NULL);
3713
3714   private = (GdkICPrivate *) ic;
3715
3716   va_start (list, target);
3717   count = gdk_im_va_count (list);
3718   va_end (list);
3719
3720   va_start (list, target);
3721   attr = gdk_im_va_to_nested (list, count);
3722   va_end (list);
3723
3724   XSetICValues (private->xic, target, attr, NULL);
3725
3726   g_free (attr);
3727 }
3728
3729 void 
3730 gdk_ic_get_attr (GdkIC ic, const char *target, ...)
3731 {
3732   va_list list;
3733   XVaNestedList attr;
3734   GdkICPrivate *private;
3735   guint count;
3736
3737   g_return_if_fail (ic != NULL);
3738   g_return_if_fail (target != NULL);
3739
3740   private = (GdkICPrivate *) ic;
3741
3742   va_start (list, target);
3743   count = gdk_im_va_count (list);
3744   va_end (list);
3745
3746   va_start (list, target);
3747   attr = gdk_im_va_to_nested (list, count);
3748   va_end (list);
3749
3750   XGetICValues (private->xic, target, attr, NULL);
3751
3752   g_free (attr);
3753 }
3754
3755 GdkEventMask 
3756 gdk_ic_get_events (GdkIC ic)
3757 {
3758   GdkEventMask mask;
3759   glong xmask;
3760   glong bit;
3761   GdkICPrivate *private;
3762   gint i;
3763
3764   /*  From gdkwindow.c  */
3765   extern int nevent_masks;
3766   extern int event_mask_table[];
3767
3768   g_return_val_if_fail (ic != NULL, 0);
3769
3770   private = (GdkICPrivate *) ic;
3771
3772   if (XGetICValues (private->xic, XNFilterEvents, &xmask, NULL) != NULL)
3773     {
3774       GDK_NOTE (XIM, g_warning ("Call to XGetICValues: %s failed", XNFilterEvents));
3775       return 0;
3776     }
3777
3778   mask = 0;
3779   for (i=0, bit=2; i < nevent_masks; i++, bit <<= 1)
3780     if (xmask & event_mask_table [i])
3781       {
3782         mask |= bit;
3783         xmask &= ~ event_mask_table [i];
3784       }
3785
3786   if (xmask)
3787     g_warning ("ic requires events not supported by the application (%#04lx)", xmask);
3788   
3789   return mask;
3790 }
3791
3792 static void 
3793 gdk_ic_cleanup (void)
3794 {
3795   GList* node;
3796   gint destroyed;
3797   GdkICPrivate *private;
3798
3799   destroyed = 0;
3800   for (node = xim_ic_list; node != NULL; node = node->next)
3801     {
3802       if (node->data)
3803        {
3804          private = (GdkICPrivate *) (node->data);
3805          XDestroyIC (private->xic);
3806          g_free (private);
3807          destroyed++;
3808        }
3809     }
3810 #ifdef G_ENABLE_DEBUG
3811   if ((gdk_debug_flags & GDK_DEBUG_XIM) && destroyed > 0)
3812     {
3813       g_warning ("Cleaned up %i IC(s)\n", destroyed);
3814     }
3815 #endif /* G_ENABLE_DEBUG */
3816   g_list_free(xim_ic_list);
3817   xim_ic_list = NULL;
3818 }
3819
3820 #else /* !USE_XIM */
3821
3822 void 
3823 gdk_im_begin (GdkIC ic, GdkWindow* window)
3824 {
3825 }
3826
3827 void 
3828 gdk_im_end (void)
3829 {
3830 }
3831
3832 GdkIMStyle
3833 gdk_im_decide_style (GdkIMStyle supported_style)
3834 {
3835   return GdkIMPreeditNone | GdkIMStatusNone;
3836 }
3837
3838 GdkIMStyle
3839 gdk_im_set_best_style (GdkIMStyle style)
3840 {
3841   return GdkIMPreeditNone | GdkIMStatusNone;
3842 }
3843
3844 gint 
3845 gdk_im_ready (void)
3846 {
3847   return FALSE;
3848 }
3849
3850 GdkIC 
3851 gdk_ic_new (GdkWindow* client_window,
3852             GdkWindow* focus_window,
3853             GdkIMStyle style, ...)
3854 {
3855   return NULL;
3856 }
3857
3858 void 
3859 gdk_ic_destroy (GdkIC ic)
3860 {
3861 }
3862
3863 GdkIMStyle
3864 gdk_ic_get_style (GdkIC ic)
3865 {
3866   return GdkIMPreeditNone | GdkIMStatusNone;
3867 }
3868
3869 void 
3870 gdk_ic_set_values (GdkIC ic, ...)
3871 {
3872 }
3873
3874 void 
3875 gdk_ic_get_values (GdkIC ic, ...)
3876 {
3877 }
3878
3879 void 
3880 gdk_ic_set_attr (GdkIC ic, const char *target, ...)
3881 {
3882 }
3883
3884 void 
3885 gdk_ic_get_attr (GdkIC ic, const char *target, ...)
3886 {
3887 }
3888
3889 GdkEventMask 
3890 gdk_ic_get_events (GdkIC ic)
3891 {
3892   return 0;
3893 }
3894
3895 #endif /* USE_XIM */
3896
3897 #ifdef X_LOCALE
3898
3899 gint
3900 _g_mbtowc (wchar_t *wstr, const char *str, size_t len)
3901 {
3902   static wchar_t wcs[MB_CUR_MAX + 1];
3903   static gchar mbs[MB_CUR_MAX + 1];
3904
3905   wcs[0] = (wchar_t) NULL;
3906   mbs[0] = '\0';
3907
3908   /* The last argument isn't a mistake. The X locale code trims
3909    *  the input string to the length of the output string!
3910    */
3911   len = _Xmbstowcs (wcs, str, (len<MB_CUR_MAX)? len:MB_CUR_MAX);
3912   if (len < 1)
3913     return len;
3914   else if (wcs[0] == (wchar_t) NULL)
3915     return -1;
3916
3917   len = _Xwctomb (mbs, wcs[0]);
3918   if (mbs[0] == '\0')
3919     return -1;
3920   if (wstr)
3921     *wstr = wcs[0];
3922
3923   return len;
3924 }
3925
3926 #endif /* X_LOCALE */
3927
3928 static void
3929 gdk_dnd_drag_leave (Window dest)
3930 {
3931   XEvent sev;
3932   GdkEventDropLeave tev;
3933   int i;
3934   GdkWindowPrivate *wp;
3935
3936   tev.u.allflags = 0;
3937
3938   tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
3939   sev.xclient.type = ClientMessage;
3940   sev.xclient.window = dest;
3941   sev.xclient.format = 32;
3942   sev.xclient.message_type = gdk_dnd.gdk_XdeLeave;
3943   sev.xclient.data.l[1] = tev.u.allflags;
3944   for (i = 0; i < gdk_dnd.drag_numwindows; i++)
3945     {
3946       wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i];
3947       sev.xclient.data.l[0] = wp->xwindow;
3948       if (!gdk_send_xevent (dest, False, StructureNotifyMask, &sev))
3949         GDK_NOTE (DND, g_print("Sending XdeLeave to %#lx failed\n",
3950                                dest));
3951       wp->dnd_drag_accepted = 0;
3952     }
3953 }
3954
3955 /* 
3956  * when a drop occurs, we go through the list of windows being dragged and
3957  * tell them that it has occurred, so that they can set things up and reply
3958  * to 'dest' window 
3959  */
3960 static void
3961 gdk_dnd_drag_end (Window     dest, 
3962                   GdkPoint   coords)
3963 {
3964   GdkWindowPrivate *wp;
3965   GdkEvent tev;
3966   int i;
3967
3968   tev.dragrequest.type = GDK_DRAG_REQUEST;
3969   tev.dragrequest.drop_coords = coords;
3970   tev.dragrequest.requestor = dest;
3971   tev.dragrequest.u.allflags = 0;
3972   tev.dragrequest.u.flags.protocol_version = DND_PROTOCOL_VERSION;
3973   tev.dragrequest.isdrop = 1;
3974
3975   for (i = 0; i < gdk_dnd.drag_numwindows; i++)
3976     {
3977       wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i];
3978       if (wp->dnd_drag_accepted)
3979         {
3980           tev.dragrequest.window = (GdkWindow *) wp;
3981           tev.dragrequest.u.flags.delete_data = wp->dnd_drag_destructive_op;
3982           tev.dragrequest.timestamp = gdk_dnd.last_drop_time;
3983           tev.dragrequest.data_type = 
3984                 gdk_atom_name(wp->dnd_drag_data_type);
3985
3986           gdk_event_put(&tev);
3987         }
3988     }
3989 }
3990
3991 static GdkAtom
3992 gdk_dnd_check_types (GdkWindow   *window, 
3993                      XEvent      *xevent)
3994 {
3995   GdkWindowPrivate *wp = (GdkWindowPrivate *) window;
3996   int i, j;
3997   GdkEventDropEnter event;
3998
3999   g_return_val_if_fail(window != NULL, 0);
4000   g_return_val_if_fail(xevent != NULL, 0);
4001   g_return_val_if_fail(xevent->type == ClientMessage, 0);
4002   g_return_val_if_fail(xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter, 0);
4003
4004   if(wp->dnd_drop_data_numtypesavail <= 0 ||
4005      !wp->dnd_drop_data_typesavail)
4006     return 0;
4007
4008   for (i = 2; i <= 4; i++)
4009     {
4010       for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++)
4011         {
4012           if (xevent->xclient.data.l[i] == wp->dnd_drop_data_typesavail[j])
4013             return xevent->xclient.data.l[i];
4014         }
4015     }
4016
4017   /* Now we get the extended type list if it's available */
4018   event.u.allflags = xevent->xclient.data.l[1];
4019   if (event.u.flags.extended_typelist)
4020     {
4021       Atom *exttypes, realtype;
4022       gulong nitems, nbar;
4023       gint realfmt;
4024
4025       if (XGetWindowProperty(gdk_display, xevent->xclient.data.l[0],
4026                              gdk_dnd.gdk_XdeTypelist, 0L, LONG_MAX - 1,
4027                              False, AnyPropertyType, &realtype, &realfmt,
4028                              &nitems, &nbar, (unsigned char **) &exttypes)
4029          != Success)
4030         return 0;
4031
4032       if (realfmt != (sizeof(Atom) * 8))
4033         {
4034           g_warning("XdeTypelist property had format of %d instead of the expected %ld, on window %#lx\n",
4035                     realfmt, (glong)sizeof(Atom) * 8, xevent->xclient.data.l[0]);
4036           return 0;
4037         }
4038
4039       for (i = 0; i <= nitems; i++)
4040         {
4041           for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++)
4042             {
4043               if (exttypes[i] == wp->dnd_drop_data_typesavail[j])
4044                 {
4045                   XFree (exttypes);
4046                   return exttypes[i];
4047                 }
4048             }
4049         }
4050       XFree (exttypes);
4051     }
4052   return 0;
4053 }
4054
4055 /* 
4056  * used for debugging only 
4057  */
4058 #ifdef DEBUG_DND
4059 static void
4060 gdk_print_atom (GdkAtom anatom)
4061 {
4062   gchar *tmpstr = NULL;
4063   tmpstr = (anatom!=None)?gdk_atom_name(anatom):"(none)";
4064   g_print("Atom %lu has name %s\n", anatom, tmpstr);
4065   if(tmpstr)
4066     g_free(tmpstr);
4067 }
4068 #endif
4069
4070 /* 
4071  * used only by below routine and itself 
4072  */
4073 static Window 
4074 getchildren (Display     *dpy, 
4075              Window       win, 
4076              Atom         WM_STATE)
4077 {
4078   Window root, parent, *children, inf = 0;
4079   Atom type = None;
4080   unsigned int nchildren, i;
4081   int format;
4082   unsigned long nitems, after;
4083   unsigned char *data;
4084
4085   if (XQueryTree(dpy, win, &root, &parent, &children, &nchildren) == 0)
4086     return 0;
4087
4088   for (i = 0; !inf && (i < nchildren); i++)
4089     {
4090       XGetWindowProperty (dpy, children[i], WM_STATE, 0, 0, False,
4091                           AnyPropertyType, &type, &format, &nitems,
4092                           &after, &data);
4093       if (type != 0)
4094         inf = children[i];
4095       XFree(data);
4096     }
4097
4098   for (i = 0; !inf && (i < nchildren); i++)
4099     inf = getchildren (dpy, children[i], WM_STATE);
4100
4101   if (children != None)
4102     XFree ((char *) children);
4103
4104   return inf;
4105 }
4106
4107 /* 
4108  * find a window with WM_STATE, else return win itself, as per ICCCM
4109  *
4110  * modification of the XmuClientWindow() routine from X11R6.3
4111  */
4112 Window
4113 gdk_get_client_window (Display  *dpy, 
4114                        Window    win)
4115 {
4116   Atom WM_STATE;
4117   Atom type = None;
4118   int format;
4119   unsigned long nitems, after;
4120   unsigned char *data;
4121   Window inf;
4122
4123   if (win == 0)
4124     return DefaultRootWindow(dpy);
4125
4126   if ((WM_STATE = XInternAtom (dpy, "WM_STATE", True)) == 0)
4127     return win;
4128
4129   XGetWindowProperty (dpy, win, WM_STATE, 0, 0, False, AnyPropertyType,
4130                       &type, &format, &nitems, &after, &data);
4131   if (type)
4132     return win;
4133
4134   inf = getchildren (dpy, win, WM_STATE);
4135
4136   if (inf == 0)
4137     return win;
4138   else
4139     return inf;
4140 }
4141
4142 #ifdef WE_HAVE_MOTIF_DROPS_DONE
4143 static GdkWindow *
4144 gdk_drop_get_real_window (GdkWindow   *w, 
4145                           guint16     *x, 
4146                           guint16     *y)
4147 {
4148   GdkWindow *retval = w;
4149   GdkWindowPrivate *awin;
4150   GList *children;
4151   gint16 myx = *x, myy = *y;
4152
4153   g_return_val_if_fail(w != NULL && x != NULL && y != NULL, NULL);
4154
4155   myx = *x; 
4156   myy = *y;
4157
4158 descend:
4159   for (children = gdk_window_get_children(retval); 
4160        children && children->next;
4161        children = children->next)
4162     {
4163       awin = (GdkWindowPrivate *) children->data;
4164       if ((myx >= awin->x) && (myy >= awin->y)
4165           && (myx < (awin->x + awin->width))
4166           && (myy < (awin->y + awin->height)))
4167         {
4168           retval = (GdkWindow *) awin;
4169           myx -= awin->x;
4170           myy -= awin->y;
4171           goto descend;
4172         }
4173     }
4174
4175   *x = myx; 
4176   *y = myy;
4177
4178   return retval;
4179 }
4180 #endif
4181
4182 /* Sends a ClientMessage to all toplevel client windows */
4183 void
4184 gdk_event_send_clientmessage_toall(GdkEvent *event)
4185 {
4186   XEvent sev;
4187   Window *ret_children, ret_root, ret_parent, curwin;
4188   unsigned int ret_nchildren;
4189   int i;
4190
4191   g_return_if_fail(event != NULL);
4192
4193   /* Set up our event to send, with the exception of its target window */
4194   sev.xclient.type = ClientMessage;
4195   sev.xclient.display = gdk_display;
4196   sev.xclient.format = event->client.data_format;
4197   sev.xclient.serial = CurrentTime;
4198   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
4199   sev.xclient.message_type = event->client.message_type;
4200
4201   /* OK, we're all set, now let's find some windows to send this to */
4202   if(XQueryTree(gdk_display, gdk_root_window, &ret_root, &ret_parent,
4203                 &ret_children, &ret_nchildren) != True)
4204     return;
4205
4206   /* foreach true child window of the root window, send an event to it */
4207   for(i = 0; i < ret_nchildren; i++) {
4208     curwin = gdk_get_client_window(gdk_display, ret_children[i]);
4209     sev.xclient.window = curwin;
4210     if (!gdk_send_xevent (curwin, False, NoEventMask, &sev))
4211       GDK_NOTE (MISC, g_print("Gdk: Sending client message %ld to %#lx failed\n",
4212                              event->client.message_type, curwin));
4213   }
4214
4215   XFree(ret_children);
4216 }
4217
4218 gchar *
4219 gdk_get_display(void)
4220 {
4221   return (gchar *)XDisplayName (gdk_display_name);
4222 }
4223
4224 gint 
4225 gdk_send_xevent (Window window, gboolean propagate, glong event_mask,
4226                  XEvent *event_send)
4227 {
4228   Status result;
4229   
4230   gdk_error_code = 0;
4231   
4232   gdk_error_warnings = 0;
4233   result = XSendEvent (gdk_display, window, propagate, event_mask, event_send);
4234   XSync (gdk_display, False);
4235   gdk_error_warnings = 1;
4236     
4237   return result && (gdk_error_code != -1);
4238 }