X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/fd495ab3ea1282ddb8bb0cd0fb79fc758ae5fcee..c0bfefb6cf9dbe736300a7100dd4786f1a3277dd:/src/mgl/app.cpp diff --git a/src/mgl/app.cpp b/src/mgl/app.cpp index d9288130de..1a614e3f81 100644 --- a/src/mgl/app.cpp +++ b/src/mgl/app.cpp @@ -1,16 +1,12 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: app.cpp +// Name: src/mgl/app.cpp // Author: Vaclav Slavik // based on GTK and MSW implementations // Id: $Id$ -// Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com) +// Copyright: (c) 2001-2002 SciTech Software, Inc. (www.scitechsoft.com) // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ - #pragma implementation "app.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -18,33 +14,31 @@ #pragma hdrstop #endif +#include "wx/app.h" + #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" + #include "wx/module.h" #endif -#include "wx/app.h" +#include "wx/evtloop.h" +#include "wx/fontutil.h" +#include "wx/univ/theme.h" +#include "wx/univ/renderer.h" +#include "wx/univ/colschem.h" +#include "wx/sysopt.h" #include "wx/mgl/private.h" +#include "wx/private/fontmgr.h" //----------------------------------------------------------------------------- -// Global data -//----------------------------------------------------------------------------- - -wxApp *wxTheApp = NULL; -wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL; - -static wxEventLoop *gs_mainEventLoop = NULL; - - -//----------------------------------------------------------------------------- -// wxExit +// wxApp::Exit() //----------------------------------------------------------------------------- -void wxExit() +void wxApp::Exit() { MGL_exit(); exit(0); @@ -54,25 +48,38 @@ void wxExit() // wxYield //----------------------------------------------------------------------------- -static bool gs_inYield = FALSE; +static bool gs_inYield = false; -bool wxYield() +bool wxApp::Yield(bool onlyIfNeeded) { + if ( gs_inYield ) + { + if ( !onlyIfNeeded ) + { + wxFAIL_MSG( wxT("wxYield called recursively" ) ); + } + + return false; + } + #if wxUSE_THREADS if ( !wxThread::IsMain() ) { // can't process events from other threads, MGL is thread-unsafe - return TRUE; + return true; } #endif // wxUSE_THREADS - gs_inYield = TRUE; + gs_inYield = true; wxLog::Suspend(); - while (gs_mainEventLoop->Pending()) - gs_mainEventLoop->Dispatch(); - + 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) */ @@ -80,17 +87,9 @@ bool wxYield() wxLog::Resume(); - gs_inYield = FALSE; - - return TRUE; -} - -bool wxYieldIfNeeded() -{ - if (gs_inYield) - return FALSE; + gs_inYield = false; - return wxYield(); + return true; } @@ -98,14 +97,15 @@ bool wxYieldIfNeeded() // wxWakeUpIdle //----------------------------------------------------------------------------- -void wxWakeUpIdle() +void wxApp::WakeUpIdle() { #if wxUSE_THREADS if (!wxThread::IsMain()) wxMutexGuiEnter(); #endif - while (wxTheApp->ProcessIdle()) {} + while (wxTheApp->ProcessIdle()) + ; #if wxUSE_THREADS if (!wxThread::IsMain()) @@ -114,403 +114,212 @@ void wxWakeUpIdle() } //----------------------------------------------------------------------------- -// wxApp +// Root window //----------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler) - -BEGIN_EVENT_TABLE(wxApp, wxEvtHandler) - EVT_IDLE(wxApp::OnIdle) -END_EVENT_TABLE() - - -wxApp::wxApp() +class wxRootWindow : public wxWindow { -} - -wxApp::~wxApp() -{ -} + public: + wxRootWindow() : wxWindow(NULL, wxID_ANY) + { + SetMGLwindow_t(MGL_wmGetRootWindow(g_winMng)); + SetBackgroundColour(wxTHEME_COLOUR(DESKTOP)); + } + virtual ~wxRootWindow() + { + // we don't want to delete MGL_WM's rootWnd + m_wnd = NULL; + } -bool wxApp::OnInitGui() -{ - if ( MGL_init(".", NULL) == 0 ) - return FALSE; - if ( !wxCreateMGL_WM() ) - return FALSE; + virtual bool AcceptsFocus() const { return false; } - // This has to be done *after* wxCreateMGL_WM() because it initializes - // wxUniv's themes - if ( !wxAppBase::OnInitGui() ) - return FALSE; + DECLARE_DYNAMIC_CLASS(wxRootWindow) +}; - return TRUE; -} +IMPLEMENT_DYNAMIC_CLASS(wxRootWindow, wxWindow) -bool wxApp::ProcessIdle() -{ - wxIdleEvent event; - event.SetEventObject(this); - ProcessEvent(event); +static wxRootWindow *gs_rootWindow = NULL; - return event.MoreRequested(); -} +//----------------------------------------------------------------------------- +// MGL initialization +//----------------------------------------------------------------------------- -void wxApp::OnIdle(wxIdleEvent &event) +static bool wxCreateMGL_WM(const wxVideoMode& displayMode) { - static bool s_inOnIdle = FALSE; - - /* Avoid recursion (via ProcessEvent default case) */ - if (s_inOnIdle) - return; - - s_inOnIdle = TRUE; + int mode; + int refresh = MGL_DEFAULT_REFRESH; - /* Resend in the main thread events which have been prepared in other - threads */ - ProcessPendingEvents(); +#if wxUSE_SYSTEM_OPTIONS + if ( wxSystemOptions::HasOption(wxT("mgl.screen-refresh")) ) + refresh = wxSystemOptions::GetOptionInt(wxT("mgl.screen-refresh")); +#endif - // 'Garbage' collection of windows deleted with Close(). - DeletePendingObjects(); + mode = MGL_findMode(displayMode.GetWidth(), + displayMode.GetHeight(), + displayMode.GetDepth()); + if ( mode == -1 ) + { + wxLogError(_("Mode %ix%i-%i not available."), + displayMode.GetWidth(), + displayMode.GetHeight(), + displayMode.GetDepth()); + return false; + } + g_displayDC = new MGLDisplayDC(mode, 1, refresh); + if ( !g_displayDC->isValid() ) + { + delete g_displayDC; + g_displayDC = NULL; + return false; + } - // Send OnIdle events to all windows - if ( SendIdleEvents() ) - event.RequestMore(TRUE); + g_winMng = MGL_wmCreate(g_displayDC->getDC()); + if (!g_winMng) + return false; - s_inOnIdle = FALSE; + return true; } -bool wxApp::SendIdleEvents() +static void wxDestroyMGL_WM() { - bool needMore = FALSE; - - wxWindowList::Node* node = wxTopLevelWindows.GetFirst(); - while (node) + if ( g_winMng ) { - wxWindow* win = node->GetData(); - if ( SendIdleEvents(win) ) - needMore = TRUE; - node = node->GetNext(); + MGL_wmDestroy(g_winMng); + g_winMng = NULL; } - - return needMore; -} - -bool wxApp::SendIdleEvents(wxWindow* win) -{ - bool needMore = FALSE; - - wxIdleEvent event; - event.SetEventObject(win); - - win->GetEventHandler()->ProcessEvent(event); - -#if 0 // FIXME_MGL - what the hell it is? - win->OnInternalIdle(); - - if ( event.MoreRequested() ) - needMore = TRUE; -#endif - - wxNode* node = win->GetChildren().First(); - while (node) + if ( g_displayDC ) { - wxWindow* win = (wxWindow*) node->Data(); - if ( SendIdleEvents(win) ) - needMore = TRUE; - - node = node->Next(); + delete g_displayDC; + g_displayDC = NULL; } - return needMore; } -int wxApp::MainLoop() -{ - int rt; - gs_mainEventLoop = new wxEventLoop; - rt = gs_mainEventLoop->Run(); - delete gs_mainEventLoop; - gs_mainEventLoop = NULL; - return rt; -} +//----------------------------------------------------------------------------- +// wxApp +//----------------------------------------------------------------------------- -void wxApp::ExitMainLoop() -{ - gs_mainEventLoop->Exit(0); -} +IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler) -bool wxApp::Initialized() -{ - // FIXME_MGL -- only for now because we don't have wxFrame/wxDialog yet - return TRUE; - //return (wxTopLevelWindows.GetCount() != 0); -} +BEGIN_EVENT_TABLE(wxApp, wxEvtHandler) + EVT_IDLE(wxAppBase::OnIdle) +END_EVENT_TABLE() -bool wxApp::Pending() -{ - return gs_mainEventLoop->Pending(); -} -void wxApp::Dispatch() +wxApp::wxApp() { - gs_mainEventLoop->Dispatch(); } -void wxApp::DeletePendingObjects() +wxApp::~wxApp() { - 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() +wxVideoMode wxGetDefaultDisplayMode() { - wxBuffer = new wxChar[BUFSIZ + 512]; - - wxClassInfo::InitializeClasses(); - - wxSystemSettings::Init(); - -#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(); + wxString mode; + unsigned w, h, bpp; - wxInitializeStockLists(); - wxInitializeStockObjects(); - -#if wxUSE_WX_RESOURCES - wxInitializeResourceSystem(); -#endif - - wxModule::RegisterModules(); - if (!wxModule::InitializeModules()) return FALSE; + if ( !wxGetEnv(wxT("WXMODE"), &mode) || + (wxSscanf(mode.c_str(), _T("%ux%u-%u"), &w, &h, &bpp) != 3) ) + { + w = 640, h = 480, bpp = 16; + } - return TRUE; + return wxVideoMode(w, h, bpp); } -#include "info.xpm" -#include "error.xpm" -#include "question.xpm" -#include "warning.xpm" - -wxIcon wxApp::GetStdIcon(int which) const +bool wxApp::SetDisplayMode(const wxVideoMode& mode) { - switch(which) + if ( !mode.IsOk() ) { - 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); + return false; } -} - -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(); - - 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) + if ( g_displayDC != NULL ) { - wxLogDebug(wxT("There were memory leaks.\n")); - wxDebugContext::Dump(); - wxDebugContext::PrintStatistics(); + // FIXME_MGL -- we currently don't allow to switch video mode + // more than once. This can hopefully be changed... + wxFAIL_MSG(wxT("Can't change display mode after intialization!")); + return false; } -#endif // Debug -#if wxUSE_LOG - // do this as the very last thing because everything else can log messages - wxLog::DontCreateOnDemand(); + if ( !wxCreateMGL_WM(mode) ) + return false; + gs_rootWindow = new wxRootWindow; - wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL ); - if (oldLog) - delete oldLog; -#endif // wxUSE_LOG + m_displayMode = mode; - wxDestroyMGL_WM(); - MGL_exit(); + return true; } - -int wxEntryStart(int argc, char *argv[]) +bool wxApp::OnInitGui() { - return wxApp::Initialize() ? 0 : -1; -} + if ( !wxAppBase::OnInitGui() ) + return false; +#ifdef __WXDEBUG__ + // MGL redirects stdout and stderr to physical console, so lets redirect + // it to file in debug build. Do it only when WXSTDERR environment variable is set + wxString redirect; + if ( wxGetEnv(wxT("WXSTDERR"), &redirect) ) + freopen(redirect.mb_str(), "wt", stderr); +#endif // __WXDEBUG__ -int wxEntryInitGui() -{ - return wxTheApp->OnInitGui() ? 0 : -1; -} - + wxLog *oldLog = wxLog::SetActiveTarget(new wxLogGui); + if ( oldLog ) delete oldLog; -void wxEntryCleanup() -{ - wxApp::CleanUp(); + return true; } - - -int wxEntry(int argc, char *argv[]) +bool wxApp::Initialize(int& argc, wxChar **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(); +#ifdef __DJGPP__ + // VS: disable long filenames under DJGPP as the very first thing, + // since SciTech MGL doesn't like them much... + wxSetEnv(wxT("LFN"), wxT("N")); #endif - int err = wxEntryStart(argc, argv); - if ( err ) - return err; - if ( !wxTheApp ) + // intialize MGL before creating wxFontsManager since it uses MGL funcs + if ( MGL_init(".", NULL) == 0 ) { - 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; + wxLogError(_("Cannot initialize SciTech MGL!")); + return false; } - 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) + if ( !wxAppBase::Initialize(argc, argv) ) { - wxTheApp->argv[mb_argc] = wxStrdup(wxConvLibc.cMB2WX(argv[mb_argc])); - mb_argc++; + MGL_exit(); + return false; } - wxTheApp->argv[mb_argc] = (wxChar *)NULL; -#else - wxTheApp->argv = argv; -#endif - wxString name(wxFileNameFromPath(argv[0])); - wxStripExtension(name); - wxTheApp->SetAppName(name); +#if wxUSE_INTL + wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding()); +#endif - int retValue; - retValue = wxEntryInitGui(); + return true; +} - // Here frames insert themselves automatically into wxTopLevelWindows by - // getting created in OnInit(). - if ( retValue == 0 ) - { - if ( !wxTheApp->OnInit() ) - retValue = -1; - } +// Modules are cleaned up after wxApp::CleanUp(), and some modules may +// require MGL to still be alive, e.g. the stock fonts need the fonts +// manager. So append this module last minute in wxApp::CleanUp() to close +// down MGL after all the other modules have been cleaned up. +// +struct wxMGLFinalCleanup: public wxModule +{ + bool OnInit() { return true; } - if ( retValue == 0 ) + void OnExit() { - /* delete pending toplevel windows (typically a single - dialog) so that, if there isn't any left, we don't - call OnRun() */ - wxTheApp->DeletePendingObjects(); + wxFontsManager::CleanUp(); - 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(); - } + wxDestroyMGL_WM(); + MGL_exit(); } +}; + +void wxApp::CleanUp() +{ + delete gs_rootWindow; - wxEntryCleanup(); + wxAppBase::CleanUp(); - return retValue; + wxModule::RegisterModule(new wxMGLFinalCleanup); }