]> git.saurik.com Git - wxWidgets.git/blob - src/mgl/app.cpp
added conditional compilation test around wxGetDiskSpace for Mac OS X
[wxWidgets.git] / src / mgl / app.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: app.cpp
3 // Author: Vaclav Slavik
4 // based on GTK and MSW implementations
5 // Id: $Id$
6 // Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "app.h"
12 #endif
13
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
16
17 #ifdef __BORLANDC__
18 #pragma hdrstop
19 #endif
20
21
22 #ifndef WX_PRECOMP
23 #include "wx/settings.h"
24 #include "wx/module.h"
25 #include "wx/evtloop.h"
26 #include "wx/frame.h"
27 #include "wx/dialog.h"
28 #include "wx/log.h"
29 #include "wx/intl.h"
30 #endif
31
32 #include "wx/app.h"
33 #include "wx/fontutil.h"
34 #include "wx/mgl/private.h"
35
36 #define MGL_DEBUG
37
38 #if defined(MGL_DEBUG) && !defined(__WXDEBUG__)
39 #undef MGL_DEBUG
40 #endif
41
42 //-----------------------------------------------------------------------------
43 // Global data
44 //-----------------------------------------------------------------------------
45
46 wxApp *wxTheApp = NULL;
47 wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
48
49
50 //-----------------------------------------------------------------------------
51 // wxExit
52 //-----------------------------------------------------------------------------
53
54 void wxExit()
55 {
56 MGL_exit();
57 exit(0);
58 }
59
60 //-----------------------------------------------------------------------------
61 // wxYield
62 //-----------------------------------------------------------------------------
63
64 static bool gs_inYield = FALSE;
65
66 bool wxYield()
67 {
68 #if wxUSE_THREADS
69 if ( !wxThread::IsMain() )
70 {
71 // can't process events from other threads, MGL is thread-unsafe
72 return TRUE;
73 }
74 #endif // wxUSE_THREADS
75
76 gs_inYield = TRUE;
77
78 wxLog::Suspend();
79
80 if ( wxEventLoop::GetActive() )
81 {
82 while (wxEventLoop::GetActive()->Pending())
83 wxEventLoop::GetActive()->Dispatch();
84 }
85
86 /* it's necessary to call ProcessIdle() to update the frames sizes which
87 might have been changed (it also will update other things set from
88 OnUpdateUI() which is a nice (and desired) side effect) */
89 while (wxTheApp->ProcessIdle()) { }
90
91 wxLog::Resume();
92
93 gs_inYield = FALSE;
94
95 return TRUE;
96 }
97
98 bool wxYieldIfNeeded()
99 {
100 if (gs_inYield)
101 return FALSE;
102
103 return wxYield();
104 }
105
106
107 //-----------------------------------------------------------------------------
108 // wxWakeUpIdle
109 //-----------------------------------------------------------------------------
110
111 void wxWakeUpIdle()
112 {
113 #if wxUSE_THREADS
114 if (!wxThread::IsMain())
115 wxMutexGuiEnter();
116 #endif
117
118 while (wxTheApp->ProcessIdle()) {}
119
120 #if wxUSE_THREADS
121 if (!wxThread::IsMain())
122 wxMutexGuiLeave();
123 #endif
124 }
125
126 //-----------------------------------------------------------------------------
127 // wxApp
128 //-----------------------------------------------------------------------------
129
130 IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
131
132 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
133 EVT_IDLE(wxApp::OnIdle)
134 END_EVENT_TABLE()
135
136
137 wxApp::wxApp() : m_mainLoop(NULL)
138 {
139 }
140
141 wxApp::~wxApp()
142 {
143 }
144
145 bool wxApp::OnInitGui()
146 {
147 if ( !wxCreateMGL_WM() )
148 return FALSE;
149
150 // This has to be done *after* wxCreateMGL_WM() because it initializes
151 // wxUniv's themes
152 if ( !wxAppBase::OnInitGui() )
153 return FALSE;
154
155 #ifdef MGL_DEBUG
156 // That damn MGL redirects stdin and stdout to physical console
157 FILE *file = fopen("stderr", "wt");
158 wxLog::SetActiveTarget(new wxLogStderr(file));
159 #endif
160
161 return TRUE;
162 }
163
164 bool wxApp::ProcessIdle()
165 {
166 wxIdleEvent event;
167 event.SetEventObject(this);
168 ProcessEvent(event);
169
170 return event.MoreRequested();
171 }
172
173 void wxApp::OnIdle(wxIdleEvent &event)
174 {
175 static bool s_inOnIdle = FALSE;
176
177 /* Avoid recursion (via ProcessEvent default case) */
178 if (s_inOnIdle)
179 return;
180
181 s_inOnIdle = TRUE;
182
183 /* Resend in the main thread events which have been prepared in other
184 threads */
185 ProcessPendingEvents();
186
187 // 'Garbage' collection of windows deleted with Close().
188 DeletePendingObjects();
189
190 // Send OnIdle events to all windows
191 if ( SendIdleEvents() )
192 event.RequestMore(TRUE);
193
194 s_inOnIdle = FALSE;
195 }
196
197 bool wxApp::SendIdleEvents()
198 {
199 bool needMore = FALSE;
200
201 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
202 while (node)
203 {
204 wxWindow* win = node->GetData();
205 if ( SendIdleEvents(win) )
206 needMore = TRUE;
207 node = node->GetNext();
208 }
209
210 return needMore;
211 }
212
213 bool wxApp::SendIdleEvents(wxWindow* win)
214 {
215 bool needMore = FALSE;
216
217 wxIdleEvent event;
218 event.SetEventObject(win);
219
220 win->GetEventHandler()->ProcessEvent(event);
221
222 if ( event.MoreRequested() )
223 needMore = TRUE;
224
225 wxNode* node = win->GetChildren().First();
226 while (node)
227 {
228 wxWindow* win = (wxWindow*) node->Data();
229 if ( SendIdleEvents(win) )
230 needMore = TRUE;
231
232 node = node->Next();
233 }
234 return needMore;
235 }
236
237 int wxApp::MainLoop()
238 {
239 int rt;
240 m_mainLoop = new wxEventLoop;
241
242 rt = m_mainLoop->Run();
243
244 delete m_mainLoop;
245 m_mainLoop = NULL;
246 return rt;
247 }
248
249 void wxApp::ExitMainLoop()
250 {
251 if ( m_mainLoop )
252 m_mainLoop->Exit(0);
253 }
254
255 bool wxApp::Initialized()
256 {
257 return (wxTopLevelWindows.GetCount() != 0);
258 }
259
260 bool wxApp::Pending()
261 {
262 return wxEventLoop::GetActive()->Pending();
263 }
264
265 void wxApp::Dispatch()
266 {
267 wxEventLoop::GetActive()->Dispatch();
268 }
269
270 void wxApp::DeletePendingObjects()
271 {
272 wxNode *node = wxPendingDelete.First();
273 while (node)
274 {
275 wxObject *obj = (wxObject *)node->Data();
276
277 delete obj;
278
279 if ( wxPendingDelete.Find(obj) )
280 delete node;
281
282 node = wxPendingDelete.First();
283 }
284 }
285
286 bool wxApp::Initialize()
287 {
288 if ( MGL_init(".", NULL) == 0 )
289 return FALSE;
290
291 wxBuffer = new wxChar[BUFSIZ + 512];
292
293 wxClassInfo::InitializeClasses();
294
295 wxSystemSettings::Init();
296
297 #if wxUSE_INTL
298 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
299 #endif
300
301 // GL: I'm annoyed ... I don't know where to put this and I don't want to
302 // create a module for that as it's part of the core.
303 #if wxUSE_THREADS
304 wxPendingEvents = new wxList;
305 wxPendingEventsLocker = new wxCriticalSection;
306 #endif
307
308 wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING);
309 wxTheColourDatabase->Initialize();
310
311 // Can't do this in wxModule, because fonts are needed by stock lists
312 wxTheFontsManager = new wxFontsManager;
313
314 wxInitializeStockLists();
315 wxInitializeStockObjects();
316
317 #if wxUSE_WX_RESOURCES
318 wxInitializeResourceSystem();
319 #endif
320
321 wxModule::RegisterModules();
322 if (!wxModule::InitializeModules()) return FALSE;
323
324 return TRUE;
325 }
326
327 #include "info.xpm"
328 #include "error.xpm"
329 #include "question.xpm"
330 #include "warning.xpm"
331
332 wxIcon wxApp::GetStdIcon(int which) const
333 {
334 switch(which)
335 {
336 case wxICON_INFORMATION:
337 return wxIcon(info_xpm);
338 case wxICON_QUESTION:
339 return wxIcon(question_xpm);
340 case wxICON_EXCLAMATION:
341 return wxIcon(warning_xpm);
342 default:
343 wxFAIL_MSG(wxT("requested non existent standard icon"));
344 // still fall through
345 case wxICON_HAND:
346 return wxIcon(error_xpm);
347 }
348 }
349
350 void wxApp::CleanUp()
351 {
352 #if wxUSE_LOG
353 // flush the logged messages if any
354 wxLog *log = wxLog::GetActiveTarget();
355 if (log != NULL && log->HasPendingMessages())
356 log->Flush();
357
358 // continuing to use user defined log target is unsafe from now on because
359 // some resources may be already unavailable, so replace it by something
360 // more safe
361 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
362 if ( oldlog )
363 delete oldlog;
364 #endif // wxUSE_LOG
365
366 wxModule::CleanUpModules();
367
368 #if wxUSE_WX_RESOURCES
369 wxCleanUpResourceSystem();
370 #endif
371
372 if (wxTheColourDatabase)
373 delete wxTheColourDatabase;
374
375 wxTheColourDatabase = (wxColourDatabase*) NULL;
376
377 wxDeleteStockObjects();
378 wxDeleteStockLists();
379
380 // Can't do this in wxModule, because fonts are needed by stock lists
381 delete wxTheFontsManager;
382 wxTheFontsManager = (wxFontsManager*) NULL;
383
384 delete wxTheApp;
385 wxTheApp = (wxApp*) NULL;
386
387 // GL: I'm annoyed ... I don't know where to put this and I don't want to
388 // create a module for that as it's part of the core.
389 #if wxUSE_THREADS
390 delete wxPendingEvents;
391 delete wxPendingEventsLocker;
392 #endif
393
394 wxSystemSettings::Done();
395
396 delete[] wxBuffer;
397
398 wxClassInfo::CleanUpClasses();
399
400 // check for memory leaks
401 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
402 if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
403 {
404 wxLogDebug(wxT("There were memory leaks.\n"));
405 wxDebugContext::Dump();
406 wxDebugContext::PrintStatistics();
407 }
408 #endif // Debug
409
410 #if wxUSE_LOG
411 // do this as the very last thing because everything else can log messages
412 wxLog::DontCreateOnDemand();
413
414 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
415 if (oldLog)
416 delete oldLog;
417 #endif // wxUSE_LOG
418
419 wxDestroyMGL_WM();
420 MGL_exit();
421 }
422
423
424 int wxEntryStart(int argc, char *argv[])
425 {
426 return wxApp::Initialize() ? 0 : -1;
427 }
428
429
430 int wxEntryInitGui()
431 {
432 return wxTheApp->OnInitGui() ? 0 : -1;
433 }
434
435
436 void wxEntryCleanup()
437 {
438 wxApp::CleanUp();
439 }
440
441
442
443 int wxEntry(int argc, char *argv[])
444 {
445 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
446 // This seems to be necessary since there are 'rogue'
447 // objects present at this point (perhaps global objects?)
448 // Setting a checkpoint will ignore them as far as the
449 // memory checking facility is concerned.
450 // Of course you may argue that memory allocated in globals should be
451 // checked, but this is a reasonable compromise.
452 wxDebugContext::SetCheckpoint();
453 #endif
454 int err = wxEntryStart(argc, argv);
455 if ( err )
456 return err;
457
458 if ( !wxTheApp )
459 {
460 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
461 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
462
463 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
464
465 wxObject *test_app = app_ini();
466
467 wxTheApp = (wxApp*) test_app;
468 }
469
470 wxCHECK_MSG( wxTheApp, -1, wxT("wxWindows error: no application object") );
471
472 wxTheApp->argc = argc;
473 #if wxUSE_UNICODE
474 wxTheApp->argv = new wxChar*[argc+1];
475 int mb_argc = 0;
476 while (mb_argc < argc)
477 {
478 wxTheApp->argv[mb_argc] = wxStrdup(wxConvLibc.cMB2WX(argv[mb_argc]));
479 mb_argc++;
480 }
481 wxTheApp->argv[mb_argc] = (wxChar *)NULL;
482 #else
483 wxTheApp->argv = argv;
484 #endif
485
486 wxString name(wxFileNameFromPath(argv[0]));
487 wxStripExtension(name);
488 wxTheApp->SetAppName(name);
489
490 int retValue;
491 retValue = wxEntryInitGui();
492
493 // Here frames insert themselves automatically into wxTopLevelWindows by
494 // getting created in OnInit().
495 if ( retValue == 0 )
496 {
497 if ( !wxTheApp->OnInit() )
498 retValue = -1;
499 }
500
501 if ( retValue == 0 )
502 {
503 /* delete pending toplevel windows (typically a single
504 dialog) so that, if there isn't any left, we don't
505 call OnRun() */
506 wxTheApp->DeletePendingObjects();
507
508 if ( wxTheApp->Initialized() )
509 {
510 wxTheApp->OnRun();
511
512 wxWindow *topWindow = wxTheApp->GetTopWindow();
513 if ( topWindow )
514 {
515 /* Forcibly delete the window. */
516 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
517 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
518 {
519 topWindow->Close(TRUE);
520 wxTheApp->DeletePendingObjects();
521 }
522 else
523 {
524 delete topWindow;
525 wxTheApp->SetTopWindow((wxWindow*) NULL);
526 }
527 }
528
529 retValue = wxTheApp->OnExit();
530 }
531 }
532
533 wxEntryCleanup();
534
535 return retValue;
536 }