]> Pileus Git - ~andy/gtk/blob - gdk/gdk.c
Basic thread-awareness:
[~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             gdk_dnd.drag_really = 0;
2283
2284             GDK_NOTE (DND, g_print("Ungrabbed\n"));
2285
2286             gdk_dnd.drag_numwindows = 0;
2287             g_free(gdk_dnd.drag_startwindows);
2288             gdk_dnd.drag_startwindows = NULL;
2289             /* We don't want to ungrab the pointer here, or we'll
2290              * start getting spurious enter/leave events */
2291 #if 0
2292             XChangeActivePointerGrab (gdk_display, 0, None, CurrentTime);
2293 #endif
2294           }
2295         
2296         return_val = window_private && !window_private->destroyed;
2297         break;
2298
2299     case LeaveNotify:
2300       /* Print debugging info.
2301        */
2302       GDK_NOTE (EVENTS, 
2303         g_print ("leave notify:\t\twindow: %ld  detail: %d subwin: %ld\n",
2304                  xevent->xcrossing.window - base_id,
2305                  xevent->xcrossing.detail, xevent->xcrossing.subwindow - base_id));
2306
2307       event->crossing.type = GDK_LEAVE_NOTIFY;
2308       event->crossing.window = window;
2309
2310       /* If the subwindow field of the XEvent is non-NULL, then
2311        *  lookup the corresponding GdkWindow.
2312        */
2313       if (xevent->xcrossing.subwindow != None)
2314         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
2315       else
2316         event->crossing.subwindow = NULL;
2317
2318       /* Translate the crossing detail into Gdk terms.
2319        */
2320       switch (xevent->xcrossing.detail)
2321         {
2322         case NotifyInferior:
2323           event->crossing.detail = GDK_NOTIFY_INFERIOR;
2324           break;
2325         case NotifyAncestor:
2326           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
2327           break;
2328         case NotifyVirtual:
2329           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
2330           break;
2331         case NotifyNonlinear:
2332           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
2333           break;
2334         case NotifyNonlinearVirtual:
2335           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
2336           break;
2337         default:
2338           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
2339           break;
2340         }
2341 #ifdef G_ENABLE_DEBUG
2342       if ((gdk_debug_flags & GDK_DEBUG_DND) & gdk_dnd.drag_perhaps)
2343         {
2344           g_print("We may[%d] have a drag out of %#lx = %#lx\n",
2345                   gdk_dnd.drag_really,
2346                   xevent->xcrossing.window, gdk_dnd.real_sw->xwindow);
2347         }
2348 #endif /* G_ENABLE_DEBUG */
2349       if (gdk_dnd.drag_perhaps && !gdk_dnd.drag_really &&
2350           (xevent->xcrossing.window == gdk_dnd.real_sw->xwindow))
2351         {
2352           gboolean xgpret;
2353           gdk_dnd_drag_addwindow((GdkWindow *) gdk_dnd.real_sw);
2354           gdk_dnd_drag_begin((GdkWindow *) gdk_dnd.real_sw);
2355           xgpret = 
2356           XGrabPointer(gdk_display, gdk_dnd.real_sw->xwindow, False,
2357                        ButtonMotionMask | PointerMotionMask |
2358                        /* PointerMotionHintMask | */ /* HINTME */
2359                        ButtonPressMask | ButtonReleaseMask,
2360                        GrabModeAsync, GrabModeAsync, None,
2361                        None, CurrentTime);
2362 #ifdef G_ENABLE_DEBUG
2363           GDK_NOTE(DND, g_print("xgpret = %d\n", xgpret));
2364 #endif
2365           gdk_dnd.dnd_grabbed = TRUE;
2366           gdk_dnd.drag_really = 1;
2367           gdk_dnd_display_drag_cursor(xevent->xmotion.x_root,
2368                                       xevent->xmotion.y_root,
2369                                       FALSE, TRUE);
2370         }
2371
2372       return_val = window_private && !window_private->destroyed;
2373       break;
2374
2375     case FocusIn:
2376     case FocusOut:
2377       /* We only care about focus events that indicate that _this_
2378        * window (not a ancestor or child) got or lost the focus
2379        */
2380       switch (xevent->xfocus.detail)
2381         {
2382         case NotifyAncestor:
2383         case NotifyInferior:
2384         case NotifyNonlinear:
2385           /* Print debugging info.
2386            */
2387           GDK_NOTE (EVENTS,
2388             g_print ("focus %s:\t\twindow: %ld\n",
2389                      (xevent->xany.type == FocusIn) ? "in" : "out",
2390                      xevent->xfocus.window - base_id));
2391           
2392           event->focus_change.type = GDK_FOCUS_CHANGE;
2393           event->focus_change.window = window;
2394           event->focus_change.in = (xevent->xany.type == FocusIn);
2395           
2396           return_val = window_private && !window_private->destroyed;
2397           break;
2398         default:
2399           ;
2400         }
2401       break;
2402
2403     case KeymapNotify:
2404       /* Print debugging info.
2405        */
2406       GDK_NOTE (EVENTS,
2407         g_print ("keymap notify\n"));
2408
2409       /* Not currently handled */
2410       break;
2411
2412     case Expose:
2413       /* Print debugging info.
2414        */
2415       GDK_NOTE (EVENTS,
2416         g_print ("expose:\t\twindow: %ld  %d  x,y: %d %d  w,h: %d %d\n",
2417                  xevent->xexpose.window - base_id, xevent->xexpose.count,
2418                  xevent->xexpose.x, xevent->xexpose.y,
2419                  xevent->xexpose.width, xevent->xexpose.height));
2420
2421       event->expose.type = GDK_EXPOSE;
2422       event->expose.window = window;
2423       event->expose.area.x = xevent->xexpose.x;
2424       event->expose.area.y = xevent->xexpose.y;
2425       event->expose.area.width = xevent->xexpose.width;
2426       event->expose.area.height = xevent->xexpose.height;
2427       event->expose.count = xevent->xexpose.count;
2428
2429       return_val = window_private && !window_private->destroyed;
2430       break;
2431
2432     case GraphicsExpose:
2433       /* Print debugging info.
2434        */
2435       GDK_NOTE (EVENTS,
2436         g_print ("graphics expose:\tdrawable: %ld\n",
2437                  xevent->xgraphicsexpose.drawable - base_id));
2438
2439       event->expose.type = GDK_EXPOSE;
2440       event->expose.window = window;
2441       event->expose.area.x = xevent->xgraphicsexpose.x;
2442       event->expose.area.y = xevent->xgraphicsexpose.y;
2443       event->expose.area.width = xevent->xgraphicsexpose.width;
2444       event->expose.area.height = xevent->xgraphicsexpose.height;
2445       event->expose.count = xevent->xexpose.count;
2446
2447       return_val = window_private && !window_private->destroyed;
2448       break;
2449
2450     case NoExpose:
2451       /* Print debugging info.
2452        */
2453       GDK_NOTE (EVENTS,
2454         g_print ("no expose:\t\tdrawable: %ld\n",
2455                  xevent->xnoexpose.drawable - base_id));
2456
2457       event->no_expose.type = GDK_NO_EXPOSE;
2458       event->no_expose.window = window;
2459
2460       return_val = window_private && !window_private->destroyed;
2461       break;
2462
2463     case VisibilityNotify:
2464       /* Print debugging info.
2465        */
2466 #ifdef G_ENABLE_DEBUG
2467       if (gdk_debug_flags & GDK_DEBUG_EVENTS)
2468         switch (xevent->xvisibility.state)
2469           {
2470           case VisibilityFullyObscured:
2471             g_print ("visibility notify:\twindow: %ld  none\n",
2472                      xevent->xvisibility.window - base_id);
2473             break;
2474           case VisibilityPartiallyObscured:
2475             g_print ("visibility notify:\twindow: %ld  partial\n",
2476                      xevent->xvisibility.window - base_id);
2477             break;
2478           case VisibilityUnobscured:
2479             g_print ("visibility notify:\twindow: %ld  full\n",
2480                      xevent->xvisibility.window - base_id);
2481             break;
2482           }
2483 #endif /* G_ENABLE_DEBUG */
2484
2485       event->visibility.type = GDK_VISIBILITY_NOTIFY;
2486       event->visibility.window = window;
2487
2488       switch (xevent->xvisibility.state)
2489         {
2490         case VisibilityFullyObscured:
2491           event->visibility.state = GDK_VISIBILITY_FULLY_OBSCURED;
2492           break;
2493
2494         case VisibilityPartiallyObscured:
2495           event->visibility.state = GDK_VISIBILITY_PARTIAL;
2496           break;
2497
2498         case VisibilityUnobscured:
2499           event->visibility.state = GDK_VISIBILITY_UNOBSCURED;
2500           break;
2501         }
2502       
2503       return_val = window_private && !window_private->destroyed;
2504       break;
2505
2506     case CreateNotify:
2507       /* Not currently handled */
2508       break;
2509
2510     case DestroyNotify:
2511       /* Print debugging info.
2512        */
2513       GDK_NOTE (EVENTS,
2514         g_print ("destroy notify:\twindow: %ld\n",
2515                  xevent->xdestroywindow.window - base_id));
2516
2517       event->any.type = GDK_DESTROY;
2518       event->any.window = window;
2519
2520       return_val = window_private && !window_private->destroyed;
2521
2522       gdk_window_destroy_notify (window);
2523       break;
2524
2525     case UnmapNotify:
2526       /* Print debugging info.
2527        */
2528       GDK_NOTE (EVENTS,
2529         g_print ("unmap notify:\t\twindow: %ld\n",
2530                  xevent->xmap.window - base_id));
2531
2532       event->any.type = GDK_UNMAP;
2533       event->any.window = window;
2534
2535       if (xgrab_window == window_private)
2536         xgrab_window = NULL;
2537
2538       return_val = window_private && !window_private->destroyed;
2539       break;
2540
2541     case MapNotify:
2542       /* Print debugging info.
2543        */
2544       GDK_NOTE (EVENTS,
2545         g_print ("map notify:\t\twindow: %ld\n",
2546                  xevent->xmap.window - base_id));
2547
2548       event->any.type = GDK_MAP;
2549       event->any.window = window;
2550
2551       return_val = window_private && !window_private->destroyed;
2552       break;
2553
2554     case ReparentNotify:
2555       /* Print debugging info.
2556        */
2557       GDK_NOTE (EVENTS,
2558         g_print ("reparent notify:\twindow: %ld\n",
2559                  xevent->xreparent.window - base_id));
2560
2561       /* Not currently handled */
2562       break;
2563
2564     case ConfigureNotify:
2565       /* Print debugging info.
2566        */
2567       while ((XPending (gdk_display) > 0) &&
2568              XCheckTypedWindowEvent(gdk_display, xevent->xany.window,
2569                                     ConfigureNotify, xevent))
2570         {
2571           GdkFilterReturn result;
2572
2573           GDK_NOTE (EVENTS, 
2574                     g_print ("configure notify discarded:\twindow: %ld\n",
2575                              xevent->xconfigure.window - base_id));
2576
2577           result = gdk_event_apply_filters (xevent, event,
2578                                             window_private
2579                                             ?window_private->filters
2580                                             :gdk_default_filters);
2581
2582           /* If the result is GDK_FILTER_REMOVE, there will be
2583            * trouble, but anybody who filtering the Configure events
2584            * better know what they are doing
2585            */
2586           if (result != GDK_FILTER_CONTINUE)
2587             {
2588               return (result == GDK_FILTER_TRANSLATE) ? TRUE : FALSE;
2589             }
2590
2591             /*XSync (gdk_display, 0);*/
2592         }
2593
2594       
2595       GDK_NOTE (EVENTS,
2596         g_print ("configure notify:\twindow: %ld  x,y: %d %d  w,h: %d %d  b-w: %d  above: %ld  ovr: %d\n",
2597                  xevent->xconfigure.window - base_id,
2598                  xevent->xconfigure.x,
2599                  xevent->xconfigure.y,
2600                  xevent->xconfigure.width,
2601                  xevent->xconfigure.height,
2602                  xevent->xconfigure.border_width,
2603                  xevent->xconfigure.above - base_id,
2604                  xevent->xconfigure.override_redirect));
2605       
2606       if (window_private)
2607         {
2608           if ((window_private->extension_events != 0) &&
2609               gdk_input_vtable.configure_event)
2610             gdk_input_vtable.configure_event (&xevent->xconfigure, window);
2611           
2612           if (window_private->window_type != GDK_WINDOW_CHILD)
2613             {
2614               event->configure.type = GDK_CONFIGURE;
2615               event->configure.window = window;
2616               event->configure.width = xevent->xconfigure.width;
2617               event->configure.height = xevent->xconfigure.height;
2618               
2619               if (!xevent->xconfigure.x &&
2620                   !xevent->xconfigure.y &&
2621                   !window_private->destroyed)
2622                 {
2623                   gint tx = 0;
2624                   gint ty = 0;
2625                   Window child_window = 0;
2626
2627                   if (!XTranslateCoordinates (window_private->xdisplay,
2628                                               window_private->xwindow,
2629                                               gdk_root_window,
2630                                               0, 0,
2631                                               &tx, &ty,
2632                                               &child_window))
2633                     g_warning ("GdkWindow %ld doesn't share root windows display?",
2634                                window_private->xwindow - base_id);
2635                   event->configure.x = tx;
2636                   event->configure.y = ty;
2637                 }
2638               else
2639                 {
2640                   event->configure.x = xevent->xconfigure.x;
2641                   event->configure.y = xevent->xconfigure.y;
2642                 }
2643               window_private->x = event->configure.x;
2644               window_private->y = event->configure.y;
2645               window_private->width = xevent->xconfigure.width;
2646               window_private->height = xevent->xconfigure.height;
2647               if (window_private->resize_count > 1)
2648                 window_private->resize_count -= 1;
2649               
2650               return_val = !window_private->destroyed;
2651             }
2652         }
2653       break;
2654       
2655     case PropertyNotify:
2656       /* Print debugging info.
2657        */
2658       GDK_NOTE (EVENTS,
2659         g_print ("property notify:\twindow: %ld\n",
2660                  xevent->xproperty.window - base_id));
2661
2662       event->property.type = GDK_PROPERTY_NOTIFY;
2663       event->property.window = window;
2664       event->property.atom = xevent->xproperty.atom;
2665       event->property.time = xevent->xproperty.time;
2666       event->property.state = xevent->xproperty.state;
2667
2668       return_val = window_private && !window_private->destroyed;
2669       break;
2670
2671     case SelectionClear:
2672       GDK_NOTE (EVENTS,
2673         g_print ("selection clear:\twindow: %ld\n",
2674                  xevent->xproperty.window - base_id));
2675
2676       event->selection.type = GDK_SELECTION_CLEAR;
2677       event->selection.window = window;
2678       event->selection.selection = xevent->xselectionclear.selection;
2679       event->selection.time = xevent->xselectionclear.time;
2680
2681       return_val = window_private && !window_private->destroyed;
2682       break;
2683
2684     case SelectionRequest:
2685       GDK_NOTE (EVENTS,
2686         g_print ("selection request:\twindow: %ld\n",
2687                  xevent->xproperty.window - base_id));
2688
2689       event->selection.type = GDK_SELECTION_REQUEST;
2690       event->selection.window = window;
2691       event->selection.selection = xevent->xselectionrequest.selection;
2692       event->selection.target = xevent->xselectionrequest.target;
2693       event->selection.property = xevent->xselectionrequest.property;
2694       event->selection.requestor = xevent->xselectionrequest.requestor;
2695       event->selection.time = xevent->xselectionrequest.time;
2696
2697       return_val = window_private && !window_private->destroyed;
2698       break;
2699
2700     case SelectionNotify:
2701       GDK_NOTE (EVENTS,
2702         g_print ("selection notify:\twindow: %ld\n",
2703                  xevent->xproperty.window - base_id));
2704
2705
2706       event->selection.type = GDK_SELECTION_NOTIFY;
2707       event->selection.window = window;
2708       event->selection.selection = xevent->xselection.selection;
2709       event->selection.target = xevent->xselection.target;
2710       event->selection.property = xevent->xselection.property;
2711       event->selection.time = xevent->xselection.time;
2712
2713       return_val = window_private && !window_private->destroyed;
2714       break;
2715
2716     case ColormapNotify:
2717       /* Print debugging info.
2718        */
2719       GDK_NOTE (EVENTS,
2720         g_print ("colormap notify:\twindow: %ld\n",
2721                  xevent->xcolormap.window - base_id));
2722
2723       /* Not currently handled */
2724       break;
2725
2726     case ClientMessage:
2727       /* Print debugging info.
2728        */
2729       GDK_NOTE (EVENTS,
2730         g_print ("client message:\twindow: %ld\n",
2731                  xevent->xclient.window - base_id));
2732
2733       /* Client messages are the means of the window manager
2734        *  communicating with a program. We'll first check to
2735        *  see if this is really the window manager talking
2736        *  to us.
2737        */
2738       if (xevent->xclient.message_type == gdk_wm_protocols)
2739         {
2740           if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window)
2741             {
2742               /* The delete window request specifies a window
2743                *  to delete. We don't actually destroy the
2744                *  window because "it is only a request". (The
2745                *  window might contain vital data that the
2746                *  program does not want destroyed). Instead
2747                *  the event is passed along to the program,
2748                *  which should then destroy the window.
2749                */
2750
2751               /* Print debugging info.
2752                */
2753               GDK_NOTE (EVENTS,
2754                 g_print ("delete window:\t\twindow: %ld\n",
2755                          xevent->xclient.window - base_id));
2756
2757               event->any.type = GDK_DELETE;
2758               event->any.window = window;
2759
2760               return_val = window_private && !window_private->destroyed;
2761             }
2762           else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
2763             {
2764             }
2765         }
2766       else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter)
2767         {
2768           Atom reptype = 0;
2769
2770           event->dropenter.u.allflags = xevent->xclient.data.l[1];
2771
2772           GDK_NOTE (DND, g_print ("GDK_DROP_ENTER [%d][%d]\n",
2773                 window_private->dnd_drop_enabled, event->dropenter.u.flags.sendreply));
2774           return_val = FALSE;
2775
2776           /* Now figure out if we really want this drop...
2777            * If someone is trying funky clipboard stuff, ignore 
2778            */
2779           if (window_private
2780               && window_private->dnd_drop_enabled
2781               && event->dropenter.u.flags.sendreply
2782               && (reptype = gdk_dnd_check_types (window, xevent)))
2783             {
2784               XEvent replyev;
2785
2786               replyev.xclient.type = ClientMessage;
2787               replyev.xclient.window = xevent->xclient.data.l[0];
2788               replyev.xclient.format = 32;
2789               replyev.xclient.message_type = gdk_dnd.gdk_XdeRequest;
2790               replyev.xclient.data.l[0] = window_private->xwindow;
2791
2792               event->dragrequest.u.allflags = 0;
2793               event->dragrequest.u.flags.protocol_version =
2794                 DND_PROTOCOL_VERSION;
2795               event->dragrequest.u.flags.willaccept = 1;
2796               event->dragrequest.u.flags.delete_data =
2797                 (window_private->dnd_drop_destructive_op) ? 1 : 0;
2798
2799               replyev.xclient.data.l[1] = event->dragrequest.u.allflags;
2800               replyev.xclient.data.l[2] = replyev.xclient.data.l[3] = 0;
2801               replyev.xclient.data.l[4] = reptype;
2802
2803               if (!gdk_send_xevent (replyev.xclient.window, False, 
2804                                     NoEventMask, &replyev))
2805                 GDK_NOTE (DND, g_print("Sending XdeRequest to %#lx failed\n",
2806                                        replyev.xclient.window));
2807
2808               event->any.type = GDK_DROP_ENTER;
2809               event->any.window = window;
2810               event->dropenter.requestor = replyev.xclient.window;
2811               event->dropenter.u.allflags = xevent->xclient.data.l[1];
2812
2813               GDK_NOTE (DND, g_print("We sent a GDK_DROP_ENTER on to Gtk\n"));
2814               return_val = TRUE;
2815             }
2816         }
2817       else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeLeave)
2818         {
2819 #ifdef G_ENABLE_DEBUG     
2820           if (gdk_debug_flags & (GDK_DEBUG_EVENTS | GDK_DEBUG_DND))
2821             g_print ("GDK_DROP_LEAVE\n");
2822 #endif    
2823
2824           if (window_private && window_private->dnd_drop_enabled)
2825             {
2826               event->dropleave.type = GDK_DROP_LEAVE;
2827               event->dropleave.window = window;
2828               event->dropleave.requestor = xevent->xclient.data.l[0];
2829               event->dropleave.u.allflags = xevent->xclient.data.l[1];
2830               return_val = TRUE;
2831             }
2832           else
2833             return_val = FALSE;
2834         }
2835       else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeRequest)
2836         {
2837           /* 
2838            * make sure to only handle requests from the window the cursor is
2839            * over 
2840            */
2841 #ifdef G_ENABLE_DEBUG     
2842           if (gdk_debug_flags & (GDK_DEBUG_EVENTS | GDK_DEBUG_DND))
2843             g_print ("GDK_DRAG_REQUEST\n");
2844 #endif    
2845           event->dragrequest.u.allflags = xevent->xclient.data.l[1];
2846           return_val = FALSE;
2847
2848           if (window && gdk_dnd.drag_really &&
2849               xevent->xclient.data.l[0] == gdk_dnd.dnd_drag_curwin &&
2850               event->dragrequest.u.flags.sendreply == 0)
2851             {
2852               /* Got request - do we need to ask user? */
2853               if (!event->dragrequest.u.flags.willaccept
2854                   && event->dragrequest.u.flags.senddata)
2855                 {
2856                   /* Yes we do :) */
2857                   event->dragrequest.type = GDK_DRAG_REQUEST;
2858                   event->dragrequest.window = window;
2859                   event->dragrequest.requestor = xevent->xclient.data.l[0];
2860                   event->dragrequest.isdrop = 0;
2861                   event->dragrequest.drop_coords.x =
2862                     event->dragrequest.drop_coords.y = 0;
2863                   return_val = TRUE;
2864                 }
2865               else if (event->dragrequest.u.flags.willaccept)
2866                 {
2867                   window_private->dnd_drag_destructive_op =
2868                     event->dragrequest.u.flags.delete_data;
2869                   window_private->dnd_drag_accepted = 1;
2870                   window_private->dnd_drag_data_type =
2871                     xevent->xclient.data.l[4];
2872
2873                   gdk_dnd.dnd_drag_target = gdk_dnd.dnd_drag_curwin;
2874                   gdk_dnd_display_drag_cursor(-1, -1, TRUE, TRUE);
2875                 }
2876               gdk_dnd.dnd_drag_dropzone.x = xevent->xclient.data.l[2] & 65535;
2877               gdk_dnd.dnd_drag_dropzone.y =
2878                 (xevent->xclient.data.l[2] >> 16) & 65535;
2879               gdk_dnd.dnd_drag_dropzone.width = xevent->xclient.data.l[3] & 65535;
2880               gdk_dnd.dnd_drag_dropzone.height =
2881                 (xevent->xclient.data.l[3] >> 16) & 65535;
2882             }
2883         }
2884       else if(xevent->xclient.message_type == gdk_dnd.gdk_XdeDataAvailable)
2885           {
2886             gint tmp_int; Atom tmp_atom;
2887             gulong tmp_long;
2888             guchar *tmp_charptr;
2889
2890 #ifdef G_ENABLE_DEBUG     
2891           if (gdk_debug_flags & (GDK_DEBUG_EVENTS | GDK_DEBUG_DND))
2892             g_print("GDK_DROP_DATA_AVAIL\n");
2893 #endif    
2894             event->dropdataavailable.u.allflags = xevent->xclient.data.l[1];
2895             event->dropdataavailable.timestamp = xevent->xclient.data.l[4];
2896             event->dropdataavailable.coords.x =
2897                         xevent->xclient.data.l[3] & 0xffff;
2898             event->dropdataavailable.coords.y =
2899                         (xevent->xclient.data.l[3] >> 16) & 0xffff;
2900             if(window
2901                /* No preview of data ATM */
2902                && event->dropdataavailable.u.flags.isdrop)
2903               {
2904                 event->dropdataavailable.type = GDK_DROP_DATA_AVAIL;
2905                 event->dropdataavailable.window = window;
2906                 event->dropdataavailable.requestor = xevent->xclient.data.l[0];
2907                 event->dropdataavailable.data_type =
2908                         gdk_atom_name(xevent->xclient.data.l[2]);
2909                 if(XGetWindowProperty (gdk_display,
2910                                     event->dropdataavailable.requestor,
2911                                     xevent->xclient.data.l[2],
2912                                     0, LONG_MAX - 1,
2913                                     False, XA_PRIMARY, &tmp_atom,
2914                                     &tmp_int,
2915                                     &event->dropdataavailable.data_numbytes,
2916                                     &tmp_long,
2917                                     &tmp_charptr)
2918                    != Success)
2919                   {
2920                     g_warning("XGetWindowProperty on %#x may have failed\n",
2921                             event->dropdataavailable.requestor);
2922                             event->dropdataavailable.data = NULL;
2923                   }
2924                 else
2925                   {
2926                     GDK_NOTE (DND, g_print("XGetWindowProperty got us %ld bytes\n",
2927                             event->dropdataavailable.data_numbytes));
2928                     event->dropdataavailable.data =
2929                         g_malloc (event->dropdataavailable.data_numbytes);
2930                     memcpy (event->dropdataavailable.data,
2931                         tmp_charptr, event->dropdataavailable.data_numbytes);
2932                     XFree(tmp_charptr);
2933                     return_val = TRUE;
2934                   }
2935               return_val = TRUE;
2936             }
2937         }
2938       else
2939         {
2940           /* Send unknown ClientMessage's on to Gtk for it to use */
2941           event->client.type = GDK_CLIENT_EVENT;
2942           event->client.window = window;
2943           event->client.message_type = xevent->xclient.message_type;
2944           event->client.data_format = xevent->xclient.format;
2945           memcpy(&event->client.data, &xevent->xclient.data,
2946                  sizeof(event->client.data));
2947           if(window)
2948             return_val = TRUE;
2949           else  
2950             return_val = FALSE;
2951         }
2952       if(window_private)
2953         return_val = return_val && !window_private->destroyed;
2954       break;
2955       
2956     case MappingNotify:
2957       /* Print debugging info.
2958        */
2959       GDK_NOTE (EVENTS,
2960         g_print ("mapping notify\n"));
2961
2962       /* Let XLib know that there is a new keyboard mapping.
2963        */
2964       XRefreshKeyboardMapping (&xevent->xmapping);
2965       break;
2966
2967     default:
2968       /* something else - (e.g., a Xinput event) */
2969
2970       if (window_private &&
2971           (window_private->extension_events != 0) &&
2972           gdk_input_vtable.other_event)
2973         return_val = gdk_input_vtable.other_event(event, xevent, window);
2974       else
2975         return_val = FALSE;
2976
2977       return_val = return_val && !window_private->destroyed;
2978
2979       break;
2980     }
2981
2982   if (return_val)
2983     {
2984       if (event->any.window)
2985         gdk_window_ref (event->any.window);
2986       if (((event->any.type == GDK_ENTER_NOTIFY) ||
2987            (event->any.type == GDK_LEAVE_NOTIFY)) &&
2988           (event->crossing.subwindow != NULL))
2989         gdk_window_ref (event->crossing.subwindow);
2990     }
2991   else
2992     {
2993       /* Mark this event as having no resources to be freed */
2994       event->any.window = NULL;
2995       event->any.type = GDK_NOTHING;
2996     }
2997
2998   if (window)
2999     gdk_window_unref (window);
3000
3001   return return_val;
3002 }
3003
3004 #if 0
3005 static Bool
3006 gdk_event_get_type (Display  *display,
3007                     XEvent   *xevent,
3008                     XPointer  arg)
3009 {
3010   GdkEvent event;
3011   GdkPredicate *pred;
3012
3013   if (gdk_event_translate (&event, xevent))
3014     {
3015       pred = (GdkPredicate*) arg;
3016       return (* pred->func) (&event, pred->data);
3017     }
3018
3019   return FALSE;
3020 }
3021 #endif
3022
3023 static void
3024 gdk_synthesize_click (GdkEvent *event,
3025                       gint      nclicks)
3026 {
3027   GdkEvent temp_event;
3028
3029   g_return_if_fail (event != NULL);
3030
3031   temp_event = *event;
3032   temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
3033
3034   gdk_event_put (&temp_event);
3035 }
3036
3037 /*
3038  *--------------------------------------------------------------
3039  * gdk_exit_func
3040  *
3041  *   This is the "atexit" function that makes sure the
3042  *   library gets a chance to cleanup.
3043  *
3044  * Arguments:
3045  *
3046  * Results:
3047  *
3048  * Side effects:
3049  *   The library is un-initialized and the program exits.
3050  *
3051  *--------------------------------------------------------------
3052  */
3053
3054 static void
3055 gdk_exit_func (void)
3056 {
3057   static gboolean in_gdk_exit_func = FALSE;
3058
3059   /* This is to avoid an infinite loop if a program segfaults in
3060      an atexit() handler (and yes, it does happen, especially if a program
3061      has trounced over memory too badly for even g_print to work) */
3062   if(in_gdk_exit_func == TRUE) return;
3063   in_gdk_exit_func = TRUE;
3064
3065   if (initialized)
3066     {
3067 #ifdef USE_XIM
3068       /* cleanup IC */
3069       gdk_ic_cleanup ();
3070       /* close IM */
3071       gdk_im_close ();
3072 #endif
3073       gdk_image_exit ();
3074       gdk_input_exit ();
3075       gdk_key_repeat_restore ();
3076
3077       XCloseDisplay (gdk_display);
3078       initialized = 0;
3079     }
3080 }
3081
3082 /*
3083  *--------------------------------------------------------------
3084  * gdk_x_error
3085  *
3086  *   The X error handling routine.
3087  *
3088  * Arguments:
3089  *   "display" is the X display the error orignated from.
3090  *   "error" is the XErrorEvent that we are handling.
3091  *
3092  * Results:
3093  *   Either we were expecting some sort of error to occur,
3094  *   in which case we set the "gdk_error_code" flag, or this
3095  *   error was unexpected, in which case we will print an
3096  *   error message and exit. (Since trying to continue will
3097  *   most likely simply lead to more errors).
3098  *
3099  * Side effects:
3100  *
3101  *--------------------------------------------------------------
3102  */
3103
3104 static int
3105 gdk_x_error (Display     *display,
3106              XErrorEvent *error)
3107 {
3108   char buf[64];
3109
3110   if (gdk_error_warnings)
3111     {
3112       XGetErrorText (display, error->error_code, buf, 63);
3113       g_error ("%s\n  serial %ld error_code %d request_code %d minor_code %d\n", 
3114                buf, 
3115                error->serial, 
3116                error->error_code, 
3117                error->request_code,
3118                error->minor_code);
3119     }
3120
3121   gdk_error_code = -1;
3122   return 0;
3123 }
3124
3125 /*
3126  *--------------------------------------------------------------
3127  * gdk_x_io_error
3128  *
3129  *   The X I/O error handling routine.
3130  *
3131  * Arguments:
3132  *   "display" is the X display the error orignated from.
3133  *
3134  * Results:
3135  *   An X I/O error basically means we lost our connection
3136  *   to the X server. There is not much we can do to
3137  *   continue, so simply print an error message and exit.
3138  *
3139  * Side effects:
3140  *
3141  *--------------------------------------------------------------
3142  */
3143
3144 static int
3145 gdk_x_io_error (Display *display)
3146 {
3147   g_error ("an x io error occurred");
3148   return 0;
3149 }
3150
3151 /*
3152  *--------------------------------------------------------------
3153  * gdk_signal
3154  *
3155  *   The signal handler.
3156  *
3157  * Arguments:
3158  *   "sig_num" is the number of the signal we received.
3159  *
3160  * Results:
3161  *   The signals we catch are all fatal. So we simply build
3162  *   up a nice little error message and print it and exit.
3163  *   If in the process of doing so another signal is received
3164  *   we notice that we are already exiting and simply kill
3165  *   our process.
3166  *
3167  * Side effects:
3168  *
3169  *--------------------------------------------------------------
3170  */
3171
3172 static RETSIGTYPE
3173 gdk_signal (int sig_num)
3174 {
3175   static int caught_fatal_sig = 0;
3176   char *sig;
3177
3178   if (caught_fatal_sig)
3179     kill (getpid (), sig_num);
3180   caught_fatal_sig = 1;
3181
3182   switch (sig_num)
3183     {
3184     case SIGHUP:
3185       sig = "sighup";
3186       break;
3187     case SIGINT:
3188       sig = "sigint";
3189       break;
3190     case SIGQUIT:
3191       sig = "sigquit";
3192       break;
3193     case SIGBUS:
3194       sig = "sigbus";
3195       break;
3196     case SIGSEGV:
3197       sig = "sigsegv";
3198       break;
3199     case SIGPIPE:
3200       sig = "sigpipe";
3201       break;
3202     case SIGTERM:
3203       sig = "sigterm";
3204       break;
3205     default:
3206       sig = "unknown signal";
3207       break;
3208     }
3209
3210   g_print ("\n** ERROR **: %s caught\n", sig);
3211 #ifdef G_ENABLE_DEBUG
3212   abort ();
3213 #else /* !G_ENABLE_DEBUG */
3214   gdk_exit (1);
3215 #endif /* !G_ENABLE_DEBUG */
3216 }
3217
3218 static void
3219 gdk_dnd_drag_begin (GdkWindow *initial_window)
3220 {
3221   GdkEvent tev;
3222
3223   GDK_NOTE(DND, g_print("------- STARTING DRAG from %p\n", initial_window));
3224
3225   tev.type = GDK_DRAG_BEGIN;
3226   tev.dragbegin.window = initial_window;
3227   tev.dragbegin.u.allflags = 0;
3228   tev.dragbegin.u.flags.protocol_version = DND_PROTOCOL_VERSION;
3229
3230   gdk_event_put (&tev);
3231 }
3232
3233 static void
3234 gdk_dnd_drag_enter (Window dest)
3235 {
3236   XEvent sev;
3237   GdkEventDropEnter tev;
3238   int i;
3239   GdkWindowPrivate *wp;
3240   
3241   sev.xclient.type = ClientMessage;
3242   sev.xclient.format = 32;
3243   sev.xclient.message_type = gdk_dnd.gdk_XdeEnter;
3244   sev.xclient.window = dest;
3245
3246   tev.u.allflags = 0;
3247   tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
3248   tev.u.flags.sendreply = 1;
3249   for (i = 0; i < gdk_dnd.drag_numwindows; i++)
3250     {
3251       wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i];
3252       if (wp->dnd_drag_data_numtypesavail)
3253         {
3254           sev.xclient.data.l[0] = wp->xwindow;
3255           tev.u.flags.extended_typelist = (wp->dnd_drag_data_numtypesavail > 3)?1:0;
3256           sev.xclient.data.l[1] = tev.u.allflags;
3257           sev.xclient.data.l[2] = wp->dnd_drag_data_typesavail[0];
3258           if (wp->dnd_drag_data_numtypesavail > 1)
3259             {
3260               sev.xclient.data.l[3] = wp->dnd_drag_data_typesavail[1];
3261               if (wp->dnd_drag_data_numtypesavail > 2)
3262                 {
3263                   sev.xclient.data.l[4] = wp->dnd_drag_data_typesavail[2];
3264                 }
3265               else
3266                 sev.xclient.data.l[4] = None;
3267             }
3268           else
3269             sev.xclient.data.l[3] = sev.xclient.data.l[4] = None;
3270           if (!gdk_send_xevent (dest, False, StructureNotifyMask, &sev))
3271                 GDK_NOTE (DND, g_print("Sending XdeEnter to %#lx failed\n",
3272                                        dest));
3273         }
3274
3275     }
3276 }
3277
3278
3279 #ifdef USE_XIM
3280
3281 /* The following routines duplicate functionality in Xlib to
3282  * translate from varargs to X's internal opaque XVaNestedList.
3283  * 
3284  * If all vendors have stuck close to the reference implementation,
3285  * then we should hopefully be OK. 
3286  */
3287
3288 /* This needs to match XIMArg as defined in Xlcint.h exactly */
3289   
3290 typedef struct {
3291   gchar   *name;
3292   gpointer value;
3293 } GdkImArg;
3294
3295 /*************************************************************
3296  * gdk_im_va_count:
3297  *    Counts the number of name/value pairs in the vararg list
3298  *
3299  *   arguments:
3300  *     
3301  *   results:
3302  *************************************************************/
3303
3304 static guint 
3305 gdk_im_va_count (va_list list)
3306 {
3307   gint count = 0;
3308   gchar *name;
3309
3310   name = va_arg (list, gchar *);
3311   while (name)
3312     {
3313       count++;
3314       (void)va_arg (list, gpointer);
3315       name = va_arg (list, gchar *);
3316     }
3317
3318   return count;
3319 }
3320
3321 /*************************************************************
3322  * gdk_im_va_to_nested:
3323  *     Given a varargs list and the result of gdk_im_va_count,
3324  *     create a XVaNestedList.
3325  *
3326  *   arguments:
3327  *     
3328  *   results:
3329  *************************************************************/
3330
3331 static XVaNestedList
3332 gdk_im_va_to_nested (va_list list, guint count)
3333 {
3334   GdkImArg *result;
3335   GdkImArg *arg;
3336
3337   gchar *name;
3338
3339   if (count == 0)
3340     return NULL;
3341
3342   result = g_new (GdkImArg, count+1);
3343   arg = result;
3344
3345   name = va_arg (list, gchar *);
3346   while (name)
3347     {
3348       arg->name = name;
3349       arg->value = va_arg (list, gpointer);
3350       arg++;
3351       name = va_arg (list, gchar *);
3352     }
3353
3354   arg->name = NULL;
3355
3356   return (XVaNestedList)result;
3357 }
3358
3359 /*
3360  *--------------------------------------------------------------
3361  * gdk_im_begin
3362  *
3363  *   Begin using input method with XIM Protocol(X11R6 standard)
3364  *
3365  * Arguments:
3366  *   "ic" is the "Input Context" which is created by gtk_ic_new.
3367  *   The input area is specified with "window".
3368  *
3369  * Results:
3370  *   The gdk's event handling routine is switched to XIM based routine.
3371  *   XIM based routine uses XFilterEvent to get rid of events used by IM,
3372  *   and uses XmbLookupString instead of XLookupString.
3373  *
3374  * Side effects:
3375  *
3376  *--------------------------------------------------------------
3377  */
3378
3379 void 
3380 gdk_im_begin (GdkIC ic, GdkWindow* window)
3381 {
3382   GdkICPrivate *private;
3383   Window xwin;
3384
3385   g_return_if_fail (ic != NULL);
3386   g_return_if_fail (window);
3387
3388   private = (GdkICPrivate *) ic;
3389
3390   xim_using = TRUE;
3391   xim_ic = private;
3392   xim_window = window;
3393   if (gdk_im_ready())
3394     {
3395       XGetICValues (private->xic, XNFocusWindow, &xwin, NULL);
3396       if (xwin != GDK_WINDOW_XWINDOW(window))
3397         XSetICValues (private->xic, XNFocusWindow, 
3398                       GDK_WINDOW_XWINDOW(window), NULL);
3399       if (private != xim_ic)
3400         XSetICFocus (private->xic);
3401     }
3402 }
3403
3404 /*
3405  *--------------------------------------------------------------
3406  * gdk_im_end
3407  *
3408  *   End using input method with XIM Protocol(X11R6 standard)
3409  *
3410  * Arguments:
3411  *
3412  * Results:
3413  *   The gdk's event handling routine is switched to normal routine.
3414  *   User should call this function before ic and window will be destroyed.
3415  *
3416  * Side effects:
3417  *
3418  *--------------------------------------------------------------
3419  */
3420
3421 void 
3422 gdk_im_end (void)
3423 {
3424   xim_using = FALSE;
3425   xim_ic = NULL;
3426   xim_window = NULL;
3427 }
3428
3429 static GdkIM 
3430 gdk_im_get (void)
3431 {
3432   return xim_im;
3433 }
3434
3435 static GdkIMStyle 
3436 gdk_im_choose_better_style (GdkIMStyle style1, GdkIMStyle style2) 
3437 {
3438   GdkIMStyle s1, s2, u;
3439
3440   if (style1 == 0) return style2;
3441   if (style2 == 0) return style1;
3442   if ((style1 & (GdkIMPreeditMask | GdkIMStatusMask))
3443         == (style2 & (GdkIMPreeditMask | GdkIMStatusMask)))
3444     return style1;
3445
3446   s1 = style1 & GdkIMPreeditMask;
3447   s2 = style2 & GdkIMPreeditMask;
3448   u = s1 | s2;
3449   if (s1 != s2) {
3450     if (u & GdkIMPreeditCallbacks)
3451       return (s1 == GdkIMPreeditCallbacks)? style1:style2;
3452     else if (u & GdkIMPreeditPosition)
3453       return (s1 == GdkIMPreeditPosition)? style1:style2;
3454     else if (u & GdkIMPreeditArea)
3455       return (s1 == GdkIMPreeditArea)? style1:style2;
3456     else if (u & GdkIMPreeditNothing)
3457       return (s1 == GdkIMPreeditNothing)? style1:style2;
3458   } else {
3459     s1 = style1 & GdkIMStatusMask;
3460     s2 = style2 & GdkIMStatusMask;
3461     u = s1 | s2;
3462     if ( u & GdkIMStatusCallbacks)
3463       return (s1 == GdkIMStatusCallbacks)? style1:style2;
3464     else if ( u & GdkIMStatusArea)
3465       return (s1 == GdkIMStatusArea)? style1:style2;
3466     else if ( u & GdkIMStatusNothing)
3467       return (s1 == GdkIMStatusNothing)? style1:style2;
3468     else if ( u & GdkIMStatusNone)
3469       return (s1 == GdkIMStatusNone)? style1:style2;
3470   }
3471   return 0; /* Get rid of stupid warning */
3472 }
3473
3474 GdkIMStyle
3475 gdk_im_decide_style (GdkIMStyle supported_style)
3476 {
3477   gint i;
3478   GdkIMStyle style, tmp;
3479
3480   g_return_val_if_fail (xim_styles != NULL, 0);
3481
3482   style = 0;
3483   for (i=0; i<xim_styles->count_styles; i++)
3484     {
3485       tmp = xim_styles->supported_styles[i];
3486       if (tmp == (tmp & supported_style & xim_best_allowed_style))
3487         style = gdk_im_choose_better_style (style, tmp);
3488     }
3489   return style;
3490 }
3491
3492 GdkIMStyle
3493 gdk_im_set_best_style (GdkIMStyle style)
3494 {
3495   if (style & GdkIMPreeditMask)
3496     {
3497       xim_best_allowed_style &= ~GdkIMPreeditMask;
3498
3499       xim_best_allowed_style |= GdkIMPreeditNone;
3500       if (!(style & GdkIMPreeditNone))
3501         {
3502           xim_best_allowed_style |= GdkIMPreeditNothing;
3503           if (!(style & GdkIMPreeditNothing))
3504             {
3505               xim_best_allowed_style |= GdkIMPreeditArea;
3506               if (!(style & GdkIMPreeditArea))
3507                 {
3508                   xim_best_allowed_style |= GdkIMPreeditPosition;
3509                   if (!(style & GdkIMPreeditPosition))
3510                     xim_best_allowed_style |= GdkIMPreeditCallbacks;
3511                 }
3512             }
3513         }
3514     }
3515   if (style & GdkIMStatusMask)
3516     {
3517       xim_best_allowed_style &= ~GdkIMStatusMask;
3518
3519       xim_best_allowed_style |= GdkIMStatusNone;
3520       if (!(style & GdkIMStatusNone))
3521         {
3522           xim_best_allowed_style |= GdkIMStatusNothing;
3523           if (!(style & GdkIMStatusNothing))
3524             {
3525               xim_best_allowed_style |= GdkIMStatusArea;
3526               if (!(style & GdkIMStatusArea))
3527                 xim_best_allowed_style |= GdkIMStatusCallbacks;
3528             }
3529         }
3530     }
3531   
3532   return xim_best_allowed_style;
3533 }
3534
3535 static gint 
3536 gdk_im_open (XrmDatabase db, gchar* res_name, gchar* res_class)
3537 {
3538   xim_im = XOpenIM (GDK_DISPLAY(), db, res_name, res_class);
3539   if (xim_im == NULL)
3540     {
3541       GDK_NOTE (XIM, g_warning ("Unable to open open IM."));
3542       return FALSE;
3543     }
3544   XGetIMValues (xim_im, XNQueryInputStyle, &xim_styles, NULL, NULL);
3545
3546   return TRUE;
3547 }
3548
3549 static void 
3550 gdk_im_close (void)
3551 {
3552   if (xim_im)
3553     {
3554       XCloseIM (xim_im);
3555       xim_im = NULL;
3556     }
3557   if (xim_styles)
3558     {
3559       XFree (xim_styles);
3560       xim_styles = NULL;
3561     }
3562 }
3563
3564 gint 
3565 gdk_im_ready (void)
3566 {
3567   return (xim_im != NULL);
3568 }
3569
3570 GdkIC 
3571 gdk_ic_new (GdkWindow* client_window,
3572             GdkWindow* focus_window,
3573             GdkIMStyle style, ...)
3574 {
3575   va_list list;
3576   GdkICPrivate *private;
3577   XVaNestedList preedit_attr = NULL;
3578   guint count;
3579
3580   g_return_val_if_fail (client_window != NULL, NULL);
3581   g_return_val_if_fail (focus_window != NULL, NULL);
3582   g_return_val_if_fail (gdk_im_ready(), NULL);
3583
3584   private = g_new (GdkICPrivate, 1);
3585
3586   va_start (list, style);
3587   count = gdk_im_va_count (list);
3588   va_end (list);
3589
3590   va_start (list, style);
3591   preedit_attr = gdk_im_va_to_nested (list, count);
3592   va_end (list);
3593   
3594   private->style = gdk_im_decide_style (style);
3595   if (private->style != style)
3596     {
3597       g_warning ("can not create input context with specified input style.");
3598       g_free (private);
3599       return NULL;
3600     }
3601
3602   private->xic = XCreateIC(gdk_im_get (),
3603                         XNInputStyle,   style,
3604                         XNClientWindow, GDK_WINDOW_XWINDOW (client_window),
3605                         XNFocusWindow,  GDK_WINDOW_XWINDOW (focus_window),
3606                         preedit_attr? XNPreeditAttributes : NULL, preedit_attr,
3607                         NULL);
3608
3609   g_free (preedit_attr);
3610   
3611   if (!private->xic)
3612     {
3613       g_free (private);
3614       return NULL;
3615     }
3616
3617   xim_ic_list = g_list_append (xim_ic_list, private);
3618   return private;
3619 }
3620
3621 void 
3622 gdk_ic_destroy (GdkIC ic)
3623 {
3624   GdkICPrivate *private;
3625
3626   g_return_if_fail (ic != NULL);
3627   
3628   private = (GdkICPrivate *) ic;
3629
3630   if (xim_ic == private)
3631     gdk_im_end ();
3632
3633   XDestroyIC (private->xic);
3634   xim_ic_list = g_list_remove (xim_ic_list, private);
3635   g_free (private);
3636 }
3637
3638 GdkIMStyle
3639 gdk_ic_get_style (GdkIC ic)
3640 {
3641   GdkICPrivate *private;
3642
3643   g_return_val_if_fail (ic != NULL, 0);
3644
3645   private = (GdkICPrivate *) ic;
3646
3647   return private->style;
3648 }
3649
3650 void 
3651 gdk_ic_set_values (GdkIC ic, ...)
3652 {
3653   va_list list;
3654   XVaNestedList args;
3655   GdkICPrivate *private;
3656   guint count;
3657
3658   g_return_if_fail (ic != NULL);
3659
3660   private = (GdkICPrivate *) ic;
3661
3662   va_start (list, ic);
3663   count = gdk_im_va_count (list);
3664   va_end (list);
3665
3666   va_start (list, ic);
3667   args = gdk_im_va_to_nested (list, count);
3668   va_end (list);
3669
3670   XSetICValues (private->xic, XNVaNestedList, args, NULL);
3671
3672   g_free (args);
3673 }
3674
3675 void 
3676 gdk_ic_get_values (GdkIC ic, ...)
3677 {
3678   va_list list;
3679   XVaNestedList args;
3680   GdkICPrivate *private;
3681   guint count;
3682
3683   g_return_if_fail (ic != NULL);
3684
3685   private = (GdkICPrivate *) ic;
3686
3687   va_start (list, ic);
3688   count = gdk_im_va_count (list);
3689   va_end (list);
3690
3691   va_start (list, ic);
3692   args = gdk_im_va_to_nested (list, count);
3693   va_end (list);
3694
3695   XGetICValues (private->xic, XNVaNestedList, args, NULL);
3696
3697   g_free (args);
3698 }
3699
3700 void 
3701 gdk_ic_set_attr (GdkIC ic, const char *target, ...)
3702 {
3703   va_list list;
3704   XVaNestedList attr;
3705   GdkICPrivate *private;
3706   guint count;
3707
3708   g_return_if_fail (ic != NULL);
3709   g_return_if_fail (target != NULL);
3710
3711   private = (GdkICPrivate *) ic;
3712
3713   va_start (list, target);
3714   count = gdk_im_va_count (list);
3715   va_end (list);
3716
3717   va_start (list, target);
3718   attr = gdk_im_va_to_nested (list, count);
3719   va_end (list);
3720
3721   XSetICValues (private->xic, target, attr, NULL);
3722
3723   g_free (attr);
3724 }
3725
3726 void 
3727 gdk_ic_get_attr (GdkIC ic, const char *target, ...)
3728 {
3729   va_list list;
3730   XVaNestedList attr;
3731   GdkICPrivate *private;
3732   guint count;
3733
3734   g_return_if_fail (ic != NULL);
3735   g_return_if_fail (target != NULL);
3736
3737   private = (GdkICPrivate *) ic;
3738
3739   va_start (list, target);
3740   count = gdk_im_va_count (list);
3741   va_end (list);
3742
3743   va_start (list, target);
3744   attr = gdk_im_va_to_nested (list, count);
3745   va_end (list);
3746
3747   XGetICValues (private->xic, target, attr, NULL);
3748
3749   g_free (attr);
3750 }
3751
3752 GdkEventMask 
3753 gdk_ic_get_events (GdkIC ic)
3754 {
3755   GdkEventMask mask;
3756   glong xmask;
3757   glong bit;
3758   GdkICPrivate *private;
3759   gint i;
3760
3761   /*  From gdkwindow.c  */
3762   extern int nevent_masks;
3763   extern int event_mask_table[];
3764
3765   g_return_val_if_fail (ic != NULL, 0);
3766
3767   private = (GdkICPrivate *) ic;
3768
3769   if (XGetICValues (private->xic, XNFilterEvents, &xmask, NULL) != NULL)
3770     {
3771       GDK_NOTE (XIM, g_warning ("Call to XGetICValues: %s failed", XNFilterEvents));
3772       return 0;
3773     }
3774
3775   mask = 0;
3776   for (i=0, bit=2; i < nevent_masks; i++, bit <<= 1)
3777     if (xmask & event_mask_table [i])
3778       {
3779         mask |= bit;
3780         xmask &= ~ event_mask_table [i];
3781       }
3782
3783   if (xmask)
3784     g_warning ("ic requires events not supported by the application (%#04lx)", xmask);
3785   
3786   return mask;
3787 }
3788
3789 static void 
3790 gdk_ic_cleanup (void)
3791 {
3792   GList* node;
3793   gint destroyed;
3794   GdkICPrivate *private;
3795
3796   destroyed = 0;
3797   for (node = xim_ic_list; node != NULL; node = node->next)
3798     {
3799       if (node->data)
3800        {
3801          private = (GdkICPrivate *) (node->data);
3802          XDestroyIC (private->xic);
3803          g_free (private);
3804          destroyed++;
3805        }
3806     }
3807 #ifdef G_ENABLE_DEBUG
3808   if ((gdk_debug_flags & GDK_DEBUG_XIM) && destroyed > 0)
3809     {
3810       g_warning ("Cleaned up %i IC(s)\n", destroyed);
3811     }
3812 #endif /* G_ENABLE_DEBUG */
3813   g_list_free(xim_ic_list);
3814   xim_ic_list = NULL;
3815 }
3816
3817 #else /* !USE_XIM */
3818
3819 void 
3820 gdk_im_begin (GdkIC ic, GdkWindow* window)
3821 {
3822 }
3823
3824 void 
3825 gdk_im_end (void)
3826 {
3827 }
3828
3829 GdkIMStyle
3830 gdk_im_decide_style (GdkIMStyle supported_style)
3831 {
3832   return GdkIMPreeditNone | GdkIMStatusNone;
3833 }
3834
3835 GdkIMStyle
3836 gdk_im_set_best_style (GdkIMStyle style)
3837 {
3838   return GdkIMPreeditNone | GdkIMStatusNone;
3839 }
3840
3841 gint 
3842 gdk_im_ready (void)
3843 {
3844   return FALSE;
3845 }
3846
3847 GdkIC 
3848 gdk_ic_new (GdkWindow* client_window,
3849             GdkWindow* focus_window,
3850             GdkIMStyle style, ...)
3851 {
3852   return NULL;
3853 }
3854
3855 void 
3856 gdk_ic_destroy (GdkIC ic)
3857 {
3858 }
3859
3860 GdkIMStyle
3861 gdk_ic_get_style (GdkIC ic)
3862 {
3863   return GdkIMPreeditNone | GdkIMStatusNone;
3864 }
3865
3866 void 
3867 gdk_ic_set_values (GdkIC ic, ...)
3868 {
3869 }
3870
3871 void 
3872 gdk_ic_get_values (GdkIC ic, ...)
3873 {
3874 }
3875
3876 void 
3877 gdk_ic_set_attr (GdkIC ic, const char *target, ...)
3878 {
3879 }
3880
3881 void 
3882 gdk_ic_get_attr (GdkIC ic, const char *target, ...)
3883 {
3884 }
3885
3886 GdkEventMask 
3887 gdk_ic_get_events (GdkIC ic)
3888 {
3889   return 0;
3890 }
3891
3892 #endif /* USE_XIM */
3893
3894 #ifdef X_LOCALE
3895
3896 gint
3897 _g_mbtowc (wchar_t *wstr, const char *str, size_t len)
3898 {
3899   static wchar_t wcs[MB_CUR_MAX + 1];
3900   static gchar mbs[MB_CUR_MAX + 1];
3901
3902   wcs[0] = (wchar_t) NULL;
3903   mbs[0] = '\0';
3904
3905   /* The last argument isn't a mistake. The X locale code trims
3906    *  the input string to the length of the output string!
3907    */
3908   len = _Xmbstowcs (wcs, str, (len<MB_CUR_MAX)? len:MB_CUR_MAX);
3909   if (len < 1)
3910     return len;
3911   else if (wcs[0] == (wchar_t) NULL)
3912     return -1;
3913
3914   len = _Xwctomb (mbs, wcs[0]);
3915   if (mbs[0] == '\0')
3916     return -1;
3917   if (wstr)
3918     *wstr = wcs[0];
3919
3920   return len;
3921 }
3922
3923 #endif /* X_LOCALE */
3924
3925 static void
3926 gdk_dnd_drag_leave (Window dest)
3927 {
3928   XEvent sev;
3929   GdkEventDropLeave tev;
3930   int i;
3931   GdkWindowPrivate *wp;
3932
3933   tev.u.allflags = 0;
3934
3935   tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
3936   sev.xclient.type = ClientMessage;
3937   sev.xclient.window = dest;
3938   sev.xclient.format = 32;
3939   sev.xclient.message_type = gdk_dnd.gdk_XdeLeave;
3940   sev.xclient.data.l[1] = tev.u.allflags;
3941   for (i = 0; i < gdk_dnd.drag_numwindows; i++)
3942     {
3943       wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i];
3944       sev.xclient.data.l[0] = wp->xwindow;
3945       if (!gdk_send_xevent (dest, False, StructureNotifyMask, &sev))
3946         GDK_NOTE (DND, g_print("Sending XdeLeave to %#lx failed\n",
3947                                dest));
3948       wp->dnd_drag_accepted = 0;
3949     }
3950 }
3951
3952 /* 
3953  * when a drop occurs, we go through the list of windows being dragged and
3954  * tell them that it has occurred, so that they can set things up and reply
3955  * to 'dest' window 
3956  */
3957 static void
3958 gdk_dnd_drag_end (Window     dest, 
3959                   GdkPoint   coords)
3960 {
3961   GdkWindowPrivate *wp;
3962   GdkEvent tev;
3963   int i;
3964
3965   tev.dragrequest.type = GDK_DRAG_REQUEST;
3966   tev.dragrequest.drop_coords = coords;
3967   tev.dragrequest.requestor = dest;
3968   tev.dragrequest.u.allflags = 0;
3969   tev.dragrequest.u.flags.protocol_version = DND_PROTOCOL_VERSION;
3970   tev.dragrequest.isdrop = 1;
3971
3972   for (i = 0; i < gdk_dnd.drag_numwindows; i++)
3973     {
3974       wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i];
3975       if (wp->dnd_drag_accepted)
3976         {
3977           tev.dragrequest.window = (GdkWindow *) wp;
3978           tev.dragrequest.u.flags.delete_data = wp->dnd_drag_destructive_op;
3979           tev.dragrequest.timestamp = gdk_dnd.last_drop_time;
3980           tev.dragrequest.data_type = 
3981                 gdk_atom_name(wp->dnd_drag_data_type);
3982
3983           gdk_event_put(&tev);
3984         }
3985     }
3986 }
3987
3988 static GdkAtom
3989 gdk_dnd_check_types (GdkWindow   *window, 
3990                      XEvent      *xevent)
3991 {
3992   GdkWindowPrivate *wp = (GdkWindowPrivate *) window;
3993   int i, j;
3994   GdkEventDropEnter event;
3995
3996   g_return_val_if_fail(window != NULL, 0);
3997   g_return_val_if_fail(xevent != NULL, 0);
3998   g_return_val_if_fail(xevent->type == ClientMessage, 0);
3999   g_return_val_if_fail(xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter, 0);
4000
4001   if(wp->dnd_drop_data_numtypesavail <= 0 ||
4002      !wp->dnd_drop_data_typesavail)
4003     return 0;
4004
4005   for (i = 2; i <= 4; i++)
4006     {
4007       for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++)
4008         {
4009           if (xevent->xclient.data.l[i] == wp->dnd_drop_data_typesavail[j])
4010             return xevent->xclient.data.l[i];
4011         }
4012     }
4013
4014   /* Now we get the extended type list if it's available */
4015   event.u.allflags = xevent->xclient.data.l[1];
4016   if (event.u.flags.extended_typelist)
4017     {
4018       Atom *exttypes, realtype;
4019       gulong nitems, nbar;
4020       gint realfmt;
4021
4022       if (XGetWindowProperty(gdk_display, xevent->xclient.data.l[0],
4023                              gdk_dnd.gdk_XdeTypelist, 0L, LONG_MAX - 1,
4024                              False, AnyPropertyType, &realtype, &realfmt,
4025                              &nitems, &nbar, (unsigned char **) &exttypes)
4026          != Success)
4027         return 0;
4028
4029       if (realfmt != (sizeof(Atom) * 8))
4030         {
4031           g_warning("XdeTypelist property had format of %d instead of the expected %ld, on window %#lx\n",
4032                     realfmt, (glong)sizeof(Atom) * 8, xevent->xclient.data.l[0]);
4033           return 0;
4034         }
4035
4036       for (i = 0; i <= nitems; i++)
4037         {
4038           for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++)
4039             {
4040               if (exttypes[i] == wp->dnd_drop_data_typesavail[j])
4041                 {
4042                   XFree (exttypes);
4043                   return exttypes[i];
4044                 }
4045             }
4046         }
4047       XFree (exttypes);
4048     }
4049   return 0;
4050 }
4051
4052 /* 
4053  * used for debugging only 
4054  */
4055 #ifdef DEBUG_DND
4056 static void
4057 gdk_print_atom (GdkAtom anatom)
4058 {
4059   gchar *tmpstr = NULL;
4060   tmpstr = (anatom!=None)?gdk_atom_name(anatom):"(none)";
4061   g_print("Atom %lu has name %s\n", anatom, tmpstr);
4062   if(tmpstr)
4063     g_free(tmpstr);
4064 }
4065 #endif
4066
4067 /* 
4068  * used only by below routine and itself 
4069  */
4070 static Window 
4071 getchildren (Display     *dpy, 
4072              Window       win, 
4073              Atom         WM_STATE)
4074 {
4075   Window root, parent, *children, inf = 0;
4076   Atom type = None;
4077   unsigned int nchildren, i;
4078   int format;
4079   unsigned long nitems, after;
4080   unsigned char *data;
4081
4082   if (XQueryTree(dpy, win, &root, &parent, &children, &nchildren) == 0)
4083     return 0;
4084
4085   for (i = 0; !inf && (i < nchildren); i++)
4086     {
4087       XGetWindowProperty (dpy, children[i], WM_STATE, 0, 0, False,
4088                           AnyPropertyType, &type, &format, &nitems,
4089                           &after, &data);
4090       if (type != 0)
4091         inf = children[i];
4092       XFree(data);
4093     }
4094
4095   for (i = 0; !inf && (i < nchildren); i++)
4096     inf = getchildren (dpy, children[i], WM_STATE);
4097
4098   if (children != None)
4099     XFree ((char *) children);
4100
4101   return inf;
4102 }
4103
4104 /* 
4105  * find a window with WM_STATE, else return win itself, as per ICCCM
4106  *
4107  * modification of the XmuClientWindow() routine from X11R6.3
4108  */
4109 Window
4110 gdk_get_client_window (Display  *dpy, 
4111                        Window    win)
4112 {
4113   Atom WM_STATE;
4114   Atom type = None;
4115   int format;
4116   unsigned long nitems, after;
4117   unsigned char *data;
4118   Window inf;
4119
4120   if (win == 0)
4121     return DefaultRootWindow(dpy);
4122
4123   if ((WM_STATE = XInternAtom (dpy, "WM_STATE", True)) == 0)
4124     return win;
4125
4126   XGetWindowProperty (dpy, win, WM_STATE, 0, 0, False, AnyPropertyType,
4127                       &type, &format, &nitems, &after, &data);
4128   if (type)
4129     return win;
4130
4131   inf = getchildren (dpy, win, WM_STATE);
4132
4133   if (inf == 0)
4134     return win;
4135   else
4136     return inf;
4137 }
4138
4139 #ifdef WE_HAVE_MOTIF_DROPS_DONE
4140 static GdkWindow *
4141 gdk_drop_get_real_window (GdkWindow   *w, 
4142                           guint16     *x, 
4143                           guint16     *y)
4144 {
4145   GdkWindow *retval = w;
4146   GdkWindowPrivate *awin;
4147   GList *children;
4148   gint16 myx = *x, myy = *y;
4149
4150   g_return_val_if_fail(w != NULL && x != NULL && y != NULL, NULL);
4151
4152   myx = *x; 
4153   myy = *y;
4154
4155 descend:
4156   for (children = gdk_window_get_children(retval); 
4157        children && children->next;
4158        children = children->next)
4159     {
4160       awin = (GdkWindowPrivate *) children->data;
4161       if ((myx >= awin->x) && (myy >= awin->y)
4162           && (myx < (awin->x + awin->width))
4163           && (myy < (awin->y + awin->height)))
4164         {
4165           retval = (GdkWindow *) awin;
4166           myx -= awin->x;
4167           myy -= awin->y;
4168           goto descend;
4169         }
4170     }
4171
4172   *x = myx; 
4173   *y = myy;
4174
4175   return retval;
4176 }
4177 #endif
4178
4179 /* Sends a ClientMessage to all toplevel client windows */
4180 void
4181 gdk_event_send_clientmessage_toall(GdkEvent *event)
4182 {
4183   XEvent sev;
4184   Window *ret_children, ret_root, ret_parent, curwin;
4185   unsigned int ret_nchildren;
4186   int i;
4187
4188   g_return_if_fail(event != NULL);
4189
4190   /* Set up our event to send, with the exception of its target window */
4191   sev.xclient.type = ClientMessage;
4192   sev.xclient.display = gdk_display;
4193   sev.xclient.format = event->client.data_format;
4194   sev.xclient.serial = CurrentTime;
4195   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
4196   sev.xclient.message_type = event->client.message_type;
4197
4198   /* OK, we're all set, now let's find some windows to send this to */
4199   if(XQueryTree(gdk_display, gdk_root_window, &ret_root, &ret_parent,
4200                 &ret_children, &ret_nchildren) != True)
4201     return;
4202
4203   /* foreach true child window of the root window, send an event to it */
4204   for(i = 0; i < ret_nchildren; i++) {
4205     curwin = gdk_get_client_window(gdk_display, ret_children[i]);
4206     sev.xclient.window = curwin;
4207     if (!gdk_send_xevent (curwin, False, NoEventMask, &sev))
4208       GDK_NOTE (MISC, g_print("Gdk: Sending client message %ld to %#lx failed\n",
4209                              event->client.message_type, curwin));
4210   }
4211
4212   XFree(ret_children);
4213 }
4214
4215 gchar *
4216 gdk_get_display(void)
4217 {
4218   return (gchar *)XDisplayName (gdk_display_name);
4219 }
4220
4221 gint 
4222 gdk_send_xevent (Window window, gboolean propagate, glong event_mask,
4223                  XEvent *event_send)
4224 {
4225   Status result;
4226   
4227   gdk_error_code = 0;
4228   
4229   gdk_error_warnings = 0;
4230   result = XSendEvent (gdk_display, window, propagate, event_mask, event_send);
4231   XSync (gdk_display, False);
4232   gdk_error_warnings = 1;
4233     
4234   return result && (gdk_error_code != -1);
4235 }