#include "wx/image.h"
#if wxUSE_THREADS
-#include "wx/thread.h"
+ #include "wx/thread.h"
#endif
#include <unistd.h>
extern bool g_isIdle;
-bool g_mainThreadLocked = FALSE;
+bool g_mainThreadLocked = FALSE;
+gint g_pendingTag = 0;
-GtkWidget *wxRootWindow = (GtkWidget*) NULL;
+static GtkWidget *gs_RootWindow = (GtkWidget*) NULL;
//-----------------------------------------------------------------------------
// local functions
/* forward declaration */
gint wxapp_idle_callback( gpointer WXUNUSED(data) );
+gint wxapp_pending_callback( gpointer WXUNUSED(data) );
void wxapp_install_idle_handler();
#if wxUSE_THREADS
// wxYield
//-----------------------------------------------------------------------------
+static bool gs_inYield = FALSE;
+
bool wxYield()
{
- bool has_idle = (wxTheApp->m_idleTag != 0);
+#if wxUSE_THREADS
+ if ( !wxThread::IsMain() )
+ {
+ // can't call gtk_main_iteration() from other threads like this
+ return TRUE;
+ }
+#endif // wxUSE_THREADS
- if (has_idle)
+#ifdef __WXDEBUG__
+ if (gs_inYield)
+ wxFAIL_MSG( wxT("wxYield called recursively" ) );
+#endif
+
+ gs_inYield = TRUE;
+
+ if (!g_isIdle)
{
- /* We need to temporarily remove idle callbacks or the loop will
- never finish. */
+ // We need to remove idle callbacks or the loop will
+ // never finish.
gtk_idle_remove( wxTheApp->m_idleTag );
wxTheApp->m_idleTag = 0;
+ g_isIdle = TRUE;
}
while (gtk_events_pending())
gtk_main_iteration();
- if (has_idle)
- {
- /* re-add idle handler */
- wxTheApp->m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
- }
+ // disable log flushing from here because a call to wxYield() shouldn't
+ // normally result in message boxes popping up &c
+ wxLog::Suspend();
/* it's necessary to call ProcessIdle() to update the frames sizes which
might have been changed (it also will update other things set from
OnUpdateUI() which is a nice (and desired) side effect) */
while (wxTheApp->ProcessIdle()) { }
+ // let the logs be flashed again
+ wxLog::Resume();
+
+ gs_inYield = FALSE;
+
return TRUE;
}
+//-----------------------------------------------------------------------------
+// wxYieldIfNeeded
+// Like wxYield, but fails silently if the yield is recursive.
+//-----------------------------------------------------------------------------
+
+bool wxYieldIfNeeded()
+{
+ if (gs_inYield)
+ return FALSE;
+
+ return wxYield();
+}
+
//-----------------------------------------------------------------------------
// wxWakeUpIdle
//-----------------------------------------------------------------------------
// local functions
//-----------------------------------------------------------------------------
-gint wxapp_idle_callback( gpointer WXUNUSED(data) )
+gint wxapp_pending_callback( gpointer WXUNUSED(data) )
{
if (!wxTheApp) return TRUE;
// thread so we must lock it here ourselves
gdk_threads_enter();
- /* we don't want any more idle events until the next event is
- sent to wxGTK */
- gtk_idle_remove( wxTheApp->m_idleTag );
- wxTheApp->m_idleTag = 0;
+ // Sent idle event to all who request them
+ wxTheApp->ProcessPendingEvents();
+
+ g_pendingTag = 0;
+
+ /* flush the logged messages if any */
+#if wxUSE_LOG
+ wxLog::FlushActive();
+#endif // wxUSE_LOG
+
+ // Release lock again
+ gdk_threads_leave();
+
+ // Return FALSE to indicate that no more idle events are
+ // to be sent (single shot instead of continuous stream)
+ return FALSE;
+}
+
+gint wxapp_idle_callback( gpointer WXUNUSED(data) )
+{
+ if (!wxTheApp) return TRUE;
- /* indicate that we are now in idle mode - even so deeply
+ // when getting called from GDK's time-out handler
+ // we are no longer within GDK's grab on the GUI
+ // thread so we must lock it here ourselves
+ gdk_threads_enter();
+
+ /* Indicate that we are now in idle mode - even so deeply
in idle mode that we don't get any idle events anymore.
this is like wxMSW where an idle event is sent only
once each time after the event queue has been completely
emptied */
g_isIdle = TRUE;
+ wxTheApp->m_idleTag = 0;
- /* sent idle event to all who request them */
+ // Sent idle event to all who request them
while (wxTheApp->ProcessIdle()) { }
- // release lock again
+ // Release lock again
gdk_threads_leave();
- return TRUE;
+ // Return FALSE to indicate that no more idle events are
+ // to be sent (single shot instead of continuous stream)
+ return FALSE;
}
void wxapp_install_idle_handler()
{
wxASSERT_MSG( wxTheApp->m_idleTag == 0, wxT("attempt to install idle handler twice") );
+ g_isIdle = FALSE;
+
+ if (g_pendingTag == 0)
+ g_pendingTag = gtk_idle_add_priority( 900, wxapp_pending_callback, (gpointer) NULL );
+
/* This routine gets called by all event handlers
indicating that the idle is over. It may also
get called from other thread for sending events
to the main thread (and processing these in
- idle time). */
+ idle time). Very low priority. */
- wxTheApp->m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
-
- g_isIdle = FALSE;
+ wxTheApp->m_idleTag = gtk_idle_add_priority( 1000, wxapp_idle_callback, (gpointer) NULL );
}
#if wxUSE_THREADS
+static int g_threadUninstallLevel = 0;
+
void wxapp_install_thread_wakeup()
{
+ g_threadUninstallLevel++;
+
+ if (g_threadUninstallLevel != 1) return;
+
if (wxTheApp->m_wakeUpTimerTag) return;
wxTheApp->m_wakeUpTimerTag = gtk_timeout_add( 50, wxapp_wakeup_timerout_callback, (gpointer) NULL );
void wxapp_uninstall_thread_wakeup()
{
+ g_threadUninstallLevel--;
+
+ if (g_threadUninstallLevel != 0) return;
+
if (!wxTheApp->m_wakeUpTimerTag) return;
gtk_timeout_remove( wxTheApp->m_wakeUpTimerTag );
m_topWindow = (wxWindow *) NULL;
m_exitOnFrameDelete = TRUE;
- m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
+ m_idleTag = 0;
+ wxapp_install_idle_handler();
#if wxUSE_THREADS
m_wakeUpTimerTag = 0;
if ((gdk_visual_get_best() != gdk_visual_get_system()) &&
(m_useBestVisual))
{
+#ifdef __WXGTK20__
+ /* seems gtk_widget_set_default_visual no longer exists? */
+ GdkVisual* vis = gtk_widget_get_default_visual();
+#else
GdkVisual* vis = gdk_visual_get_best();
gtk_widget_set_default_visual( vis );
+#endif
GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
gtk_widget_set_default_colormap( colormap );
event.RequestMore(TRUE);
s_inOnIdle = FALSE;
-
- /* flush the logged messages if any */
-#if wxUSE_LOG
- wxLog *log = wxLog::GetActiveTarget();
- if (log != NULL && log->HasPendingMessages())
- log->Flush();
-#endif // wxUSE_LOG
}
bool wxApp::SendIdleEvents()
wxIdleEvent event;
event.SetEventObject(win);
- win->ProcessEvent(event);
+ win->GetEventHandler()->ProcessEvent(event);
win->OnInternalIdle();
// check for memory leaks
#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
- if (wxDebugContext::CountObjectsLeft() > 0)
+ if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
{
wxLogDebug(wxT("There were memory leaks.\n"));
wxDebugContext::Dump();
#endif // wxUSE_LOG
}
+//-----------------------------------------------------------------------------
+// Access to the root window global
+//-----------------------------------------------------------------------------
+
+GtkWidget* wxGetRootWindow()
+{
+ if (gs_RootWindow == NULL) {
+ gs_RootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
+ gtk_widget_realize( gs_RootWindow );
+ }
+ return gs_RootWindow;
+}
+
//-----------------------------------------------------------------------------
// wxEntry
//-----------------------------------------------------------------------------
-int wxEntry( int argc, char *argv[] )
+
+int wxEntryStart( int argc, char *argv[] )
{
#if wxUSE_THREADS
/* GTK 1.2 up to version 1.2.3 has broken threads */
- if ((gtk_major_version == 1) &&
+ if ((gtk_major_version == 1) &&
(gtk_minor_version == 2) &&
(gtk_micro_version < 4))
{
gtk_set_locale();
+ // We should have the wxUSE_WCHAR_T test on the _outside_
#if wxUSE_WCHAR_T
+#if defined(__WXGTK20__)
+ // gtk+ 2.0 supports Unicode through UTF-8 strings
+ wxConvCurrent = &wxConvUTF8;
+#else
if (!wxOKlibc()) wxConvCurrent = &wxConvLocal;
+#endif
#else
if (!wxOKlibc()) wxConvCurrent = (wxMBConv*) NULL;
#endif
return -1;
}
+ return 0;
+}
+
+
+int wxEntryInitGui()
+{
+ int retValue = 0;
+
+ if ( !wxTheApp->OnInitGui() )
+ retValue = -1;
+
+ wxGetRootWindow();
+
+ return retValue;
+}
+
+
+void wxEntryCleanup()
+{
+#if wxUSE_LOG
+ // flush the logged messages if any
+ wxLog *log = wxLog::GetActiveTarget();
+ if (log != NULL && log->HasPendingMessages())
+ log->Flush();
+
+ // continuing to use user defined log target is unsafe from now on because
+ // some resources may be already unavailable, so replace it by something
+ // more safe
+ wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
+ if ( oldlog )
+ delete oldlog;
+#endif // wxUSE_LOG
+
+ wxApp::CleanUp();
+
+ gdk_threads_leave();
+}
+
+
+
+int wxEntry( int argc, char *argv[] )
+{
+#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
+ // This seems to be necessary since there are 'rogue'
+ // objects present at this point (perhaps global objects?)
+ // Setting a checkpoint will ignore them as far as the
+ // memory checking facility is concerned.
+ // Of course you may argue that memory allocated in globals should be
+ // checked, but this is a reasonable compromise.
+ wxDebugContext::SetCheckpoint();
+#endif
+ int err = wxEntryStart(argc, argv);
+ if (err)
+ return err;
+
if (!wxTheApp)
{
wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
wxStripExtension( name );
wxTheApp->SetAppName( name );
- int retValue = 0;
-
- if ( !wxTheApp->OnInitGui() )
- retValue = -1;
-
- wxRootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
- gtk_widget_realize( wxRootWindow );
+ int retValue;
+ retValue = wxEntryInitGui();
// Here frames insert themselves automatically into wxTopLevelWindows by
// getting created in OnInit().
}
}
-#if wxUSE_LOG
- // flush the logged messages if any
- wxLog *log = wxLog::GetActiveTarget();
- if (log != NULL && log->HasPendingMessages())
- log->Flush();
-
- // continuing to use user defined log target is unsafe from now on because
- // some resources may be already unavailable, so replace it by something
- // more safe
- wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
- if ( oldlog )
- delete oldlog;
-#endif // wxUSE_LOG
-
- wxApp::CleanUp();
-
- gdk_threads_leave();
+ wxEntryCleanup();
return retValue;
}