]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk1/app.cpp
Applied patch [ 638561 ] Allow SetFont(wxNullFont) in wxGTK
[wxWidgets.git] / src / gtk1 / app.cpp
index 8d6ae8f81455a21383a122fd38d5116c10c1ffe6..eccbb52d0a7ea32e83d2f6e738a56f94e6da69d9 100644 (file)
     #pragma implementation "app.h"
 #endif
 
+#ifdef __VMS
+#include <vms_jackets.h>
+#endif
+
 #include "wx/app.h"
 #include "wx/gdicmn.h"
 #include "wx/utils.h"
@@ -20,6 +24,9 @@
 #include "wx/font.h"
 #include "wx/settings.h"
 #include "wx/dialog.h"
+#include "wx/msgdlg.h"
+#include "wx/file.h"
+#include "wx/filename.h"
 
 #if wxUSE_WX_RESOURCES
     #include "wx/resource.h"
 #endif
 
 #include <unistd.h>
+
+#ifdef HAVE_POLL
+    #if defined(__VMS)
+        #include <poll.h>
+    #else
+        // bug in the OpenBSD headers: at least in 3.1 there is no extern "C"
+        // in neither poll.h nor sys/poll.h which results in link errors later
+        #ifdef __OPENBSD__
+            extern "C"
+            {
+        #endif
+
+        #include <sys/poll.h>
+
+        #ifdef __OPENBSD__
+            };
+        #endif
+    #endif // platform
+#else // !HAVE_POLL
+    // we implement poll() ourselves using select() which is supposed exist in
+    // all modern Unices
+    #include <sys/types.h>
+    #include <sys/time.h>
+    #include <unistd.h>
+#endif // HAVE_POLL/!HAVE_POLL
+
 #include "wx/gtk/win_gtk.h"
 
 #include <gtk/gtk.h>
 wxApp *wxTheApp = (wxApp *)  NULL;
 wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
 
-extern bool g_isIdle;
-
 bool   g_mainThreadLocked = FALSE;
 gint   g_pendingTag = 0;
 
 static GtkWidget *gs_RootWindow = (GtkWidget*) NULL;
 
 //-----------------------------------------------------------------------------
-// local functions
+// idle system
 //-----------------------------------------------------------------------------
 
-extern "C"
-{
-    gint wxapp_idle_callback( gpointer WXUNUSED(data) );
-    gint wxapp_pending_callback( gpointer WXUNUSED(data) );
-}
+extern bool g_isIdle;
 
-void wxapp_install_thread_wakeup();
-void wxapp_uninstall_thread_wakeup();
 void wxapp_install_idle_handler();
 
 //-----------------------------------------------------------------------------
@@ -84,12 +109,14 @@ void wxExit()
 // wxYield
 //-----------------------------------------------------------------------------
 
+// not static because used by textctrl.cpp
+//
+// MT-FIXME
+bool wxIsInsideYield = FALSE;
+
 bool wxApp::Yield(bool onlyIfNeeded)
 {
-    // MT-FIXME
-    static bool s_inYield = FALSE;
-
-    if ( s_inYield )
+    if ( wxIsInsideYield )
     {
         if ( !onlyIfNeeded )
         {
@@ -107,7 +134,7 @@ bool wxApp::Yield(bool onlyIfNeeded)
     }
 #endif // wxUSE_THREADS
 
-    s_inYield = TRUE;
+    wxIsInsideYield = TRUE;
 
     if (!g_isIdle)
     {
@@ -125,17 +152,18 @@ bool wxApp::Yield(bool onlyIfNeeded)
     while (gtk_events_pending())
         gtk_main_iteration();
 
-    /* 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 ( ProcessIdle() )
-    {
-    }
+    // 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). But we
+    // call ProcessIdle() only once since this is not meant for longish
+    // background jobs (controlled by wxIdleEvent::RequestMore() and the
+    // return value of Processidle().
+    ProcessIdle();
 
     // let the logs be flashed again
     wxLog::Resume();
 
-    s_inYield = FALSE;
+    wxIsInsideYield = FALSE;
 
     return TRUE;
 }
@@ -164,43 +192,25 @@ void wxWakeUpIdle()
 // local functions
 //-----------------------------------------------------------------------------
 
-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). Very low priority. */
-
-    wxTheApp->m_idleTag = gtk_idle_add_priority( 1000, wxapp_idle_callback, (gpointer) NULL );
-}
-
 // the callback functions must be extern "C" to comply with GTK+ declarations
 extern "C"
 {
 
-gint wxapp_pending_callback( gpointer WXUNUSED(data) )
+static gint wxapp_pending_callback( gpointer WXUNUSED(data) )
 {
     if (!wxTheApp) return TRUE;
 
-    // when getting called from GDK's time-out handler
+    // 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
+    // thread so we must lock it here ourselves.
     gdk_threads_enter();
 
-    // Sent idle event to all who request them
+    // Sent idle event to all who request them.
     wxTheApp->ProcessPendingEvents();
 
     g_pendingTag = 0;
 
-    /* flush the logged messages if any */
+    // Flush the logged messages if any.
 #if wxUSE_LOG
     wxLog::FlushActive();
 #endif // wxUSE_LOG
@@ -213,7 +223,7 @@ gint wxapp_pending_callback( gpointer WXUNUSED(data) )
     return FALSE;
 }
 
-gint wxapp_idle_callback( gpointer WXUNUSED(data) )
+static gint wxapp_idle_callback( gpointer WXUNUSED(data) )
 {
     if (!wxTheApp)
         return TRUE;
@@ -224,100 +234,148 @@ gint wxapp_idle_callback( gpointer WXUNUSED(data) )
     // from some safely-looking functions
     if ( wxTheApp->IsInAssert() )
     {
+        // But repaint the assertion message if necessary
+        if (wxTopLevelWindows.GetCount() > 0)
+        {
+            wxWindow* win = (wxWindow*) wxTopLevelWindows.Last()->Data();
+            if (win->IsKindOf(CLASSINFO(wxGenericMessageDialog)))
+                win->OnInternalIdle();
+        }
         return TRUE;
     }
 #endif // __WXDEBUG__
 
-    // when getting called from GDK's time-out handler
+    // 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
+    // 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 */
+    // Indicate that we are now in idle mode and event handlers
+    // will have to reinstall the idle handler again.
     g_isIdle = TRUE;
     wxTheApp->m_idleTag = 0;
 
-    // Sent idle event to all who request them as long as they do
-    while (wxTheApp->ProcessIdle())
+    // Send idle event to all who request them as long as
+    // no events have popped up in the event queue.
+    while (wxTheApp->ProcessIdle() && (gtk_events_pending() == 0))
         ;
 
     // 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)
+    // to be sent (single shot instead of continuous stream).
     return FALSE;
 }
 
 #if wxUSE_THREADS
 
-gint wxapp_wakeup_timerout_callback( gpointer WXUNUSED(data) )
+#ifdef HAVE_POLL
+    #define wxPoll poll
+    #define wxPollFd pollfd
+#else // !HAVE_POLL
+
+typedef GPollFD wxPollFd;
+
+int wxPoll(wxPollFd *ufds, unsigned int nfds, int timeout)
 {
-    // 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();
+    // convert timeout from ms to struct timeval (s/us)
+    timeval tv_timeout;
+    tv_timeout.tv_sec = timeout/1000;
+    tv_timeout.tv_usec = (timeout%1000)*1000;
 
-    wxapp_uninstall_thread_wakeup();
+    // remember the highest fd used here
+    int fdMax = -1;
 
-    // unblock other threads wishing to do some GUI things
-    wxMutexGuiLeave();
+    // and fill the sets for select()
+    fd_set readfds;
+    fd_set writefds;
+    fd_set exceptfds;
+    FD_ZERO(&readfds);
+    FD_ZERO(&writefds);
+    FD_ZERO(&exceptfds);
 
-    g_mainThreadLocked = TRUE;
+    unsigned int i;
+    for ( i = 0; i < nfds; i++ )
+    {
+        wxASSERT_MSG( ufds[i].fd < FD_SETSIZE, _T("fd out of range") );
 
-    // wake up other threads
-    wxUsleep( 1 );
+        if ( ufds[i].events & G_IO_IN )
+            FD_SET(ufds[i].fd, &readfds);
 
-    // block other thread again
-    wxMutexGuiEnter();
+        if ( ufds[i].events & G_IO_PRI )
+            FD_SET(ufds[i].fd, &exceptfds);
 
-    g_mainThreadLocked = FALSE;
+        if ( ufds[i].events & G_IO_OUT )
+            FD_SET(ufds[i].fd, &writefds);
 
-    wxapp_install_thread_wakeup();
+        if ( ufds[i].fd > fdMax )
+            fdMax = ufds[i].fd;
+    }
 
-    // release lock again
-    gdk_threads_leave();
+    fdMax++;
+    int res = select(fdMax, &readfds, &writefds, &exceptfds, &tv_timeout);
 
-    return TRUE;
-}
+    // translate the results back
+    for ( i = 0; i < nfds; i++ )
+    {
+        ufds[i].revents = 0;
 
-#endif // wxUSE_THREADS
+        if ( FD_ISSET(ufds[i].fd, &readfds ) )
+            ufds[i].revents |= G_IO_IN;
 
-} // extern "C"
+        if ( FD_ISSET(ufds[i].fd, &exceptfds ) )
+            ufds[i].revents |= G_IO_PRI;
 
-#if wxUSE_THREADS
+        if ( FD_ISSET(ufds[i].fd, &writefds ) )
+            ufds[i].revents |= G_IO_OUT;
+    }
+
+    return res;
+}
 
-static int g_threadUninstallLevel = 0;
+#endif // HAVE_POLL/!HAVE_POLL
 
-void wxapp_install_thread_wakeup()
+static gint wxapp_poll_func( GPollFD *ufds, guint nfds, gint timeout )
 {
-    g_threadUninstallLevel++;
+    gdk_threads_enter();
 
-    if (g_threadUninstallLevel != 1) return;
+    wxMutexGuiLeave();
+    g_mainThreadLocked = TRUE;
+
+    // we rely on the fact that glib GPollFD struct is really just pollfd but
+    // I wonder how wise is this in the long term (VZ)
+    gint res = wxPoll( (wxPollFd *) ufds, nfds, timeout );
+
+    wxMutexGuiEnter();
+    g_mainThreadLocked = FALSE;
 
-    if (wxTheApp->m_wakeUpTimerTag) return;
+    gdk_threads_leave();
 
-    wxTheApp->m_wakeUpTimerTag = gtk_timeout_add( 50, wxapp_wakeup_timerout_callback, (gpointer) NULL );
+    return res;
 }
 
-void wxapp_uninstall_thread_wakeup()
+#endif // wxUSE_THREADS
+
+} // extern "C"
+
+void wxapp_install_idle_handler()
 {
-    g_threadUninstallLevel--;
+    wxASSERT_MSG( wxTheApp->m_idleTag == 0, wxT("attempt to install idle handler twice") );
 
-    if (g_threadUninstallLevel != 0) return;
+    g_isIdle = FALSE;
 
-    if (!wxTheApp->m_wakeUpTimerTag) return;
+    if (g_pendingTag == 0)
+        g_pendingTag = gtk_idle_add_priority( 900, wxapp_pending_callback, (gpointer) NULL );
 
-    gtk_timeout_remove( wxTheApp->m_wakeUpTimerTag );
-    wxTheApp->m_wakeUpTimerTag = 0;
+    // 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 );
 }
 
-#endif // wxUSE_THREADS
-
 //-----------------------------------------------------------------------------
 // Access to the root window global
 //-----------------------------------------------------------------------------
@@ -353,12 +411,11 @@ wxApp::wxApp()
     wxapp_install_idle_handler();
 
 #if wxUSE_THREADS
-    m_wakeUpTimerTag = 0;
-    wxapp_install_thread_wakeup();
+    g_main_set_poll_func( wxapp_poll_func );
 #endif
 
     m_colorCube = (unsigned char*) NULL;
-    
+
     // this is NULL for a "regular" wxApp, but is set (and freed) by a wxGLApp
     m_glVisualInfo = (void *) NULL;
 }
@@ -367,10 +424,6 @@ wxApp::~wxApp()
 {
     if (m_idleTag) gtk_idle_remove( m_idleTag );
 
-#if wxUSE_THREADS
-    wxapp_uninstall_thread_wakeup();
-#endif
-
     if (m_colorCube) free(m_colorCube);
 }
 
@@ -389,7 +442,7 @@ bool wxApp::OnInitGui()
         // seems gtk_widget_set_default_visual no longer exists?
         GdkVisual* vis = gtk_widget_get_default_visual();
 #else
-        GdkVisual* vis = gdkx_visual_get( 
+        GdkVisual* vis = gdkx_visual_get(
             ((XVisualInfo *) m_glVisualInfo) ->visualid );
         gtk_widget_set_default_visual( vis );
 #endif
@@ -399,7 +452,7 @@ bool wxApp::OnInitGui()
 
         visual = vis;
     }
-    
+
     // On some machines, the default visual is just 256 colours, so
     // we make sure we get the best. This can sometimes be wasteful.
 
@@ -477,19 +530,29 @@ bool wxApp::OnInitGui()
 GdkVisual *wxApp::GetGdkVisual()
 {
     GdkVisual *visual = NULL;
-    
+
     if (m_glVisualInfo)
-        visual = gdkx_visual_get( ((XVisualInfo *) wxTheApp->m_glVisualInfo)->visualid );
+        visual = gdkx_visual_get( ((XVisualInfo *) m_glVisualInfo)->visualid );
     else
         visual = gdk_window_get_visual( wxGetRootWindow()->window );
-        
+
     wxASSERT( visual );
-    
+
     return visual;
 }
 
 bool wxApp::ProcessIdle()
 {
+    wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
+    node = wxTopLevelWindows.GetFirst();
+    while (node)
+    {
+        wxWindow* win = node->GetData();
+        CallInternalIdle( win );
+
+        node = node->GetNext();
+    }
+
     wxIdleEvent event;
     event.SetEventObject( this );
     ProcessEvent( event );
@@ -501,20 +564,20 @@ void wxApp::OnIdle( wxIdleEvent &event )
 {
     static bool s_inOnIdle = FALSE;
 
-    /* Avoid recursion (via ProcessEvent default case) */
+    // Avoid recursion (via ProcessEvent default case)
     if (s_inOnIdle)
         return;
 
     s_inOnIdle = TRUE;
 
-    /* Resend in the main thread events which have been prepared in other
-       threads */
+    // Resend in the main thread events which have been prepared in other
+    // threads
     ProcessPendingEvents();
 
-    /* 'Garbage' collection of windows deleted with Close(). */
+    // 'Garbage' collection of windows deleted with Close()
     DeletePendingObjects();
 
-    /* Send OnIdle events to all windows */
+    // Send OnIdle events to all windows
     bool needMore = SendIdleEvents();
 
     if (needMore)
@@ -533,12 +596,29 @@ bool wxApp::SendIdleEvents()
         wxWindow* win = node->GetData();
         if (SendIdleEvents(win))
             needMore = TRUE;
+
         node = node->GetNext();
     }
 
     return needMore;
 }
 
+bool wxApp::CallInternalIdle( wxWindow* win )
+{
+    win->OnInternalIdle();
+
+    wxNode* node = win->GetChildren().First();
+    while (node)
+    {
+        wxWindow* win = (wxWindow*) node->Data();
+        CallInternalIdle( win );
+
+        node = node->Next();
+    }
+
+    return TRUE;
+}
+
 bool wxApp::SendIdleEvents( wxWindow* win )
 {
     bool needMore = FALSE;
@@ -548,8 +628,6 @@ bool wxApp::SendIdleEvents( wxWindow* win )
 
     win->GetEventHandler()->ProcessEvent(event);
 
-    win->OnInternalIdle();
-
     if (event.MoreRequested())
         needMore = TRUE;
 
@@ -562,7 +640,8 @@ bool wxApp::SendIdleEvents( wxWindow* win )
 
         node = node->Next();
     }
-    return needMore ;
+
+    return needMore;
 }
 
 int wxApp::MainLoop()
@@ -610,14 +689,8 @@ void wxApp::DeletePendingObjects()
 
 bool wxApp::Initialize()
 {
-    wxBuffer = new wxChar[BUFSIZ + 512];
-
     wxClassInfo::InitializeClasses();
 
-#if wxUSE_INTL
-    wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
-#endif
-
     // GL: I'm annoyed ... I don't know where to put this and I don't want to
     // create a module for that as it's part of the core.
 #if wxUSE_THREADS
@@ -636,7 +709,12 @@ bool wxApp::Initialize()
 #endif
 
     wxModule::RegisterModules();
-    if (!wxModule::InitializeModules()) return FALSE;
+    if (!wxModule::InitializeModules())
+        return FALSE;
+
+#if wxUSE_INTL
+    wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
+#endif
 
     return TRUE;
 }
@@ -649,9 +727,7 @@ void wxApp::CleanUp()
     wxCleanUpResourceSystem();
 #endif
 
-    if (wxTheColourDatabase)
-        delete wxTheColourDatabase;
-
+    delete wxTheColourDatabase;
     wxTheColourDatabase = (wxColourDatabase*) NULL;
 
     wxDeleteStockObjects();
@@ -661,17 +737,13 @@ void wxApp::CleanUp()
     delete wxTheApp;
     wxTheApp = (wxApp*) NULL;
 
-    // GL: I'm annoyed ... I don't know where to put this and I don't want to
-    // create a module for that as it's part of the core.
+    wxClassInfo::CleanUpClasses();
+
 #if wxUSE_THREADS
     delete wxPendingEvents;
     delete wxPendingEventsLocker;
 #endif
 
-    delete[] wxBuffer;
-
-    wxClassInfo::CleanUpClasses();
-
     // check for memory leaks
 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
     if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
@@ -821,9 +893,11 @@ int wxEntry( int argc, char *argv[] )
     wxTheApp->argv = argv;
 #endif
 
-    wxString name(wxFileNameFromPath(argv[0]));
-    wxStripExtension( name );
-    wxTheApp->SetAppName( name );
+    if (wxTheApp->argc > 0)
+    {
+        wxFileName fname( wxTheApp->argv[0] );
+        wxTheApp->SetAppName( fname.GetName() );
+    }
 
     int retValue;
     retValue = wxEntryInitGui();
@@ -838,33 +912,24 @@ 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() */
+        // Delete pending toplevel windows
         wxTheApp->DeletePendingObjects();
 
-        wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
+        // When is the app not initialized ?
+        wxTheApp->m_initialized = TRUE;
 
         if (wxTheApp->Initialized())
         {
             wxTheApp->OnRun();
 
             wxWindow *topWindow = wxTheApp->GetTopWindow();
+
+            // Delete all pending windows if any
+            wxTheApp->DeletePendingObjects();
+
+            // Reset top window
             if (topWindow)
-            {
-                /* 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->SetTopWindow( (wxWindow*) NULL );
 
             retValue = wxTheApp->OnExit();
         }
@@ -875,54 +940,13 @@ int wxEntry( int argc, char *argv[] )
     return retValue;
 }
 
-#ifndef __WXUNIVERSAL__
-
-// XPM hack: make the arrays const
-#define static static const
-
-#include "wx/gtk/info.xpm"
-#include "wx/gtk/error.xpm"
-#include "wx/gtk/question.xpm"
-#include "wx/gtk/warning.xpm"
-
-#undef static
-
-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);
-    }
-}
-#else
-wxIcon wxApp::GetStdIcon(int which) const
-{
-    return wxTheme::Get()->GetRenderer()->GetStdIcon(which);
-}
-#endif // !__WXUNIVERSAL__
-
-
 #ifdef __WXDEBUG__
 
-void wxApp::OnAssert(const wxChar *file, int line, const wxChar *msg)
+void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
 {
     m_isInAssert = TRUE;
 
-    wxAppBase::OnAssert(file, line, msg);
+    wxAppBase::OnAssert(file, line, cond, msg);
 
     m_isInAssert = FALSE;
 }