]> git.saurik.com Git - wxWidgets.git/blob - src/mgl/app.cpp
better <HR> tag handling in wxHTML
[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 #include "wx/resource.h"
31 #endif
32
33 #include "wx/app.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"
39
40 #define MGL_DEBUG
41
42 #if defined(MGL_DEBUG) && !defined(__WXDEBUG__)
43 #undef MGL_DEBUG
44 #endif
45
46 //-----------------------------------------------------------------------------
47 // Global data
48 //-----------------------------------------------------------------------------
49
50 wxApp *wxTheApp = NULL;
51 wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
52
53
54 //-----------------------------------------------------------------------------
55 // wxExit
56 //-----------------------------------------------------------------------------
57
58 void wxExit()
59 {
60 MGL_exit();
61 exit(0);
62 }
63
64 //-----------------------------------------------------------------------------
65 // wxYield
66 //-----------------------------------------------------------------------------
67
68 static bool gs_inYield = FALSE;
69
70 bool wxApp::Yield(bool onlyIfNeeded)
71 {
72 if ( gs_inYield )
73 {
74 if ( !onlyIfNeeded )
75 {
76 wxFAIL_MSG( wxT("wxYield called recursively" ) );
77 }
78
79 return FALSE;
80 }
81
82 #if wxUSE_THREADS
83 if ( !wxThread::IsMain() )
84 {
85 // can't process events from other threads, MGL is thread-unsafe
86 return TRUE;
87 }
88 #endif // wxUSE_THREADS
89
90 gs_inYield = TRUE;
91
92 wxLog::Suspend();
93
94 if ( wxEventLoop::GetActive() )
95 {
96 while (wxEventLoop::GetActive()->Pending())
97 wxEventLoop::GetActive()->Dispatch();
98 }
99
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()) { }
104
105 wxLog::Resume();
106
107 gs_inYield = FALSE;
108
109 return TRUE;
110 }
111
112
113 //-----------------------------------------------------------------------------
114 // wxWakeUpIdle
115 //-----------------------------------------------------------------------------
116
117 void wxWakeUpIdle()
118 {
119 #if wxUSE_THREADS
120 if (!wxThread::IsMain())
121 wxMutexGuiEnter();
122 #endif
123
124 while (wxTheApp->ProcessIdle()) {}
125
126 #if wxUSE_THREADS
127 if (!wxThread::IsMain())
128 wxMutexGuiLeave();
129 #endif
130 }
131
132 //-----------------------------------------------------------------------------
133 // Root window
134 //-----------------------------------------------------------------------------
135
136 class wxRootWindow : public wxWindow
137 {
138 public:
139 wxRootWindow() : wxWindow(NULL, -1)
140 {
141 SetMGLwindow_t(MGL_wmGetRootWindow(g_winMng));
142 SetBackgroundColour(wxTHEME_COLOUR(DESKTOP));
143 }
144 ~wxRootWindow()
145 {
146 // we don't want to delete MGL_WM's rootWnd
147 m_wnd = NULL;
148 }
149
150 virtual bool AcceptsFocus() { return FALSE; }
151 };
152
153 static wxRootWindow *gs_rootWindow = NULL;
154
155 //-----------------------------------------------------------------------------
156 // MGL initialization
157 //-----------------------------------------------------------------------------
158
159 static bool wxCreateMGL_WM(const wxDisplayModeInfo& displayMode)
160 {
161 int mode;
162 int refresh = MGL_DEFAULT_REFRESH;
163
164 #if wxUSE_SYSTEM_OPTIONS
165 if ( wxSystemOptions::HasOption(wxT("mgl.screen-refresh") )
166 refresh = wxSystemOptions::GetOptionInt(wxT("mgl.screen-refresh"));
167 #endif
168
169 mode = MGL_findMode(displayMode.GetScreenSize().x,
170 displayMode.GetScreenSize().y,
171 displayMode.GetDepth());
172 if ( mode == -1 )
173 {
174 wxLogError(_("Mode %ix%i-%i not available."),
175 displayMode.GetScreenSize().x,
176 displayMode.GetScreenSize().y,
177 displayMode.GetDepth());
178 return FALSE;
179 }
180 g_displayDC = new MGLDisplayDC(mode, 1, refresh);
181 if ( !g_displayDC->isValid() )
182 {
183 delete g_displayDC;
184 g_displayDC = NULL;
185 return FALSE;
186 }
187
188 g_winMng = MGL_wmCreate(g_displayDC->getDC());
189 if (!g_winMng)
190 return FALSE;
191
192 return TRUE;
193 }
194
195 static void wxDestroyMGL_WM()
196 {
197 if ( g_winMng )
198 {
199 MGL_wmDestroy(g_winMng);
200 g_winMng = NULL;
201 }
202 if ( g_displayDC )
203 {
204 delete g_displayDC;
205 g_displayDC = NULL;
206 }
207 }
208
209 //-----------------------------------------------------------------------------
210 // wxApp
211 //-----------------------------------------------------------------------------
212
213 IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
214
215 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
216 EVT_IDLE(wxApp::OnIdle)
217 END_EVENT_TABLE()
218
219
220 wxApp::wxApp() : m_mainLoop(NULL)
221 {
222 }
223
224 wxApp::~wxApp()
225 {
226 }
227
228 bool wxApp::SetDisplayMode(const wxDisplayModeInfo& mode)
229 {
230 if ( !mode.IsOk() )
231 {
232 return FALSE;
233 }
234 if ( g_displayDC != NULL )
235 {
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!"));
239 return FALSE;
240 }
241
242 if ( !wxCreateMGL_WM(mode) )
243 return FALSE;
244 gs_rootWindow = new wxRootWindow;
245
246 m_displayMode = mode;
247
248 return TRUE;
249 }
250
251 bool wxApp::OnInitGui()
252 {
253 if ( !wxAppBase::OnInitGui() )
254 return FALSE;
255
256 #ifdef MGL_DEBUG
257 // That damn MGL redirects stdin and stdout to physical console
258 FILE *file = fopen("stderr", "wt");
259 wxLog::SetActiveTarget(new wxLogStderr(file));
260 #endif
261
262 return TRUE;
263 }
264
265 bool wxApp::ProcessIdle()
266 {
267 wxIdleEvent event;
268 event.SetEventObject(this);
269 ProcessEvent(event);
270
271 return event.MoreRequested();
272 }
273
274 void wxApp::OnIdle(wxIdleEvent &event)
275 {
276 static bool s_inOnIdle = FALSE;
277
278 /* Avoid recursion (via ProcessEvent default case) */
279 if (s_inOnIdle)
280 return;
281
282 s_inOnIdle = TRUE;
283
284 /* Resend in the main thread events which have been prepared in other
285 threads */
286 ProcessPendingEvents();
287
288 // 'Garbage' collection of windows deleted with Close().
289 DeletePendingObjects();
290
291 // Send OnIdle events to all windows
292 if ( SendIdleEvents() )
293 event.RequestMore(TRUE);
294
295 s_inOnIdle = FALSE;
296 }
297
298 bool wxApp::SendIdleEvents()
299 {
300 bool needMore = FALSE;
301
302 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
303 while (node)
304 {
305 wxWindow* win = node->GetData();
306 if ( SendIdleEvents(win) )
307 needMore = TRUE;
308 node = node->GetNext();
309 }
310
311 return needMore;
312 }
313
314 bool wxApp::SendIdleEvents(wxWindow* win)
315 {
316 bool needMore = FALSE;
317
318 wxIdleEvent event;
319 event.SetEventObject(win);
320
321 win->GetEventHandler()->ProcessEvent(event);
322
323 if ( event.MoreRequested() )
324 needMore = TRUE;
325
326 wxNode* node = win->GetChildren().First();
327 while (node)
328 {
329 wxWindow* win = (wxWindow*) node->Data();
330 if ( SendIdleEvents(win) )
331 needMore = TRUE;
332
333 node = node->Next();
334 }
335 return needMore;
336 }
337
338 int wxApp::MainLoop()
339 {
340 int rt;
341 m_mainLoop = new wxEventLoop;
342
343 rt = m_mainLoop->Run();
344
345 delete m_mainLoop;
346 m_mainLoop = NULL;
347 return rt;
348 }
349
350 void wxApp::ExitMainLoop()
351 {
352 if ( m_mainLoop )
353 m_mainLoop->Exit(0);
354 }
355
356 bool wxApp::Initialized()
357 {
358 return (wxTopLevelWindows.GetCount() != 0);
359 }
360
361 bool wxApp::Pending()
362 {
363 return wxEventLoop::GetActive()->Pending();
364 }
365
366 void wxApp::Dispatch()
367 {
368 wxEventLoop::GetActive()->Dispatch();
369 }
370
371 void wxApp::DeletePendingObjects()
372 {
373 wxNode *node = wxPendingDelete.First();
374 while (node)
375 {
376 wxObject *obj = (wxObject *)node->Data();
377
378 delete obj;
379
380 if ( wxPendingDelete.Find(obj) )
381 delete node;
382
383 node = wxPendingDelete.First();
384 }
385 }
386
387 bool wxApp::Initialize()
388 {
389 if ( MGL_init(".", NULL) == 0 )
390 return FALSE;
391
392 wxBuffer = new wxChar[BUFSIZ + 512];
393
394 wxClassInfo::InitializeClasses();
395
396 wxSystemSettings::Init();
397
398 #if wxUSE_INTL
399 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
400 #endif
401
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.
404 #if wxUSE_THREADS
405 wxPendingEvents = new wxList;
406 wxPendingEventsLocker = new wxCriticalSection;
407 #endif
408
409 wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING);
410 wxTheColourDatabase->Initialize();
411
412 // Can't do this in wxModule, because fonts are needed by stock lists
413 wxTheFontsManager = new wxFontsManager;
414
415 wxInitializeStockLists();
416 wxInitializeStockObjects();
417
418 #if wxUSE_WX_RESOURCES
419 wxInitializeResourceSystem();
420 #endif
421
422 wxModule::RegisterModules();
423 if (!wxModule::InitializeModules()) return FALSE;
424
425 return TRUE;
426 }
427
428 wxIcon wxApp::GetStdIcon(int which) const
429 {
430 return wxTheme::Get()->GetRenderer()->GetStdIcon(which);
431 }
432
433 void wxApp::CleanUp()
434 {
435 delete gs_rootWindow;
436
437 #if wxUSE_LOG
438 // flush the logged messages if any
439 wxLog *log = wxLog::GetActiveTarget();
440 if (log != NULL && log->HasPendingMessages())
441 log->Flush();
442
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
445 // more safe
446 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
447 if ( oldlog )
448 delete oldlog;
449 #endif // wxUSE_LOG
450
451 wxModule::CleanUpModules();
452
453 #if wxUSE_WX_RESOURCES
454 wxCleanUpResourceSystem();
455 #endif
456
457 if (wxTheColourDatabase)
458 delete wxTheColourDatabase;
459
460 wxTheColourDatabase = (wxColourDatabase*) NULL;
461
462 wxDeleteStockObjects();
463 wxDeleteStockLists();
464
465 // Can't do this in wxModule, because fonts are needed by stock lists
466 delete wxTheFontsManager;
467 wxTheFontsManager = (wxFontsManager*) NULL;
468
469 delete wxTheApp;
470 wxTheApp = (wxApp*) NULL;
471
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.
474 #if wxUSE_THREADS
475 delete wxPendingEvents;
476 delete wxPendingEventsLocker;
477 #endif
478
479 wxSystemSettings::Done();
480
481 delete[] wxBuffer;
482
483 wxClassInfo::CleanUpClasses();
484
485 // check for memory leaks
486 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
487 if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
488 {
489 wxLogDebug(wxT("There were memory leaks.\n"));
490 wxDebugContext::Dump();
491 wxDebugContext::PrintStatistics();
492 }
493 #endif // Debug
494
495 #if wxUSE_LOG
496 // do this as the very last thing because everything else can log messages
497 wxLog::DontCreateOnDemand();
498
499 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
500 if (oldLog)
501 delete oldLog;
502 #endif // wxUSE_LOG
503
504 wxDestroyMGL_WM();
505 MGL_exit();
506 }
507
508
509 int wxEntryStart(int argc, char *argv[])
510 {
511 return wxApp::Initialize() ? 0 : -1;
512 }
513
514
515 int wxEntryInitGui()
516 {
517 return wxTheApp->OnInitGui() ? 0 : -1;
518 }
519
520
521 void wxEntryCleanup()
522 {
523 wxApp::CleanUp();
524 }
525
526
527
528 int wxEntry(int argc, char *argv[])
529 {
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();
538 #endif
539 int err = wxEntryStart(argc, argv);
540 if ( err )
541 return err;
542
543 if ( !wxTheApp )
544 {
545 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
546 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
547
548 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
549
550 wxObject *test_app = app_ini();
551
552 wxTheApp = (wxApp*) test_app;
553 }
554
555 wxCHECK_MSG( wxTheApp, -1, wxT("wxWindows error: no application object") );
556
557 wxTheApp->argc = argc;
558 #if wxUSE_UNICODE
559 wxTheApp->argv = new wxChar*[argc+1];
560 int mb_argc = 0;
561 while (mb_argc < argc)
562 {
563 wxTheApp->argv[mb_argc] = wxStrdup(wxConvLibc.cMB2WX(argv[mb_argc]));
564 mb_argc++;
565 }
566 wxTheApp->argv[mb_argc] = (wxChar *)NULL;
567 #else
568 wxTheApp->argv = argv;
569 #endif
570
571 wxString name(wxFileNameFromPath(argv[0]));
572 wxStripExtension(name);
573 wxTheApp->SetAppName(name);
574
575 int retValue;
576 retValue = wxEntryInitGui();
577
578 // Here frames insert themselves automatically into wxTopLevelWindows by
579 // getting created in OnInit().
580 if ( retValue == 0 )
581 {
582 if ( !wxTheApp->OnInit() )
583 retValue = -1;
584 }
585
586 if ( retValue == 0 )
587 {
588 /* delete pending toplevel windows (typically a single
589 dialog) so that, if there isn't any left, we don't
590 call OnRun() */
591 wxTheApp->DeletePendingObjects();
592
593 if ( wxTheApp->Initialized() )
594 {
595 wxTheApp->OnRun();
596
597 wxWindow *topWindow = wxTheApp->GetTopWindow();
598 if ( topWindow )
599 {
600 /* Forcibly delete the window. */
601 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
602 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
603 {
604 topWindow->Close(TRUE);
605 wxTheApp->DeletePendingObjects();
606 }
607 else
608 {
609 delete topWindow;
610 wxTheApp->SetTopWindow((wxWindow*) NULL);
611 }
612 }
613
614 retValue = wxTheApp->OnExit();
615 }
616 }
617
618 wxEntryCleanup();
619
620 return retValue;
621 }