X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a4bbc9f720cbd99d7092e8944e671a6291068b13..f056ea60f3a14553a7ca76451f45ebd4d1ecd58b:/src/mgl/app.cpp diff --git a/src/mgl/app.cpp b/src/mgl/app.cpp index f1c96de528..bb061200c3 100644 --- a/src/mgl/app.cpp +++ b/src/mgl/app.cpp @@ -1,7 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // Name: app.cpp -// Purpose: // Author: Vaclav Slavik +// based on GTK and MSW implementations // Id: $Id$ // Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com) // Licence: wxWindows licence @@ -11,28 +11,51 @@ #pragma implementation "app.h" #endif +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + + +#ifndef WX_PRECOMP + #include "wx/settings.h" + #include "wx/module.h" + #include "wx/evtloop.h" + #include "wx/frame.h" + #include "wx/dialog.h" + #include "wx/log.h" + #include "wx/intl.h" +#endif + #include "wx/app.h" -#include "wx/settings.h" -#include "wx/module.h" +#include "wx/fontutil.h" +#include "wx/univ/theme.h" +#include "wx/univ/renderer.h" +#include "wx/mgl/private.h" + +#define MGL_DEBUG -#include +#if defined(MGL_DEBUG) && !defined(__WXDEBUG__) +#undef MGL_DEBUG +#endif //----------------------------------------------------------------------------- // Global data //----------------------------------------------------------------------------- -wxApp *wxTheApp = (wxApp *) NULL; +wxApp *wxTheApp = NULL; wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL; -// FIXME_MGL - whole file - - -extern bool g_isIdle; -bool g_mainThreadLocked = FALSE; +//----------------------------------------------------------------------------- +// wxExit +//----------------------------------------------------------------------------- void wxExit() { + MGL_exit(); exit(0); } @@ -40,17 +63,66 @@ void wxExit() // wxYield //----------------------------------------------------------------------------- +static bool gs_inYield = FALSE; + bool wxYield() { +#if wxUSE_THREADS + if ( !wxThread::IsMain() ) + { + // can't process events from other threads, MGL is thread-unsafe + return TRUE; + } +#endif // wxUSE_THREADS + + gs_inYield = TRUE; + + wxLog::Suspend(); + + if ( wxEventLoop::GetActive() ) + { + while (wxEventLoop::GetActive()->Pending()) + wxEventLoop::GetActive()->Dispatch(); + } + + /* 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()) { } + + wxLog::Resume(); + + gs_inYield = FALSE; + return TRUE; } +bool wxYieldIfNeeded() +{ + if (gs_inYield) + return FALSE; + + return wxYield(); +} + + //----------------------------------------------------------------------------- // wxWakeUpIdle //----------------------------------------------------------------------------- void wxWakeUpIdle() { +#if wxUSE_THREADS + if (!wxThread::IsMain()) + wxMutexGuiEnter(); +#endif + + while (wxTheApp->ProcessIdle()) {} + +#if wxUSE_THREADS + if (!wxThread::IsMain()) + wxMutexGuiLeave(); +#endif } //----------------------------------------------------------------------------- @@ -64,26 +136,385 @@ BEGIN_EVENT_TABLE(wxApp, wxEvtHandler) END_EVENT_TABLE() -int wxEntry( int argc, char *argv[] ) +wxApp::wxApp() : m_mainLoop(NULL) +{ +} + +wxApp::~wxApp() +{ +} + +bool wxApp::OnInitGui() +{ + if ( !wxCreateMGL_WM() ) + return FALSE; + + // This has to be done *after* wxCreateMGL_WM() because it initializes + // wxUniv's themes + if ( !wxAppBase::OnInitGui() ) + return FALSE; + +#ifdef MGL_DEBUG + // That damn MGL redirects stdin and stdout to physical console + FILE *file = fopen("stderr", "wt"); + wxLog::SetActiveTarget(new wxLogStderr(file)); +#endif + + return TRUE; +} + +bool wxApp::ProcessIdle() +{ + wxIdleEvent event; + event.SetEventObject(this); + ProcessEvent(event); + + return event.MoreRequested(); +} + +void wxApp::OnIdle(wxIdleEvent &event) +{ + static bool s_inOnIdle = FALSE; + + /* 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 */ + ProcessPendingEvents(); + + // 'Garbage' collection of windows deleted with Close(). + DeletePendingObjects(); + + // Send OnIdle events to all windows + if ( SendIdleEvents() ) + event.RequestMore(TRUE); + + s_inOnIdle = FALSE; +} + +bool wxApp::SendIdleEvents() { - return 0; + bool needMore = FALSE; + + wxWindowList::Node* node = wxTopLevelWindows.GetFirst(); + while (node) + { + wxWindow* win = node->GetData(); + if ( SendIdleEvents(win) ) + needMore = TRUE; + node = node->GetNext(); + } + + return needMore; } +bool wxApp::SendIdleEvents(wxWindow* win) +{ + bool needMore = FALSE; + + wxIdleEvent event; + event.SetEventObject(win); + + win->GetEventHandler()->ProcessEvent(event); + + if ( event.MoreRequested() ) + needMore = TRUE; + + wxNode* node = win->GetChildren().First(); + while (node) + { + wxWindow* win = (wxWindow*) node->Data(); + if ( SendIdleEvents(win) ) + needMore = TRUE; + + node = node->Next(); + } + return needMore; +} + +int wxApp::MainLoop() +{ + int rt; + m_mainLoop = new wxEventLoop; + + rt = m_mainLoop->Run(); + + delete m_mainLoop; + m_mainLoop = NULL; + return rt; +} + +void wxApp::ExitMainLoop() +{ + if ( m_mainLoop ) + m_mainLoop->Exit(0); +} + +bool wxApp::Initialized() +{ + return (wxTopLevelWindows.GetCount() != 0); +} + +bool wxApp::Pending() +{ + return wxEventLoop::GetActive()->Pending(); +} -// FIXME_MGL - this is temporary solution, will be removed -// once I have wxApp up and running -bool wxMGL_Initialize() +void wxApp::Dispatch() { + wxEventLoop::GetActive()->Dispatch(); +} + +void wxApp::DeletePendingObjects() +{ + wxNode *node = wxPendingDelete.First(); + while (node) + { + wxObject *obj = (wxObject *)node->Data(); + + delete obj; + + if ( wxPendingDelete.Find(obj) ) + delete node; + + node = wxPendingDelete.First(); + } +} + +bool wxApp::Initialize() +{ + if ( MGL_init(".", NULL) == 0 ) + return FALSE; + wxBuffer = new wxChar[BUFSIZ + 512]; wxClassInfo::InitializeClasses(); + wxSystemSettings::Init(); - wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING ); + +#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 + wxPendingEvents = new wxList; + wxPendingEventsLocker = new wxCriticalSection; +#endif + + wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING); wxTheColourDatabase->Initialize(); + + // Can't do this in wxModule, because fonts are needed by stock lists + wxTheFontsManager = new wxFontsManager; + wxInitializeStockLists(); wxInitializeStockObjects(); + +#if wxUSE_WX_RESOURCES + wxInitializeResourceSystem(); +#endif + wxModule::RegisterModules(); if (!wxModule::InitializeModules()) return FALSE; + return TRUE; } +wxIcon wxApp::GetStdIcon(int which) const +{ + return wxTheme::Get()->GetRenderer()->GetStdIcon(which); +} + +void wxApp::CleanUp() +{ +#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 + + wxModule::CleanUpModules(); + +#if wxUSE_WX_RESOURCES + wxCleanUpResourceSystem(); +#endif + + if (wxTheColourDatabase) + delete wxTheColourDatabase; + + wxTheColourDatabase = (wxColourDatabase*) NULL; + + wxDeleteStockObjects(); + wxDeleteStockLists(); + + // Can't do this in wxModule, because fonts are needed by stock lists + delete wxTheFontsManager; + wxTheFontsManager = (wxFontsManager*) NULL; + + 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. +#if wxUSE_THREADS + delete wxPendingEvents; + delete wxPendingEventsLocker; +#endif + + wxSystemSettings::Done(); + + delete[] wxBuffer; + + wxClassInfo::CleanUpClasses(); + + // 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 + +#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; +#endif // wxUSE_LOG + + wxDestroyMGL_WM(); + MGL_exit(); +} + + +int wxEntryStart(int argc, char *argv[]) +{ + return wxApp::Initialize() ? 0 : -1; +} + + +int wxEntryInitGui() +{ + return wxTheApp->OnInitGui() ? 0 : -1; +} + + +void wxEntryCleanup() +{ + wxApp::CleanUp(); +} + + + +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, + wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") ); + + wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction(); + + wxObject *test_app = app_ini(); + + wxTheApp = (wxApp*) test_app; + } + + 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; + retValue = wxEntryInitGui(); + + // Here frames insert themselves automatically into wxTopLevelWindows by + // getting created in OnInit(). + if ( retValue == 0 ) + { + if ( !wxTheApp->OnInit() ) + retValue = -1; + } + + 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(); + + if ( wxTheApp->Initialized() ) + { + 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 + { + delete topWindow; + wxTheApp->SetTopWindow((wxWindow*) NULL); + } + } + + retValue = wxTheApp->OnExit(); + } + } + + wxEntryCleanup(); + + return retValue; +}