Mem leaks in connection with print factory code.
[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/prntbase.h"
50
51 #if defined(__WXMSW__) && !defined(__PALMOS__)
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 wxPrintFactory::SetPrintFactory( NULL );
145
146 // undo everything we did in Initialize() above
147 wxBitmap::CleanUpHandlers();
148
149 wxDeleteStockObjects();
150
151 wxDeleteStockLists();
152
153 delete wxTheColourDatabase;
154 wxTheColourDatabase = NULL;
155
156 delete wxPendingEvents;
157 wxPendingEvents = NULL;
158
159 #if wxUSE_THREADS
160 delete wxPendingEventsLocker;
161 wxPendingEventsLocker = NULL;
162
163 #if wxUSE_VALIDATORS
164 // If we don't do the following, we get an apparent memory leak.
165 ((wxEvtHandler&) wxDefaultValidator).ClearEventLocker();
166 #endif // wxUSE_VALIDATORS
167 #endif // wxUSE_THREADS
168 }
169
170 #if wxUSE_CMDLINE_PARSER
171
172 // ----------------------------------------------------------------------------
173 // GUI-specific command line options handling
174 // ----------------------------------------------------------------------------
175
176 #define OPTION_THEME _T("theme")
177 #define OPTION_MODE _T("mode")
178
179 void wxAppBase::OnInitCmdLine(wxCmdLineParser& parser)
180 {
181 // first add the standard non GUI options
182 wxAppConsole::OnInitCmdLine(parser);
183
184 // the standard command line options
185 static const wxCmdLineEntryDesc cmdLineGUIDesc[] =
186 {
187 #ifdef __WXUNIVERSAL__
188 {
189 wxCMD_LINE_OPTION,
190 _T(""),
191 OPTION_THEME,
192 gettext_noop("specify the theme to use"),
193 wxCMD_LINE_VAL_STRING,
194 0x0
195 },
196 #endif // __WXUNIVERSAL__
197
198 #if defined(__WXMGL__)
199 // VS: this is not specific to wxMGL, all fullscreen (framebuffer) ports
200 // should provide this option. That's why it is in common/appcmn.cpp
201 // and not mgl/app.cpp
202 {
203 wxCMD_LINE_OPTION,
204 _T(""),
205 OPTION_MODE,
206 gettext_noop("specify display mode to use (e.g. 640x480-16)"),
207 wxCMD_LINE_VAL_STRING,
208 0x0
209 },
210 #endif // __WXMGL__
211
212 // terminator
213 {
214 wxCMD_LINE_NONE,
215 _T(""),
216 _T(""),
217 _T(""),
218 wxCMD_LINE_VAL_NONE,
219 0x0
220 }
221 };
222
223 parser.SetDesc(cmdLineGUIDesc);
224 }
225
226 bool wxAppBase::OnCmdLineParsed(wxCmdLineParser& parser)
227 {
228 #ifdef __WXUNIVERSAL__
229 wxString themeName;
230 if ( parser.Found(OPTION_THEME, &themeName) )
231 {
232 wxTheme *theme = wxTheme::Create(themeName);
233 if ( !theme )
234 {
235 wxLogError(_("Unsupported theme '%s'."), themeName.c_str());
236 return false;
237 }
238
239 // Delete the defaultly created theme and set the new theme.
240 delete wxTheme::Get();
241 wxTheme::Set(theme);
242 }
243 #endif // __WXUNIVERSAL__
244
245 #if defined(__WXMGL__)
246 wxString modeDesc;
247 if ( parser.Found(OPTION_MODE, &modeDesc) )
248 {
249 unsigned w, h, bpp;
250 if ( wxSscanf(modeDesc.c_str(), _T("%ux%u-%u"), &w, &h, &bpp) != 3 )
251 {
252 wxLogError(_("Invalid display mode specification '%s'."), modeDesc.c_str());
253 return false;
254 }
255
256 if ( !SetDisplayMode(wxVideoMode(w, h, bpp)) )
257 return false;
258 }
259 #endif // __WXMGL__
260
261 return wxAppConsole::OnCmdLineParsed(parser);
262 }
263
264 #endif // wxUSE_CMDLINE_PARSER
265
266 // ----------------------------------------------------------------------------
267 // main event loop implementation
268 // ----------------------------------------------------------------------------
269
270 int wxAppBase::MainLoop()
271 {
272 #if wxUSE_EVTLOOP_IN_APP
273 wxEventLoopTiedPtr mainLoop(&m_mainLoop, new wxEventLoop);
274
275 return m_mainLoop->Run();
276 #else // !wxUSE_EVTLOOP_IN_APP
277 return 0;
278 #endif // wxUSE_EVTLOOP_IN_APP/!wxUSE_EVTLOOP_IN_APP
279 }
280
281 void wxAppBase::ExitMainLoop()
282 {
283 #if wxUSE_EVTLOOP_IN_APP
284 // we should exit from the main event loop, not just any currently active
285 // (e.g. modal dialog) event loop
286 if ( m_mainLoop && m_mainLoop->IsRunning() )
287 {
288 m_mainLoop->Exit(0);
289 }
290 #endif // wxUSE_EVTLOOP_IN_APP
291 }
292
293 bool wxAppBase::Pending()
294 {
295 #if wxUSE_EVTLOOP_IN_APP
296 // use the currently active message loop here, not m_mainLoop, because if
297 // we're showing a modal dialog (with its own event loop) currently the
298 // main event loop is not running anyhow
299 wxEventLoop * const loop = wxEventLoop::GetActive();
300
301 return loop && loop->Pending();
302 #else // wxUSE_EVTLOOP_IN_APP
303 return false;
304 #endif // wxUSE_EVTLOOP_IN_APP/!wxUSE_EVTLOOP_IN_APP
305 }
306
307 bool wxAppBase::Dispatch()
308 {
309 #if wxUSE_EVTLOOP_IN_APP
310 // see comment in Pending()
311 wxEventLoop * const loop = wxEventLoop::GetActive();
312
313 return loop && loop->Dispatch();
314 #else // wxUSE_EVTLOOP_IN_APP
315 return true;
316 #endif // wxUSE_EVTLOOP_IN_APP/!wxUSE_EVTLOOP_IN_APP
317 }
318
319 // ----------------------------------------------------------------------------
320 // OnXXX() hooks
321 // ----------------------------------------------------------------------------
322
323 bool wxAppBase::OnInitGui()
324 {
325 #ifdef __WXUNIVERSAL__
326 if ( !wxTheme::Get() && !wxTheme::CreateDefault() )
327 return false;
328 #endif // __WXUNIVERSAL__
329
330 return true;
331 }
332
333 int wxAppBase::OnRun()
334 {
335 // see the comment in ctor: if the initial value hasn't been changed, use
336 // the default Yes from now on
337 if ( m_exitOnFrameDelete == Later )
338 {
339 m_exitOnFrameDelete = Yes;
340 }
341 //else: it has been changed, assume the user knows what he is doing
342
343 return MainLoop();
344 }
345
346 int wxAppBase::OnExit()
347 {
348 #ifdef __WXUNIVERSAL__
349 delete wxTheme::Set(NULL);
350 #endif // __WXUNIVERSAL__
351
352 return wxAppConsole::OnExit();
353 }
354
355 void wxAppBase::Exit()
356 {
357 ExitMainLoop();
358 }
359
360 wxAppTraits *wxAppBase::CreateTraits()
361 {
362 return new wxGUIAppTraits;
363 }
364
365 // ----------------------------------------------------------------------------
366 // misc
367 // ----------------------------------------------------------------------------
368
369 void wxAppBase::SetActive(bool active, wxWindow * WXUNUSED(lastFocus))
370 {
371 if ( active == m_isActive )
372 return;
373
374 m_isActive = active;
375
376 wxActivateEvent event(wxEVT_ACTIVATE_APP, active);
377 event.SetEventObject(this);
378
379 (void)ProcessEvent(event);
380 }
381
382 void wxAppBase::DeletePendingObjects()
383 {
384 wxList::compatibility_iterator node = wxPendingDelete.GetFirst();
385 while (node)
386 {
387 wxObject *obj = node->GetData();
388
389 delete obj;
390
391 if (wxPendingDelete.Member(obj))
392 wxPendingDelete.Erase(node);
393
394 // Deleting one object may have deleted other pending
395 // objects, so start from beginning of list again.
396 node = wxPendingDelete.GetFirst();
397 }
398 }
399
400 // Returns true if more time is needed.
401 bool wxAppBase::ProcessIdle()
402 {
403 wxIdleEvent event;
404 bool needMore = false;
405 wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst();
406 while (node)
407 {
408 wxWindow* win = node->GetData();
409 if (SendIdleEvents(win, event))
410 needMore = true;
411 node = node->GetNext();
412 }
413
414 event.SetEventObject(this);
415 (void) ProcessEvent(event);
416 if (event.MoreRequested())
417 needMore = true;
418
419 wxUpdateUIEvent::ResetUpdateTime();
420
421 return needMore;
422 }
423
424 // Send idle event to window and all subwindows
425 bool wxAppBase::SendIdleEvents(wxWindow* win, wxIdleEvent& event)
426 {
427 bool needMore = false;
428
429 win->OnInternalIdle();
430
431 if (wxIdleEvent::CanSend(win))
432 {
433 event.SetEventObject(win);
434 win->GetEventHandler()->ProcessEvent(event);
435
436 if (event.MoreRequested())
437 needMore = true;
438 }
439 wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
440 while ( node )
441 {
442 wxWindow *child = node->GetData();
443 if (SendIdleEvents(child, event))
444 needMore = true;
445
446 node = node->GetNext();
447 }
448
449 return needMore;
450 }
451
452 void wxAppBase::OnIdle(wxIdleEvent& WXUNUSED(event))
453 {
454 // If there are pending events, we must process them: pending events
455 // are either events to the threads other than main or events posted
456 // with wxPostEvent() functions
457 // GRG: I have moved this here so that all pending events are processed
458 // before starting to delete any objects. This behaves better (in
459 // particular, wrt wxPostEvent) and is coherent with wxGTK's current
460 // behaviour. Changed Feb/2000 before 2.1.14
461 ProcessPendingEvents();
462
463 // 'Garbage' collection of windows deleted with Close().
464 DeletePendingObjects();
465
466 #if wxUSE_LOG
467 // flush the logged messages if any
468 wxLog::FlushActive();
469 #endif // wxUSE_LOG
470
471 }
472
473 // ----------------------------------------------------------------------------
474 // wxGUIAppTraitsBase
475 // ----------------------------------------------------------------------------
476
477 #if wxUSE_LOG
478
479 wxLog *wxGUIAppTraitsBase::CreateLogTarget()
480 {
481 #if wxUSE_LOGGUI
482 return new wxLogGui;
483 #else
484 // wem ust have something!
485 return new wxLogStderr;
486 #endif
487 }
488
489 #endif // wxUSE_LOG
490
491 wxMessageOutput *wxGUIAppTraitsBase::CreateMessageOutput()
492 {
493 // The standard way of printing help on command line arguments (app --help)
494 // is (according to common practice):
495 // - console apps: to stderr (on any platform)
496 // - GUI apps: stderr on Unix platforms (!)
497 // message box under Windows and others
498 #ifdef __UNIX__
499 return new wxMessageOutputStderr;
500 #else // !__UNIX__
501 // wxMessageOutputMessageBox doesn't work under Motif
502 #ifdef __WXMOTIF__
503 return new wxMessageOutputLog;
504 #else
505 return new wxMessageOutputMessageBox;
506 #endif
507 #endif // __UNIX__/!__UNIX__
508 }
509
510 #if wxUSE_FONTMAP
511
512 wxFontMapper *wxGUIAppTraitsBase::CreateFontMapper()
513 {
514 return new wxFontMapper;
515 }
516
517 #endif // wxUSE_FONTMAP
518
519 wxRendererNative *wxGUIAppTraitsBase::CreateRenderer()
520 {
521 // use the default native renderer by default
522 return NULL;
523 }
524
525 #ifdef __WXDEBUG__
526
527 bool wxGUIAppTraitsBase::ShowAssertDialog(const wxString& msg)
528 {
529 // under MSW we prefer to use the base class version using ::MessageBox()
530 // even if wxMessageBox() is available because it has less chances to
531 // double fault our app than our wxMessageBox()
532 #if defined(__WXMSW__) || !wxUSE_MSGDLG
533 return wxAppTraitsBase::ShowAssertDialog(msg);
534 #else // wxUSE_MSGDLG
535 // this message is intentionally not translated -- it is for
536 // developpers only
537 wxString msgDlg(msg);
538 msgDlg += wxT("\nDo you want to stop the program?\n")
539 wxT("You can also choose [Cancel] to suppress ")
540 wxT("further warnings.");
541
542 switch ( wxMessageBox(msgDlg, wxT("wxWidgets Debug Alert"),
543 wxYES_NO | wxCANCEL | wxICON_STOP ) )
544 {
545 case wxYES:
546 wxTrap();
547 break;
548
549 case wxCANCEL:
550 // no more asserts
551 return true;
552
553 //case wxNO: nothing to do
554 }
555
556 return false;
557 #endif // !wxUSE_MSGDLG/wxUSE_MSGDLG
558 }
559
560 #endif // __WXDEBUG__
561
562 bool wxGUIAppTraitsBase::HasStderr()
563 {
564 // we consider that under Unix stderr always goes somewhere, even if the
565 // user doesn't always see it under GUI desktops
566 #ifdef __UNIX__
567 return true;
568 #else
569 return false;
570 #endif
571 }
572
573 void wxGUIAppTraitsBase::ScheduleForDestroy(wxObject *object)
574 {
575 if ( !wxPendingDelete.Member(object) )
576 wxPendingDelete.Append(object);
577 }
578
579 void wxGUIAppTraitsBase::RemoveFromPendingDelete(wxObject *object)
580 {
581 wxPendingDelete.DeleteObject(object);
582 }
583
584 #if wxUSE_SOCKETS
585
586 #if defined(__UNIX__) || defined(__DARWIN__) || defined(__OS2__)
587 #include "wx/unix/gsockunx.h"
588 #elif defined(__WINDOWS__)
589 #include "wx/msw/gsockmsw.h"
590 #elif defined(__WXMAC__)
591 #include <MacHeaders.c>
592 #define OTUNIXERRORS 1
593 #include <OpenTransport.h>
594 #include <OpenTransportProviders.h>
595 #include <OpenTptInternet.h>
596
597 #include "wx/mac/gsockmac.h"
598 #else
599 #error "Must include correct GSocket header here"
600 #endif
601
602 GSocketGUIFunctionsTable* wxGUIAppTraitsBase::GetSocketGUIFunctionsTable()
603 {
604 #if defined(__WXMAC__) && !defined(__DARWIN__)
605 // NB: wxMac CFM does not have any GUI-specific functions in gsocket.c and
606 // so it doesn't need this table at all
607 return NULL;
608 #else // !__WXMAC__ || __DARWIN__
609 static GSocketGUIFunctionsTableConcrete table;
610 return &table;
611 #endif // !__WXMAC__ || __DARWIN__
612 }
613
614 #endif
615