X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/d6f2a8911e509fd9e61f881cc881a97f5aa05ae8..fc5e8e07f795e2c5a7e1b3bef1e9e97e1910ef0d:/src/common/appbase.cpp diff --git a/src/common/appbase.cpp b/src/common/appbase.cpp index 339fe276c4..111ff3c7af 100644 --- a/src/common/appbase.cpp +++ b/src/common/appbase.cpp @@ -42,37 +42,27 @@ #include "wx/evtloop.h" #include "wx/filename.h" #include "wx/msgout.h" -#include "wx/ptr_scpd.h" +#include "wx/scopedptr.h" #include "wx/tokenzr.h" +#include "wx/thread.h" #if wxUSE_EXCEPTIONS && wxUSE_STL #include #include #endif +#ifndef __WXPALMOS5__ #if !defined(__WXMSW__) || defined(__WXMICROWIN__) #include // for SIGTRAP used by wxTrap() #endif //Win/Unix #include +#endif // ! __WXPALMOS5__ #if wxUSE_FONTMAP #include "wx/fontmap.h" #endif // wxUSE_FONTMAP -#if defined(__DARWIN__) && defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS - // For MacTypes.h for Debugger function - #include -#endif - -#if defined(__WXMAC__) - #ifdef __DARWIN__ - #include - #else - #include "wx/mac/private.h" // includes mac headers - #endif -#endif // __WXMAC__ - #ifdef __WXDEBUG__ #if wxUSE_STACKWALKER #include "wx/stackwalk.h" @@ -80,6 +70,8 @@ #include "wx/msw/debughlp.h" #endif #endif // wxUSE_STACKWALKER + + #include "wx/recguard.h" #endif // __WXDEBUG__ // wxABI_VERSION can be defined when compiling applications but it should be @@ -119,6 +111,8 @@ wxAppConsole *wxAppConsoleBase::ms_appInstance = NULL; wxAppInitializerFunction wxAppConsoleBase::ms_appInitFn = NULL; +wxSocketManager *wxAppTraitsBase::ms_manager = NULL; + // ---------------------------------------------------------------------------- // wxEventLoopPtr // ---------------------------------------------------------------------------- @@ -138,8 +132,9 @@ wxAppConsoleBase::wxAppConsoleBase() { m_traits = NULL; m_mainLoop = NULL; + m_bDoPendingEventProcessing = true; - ms_appInstance = wx_static_cast(wxAppConsole *, this); + ms_appInstance = static_cast(this); #ifdef __WXDEBUG__ SetTraceMasks(); @@ -159,25 +154,17 @@ wxAppConsoleBase::~wxAppConsoleBase() } // ---------------------------------------------------------------------------- -// initilization/cleanup +// initialization/cleanup // ---------------------------------------------------------------------------- -bool wxAppConsoleBase::Initialize(int& argcOrig, wxChar **argvOrig) +bool wxAppConsoleBase::Initialize(int& WXUNUSED(argc), wxChar **argv) { #if wxUSE_INTL GetTraits()->SetLocale(); #endif // wxUSE_INTL - // remember the command line arguments - argc = argcOrig; - argv = argvOrig; - -#if wxUSE_THREADS - wxPendingEventsLocker = new wxCriticalSection; -#endif - #ifndef __WXPALMOS__ - if ( m_appName.empty() && argv ) + if ( m_appName.empty() && argv && argv[0] ) { // the application name is, by default, the name of its executable file wxFileName::SplitPath(argv[0], NULL, &m_appName, NULL); @@ -199,14 +186,6 @@ void wxAppConsoleBase::CleanUp() delete m_mainLoop; m_mainLoop = NULL; } - - delete wxPendingEvents; - wxPendingEvents = NULL; - -#if wxUSE_THREADS - delete wxPendingEventsLocker; - wxPendingEventsLocker = NULL; -#endif // wxUSE_THREADS } // ---------------------------------------------------------------------------- @@ -253,7 +232,7 @@ int wxAppConsoleBase::OnExit() #if wxUSE_CONFIG // delete the config object if any (don't use Get() here, but Set() // because Get() could create a new config object) - delete wxConfigBase::Set((wxConfigBase *) NULL); + delete wxConfigBase::Set(NULL); #endif // wxUSE_CONFIG return 0; @@ -289,8 +268,15 @@ wxAppTraits *wxAppConsoleBase::GetTraits() return m_traits; } +/* static */ +wxAppTraits *wxAppConsoleBase::GetTraitsIfExists() +{ + wxAppConsole * const app = GetInstance(); + return app ? app->GetTraits() : NULL; +} + // ---------------------------------------------------------------------------- -// event processing +// wxEventLoop redirection // ---------------------------------------------------------------------------- int wxAppConsoleBase::MainLoop() @@ -328,17 +314,30 @@ bool wxAppConsoleBase::Dispatch() return loop && loop->Dispatch(); } -bool wxAppConsoleBase::HasPendingEvents() const +bool wxAppConsoleBase::Yield(bool onlyIfNeeded) { - wxENTER_CRIT_SECT( *wxPendingEventsLocker ); + wxEventLoopBase * const loop = wxEventLoopBase::GetActive(); - bool has = wxPendingEvents && !wxPendingEvents->IsEmpty(); + return loop && loop->Yield(onlyIfNeeded); +} + +void wxAppConsoleBase::WakeUpIdle() +{ + if ( m_mainLoop ) + m_mainLoop->WakeUp(); +} - wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); +bool wxAppConsoleBase::ProcessIdle() +{ + wxEventLoopBase * const loop = wxEventLoopBase::GetActive(); - return has; + return loop && loop->ProcessIdle(); } +// ---------------------------------------------------------------------------- +// events +// ---------------------------------------------------------------------------- + /* static */ bool wxAppConsoleBase::IsMainLoopRunning() { @@ -347,58 +346,138 @@ bool wxAppConsoleBase::IsMainLoopRunning() return app && app->m_mainLoop != NULL; } -void wxAppConsoleBase::ProcessPendingEvents() +int wxAppConsoleBase::FilterEvent(wxEvent& WXUNUSED(event)) { -#if wxUSE_THREADS - if ( !wxPendingEventsLocker ) - return; -#endif + // process the events normally by default + return -1; +} - wxENTER_CRIT_SECT( *wxPendingEventsLocker ); +void wxAppConsoleBase::DelayPendingEventHandler(wxEvtHandler* toDelay) +{ + wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker); - if (wxPendingEvents) - { - // iterate until the list becomes empty - wxList::compatibility_iterator node = wxPendingEvents->GetFirst(); - while (node) - { - wxEvtHandler *handler = (wxEvtHandler *)node->GetData(); - wxPendingEvents->Erase(node); + // move the handler from the list of handlers with processable pending events + // to the list of handlers with pending events which needs to be processed later + m_handlersWithPendingEvents.Remove(toDelay); - // In ProcessPendingEvents(), new handlers might be add - // and we can safely leave the critical section here. - wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); + if (m_handlersWithPendingDelayedEvents.Index(toDelay) == wxNOT_FOUND) + m_handlersWithPendingDelayedEvents.Add(toDelay); - handler->ProcessPendingEvents(); + wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker); +} - wxENTER_CRIT_SECT( *wxPendingEventsLocker ); +void wxAppConsoleBase::RemovePendingEventHandler(wxEvtHandler* toRemove) +{ + wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker); - node = wxPendingEvents->GetFirst(); - } + if (m_handlersWithPendingEvents.Index(toRemove) != wxNOT_FOUND) + { + m_handlersWithPendingEvents.Remove(toRemove); + + // check that the handler was present only once in the list + wxASSERT_MSG( m_handlersWithPendingEvents.Index(toRemove) == wxNOT_FOUND, + "Handler occurs twice in the m_handlersWithPendingEvents list!" ); + } + //else: it wasn't in this list at all, it's ok + + if (m_handlersWithPendingDelayedEvents.Index(toRemove) != wxNOT_FOUND) + { + m_handlersWithPendingDelayedEvents.Remove(toRemove); + + // check that the handler was present only once in the list + wxASSERT_MSG( m_handlersWithPendingDelayedEvents.Index(toRemove) == wxNOT_FOUND, + "Handler occurs twice in m_handlersWithPendingDelayedEvents list!" ); } + //else: it wasn't in this list at all, it's ok - wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); + wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker); } -void wxAppConsoleBase::WakeUpIdle() +void wxAppConsoleBase::AppendPendingEventHandler(wxEvtHandler* toAppend) { - if ( m_mainLoop ) - m_mainLoop->WakeUp(); + wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker); + + if ( m_handlersWithPendingEvents.Index(toAppend) == wxNOT_FOUND ) + m_handlersWithPendingEvents.Add(toAppend); + + wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker); } -bool wxAppConsoleBase::ProcessIdle() +bool wxAppConsoleBase::HasPendingEvents() const { - wxIdleEvent event; + wxENTER_CRIT_SECT(const_cast(this)->m_handlersWithPendingEventsLocker); + + bool has = !m_handlersWithPendingEvents.IsEmpty(); - event.SetEventObject(this); - ProcessEvent(event); - return event.MoreRequested(); + wxLEAVE_CRIT_SECT(const_cast(this)->m_handlersWithPendingEventsLocker); + + return has; } -int wxAppConsoleBase::FilterEvent(wxEvent& WXUNUSED(event)) +void wxAppConsoleBase::SuspendProcessingOfPendingEvents() { - // process the events normally by default - return -1; + m_bDoPendingEventProcessing = false; +} + +void wxAppConsoleBase::ResumeProcessingOfPendingEvents() +{ + m_bDoPendingEventProcessing = true; +} + +void wxAppConsoleBase::ProcessPendingEvents() +{ + if (!m_bDoPendingEventProcessing) + return; + + wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker); + + wxCHECK_RET( m_handlersWithPendingDelayedEvents.IsEmpty(), + "this helper list should be empty" ); + + // iterate until the list becomes empty: the handlers remove themselves + // from it when they don't have any more pending events + while (!m_handlersWithPendingEvents.IsEmpty()) + { + // In ProcessPendingEvents(), new handlers might be added + // and we can safely leave the critical section here. + wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker); + + // NOTE: we always call ProcessPendingEvents() on the first event handler + // with pending events because handlers auto-remove themselves + // from this list (see RemovePendingEventHandler) if they have no + // more pending events. + m_handlersWithPendingEvents[0]->ProcessPendingEvents(); + + wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker); + } + + // now the wxHandlersWithPendingEvents is surely empty; however some event + // handlers may have moved themselves into wxHandlersWithPendingDelayedEvents + // because of a selective wxYield call in progress. + // Now we need to move them back to wxHandlersWithPendingEvents so the next + // call to this function has the chance of processing them: + if (!m_handlersWithPendingDelayedEvents.IsEmpty()) + { + WX_APPEND_ARRAY(m_handlersWithPendingEvents, m_handlersWithPendingDelayedEvents); + m_handlersWithPendingDelayedEvents.Clear(); + } + + wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker); +} + +void wxAppConsoleBase::DeletePendingEvents() +{ + wxENTER_CRIT_SECT(m_handlersWithPendingEventsLocker); + + wxCHECK_RET( m_handlersWithPendingDelayedEvents.IsEmpty(), + "this helper list should be empty" ); + + for (unsigned int i=0; iDeletePendingEvents(); + + m_handlersWithPendingEvents.Clear(); + + wxLEAVE_CRIT_SECT(m_handlersWithPendingEventsLocker); } // ---------------------------------------------------------------------------- @@ -416,6 +495,20 @@ wxAppConsoleBase::HandleEvent(wxEvtHandler *handler, (handler->*func)(event); } +void wxAppConsoleBase::CallEventHandler(wxEvtHandler *handler, + wxEventFunctor& functor, + wxEvent& event) const +{ + // If the functor holds a method then, for backward compatibility, call + // HandleEvent(): + wxEventFunction eventFunction = functor.GetMethod(); + + if ( eventFunction ) + HandleEvent(handler, eventFunction, event); + else + functor(handler, event); +} + void wxAppConsoleBase::OnUnhandledException() { #ifdef __WXDEBUG__ @@ -466,7 +559,7 @@ bool wxAppConsoleBase::OnExceptionInMainLoop() #if wxUSE_CMDLINE_PARSER -#define OPTION_VERBOSE _T("verbose") +#define OPTION_VERBOSE "verbose" void wxAppConsoleBase::OnInitCmdLine(wxCmdLineParser& parser) { @@ -475,8 +568,8 @@ void wxAppConsoleBase::OnInitCmdLine(wxCmdLineParser& parser) { { wxCMD_LINE_SWITCH, - _T("h"), - _T("help"), + "h", + "help", gettext_noop("show this help message"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP @@ -485,7 +578,7 @@ void wxAppConsoleBase::OnInitCmdLine(wxCmdLineParser& parser) #if wxUSE_LOG { wxCMD_LINE_SWITCH, - wxEmptyString, + NULL, OPTION_VERBOSE, gettext_noop("generate verbose log messages"), wxCMD_LINE_VAL_NONE, @@ -494,14 +587,7 @@ void wxAppConsoleBase::OnInitCmdLine(wxCmdLineParser& parser) #endif // wxUSE_LOG // terminator - { - wxCMD_LINE_NONE, - wxEmptyString, - wxEmptyString, - wxEmptyString, - wxCMD_LINE_VAL_NONE, - 0x0 - } + wxCMD_LINE_DESC_END }; parser.SetDesc(cmdLineDesc); @@ -565,7 +651,6 @@ bool wxAppConsoleBase::CheckBuildOptions(const char *optionsSignature, // normally wxLogFatalError doesn't return return false; } -#undef wxCMP return true; } @@ -651,13 +736,6 @@ void wxConsoleAppTraitsBase::RemoveFromPendingDelete(wxObject * WXUNUSED(object) // nothing to do } -#if wxUSE_SOCKETS -GSocketGUIFunctionsTable* wxConsoleAppTraitsBase::GetSocketGUIFunctionsTable() -{ - return NULL; -} -#endif - // ---------------------------------------------------------------------------- // wxAppTraits // ---------------------------------------------------------------------------- @@ -670,6 +748,35 @@ void wxAppTraitsBase::SetLocale() } #endif +#if wxUSE_THREADS +void wxMutexGuiEnterImpl(); +void wxMutexGuiLeaveImpl(); + +void wxAppTraitsBase::MutexGuiEnter() +{ + wxMutexGuiEnterImpl(); +} + +void wxAppTraitsBase::MutexGuiLeave() +{ + wxMutexGuiLeaveImpl(); +} + +void WXDLLIMPEXP_BASE wxMutexGuiEnter() +{ + wxAppTraits * const traits = wxAppConsoleBase::GetTraitsIfExists(); + if ( traits ) + traits->MutexGuiEnter(); +} + +void WXDLLIMPEXP_BASE wxMutexGuiLeave() +{ + wxAppTraits * const traits = wxAppConsoleBase::GetTraitsIfExists(); + if ( traits ) + traits->MutexGuiLeave(); +} +#endif // wxUSE_THREADS + #ifdef __WXDEBUG__ bool wxAppTraitsBase::ShowAssertDialog(const wxString& msgOriginal) @@ -797,12 +904,6 @@ void wxTrap() { #if defined(__WXMSW__) && !defined(__WXMICROWIN__) DebugBreak(); -#elif defined(__WXMAC__) && !defined(__DARWIN__) - #if __powerc - Debugger(); - #else - SysBreak(); - #endif #elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS Debugger(); #elif defined(__UNIX__) @@ -820,20 +921,17 @@ static void wxDoOnAssert(const wxString& szFile, const wxString& szMsg = wxEmptyString) { // FIXME MT-unsafe - static bool s_bInAssert = false; + static int s_bInAssert = 0; - if ( s_bInAssert ) + wxRecursionGuard guard(s_bInAssert); + if ( guard.IsInside() ) { - // He-e-e-e-elp!! we're trapped in endless loop + // can't use assert here to avoid infinite loops, so just trap wxTrap(); - s_bInAssert = false; - return; } - s_bInAssert = true; - if ( !wxTheApp ) { // by default, show the assert dialog box -- we can't customize this @@ -847,8 +945,6 @@ static void wxDoOnAssert(const wxString& szFile, wxTheApp->OnAssertFailure(szFile.c_str(), nLine, szFunc.c_str(), szCond.c_str(), szMsg.c_str()); } - - s_bInAssert = false; } void wxOnAssert(const wxString& szFile, @@ -944,6 +1040,7 @@ static void LINKAGEMODE SetTraceMasks() #endif // wxUSE_LOG } +static bool DoShowAssertDialog(const wxString& msg) { // under MSW we can show the dialog even in the console mode