Index: gtk/gtkmain.c
===================================================================
--- gtk/gtkmain.c	(revision 17288)
+++ gtk/gtkmain.c	(working copy)
@@ -1132,9 +1132,11 @@
 
   if (g_main_loop_is_running (main_loops->data))
     {
+      gdk_set_main_thread_libgtk_only (g_thread_self ());
       GDK_THREADS_LEAVE ();
       g_main_loop_run (loop);
       GDK_THREADS_ENTER ();
+      gdk_set_main_thread_libgtk_only (NULL);
       gdk_flush ();
     }
 
Index: gdk/gdk.c
===================================================================
--- gdk/gdk.c	(revision 17288)
+++ gdk/gdk.c	(working copy)
@@ -61,6 +61,7 @@
 static int gdk_initialized = 0;			    /* 1 if the library is initialized,
 						     * 0 otherwise.
 						     */
+static GThread *gdk_main_thread;
 
 static gchar  *gdk_progclass = NULL;
 
@@ -682,7 +683,76 @@
                                        interval, function, data, NULL);
 }
 
+static gboolean
+gdk_main_thread_dispatch (gpointer data)
+{
+  GdkThreadsDispatch *dispatch = data;
 
+  GDK_THREADS_ENTER ();
+
+  if (!g_source_is_destroyed (g_main_current_source ()))
+    dispatch->func (dispatch->data);
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+/**
+ * gdk_main_thread_do:
+ * @function: callback function
+ * @user:     data passed to the callback function
+ * @notify:   function to call after the callback is removed or %NULL
+ *
+ * Execute the callback in the main thread.
+ * If the current thread is not the main thread, as defined by the one
+ * that is currently processing gtk_main(),
+ * then the callback is scheduled for execution in an idle handler.
+ *
+ * Return value: 0 if the callback was executed synchronously,
+ * otherwise the id of the idle event source.
+ *
+ * Since: 2.12
+ **/
+guint
+gdk_main_thread_do (GFunc function,
+		    gpointer data,
+		    GDestroyNotify notify)
+{
+  guint retval = 0;
+
+  g_return_if_fail (fn != NULL);
+
+  if (g_thread_self () == gdk_main_thread)
+    {
+      fn (data);
+      if (notify && data)
+	notify (data);
+    }
+  else
+    {
+      GdkThreadsDispatch *dispatch;
+      dispatch = g_slice_new (GdkThreadsDispatch);
+      dispatch->func = function;
+      dispatch->data = data;
+      dispatch->destroy = notify;
+
+      retval = g_idle_add_full (G_PRIORITY_DEFAULT,
+			        gdk_main_thread_dispatch,
+			        dispatch,
+			        gdk_threads_dispatch_free);
+    }
+
+  return retval;
+}
+
+void
+gdk_set_main_thread_libgtk_only (GThread *thread)
+{
+  gdk_main_thread = thread;
+}
+
+
 G_CONST_RETURN char *
 gdk_get_program_class (void)
 {
Index: gdk/gdk.h
===================================================================
--- gdk/gdk.h	(revision 17288)
+++ gdk/gdk.h	(working copy)
@@ -207,6 +207,10 @@
 guint    gdk_threads_add_timeout          (guint          interval,
                                            GSourceFunc    function,
                                            gpointer       data);
+guint    gdk_main_thread_do               (GFunc function,
+                                           gpointer data,
+                                           GDestroyNotify notify);
+void     gdk_set_main_thread_libgtk_only  (GThread *thread);
 
 #ifdef	G_THREADS_ENABLED
 #  define GDK_THREADS_ENTER()	G_STMT_START {	\
Index: gdk/gdk.symbols
===================================================================
--- gdk/gdk.symbols	(revision 17288)
+++ gdk/gdk.symbols	(working copy)
@@ -138,6 +138,8 @@
 gdk_threads_add_idle_full
 gdk_threads_add_timeout
 gdk_threads_add_timeout_full
+gdk_main_thread_do
+gdk_set_main_thread_libgtk_only
 #endif
 #endif
 
