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