X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/e8e1149bd7154e04ad36100bfdcc0f81de9f1a89..8cbc59fe84f046685b873cf58f6c56debe59de1c:/src/common/init.cpp?ds=sidebyside diff --git a/src/common/init.cpp b/src/common/init.cpp index 32288fd1e3..7af0af2157 100644 --- a/src/common/init.cpp +++ b/src/common/init.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: common/init.cpp +// Name: src/common/init.cpp // Purpose: initialisation for the library // Author: Vadim Zeitlin // Modified by: @@ -20,21 +20,22 @@ #include "wx/wxprec.h" #ifdef __BORLANDC__ - #pragma hdrstop + #pragma hdrstop #endif //__BORLANDC__ #ifndef WX_PRECOMP #include "wx/app.h" - #include "wx/debug.h" #include "wx/filefn.h" #include "wx/log.h" - #include "wx/thread.h" + #include "wx/intl.h" + #include "wx/module.h" #endif #include "wx/init.h" +#include "wx/thread.h" -#include "wx/ptr_scpd.h" -#include "wx/module.h" +#include "wx/scopedptr.h" +#include "wx/except.h" #if defined(__WXMSW__) && defined(__WXDEBUG__) #include "wx/msw/msvcrt.h" @@ -62,37 +63,38 @@ public: wxDummyConsoleApp() { } virtual int OnRun() { wxFAIL_MSG( _T("unreachable code") ); return 0; } + virtual bool DoYield(bool, long) { return true; } - DECLARE_NO_COPY_CLASS(wxDummyConsoleApp) + wxDECLARE_NO_COPY_CLASS(wxDummyConsoleApp); }; // we need a special kind of auto pointer to wxApp which not only deletes the -// pointer it holds in its dtor but also resets wxTheApp -wxDECLARE_SCOPED_PTR(wxApp, wxAppPtrBase); -wxDEFINE_SCOPED_PTR(wxApp, wxAppPtrBase); +// pointer it holds in its dtor but also resets the global application pointer +wxDECLARE_SCOPED_PTR(wxAppConsole, wxAppPtrBase) +wxDEFINE_SCOPED_PTR(wxAppConsole, wxAppPtrBase) class wxAppPtr : public wxAppPtrBase { public: - wxEXPLICIT wxAppPtr(wxApp *ptr = NULL) : wxAppPtrBase(ptr) { } + wxEXPLICIT wxAppPtr(wxAppConsole *ptr = NULL) : wxAppPtrBase(ptr) { } ~wxAppPtr() { if ( get() ) { // the pointer is going to be deleted in the base class dtor, don't // leave the dangling pointer! - wxTheApp = NULL; + wxApp::SetInstance(NULL); } } - void Set(wxApp *ptr) + void Set(wxAppConsole *ptr) { reset(ptr); - wxTheApp = ptr; + wxApp::SetInstance(ptr); } - DECLARE_NO_COPY_CLASS(wxAppPtr) + wxDECLARE_NO_COPY_CLASS(wxAppPtr); }; // class to ensure that wxAppBase::CleanUp() is called if our Initialize() @@ -100,13 +102,13 @@ public: class wxCallAppCleanup { public: - wxCallAppCleanup(wxApp *app) : m_app(app) { } + wxCallAppCleanup(wxAppConsole *app) : m_app(app) { } ~wxCallAppCleanup() { if ( m_app ) m_app->CleanUp(); } void Dismiss() { m_app = NULL; } private: - wxApp *m_app; + wxAppConsole *m_app; }; // another tiny class which simply exists to ensure that wxEntryCleanup is @@ -159,7 +161,7 @@ static struct InitData wchar_t **argv; #endif // wxUSE_UNICODE - DECLARE_NO_COPY_CLASS(InitData) + wxDECLARE_NO_COPY_CLASS(InitData); } gs_initData; // ============================================================================ @@ -175,12 +177,27 @@ static struct InitData static void ConvertArgsToUnicode(int argc, char **argv) { gs_initData.argv = new wchar_t *[argc + 1]; + int wargc = 0; for ( int i = 0; i < argc; i++ ) { - gs_initData.argv[i] = wxStrdup(wxConvLocal.cMB2WX(argv[i])); +#ifdef __DARWIN__ + wxWCharBuffer buf(wxConvFileName->cMB2WX(argv[i])); +#else + wxWCharBuffer buf(wxConvLocal.cMB2WX(argv[i])); +#endif + if ( !buf ) + { + wxLogWarning(_("Command line argument %d couldn't be converted to Unicode and will be ignored."), + i); + } + else // converted ok + { + gs_initData.argv[wargc++] = wxStrdup(buf); + } } - gs_initData.argv[argc] = NULL; + gs_initData.argc = wargc; + gs_initData.argv[wargc] = NULL; } static void FreeConvertedArgs() @@ -194,6 +211,7 @@ static void FreeConvertedArgs() delete [] gs_initData.argv; gs_initData.argv = NULL; + gs_initData.argc = 0; } } @@ -206,7 +224,17 @@ static void FreeConvertedArgs() // initialization which is always done (not customizable) before wxApp creation static bool DoCommonPreInit() { - wxClassInfo::InitializeClasses(); +#if wxUSE_LOG + // Reset logging in case we were cleaned up and are being reinitialized. + wxLog::DoCreateOnDemand(); + + // install temporary log sink: we can't use wxLogGui before wxApp is + // constructed and if we use wxLogStderr, all messages during + // initialization simply disappear under Windows + // + // note that we will delete this log target below + delete wxLog::SetActiveTarget(new wxLogBuffer); +#endif // wxUSE_LOG return true; } @@ -216,7 +244,51 @@ static bool DoCommonPostInit() { wxModule::RegisterModules(); - return wxModule::InitializeModules(); + if ( !wxModule::InitializeModules() ) + { + wxLogError(_("Initialization failed in post init, aborting.")); + return false; + } + +#if defined(__WXDEBUG__) + // check if event classes implement Clone() correctly + // NOTE: the check is done against _all_ event classes which are linked to + // the executable currently running, which are not necessarily all + // wxWidgets event classes. + const wxClassInfo *ci = wxClassInfo::GetFirst(); + for (; ci; ci = ci->GetNext()) + { + // is this class derived from wxEvent? + if (!ci->IsKindOf(CLASSINFO(wxEvent)) || wxString(ci->GetClassName()) == "wxEvent") + continue; + + if (!ci->IsDynamic()) + { + wxLogWarning("The event class '%s' should have a DECLARE_DYNAMIC_CLASS macro!", + ci->GetClassName()); + continue; + } + + // yes; test if it implements Clone() correctly + wxEvent* test = wxDynamicCast(ci->CreateObject(),wxEvent); + if (test == NULL) + { + wxLogWarning("The event class '%s' should have a DECLARE_DYNAMIC_CLASS macro!", + ci->GetClassName()); + continue; + } + + wxEvent* cloned = test->Clone(); + if (!cloned || cloned->GetClassInfo() != ci) + wxLogWarning("The event class '%s' does not correctly implement Clone()!", + ci->GetClassName()); + + delete cloned; + delete test; + } +#endif + + return true; } bool wxEntryStart(int& argc, wxChar **argv) @@ -226,9 +298,7 @@ bool wxEntryStart(int& argc, wxChar **argv) // initialize wxRTTI if ( !DoCommonPreInit() ) - { return false; - } // first of all, we need an application object @@ -245,11 +315,7 @@ bool wxEntryStart(int& argc, wxChar **argv) if ( fnCreate ) { // he did, try to create the custom wxApp object - // - // NB: cast is needed because for the backwards-compatibility - // reasons wxTheApp is really a wxApp and not just - // wxAppConsole... - app.Set((wxApp*)(*fnCreate)()); + app.Set((*fnCreate)()); } } @@ -257,26 +323,22 @@ bool wxEntryStart(int& argc, wxChar **argv) { // either IMPLEMENT_APP() was not used at all or it failed -- in any // case we still need something - // - // NB: cast is needed because for the backwards-compatibility reasons - // wxTheApp is really a wxApp and not just wxAppConsole... - app.Set((wxApp *)new wxDummyConsoleApp); + app.Set(new wxDummyConsoleApp); } // wxApp initialization: this can be customized // -------------------------------------------- - if ( !wxTheApp->Initialize(argc, argv) ) - { + if ( !app->Initialize(argc, argv) ) return false; - } - wxCallAppCleanup callAppCleanup(wxTheApp); + // remember, possibly modified (e.g. due to removal of toolkit-specific + // parameters), command line arguments in member variables + app->argc = argc; + app->argv = argv; - // for compatibility call the old initialization function too - if ( !wxTheApp->OnInitGui() ) - return false; + wxCallAppCleanup callAppCleanup(app.get()); // common initialization after wxTheApp creation @@ -292,6 +354,14 @@ bool wxEntryStart(int& argc, wxChar **argv) // and the cleanup object from doing cleanup callAppCleanup.Dismiss(); +#if wxUSE_LOG + // now that we have a valid wxApp (wxLogGui would have crashed if we used + // it before now), we can delete the temporary sink we had created for the + // initialization messages -- the next time logging function is called, the + // sink will be recreated but this time wxAppTraits will be used + delete wxLog::SetActiveTarget(NULL); +#endif // wxUSE_LOG + return true; } @@ -302,7 +372,7 @@ bool wxEntryStart(int& argc, char **argv) { ConvertArgsToUnicode(argc, argv); - if ( !wxEntryStart(argc, gs_initData.argv) ) + if ( !wxEntryStart(gs_initData.argc, gs_initData.argv) ) { FreeConvertedArgs(); @@ -318,27 +388,25 @@ bool wxEntryStart(int& argc, char **argv) // clean up // ---------------------------------------------------------------------------- -// cleanup done before destroying wxTheApp +// cleanup done before destroying wxTheApp static void DoCommonPreCleanup() { #if wxUSE_LOG // flush the logged messages if any and install a 'safer' log target: the // default one (wxLogGui) can't be used after the resources are freed just // below and the user supplied one might be even more unsafe (using any - // wxWindows GUI function is unsafe starting from now) + // wxWidgets GUI function is unsafe starting from now) wxLog::DontCreateOnDemand(); // this will flush the old messages if any delete wxLog::SetActiveTarget(new wxLogStderr); #endif // wxUSE_LOG - - wxModule::CleanUpModules(); } // cleanup done after destroying wxTheApp static void DoCommonPostCleanup() { - wxClassInfo::CleanUpClasses(); + wxModule::CleanUpModules(); // we can't do this in wxApp itself because it doesn't know if argv had // been allocated @@ -346,6 +414,10 @@ static void DoCommonPostCleanup() FreeConvertedArgs(); #endif // wxUSE_UNICODE + // use Set(NULL) and not Get() to avoid creating a message output object on + // demand when we just want to delete it + delete wxMessageOutput::Set(NULL); + #if wxUSE_LOG // and now delete the last logger as well delete wxLog::SetActiveTarget(NULL); @@ -362,38 +434,36 @@ void wxEntryCleanup() { wxTheApp->CleanUp(); - delete wxTheApp; - wxTheApp = NULL; + // reset the global pointer to it to NULL before destroying it as in + // some circumstances this can result in executing the code using + // wxTheApp and using half-destroyed object is no good + wxAppConsole * const app = wxApp::GetInstance(); + wxApp::SetInstance(NULL); + delete app; } DoCommonPostCleanup(); - - // check for memory leaks -#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT - if (wxDebugContext::CountObjectsLeft(TRUE) > 0) - { - wxLogDebug(wxT("There were memory leaks.\n")); - wxDebugContext::Dump(); - wxDebugContext::PrintStatistics(); - } -#endif // Debug - } // ---------------------------------------------------------------------------- // wxEntry // ---------------------------------------------------------------------------- -#if !defined(__WXMSW__) || !wxUSE_ON_FATAL_EXCEPTION +// for MSW the real wxEntry is defined in msw/main.cpp +#ifndef __WXMSW__ #define wxEntryReal wxEntry -#endif // !(__WXMSW__ && wxUSE_ON_FATAL_EXCEPTION) +#endif // !__WXMSW__ int wxEntryReal(int& argc, wxChar **argv) { // library initialization if ( !wxEntryStart(argc, argv) ) { +#if wxUSE_LOG + // flush any log messages explaining why we failed + delete wxLog::SetActiveTarget(NULL); +#endif return -1; } @@ -403,57 +473,30 @@ int wxEntryReal(int& argc, wxChar **argv) WX_SUPPRESS_UNUSED_WARN(cleanupOnExit); - // app initialization - if ( !wxTheApp->CallOnInit() ) + wxTRY { - // don't call OnExit() if OnInit() failed - return -1; - } - - // app execution - int retValue = wxTheApp->OnRun(); - - // app clean up - wxTheApp->OnExit(); - - return retValue; -} - -// wrap real wxEntry in a try-except block to be able to call -// OnFatalException() if necessary -#if defined(__WXMSW__) && wxUSE_ON_FATAL_EXCEPTION - -#ifdef __WXWINCE__ -// For ExitThread -#include "wx/msw/private.h" -#endif + // app initialization + if ( !wxTheApp->CallOnInit() ) + { + // don't call OnExit() if OnInit() failed + return -1; + } -extern unsigned long wxGlobalSEHandler(EXCEPTION_POINTERS *pExcPtrs); + // ensure that OnExit() is called if OnInit() had succeeded + class CallOnExit + { + public: + ~CallOnExit() { wxTheApp->OnExit(); } + } callOnExit; -int wxEntry(int& argc, wxChar **argv) -{ - __try - { - return wxEntryReal(argc, argv); - } - __except ( wxGlobalSEHandler(GetExceptionInformation()) ) - { -#ifdef __WXWINCE__ - ::ExitThread(3); // the same exit code as abort() -#else - ::ExitProcess(3); // the same exit code as abort() -#endif + WX_SUPPRESS_UNUSED_WARN(callOnExit); -#if !defined(_MSC_VER) || _MSC_VER < 1300 - // this code is unreachable but put it here to suppress warnings - // from some compilers - return -1; -#endif + // app execution + return wxTheApp->OnRun(); } + wxCATCH_ALL( wxTheApp->OnUnhandledException(); return -1; ) } -#endif // __WXMSW__ && wxUSE_ON_FATAL_EXCEPTION - #if wxUSE_UNICODE // as with wxEntryStart, we provide an ANSI wrapper @@ -461,7 +504,7 @@ int wxEntry(int& argc, char **argv) { ConvertArgsToUnicode(argc, argv); - return wxEntry(argc, gs_initData.argv); + return wxEntry(gs_initData.argc, gs_initData.argv); } #endif // wxUSE_UNICODE @@ -487,9 +530,8 @@ void wxUninitialize() { wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit); - if ( !--gs_initData.nInitCount ) + if ( --gs_initData.nInitCount == 0 ) { wxEntryCleanup(); } } -