]> Pileus Git - ~andy/gtk/blob - gdk/gdk.c
Initial revision
[~andy/gtk] / gdk / gdk.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 #include "../config.h"
19
20 #include <ctype.h>
21 #include <locale.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <limits.h>
27
28 #ifdef HAVE_SYS_SELECT_H
29 #include <sys/select.h>
30 #endif /* HAVE_SYS_SELECT_H_ */
31
32 #define XLIB_ILLEGAL_ACCESS
33 #include <X11/Xatom.h>
34 #include <X11/Xlib.h>
35 #include <X11/Xos.h>
36 #include <X11/Xutil.h>
37 #include <X11/Xmu/WinUtil.h>
38 #include <X11/cursorfont.h>
39 #include "gdk.h"
40 #include "gdkprivate.h"
41 #include "gdkinput.h"
42
43
44 #ifndef X_GETTIMEOFDAY
45 #define X_GETTIMEOFDAY(tv)  gettimeofday (tv, NULL)
46 #endif /* X_GETTIMEOFDAY */
47
48
49 #define DOUBLE_CLICK_TIME      250
50 #define TRIPLE_CLICK_TIME      500
51 #define DOUBLE_CLICK_DIST      5
52 #define TRIPLE_CLICK_DIST      5
53
54
55 #ifndef NO_FD_SET
56 #  define SELECT_MASK fd_set
57 #else
58 #  ifndef _AIX
59      typedef long fd_mask;
60 #  endif
61 #  if defined(_IBMR2)
62 #    define SELECT_MASK void
63 #  else
64 #    define SELECT_MASK int
65 #  endif
66 #endif
67
68
69 typedef struct _GdkInput      GdkInput;
70 typedef struct _GdkPredicate  GdkPredicate;
71
72 struct _GdkInput
73 {
74   gint tag;
75   gint source;
76   GdkInputCondition condition;
77   GdkInputFunction function;
78   gpointer data;
79 };
80
81 struct _GdkPredicate
82 {
83   GdkEventFunc func;
84   gpointer data;
85 };
86
87 /* 
88  * Private function declarations
89  */
90 static gint      gdk_event_wait         (void);
91 static gint      gdk_event_translate    (GdkEvent     *event, 
92                                          XEvent       *xevent);
93 static Bool      gdk_event_get_type     (Display      *display, 
94                                          XEvent       *xevent, 
95                                          XPointer      arg);
96 static void      gdk_synthesize_click   (GdkEvent     *event, 
97                                          gint          nclicks);
98
99 static void      gdk_dnd_drag_begin     (GdkWindow    *initial_window);
100 static void      gdk_dnd_drag_enter     (Window        dest);
101 static void      gdk_dnd_drag_leave     (Window        dest);
102 static void      gdk_dnd_drag_end       (Window        dest, 
103                                          GdkPoint      coords);
104 static GdkAtom   gdk_dnd_check_types    (GdkWindow    *window,
105                                          XEvent       *xevent);
106 static void      gdk_print_atom         (GdkAtom       anatom);
107
108 /* 
109  * old junk from offix, we might use it though so leave it 
110  */
111 static Window       gdk_drop_get_client_window   (Display     *dpy, 
112                                                   Window       win);
113 static GdkWindow *  gdk_drop_get_real_window     (GdkWindow   *w, 
114                                                   guint16     *x,
115                                                   guint16     *y);
116 static void         gdk_exit_func                (void);
117 static int          gdk_x_error                  (Display     *display, 
118                                                   XErrorEvent *error);
119 static int          gdk_x_io_error               (Display     *display);
120 static RETSIGTYPE   gdk_signal                   (int          signum);
121
122
123 /* Private variable declarations
124  */
125 static int initialized = 0;                         /* 1 if the library is initialized,
126                                                      * 0 otherwise.
127                                                      */
128 static int connection_number = 0;                   /* The file descriptor number of our
129                                                      *  connection to the X server. This
130                                                      *  is used so that we may determine
131                                                      *  when events are pending by using
132                                                      *  the "select" system call.
133                                                      */
134
135 static gint received_destroy_notify = FALSE;        /* Did we just receive a destroy notify
136                                                      *  event? If so, we need to actually
137                                                      *  destroy the window which received
138                                                      *  it now.
139                                                      */
140 static GdkWindow *window_to_destroy = NULL;         /* If we previously received a destroy
141                                                      *  notify event then this is the window
142                                                      *  which received that event.
143                                                      */
144
145 static struct timeval start;                        /* The time at which the library was
146                                                      *  last initialized.
147                                                      */
148 static struct timeval timer;                        /* Timeout interval to use in the call
149                                                      *  to "select". This is used in
150                                                      *  conjunction with "timerp" to create
151                                                      *  a maximum time to wait for an event
152                                                      *  to arrive.
153                                                      */
154 static struct timeval *timerp;                      /* The actual timer passed to "select"
155                                                      *  This may be NULL, in which case
156                                                      *  "select" will block until an event
157                                                      *  arrives.
158                                                      */
159 static guint32 timer_val;                           /* The timeout length as specified by
160                                                      *  the user in milliseconds.
161                                                      */
162 static GList *inputs;                               /* A list of the input file descriptors
163                                                      *  that we care about. Each list node
164                                                      *  contains a GdkInput struct that describes
165                                                      *  when we are interested in the specified
166                                                      *  file descriptor. That is, when it is
167                                                      *  available for read, write or has an
168                                                      *  exception pending.
169                                                      */
170 static guint32 button_click_time[2];                /* The last 2 button click times. Used
171                                                      *  to determine if the latest button click
172                                                      *  is part of a double or triple click.
173                                                      */
174 static GdkWindow *button_window[2];                 /* The last 2 windows to receive button presses.
175                                                      *  Also used to determine if the latest button
176                                                      *  click is part of a double or triple click.
177                                                      */
178 static guint button_number[2];                      /* The last 2 buttons to be pressed.
179                                                      */
180
181 #define OTHER_XEVENT_BUFSIZE 4
182 static XEvent other_xevent[OTHER_XEVENT_BUFSIZE];   /* XEvents passed along to user  */
183 static int other_xevent_i = 0;
184 static GList *putback_events = NULL;
185
186 static gulong base_id;
187 static gint autorepeat;
188
189
190 /*
191  *--------------------------------------------------------------
192  * gdk_init
193  *
194  *   Initialize the library for use.
195  *
196  * Arguments:
197  *   "argc" is the number of arguments.
198  *   "argv" is an array of strings.
199  *
200  * Results:
201  *   "argc" and "argv" are modified to reflect any arguments
202  *   which were not handled. (Such arguments should either
203  *   be handled by the application or dismissed).
204  *
205  * Side effects:
206  *   The library is initialized.
207  *
208  *--------------------------------------------------------------
209  */
210
211 void
212 gdk_init (int    *argc,
213           char ***argv)
214 {
215   XKeyboardState keyboard_state;
216   int synchronize;
217   int i, j, k;
218   XClassHint *class_hint;
219   int argc_orig = *argc;
220   char **argv_orig;
221
222   argv_orig = malloc ((argc_orig + 1) * sizeof (char*));
223   for (i = 0; i < argc_orig; i++)
224     argv_orig[i] = g_strdup ((*argv)[i]);
225   argv_orig[argc_orig] = NULL;
226
227   X_GETTIMEOFDAY (&start);
228
229   signal (SIGHUP, gdk_signal);
230   signal (SIGINT, gdk_signal);
231   signal (SIGQUIT, gdk_signal);
232   signal (SIGBUS, gdk_signal);
233   signal (SIGSEGV, gdk_signal);
234   signal (SIGPIPE, gdk_signal);
235   signal (SIGTERM, gdk_signal);
236
237   gdk_display_name = NULL;
238
239   XSetErrorHandler (gdk_x_error);
240   XSetIOErrorHandler (gdk_x_io_error);
241
242   synchronize = FALSE;
243
244   if (argc && argv)
245     {
246       if (*argc > 0)
247         gdk_progname = (*argv)[0];
248
249       for (i = 1; i < *argc;)
250         {
251           if (strcmp ("--display", (*argv)[i]) == 0)
252             {
253               (*argv)[i] = NULL;
254
255               if ((i + 1) < *argc)
256                 {
257                   gdk_display_name = g_strdup ((*argv)[i + 1]);
258                   (*argv)[i + 1] = NULL;
259                   i += 1;
260                 }
261             }
262           else if (strcmp ("--sync", (*argv)[i]) == 0)
263             {
264               (*argv)[i] = NULL;
265               synchronize = TRUE;
266             }
267           else if (strcmp ("--show-events", (*argv)[i]) == 0)
268             {
269               (*argv)[i] = NULL;
270               gdk_show_events = TRUE;
271             }
272           else if (strcmp ("--no-show-events", (*argv)[i]) == 0)
273             {
274               (*argv)[i] = NULL;
275               gdk_show_events = FALSE;
276             }
277           else if (strcmp ("--no-xshm", (*argv)[i]) == 0)
278             {
279               (*argv)[i] = NULL;
280               gdk_use_xshm = FALSE;
281             }
282           else if (strcmp ("--debug-level", (*argv)[i]) == 0)
283             {
284               if ((i + 1) < *argc)
285                 {
286                   (*argv)[i++] = NULL;
287                   gdk_debug_level = atoi ((*argv)[i]);
288                   (*argv)[i] = NULL;
289                 }
290             }
291           else if (strcmp ("-name", (*argv)[i]) == 0)
292             {
293               if ((i + 1) < *argc)
294                 {
295                   (*argv)[i++] = NULL;
296                   gdk_progname = (*argv)[i];
297                   (*argv)[i] = NULL;
298                 }
299             }
300           else if (strcmp ("-class", (*argv)[i]) == 0)
301             {
302               if ((i + 1) < *argc)
303                 {
304                   (*argv)[i++] = NULL;
305                   gdk_progclass = (*argv)[i];
306                   (*argv)[i] = NULL;
307                 }
308             }
309 #ifdef XINPUT_GXI
310           else if (strcmp ("--gxid_host", (*argv)[i]) == 0)
311             {
312               if ((i + 1) < *argc)
313                 {
314                   (*argv)[i++] = NULL;
315                   gdk_input_gxid_host = ((*argv)[i]);
316                   (*argv)[i] = NULL;
317                 }
318             }
319           else if (strcmp ("--gxid_port", (*argv)[i]) == 0)
320             {
321               if ((i + 1) < *argc)
322                 {
323                   (*argv)[i++] = NULL;
324                   gdk_input_gxid_port = atoi ((*argv)[i]);
325                   (*argv)[i] = NULL;
326                 }
327             }
328 #endif
329           i += 1;
330         }
331
332       for (i = 1; i < *argc; i++)
333         {
334           for (k = i; k < *argc; k++)
335             if ((*argv)[k] != NULL)
336               break;
337
338           if (k > i)
339             {
340               k -= i;
341               for (j = i + k; j < *argc; j++)
342                 (*argv)[j-k] = (*argv)[j];
343               *argc -= k;
344             }
345         }
346     }
347   else
348     {
349       gdk_progname = "<unknown>";
350     }
351
352   gdk_display = XOpenDisplay (gdk_display_name);
353   if (!gdk_display)
354     g_error ("cannot open display: %s", XDisplayName (gdk_display_name));
355
356   /* This is really crappy. We have to look into the display structure
357    *  to find the base resource id. This is only needed for recording
358    *  and playback of events.
359    */
360   /* base_id = RESOURCE_BASE; */
361   base_id = 0;
362   if (gdk_show_events)
363     g_print ("base id: %lu\n", base_id);
364
365   connection_number = ConnectionNumber (gdk_display);
366   if (gdk_debug_level >= 1)
367     g_print ("connection number: %d\n", connection_number);
368
369   if (synchronize)
370     XSynchronize (gdk_display, True);
371
372   gdk_screen = DefaultScreen (gdk_display);
373   gdk_root_window = RootWindow (gdk_display, gdk_screen);
374
375   gdk_leader_window = XCreateSimpleWindow(gdk_display, gdk_root_window,
376                                           10, 10, 10, 10, 0, 0 , 0);
377   class_hint = XAllocClassHint();
378   class_hint->res_name = gdk_progname;
379   class_hint->res_class = gdk_progclass;
380   XSetClassHint(gdk_display, gdk_leader_window, class_hint);
381   XSetCommand(gdk_display, gdk_leader_window, argv_orig, argc_orig);
382   XFree (class_hint);
383
384   gdk_wm_delete_window = XInternAtom (gdk_display, "WM_DELETE_WINDOW", True);
385   gdk_wm_take_focus = XInternAtom (gdk_display, "WM_TAKE_FOCUS", True);
386   gdk_wm_protocols = XInternAtom (gdk_display, "WM_PROTOCOLS", True);
387   gdk_wm_window_protocols[0] = gdk_wm_delete_window;
388   gdk_wm_window_protocols[1] = gdk_wm_take_focus;
389   gdk_selection_property = XInternAtom (gdk_display, "GDK_SELECTION", False);
390
391   gdk_dnd.gdk_XdeEnter = gdk_atom_intern("_XDE_ENTER", FALSE);
392   gdk_dnd.gdk_XdeLeave = gdk_atom_intern("_XDE_LEAVE", FALSE);
393   gdk_dnd.gdk_XdeRequest = gdk_atom_intern("_XDE_REQUEST", FALSE);
394   gdk_dnd.gdk_XdeDataAvailable = gdk_atom_intern("_XDE_DATA_AVAILABLE", FALSE);
395   gdk_dnd.gdk_XdeTypelist = gdk_atom_intern("_XDE_TYPELIST", FALSE);
396   gdk_dnd.gdk_cursor_dragdefault = XCreateFontCursor(gdk_display, XC_bogosity);
397   gdk_dnd.gdk_cursor_dragok = XCreateFontCursor(gdk_display, XC_heart);
398
399   XGetKeyboardControl (gdk_display, &keyboard_state);
400   autorepeat = keyboard_state.global_auto_repeat;
401
402   timer.tv_sec = 0;
403   timer.tv_usec = 0;
404   timerp = NULL;
405
406   button_click_time[0] = 0;
407   button_click_time[1] = 0;
408   button_window[0] = NULL;
409   button_window[1] = NULL;
410   button_number[0] = -1;
411   button_number[1] = -1;
412
413   if (ATEXIT (gdk_exit_func))
414     g_warning ("unable to register exit function");
415
416   gdk_visual_init ();
417   gdk_window_init ();
418   gdk_image_init ();
419   gdk_input_init ();
420
421   initialized = 1;
422 }
423
424 /*
425  *--------------------------------------------------------------
426  * gdk_exit
427  *
428  *   Restores the library to an un-itialized state and exits
429  *   the program using the "exit" system call.
430  *
431  * Arguments:
432  *   "errorcode" is the error value to pass to "exit".
433  *
434  * Results:
435  *   Allocated structures are freed and the program exits
436  *   cleanly.
437  *
438  * Side effects:
439  *
440  *--------------------------------------------------------------
441  */
442
443 void
444 gdk_exit (int errorcode)
445 {
446  /* de-initialisation is done by the gdk_exit_funct(),
447     no need to do this here (Alex J.) */
448  exit (errorcode);
449 }
450
451 /*
452  *--------------------------------------------------------------
453  * gdk_set_locale
454  *
455  * Arguments:
456  *
457  * Results:
458  *
459  * Side effects:
460  *
461  *--------------------------------------------------------------
462  */
463
464 gchar*
465 gdk_set_locale ()
466 {
467   if (!setlocale (LC_ALL,""))
468     g_print ("locale not supported by C library\n");
469
470   if (!XSupportsLocale ())
471     {
472       g_print ("locale not supported by Xlib, locale set to C\n");
473       setlocale (LC_ALL, "C");
474     }
475
476   if (!XSetLocaleModifiers (""))
477     {
478       g_print ("can not set locale modifiers\n");
479     }
480
481   return setlocale (LC_ALL,NULL);
482 }
483
484 /*
485  *--------------------------------------------------------------
486  * gdk_events_pending
487  *
488  *   Returns the number of events pending on the queue.
489  *   These events have already been read from the server
490  *   connection.
491  *
492  * Arguments:
493  *
494  * Results:
495  *   Returns the number of events on XLib's event queue.
496  *
497  * Side effects:
498  *
499  *--------------------------------------------------------------
500  */
501
502 gint
503 gdk_events_pending ()
504 {
505   return XPending (gdk_display);
506 }
507
508 /*
509  *--------------------------------------------------------------
510  * gdk_event_get
511  *
512  *   Gets the next event.
513  *
514  * Arguments:
515  *   "event" is used to hold the received event.
516  *   If "event" is NULL an event is received as normal
517  *   however it is not placed in "event" (and thus no
518  *   error occurs).
519  *
520  * Results:
521  *   Returns TRUE if an event was received that we care about
522  *   and FALSE otherwise. This function will also return
523  *   before an event is received if the timeout interval
524  *   runs out.
525  *
526  * Side effects:
527  *
528  *--------------------------------------------------------------
529  */
530
531 gint
532 gdk_event_get (GdkEvent     *event,
533                GdkEventFunc  pred,
534                gpointer      data)
535 {
536   GdkEvent *temp_event;
537   GdkPredicate event_pred;
538   GList *temp_list;
539   XEvent xevent;
540
541   /* If the last event we received was a destroy notify
542    *  event then we will actually destroy the "gdk" data
543    *  structures now. We don't want to destroy them at the
544    *  time of receiving the event since the main program
545    *  may try to access them and may need to destroy user
546    *  data that has been attached to the window
547    */
548   if (received_destroy_notify)
549     {
550       if (gdk_show_events)
551         g_print ("destroying window:\twindow: %ld\n",
552                  ((GdkWindowPrivate*) window_to_destroy)->xwindow - base_id);
553
554       gdk_window_real_destroy (window_to_destroy);
555       received_destroy_notify = FALSE;
556       window_to_destroy = NULL;
557     }
558
559   /* Initially we haven't received an event and want to
560    *  return FALSE. If "event" is non-NULL, then initialize
561    *  it to the nothing event.
562    */
563   if (event)
564     {
565       event->any.type = GDK_NOTHING;
566       event->any.window = NULL;
567       event->any.send_event = FALSE;
568     }
569
570   if (pred)
571     {
572       temp_list = putback_events;
573       while (temp_list)
574         {
575           temp_event = temp_list->data;
576
577           if ((* pred) (temp_event, data))
578             {
579               if (event)
580                 *event = *temp_event;
581               putback_events = g_list_remove_link (putback_events, temp_list);
582               g_list_free (temp_list);
583               return TRUE;
584             }
585
586           temp_list = temp_list->next;
587         }
588
589       event_pred.func = pred;
590       event_pred.data = data;
591
592       if (XCheckIfEvent (gdk_display, &xevent, gdk_event_get_type, (XPointer) &event_pred))
593         if (event)
594           return gdk_event_translate (event, &xevent);
595     }
596   else
597     {
598       if (putback_events)
599         {
600           temp_event = putback_events->data;
601           *event = *temp_event;
602
603           temp_list = putback_events;
604           putback_events = putback_events->next;
605           if (putback_events)
606             putback_events->prev = NULL;
607
608           temp_list->next = NULL;
609           temp_list->prev = NULL;
610           g_list_free (temp_list);
611           g_free (temp_event);
612
613           return TRUE;
614         }
615
616       /* Wait for an event to occur or the timeout to elapse.
617        * If an event occurs "gdk_event_wait" will return TRUE.
618        *  If the timeout elapses "gdk_event_wait" will return
619        *  FALSE.
620        */
621       if (gdk_event_wait ())
622         {
623           /* If we get here we can rest assurred that an event
624            *  has occurred. Read it.
625            */
626           XNextEvent (gdk_display, &xevent);
627
628           event->any.send_event = xevent.xany.send_event;
629
630           /* If "event" non-NULL.
631            */
632           if (event)
633             return gdk_event_translate (event, &xevent);
634         }
635     }
636
637   return FALSE;
638 }
639
640 void
641 gdk_event_put (GdkEvent *event)
642 {
643   GdkEvent *new_event;
644
645   g_return_if_fail (event != NULL);
646
647   new_event = g_new (GdkEvent, 1);
648   *new_event = *event;
649
650   putback_events = g_list_prepend (putback_events, new_event);
651 }
652
653 /*
654  *--------------------------------------------------------------
655  * gdk_event_copy
656  *
657  *   Copy a event structure into new storage.
658  *
659  * Arguments:
660  *   "event" is the event struct to copy.
661  *
662  * Results:
663  *   A new event structure.  Free it with gdk_event_free.
664  *
665  * Side effects:
666  *   The reference count of the window in the event is increased.
667  *
668  *--------------------------------------------------------------
669  */
670
671 static GMemChunk *event_chunk;
672
673 GdkEvent*
674 gdk_event_copy (GdkEvent *event)
675 {
676   GdkEvent *new_event;
677   
678   g_return_val_if_fail (event != NULL, NULL);
679
680   if (event_chunk == NULL)
681     event_chunk = g_mem_chunk_new ("events",
682                                    sizeof (GdkEvent),
683                                    4096,
684                                    G_ALLOC_AND_FREE);
685
686   new_event = g_chunk_new (GdkEvent, event_chunk);
687   *new_event = *event;
688   gdk_window_ref (new_event->any.window);
689   return new_event;
690 }
691
692 /*
693  *--------------------------------------------------------------
694  * gdk_event_free
695  *
696  *   Free a event structure obtained from gdk_event_copy.  Do not use
697  *   with other event structures.
698  *
699  * Arguments:
700  *   "event" is the event struct to free.
701  *
702  * Results:
703  *
704  * Side effects:
705  *   The reference count of the window in the event is decreased and
706  *   might be freed, too.
707  *
708  *-------------------------------------------------------------- */
709
710 void
711 gdk_event_free (GdkEvent *event)
712 {
713   g_assert (event_chunk != NULL);
714   g_return_if_fail (event != NULL);
715
716   gdk_window_unref (event->any.window);
717   g_mem_chunk_free (event_chunk, event);
718 }
719
720 /*
721  *--------------------------------------------------------------
722  * gdk_set_debug_level
723  *
724  *   Sets the debugging level.
725  *
726  * Arguments:
727  *   "level" is the new debugging level.
728  *
729  * Results:
730  *
731  * Side effects:
732  *   Other function calls to "gdk" use the debugging
733  *   level to determine what kind of debugging information
734  *   to print out.
735  *
736  *--------------------------------------------------------------
737  */
738
739 void
740 gdk_set_debug_level (int level)
741 {
742   gdk_debug_level = level;
743 }
744
745 /*
746  *--------------------------------------------------------------
747  * gdk_set_show_events
748  *
749  *   Turns on/off the showing of events.
750  *
751  * Arguments:
752  *   "show_events" is a boolean describing whether or
753  *   not to show the events gdk receives.
754  *
755  * Results:
756  *
757  * Side effects:
758  *   When "show_events" is TRUE, calls to "gdk_event_get"
759  *   will output debugging informatin regarding the event
760  *   received to stdout.
761  *
762  *--------------------------------------------------------------
763  */
764
765 void
766 gdk_set_show_events (int show_events)
767 {
768   gdk_show_events = show_events;
769 }
770
771 void
772 gdk_set_use_xshm (gint use_xshm)
773 {
774   gdk_use_xshm = use_xshm;
775 }
776
777 gint
778 gdk_get_debug_level ()
779 {
780   return gdk_debug_level;
781 }
782
783 gint
784 gdk_get_show_events ()
785 {
786   return gdk_show_events;
787 }
788
789 gint
790 gdk_get_use_xshm ()
791 {
792   return gdk_use_xshm;
793 }
794
795 /*
796  *--------------------------------------------------------------
797  * gdk_time_get
798  *
799  *   Get the number of milliseconds since the library was
800  *   initialized.
801  *
802  * Arguments:
803  *
804  * Results:
805  *   The time since the library was initialized is returned.
806  *   This time value is accurate to milliseconds even though
807  *   a more accurate time down to the microsecond could be
808  *   returned.
809  *
810  * Side effects:
811  *
812  *--------------------------------------------------------------
813  */
814
815 guint32
816 gdk_time_get ()
817 {
818   struct timeval end;
819   struct timeval elapsed;
820   guint32 milliseconds;
821
822   X_GETTIMEOFDAY (&end);
823
824   if (start.tv_usec > end.tv_usec)
825     {
826       end.tv_usec += 1000000;
827       end.tv_sec--;
828     }
829   elapsed.tv_sec = end.tv_sec - start.tv_sec;
830   elapsed.tv_usec = end.tv_usec - start.tv_usec;
831
832   milliseconds = (elapsed.tv_sec * 1000) + (elapsed.tv_usec / 1000);
833
834   return milliseconds;
835 }
836
837 /*
838  *--------------------------------------------------------------
839  * gdk_timer_get
840  *
841  *   Returns the current timer.
842  *
843  * Arguments:
844  *
845  * Results:
846  *   Returns the current timer interval. This interval is
847  *   in units of milliseconds.
848  *
849  * Side effects:
850  *
851  *--------------------------------------------------------------
852  */
853
854 guint32
855 gdk_timer_get ()
856 {
857   return timer_val;
858 }
859
860 /*
861  *--------------------------------------------------------------
862  * gdk_timer_set
863  *
864  *   Sets the timer interval.
865  *
866  * Arguments:
867  *   "milliseconds" is the new value for the timer.
868  *
869  * Results:
870  *
871  * Side effects:
872  *   Calls to "gdk_event_get" will last for a maximum
873  *   of time of "milliseconds". However, a value of 0
874  *   milliseconds will cause "gdk_event_get" to block
875  *   indefinately until an event is received.
876  *
877  *--------------------------------------------------------------
878  */
879
880 void
881 gdk_timer_set (guint32 milliseconds)
882 {
883   timer_val = milliseconds;
884   timer.tv_sec = milliseconds / 1000;
885   timer.tv_usec = (milliseconds % 1000) * 1000;
886
887 }
888
889 void
890 gdk_timer_enable ()
891 {
892   timerp = &timer;
893 }
894
895 void
896 gdk_timer_disable ()
897 {
898   timerp = NULL;
899 }
900
901 gint
902 gdk_input_add (gint              source,
903                GdkInputCondition condition,
904                GdkInputFunction  function,
905                gpointer          data)
906 {
907   static gint next_tag = 1;
908   GList *list;
909   GdkInput *input;
910   gint tag;
911
912   tag = 0;
913   list = inputs;
914
915   while (list)
916     {
917       input = list->data;
918       list = list->next;
919
920       if ((input->source == source) && (input->condition == condition))
921         {
922           input->function = function;
923           input->data = data;
924           tag = input->tag;
925         }
926     }
927
928   if (!tag)
929     {
930       input = g_new (GdkInput, 1);
931       input->tag = next_tag++;
932       input->source = source;
933       input->condition = condition;
934       input->function = function;
935       input->data = data;
936       tag = input->tag;
937
938       inputs = g_list_prepend (inputs, input);
939     }
940
941   return tag;
942 }
943
944 void
945 gdk_input_remove (gint tag)
946 {
947   GList *list;
948   GList *temp_list;
949   GdkInput *input;
950
951   list = inputs;
952   while (list)
953     {
954       input = list->data;
955
956       if (input->tag == tag)
957         {
958           temp_list = list;
959
960           if (list->next)
961             list->next->prev = list->prev;
962           if (list->prev)
963             list->prev->next = list->next;
964           if (inputs == list)
965             inputs = list->next;
966
967           temp_list->next = NULL;
968           temp_list->prev = NULL;
969
970           g_free (temp_list->data);
971           g_list_free (temp_list);
972           break;
973         }
974
975       list = list->next;
976     }
977 }
978
979 /*
980  *--------------------------------------------------------------
981  * gdk_pointer_grab
982  *
983  *   Grabs the pointer to a specific window
984  *
985  * Arguments:
986  *   "window" is the window which will receive the grab
987  *   "owner_events" specifies whether events will be reported as is,
988  *     or relative to "window"
989  *   "event_mask" masks only interesting events
990  *   "confine_to" limits the cursor movement to the specified window
991  *   "cursor" changes the cursor for the duration of the grab
992  *   "time" specifies the time
993  *
994  * Results:
995  *
996  * Side effects:
997  *   requires a corresponding call to gdk_pointer_ungrab
998  *
999  *--------------------------------------------------------------
1000  */
1001
1002 gint
1003 gdk_pointer_grab (GdkWindow *     window,
1004                   gint            owner_events,
1005                   GdkEventMask    event_mask,
1006                   GdkWindow *     confine_to,
1007                   GdkCursor *     cursor,
1008                   guint32         time)
1009 {
1010   /*  From gdkwindow.c  */
1011   extern int nevent_masks;
1012   extern int event_mask_table[];
1013
1014   gint return_val;
1015   GdkWindowPrivate *window_private;
1016   GdkWindowPrivate *confine_to_private;
1017   GdkCursorPrivate *cursor_private;
1018   guint xevent_mask;
1019   Window xwindow;
1020   Window xconfine_to;
1021   Cursor xcursor;
1022   int i;
1023
1024   g_return_val_if_fail (window != NULL, 0);
1025
1026   window_private = (GdkWindowPrivate*) window;
1027   confine_to_private = (GdkWindowPrivate*) confine_to;
1028   cursor_private = (GdkCursorPrivate*) cursor;
1029
1030   xwindow = window_private->xwindow;
1031
1032   if (!confine_to)
1033     xconfine_to = None;
1034   else
1035     xconfine_to = confine_to_private->xwindow;
1036
1037   if (!cursor)
1038     xcursor = None;
1039   else
1040     xcursor = cursor_private->xcursor;
1041
1042
1043   xevent_mask = 0;
1044   for (i = 0; i < nevent_masks; i++)
1045     {
1046       if (event_mask & (1 << (i + 1)))
1047         xevent_mask |= event_mask_table[i];
1048     }
1049
1050   if (((GdkWindowPrivate *)window)->extension_events &&
1051       gdk_input_vtable.grab_pointer)
1052     return_val = gdk_input_vtable.grab_pointer (window,
1053                                                 owner_events,
1054                                                 event_mask,
1055                                                 confine_to,
1056                                                 time);
1057   else
1058     return_val = Success;;
1059
1060   if (return_val == Success)
1061     return_val = XGrabPointer (window_private->xdisplay,
1062                                xwindow,
1063                                owner_events,
1064                                xevent_mask,
1065                                GrabModeAsync, GrabModeAsync,
1066                                xconfine_to,
1067                                xcursor,
1068                                time);
1069
1070   return return_val;
1071 }
1072
1073 /*
1074  *--------------------------------------------------------------
1075  * gdk_pointer_ungrab
1076  *
1077  *   Releases any pointer grab
1078  *
1079  * Arguments:
1080  *
1081  * Results:
1082  *
1083  * Side effects:
1084  *
1085  *--------------------------------------------------------------
1086  */
1087
1088 void
1089 gdk_pointer_ungrab (guint32 time)
1090 {
1091   if (gdk_input_vtable.ungrab_pointer)
1092     gdk_input_vtable.ungrab_pointer (time);
1093
1094   XUngrabPointer (gdk_display, time);
1095 }
1096
1097 /*
1098  *--------------------------------------------------------------
1099  * gdk_keyboard_grab
1100  *
1101  *   Grabs the keyboard to a specific window
1102  *
1103  * Arguments:
1104  *   "window" is the window which will receive the grab
1105  *   "owner_events" specifies whether events will be reported as is,
1106  *     or relative to "window"
1107  *   "time" specifies the time
1108  *
1109  * Results:
1110  *
1111  * Side effects:
1112  *   requires a corresponding call to gdk_keyboard_ungrab
1113  *
1114  *--------------------------------------------------------------
1115  */
1116
1117 gint
1118 gdk_keyboard_grab (GdkWindow *     window,
1119                    gint            owner_events,
1120                    guint32         time)
1121 {
1122   GdkWindowPrivate *window_private;
1123   Window xwindow;
1124
1125   g_return_val_if_fail (window != NULL, 0);
1126
1127   window_private = (GdkWindowPrivate*) window;
1128   xwindow = window_private->xwindow;
1129
1130   return XGrabKeyboard (window_private->xdisplay,
1131                         xwindow,
1132                         owner_events,
1133                         GrabModeAsync, GrabModeAsync,
1134                         time);
1135 }
1136
1137 /*
1138  *--------------------------------------------------------------
1139  * gdk_keyboard_ungrab
1140  *
1141  *   Releases any keyboard grab
1142  *
1143  * Arguments:
1144  *
1145  * Results:
1146  *
1147  * Side effects:
1148  *
1149  *--------------------------------------------------------------
1150  */
1151
1152 void
1153 gdk_keyboard_ungrab (guint32 time)
1154 {
1155   XUngrabKeyboard (gdk_display, time);
1156 }
1157
1158 /*
1159  *--------------------------------------------------------------
1160  * gdk_screen_width
1161  *
1162  *   Return the width of the screen.
1163  *
1164  * Arguments:
1165  *
1166  * Results:
1167  *
1168  * Side effects:
1169  *
1170  *--------------------------------------------------------------
1171  */
1172
1173 gint
1174 gdk_screen_width ()
1175 {
1176   gint return_val;
1177
1178   return_val = DisplayWidth (gdk_display, gdk_screen);
1179
1180   return return_val;
1181 }
1182
1183 /*
1184  *--------------------------------------------------------------
1185  * gdk_screen_height
1186  *
1187  *   Return the height of the screen.
1188  *
1189  * Arguments:
1190  *
1191  * Results:
1192  *
1193  * Side effects:
1194  *
1195  *--------------------------------------------------------------
1196  */
1197
1198 gint
1199 gdk_screen_height ()
1200 {
1201   gint return_val;
1202
1203   return_val = DisplayHeight (gdk_display, gdk_screen);
1204
1205   return return_val;
1206 }
1207
1208 void
1209 gdk_key_repeat_disable ()
1210 {
1211   XAutoRepeatOff (gdk_display);
1212 }
1213
1214 void
1215 gdk_key_repeat_restore ()
1216 {
1217   if (autorepeat)
1218     XAutoRepeatOn (gdk_display);
1219   else
1220     XAutoRepeatOff (gdk_display);
1221 }
1222
1223
1224 /*
1225  *--------------------------------------------------------------
1226  * gdk_flush
1227  *
1228  *   Flushes the Xlib output buffer and then waits
1229  *   until all requests have been received and processed
1230  *   by the X server. The only real use for this function
1231  *   is in dealing with XShm.
1232  *
1233  * Arguments:
1234  *
1235  * Results:
1236  *
1237  * Side effects:
1238  *
1239  *--------------------------------------------------------------
1240  */
1241
1242 void gdk_flush ()
1243 {
1244   XSync (gdk_display, False);
1245 }
1246
1247
1248 void
1249 gdk_beep ()
1250 {
1251   XBell(gdk_display, 100);
1252 }
1253
1254
1255 /*
1256  *--------------------------------------------------------------
1257  * gdk_event_wait
1258  *
1259  *   Waits until an event occurs or the timer runs out.
1260  *
1261  * Arguments:
1262  *
1263  * Results:
1264  *   Returns TRUE if an event is ready to be read and FALSE
1265  *   if the timer ran out.
1266  *
1267  * Side effects:
1268  *
1269  *--------------------------------------------------------------
1270  */
1271
1272 static gint
1273 gdk_event_wait ()
1274 {
1275   GList *list;
1276   GdkInput *input;
1277   GdkInputCondition condition;
1278   SELECT_MASK readfds;
1279   SELECT_MASK writefds;
1280   SELECT_MASK exceptfds;
1281   int max_input;
1282   int nfd;
1283
1284   /* If there are no events pending we will wait for an event.
1285    * The time we wait is dependant on the "timer". If no timer
1286    *  has been specified then we'll block until an event arrives.
1287    *  If a timer has been specified we'll block until an event
1288    *  arrives or the timer expires. (This is all done using the
1289    *  "select" system call).
1290    */
1291
1292   if (XPending (gdk_display) == 0)
1293     {
1294       FD_ZERO (&readfds);
1295       FD_ZERO (&writefds);
1296       FD_ZERO (&exceptfds);
1297
1298       FD_SET (connection_number, &readfds);
1299       max_input = connection_number;
1300
1301       list = inputs;
1302       while (list)
1303         {
1304           input = list->data;
1305           list = list->next;
1306
1307           if (input->condition & GDK_INPUT_READ)
1308             FD_SET (input->source, &readfds);
1309           if (input->condition & GDK_INPUT_WRITE)
1310             FD_SET (input->source, &writefds);
1311           if (input->condition & GDK_INPUT_EXCEPTION)
1312             FD_SET (input->source, &exceptfds);
1313
1314           max_input = MAX (max_input, input->source);
1315         }
1316
1317       nfd = select (max_input+1, &readfds, &writefds, &exceptfds, timerp);
1318
1319       timerp = NULL;
1320       timer_val = 0;
1321
1322       if (nfd > 0)
1323         {
1324           if (FD_ISSET (connection_number, &readfds))
1325             {
1326               if (XPending (gdk_display) == 0)
1327                 {
1328                   if (nfd == 1)
1329                     {
1330                       XNoOp (gdk_display);
1331                       XFlush (gdk_display);
1332                     }
1333                   return FALSE;
1334                 }
1335               else
1336                 return TRUE;
1337             }
1338
1339           list = inputs;
1340           while (list)
1341             {
1342               input = list->data;
1343               list = list->next;
1344
1345               condition = 0;
1346               if (FD_ISSET (input->source, &readfds))
1347                 condition |= GDK_INPUT_READ;
1348               if (FD_ISSET (input->source, &writefds))
1349                 condition |= GDK_INPUT_WRITE;
1350               if (FD_ISSET (input->source, &exceptfds))
1351                 condition |= GDK_INPUT_EXCEPTION;
1352
1353               if (condition && input->function)
1354                 (* input->function) (input->data, input->source, condition);
1355             }
1356         }
1357     }
1358   else
1359     return TRUE;
1360
1361   return FALSE;
1362 }
1363
1364 static gint
1365 gdk_event_translate (GdkEvent *event,
1366                      XEvent   *xevent)
1367 {
1368
1369   GdkWindow *window;
1370   GdkWindowPrivate *window_private;
1371   XComposeStatus compose;
1372   int charcount;
1373   char buf[16];
1374   gint return_val;
1375
1376   /* Are static variables used for this purpose thread-safe? */
1377   static GdkPoint dnd_drag_start = {0,0},
1378                   dnd_drag_oldpos = {0,0};
1379   static GdkRectangle dnd_drag_dropzone = {0,0,0,0};
1380   static gint dnd_drag_perhaps = 0;
1381   static GdkWindowPrivate *real_sw = NULL;
1382   static Window dnd_drag_curwin = None, dnd_drag_target = None;
1383
1384   return_val = FALSE;
1385
1386   /* Find the GdkWindow that this event occurred in.
1387    * All events occur in some GdkWindow (otherwise, why
1388    *  would we be receiving them). It really is an error
1389    *  to receive an event for which we cannot find the
1390    *  corresponding GdkWindow. We handle events with window=None
1391    *  specially - they are generated by XFree86's XInput under
1392    *  some circumstances.
1393    */
1394
1395   if ((xevent->xany.window == None) &&
1396       gdk_input_vtable.window_none_event)
1397     {
1398       return_val = gdk_input_vtable.window_none_event (event,xevent);
1399
1400       if (return_val >= 0)      /* was handled */
1401         return return_val;
1402       else
1403         return_val = FALSE;
1404     }
1405
1406   window = gdk_window_lookup (xevent->xany.window);
1407   window_private = (GdkWindowPrivate *) window;
1408
1409   /* We do a "manual" conversion of the XEvent to a
1410    *  GdkEvent. The structures are mostly the same so
1411    *  the conversion is fairly straightforward. We also
1412    *  optionally print debugging info regarding events
1413    *  received.
1414    */
1415   /* Addendum:
1416    * During drag & drop you get events where the pointer is
1417    * in other windows. Need to just do finer-grained checking
1418    */
1419   switch (xevent->type)
1420     {
1421     case KeyPress:
1422       /* Lookup the string corresponding to the given keysym.
1423        */
1424       charcount = XLookupString (&xevent->xkey, buf, 16,
1425                                  (KeySym*) &event->key.keyval,
1426                                  &compose);
1427
1428       /* Print debugging info.
1429        */
1430       if (gdk_show_events)
1431         g_print ("key press:\t\twindow: %ld  key: %12s  %d\n",
1432                  xevent->xkey.window - base_id,
1433                  XKeysymToString (event->key.keyval),
1434                  event->key.keyval);
1435
1436       event->key.type = GDK_KEY_PRESS;
1437       event->key.window = window;
1438       event->key.time = xevent->xkey.time;
1439       event->key.state = (GdkModifierType) xevent->xkey.state;
1440
1441       return_val = !window_private->destroyed;
1442       break;
1443
1444     case KeyRelease:
1445       /* Lookup the string corresponding to the given keysym.
1446        */
1447       charcount = XLookupString (&xevent->xkey, buf, 16,
1448                                  (KeySym*) &event->key.keyval,
1449                                  &compose);
1450
1451       /* Print debugging info.
1452        */
1453       if (gdk_show_events)
1454         g_print ("key release:\t\twindow: %ld  key: %12s  %d\n",
1455                  xevent->xkey.window - base_id,
1456                  XKeysymToString (event->key.keyval),
1457                  event->key.keyval);
1458
1459       event->key.type = GDK_KEY_RELEASE;
1460       event->key.window = window;
1461       event->key.time = xevent->xkey.time;
1462       event->key.state = (GdkModifierType) xevent->xkey.state;
1463
1464       return_val = !window_private->destroyed;
1465       break;
1466
1467     case ButtonPress:
1468       /* Print debugging info.
1469        */
1470       if (gdk_show_events)
1471         g_print ("button press[%d]:\t\twindow: %ld  x,y: %d %d  button: %d\n",
1472                  window_private?window_private->dnd_drag_enabled:0,
1473                  xevent->xbutton.window - base_id,
1474                  xevent->xbutton.x, xevent->xbutton.y,
1475                  xevent->xbutton.button);
1476
1477       if (window_private &&
1478           (window_private->extension_events != 0) &&
1479           gdk_input_ignore_core)
1480         break;
1481
1482       event->button.type = GDK_BUTTON_PRESS;
1483       event->button.window = window;
1484       event->button.time = xevent->xbutton.time;
1485       event->button.x = xevent->xbutton.x;
1486       event->button.y = xevent->xbutton.y;
1487       event->button.pressure = 0.5;
1488       event->button.xtilt = 0;
1489       event->button.ytilt = 0;
1490       event->button.state = (GdkModifierType) xevent->xbutton.state;
1491       event->button.button = xevent->xbutton.button;
1492       event->button.source = GDK_SOURCE_MOUSE;
1493       event->button.deviceid = GDK_CORE_POINTER;
1494
1495       if ((event->button.time < (button_click_time[1] + TRIPLE_CLICK_TIME)) &&
1496           (event->button.window == button_window[1]) &&
1497           (event->button.button == button_number[1]))
1498         {
1499           gdk_synthesize_click (event, 3);
1500
1501           button_click_time[1] = 0;
1502           button_click_time[0] = 0;
1503           button_window[1] = NULL;
1504           button_window[0] = 0;
1505           button_number[1] = -1;
1506           button_number[0] = -1;
1507         }
1508       else if ((event->button.time < (button_click_time[0] + DOUBLE_CLICK_TIME)) &&
1509                (event->button.window == button_window[0]) &&
1510                (event->button.button == button_number[0]))
1511         {
1512           gdk_synthesize_click (event, 2);
1513
1514           button_click_time[1] = button_click_time[0];
1515           button_click_time[0] = event->button.time;
1516           button_window[1] = button_window[0];
1517           button_window[0] = event->button.window;
1518           button_number[1] = button_number[0];
1519           button_number[0] = event->button.button;
1520         }
1521       else
1522         {
1523           button_click_time[1] = 0;
1524           button_click_time[0] = event->button.time;
1525           button_window[1] = NULL;
1526           button_window[0] = event->button.window;
1527           button_number[1] = -1;
1528           button_number[0] = event->button.button;
1529         }
1530       if(window_private
1531          && window_private->dnd_drag_enabled
1532          && !dnd_drag_perhaps
1533          && !gdk_dnd.drag_really)
1534         {
1535           dnd_drag_perhaps = 1;
1536           dnd_drag_start.x = xevent->xbutton.x_root;
1537           dnd_drag_start.y = xevent->xbutton.y_root;
1538           real_sw = window_private;
1539           
1540           if(gdk_dnd.drag_startwindows)
1541             {
1542               g_free(gdk_dnd.drag_startwindows);
1543               gdk_dnd.drag_startwindows = NULL;
1544             }
1545           gdk_dnd.drag_numwindows = gdk_dnd.drag_really = 0;
1546
1547           {
1548             /* Set motion mask for first DnD'd window, since it
1549                will be the one that is actually dragged */
1550             XWindowAttributes dnd_winattr;
1551             XSetWindowAttributes dnd_setwinattr;
1552             Status rv;
1553
1554             /* We need to get motion events while the button is down, so
1555                we can know whether to really start dragging or not... */
1556             XGetWindowAttributes(gdk_display, (Window)window_private->xwindow,
1557                                  &dnd_winattr);
1558             
1559             window_private->dnd_drag_savedeventmask = dnd_winattr.your_event_mask;
1560             dnd_setwinattr.event_mask = 
1561               window_private->dnd_drag_eventmask = ButtonMotionMask;
1562             XChangeWindowAttributes(gdk_display, window_private->xwindow,
1563                                     CWEventMask, &dnd_setwinattr);
1564         }
1565       }
1566       return_val = window_private?(!window_private->destroyed):FALSE;
1567       break;
1568
1569     case ButtonRelease:
1570       /* Print debugging info.
1571        */
1572       if (gdk_show_events)
1573         g_print ("button release[%d]:\twindow: %ld  x,y: %d %d  button: %d\n",
1574                  window_private?window_private->dnd_drag_enabled:0,
1575                  xevent->xbutton.window - base_id,
1576                  xevent->xbutton.x, xevent->xbutton.y,
1577                  xevent->xbutton.button);
1578
1579       if (window_private &&
1580           (window_private->extension_events != 0) &&
1581           gdk_input_ignore_core)
1582         break;
1583
1584       event->button.type = GDK_BUTTON_RELEASE;
1585       event->button.window = window;
1586       event->button.time = xevent->xbutton.time;
1587       event->button.x = xevent->xbutton.x;
1588       event->button.y = xevent->xbutton.y;
1589       event->button.pressure = 0.5;
1590       event->button.xtilt = 0;
1591       event->button.ytilt = 0;
1592       event->button.state = (GdkModifierType) xevent->xbutton.state;
1593       event->button.button = xevent->xbutton.button;
1594       event->button.source = GDK_SOURCE_MOUSE;
1595       event->button.deviceid = GDK_CORE_POINTER;
1596
1597       if(dnd_drag_perhaps)
1598         {
1599         if(gdk_dnd.drag_really)
1600           {
1601           GdkPoint foo = {xevent->xbutton.x_root,
1602                           xevent->xbutton.y_root};
1603           XUngrabPointer(gdk_display, CurrentTime);
1604
1605           if(dnd_drag_target != None)
1606             gdk_dnd_drag_end(dnd_drag_target, foo);
1607           gdk_dnd.drag_really = 0;
1608
1609           if(gdk_dnd.drag_numwindows)
1610             {
1611               XSetWindowAttributes attrs;
1612               /* Reset event mask to pre-drag value, assuming event_mask
1613                  doesn't change during drag */
1614               attrs.event_mask = real_sw->dnd_drag_savedeventmask;
1615               XChangeWindowAttributes(gdk_display, real_sw->xwindow,
1616                                       CWEventMask, &attrs);
1617             }
1618
1619           gdk_dnd.drag_numwindows = 0;
1620           if(gdk_dnd.drag_startwindows)
1621             {
1622             g_free(gdk_dnd.drag_startwindows);
1623             gdk_dnd.drag_startwindows = NULL;
1624             }
1625
1626           real_sw = NULL;
1627           }
1628
1629         dnd_drag_perhaps = 0;
1630         dnd_drag_start.x = dnd_drag_start.y = 0;
1631         dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0;
1632         dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0;
1633         dnd_drag_curwin = None;
1634       }
1635       return_val = window ? (!window_private->destroyed) : FALSE;
1636       break;
1637
1638     case MotionNotify:
1639       /* Print debugging info.
1640        */
1641       if (gdk_show_events)
1642         g_print ("motion notify:\t\twindow: %ld  x,y: %d %d  hint: %s d:%d r%d\n",
1643                  xevent->xmotion.window - base_id,
1644                  xevent->xmotion.x, xevent->xmotion.y,
1645                  (xevent->xmotion.is_hint) ? "true" : "false",
1646                  dnd_drag_perhaps, gdk_dnd.drag_really);
1647
1648       if (window_private &&
1649           (window_private->extension_events != 0) &&
1650           gdk_input_ignore_core)
1651         break;
1652
1653       event->motion.type = GDK_MOTION_NOTIFY;
1654       event->motion.window = window;
1655       event->motion.time = xevent->xmotion.time;
1656       event->motion.x = xevent->xmotion.x;
1657       event->motion.y = xevent->xmotion.y;
1658       event->motion.pressure = 0.5;
1659       event->motion.xtilt = 0;
1660       event->motion.ytilt = 0;
1661       event->motion.state = (GdkModifierType) xevent->xmotion.state;
1662       event->motion.is_hint = xevent->xmotion.is_hint;
1663       event->motion.source = GDK_SOURCE_MOUSE;
1664       event->motion.deviceid = GDK_CORE_POINTER;
1665
1666 #define IS_IN_ZONE(cx, cy) (cx >= dnd_drag_dropzone.x \
1667      && cy >= dnd_drag_dropzone.y \
1668      && cx < (dnd_drag_dropzone.x + dnd_drag_dropzone.width) \
1669      && cy < (dnd_drag_dropzone.y + dnd_drag_dropzone.height))
1670
1671       if(dnd_drag_perhaps && gdk_dnd.drag_really)
1672         {
1673           /* First, we have to find what window the motion was in... */
1674           /* XXX there has to be a better way to do this, perhaps with
1675              XTranslateCoordinates or XQueryTree - I don't know how,
1676              and this sort of works */
1677           Window curwin, childwin = gdk_root_window, rootwinret;
1678           int x, y;
1679           unsigned int mask;
1680           while(childwin != None)
1681             {
1682               curwin = childwin;
1683               XQueryPointer(gdk_display, curwin, &rootwinret, &childwin,
1684                             &x, &y, &x, &y, &mask);
1685             }
1686           if(curwin != dnd_drag_curwin)
1687             {
1688               /* We have left one window and entered another
1689                  (do leave & enter bits) */
1690               if(dnd_drag_curwin != real_sw->xwindow && dnd_drag_curwin != None)
1691                 gdk_dnd_drag_leave(dnd_drag_curwin);
1692               dnd_drag_curwin = curwin;
1693               gdk_dnd_drag_enter(dnd_drag_curwin);
1694               dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0;
1695               dnd_drag_dropzone.width = dnd_drag_dropzone.height = 0;
1696               dnd_drag_target = None;
1697               XChangeActivePointerGrab(gdk_display,
1698                                        ButtonMotionMask |
1699                                        ButtonPressMask | ButtonReleaseMask |
1700                                        EnterWindowMask | LeaveWindowMask,
1701                                        gdk_dnd.gdk_cursor_dragdefault,
1702                                        CurrentTime);
1703             }
1704           else if(dnd_drag_dropzone.width > 0
1705                   && dnd_drag_dropzone.height > 0)
1706             {
1707               /* Handle all that dropzone stuff - thanks John ;-) */
1708               if(dnd_drag_target != None
1709                  && IS_IN_ZONE(dnd_drag_oldpos.x, dnd_drag_oldpos.y)
1710                  && !IS_IN_ZONE(xevent->xmotion.x_root,
1711                                 xevent->xmotion.y_root))
1712                 {
1713                   /* We were in the drop zone and moved out */
1714                   dnd_drag_target = None;
1715                   gdk_dnd_drag_leave(curwin);
1716                 }
1717               else
1718                 {
1719                   /* We were outside drop zone but in the window
1720                      - have to send enter events */
1721                   gdk_dnd_drag_enter(curwin);
1722                   dnd_drag_curwin = curwin;
1723                   dnd_drag_dropzone.x = dnd_drag_dropzone.y = 0;
1724                   dnd_drag_target = None;
1725                 }
1726             } else
1727               dnd_drag_curwin = None;
1728           return_val = FALSE;
1729         }
1730       else
1731       return_val = window?(!window_private->destroyed):FALSE;
1732       break;
1733
1734     case EnterNotify:
1735       /* Print debugging info.
1736        */
1737       if (gdk_show_events)
1738         g_print ("enter notify:\t\twindow: %ld  detail: %d subwin: %ld\n",
1739                  xevent->xcrossing.window - base_id,
1740                  xevent->xcrossing.detail,
1741                  xevent->xcrossing.subwindow - base_id);
1742
1743       /* Tell XInput stuff about it if appropriate */
1744       if (window_private &&
1745           (window_private->extension_events != 0) &&
1746           gdk_input_vtable.enter_event)
1747         gdk_input_vtable.enter_event (&xevent->xcrossing, window);
1748
1749       event->crossing.type = GDK_ENTER_NOTIFY;
1750       event->crossing.window = window;
1751
1752       /* If the subwindow field of the XEvent is non-NULL, then
1753        *  lookup the corresponding GdkWindow.
1754        */
1755       if (xevent->xcrossing.subwindow != None)
1756         event->crossing.subwindow = gdk_window_lookup (xevent->xcrossing.subwindow);
1757       else
1758         event->crossing.subwindow = NULL;
1759
1760       /* Translate the crossing detail into Gdk terms.
1761        */
1762       switch (xevent->xcrossing.detail)
1763         {
1764         case NotifyInferior:
1765           event->crossing.detail = GDK_NOTIFY_INFERIOR;
1766           break;
1767         case NotifyAncestor:
1768           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
1769           break;
1770         case NotifyVirtual:
1771           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
1772           break;
1773         case NotifyNonlinear:
1774           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
1775           break;
1776         case NotifyNonlinearVirtual:
1777           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
1778           break;
1779         default:
1780           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
1781           break;
1782         }
1783
1784       if(dnd_drag_perhaps
1785          && gdk_dnd.drag_really
1786          && xevent->xcrossing.window == real_sw->xwindow)
1787         {
1788           gdk_dnd.drag_really = 0;
1789           XUngrabPointer(gdk_display, CurrentTime);
1790         }
1791
1792       return_val = (window ? !window_private->destroyed : FALSE);
1793       break;
1794
1795     case LeaveNotify:
1796       /* Print debugging info.
1797        */
1798       if (gdk_show_events)
1799         g_print ("leave notify:\t\twindow: %ld  detail: %d subwin: %ld\n",
1800                  xevent->xcrossing.window - base_id,
1801                  xevent->xcrossing.detail, xevent->xcrossing.subwindow - base_id);
1802
1803       event->crossing.type = GDK_LEAVE_NOTIFY;
1804       event->crossing.window = window;
1805
1806       /* Translate the crossing detail into Gdk terms.
1807        */
1808       switch (xevent->xcrossing.detail)
1809         {
1810         case NotifyInferior:
1811           event->crossing.detail = GDK_NOTIFY_INFERIOR;
1812           break;
1813         case NotifyAncestor:
1814           event->crossing.detail = GDK_NOTIFY_ANCESTOR;
1815           break;
1816         case NotifyVirtual:
1817           event->crossing.detail = GDK_NOTIFY_VIRTUAL;
1818           break;
1819         case NotifyNonlinear:
1820           event->crossing.detail = GDK_NOTIFY_NONLINEAR;
1821           break;
1822         case NotifyNonlinearVirtual:
1823           event->crossing.detail = GDK_NOTIFY_NONLINEAR_VIRTUAL;
1824           break;
1825         default:
1826           event->crossing.detail = GDK_NOTIFY_UNKNOWN;
1827           break;
1828         }
1829       if(dnd_drag_perhaps
1830          && !gdk_dnd.drag_really)
1831         {
1832           gdk_dnd_drag_addwindow((GdkWindow *) real_sw);
1833           gdk_dnd_drag_begin((GdkWindow *) real_sw);
1834           XGrabPointer(gdk_display, real_sw->xwindow, False,
1835                        ButtonMotionMask |
1836                        ButtonPressMask | ButtonReleaseMask |
1837                        EnterWindowMask | LeaveWindowMask,
1838                        GrabModeAsync, GrabModeAsync, gdk_root_window,
1839                        gdk_dnd.gdk_cursor_dragdefault, CurrentTime);
1840           gdk_dnd.drag_really = 1;
1841       }
1842       return_val = window ? (!window_private->destroyed) : FALSE;
1843       break;
1844
1845     case FocusIn:
1846       /* Print debugging info.
1847        */
1848       if (gdk_show_events)
1849         g_print ("focus in:\t\twindow: %ld\n",
1850                  xevent->xfocus.window - base_id);
1851
1852       event->focus_change.type = GDK_FOCUS_CHANGE;
1853       event->focus_change.window = window;
1854       event->focus_change.in = TRUE;
1855
1856       return_val = !window_private->destroyed;
1857       break;
1858
1859     case FocusOut:
1860       /* Print debugging info.
1861        */
1862       if (gdk_show_events)
1863         g_print ("focus out:\t\twindow: %ld\n",
1864                  xevent->xfocus.window - base_id);
1865
1866       event->focus_change.type = GDK_FOCUS_CHANGE;
1867       event->focus_change.window = window;
1868       event->focus_change.in = FALSE;
1869
1870       return_val = !window_private->destroyed;
1871       break;
1872
1873     case KeymapNotify:
1874       /* Print debugging info.
1875        */
1876       if (gdk_show_events)
1877         g_print ("keymap notify\n");
1878
1879       /* Not currently handled */
1880       break;
1881
1882     case Expose:
1883       /* Print debugging info.
1884        */
1885       if (gdk_show_events)
1886         g_print ("expose:\t\twindow: %ld  %d  x,y: %d %d  w,h: %d %d\n",
1887                  xevent->xexpose.window - base_id, xevent->xexpose.count,
1888                  xevent->xexpose.x, xevent->xexpose.y,
1889                  xevent->xexpose.width, xevent->xexpose.height);
1890
1891       event->expose.type = GDK_EXPOSE;
1892       event->expose.window = window;
1893       event->expose.area.x = xevent->xexpose.x;
1894       event->expose.area.y = xevent->xexpose.y;
1895       event->expose.area.width = xevent->xexpose.width;
1896       event->expose.area.height = xevent->xexpose.height;
1897       event->expose.count = xevent->xexpose.count;
1898
1899       return_val = !window_private->destroyed;
1900       break;
1901
1902     case GraphicsExpose:
1903       /* Print debugging info.
1904        */
1905       if (gdk_show_events)
1906         g_print ("graphics expose:\tdrawable: %ld\n",
1907                  xevent->xgraphicsexpose.drawable - base_id);
1908
1909       event->expose.type = GDK_EXPOSE;
1910       event->expose.window = window;
1911       event->expose.area.x = xevent->xgraphicsexpose.x;
1912       event->expose.area.y = xevent->xgraphicsexpose.y;
1913       event->expose.area.width = xevent->xgraphicsexpose.width;
1914       event->expose.area.height = xevent->xgraphicsexpose.height;
1915       event->expose.count = xevent->xexpose.count;
1916
1917       return_val = !window_private->destroyed;
1918       break;
1919
1920     case NoExpose:
1921       /* Print debugging info.
1922        */
1923       if (gdk_show_events)
1924         g_print ("no expose:\t\tdrawable: %ld\n",
1925                  xevent->xnoexpose.drawable - base_id);
1926
1927       /* Not currently handled */
1928       break;
1929
1930     case VisibilityNotify:
1931       /* Print debugging info.
1932        */
1933       if (gdk_show_events)
1934         switch (xevent->xvisibility.state)
1935           {
1936           case VisibilityFullyObscured:
1937             g_print ("visibility notify:\twindow: %ld  none\n",
1938                      xevent->xvisibility.window - base_id);
1939             break;
1940           case VisibilityPartiallyObscured:
1941             g_print ("visibility notify:\twindow: %ld  partial\n",
1942                      xevent->xvisibility.window - base_id);
1943             break;
1944           case VisibilityUnobscured:
1945             g_print ("visibility notify:\twindow: %ld  full\n",
1946                      xevent->xvisibility.window - base_id);
1947             break;
1948           }
1949
1950       /* Not currently handled */
1951       break;
1952
1953     case CreateNotify:
1954       /* Not currently handled */
1955       break;
1956
1957     case DestroyNotify:
1958       /* Print debugging info.
1959        */
1960       if (gdk_show_events)
1961         g_print ("destroy notify:\twindow: %ld\n",
1962                  xevent->xdestroywindow.window - base_id);
1963
1964       event->any.type = GDK_DESTROY;
1965       event->any.window = window;
1966
1967       /* Remeber which window received the destroy notify
1968        *  event so that we can destroy our associated
1969        *  data structures the next time the user asks
1970        *  us for an event.
1971        */
1972       received_destroy_notify = TRUE;
1973       window_to_destroy = window;
1974
1975       return_val = !window_private->destroyed;
1976       break;
1977
1978     case UnmapNotify:
1979       /* Print debugging info.
1980        */
1981       if (gdk_show_events)
1982         g_print ("unmap notify:\t\twindow: %ld\n",
1983                  xevent->xmap.window - base_id);
1984
1985       event->any.type = GDK_UNMAP;
1986       event->any.window = window;
1987
1988       return_val = !window_private->destroyed;
1989       break;
1990
1991     case MapNotify:
1992       /* Print debugging info.
1993        */
1994       if (gdk_show_events)
1995         g_print ("map notify:\t\twindow: %ld\n",
1996                  xevent->xmap.window - base_id);
1997
1998       event->any.type = GDK_MAP;
1999       event->any.window = window;
2000
2001       return_val = !window_private->destroyed;
2002       break;
2003
2004     case ReparentNotify:
2005       /* Print debugging info.
2006        */
2007       if (gdk_show_events)
2008         g_print ("reparent notify:\twindow: %ld\n",
2009                  xevent->xreparent.window - base_id);
2010
2011       /* Not currently handled */
2012       break;
2013
2014     case ConfigureNotify:
2015       /* Print debugging info.
2016        */
2017       while ((XPending(gdk_display) > 0) &&
2018                 XCheckTypedWindowEvent(gdk_display, xevent->xany.window,
2019                                        ConfigureNotify, xevent))
2020           /*XSync(gdk_display, 0)*/;
2021
2022       if (gdk_show_events)
2023         g_print ("configure notify:\twindow: %ld  x,y: %d %d  w,h: %d %d\n",
2024                  xevent->xconfigure.window - base_id,
2025                  xevent->xconfigure.x, xevent->xconfigure.y,
2026                  xevent->xconfigure.width, xevent->xconfigure.height);
2027
2028       if (window_private &&
2029           (window_private->extension_events != 0) &&
2030           gdk_input_vtable.configure_event)
2031         gdk_input_vtable.configure_event (&xevent->xconfigure, window);
2032
2033       if ((window_private->window_type != GDK_WINDOW_CHILD) &&
2034           ((window_private->width != xevent->xconfigure.width) ||
2035            (window_private->height != xevent->xconfigure.height)))
2036         {
2037           event->configure.type = GDK_CONFIGURE;
2038           event->configure.window = window;
2039           event->configure.x = xevent->xconfigure.x;
2040           event->configure.y = xevent->xconfigure.y;
2041           event->configure.width = xevent->xconfigure.width;
2042           event->configure.height = xevent->xconfigure.height;
2043
2044           window_private->x = xevent->xconfigure.x;
2045           window_private->y = xevent->xconfigure.y;
2046           window_private->width = xevent->xconfigure.width;
2047           window_private->height = xevent->xconfigure.height;
2048           if (window_private->resize_count > 1)
2049             window_private->resize_count -= 1;
2050
2051           return_val = !window_private->destroyed;
2052         }
2053       break;
2054
2055     case PropertyNotify:
2056       /* Print debugging info.
2057        */
2058       if (gdk_show_events)
2059         g_print ("property notify:\twindow: %ld\n",
2060                  xevent->xproperty.window - base_id);
2061
2062       event->property.type = GDK_PROPERTY_NOTIFY;
2063       event->property.window = window;
2064       event->property.atom = xevent->xproperty.atom;
2065       event->property.time = xevent->xproperty.time;
2066       event->property.state = xevent->xproperty.state;
2067
2068       return_val = !window_private->destroyed;
2069       break;
2070
2071     case SelectionClear:
2072       if (gdk_show_events)
2073         g_print ("selection clear:\twindow: %ld\n",
2074                  xevent->xproperty.window - base_id);
2075
2076       event->selection.type = GDK_SELECTION_CLEAR;
2077       event->selection.window = window;
2078       event->selection.selection = xevent->xselectionclear.selection;
2079       event->selection.time = xevent->xselectionclear.time;
2080
2081       return_val = !((GdkWindowPrivate*) window)->destroyed;
2082       break;
2083
2084     case SelectionRequest:
2085       if (gdk_show_events)
2086         g_print ("selection request:\twindow: %ld\n",
2087                  xevent->xproperty.window - base_id);
2088
2089       event->selection.type = GDK_SELECTION_REQUEST;
2090       event->selection.window = window;
2091       event->selection.selection = xevent->xselectionrequest.selection;
2092       event->selection.target = xevent->xselectionrequest.target;
2093       event->selection.property = xevent->xselectionrequest.property;
2094       event->selection.requestor = xevent->xselectionrequest.requestor;
2095       event->selection.time = xevent->xselectionrequest.time;
2096
2097       return_val = !((GdkWindowPrivate*) window)->destroyed;
2098       break;
2099
2100     case SelectionNotify:
2101       if (gdk_show_events)
2102         g_print ("selection notify:\twindow: %ld\n",
2103                  xevent->xproperty.window - base_id);
2104
2105
2106       event->selection.type = GDK_SELECTION_NOTIFY;
2107       event->selection.window = window;
2108       event->selection.selection = xevent->xselection.selection;
2109       event->selection.target = xevent->xselection.target;
2110       event->selection.property = xevent->xselection.property;
2111       event->selection.time = xevent->xselection.time;
2112
2113       return_val = !((GdkWindowPrivate*) window)->destroyed;
2114       break;
2115
2116     case ColormapNotify:
2117       /* Print debugging info.
2118        */
2119       if (gdk_show_events)
2120         g_print ("colormap notify:\twindow: %ld\n",
2121                  xevent->xcolormap.window - base_id);
2122
2123       /* Not currently handled */
2124       break;
2125
2126     case ClientMessage:
2127       /* Print debugging info.
2128        */
2129       if (gdk_show_events)
2130         g_print ("client message:\twindow: %ld\n",
2131                  xevent->xclient.window - base_id);
2132
2133       /* Client messages are the means of the window manager
2134        *  communicating with a program. We'll first check to
2135        *  see if this is really the window manager talking
2136        *  to us.
2137        */
2138       if (xevent->xclient.message_type == gdk_wm_protocols)
2139         {
2140           if ((Atom) xevent->xclient.data.l[0] == gdk_wm_delete_window)
2141             {
2142               /* The delete window request specifies a window
2143                *  to delete. We don't actually destroy the
2144                *  window because "it is only a request". (The
2145                *  window might contain vital data that the
2146                *  program does not want destroyed). Instead
2147                *  the event is passed along to the program,
2148                *  which should then destroy the window.
2149                */
2150
2151               /* Print debugging info.
2152                */
2153               if (gdk_show_events)
2154                 g_print ("delete window:\t\twindow: %ld\n",
2155                          xevent->xclient.window - base_id);
2156
2157               event->any.type = GDK_DELETE;
2158               event->any.window = window;
2159
2160               return_val = !window_private->destroyed;
2161             }
2162           else if ((Atom) xevent->xclient.data.l[0] == gdk_wm_take_focus)
2163             {
2164             }
2165         }
2166       else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter)
2167         {
2168           Atom reptype = 0;
2169
2170           event->dropenter.u.allflags = xevent->xclient.data.l[1];
2171           if (gdk_show_events)
2172             g_print ("GDK_DROP_ENTER\n");
2173           return_val = FALSE;
2174
2175           /* Now figure out if we really want this drop...
2176            * If someone is trying funky clipboard stuff, ignore 
2177            */
2178           if (window_private
2179               && window_private->dnd_drop_enabled
2180               && event->dropenter.u.flags.sendreply
2181               && (reptype = gdk_dnd_check_types (window, xevent)))
2182             {
2183               XEvent replyev;
2184
2185               replyev.xclient.type = ClientMessage;
2186               replyev.xclient.window = xevent->xclient.data.l[0];
2187               replyev.xclient.format = 32;
2188               replyev.xclient.message_type = gdk_dnd.gdk_XdeRequest;
2189               replyev.xclient.data.l[0] = window_private->xwindow;
2190
2191               event->dragrequest.u.allflags = 0;
2192               event->dragrequest.u.flags.protocol_version =
2193                 DND_PROTOCOL_VERSION;
2194               event->dragrequest.u.flags.willaccept = 1;
2195               event->dragrequest.u.flags.delete_data =
2196                 (window_private->dnd_drop_destructive_op) ? 1 : 0;
2197
2198               replyev.xclient.data.l[1] = event->dragrequest.u.allflags;
2199               replyev.xclient.data.l[2] = replyev.xclient.data.l[3] = 0;
2200               replyev.xclient.data.l[4] = reptype;
2201
2202               XSendEvent (gdk_display, replyev.xclient.window,
2203                           False, NoEventMask, &replyev);
2204
2205               event->any.type = GDK_DROP_ENTER;
2206               event->dropenter.requestor = replyev.xclient.window;
2207               event->dropenter.u.allflags = xevent->xclient.data.l[1];
2208             }
2209         }
2210       else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeLeave)
2211         {
2212           if (gdk_show_events)
2213             g_print ("GDK_DROP_LEAVE\n");
2214           if (window_private && window_private->dnd_drop_enabled)
2215             {
2216               event->dropleave.type = GDK_DROP_LEAVE;
2217               event->dropleave.window = window;
2218               event->dropleave.requestor = xevent->xclient.data.l[0];
2219               event->dropleave.u.allflags = xevent->xclient.data.l[1];
2220               return_val = TRUE;
2221             }
2222           else
2223             return_val = FALSE;
2224         }
2225       else if (xevent->xclient.message_type == gdk_dnd.gdk_XdeRequest)
2226         {
2227           /* 
2228            * make sure to only handle requests from the window the cursor is
2229            * over 
2230            */
2231           if (gdk_show_events)
2232             g_print ("GDK_DRAG_REQUEST\n");
2233           event->dragrequest.u.allflags = xevent->xclient.data.l[1];
2234           return_val = FALSE;
2235
2236           if (window && gdk_dnd.drag_really &&
2237               xevent->xclient.data.l[0] == dnd_drag_curwin &&
2238               event->dragrequest.u.flags.sendreply == 0)
2239             {
2240               /* Got request - do we need to ask user? */
2241               if (!event->dragrequest.u.flags.willaccept
2242                   && event->dragrequest.u.flags.senddata)
2243                 {
2244                   /* Yes we do :) */
2245                   event->dragrequest.type = GDK_DRAG_REQUEST;
2246                   event->dragrequest.window = window;
2247                   event->dragrequest.requestor = xevent->xclient.data.l[0];
2248                   event->dragrequest.isdrop = 0;
2249                   event->dragrequest.drop_coords.x =
2250                     event->dragrequest.drop_coords.y = 0;
2251                   return_val = TRUE;
2252                 }
2253               else if (event->dragrequest.u.flags.willaccept)
2254                 {
2255                   window_private->dnd_drag_destructive_op =
2256                     event->dragrequest.u.flags.delete_data;
2257                   window_private->dnd_drag_accepted = 1;
2258                   window_private->dnd_drag_data_type =
2259                     xevent->xclient.data.l[4];
2260
2261                   dnd_drag_target = dnd_drag_curwin;
2262                   XChangeActivePointerGrab (gdk_display,
2263                                             ButtonMotionMask |
2264                                             ButtonPressMask |
2265                                             ButtonReleaseMask |
2266                                             EnterWindowMask | LeaveWindowMask,
2267                                             gdk_dnd.gdk_cursor_dragok,
2268                                             CurrentTime);
2269                 }
2270               dnd_drag_dropzone.x = xevent->xclient.data.l[2] & 65535;
2271               dnd_drag_dropzone.y =
2272                 (xevent->xclient.data.l[2] >> 16) & 65535;
2273               dnd_drag_dropzone.width = xevent->xclient.data.l[3] & 65535;
2274               dnd_drag_dropzone.height =
2275                 (xevent->xclient.data.l[3] >> 16) & 65535;
2276             }
2277         }
2278       else if(xevent->xclient.message_type == gdk_dnd.gdk_XdeDataAvailable)
2279           {
2280             gint tmp_int; Atom tmp_atom;
2281             gulong tmp_long;
2282             guchar *tmp_charptr;
2283             gpointer tmp_ptr;
2284             
2285             if(gdk_show_events)
2286               g_print("GDK_DROP_DATA_AVAIL\n");
2287             event->dropdataavailable.u.allflags = xevent->xclient.data.l[1];
2288             if(window
2289                /* No preview of data ATM */
2290                && event->dropdataavailable.u.flags.isdrop)
2291               {
2292                 event->dropdataavailable.type = GDK_DROP_DATA_AVAIL;
2293                 event->dropdataavailable.window = window;
2294                 event->dropdataavailable.requestor = xevent->xclient.data.l[0];
2295                 event->dropdataavailable.data_type =
2296                         gdk_atom_name(xevent->xclient.data.l[2]);
2297                 if(XGetWindowProperty (gdk_display,
2298                                     event->dropdataavailable.requestor,
2299                                     xevent->xclient.data.l[2],
2300                                     0, LONG_MAX - 1,
2301                                     False, XA_PRIMARY, &tmp_atom,
2302                                     &tmp_int,
2303                                     &event->dropdataavailable.data_numbytes,
2304                                     &tmp_long,
2305                                     &tmp_charptr)
2306                    != Success)
2307                   {
2308                     g_warning("XGetWindowProperty on %#x may have failed\n",
2309                             event->dropdataavailable.requestor);
2310                             event->dropdataavailable.data = NULL;
2311                   }
2312                 else
2313                   {
2314                     g_print("XGetWindowProperty got us %d bytes\n",
2315                             event->dropdataavailable.data_numbytes);
2316                     event->dropdataavailable.data =
2317                         g_malloc(event->dropdataavailable.data_numbytes);
2318                     memcpy(event->dropdataavailable.data,
2319                         tmp_charptr, event->dropdataavailable.data_numbytes);
2320                     XFree(tmp_charptr);
2321                     return_val = TRUE;
2322                   }
2323               return_val = TRUE;
2324             }
2325         } else {
2326           /* Send unknown ClientMessage's on to Gtk for it to use */
2327           event->client.type = GDK_CLIENT_EVENT;
2328           event->client.window = window;
2329           event->client.message_type = xevent->xclient.message_type;
2330           event->client.data_format = xevent->xclient.format;
2331           memcpy(&event->client.data, &xevent->xclient.data,
2332                  sizeof(event->client.data));
2333           return_val = TRUE;
2334         }
2335       return_val = return_val && !window_private->destroyed;
2336       break;
2337       
2338     case MappingNotify:
2339       /* Print debugging info.
2340        */
2341       if (gdk_show_events)
2342         g_print ("mapping notify\n");
2343
2344       /* Let XLib know that there is a new keyboard mapping.
2345        */
2346       XRefreshKeyboardMapping (&xevent->xmapping);
2347       break;
2348
2349     default:
2350       /* something else - (e.g., a Xinput event) */
2351
2352       if (window_private &&
2353           (window_private->extension_events != 0) &&
2354           gdk_input_vtable.other_event)
2355         return_val = gdk_input_vtable.other_event(event, xevent, window);
2356
2357       if (return_val < 0)       /* not an XInput event, convert */
2358         {
2359           event->other.type = GDK_OTHER_EVENT;
2360           event->other.window = window;
2361           event->other.xevent = &other_xevent[other_xevent_i];
2362           memcpy (&other_xevent[other_xevent_i], xevent, sizeof (XEvent));
2363           other_xevent_i = (other_xevent_i+1) % OTHER_XEVENT_BUFSIZE;
2364           return_val = TRUE;
2365         }
2366
2367       return_val = return_val && !window_private->destroyed;
2368       break;
2369     }
2370
2371   return return_val;
2372 }
2373
2374 static Bool
2375 gdk_event_get_type (Display  *display,
2376                     XEvent   *xevent,
2377                     XPointer  arg)
2378 {
2379   GdkEvent event;
2380   GdkPredicate *pred;
2381
2382   if (gdk_event_translate (&event, xevent))
2383     {
2384       pred = (GdkPredicate*) arg;
2385       return (* pred->func) (&event, pred->data);
2386     }
2387
2388   return FALSE;
2389 }
2390
2391 static void
2392 gdk_synthesize_click (GdkEvent *event,
2393                       gint      nclicks)
2394 {
2395   GdkEvent temp_event;
2396
2397   g_return_if_fail (event != NULL);
2398
2399   temp_event = *event;
2400   temp_event.type = (nclicks == 2) ? GDK_2BUTTON_PRESS : GDK_3BUTTON_PRESS;
2401
2402   gdk_event_put (&temp_event);
2403 }
2404
2405 /*
2406  *--------------------------------------------------------------
2407  * gdk_exit_func
2408  *
2409  *   This is the "atexit" function that makes sure the
2410  *   library gets a chance to cleanup.
2411  *
2412  * Arguments:
2413  *
2414  * Results:
2415  *
2416  * Side effects:
2417  *   The library is un-initialized and the program exits.
2418  *
2419  *--------------------------------------------------------------
2420  */
2421
2422 static void
2423 gdk_exit_func ()
2424 {
2425   if (initialized)
2426     {
2427       gdk_image_exit ();
2428       gdk_input_exit ();
2429       gdk_key_repeat_restore ();
2430
2431       XCloseDisplay (gdk_display);
2432       initialized = 0;
2433     }
2434 }
2435
2436 /*
2437  *--------------------------------------------------------------
2438  * gdk_x_error
2439  *
2440  *   The X error handling routine.
2441  *
2442  * Arguments:
2443  *   "display" is the X display the error orignated from.
2444  *   "error" is the XErrorEvent that we are handling.
2445  *
2446  * Results:
2447  *   Either we were expecting some sort of error to occur,
2448  *   in which case we set the "gdk_error_code" flag, or this
2449  *   error was unexpected, in which case we will print an
2450  *   error message and exit. (Since trying to continue will
2451  *   most likely simply lead to more errors).
2452  *
2453  * Side effects:
2454  *
2455  *--------------------------------------------------------------
2456  */
2457
2458 static int
2459 gdk_x_error (Display     *display,
2460              XErrorEvent *error)
2461 {
2462   char buf[64];
2463
2464   if (gdk_error_warnings)
2465     {
2466       XGetErrorText (display, error->error_code, buf, 63);
2467       g_error ("%s", buf);
2468     }
2469
2470   gdk_error_code = -1;
2471   return 0;
2472 }
2473
2474 /*
2475  *--------------------------------------------------------------
2476  * gdk_x_io_error
2477  *
2478  *   The X I/O error handling routine.
2479  *
2480  * Arguments:
2481  *   "display" is the X display the error orignated from.
2482  *
2483  * Results:
2484  *   An X I/O error basically means we lost our connection
2485  *   to the X server. There is not much we can do to
2486  *   continue, so simply print an error message and exit.
2487  *
2488  * Side effects:
2489  *
2490  *--------------------------------------------------------------
2491  */
2492
2493 static int
2494 gdk_x_io_error (Display *display)
2495 {
2496   g_error ("an x io error occurred");
2497   return 0;
2498 }
2499
2500 /*
2501  *--------------------------------------------------------------
2502  * gdk_signal
2503  *
2504  *   The signal handler.
2505  *
2506  * Arguments:
2507  *   "sig_num" is the number of the signal we received.
2508  *
2509  * Results:
2510  *   The signals we catch are all fatal. So we simply build
2511  *   up a nice little error message and print it and exit.
2512  *   If in the process of doing so another signal is received
2513  *   we notice that we are already exiting and simply kill
2514  *   our process.
2515  *
2516  * Side effects:
2517  *
2518  *--------------------------------------------------------------
2519  */
2520
2521 static RETSIGTYPE
2522 gdk_signal (int sig_num)
2523 {
2524   static int caught_fatal_sig = 0;
2525   char *sig;
2526
2527   if (caught_fatal_sig)
2528     kill (getpid (), sig_num);
2529   caught_fatal_sig = 1;
2530
2531   switch (sig_num)
2532     {
2533     case SIGHUP:
2534       sig = "sighup";
2535       break;
2536     case SIGINT:
2537       sig = "sigint";
2538       break;
2539     case SIGQUIT:
2540       sig = "sigquit";
2541       break;
2542     case SIGBUS:
2543       sig = "sigbus";
2544       break;
2545     case SIGSEGV:
2546       sig = "sigsegv";
2547       break;
2548     case SIGPIPE:
2549       sig = "sigpipe";
2550       break;
2551     case SIGTERM:
2552       sig = "sigterm";
2553       break;
2554     default:
2555       sig = "unknown signal";
2556       break;
2557     }
2558
2559   g_print ("\n** ERROR **: %s caught\n", sig);
2560   gdk_exit (1);
2561 }
2562
2563 static void
2564 gdk_dnd_drag_begin (GdkWindow *initial_window)
2565 {
2566   GdkEventDragBegin tev;
2567   tev.type = GDK_DRAG_BEGIN;
2568   tev.window = initial_window;
2569   tev.u.allflags = 0;
2570   tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
2571
2572   gdk_event_put ((GdkEvent *) &tev);
2573 }
2574
2575 static void
2576 gdk_dnd_drag_enter (Window dest)
2577 {
2578   XEvent sev;
2579   GdkEventDropEnter tev;
2580   int i;
2581   GdkWindowPrivate *wp;
2582   
2583   sev.xclient.type = ClientMessage;
2584   sev.xclient.format = 32;
2585   sev.xclient.message_type = gdk_dnd.gdk_XdeEnter;
2586   sev.xclient.window = dest;
2587
2588   tev.u.allflags = 0;
2589   tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
2590   tev.u.flags.sendreply = 1;
2591   for (i = 0; i < gdk_dnd.drag_numwindows; i++)
2592     {
2593       wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i];
2594       if (wp->dnd_drag_data_numtypesavail)
2595         {
2596           sev.xclient.data.l[0] = wp->xwindow;
2597           tev.u.flags.extended_typelist = (wp->dnd_drag_data_numtypesavail > 3)?1:0;
2598           sev.xclient.data.l[1] = tev.u.allflags;
2599           sev.xclient.data.l[2] = wp->dnd_drag_data_typesavail[0];
2600           if (wp->dnd_drag_data_numtypesavail > 1)
2601             {
2602               sev.xclient.data.l[3] = wp->dnd_drag_data_typesavail[1];
2603               if (wp->dnd_drag_data_numtypesavail > 2)
2604                 {
2605                   sev.xclient.data.l[4] = wp->dnd_drag_data_typesavail[2];
2606                 }
2607               else
2608                 sev.xclient.data.l[4] = None;
2609             }
2610           else
2611             sev.xclient.data.l[3] = sev.xclient.data.l[4] = None;
2612           XSendEvent (gdk_display, dest, False, NoEventMask, &sev);
2613         }
2614
2615     }
2616 }
2617
2618 static void
2619 gdk_dnd_drag_leave (Window dest)
2620 {
2621   XEvent sev;
2622   GdkEventDropLeave tev;
2623   int i;
2624   GdkWindowPrivate *wp;
2625
2626   tev.u.allflags = 0;
2627
2628   tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
2629   sev.xclient.type = ClientMessage;
2630   sev.xclient.window = dest;
2631   sev.xclient.format = 32;
2632   sev.xclient.message_type = gdk_dnd.gdk_XdeLeave;
2633   sev.xclient.data.l[1] = tev.u.allflags;
2634   for (i = 0; i < gdk_dnd.drag_numwindows; i++)
2635     {
2636       wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i];
2637       sev.xclient.data.l[0] = wp->xwindow;
2638       XSendEvent(gdk_display, dest, False, NoEventMask, &sev);
2639       wp->dnd_drag_accepted = 0;
2640     }
2641 }
2642
2643 /* 
2644  * when a drop occurs, we go through the list of windows being dragged and
2645  * tell them that it has occurred, so that they can set things up and reply
2646  * to 'dest' window 
2647  */
2648 static void
2649 gdk_dnd_drag_end (Window     dest, 
2650                   GdkPoint   coords)
2651 {
2652   GdkWindowPrivate *wp;
2653   GdkEventDragRequest tev;
2654   gchar *tmp_cptr;
2655   int i;
2656
2657   tev.type = GDK_DRAG_REQUEST;
2658   tev.drop_coords = coords;
2659   tev.requestor = dest;
2660   tev.u.allflags = 0;
2661   tev.u.flags.protocol_version = DND_PROTOCOL_VERSION;
2662   tev.isdrop = 1;
2663
2664   for (i = 0; i < gdk_dnd.drag_numwindows; i++)
2665     {
2666       wp = (GdkWindowPrivate *) gdk_dnd.drag_startwindows[i];
2667       if (wp->dnd_drag_accepted)
2668         {
2669           tev.window = (GdkWindow *) wp;
2670           tev.u.flags.delete_data = wp->dnd_drag_destructive_op;
2671           tev.data_type = 
2672                 gdk_atom_name(wp->dnd_drag_data_type);
2673
2674           gdk_event_put((GdkEvent *) &tev);
2675         }
2676     }
2677 }
2678
2679 static GdkAtom
2680 gdk_dnd_check_types (GdkWindow   *window, 
2681                      XEvent      *xevent)
2682 {
2683   GdkWindowPrivate *wp = (GdkWindowPrivate *) window;
2684   int i, j;
2685   GdkEventDropEnter event;
2686
2687   g_return_val_if_fail(window != NULL, 0);
2688   g_return_val_if_fail(xevent != NULL, 0);
2689   g_return_val_if_fail(xevent->type == ClientMessage, 0);
2690   g_return_val_if_fail(xevent->xclient.message_type == gdk_dnd.gdk_XdeEnter, 0);
2691
2692   if(wp->dnd_drop_data_numtypesavail <= 0 ||
2693      !wp->dnd_drop_data_typesavail)
2694     return 0;
2695
2696   for (i = 2; i <= 4; i++)
2697     {
2698       for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++)
2699         {
2700           if (xevent->xclient.data.l[i] == wp->dnd_drop_data_typesavail[j])
2701             return xevent->xclient.data.l[i];
2702         }
2703     }
2704
2705   /* Now we get the extended type list if it's available */
2706   event.u.allflags = xevent->xclient.data.l[1];
2707   if (event.u.flags.extended_typelist)
2708     {
2709       Atom *exttypes, realtype;
2710       gulong nitems, nbar;
2711       gint realfmt;
2712
2713       if (XGetWindowProperty(gdk_display, xevent->xclient.data.l[0],
2714                              gdk_dnd.gdk_XdeTypelist, 0L, LONG_MAX - 1,
2715                              False, AnyPropertyType, &realtype, &realfmt,
2716                              &nitems, &nbar, (unsigned char **) &exttypes)
2717          != Success)
2718         return 0;
2719
2720       if (realfmt != (sizeof(Atom) * 8))
2721         {
2722           g_warning("XdeTypelist property had format of %d instead of the expected %d, on window %#lx\n",
2723                     realfmt, sizeof(Atom) * 8, xevent->xclient.data.l[0]);
2724           return 0;
2725         }
2726
2727       for (i = 0; i <= nitems; i++)
2728         {
2729           for (j = 0; j < wp->dnd_drop_data_numtypesavail; j++)
2730             {
2731               if (exttypes[i] == wp->dnd_drop_data_typesavail[j])
2732                 {
2733                   XFree (exttypes);
2734                   return exttypes[i];
2735                 }
2736             }
2737         }
2738       XFree (exttypes);
2739     }
2740   return 0;
2741 }
2742
2743 /* 
2744  * used for debugging only 
2745  */
2746 static void
2747 gdk_print_atom (GdkAtom anatom)
2748 {
2749   gchar *tmpstr = NULL;
2750   tmpstr = (anatom!=None)?gdk_atom_name(anatom):"(none)";
2751   g_print("Atom %lu has name %s\n", anatom, tmpstr);
2752   if(tmpstr)
2753     g_free(tmpstr);
2754 }
2755
2756 /* 
2757  * used only by below routine and itself 
2758  */
2759 static Window 
2760 getchildren (Display     *dpy, 
2761              Window       win, 
2762              Atom         WM_STATE)
2763 {
2764   Window root, parent, *children, inf = 0;
2765   Atom type = None;
2766   unsigned int nchildren, i;
2767   int format;
2768   unsigned long nitems, after;
2769   unsigned char *data;
2770
2771   if (XQueryTree(dpy, win, &root, &parent, &children, &nchildren) == 0)
2772     return 0;
2773
2774   for (i = 0; !inf && (i < nchildren); i++)
2775     {
2776       XGetWindowProperty (dpy, children[i], WM_STATE, 0, 0, False,
2777                           AnyPropertyType, &type, &format, &nitems,
2778                           &after, &data);
2779       if (type != 0)
2780         inf = children[i];
2781     }
2782
2783   for (i = 0; !inf && (i < nchildren); i++)
2784     inf = getchildren (dpy, children[i], WM_STATE);
2785
2786   if (children != 0) 
2787     XFree ((char *) children);
2788
2789   return inf;
2790 }
2791
2792 /* 
2793  * find a window with WM_STATE, else return win itself, as per ICCCM
2794  *
2795  * modification of the XmuClientWindow() routine from X11R6.3
2796  */
2797 Window
2798 gdk_get_client_window (Display  *dpy, 
2799                        Window    win)
2800 {
2801   Atom WM_STATE;
2802   Atom type = None;
2803   int format;
2804   unsigned long nitems, after;
2805   unsigned char *data;
2806   Window inf;
2807
2808   if (win == 0)
2809     return DefaultRootWindow(dpy);
2810
2811   if ((WM_STATE = XInternAtom (dpy, "WM_STATE", True)) == 0)
2812     return win;
2813
2814   XGetWindowProperty (dpy, win, WM_STATE, 0, 0, False, AnyPropertyType,
2815                       &type, &format, &nitems, &after, &data);
2816   if (type)
2817     return win;
2818
2819   inf = getchildren (dpy, win, WM_STATE);
2820
2821   if (inf == 0)
2822     return win;
2823   else
2824     return inf;
2825 }
2826
2827 static GdkWindow *
2828 gdk_drop_get_real_window (GdkWindow   *w, 
2829                           guint16     *x, 
2830                           guint16     *y)
2831 {
2832   GdkWindow *retval = w;
2833   GdkWindowPrivate *awin;
2834   GList *children;
2835   gint16 myx = *x, myy = *y;
2836
2837   g_return_val_if_fail(w != NULL && x != NULL && y != NULL, NULL);
2838
2839   myx = *x; 
2840   myy = *y;
2841
2842 descend:
2843   for (children = gdk_window_get_children(retval); 
2844        children && children->next;
2845        children = children->next)
2846     {
2847       awin = (GdkWindowPrivate *) children->data;
2848       if ((myx >= awin->x) && (myy >= awin->y)
2849           && (myx < (awin->x + awin->width))
2850           && (myy < (awin->y + awin->height)))
2851         {
2852           retval = (GdkWindow *) awin;
2853           myx -= awin->x;
2854           myy -= awin->y;
2855           goto descend;
2856         }
2857     }
2858
2859   *x = myx; 
2860   *y = myy;
2861
2862   return retval;
2863 }
2864
2865 /* Sends a ClientMessage to all toplevel client windows */
2866 void
2867 gdk_event_send_clientmessage_toall(GdkEvent *event)
2868 {
2869   XEvent sev;
2870   Window *ret_children, ret_root, ret_parent, curwin;
2871   unsigned int ret_nchildren;
2872   int i;
2873
2874   g_return_if_fail(event != NULL);
2875
2876   /* Set up our event to send, with the exception of its target window */
2877   sev.xclient.type = ClientMessage;
2878   sev.xclient.display = gdk_display;
2879   sev.xclient.format = event->client.data_format;
2880   sev.xclient.serial = CurrentTime;
2881   memcpy(&sev.xclient.data, &event->client.data, sizeof(sev.xclient.data));
2882   sev.xclient.message_type = event->client.message_type;
2883
2884   /* OK, we're all set, now let's find some windows to send this to */
2885   if(XQueryTree(gdk_display, gdk_root_window, &ret_root, &ret_parent,
2886                 &ret_children, &ret_nchildren) != True)
2887     return;
2888
2889   /* foreach true child window of the root window, send an event to it */
2890   for(i = 0; i < ret_nchildren; i++) {
2891     curwin = gdk_get_client_window(gdk_display, ret_children[i]);
2892     sev.xclient.window = curwin;
2893     XSendEvent(gdk_display, curwin, False, NoEventMask, &sev);
2894   }
2895
2896   XFree(ret_children);
2897 }