+// One-shot signal emission hook, to install idle handler.
+extern "C" {
+static gboolean
+wx_emission_hook(GSignalInvocationHint*, guint, const GValue*, gpointer data)
+{
+ wxApp* app = wxTheApp;
+ if (app != NULL)
+ app->WakeUpIdle();
+ bool* hook_installed = (bool*)data;
+ // record that hook is not installed
+ *hook_installed = false;
+ // remove hook
+ return false;
+}
+}
+
+// Add signal emission hooks, to re-install idle handler when needed.
+static void wx_add_idle_hooks()
+{
+ // "event" hook
+ {
+ static bool hook_installed;
+ if (!hook_installed)
+ {
+ static guint sig_id;
+ if (sig_id == 0)
+ sig_id = g_signal_lookup("event", GTK_TYPE_WIDGET);
+ hook_installed = true;
+ g_signal_add_emission_hook(
+ sig_id, 0, wx_emission_hook, &hook_installed, NULL);
+ }
+ }
+ // "size_allocate" hook
+ // Needed to match the behaviour of the old idle system,
+ // but probably not necessary.
+ {
+ static bool hook_installed;
+ if (!hook_installed)
+ {
+ static guint sig_id;
+ if (sig_id == 0)
+ sig_id = g_signal_lookup("size_allocate", GTK_TYPE_WIDGET);
+ hook_installed = true;
+ g_signal_add_emission_hook(
+ sig_id, 0, wx_emission_hook, &hook_installed, NULL);
+ }
+ }
+}
+
+extern "C" {
+static gboolean wxapp_idle_callback(gpointer)
+{
+ return wxTheApp->DoIdle();
+}
+}
+
+bool wxApp::DoIdle()
+{
+ guint id_save;
+ {
+ // Allow another idle source to be added while this one is busy.
+ // Needed if an idle event handler runs a new event loop,
+ // for example by showing a dialog.
+#if wxUSE_THREADS
+ wxMutexLocker lock(m_idleMutex);
+#endif
+ id_save = m_idleSourceId;
+ m_idleSourceId = 0;
+ wx_add_idle_hooks();
+
+#if wxDEBUG_LEVEL
+ // don't generate the idle events while the assert modal dialog is shown,
+ // this matches the behaviour of wxMSW
+ if (m_isInAssert)
+ return false;
+#endif
+ }
+
+ gdk_threads_enter();
+ bool needMore;
+ do {
+ ProcessPendingEvents();
+
+ needMore = ProcessIdle();
+ } while (needMore && gtk_events_pending() == 0);
+ gdk_threads_leave();
+
+#if wxUSE_THREADS
+ wxMutexLocker lock(m_idleMutex);
+#endif
+ // if a new idle source was added during ProcessIdle
+ if (m_idleSourceId != 0)
+ {
+ // remove it
+ g_source_remove(m_idleSourceId);
+ m_idleSourceId = 0;
+ }
+
+ // Pending events can be added asynchronously,
+ // need to keep idle source if any have appeared
+ if (HasPendingEvents())
+ needMore = true;
+
+ // if more idle processing requested
+ if (needMore)
+ {
+ // keep this source installed
+ m_idleSourceId = id_save;
+ return true;
+ }
+ // add hooks and remove this source
+ wx_add_idle_hooks();
+ return false;
+}