]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkmain.c
Add new keysyms from X11R6.4 (including EuroSign).
[~andy/gtk] / gtk / gtkmain.c
index 2f3d58b073af7929b9f40f02d78b940aad8e85bc..94a5b621fa0f4a4ff04d9692d344465f5638dcd3 100644 (file)
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "gdkx.h"              /* For GDK_WINDOWING */
+
+#ifdef GDK_WINDOWING_X11
 #include <X11/Xlocale.h>       /* so we get the right setlocale */
+#else
+#include <locale.h>
+#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <gmodule.h>
 #include "gtkbutton.h"
 #include "gtkdnd.h"
-#include "gtkfeatures.h"
+#include "gtkcompat.h"
 #include "gtkhscrollbar.h"
 #include "gtkhseparator.h"
 #include "gtkmain.h"
 #include "gtkpreview.h"
 #include "gtkrc.h"
+#include "gtkscrolledwindow.h"
 #include "gtkselection.h"
 #include "gtksignal.h"
 #include "gtktable.h"
 #include "gdk/gdki18n.h"
 #include "config.h"
 #include "gtkdebug.h"
-
+#include "gtkintl.h"
 
 /* Private type definitions
  */
 typedef struct _GtkInitFunction                 GtkInitFunction;
 typedef struct _GtkQuitFunction                 GtkQuitFunction;
-typedef struct _GtkTimeoutFunction      GtkTimeoutFunction;
-typedef struct _GtkIdleHook             GtkIdleHook;
-typedef struct _GtkInputFunction        GtkInputFunction;
+typedef struct _GtkClosure              GtkClosure;
 typedef struct _GtkKeySnooperData       GtkKeySnooperData;
 
 struct _GtkInitFunction
@@ -68,37 +81,13 @@ struct _GtkQuitFunction
   GtkDestroyNotify destroy;
 };
 
-struct _GtkTimeoutFunction
+struct _GtkClosure
 {
-  guint tag;
-  guint32 start;
-  guint32 interval;
-  guint32 originterval;
-  GtkFunction function;
   GtkCallbackMarshal marshal;
   gpointer data;
   GtkDestroyNotify destroy;
 };
 
-enum
-{
-  GTK_HOOK_MARSHAL     = 1 << (G_HOOK_FLAG_USER_SHIFT)
-};
-
-struct _GtkIdleHook
-{
-  GHook        hook;
-  gint  priority;
-};
-#define        GTK_IDLE_HOOK(hook)     ((GtkIdleHook*) hook)
-
-struct _GtkInputFunction
-{
-  GtkCallbackMarshal callback;
-  gpointer data;
-  GtkDestroyNotify destroy;
-};
-
 struct _GtkKeySnooperData
 {
   GtkKeySnoopFunc func;
@@ -106,21 +95,18 @@ struct _GtkKeySnooperData
   guint id;
 };
 
-static void    gtk_exit_func            (void);
-static void    gtk_invoke_hook          (GHookList *hook_list,
-                                         GHook     *hook);
-static void    gtk_handle_idles         (void);
-static gboolean        gtk_finish_idles         (void);
+static void  gtk_exit_func              (void);
 static gint  gtk_quit_invoke_function   (GtkQuitFunction    *quitf);
 static void  gtk_quit_destroy           (GtkQuitFunction    *quitf);
-static void  gtk_timeout_insert                 (GtkTimeoutFunction *timeoutf);
-static void  gtk_handle_current_timeouts (guint32            the_time);
 static gint  gtk_invoke_key_snoopers    (GtkWidget          *grab_widget,
                                          GdkEvent           *event);
-static void  gtk_handle_timeouts        (void);
-static void  gtk_handle_timer           (void);
-static void  gtk_propagate_event        (GtkWidget          *widget,
-                                         GdkEvent           *event);
+
+static void     gtk_destroy_closure      (gpointer            data);
+static gboolean gtk_invoke_idle_timeout  (gpointer            data);
+static void     gtk_invoke_input         (gpointer            data,
+                                         gint                source,
+                                         GdkInputCondition   condition);
+
 #if 0
 static void  gtk_error                  (gchar              *str);
 static void  gtk_warning                (gchar              *str);
@@ -128,26 +114,18 @@ static void  gtk_message           (gchar              *str);
 static void  gtk_print                  (gchar              *str);
 #endif
 
-static gint  gtk_timeout_remove_from_list (GList               **list, 
-                                          guint                 tag, 
-                                          gint                  remove_link);
-
-static gint  gtk_timeout_compare        (gconstpointer      a, 
-                                         gconstpointer      b);
-
-
 const guint gtk_major_version = GTK_MAJOR_VERSION;
 const guint gtk_minor_version = GTK_MINOR_VERSION;
 const guint gtk_micro_version = GTK_MICRO_VERSION;
 const guint gtk_binary_age = GTK_BINARY_AGE;
 const guint gtk_interface_age = GTK_INTERFACE_AGE;
 
-static gboolean iteration_done = FALSE;
 static guint gtk_main_loop_level = 0;
 static gint gtk_initialized = FALSE;
-static GdkEvent *next_event = NULL;
 static GList *current_events = NULL;
 
+static GSList *main_loops = NULL;      /* stack of currently executing main loops */
+
 static GSList *grabs = NULL;              /* A stack of unique grabs. The grabbing
                                            *  widget is the first one on the list.
                                            */
@@ -155,53 +133,6 @@ static GList *init_functions = NULL;          /* A list of init functions.
                                            */
 static GList *quit_functions = NULL;      /* A list of quit functions.
                                            */
-
-
-/* When handling timeouts, the algorithm is to move all of the expired
- * timeouts from timeout_functions to current_timeouts then process
- * them as a batch. If one of the timeouts recursively calls the main
- * loop, then the remainder of the timeouts in current_timeouts will
- * be processed before anything else happens.
- * 
- * Each timeout is procesed as follows:
- *
- * - The timeout is removed from current_timeouts
- * - The timeout is pushed on the running_timeouts stack
- * - The timeout is executed
- * - The timeout stack is popped
- * - If the timeout function wasn't removed from the stack while executing,
- *   and it returned TRUE, it is added back to timeout_functions, otherwise
- *   it is destroyed if necessary.
- *
- * gtk_timeout_remove() works by checking for the timeout in
- * timeout_functions current_timeouts and running_timeouts. If it is
- * found in one of the first two, it is removed and destroyed. If it
- * is found in running_timeouts, it is destroyed and ->data is set to
- * NULL for the stack entry.
- *
- * Idle functions work pretty much identically.  
- */
-
-static GList *timeout_functions = NULL;           /* A list of timeout functions sorted by
-                                           *  when the length of the time interval
-                                           *  remaining. Therefore, the first timeout
-                                           *  function to expire is at the head of
-                                           *  the list and the last to expire is at
-                                           *  the tail of the list.  */
-/* Prioritized idle callbacks */
-static GHookList       idle_hooks = { 0 };
-static GHook           *last_idle = NULL;
-
-/* The timeouts that are currently being processed 
- *  by gtk_handle_current_timeouts
- */
-static GList *current_timeouts = NULL;
-
-/* A stack of timeouts that is currently being executed
- */
-static GList *running_timeouts = NULL;
-
-static GMemChunk *timeout_mem_chunk = NULL;
 static GMemChunk *quit_mem_chunk = NULL;
 
 static GSList *key_snoopers = NULL;
@@ -220,7 +151,8 @@ static const GDebugKey gtk_debug_keys[] = {
   {"objects", GTK_DEBUG_OBJECTS},
   {"misc", GTK_DEBUG_MISC},
   {"signals", GTK_DEBUG_SIGNALS},
-  {"dnd", GTK_DEBUG_DND}
+  {"dnd", GTK_DEBUG_DND},
+  {"plugsocket", GTK_DEBUG_PLUGSOCKET}
 };
 
 static const guint gtk_ndebug_keys = sizeof (gtk_debug_keys) / sizeof (GDebugKey);
@@ -233,34 +165,47 @@ gtk_check_version (guint required_major,
                   guint required_micro)
 {
   if (required_major > GTK_MAJOR_VERSION)
-    return "Gtk+ version to old (major mismatch)";
+    return "Gtk+ version too old (major mismatch)";
   if (required_major < GTK_MAJOR_VERSION)
-    return "Gtk+ version to new (major mismatch)";
+    return "Gtk+ version too new (major mismatch)";
   if (required_minor > GTK_MINOR_VERSION)
-    return "Gtk+ version to old (minor mismatch)";
+    return "Gtk+ version too old (minor mismatch)";
   if (required_minor < GTK_MINOR_VERSION)
-    return "Gtk+ version to new (minor mismatch)";
+    return "Gtk+ version too new (minor mismatch)";
   if (required_micro < GTK_MICRO_VERSION - GTK_BINARY_AGE)
-    return "Gtk+ version to new (micro mismatch)";
+    return "Gtk+ version too new (micro mismatch)";
   if (required_micro > GTK_MICRO_VERSION)
-    return "Gtk+ version to old (micro mismatch)";
+    return "Gtk+ version too old (micro mismatch)";
   return NULL;
 }
 
+#ifdef __EMX__
+static gchar *add_dll_suffix(gchar *module_name)
+{
+    gchar *suffix = strrchr(module_name, '.');
+    
+    if (!suffix || stricmp(suffix, ".dll"))
+    {
+       gchar *old = module_name;
+         
+       module_name = g_strconcat (module_name, ".dll", NULL);
+       g_free (old);
+    }
+    return (module_name);
+}
+#endif
 
-gint gtk_use_mb = -1;
-
-void
-gtk_init (int   *argc,
-         char ***argv)
+gboolean
+gtk_init_check (int     *argc,
+               char   ***argv)
 {
+  extern void gtk_object_post_arg_parsing_init (void);
   GSList *gtk_modules = NULL;
   GSList *slist;
-  gchar *current_locale;
   gchar *env_string = NULL;
 
   if (gtk_initialized)
-    return;
+    return TRUE;
 
 #if    0
   g_set_error_handler (gtk_error);
@@ -272,7 +217,10 @@ gtk_init (int       *argc,
   /* Initialize "gdk". We pass along the 'argc' and 'argv'
    *  parameters as they contain information that GDK uses
    */
-  gdk_init (argc, argv);
+  if (!gdk_init_check (argc, argv))
+    return FALSE;
+
+  gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL);
   
 #ifdef G_ENABLE_DEBUG
   env_string = getenv ("GTK_DEBUG");
@@ -290,7 +238,11 @@ gtk_init (int       *argc,
     {
       gchar **modules, **as;
 
-      modules = g_strsplit (env_string, ":", -1);
+#ifndef __EMX__
+      modules = g_strsplit (env_string, G_SEARCHPATH_SEPARATOR_S, -1);
+#else
+      modules = g_strsplit (env_string, ";", -1);
+#endif
       for (as = modules; *as; as++)
        {
          if (**as)
@@ -397,42 +349,6 @@ gtk_init (int       *argc,
        }
     }
   
-  /* Check if there is a good chance the mb functions will handle things
-   * correctly - set if either mblen("\xc0", MB_CUR_MAX) == 1 in the
-   * C locale, or we're using X's mb functions. (-DX_LOCALE && locale != C)
-   */
-  current_locale = setlocale (LC_CTYPE, NULL);
-
-#ifdef X_LOCALE
-  if ((strcmp (current_locale, "C")) && (strcmp (current_locale, "POSIX")))
-    gtk_use_mb = TRUE;
-  else
-#endif /* X_LOCALE */
-    {
-      /* Detect GNU libc, where mb == UTF8. Not useful unless it's
-       * really a UTF8 locale. The below still probably will
-       * screw up on Greek, Cyrillic, etc, encoded as UTF8.
-       */
-      
-      wchar_t result;
-      gtk_use_mb = TRUE;
-      
-      if ((MB_CUR_MAX == 2) &&
-         (mbstowcs (&result, "\xdd\xa5", 1) > 0) &&
-         result == 0x765)
-       {
-         if ((strlen (current_locale) < 4) ||
-             g_strcasecmp (current_locale + strlen(current_locale) - 4, "utf8"))
-           gtk_use_mb = FALSE;
-       }
-    }
-
-  GTK_NOTE (MISC,
-           g_message ("%s multi-byte string functions.", 
-                      gtk_use_mb ? "Using" : "Not using"));
-
-
   /* load gtk modules */
   gtk_modules = g_slist_reverse (gtk_modules);
   for (slist = gtk_modules; slist; slist = slist->next)
@@ -443,16 +359,17 @@ gtk_init (int      *argc,
       
       module_name = slist->data;
       slist->data = NULL;
-      if (!(module_name[0] == '/' ||
-           (module_name[0] == 'l' &&
-            module_name[1] == 'i' &&
-            module_name[2] == 'b')))
+#ifndef __EMX__
+      if (!g_path_is_absolute (module_name))
        {
          gchar *old = module_name;
          
-         module_name = g_strconcat ("lib", module_name, ".so", NULL);
+         module_name = g_module_build_path (NULL, module_name);
          g_free (old);
        }
+#else
+      module_name = add_dll_suffix(module_name);
+#endif
       if (g_module_supported ())
        {
          module = g_module_open (module_name, G_MODULE_BIND_LAZY);
@@ -483,6 +400,21 @@ gtk_init (int       *argc,
       g_free (module_name);
     }
 
+#ifdef ENABLE_NLS
+#ifndef G_OS_WIN32
+  bindtextdomain("gtk+", GTK_LOCALEDIR);
+#else
+  {
+    /* GTk+ locale dir is %WinDir%\gtk+\locale */
+    extern char *get_gtk_sysconf_directory ();
+    bindtextdomain ("gtk+", g_strconcat (get_gtk_sysconf_directory (),
+                                        G_DIR_SEPARATOR_S,
+                                        "locale",
+                                        NULL));
+  }
+#endif
+#endif  
+
   /* Initialize the default visual and colormap to be
    *  used in creating widgets. (We want to use the system
    *  defaults so as to be nice to the colormap).
@@ -491,6 +423,7 @@ gtk_init (int        *argc,
   gtk_colormap = gdk_colormap_get_system ();
 
   gtk_type_init ();
+  gtk_object_post_arg_parsing_init ();
   gtk_signal_init ();
   gtk_rc_init ();
   
@@ -516,10 +449,31 @@ gtk_init (int      *argc,
        }
     }
   g_slist_free (gtk_modules);
+  
+#ifndef G_OS_WIN32
+  /* No use warning on Win32, there aren't any non-devel versions anyhow... */
+  g_warning (""              "YOU ARE USING THE DEVEL BRANCH 1.3.x OF GTK+ WHICH IS CURRENTLY\n"
+            "                UNDER HEAVY DEVELOPMENT AND FREQUENTLY INTRODUCES INSTABILITIES.\n"
+            "                if you don't know why you are getting this, you probably want to\n"
+            "                use the stable branch which can be retrived from\n"
+            "                ftp://ftp.gtk.org/pub/gtk/v1.2/ or via CVS with\n"
+            "                cvs checkout -r glib-1-2 glib; cvs checkout -r gtk-1-2 gtk+");
+#endif
+
+  return TRUE;
+}
+void
+gtk_init (int *argc, char ***argv)
+{
+  if (!gtk_init_check (argc, argv))
+    {
+      g_warning ("cannot open display: %s", gdk_get_display ());
+      exit(1);
+    }
 }
 
 void
-gtk_exit (int errorcode)
+gtk_exit (gint errorcode)
 {
   /* Only if "gtk" has been initialized should we de-initialize.
    */
@@ -541,10 +495,13 @@ gtk_main (void)
   GList *tmp_list;
   GList *functions;
   GtkInitFunction *init;
-  int old_done;
-  
+  GMainLoop *loop;
+
   gtk_main_loop_level++;
   
+  loop = g_main_new (TRUE);
+  main_loops = g_slist_prepend (main_loops, loop);
+
   tmp_list = functions = init_functions;
   init_functions = NULL;
   
@@ -557,11 +514,14 @@ gtk_main (void)
       g_free (init);
     }
   g_list_free (functions);
-  
-  old_done = iteration_done;
-  while (!gtk_main_iteration ())
-    ;
-  iteration_done = old_done;
+
+  if (g_main_is_running (main_loops->data))
+    {
+      GDK_THREADS_LEAVE ();
+      g_main_run (loop);
+      GDK_THREADS_ENTER ();
+      gdk_flush ();
+    }
 
   if (quit_functions)
     {
@@ -595,8 +555,14 @@ gtk_main (void)
          work->next = quit_functions;
          quit_functions = work;
        }
+
+      gdk_flush ();
     }
              
+  main_loops = g_slist_remove (main_loops, loop);
+
+  g_main_destroy (loop);
+
   gtk_main_loop_level--;
 }
 
@@ -609,310 +575,263 @@ gtk_main_level (void)
 void
 gtk_main_quit (void)
 {
-  iteration_done = TRUE;
+  g_return_if_fail (main_loops != NULL);
+
+  g_main_quit (main_loops->data);
 }
 
 gint
 gtk_events_pending (void)
 {
-  gint result = 0;
-  
-  /* if this function is called from a timeout which will only return
-   * if gtk needs processor time, we need to take iteration_done==TRUE
-   * into account as well.
-   */
-  result = iteration_done;
-  result += next_event != NULL;
-  result += gdk_events_pending();
-
-  result += last_idle != NULL;
-  result += current_timeouts != NULL;
-
-  if (!result)
-    {
-      GHook *hook;
-
-      hook = g_hook_first_valid (&idle_hooks, FALSE);
-
-      result += hook && GTK_IDLE_HOOK (hook)->priority <= GTK_PRIORITY_INTERNAL;
-    }
-  
-  if (!result && timeout_functions)
-    {
-      guint32 the_time;
-      GtkTimeoutFunction *timeoutf;
-      
-      the_time = gdk_time_get ();
-      
-      timeoutf = timeout_functions->data;
-      
-      result += timeoutf->interval <= (the_time - timeoutf->start);
-    }
-  
-  return result;
+  return g_main_pending();
 }
 
 gint 
 gtk_main_iteration (void)
 {
-  return gtk_main_iteration_do (TRUE);
+  g_main_iteration (TRUE);
+
+  if (main_loops)
+    return !g_main_is_running (main_loops->data);
+  else
+    return TRUE;
 }
 
-gint
+gint 
 gtk_main_iteration_do (gboolean blocking)
+{
+  g_main_iteration (blocking);
+
+  if (main_loops)
+    return !g_main_is_running (main_loops->data);
+  else
+    return TRUE;
+}
+
+void 
+gtk_main_do_event (GdkEvent *event)
 {
   GtkWidget *event_widget;
   GtkWidget *grab_widget;
-  GdkEvent *event = NULL;
+  GdkEvent *next_event;
   GList *tmp_list;
+
+  /* If there are any events pending then get the next one.
+   */
+  next_event = gdk_event_peek ();
   
-  iteration_done = FALSE;
-  
-  /* If this is a recursive call, and there are pending timeouts or
-   * idles, finish them, then return immediately to avoid blocking
-   * in gdk_event_get()
+  /* Try to compress enter/leave notify events. These event
+   *  pairs occur when the mouse is dragged quickly across
+   *  a window with many buttons (or through a menu). Instead
+   *  of highlighting and de-highlighting each widget that
+   *  is crossed it is better to simply de-highlight the widget
+   *  which contained the mouse initially and highlight the
+   *  widget which ends up containing the mouse.
    */
-  if (current_timeouts)
-    {
-      gtk_handle_current_timeouts( gdk_time_get());
-
-      if (iteration_done)
-       gdk_flush ();
+  if (next_event)
+    if (((event->type == GDK_ENTER_NOTIFY) ||
+        (event->type == GDK_LEAVE_NOTIFY)) &&
+       ((next_event->type == GDK_ENTER_NOTIFY) ||
+        (next_event->type == GDK_LEAVE_NOTIFY)) &&
+       (next_event->type != event->type) &&
+       (next_event->any.window == event->any.window))
+      {
+       /* Throw both the peeked copy and the queued copy away 
+        */
+       gdk_event_free (next_event);
+       next_event = gdk_event_get ();
+       gdk_event_free (next_event);
+       
+       return;
+      }
 
-      return iteration_done;
-    }
-  if (last_idle && gtk_finish_idles ())
+  if (next_event)
+    gdk_event_free (next_event);
+
+  /* Find the widget which got the event. We store the widget
+   *  in the user_data field of GdkWindow's.
+   *  Ignore the event if we don't have a widget for it, except
+   *  for GDK_PROPERTY_NOTIFY events which are handled specialy.
+   *  Though this happens rarely, bogus events can occour
+   *  for e.g. destroyed GdkWindows. 
+   */
+  event_widget = gtk_get_event_widget (event);
+  if (!event_widget)
     {
-      if (iteration_done)
-       gdk_flush ();
-
-      return iteration_done;
+      /* To handle selection INCR transactions, we select
+       * PropertyNotify events on the requestor window and create
+       * a corresponding (fake) GdkWindow so that events get
+       * here. There won't be a widget though, so we have to handle
+          * them specially
+          */
+      if (event->type == GDK_PROPERTY_NOTIFY)
+       gtk_selection_incr_event (event->any.window,
+                                 &event->property);
+      
+      return;
     }
   
-  /* If there is a valid event in 'next_event' then move it to 'event'
+  /* Push the event onto a stack of current events for
+   * gtk_current_event_get().
    */
-  if (next_event)
-    {
-      event = next_event;
-      next_event = NULL;
-    }
+  current_events = g_list_prepend (current_events, event);
   
-  /* If we don't have an event then get one.
+  /* If there is a grab in effect...
    */
-  if (!event)
+  if (grabs)
     {
-      /* Handle setting of the "gdk" timer. If there are no
-       *  timeout functions, then the timer is turned off.
-       *  If there are timeout functions, then the timer is
-       *  set to the shortest timeout interval (which is
-       *  the first timeout function).
-       */
-      gtk_handle_timer ();
+      grab_widget = grabs->data;
       
-      if (blocking)
-       event = gdk_event_get ();
+      /* If the grab widget is an ancestor of the event widget
+       *  then we send the event to the original event widget.
+       *  This is the key to implementing modality.
+       */
+      if (GTK_WIDGET_IS_SENSITIVE (event_widget) &&
+         gtk_widget_is_ancestor (event_widget, grab_widget))
+       grab_widget = event_widget;
     }
-  
-  /* "gdk_event_get" can return FALSE if the timer goes off
-   *  and no events are pending. Therefore, we should make
-   *  sure that we got an event before continuing.
+  else
+    {
+      grab_widget = event_widget;
+    }
+
+  /* Not all events get sent to the grabbing widget.
+   * The delete, destroy, expose, focus change and resize
+   *  events still get sent to the event widget because
+   *  1) these events have no meaning for the grabbing widget
+   *  and 2) redirecting these events to the grabbing widget
+   *  could cause the display to be messed up.
+   * 
+   * Drag events are also not redirected, since it isn't
+   *  clear what the semantics of that would be.
    */
-  if (event)
+  switch (event->type)
     {
-      /* If there are any events pending then get the next one.
-       */
-      if (gdk_events_pending () > 0)
-       next_event = gdk_event_get ();
+    case GDK_NOTHING:
+      break;
       
-      /* Try to compress enter/leave notify events. These event
-       *  pairs occur when the mouse is dragged quickly across
-       *  a window with many buttons (or through a menu). Instead
-       *  of highlighting and de-highlighting each widget that
-       *  is crossed it is better to simply de-highlight the widget
-       *  which contained the mouse initially and highlight the
-       *  widget which ends up containing the mouse.
-       */
-      if (next_event)
-       if (((event->type == GDK_ENTER_NOTIFY) ||
-            (event->type == GDK_LEAVE_NOTIFY)) &&
-           ((next_event->type == GDK_ENTER_NOTIFY) ||
-            (next_event->type == GDK_LEAVE_NOTIFY)) &&
-           (next_event->type != event->type) &&
-           (next_event->any.window == event->any.window))
-         {
-           gdk_event_free (event);
-           gdk_event_free (next_event);
-           next_event = NULL;
-           
-           goto event_handling_done;
-         }
+    case GDK_DELETE:
+      gtk_widget_ref (event_widget);
+      if (!gtk_widget_event (event_widget, event) &&
+         !GTK_OBJECT_DESTROYED (event_widget))
+       gtk_widget_destroy (event_widget);
+      gtk_widget_unref (event_widget);
+      break;
       
-      /* Find the widget which got the event. We store the widget
-       *  in the user_data field of GdkWindow's.
-       *  Ignore the event if we don't have a widget for it, except
-       *  for GDK_PROPERTY_NOTIFY events which are handled specialy.
-       *  Though this happens rarely, bogus events can occour
-       *  for e.g. destroyed GdkWindows. 
-       */
-      event_widget = gtk_get_event_widget (event);
-      if (!event_widget)
+    case GDK_DESTROY:
+      gtk_widget_ref (event_widget);
+      gtk_widget_event (event_widget, event);
+      if (!GTK_OBJECT_DESTROYED (event_widget))
+       gtk_widget_destroy (event_widget);
+      gtk_widget_unref (event_widget);
+      break;
+      
+    case GDK_PROPERTY_NOTIFY:
+    case GDK_EXPOSE:
+    case GDK_NO_EXPOSE:
+    case GDK_FOCUS_CHANGE:
+    case GDK_CONFIGURE:
+    case GDK_MAP:
+    case GDK_UNMAP:
+    case GDK_SELECTION_CLEAR:
+    case GDK_SELECTION_REQUEST:
+    case GDK_SELECTION_NOTIFY:
+    case GDK_CLIENT_EVENT:
+    case GDK_VISIBILITY_NOTIFY:
+      gtk_widget_event (event_widget, event);
+      break;
+
+    case GDK_BUTTON_PRESS:
+    case GDK_2BUTTON_PRESS:
+    case GDK_3BUTTON_PRESS:
+    /* We treat button 4-5 specially, assume we have
+     * a MS-style scrollwheel mouse, and try to find
+     * a plausible widget to scroll. We also trap
+     * button 4-5 double and triple clicks here, since
+     * they will be generated if the user scrolls quickly.
+     */
+      if ((grab_widget == event_widget) &&
+         (event->button.button == 4 || event->button.button == 5))
        {
-         /* To handle selection INCR transactions, we select
-          * PropertyNotify events on the requestor window and create
-          * a corresponding (fake) GdkWindow so that events get
-          * here. There won't be a widget though, so we have to handle
-          * them specially
-          */
-         if (event->type == GDK_PROPERTY_NOTIFY)
-           gtk_selection_incr_event (event->any.window,
-                                     &event->property);
+         GtkWidget *range = NULL;
+         GtkWidget *scrollwin;
          
-         gdk_event_free (event);
+         if (GTK_IS_RANGE (event_widget))
+           range = event_widget;
+         else
+           {
+             scrollwin = gtk_widget_get_ancestor (event_widget,
+                                                  GTK_TYPE_SCROLLED_WINDOW);
+             if (scrollwin)
+               range = GTK_SCROLLED_WINDOW (scrollwin)->vscrollbar;
+           }
          
-         goto event_handling_done;
+         if (range && GTK_WIDGET_VISIBLE (range))
+           {
+             if (event->type == GDK_BUTTON_PRESS)
+               {
+                 GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
+                 gfloat new_value = adj->value + ((event->button.button == 4) ? 
+                                                  -adj->page_increment / 2: 
+                                                   adj->page_increment / 2);
+                 new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
+                 gtk_adjustment_set_value (adj, new_value);
+               }
+             break;
+           }
        }
-      
-      /* Push the event onto a stack of current events for
-       * gtk_current_event_get().
-       */
-      current_events = g_list_prepend (current_events, event);
-      
-      /* If there is a grab in effect...
-       */
-      if (grabs)
+      gtk_propagate_event (grab_widget, event);
+      break;
+
+    case GDK_KEY_PRESS:
+    case GDK_KEY_RELEASE:
+      if (key_snoopers)
        {
-         grab_widget = grabs->data;
-         
-         /* If the grab widget is an ancestor of the event widget
-          *  then we send the event to the original event widget.
-          *  This is the key to implementing modality.
-          */
-         if (GTK_WIDGET_IS_SENSITIVE (event_widget) &&
-             gtk_widget_is_ancestor (event_widget, grab_widget))
-           grab_widget = event_widget;
+         if (gtk_invoke_key_snoopers (grab_widget, event))
+           break;
        }
-      else
+      /* else fall through */
+    case GDK_MOTION_NOTIFY:
+    case GDK_BUTTON_RELEASE:
+    case GDK_PROXIMITY_IN:
+    case GDK_PROXIMITY_OUT:
+      gtk_propagate_event (grab_widget, event);
+      break;
+      
+    case GDK_ENTER_NOTIFY:
+      if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
        {
-         grab_widget = event_widget;
+         gtk_widget_event (grab_widget, event);
+         if (event_widget == grab_widget)
+           GTK_PRIVATE_SET_FLAG (event_widget, GTK_LEAVE_PENDING);
        }
-
-      /* Not all events get sent to the grabbing widget.
-       * The delete, destroy, expose, focus change and resize
-       *  events still get sent to the event widget because
-       *  1) these events have no meaning for the grabbing widget
-       *  and 2) redirecting these events to the grabbing widget
-       *  could cause the display to be messed up.
-       * 
-       * Drag events are also not redirected, since it isn't
-       *  clear what the semantics of that would be.
-       */
-      switch (event->type)
+      break;
+      
+    case GDK_LEAVE_NOTIFY:
+      if (GTK_WIDGET_LEAVE_PENDING (event_widget))
        {
-       case GDK_NOTHING:
-         break;
-         
-       case GDK_DELETE:
-         gtk_widget_ref (event_widget);
-         if (!gtk_widget_event (event_widget, event) &&
-             !GTK_OBJECT_DESTROYED (event_widget))
-           gtk_widget_destroy (event_widget);
-         gtk_widget_unref (event_widget);
-         break;
-         
-       case GDK_DESTROY:
-         gtk_widget_ref (event_widget);
+         GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_LEAVE_PENDING);
          gtk_widget_event (event_widget, event);
-         if (!GTK_OBJECT_DESTROYED (event_widget))
-           gtk_widget_destroy (event_widget);
-         gtk_widget_unref (event_widget);
-         break;
-         
-       case GDK_PROPERTY_NOTIFY:
-       case GDK_EXPOSE:
-       case GDK_NO_EXPOSE:
-       case GDK_FOCUS_CHANGE:
-       case GDK_CONFIGURE:
-       case GDK_MAP:
-       case GDK_UNMAP:
-       case GDK_SELECTION_CLEAR:
-       case GDK_SELECTION_REQUEST:
-       case GDK_SELECTION_NOTIFY:
-       case GDK_CLIENT_EVENT:
-       case GDK_VISIBILITY_NOTIFY:
-         gtk_widget_event (event_widget, event);
-         break;
-         
-       case GDK_KEY_PRESS:
-       case GDK_KEY_RELEASE:
-         if (key_snoopers)
-           {
-             if (gtk_invoke_key_snoopers (grab_widget, event))
-               break;
-           }
-         /* else fall through */
-       case GDK_MOTION_NOTIFY:
-       case GDK_BUTTON_PRESS:
-       case GDK_2BUTTON_PRESS:
-       case GDK_3BUTTON_PRESS:
-       case GDK_BUTTON_RELEASE:
-       case GDK_PROXIMITY_IN:
-       case GDK_PROXIMITY_OUT:
-         gtk_propagate_event (grab_widget, event);
-         break;
-         
-       case GDK_ENTER_NOTIFY:
-         if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
-           {
-             gtk_widget_event (grab_widget, event);
-             if (event_widget == grab_widget)
-               GTK_PRIVATE_SET_FLAG (event_widget, GTK_LEAVE_PENDING);
-           }
-         break;
-         
-       case GDK_LEAVE_NOTIFY:
-         if (GTK_WIDGET_LEAVE_PENDING (event_widget))
-           {
-             GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_LEAVE_PENDING);
-             gtk_widget_event (event_widget, event);
-           }
-         else if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
-           gtk_widget_event (grab_widget, event);
-         break;
-
-       case GDK_DRAG_STATUS:
-       case GDK_DROP_FINISHED:
-         gtk_drag_source_handle_event (event_widget, event);
-         break;
-       case GDK_DRAG_ENTER:
-       case GDK_DRAG_LEAVE:
-       case GDK_DRAG_MOTION:
-       case GDK_DROP_START:
-         gtk_drag_dest_handle_event (event_widget, event);
-         break;
        }
+      else if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
+       gtk_widget_event (grab_widget, event);
+      break;
       
-      tmp_list = current_events;
-      current_events = g_list_remove_link (current_events, tmp_list);
-      g_list_free_1 (tmp_list);
-      
-      gdk_event_free (event);
+    case GDK_DRAG_STATUS:
+    case GDK_DROP_FINISHED:
+      gtk_drag_source_handle_event (event_widget, event);
+      break;
+    case GDK_DRAG_ENTER:
+    case GDK_DRAG_LEAVE:
+    case GDK_DRAG_MOTION:
+    case GDK_DROP_START:
+      gtk_drag_dest_handle_event (event_widget, event);
+      break;
     }
-  else
-    {
-      if (gdk_events_pending() == 0)
-       gtk_handle_idles ();
-    }
-  
-event_handling_done:
   
-  /* Handle timeout functions that may have expired.
-   */
-  gtk_handle_timeouts ();
-  
-  if (iteration_done)
-    gdk_flush ();
-  
-  return iteration_done;
+  tmp_list = current_events;
+  current_events = g_list_remove_link (current_events, tmp_list);
+  g_list_free_1 (tmp_list);
 }
 
 gint
@@ -1034,119 +953,6 @@ gtk_invoke_key_snoopers (GtkWidget *grab_widget,
   return return_val;
 }
 
-guint
-gtk_timeout_add_full (guint32           interval,
-                     GtkFunction        function,
-                     GtkCallbackMarshal marshal,
-                     gpointer           data,
-                     GtkDestroyNotify   destroy)
-{
-  static guint timeout_tag = 1;
-  GtkTimeoutFunction *timeoutf;
-  
-  g_return_val_if_fail ((function != NULL) || (marshal != NULL), 0);
-
-  /* Create a new timeout function structure.
-   * The start time is the current time.
-   */
-  if (!timeout_mem_chunk)
-    timeout_mem_chunk = g_mem_chunk_new ("timeout mem chunk", sizeof (GtkTimeoutFunction),
-                                        1024, G_ALLOC_AND_FREE);
-  
-  timeoutf = g_chunk_new (GtkTimeoutFunction, timeout_mem_chunk);
-  
-  timeoutf->tag = timeout_tag++;
-  timeoutf->start = gdk_time_get ();
-  timeoutf->interval = interval;
-  timeoutf->originterval = interval;
-  timeoutf->function = function;
-  timeoutf->marshal = marshal;
-  timeoutf->data = data;
-  timeoutf->destroy = destroy;
-  
-  gtk_timeout_insert (timeoutf);
-  
-  return timeoutf->tag;
-}
-
-static void
-gtk_timeout_destroy (GtkTimeoutFunction *timeoutf)
-{
-  if (timeoutf->destroy)
-    (timeoutf->destroy) (timeoutf->data);
-  g_mem_chunk_free (timeout_mem_chunk, timeoutf);
-}
-
-guint
-gtk_timeout_add (guint32     interval,
-                GtkFunction function,
-                gpointer    data)
-{
-  return gtk_timeout_add_full (interval, function, FALSE, data, NULL);
-}
-
-guint
-gtk_timeout_add_interp (guint32                   interval,
-                       GtkCallbackMarshal function,
-                       gpointer           data,
-                       GtkDestroyNotify   destroy)
-{
-  g_message ("gtk_timeout_add_interp() is deprecated");
-  return gtk_timeout_add_full (interval, NULL, function, data, destroy);
-}
-
-/* Search for the specified tag in a list of timeouts. If it
- * is found, destroy the timeout, and either remove the link
- * or set link->data to NULL depending on remove_link
- */
-static gint
-gtk_timeout_remove_from_list (GList **list, guint tag, gint remove_link)
-{
-  GList *tmp_list;
-  GtkTimeoutFunction *timeoutf;
-
-  tmp_list = *list;
-  while (tmp_list)
-    {
-      timeoutf = tmp_list->data;
-      
-      if (timeoutf->tag == tag)
-       {
-         if (remove_link)
-           {
-             *list = g_list_remove_link (*list, tmp_list);
-             g_list_free (tmp_list);
-           }
-         else
-           tmp_list->data = NULL;
-
-         gtk_timeout_destroy (timeoutf);
-         
-         return TRUE;
-       }
-      
-      tmp_list = tmp_list->next;
-    }
-  return FALSE;
-}
-
-void
-gtk_timeout_remove (guint tag)
-{
-  
-  /* Remove a timeout function.
-   * (Which, basically, involves searching the
-   *  list for the tag).
-   */
-
-  if (gtk_timeout_remove_from_list (&timeout_functions, tag, TRUE))
-    return;
-  if (gtk_timeout_remove_from_list (&current_timeouts, tag, TRUE))
-    return;
-  if (gtk_timeout_remove_from_list (&running_timeouts, tag, FALSE))
-    return;
-}
-
 guint
 gtk_quit_add_full (guint               main_level,
                   GtkFunction          function,
@@ -1177,297 +983,12 @@ gtk_quit_add_full (guint                main_level,
   return quitf->id;
 }
 
-gint
-gtk_idle_compare (GHook *new_g_hook,
-                 GHook *g_sibling)
+static void
+gtk_quit_destroy (GtkQuitFunction *quitf)
 {
-  GtkIdleHook *new_hook = GTK_IDLE_HOOK (new_g_hook);
-  GtkIdleHook *sibling = GTK_IDLE_HOOK (g_sibling);
-  
-  /* We add an extra +1 to the comparision result to make sure
-   * that we get inserted at the end of the list of hooks with
-   * the same priority.
-   */
-  return new_hook->priority - sibling->priority + 1;
-}
-
-guint
-gtk_idle_add_full (gint                        priority,
-                  GtkFunction          function,
-                  GtkCallbackMarshal   marshal,
-                  gpointer             data,
-                  GtkDestroyNotify     destroy)
-{
-  GHook *hook;
-  GtkIdleHook *ihook;
-
-  if (function)
-    g_return_val_if_fail (marshal == NULL, 0);
-  else
-    g_return_val_if_fail (marshal != NULL, 0);
-
-  if (!idle_hooks.seq_id)
-    g_hook_list_init (&idle_hooks, sizeof (GtkIdleHook));
-
-  hook = g_hook_alloc (&idle_hooks);
-  ihook = GTK_IDLE_HOOK (hook);
-  hook->data = data;
-  if (marshal)
-    {
-      hook->flags |= GTK_HOOK_MARSHAL;
-      hook->func = marshal;
-    }
-  else
-    hook->func = function;
-  hook->destroy = destroy;
-  ihook->priority = priority;
-
-  /* If we are adding the first idle function, possibly wake up
-   * the main thread out of its select().
-   */
-  if (!g_hook_first_valid (&idle_hooks, TRUE))
-    gdk_threads_wake ();
-
-  g_hook_insert_sorted (&idle_hooks, hook, gtk_idle_compare);
-  
-  return hook->hook_id;
-}
-
-guint
-gtk_idle_add (GtkFunction function,
-             gpointer    data)
-{
-  return gtk_idle_add_full (GTK_PRIORITY_DEFAULT, function, NULL, data, NULL);
-}
-
-guint      
-gtk_idle_add_priority  (gint               priority,
-                        GtkFunction        function,
-                        gpointer           data)
-{
-  return gtk_idle_add_full (priority, function, NULL, data, NULL);
-}
-
-guint
-gtk_idle_add_interp  (GtkCallbackMarshal   marshal,
-                     gpointer             data,
-                     GtkDestroyNotify     destroy)
-{
-  g_message ("gtk_idle_add_interp() is deprecated");
-  return gtk_idle_add_full (GTK_PRIORITY_DEFAULT, NULL, marshal, data, destroy);
-}
-
-void
-gtk_idle_remove (guint tag)
-{
-  g_return_if_fail (tag > 0);
-
-  if (!g_hook_destroy (&idle_hooks, tag))
-    g_warning ("gtk_idle_remove(%d): no such idle function", tag);
-}
-
-void
-gtk_idle_remove_by_data (gpointer data)
-{
-  GHook *hook;
-
-  hook = g_hook_find_data (&idle_hooks, TRUE, data);
-  if (hook)
-    g_hook_destroy_link (&idle_hooks, hook);
-  else
-    g_warning ("gtk_idle_remove_by_data(%p): no such idle function", data);
-}
-
-static gboolean
-gtk_finish_idles (void)
-{
-  gboolean idles_called;
-
-  idles_called = FALSE;
-  while (last_idle)
-    {
-      GHook *hook;
-
-      hook = g_hook_next_valid (last_idle, FALSE);
-
-      if (!hook || GTK_IDLE_HOOK (hook)->priority != GTK_IDLE_HOOK (last_idle)->priority)
-       {
-         g_hook_unref (&idle_hooks, last_idle);
-         last_idle = NULL;
-       }
-      else
-       {
-         g_hook_unref (&idle_hooks, last_idle);
-         last_idle = hook;
-         g_hook_ref (&idle_hooks, last_idle);
-
-         idles_called = TRUE;
-         gtk_invoke_hook (&idle_hooks, last_idle);
-       }
-    }
-
-  return idles_called;
-}
-
-static void
-gtk_handle_idles (void)
-{
-  GHook *hook;
-
-  /* Caller must already have called gtk_finish_idles() if necessary
-   */
-  g_assert (last_idle == NULL);
-
-  hook = g_hook_first_valid (&idle_hooks, FALSE);
-
-  if (hook)
-    {
-      last_idle = hook;
-      g_hook_ref (&idle_hooks, last_idle);
-
-      gtk_invoke_hook (&idle_hooks, last_idle);
-
-      gtk_finish_idles ();
-    }
-}
-
-static void
-gtk_invoke_hook (GHookList *hook_list,
-                GHook     *hook)
-{
-  gboolean keep_alive;
-
-  if (hook->flags & GTK_HOOK_MARSHAL)
-    {
-      GtkArg args[1];
-      register GtkCallbackMarshal marshal;
-
-      keep_alive = FALSE;
-      args[0].name = NULL;
-      args[0].type = GTK_TYPE_BOOL;
-      GTK_VALUE_POINTER (args[0]) = &keep_alive;
-      marshal = hook->func;
-      marshal (NULL, hook->data, 0, args);
-    }
-  else
-    {
-      register GtkFunction func;
-
-      func = hook->func;
-      keep_alive = func (hook->data);
-    }
-  if (!keep_alive)
-    g_hook_destroy_link (hook_list, hook);
-}
-
-static gint
-gtk_invoke_timeout_function (GtkTimeoutFunction *timeoutf)
-{
-  if (!timeoutf->marshal)
-    return timeoutf->function (timeoutf->data);
-  else
-    {
-      GtkArg args[1];
-      gint ret_val = FALSE;
-      args[0].name = NULL;
-      args[0].type = GTK_TYPE_BOOL;
-      args[0].d.pointer_data = &ret_val;
-      timeoutf->marshal (NULL, timeoutf->data,  0, args);
-      return ret_val;
-    }
-}
-
-static void
-gtk_handle_current_timeouts (guint32 the_time)
-{
-  gint result;
-  GList *tmp_list;
-  GtkTimeoutFunction *timeoutf;
-  
-  while (current_timeouts)
-    {
-      tmp_list = current_timeouts;
-      timeoutf = tmp_list->data;
-      
-      current_timeouts = g_list_remove_link (current_timeouts, tmp_list);
-      if (running_timeouts)
-       {
-         running_timeouts->prev = tmp_list;
-         tmp_list->next = running_timeouts;
-       }
-      running_timeouts = tmp_list;
-      
-      result = gtk_invoke_timeout_function (timeoutf);
-
-      running_timeouts = g_list_remove_link (running_timeouts, tmp_list);
-      timeoutf = tmp_list->data;
-      
-      g_list_free_1 (tmp_list);
-
-      if (timeoutf)
-       {
-         if (!result)
-           {
-             gtk_timeout_destroy (timeoutf);
-           }
-         else
-           {
-             timeoutf->interval = timeoutf->originterval;
-             timeoutf->start = the_time;
-             gtk_timeout_insert (timeoutf);
-           }
-       }
-    }
-}
-
-static void
-gtk_handle_timeouts (void)
-{
-  guint32 the_time;
-  GList *tmp_list;
-  GList *tmp_list2;
-  GtkTimeoutFunction *timeoutf;
-  
-  /* Caller must already have called gtk_handle_current_timeouts if
-   * necessary */
-  g_assert (current_timeouts == NULL);
-  
-  if (timeout_functions)
-    {
-      the_time = gdk_time_get ();
-      
-      tmp_list = timeout_functions;
-      while (tmp_list)
-       {
-         timeoutf = tmp_list->data;
-         
-         if (timeoutf->interval <= (the_time - timeoutf->start))
-           {
-             tmp_list2 = tmp_list;
-             tmp_list = tmp_list->next;
-             
-             timeout_functions = g_list_remove_link (timeout_functions, tmp_list2);
-             current_timeouts = g_list_concat (current_timeouts, tmp_list2);
-           }
-         else
-           {
-             timeoutf->interval -= (the_time - timeoutf->start);
-             timeoutf->start = the_time;
-             tmp_list = tmp_list->next;
-           }
-       }
-      
-      if (current_timeouts)
-       gtk_handle_current_timeouts (the_time);
-    }
-}
-
-static void
-gtk_quit_destroy (GtkQuitFunction *quitf)
-{
-  if (quitf->destroy)
-    quitf->destroy (quitf->data);
-  g_mem_chunk_free (quit_mem_chunk, quitf);
+  if (quitf->destroy)
+    quitf->destroy (quitf->data);
+  g_mem_chunk_free (quit_mem_chunk, quitf);
 }
 
 static gint
@@ -1555,54 +1076,120 @@ gtk_quit_remove_by_data (gpointer data)
     }
 }
 
-static void
-gtk_invoke_input_function (GtkInputFunction *input,
-                          gint source,
-                          GdkInputCondition condition)
+guint
+gtk_timeout_add_full (guint32           interval,
+                     GtkFunction        function,
+                     GtkCallbackMarshal marshal,
+                     gpointer           data,
+                     GtkDestroyNotify   destroy)
 {
-  GtkArg args[3];
-  args[0].type = GTK_TYPE_INT;
-  args[0].name = NULL;
-  GTK_VALUE_INT(args[0]) = source;
-  args[1].type = GTK_TYPE_GDK_INPUT_CONDITION;
-  args[1].name = NULL;
-  GTK_VALUE_FLAGS(args[1]) = condition;
-  args[2].type = GTK_TYPE_NONE;
-  args[2].name = NULL;
+  if (marshal)
+    {
+      GtkClosure *closure;
+
+      closure = g_new (GtkClosure, 1);
+      closure->marshal = marshal;
+      closure->data = data;
+      closure->destroy = destroy;
+
+      return g_timeout_add_full (0, interval, 
+                                gtk_invoke_idle_timeout,
+                                closure,
+                                gtk_destroy_closure);
+    }
+  else
+    return g_timeout_add_full (0, interval, function, data, destroy);
+}
 
-  input->callback (NULL, input->data, 2, args);
+guint
+gtk_timeout_add (guint32     interval,
+                GtkFunction function,
+                gpointer    data)
+{
+  return g_timeout_add_full (0, interval, function, data, NULL);
 }
 
-static void
-gtk_destroy_input_function (GtkInputFunction *input)
+void
+gtk_timeout_remove (guint tag)
 {
-  if (input->destroy)
-    (input->destroy) (input->data);
-  g_free (input);
+  g_source_remove (tag);
 }
 
 guint
-gtk_input_add_full (gint source,
-                   GdkInputCondition condition,
-                   GdkInputFunction function,
-                   GtkCallbackMarshal marshal,
-                   gpointer data,
-                   GtkDestroyNotify destroy)
+gtk_idle_add_full (gint                        priority,
+                  GtkFunction          function,
+                  GtkCallbackMarshal   marshal,
+                  gpointer             data,
+                  GtkDestroyNotify     destroy)
 {
   if (marshal)
     {
-      GtkInputFunction *input;
+      GtkClosure *closure;
+
+      closure = g_new (GtkClosure, 1);
+      closure->marshal = marshal;
+      closure->data = data;
+      closure->destroy = destroy;
 
-      input = g_new (GtkInputFunction, 1);
-      input->callback = marshal;
-      input->data = data;
-      input->destroy = destroy;
+      return g_idle_add_full (priority,
+                             gtk_invoke_idle_timeout,
+                             closure,
+                             gtk_destroy_closure);
+    }
+  else
+    return g_idle_add_full (priority, function, data, destroy);
+}
+
+guint
+gtk_idle_add (GtkFunction function,
+             gpointer    data)
+{
+  return g_idle_add_full (GTK_PRIORITY_DEFAULT, function, data, NULL);
+}
+
+guint      
+gtk_idle_add_priority  (gint               priority,
+                        GtkFunction        function,
+                        gpointer           data)
+{
+  return g_idle_add_full (priority, function, data, NULL);
+}
+
+void
+gtk_idle_remove (guint tag)
+{
+  g_source_remove (tag);
+}
+
+void
+gtk_idle_remove_by_data (gpointer data)
+{
+  if (!g_idle_remove_by_data (data))
+    g_warning ("gtk_idle_remove_by_data(%p): no such idle", data);
+}
+
+guint
+gtk_input_add_full (gint               source,
+                   GdkInputCondition   condition,
+                   GdkInputFunction    function,
+                   GtkCallbackMarshal  marshal,
+                   gpointer            data,
+                   GtkDestroyNotify    destroy)
+{
+  if (marshal)
+    {
+      GtkClosure *closure;
+
+      closure = g_new (GtkClosure, 1);
+      closure->marshal = marshal;
+      closure->data = data;
+      closure->destroy = destroy;
 
       return gdk_input_add_full (source,
                                 condition,
-                                (GdkInputFunction) gtk_invoke_input_function,
-                                input,
-                                (GdkDestroyNotify) gtk_destroy_input_function);
+                                (GdkInputFunction) gtk_invoke_input,
+                                closure,
+                                (GdkDestroyNotify) gtk_destroy_closure);
     }
   else
     return gdk_input_add_full (source, condition, function, data, destroy);
@@ -1611,10 +1198,54 @@ gtk_input_add_full (gint source,
 void
 gtk_input_remove (guint tag)
 {
-  gdk_input_remove (tag);
+  g_source_remove (tag);
+}
+
+static void
+gtk_destroy_closure (gpointer data)
+{
+  GtkClosure *closure = data;
+
+  if (closure->destroy)
+    (closure->destroy) (closure->data);
+  g_free (closure);
+}
+
+static gboolean
+gtk_invoke_idle_timeout (gpointer data)
+{
+  GtkClosure *closure = data;
+
+  GtkArg args[1];
+  gint ret_val = FALSE;
+  args[0].name = NULL;
+  args[0].type = GTK_TYPE_BOOL;
+  args[0].d.pointer_data = &ret_val;
+  closure->marshal (NULL, closure->data,  0, args);
+  return ret_val;
 }
 
-GdkEvent *
+static void
+gtk_invoke_input (gpointer         data,
+                 gint              source,
+                 GdkInputCondition condition)
+{
+  GtkClosure *closure = data;
+
+  GtkArg args[3];
+  args[0].type = GTK_TYPE_INT;
+  args[0].name = NULL;
+  GTK_VALUE_INT(args[0]) = source;
+  args[1].type = GTK_TYPE_GDK_INPUT_CONDITION;
+  args[1].name = NULL;
+  GTK_VALUE_FLAGS(args[1]) = condition;
+  args[2].type = GTK_TYPE_NONE;
+  args[2].name = NULL;
+
+  closure->marshal (NULL, closure->data, 2, args);
+}
+
+GdkEvent*
 gtk_get_current_event (void)
 {
   if (current_events)
@@ -1646,30 +1277,6 @@ gtk_exit_func (void)
 }
 
 
-/* We rely on some knowledge of how g_list_insert_sorted works to make
- * sure that we insert after timeouts of equal interval
- */
-static gint
-gtk_timeout_compare (gconstpointer a, gconstpointer b)
-{
-  return (((const GtkTimeoutFunction *)a)->interval < 
-         ((const GtkTimeoutFunction *)b)->interval)
-    ? -1 : 1;
-}
-
-static void
-gtk_timeout_insert (GtkTimeoutFunction *timeoutf)
-{
-  g_assert (timeoutf != NULL);
-  
-  /* Insert the timeout function appropriately.
-   * Appropriately meaning sort it into the list
-   *  of timeout functions.
-   */
-  timeout_functions = g_list_insert_sorted (timeout_functions, timeoutf,
-                                           gtk_timeout_compare);
-}
-
 static gint
 gtk_quit_invoke_function (GtkQuitFunction *quitf)
 {
@@ -1690,36 +1297,14 @@ gtk_quit_invoke_function (GtkQuitFunction *quitf)
     }
 }
 
-static void
-gtk_handle_timer (void)
-{
-  GtkTimeoutFunction *timeoutf;
-  
-  if (g_hook_first_valid (&idle_hooks, FALSE))
-    {
-      gdk_timer_set (0);
-      gdk_timer_enable ();
-    }
-  else if (timeout_functions)
-    {
-      timeoutf = timeout_functions->data;
-      gdk_timer_set (timeoutf->interval);
-      gdk_timer_enable ();
-    }
-  else
-    {
-      gdk_timer_set (0);
-      gdk_timer_disable ();
-    }
-}
-
-static void
+void
 gtk_propagate_event (GtkWidget *widget,
                     GdkEvent  *event)
 {
   gint handled_event;
   
   g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_WIDGET (widget));
   g_return_if_fail (event != NULL);
   
   handled_event = FALSE;
@@ -1734,7 +1319,7 @@ gtk_propagate_event (GtkWidget *widget,
        */
       GtkWidget *window;
 
-      window = gtk_widget_get_ancestor (widget, gtk_window_get_type ());
+      window = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
       if (window)
         {
          if (GTK_WIDGET_IS_SENSITIVE (window))
@@ -1760,7 +1345,6 @@ gtk_propagate_event (GtkWidget *widget,
     }
 }
 
-
 #if 0
 static void
 gtk_error (gchar *str)