1 /////////////////////////////////////////////////////////////////////////////
3 // Author: Vaclav Slavik
4 // based on GTK and MSW implementations
6 // Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #pragma implementation "app.h"
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
23 #include "wx/settings.h"
24 #include "wx/module.h"
25 #include "wx/evtloop.h"
27 #include "wx/dialog.h"
30 #include "wx/resource.h"
34 #include "wx/fontutil.h"
35 #include "wx/univ/theme.h"
36 #include "wx/univ/renderer.h"
37 #include "wx/univ/colschem.h"
38 #include "wx/mgl/private.h"
42 #if defined(MGL_DEBUG) && !defined(__WXDEBUG__)
46 //-----------------------------------------------------------------------------
48 //-----------------------------------------------------------------------------
50 wxApp
*wxTheApp
= NULL
;
51 wxAppInitializerFunction
wxAppBase::m_appInitFn
= (wxAppInitializerFunction
) NULL
;
54 //-----------------------------------------------------------------------------
56 //-----------------------------------------------------------------------------
64 //-----------------------------------------------------------------------------
66 //-----------------------------------------------------------------------------
68 static bool gs_inYield
= FALSE
;
70 bool wxApp::Yield(bool onlyIfNeeded
)
76 wxFAIL_MSG( wxT("wxYield called recursively" ) );
83 if ( !wxThread::IsMain() )
85 // can't process events from other threads, MGL is thread-unsafe
88 #endif // wxUSE_THREADS
94 if ( wxEventLoop::GetActive() )
96 while (wxEventLoop::GetActive()->Pending())
97 wxEventLoop::GetActive()->Dispatch();
100 /* it's necessary to call ProcessIdle() to update the frames sizes which
101 might have been changed (it also will update other things set from
102 OnUpdateUI() which is a nice (and desired) side effect) */
103 while (wxTheApp
->ProcessIdle()) { }
113 //-----------------------------------------------------------------------------
115 //-----------------------------------------------------------------------------
120 if (!wxThread::IsMain())
124 while (wxTheApp
->ProcessIdle()) {}
127 if (!wxThread::IsMain())
132 //-----------------------------------------------------------------------------
134 //-----------------------------------------------------------------------------
136 class wxRootWindow
: public wxWindow
139 wxRootWindow() : wxWindow(NULL
, -1)
141 SetMGLwindow_t(MGL_wmGetRootWindow(g_winMng
));
142 SetBackgroundColour(wxTHEME_COLOUR(DESKTOP
));
146 // we don't want to delete MGL_WM's rootWnd
150 virtual bool AcceptsFocus() { return FALSE
; }
153 static wxRootWindow
*gs_rootWindow
= NULL
;
155 //-----------------------------------------------------------------------------
156 // MGL initialization
157 //-----------------------------------------------------------------------------
159 static bool wxCreateMGL_WM(const wxDisplayModeInfo
& displayMode
)
162 int refresh
= MGL_DEFAULT_REFRESH
;
164 #if wxUSE_SYSTEM_OPTIONS
165 if ( wxSystemOptions::HasOption(wxT("mgl.screen-refresh") )
166 refresh
= wxSystemOptions::GetOptionInt(wxT("mgl.screen-refresh"));
169 mode
= MGL_findMode(displayMode
.GetScreenSize().x
,
170 displayMode
.GetScreenSize().y
,
171 displayMode
.GetDepth());
174 wxLogError(_("Mode %ix%i-%i not available."),
175 displayMode
.GetScreenSize().x
,
176 displayMode
.GetScreenSize().y
,
177 displayMode
.GetDepth());
180 g_displayDC
= new MGLDisplayDC(mode
, 1, refresh
);
181 if ( !g_displayDC
->isValid() )
188 g_winMng
= MGL_wmCreate(g_displayDC
->getDC());
195 static void wxDestroyMGL_WM()
199 MGL_wmDestroy(g_winMng
);
209 //-----------------------------------------------------------------------------
211 //-----------------------------------------------------------------------------
213 IMPLEMENT_DYNAMIC_CLASS(wxApp
,wxEvtHandler
)
215 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
216 EVT_IDLE(wxApp::OnIdle
)
220 wxApp::wxApp() : m_mainLoop(NULL
)
228 bool wxApp::SetDisplayMode(const wxDisplayModeInfo
& mode
)
234 if ( g_displayDC
!= NULL
)
236 // FIXME_MGL -- we currently don't allow to switch video mode
237 // more than once. This can hopefully be changed...
238 wxFAIL_MSG(wxT("Can't change display mode after intialization!"));
242 if ( !wxCreateMGL_WM(mode
) )
244 gs_rootWindow
= new wxRootWindow
;
246 m_displayMode
= mode
;
251 bool wxApp::OnInitGui()
253 if ( !wxAppBase::OnInitGui() )
257 // That damn MGL redirects stdin and stdout to physical console
258 FILE *file
= fopen("stderr", "wt");
259 wxLog::SetActiveTarget(new wxLogStderr(file
));
265 bool wxApp::ProcessIdle()
268 event
.SetEventObject(this);
271 return event
.MoreRequested();
274 void wxApp::OnIdle(wxIdleEvent
&event
)
276 static bool s_inOnIdle
= FALSE
;
278 /* Avoid recursion (via ProcessEvent default case) */
284 /* Resend in the main thread events which have been prepared in other
286 ProcessPendingEvents();
288 // 'Garbage' collection of windows deleted with Close().
289 DeletePendingObjects();
291 // Send OnIdle events to all windows
292 if ( SendIdleEvents() )
293 event
.RequestMore(TRUE
);
298 bool wxApp::SendIdleEvents()
300 bool needMore
= FALSE
;
302 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
305 wxWindow
* win
= node
->GetData();
306 if ( SendIdleEvents(win
) )
308 node
= node
->GetNext();
314 bool wxApp::SendIdleEvents(wxWindow
* win
)
316 bool needMore
= FALSE
;
319 event
.SetEventObject(win
);
321 win
->GetEventHandler()->ProcessEvent(event
);
323 if ( event
.MoreRequested() )
326 wxNode
* node
= win
->GetChildren().First();
329 wxWindow
* win
= (wxWindow
*) node
->Data();
330 if ( SendIdleEvents(win
) )
338 int wxApp::MainLoop()
341 m_mainLoop
= new wxEventLoop
;
343 rt
= m_mainLoop
->Run();
350 void wxApp::ExitMainLoop()
356 bool wxApp::Initialized()
358 return (wxTopLevelWindows
.GetCount() != 0);
361 bool wxApp::Pending()
363 return wxEventLoop::GetActive()->Pending();
366 void wxApp::Dispatch()
368 wxEventLoop::GetActive()->Dispatch();
371 void wxApp::DeletePendingObjects()
373 wxNode
*node
= wxPendingDelete
.First();
376 wxObject
*obj
= (wxObject
*)node
->Data();
380 if ( wxPendingDelete
.Find(obj
) )
383 node
= wxPendingDelete
.First();
387 bool wxApp::Initialize()
389 if ( MGL_init(".", NULL
) == 0 )
392 wxBuffer
= new wxChar
[BUFSIZ
+ 512];
394 wxClassInfo::InitializeClasses();
396 wxSystemSettings::Init();
399 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
402 // GL: I'm annoyed ... I don't know where to put this and I don't want to
403 // create a module for that as it's part of the core.
405 wxPendingEvents
= new wxList
;
406 wxPendingEventsLocker
= new wxCriticalSection
;
409 wxTheColourDatabase
= new wxColourDatabase(wxKEY_STRING
);
410 wxTheColourDatabase
->Initialize();
412 // Can't do this in wxModule, because fonts are needed by stock lists
413 wxTheFontsManager
= new wxFontsManager
;
415 wxInitializeStockLists();
416 wxInitializeStockObjects();
418 #if wxUSE_WX_RESOURCES
419 wxInitializeResourceSystem();
422 wxModule::RegisterModules();
423 if (!wxModule::InitializeModules()) return FALSE
;
428 wxIcon
wxApp::GetStdIcon(int which
) const
430 return wxTheme::Get()->GetRenderer()->GetStdIcon(which
);
433 void wxApp::CleanUp()
435 delete gs_rootWindow
;
438 // flush the logged messages if any
439 wxLog
*log
= wxLog::GetActiveTarget();
440 if (log
!= NULL
&& log
->HasPendingMessages())
443 // continuing to use user defined log target is unsafe from now on because
444 // some resources may be already unavailable, so replace it by something
446 wxLog
*oldlog
= wxLog::SetActiveTarget(new wxLogStderr
);
451 wxModule::CleanUpModules();
453 #if wxUSE_WX_RESOURCES
454 wxCleanUpResourceSystem();
457 if (wxTheColourDatabase
)
458 delete wxTheColourDatabase
;
460 wxTheColourDatabase
= (wxColourDatabase
*) NULL
;
462 wxDeleteStockObjects();
463 wxDeleteStockLists();
465 // Can't do this in wxModule, because fonts are needed by stock lists
466 delete wxTheFontsManager
;
467 wxTheFontsManager
= (wxFontsManager
*) NULL
;
470 wxTheApp
= (wxApp
*) NULL
;
472 // GL: I'm annoyed ... I don't know where to put this and I don't want to
473 // create a module for that as it's part of the core.
475 delete wxPendingEvents
;
476 delete wxPendingEventsLocker
;
479 wxSystemSettings::Done();
483 wxClassInfo::CleanUpClasses();
485 // check for memory leaks
486 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
487 if (wxDebugContext::CountObjectsLeft(TRUE
) > 0)
489 wxLogDebug(wxT("There were memory leaks.\n"));
490 wxDebugContext::Dump();
491 wxDebugContext::PrintStatistics();
496 // do this as the very last thing because everything else can log messages
497 wxLog::DontCreateOnDemand();
499 wxLog
*oldLog
= wxLog::SetActiveTarget( (wxLog
*) NULL
);
509 int wxEntryStart(int argc
, char *argv
[])
511 return wxApp::Initialize() ? 0 : -1;
517 return wxTheApp
->OnInitGui() ? 0 : -1;
521 void wxEntryCleanup()
528 int wxEntry(int argc
, char *argv
[])
530 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
531 // This seems to be necessary since there are 'rogue'
532 // objects present at this point (perhaps global objects?)
533 // Setting a checkpoint will ignore them as far as the
534 // memory checking facility is concerned.
535 // Of course you may argue that memory allocated in globals should be
536 // checked, but this is a reasonable compromise.
537 wxDebugContext::SetCheckpoint();
539 int err
= wxEntryStart(argc
, argv
);
545 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
546 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
548 wxAppInitializerFunction app_ini
= wxApp::GetInitializerFunction();
550 wxObject
*test_app
= app_ini();
552 wxTheApp
= (wxApp
*) test_app
;
555 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
557 wxTheApp
->argc
= argc
;
559 wxTheApp
->argv
= new wxChar
*[argc
+1];
561 while (mb_argc
< argc
)
563 wxTheApp
->argv
[mb_argc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[mb_argc
]));
566 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
568 wxTheApp
->argv
= argv
;
571 wxString
name(wxFileNameFromPath(argv
[0]));
572 wxStripExtension(name
);
573 wxTheApp
->SetAppName(name
);
576 retValue
= wxEntryInitGui();
578 // Here frames insert themselves automatically into wxTopLevelWindows by
579 // getting created in OnInit().
582 if ( !wxTheApp
->OnInit() )
588 /* delete pending toplevel windows (typically a single
589 dialog) so that, if there isn't any left, we don't
591 wxTheApp
->DeletePendingObjects();
593 if ( wxTheApp
->Initialized() )
597 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
600 /* Forcibly delete the window. */
601 if (topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
602 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
604 topWindow
->Close(TRUE
);
605 wxTheApp
->DeletePendingObjects();
610 wxTheApp
->SetTopWindow((wxWindow
*) NULL
);
614 retValue
= wxTheApp
->OnExit();