]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/app.cpp
made wxApp::GetTopWindow() virtual
[wxWidgets.git] / src / gtk / app.cpp
index b7ed1c12ce07437ccbf4b89f9a2fa102721b4f25..e29797d061470572dbe7d4d4f45f64411b7754dd 100644 (file)
 #include "wx/module.h"
 #include "wx/image.h"
 
-#include "wx/thread.h"
+#if wxUSE_THREADS
+    #include "wx/thread.h"
+#endif
 
-#include "unistd.h"
+#include <unistd.h>
 
 #include <glib.h>
 #include <gdk/gdk.h>
 //-----------------------------------------------------------------------------
 
 wxApp *wxTheApp = (wxApp *)  NULL;
-wxAppInitializerFunction wxApp::m_appInitFn = (wxAppInitializerFunction) NULL;
+wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
 
-#if wxUSE_THREADS
-extern wxList *wxPendingEvents;
-extern wxCriticalSection *wxPendingEventsLocker;
-#endif
-extern wxResourceCache *wxTheResourceCache;
 extern bool g_isIdle;
 
-unsigned char g_palette[64*3] =
-{
-  0x0,  0x0,  0x0,
-  0xff, 0xff, 0xff,
-  0xff, 0x0,  0x0,
-  0xff, 0xff, 0x0,
-  0x0,  0xff, 0x0,
-  0x0,  0x0,  0xff,
-  0x0,  0xff, 0xff,
-  0x99, 0x99, 0x99,
-  0xff, 0x88, 0x0,
-  0x88, 0x0,  0x0,
-  0x0,  0x88, 0x88,
-  0x88, 0x88, 0x0,
-  0xff, 0xcc, 0x97,
-  0xbb, 0xbb, 0xbb,
-  0x9f, 0x6b, 0x42,
-  0x55, 0x55, 0x55,
-  0xdd, 0xdd, 0xdd,
-  0x77, 0x77, 0x77,
-  0x33, 0x33, 0x33,
-  0xcc, 0x0,  0x0,
-  0xff, 0x44, 0x0,
-  0xff, 0xcc, 0x0,
-  0xcc, 0xcc, 0x0,
-  0x60, 0x60, 0x0,
-  0x0,  0x43, 0x0,
-  0x0,  0x7f, 0x0,
-  0x0,  0xcc, 0x0,
-  0x0,  0x44, 0x44,
-  0x0,  0x0,  0x44,
-  0x0,  0x0,  0x88,
-  0xef, 0xb1, 0x7b,
-  0xdf, 0x98, 0x5f,
-  0xbf, 0x87, 0x56,
-  0x7f, 0x57, 0x26,
-  0x5f, 0x39, 0xc,
-  0x3f, 0x1c, 0x0,
-  0x21, 0x0,  0x0,
-  0x0,  0x43, 0x87,
-  0x2d, 0x70, 0xaf,
-  0x5a, 0x9e, 0xd7,
-  0x87, 0xcc, 0xff,
-  0xff, 0xe0, 0xba,
-  0x21, 0x43, 0xf,
-  0x3d, 0x5d, 0x25,
-  0x59, 0x78, 0x3a,
-  0x75, 0x93, 0x4f,
-  0x91, 0xae, 0x64,
-  0xad, 0xc8, 0x7a,
-  0xf0, 0xa8, 0xef,
-  0xd0, 0x88, 0xd0,
-  0xaf, 0x66, 0xaf,
-  0x8e, 0x44, 0x8e,
-  0x6d, 0x22, 0x6d,
-  0x4b, 0x0,  0x4b,
-  0xff, 0xc0, 0xbc,
-  0xff, 0x93, 0x91,
-  0xff, 0x66, 0x67,
-  0xd8, 0xf2, 0xbf,
-  0xff, 0xc9, 0x68,
-  0xff, 0x96, 0x67,
-  0xa5, 0x60, 0xff,
-  0x51, 0xff, 0x99,
-  0x3f, 0xa5, 0x63,
-  0x98, 0x90, 0x67
-};
+bool   g_mainThreadLocked = FALSE;
+gint   g_pendingTag = 0;
+
+GtkWidget *wxRootWindow = (GtkWidget*) NULL;
 
 //-----------------------------------------------------------------------------
 // local functions
 //-----------------------------------------------------------------------------
 
-extern void wxFlushResources(void);
+/* forward declaration */
+gint   wxapp_idle_callback( gpointer WXUNUSED(data) );
+gint   wxapp_pending_callback( gpointer WXUNUSED(data) );
+void   wxapp_install_idle_handler();
+
+#if wxUSE_THREADS
+gint   wxapp_wakeup_timerout_callback( gpointer WXUNUSED(data) );
+#endif
 
 //-----------------------------------------------------------------------------
-// global functions
+// wxExit
 //-----------------------------------------------------------------------------
 
 void wxExit()
@@ -135,81 +76,216 @@ void wxExit()
     gtk_main_quit();
 }
 
-/* forward declaration */
-gint wxapp_idle_callback( gpointer WXUNUSED(data) );
+//-----------------------------------------------------------------------------
+// wxYield
+//-----------------------------------------------------------------------------
 
 bool wxYield()
 {
-    // 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)
-    for ( wxWindowList::Node *node = wxTopLevelWindows.GetFirst();
-          node;
-          node = node->GetNext() )
+#if wxUSE_THREADS
+    if ( !wxThread::IsMain() )
     {
-        wxWindow *win = node->GetData();
-        win->OnInternalIdle();
+        // can't call gtk_main_iteration() from other threads like this
+        return TRUE;
     }
+#endif // wxUSE_THREADS
 
-    if (wxTheApp->m_idleTag)
+#ifdef __WXDEBUG__
+    static bool s_inYield = FALSE;
+    
+    if (s_inYield)
+        wxFAIL_MSG( wxT("wxYield called recursively" ) );
+    
+    s_inYield = TRUE;
+#endif
+
+    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();
+    while (gtk_events_pending())
+        gtk_main_iteration();
+
+    // 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();
+
+#ifdef __WXDEBUG__
+    s_inYield = FALSE;
+#endif
 
-        /* re-add idle handler */
-        wxTheApp->m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
-    }
-    else
-    {
-        while (gtk_events_pending())
-            gtk_main_iteration();
-    }
-    
     return TRUE;
 }
 
-gint wxapp_idle_callback( gpointer WXUNUSED(data) )
+//-----------------------------------------------------------------------------
+// wxWakeUpIdle
+//-----------------------------------------------------------------------------
+
+void wxWakeUpIdle()
+{
+#if wxUSE_THREADS
+    if (!wxThread::IsMain())
+        wxMutexGuiEnter();
+#endif
+
+    if (g_isIdle)
+        wxapp_install_idle_handler();
+
+#if wxUSE_THREADS
+    if (!wxThread::IsMain())
+        wxMutexGuiLeave();
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// local functions
+//-----------------------------------------------------------------------------
+
+gint wxapp_pending_callback( gpointer WXUNUSED(data) )
 {
     if (!wxTheApp) return TRUE;
     
-    /* sent idle event to all who request them */
-    while (wxTheApp->ProcessIdle()) { }
+    // 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();
+
+    // 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;
     
-    /* 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;
+    // 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
+    /* 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;
-    
-    /* wake up other threads */
-    wxMutexGuiLeave();
-    wxUsleep(0);
-    wxMutexGuiEnter();
+    wxTheApp->m_idleTag = 0;
 
-    return TRUE;
+    // Sent idle event to all who request them
+    while (wxTheApp->ProcessIdle()) { }
+
+    // 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;
 }
 
 void wxapp_install_idle_handler()
 {
-    /* this routine gets called by all event handlers
-       indicating that the idle is over. */
+    wxASSERT_MSG( wxTheApp->m_idleTag == 0, wxT("attempt to install idle handler twice") );
 
-    wxTheApp->m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
-    
     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). Very low priority. */
+
+    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 );
+    wxTheApp->m_wakeUpTimerTag = 0;
+}
+
+gint wxapp_wakeup_timerout_callback( gpointer WXUNUSED(data) )
+{
+    // 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();
+
+    wxapp_uninstall_thread_wakeup();
+
+    // unblock other threads wishing to do some GUI things
+    wxMutexGuiLeave();
+
+    g_mainThreadLocked = TRUE;
+
+    // wake up other threads
+    wxUsleep( 1 );
+
+    // block other thread again
+    wxMutexGuiEnter();
+
+    g_mainThreadLocked = FALSE;
+
+    wxapp_install_thread_wakeup();
+
+    // release lock again
+    gdk_threads_leave();
+
+    return TRUE;
+}
+
+#endif // wxUSE_THREADS
+
 //-----------------------------------------------------------------------------
 // wxApp
 //-----------------------------------------------------------------------------
@@ -227,48 +303,57 @@ wxApp::wxApp()
     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;
+    wxapp_install_thread_wakeup();
+#endif
 
     m_colorCube = (unsigned char*) NULL;
+
+    m_useBestVisual = FALSE;
 }
 
 wxApp::~wxApp()
 {
     if (m_idleTag) gtk_idle_remove( m_idleTag );
 
+#if wxUSE_THREADS
+    wxapp_uninstall_thread_wakeup();
+#endif
+
     if (m_colorCube) free(m_colorCube);
 }
 
 bool wxApp::OnInitGui()
 {
-    /* Nothing to do for 15, 16, 24, 32 bit displays */
-
     GdkVisual *visual = gdk_visual_get_system();
-    if (visual->depth > 8) return TRUE;
 
-        /* this initiates the standard palette as defined by GdkImlib
-           in the GNOME libraries. it ensures that all GNOME applications
-           use the same 64 colormap entries on 8-bit displays so you
-           can use several rather graphics-heavy applications at the
-           same time.
-           NOTE: this doesn't really seem to work this way... */
+    /* on some machines, the default visual is just 256 colours, so
+       we make sure we get the best. this can sometimes be wasteful,
+       of course, but what do these guys pay $30.000 for? */
 
-        /*
-        GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
+    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
 
-        for (int i = 0; i < 64; i++)
-        {
-            GdkColor col;
-            col.red    = g_palette[i*3 + 0] << 8;
-            col.green  = g_palette[i*3 + 1] << 8;
-            col.blue   = g_palette[i*3 + 2] << 8;
-            col.pixel  = 0;
+        GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
+        gtk_widget_set_default_colormap( colormap );
 
-            gdk_color_alloc( cmap, &col );
-        }
+        visual = vis;
+    }
 
-        gtk_widget_set_default_colormap( cmap );
-        */
+    /* Nothing to do for 15, 16, 24, 32 bit displays */
+    if (visual->depth > 8) return TRUE;
 
     /* initialize color cube for 8-bit color reduction dithering */
 
@@ -289,7 +374,7 @@ bool wxApp::OnInitGui()
                 int index = -1;
 
                 GdkColor *colors = cmap->colors;
-                if(colors)
+                if (colors)
                 {
                     int max = 3 * 65536;
 
@@ -300,12 +385,24 @@ bool wxApp::OnInitGui()
                         int bdiff = ((bb << 8) - colors[i].blue);
                         int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
                         if (sum < max)
-                        { 
+                        {
                             index = i; max = sum;
                         }
                     }
                 }
-
+                else
+                {
+#if (GTK_MINOR_VERSION > 0)
+                    /* assume 8-bit true or static colors. this really
+                       exists. */
+                    GdkVisual* vis = gdk_colormap_get_visual( cmap );
+                    index = (r >> (5 - vis->red_prec)) << vis->red_shift;
+                    index |= (g >> (5 - vis->green_prec)) << vis->green_shift;
+                    index |= (b >> (5 - vis->blue_prec)) << vis->blue_shift;
+#else
+                    wxFAIL_MSG( wxT("Unsupported graphics hardware") );
+#endif
+                }
                 m_colorCube[ (r*1024) + (g*32) + b ] = index;
             }
         }
@@ -325,35 +422,28 @@ bool wxApp::ProcessIdle()
 
 void wxApp::OnIdle( wxIdleEvent &event )
 {
-    static bool inOnIdle = FALSE;
+    static bool s_inOnIdle = FALSE;
 
     /* Avoid recursion (via ProcessEvent default case) */
-    if (inOnIdle)
+    if (s_inOnIdle)
         return;
 
-    inOnIdle = TRUE;
+    s_inOnIdle = TRUE;
 
-#if wxUSE_THREADS
     /* Resend in the main thread events which have been prepared in other
        threads */
     ProcessPendingEvents();
-#endif
 
     /* 'Garbage' collection of windows deleted with Close(). */
     DeletePendingObjects();
 
-    /* flush the logged messages if any */
-    wxLog *log = wxLog::GetActiveTarget();
-    if (log != NULL && log->HasPendingMessages())
-        log->Flush();
-
     /* Send OnIdle events to all windows */
     bool needMore = SendIdleEvents();
 
     if (needMore)
         event.RequestMore(TRUE);
 
-    inOnIdle = FALSE;
+    s_inOnIdle = FALSE;
 }
 
 bool wxApp::SendIdleEvents()
@@ -379,9 +469,9 @@ bool wxApp::SendIdleEvents( wxWindow* win )
     wxIdleEvent event;
     event.SetEventObject(win);
 
-    win->OnInternalIdle();
+    win->GetEventHandler()->ProcessEvent(event);
 
-    win->ProcessEvent(event);
+    win->OnInternalIdle();
 
     if (event.MoreRequested())
         needMore = TRUE;
@@ -406,7 +496,8 @@ int wxApp::MainLoop()
 
 void wxApp::ExitMainLoop()
 {
-    gtk_main_quit();
+    if (gtk_main_level() > 0)
+        gtk_main_quit();
 }
 
 bool wxApp::Initialized()
@@ -424,25 +515,6 @@ void wxApp::Dispatch()
     gtk_main_iteration();
 }
 
-#if wxUSE_THREADS
-void wxApp::ProcessPendingEvents()
-{
-    wxNode *node = wxPendingEvents->First();
-    wxCriticalSectionLocker locker(*wxPendingEventsLocker);
-
-    while (node)
-    {
-        wxEvtHandler *handler = (wxEvtHandler *)node->Data();
-
-        handler->ProcessPendingEvents();
-
-        delete node;
-
-        node = wxPendingEvents->First();
-    }
-}
-#endif // wxUSE_THREADS
-
 void wxApp::DeletePendingObjects()
 {
     wxNode *node = wxPendingDelete.First();
@@ -459,21 +531,6 @@ void wxApp::DeletePendingObjects()
     }
 }
 
-wxWindow *wxApp::GetTopWindow()
-{
-    if (m_topWindow)
-        return m_topWindow;
-    else if (wxTopLevelWindows.GetCount() > 0)
-        return wxTopLevelWindows.GetFirst()->GetData();
-    else
-        return NULL;
-}
-
-void wxApp::SetTopWindow( wxWindow *win )
-{
-    m_topWindow = win;
-}
-
 bool wxApp::Initialize()
 {
     wxBuffer = new wxChar[BUFSIZ + 512];
@@ -489,11 +546,6 @@ bool wxApp::Initialize()
     wxPendingEventsLocker = new wxCriticalSection();
 #endif
 
-/*
-    wxTheFontNameDirectory =  new wxFontNameDirectory;
-    wxTheFontNameDirectory->Initialize();
-*/
-
     wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
     wxTheColourDatabase->Initialize();
 
@@ -501,16 +553,9 @@ bool wxApp::Initialize()
     wxInitializeStockObjects();
 
 #if wxUSE_WX_RESOURCES
-    wxTheResourceCache = new wxResourceCache( wxKEY_STRING );
-
     wxInitializeResourceSystem();
 #endif
 
-    wxImage::InitStandardHandlers();
-
-    /* no global cursor under X
-       g_globalCursor = new wxCursor; */
-
     wxModule::RegisterModules();
     if (!wxModule::InitializeModules()) return FALSE;
 
@@ -522,30 +567,18 @@ void wxApp::CleanUp()
     wxModule::CleanUpModules();
 
 #if wxUSE_WX_RESOURCES
-    wxFlushResources();
-
-    if (wxTheResourceCache)
-        delete wxTheResourceCache;
-    wxTheResourceCache = (wxResourceCache*) NULL;
-
     wxCleanUpResourceSystem();
 #endif
 
     if (wxTheColourDatabase)
         delete wxTheColourDatabase;
-    wxTheColourDatabase = (wxColourDatabase*) NULL;
 
-/*
-    if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
-    wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
-*/
+    wxTheColourDatabase = (wxColourDatabase*) NULL;
 
     wxDeleteStockObjects();
 
     wxDeleteStockLists();
 
-    wxImage::CleanUpHandlers();
-
     delete wxTheApp;
     wxTheApp = (wxApp*) NULL;
 
@@ -564,44 +597,130 @@ void wxApp::CleanUp()
 
     // check for memory leaks
 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
-    if (wxDebugContext::CountObjectsLeft() > 0)
+    if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
     {
-        wxLogDebug(_T("There were memory leaks.\n"));
+        wxLogDebug(wxT("There were memory leaks.\n"));
         wxDebugContext::Dump();
         wxDebugContext::PrintStatistics();
     }
 #endif // Debug
 
+#if wxUSE_LOG
     // do this as the very last thing because everything else can log messages
     wxLog::DontCreateOnDemand();
 
     wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
     if (oldLog)
         delete oldLog;
-}
-
-wxLog *wxApp::CreateLogTarget()
-{
-    return new wxLogGui;
+#endif // wxUSE_LOG
 }
 
 //-----------------------------------------------------------------------------
 // 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) &&
+        (gtk_minor_version == 2) &&
+        (gtk_micro_version < 4))
+    {
+        printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" );
+    }
+    else
+    {
+        g_thread_init(NULL);
+    }
+#endif
+
     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
+
+    gdk_threads_enter();
+
     gtk_init( &argc, &argv );
 
+    wxSetDetectableAutoRepeat( TRUE );
+
     if (!wxApp::Initialize())
+    {
+        gdk_threads_leave();
         return -1;
+    }
+
+    return 0;
+}
+
+int wxEntryInitGui()
+{
+    int retValue = 0;
+
+    if ( !wxTheApp->OnInitGui() )
+        retValue = -1;
+
+    wxRootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
+    gtk_widget_realize( wxRootWindow );
+
+    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,
-                     _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
+                     wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
 
         wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
 
@@ -610,19 +729,28 @@ int wxEntry( int argc, char *argv[] )
         wxTheApp = (wxApp*) test_app;
     }
 
-    wxCHECK_MSG( wxTheApp, -1, _T("wxWindows error: no application object") );
+    wxCHECK_MSG( wxTheApp, -1, wxT("wxWindows error: no application object") );
 
     wxTheApp->argc = argc;
+#if wxUSE_UNICODE
+    wxTheApp->argv = new wxChar*[argc+1];
+    int mb_argc = 0;
+    while (mb_argc < argc)
+    {
+        wxTheApp->argv[mb_argc] = wxStrdup(wxConvLibc.cMB2WX(argv[mb_argc]));
+        mb_argc++;
+    }
+    wxTheApp->argv[mb_argc] = (wxChar *)NULL;
+#else
     wxTheApp->argv = argv;
+#endif
 
     wxString name(wxFileNameFromPath(argv[0]));
     wxStripExtension( name );
     wxTheApp->SetAppName( name );
 
-    int retValue = 0;
-
-    if ( !wxTheApp->OnInitGui() )
-        retValue = -1;
+    int retValue;
+    retValue = wxEntryInitGui();
 
     // Here frames insert themselves automatically into wxTopLevelWindows by
     // getting created in OnInit().
@@ -634,45 +762,67 @@ int wxEntry( int argc, char *argv[] )
 
     if ( retValue == 0 )
     {
+        /* delete pending toplevel windows (typically a single
+           dialog) so that, if there isn't any left, we don't
+           call OnRun() */
+        wxTheApp->DeletePendingObjects();
+
         wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
 
         if (wxTheApp->Initialized())
-            retValue = wxTheApp->OnRun();
-
-        wxWindow *topWindow = wxTheApp->GetTopWindow();
-        if (topWindow)
         {
-            // Forcibly delete the window.
-            if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
-                topWindow->IsKindOf(CLASSINFO(wxDialog)) )
-            {
-                topWindow->Close( TRUE );
-                wxTheApp->DeletePendingObjects();
-            }
-            else
+            wxTheApp->OnRun();
+
+            wxWindow *topWindow = wxTheApp->GetTopWindow();
+            if (topWindow)
             {
-                delete topWindow;
-                wxTheApp->SetTopWindow( (wxWindow*) NULL );
+                /* Forcibly delete the window. */
+                if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
+                    topWindow->IsKindOf(CLASSINFO(wxDialog)) )
+                {
+                    topWindow->Close( TRUE );
+                    wxTheApp->DeletePendingObjects();
+                }
+                else
+                {
+                    delete topWindow;
+                    wxTheApp->SetTopWindow( (wxWindow*) NULL );
+                }
             }
-        }
 
-        wxTheApp->OnExit();
+            retValue = wxTheApp->OnExit();
+        }
     }
 
-    // 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;
-
-    wxApp::CleanUp();
+    wxEntryCleanup();
 
     return retValue;
 }
 
+#include "wx/gtk/info.xpm"
+#include "wx/gtk/error.xpm"
+#include "wx/gtk/question.xpm"
+#include "wx/gtk/warning.xpm"
+
+wxIcon
+wxApp::GetStdIcon(int which) const
+{
+    switch(which)
+    {
+        case wxICON_INFORMATION:
+            return wxIcon(info_xpm);
+
+        case wxICON_QUESTION:
+            return wxIcon(question_xpm);
+
+        case wxICON_EXCLAMATION:
+            return wxIcon(warning_xpm);
+
+        default:
+            wxFAIL_MSG(wxT("requested non existent standard icon"));
+            // still fall through
+
+        case wxICON_HAND:
+            return wxIcon(error_xpm);
+    }
+}