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