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