changed exceptions handling to work under wxGTK
[wxWidgets.git] / src / common / appcmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: common/appcmn.cpp
3 // Purpose: wxAppConsole and wxAppBase methods common to all platforms
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 18.10.99
7 // RCS-ID: $Id$
8 // Copyright: (c) Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "appbase.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #if defined(__BORLANDC__)
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/app.h"
33 #include "wx/bitmap.h"
34 #include "wx/intl.h"
35 #include "wx/list.h"
36 #include "wx/log.h"
37 #include "wx/msgdlg.h"
38 #include "wx/bitmap.h"
39 #include "wx/confbase.h"
40 #endif
41
42 #include "wx/apptrait.h"
43 #include "wx/cmdline.h"
44 #include "wx/evtloop.h"
45 #include "wx/msgout.h"
46 #include "wx/thread.h"
47 #include "wx/utils.h"
48 #include "wx/ptr_scpd.h"
49 #include "wx/evtloop.h"
50
51 #if defined(__WXMSW__)
52 #include "wx/msw/private.h" // includes windows.h for LOGFONT
53 #endif
54
55 #if wxUSE_FONTMAP
56 #include "wx/fontmap.h"
57 #endif // wxUSE_FONTMAP
58
59 // DLL options compatibility check:
60 #include "wx/build.h"
61 WX_CHECK_BUILD_OPTIONS("wxCore")
62
63
64 // ----------------------------------------------------------------------------
65 // wxEventLoopPtr
66 // ----------------------------------------------------------------------------
67
68 // this defines wxEventLoopPtr
69 wxDEFINE_TIED_SCOPED_PTR_TYPE(wxEventLoop);
70
71 // ============================================================================
72 // wxAppBase implementation
73 // ============================================================================
74
75 // ----------------------------------------------------------------------------
76 // initialization
77 // ----------------------------------------------------------------------------
78
79 wxAppBase::wxAppBase()
80 {
81 m_topWindow = (wxWindow *)NULL;
82 m_useBestVisual = false;
83 m_isActive = true;
84
85 #if wxUSE_EVTLOOP_IN_APP
86 m_mainLoop = NULL;
87 #endif // wxUSE_EVTLOOP_IN_APP
88
89 // We don't want to exit the app if the user code shows a dialog from its
90 // OnInit() -- but this is what would happen if we set m_exitOnFrameDelete
91 // to Yes initially as this dialog would be the last top level window.
92 // OTOH, if we set it to No initially we'll have to overwrite it with Yes
93 // when we enter our OnRun() because we do want the default behaviour from
94 // then on. But this would be a problem if the user code calls
95 // SetExitOnFrameDelete(false) from OnInit().
96 //
97 // So we use the special "Later" value which is such that
98 // GetExitOnFrameDelete() returns false for it but which we know we can
99 // safely (i.e. without losing the effect of the users SetExitOnFrameDelete
100 // call) overwrite in OnRun()
101 m_exitOnFrameDelete = Later;
102 }
103
104 bool wxAppBase::Initialize(int& argc, wxChar **argv)
105 {
106 if ( !wxAppConsole::Initialize(argc, argv) )
107 return false;
108
109 #if wxUSE_THREADS
110 wxPendingEventsLocker = new wxCriticalSection;
111 #endif
112
113 wxInitializeStockLists();
114 wxInitializeStockObjects();
115
116 wxBitmap::InitStandardHandlers();
117
118 return true;
119 }
120
121 // ----------------------------------------------------------------------------
122 // cleanup
123 // ----------------------------------------------------------------------------
124
125 wxAppBase::~wxAppBase()
126 {
127 // this destructor is required for Darwin
128 }
129
130 void wxAppBase::CleanUp()
131 {
132 // clean up all the pending objects
133 DeletePendingObjects();
134
135 // and any remaining TLWs (they remove themselves from wxTopLevelWindows
136 // when destroyed, so iterate until none are left)
137 while ( !wxTopLevelWindows.empty() )
138 {
139 // do not use Destroy() here as it only puts the TLW in pending list
140 // but we want to delete them now
141 delete wxTopLevelWindows.GetFirst()->GetData();
142 }
143
144 // undo everything we did in Initialize() above
145 wxBitmap::CleanUpHandlers();
146
147 wxDeleteStockObjects();
148
149 wxDeleteStockLists();
150
151 delete wxTheColourDatabase;
152 wxTheColourDatabase = NULL;
153
154 delete wxPendingEvents;
155 wxPendingEvents = NULL;
156
157 #if wxUSE_THREADS
158 delete wxPendingEventsLocker;
159 wxPendingEventsLocker = NULL;
160
161 #if wxUSE_VALIDATORS
162 // If we don't do the following, we get an apparent memory leak.
163 ((wxEvtHandler&) wxDefaultValidator).ClearEventLocker();
164 #endif // wxUSE_VALIDATORS
165 #endif // wxUSE_THREADS
166 }
167
168 #if wxUSE_CMDLINE_PARSER
169
170 // ----------------------------------------------------------------------------
171 // GUI-specific command line options handling
172 // ----------------------------------------------------------------------------
173
174 #define OPTION_THEME _T("theme")
175 #define OPTION_MODE _T("mode")
176
177 void wxAppBase::OnInitCmdLine(wxCmdLineParser& parser)
178 {
179 // first add the standard non GUI options
180 wxAppConsole::OnInitCmdLine(parser);
181
182 // the standard command line options
183 static const wxCmdLineEntryDesc cmdLineGUIDesc[] =
184 {
185 #ifdef __WXUNIVERSAL__
186 {
187 wxCMD_LINE_OPTION,
188 wxEmptyString,
189 OPTION_THEME,
190 gettext_noop("specify the theme to use"),
191 wxCMD_LINE_VAL_STRING,
192 0x0
193 },
194 #endif // __WXUNIVERSAL__
195
196 #if defined(__WXMGL__)
197 // VS: this is not specific to wxMGL, all fullscreen (framebuffer) ports
198 // should provide this option. That's why it is in common/appcmn.cpp
199 // and not mgl/app.cpp
200 {
201 wxCMD_LINE_OPTION,
202 wxEmptyString,
203 OPTION_MODE,
204 gettext_noop("specify display mode to use (e.g. 640x480-16)"),
205 wxCMD_LINE_VAL_STRING,
206 0x0
207 },
208 #endif // __WXMGL__
209
210 // terminator
211 {
212 wxCMD_LINE_NONE,
213 wxEmptyString,
214 wxEmptyString,
215 wxEmptyString,
216 wxCMD_LINE_VAL_NONE,
217 0x0
218 }
219 };
220
221 parser.SetDesc(cmdLineGUIDesc);
222 }
223
224 bool wxAppBase::OnCmdLineParsed(wxCmdLineParser& parser)
225 {
226 #ifdef __WXUNIVERSAL__
227 wxString themeName;
228 if ( parser.Found(OPTION_THEME, &themeName) )
229 {
230 wxTheme *theme = wxTheme::Create(themeName);
231 if ( !theme )
232 {
233 wxLogError(_("Unsupported theme '%s'."), themeName.c_str());
234 return false;
235 }
236
237 // Delete the defaultly created theme and set the new theme.
238 delete wxTheme::Get();
239 wxTheme::Set(theme);
240 }
241 #endif // __WXUNIVERSAL__
242
243 #if defined(__WXMGL__)
244 wxString modeDesc;
245 if ( parser.Found(OPTION_MODE, &modeDesc) )
246 {
247 unsigned w, h, bpp;
248 if ( wxSscanf(modeDesc.c_str(), _T("%ux%u-%u"), &w, &h, &bpp) != 3 )
249 {
250 wxLogError(_("Invalid display mode specification '%s'."), modeDesc.c_str());
251 return false;
252 }
253
254 if ( !SetDisplayMode(wxVideoMode(w, h, bpp)) )
255 return false;
256 }
257 #endif // __WXMGL__
258
259 return wxAppConsole::OnCmdLineParsed(parser);
260 }
261
262 #endif // wxUSE_CMDLINE_PARSER
263
264 // ----------------------------------------------------------------------------
265 // main event loop implementation
266 // ----------------------------------------------------------------------------
267
268 int wxAppBase::MainLoop()
269 {
270 #if wxUSE_EVTLOOP_IN_APP
271 wxEventLoopTiedPtr mainLoop(&m_mainLoop, new wxEventLoop);
272
273 return m_mainLoop->Run();
274 #else // !wxUSE_EVTLOOP_IN_APP
275 return 0;
276 #endif // wxUSE_EVTLOOP_IN_APP/!wxUSE_EVTLOOP_IN_APP
277 }
278
279 void wxAppBase::ExitMainLoop()
280 {
281 #if wxUSE_EVTLOOP_IN_APP
282 // we should exit from the main event loop, not just any currently active
283 // (e.g. modal dialog) event loop
284 if ( m_mainLoop && m_mainLoop->IsRunning() )
285 {
286 m_mainLoop->Exit(0);
287 }
288 #endif // wxUSE_EVTLOOP_IN_APP
289 }
290
291 bool wxAppBase::Pending()
292 {
293 #if wxUSE_EVTLOOP_IN_APP
294 // use the currently active message loop here, not m_mainLoop, because if
295 // we're showing a modal dialog (with its own event loop) currently the
296 // main event loop is not running anyhow
297 wxEventLoop * const loop = wxEventLoop::GetActive();
298
299 return loop && loop->Pending();
300 #else // wxUSE_EVTLOOP_IN_APP
301 return false;
302 #endif // wxUSE_EVTLOOP_IN_APP/!wxUSE_EVTLOOP_IN_APP
303 }
304
305 bool wxAppBase::Dispatch()
306 {
307 #if wxUSE_EVTLOOP_IN_APP
308 // see comment in Pending()
309 wxEventLoop * const loop = wxEventLoop::GetActive();
310
311 return loop && loop->Dispatch();
312 #else // wxUSE_EVTLOOP_IN_APP
313 return true;
314 #endif // wxUSE_EVTLOOP_IN_APP/!wxUSE_EVTLOOP_IN_APP
315 }
316
317 // ----------------------------------------------------------------------------
318 // OnXXX() hooks
319 // ----------------------------------------------------------------------------
320
321 bool wxAppBase::OnInitGui()
322 {
323 #ifdef __WXUNIVERSAL__
324 if ( !wxTheme::Get() && !wxTheme::CreateDefault() )
325 return false;
326 #endif // __WXUNIVERSAL__
327
328 return true;
329 }
330
331 int wxAppBase::OnRun()
332 {
333 // see the comment in ctor: if the initial value hasn't been changed, use
334 // the default Yes from now on
335 if ( m_exitOnFrameDelete == Later )
336 {
337 m_exitOnFrameDelete = Yes;
338 }
339 //else: it has been changed, assume the user knows what he is doing
340
341 return MainLoop();
342 }
343
344 int wxAppBase::OnExit()
345 {
346 #ifdef __WXUNIVERSAL__
347 delete wxTheme::Set(NULL);
348 #endif // __WXUNIVERSAL__
349
350 return wxAppConsole::OnExit();
351 }
352
353 void wxAppBase::Exit()
354 {
355 ExitMainLoop();
356 }
357
358 wxAppTraits *wxAppBase::CreateTraits()
359 {
360 return new wxGUIAppTraits;
361 }
362
363 // ----------------------------------------------------------------------------
364 // misc
365 // ----------------------------------------------------------------------------
366
367 void wxAppBase::SetActive(bool active, wxWindow * WXUNUSED(lastFocus))
368 {
369 if ( active == m_isActive )
370 return;
371
372 m_isActive = active;
373
374 wxActivateEvent event(wxEVT_ACTIVATE_APP, active);
375 event.SetEventObject(this);
376
377 (void)ProcessEvent(event);
378 }
379
380 void wxAppBase::DeletePendingObjects()
381 {
382 wxList::compatibility_iterator node = wxPendingDelete.GetFirst();
383 while (node)
384 {
385 wxObject *obj = node->GetData();
386
387 delete obj;
388
389 if (wxPendingDelete.Member(obj))
390 wxPendingDelete.Erase(node);
391
392 // Deleting one object may have deleted other pending
393 // objects, so start from beginning of list again.
394 node = wxPendingDelete.GetFirst();
395 }
396 }
397
398 // Returns true if more time is needed.
399 bool wxAppBase::ProcessIdle()
400 {
401 wxIdleEvent event;
402 bool needMore = false;
403 wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst();
404 while (node)
405 {
406 wxWindow* win = node->GetData();
407 if (SendIdleEvents(win, event))
408 needMore = true;
409 node = node->GetNext();
410 }
411
412 event.SetEventObject(this);
413 (void) ProcessEvent(event);
414 if (event.MoreRequested())
415 needMore = true;
416
417 wxUpdateUIEvent::ResetUpdateTime();
418
419 return needMore;
420 }
421
422 // Send idle event to window and all subwindows
423 bool wxAppBase::SendIdleEvents(wxWindow* win, wxIdleEvent& event)
424 {
425 bool needMore = false;
426
427 win->OnInternalIdle();
428
429 if (wxIdleEvent::CanSend(win))
430 {
431 event.SetEventObject(win);
432 win->GetEventHandler()->ProcessEvent(event);
433
434 if (event.MoreRequested())
435 needMore = true;
436 }
437 wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
438 while ( node )
439 {
440 wxWindow *child = node->GetData();
441 if (SendIdleEvents(child, event))
442 needMore = true;
443
444 node = node->GetNext();
445 }
446
447 return needMore;
448 }
449
450 void wxAppBase::OnIdle(wxIdleEvent& WXUNUSED(event))
451 {
452 // If there are pending events, we must process them: pending events
453 // are either events to the threads other than main or events posted
454 // with wxPostEvent() functions
455 // GRG: I have moved this here so that all pending events are processed
456 // before starting to delete any objects. This behaves better (in
457 // particular, wrt wxPostEvent) and is coherent with wxGTK's current
458 // behaviour. Changed Feb/2000 before 2.1.14
459 ProcessPendingEvents();
460
461 // 'Garbage' collection of windows deleted with Close().
462 DeletePendingObjects();
463
464 #if wxUSE_LOG
465 // flush the logged messages if any
466 wxLog::FlushActive();
467 #endif // wxUSE_LOG
468
469 }
470
471 // ----------------------------------------------------------------------------
472 // exception handling
473 // ----------------------------------------------------------------------------
474
475 #if wxUSE_EXCEPTIONS
476
477 void wxAppBase::HandleEvent(wxEvtHandler *handler,
478 wxEventFunction func,
479 wxEvent& event) const
480 {
481 // by default, call wxApp::OnExceptionInMainLoop if an exception occurs
482 try
483 {
484 handler->DoHandleEvent(func, event);
485 }
486 catch ( ... )
487 {
488 if ( !wxConstCast(this, wxAppBase)->OnExceptionInMainLoop() )
489 {
490 wxEventLoop *loop = wxEventLoop::GetActive();
491 if ( loop )
492 loop->Exit(-1);
493 }
494 //else: continue running the event loop
495 }
496 }
497
498 #endif // wxUSE_EXCEPTIONS
499
500 // ----------------------------------------------------------------------------
501 // wxGUIAppTraitsBase
502 // ----------------------------------------------------------------------------
503
504 #if wxUSE_LOG
505
506 wxLog *wxGUIAppTraitsBase::CreateLogTarget()
507 {
508 #if wxUSE_LOGGUI
509 return new wxLogGui;
510 #else
511 // we must have something!
512 return new wxLogStderr;
513 #endif
514 }
515
516 #endif // wxUSE_LOG
517
518 wxMessageOutput *wxGUIAppTraitsBase::CreateMessageOutput()
519 {
520 // The standard way of printing help on command line arguments (app --help)
521 // is (according to common practice):
522 // - console apps: to stderr (on any platform)
523 // - GUI apps: stderr on Unix platforms (!)
524 // message box under Windows and others
525 #ifdef __UNIX__
526 return new wxMessageOutputStderr;
527 #else // !__UNIX__
528 // wxMessageOutputMessageBox doesn't work under Motif
529 #ifdef __WXMOTIF__
530 return new wxMessageOutputLog;
531 #else
532 return new wxMessageOutputMessageBox;
533 #endif
534 #endif // __UNIX__/!__UNIX__
535 }
536
537 #if wxUSE_FONTMAP
538
539 wxFontMapper *wxGUIAppTraitsBase::CreateFontMapper()
540 {
541 return new wxFontMapper;
542 }
543
544 #endif // wxUSE_FONTMAP
545
546 wxRendererNative *wxGUIAppTraitsBase::CreateRenderer()
547 {
548 // use the default native renderer by default
549 return NULL;
550 }
551
552 #ifdef __WXDEBUG__
553
554 bool wxGUIAppTraitsBase::ShowAssertDialog(const wxString& msg)
555 {
556 // under MSW we prefer to use the base class version using ::MessageBox()
557 // even if wxMessageBox() is available because it has less chances to
558 // double fault our app than our wxMessageBox()
559 #if defined(__WXMSW__) || !wxUSE_MSGDLG
560 return wxAppTraitsBase::ShowAssertDialog(msg);
561 #else // wxUSE_MSGDLG
562 // this message is intentionally not translated -- it is for
563 // developpers only
564 wxString msgDlg(msg);
565 msgDlg += wxT("\nDo you want to stop the program?\n")
566 wxT("You can also choose [Cancel] to suppress ")
567 wxT("further warnings.");
568
569 switch ( wxMessageBox(msgDlg, wxT("wxWidgets Debug Alert"),
570 wxYES_NO | wxCANCEL | wxICON_STOP ) )
571 {
572 case wxYES:
573 wxTrap();
574 break;
575
576 case wxCANCEL:
577 // no more asserts
578 return true;
579
580 //case wxNO: nothing to do
581 }
582
583 return false;
584 #endif // !wxUSE_MSGDLG/wxUSE_MSGDLG
585 }
586
587 #endif // __WXDEBUG__
588
589 bool wxGUIAppTraitsBase::HasStderr()
590 {
591 // we consider that under Unix stderr always goes somewhere, even if the
592 // user doesn't always see it under GUI desktops
593 #ifdef __UNIX__
594 return true;
595 #else
596 return false;
597 #endif
598 }
599
600 void wxGUIAppTraitsBase::ScheduleForDestroy(wxObject *object)
601 {
602 if ( !wxPendingDelete.Member(object) )
603 wxPendingDelete.Append(object);
604 }
605
606 void wxGUIAppTraitsBase::RemoveFromPendingDelete(wxObject *object)
607 {
608 wxPendingDelete.DeleteObject(object);
609 }
610
611 #if wxUSE_SOCKETS
612
613 #if defined(__WINDOWS__)
614 #include "wx/msw/gsockmsw.h"
615 #elif defined(__UNIX__) || defined(__DARWIN__) || defined(__OS2__)
616 #include "wx/unix/gsockunx.h"
617 #elif defined(__WXMAC__)
618 #include <MacHeaders.c>
619 #define OTUNIXERRORS 1
620 #include <OpenTransport.h>
621 #include <OpenTransportProviders.h>
622 #include <OpenTptInternet.h>
623
624 #include "wx/mac/gsockmac.h"
625 #else
626 #error "Must include correct GSocket header here"
627 #endif
628
629 GSocketGUIFunctionsTable* wxGUIAppTraitsBase::GetSocketGUIFunctionsTable()
630 {
631 #if defined(__WXMAC__) && !defined(__DARWIN__)
632 // NB: wxMac CFM does not have any GUI-specific functions in gsocket.c and
633 // so it doesn't need this table at all
634 return NULL;
635 #else // !__WXMAC__ || __DARWIN__
636 static GSocketGUIFunctionsTableConcrete table;
637 return &table;
638 #endif // !__WXMAC__ || __DARWIN__
639 }
640
641 #endif
642