]> git.saurik.com Git - wxWidgets.git/blob - src/common/init.cpp
Added slightly better font dialog for Mac
[wxWidgets.git] / src / common / init.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        common/init.cpp
3 // Purpose:     initialisation for the library
4 // Author:      Vadim Zeitlin
5 // Modified by:
6 // Created:     04.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 #include "wx/wxprec.h"
21
22 #ifdef    __BORLANDC__
23   #pragma hdrstop
24 #endif  //__BORLANDC__
25
26 #ifndef WX_PRECOMP
27     #include "wx/app.h"
28     #include "wx/debug.h"
29     #include "wx/filefn.h"
30     #include "wx/log.h"
31     #include "wx/thread.h"
32     #include "wx/intl.h"
33 #endif
34
35 #include "wx/init.h"
36
37 #include "wx/ptr_scpd.h"
38 #include "wx/module.h"
39 #include "wx/except.h"
40
41 #if defined(__WXMSW__) && defined(__WXDEBUG__)
42     #include "wx/msw/msvcrt.h"
43
44     static struct EnableMemLeakChecking
45     {
46         EnableMemLeakChecking()
47         {
48             // do check for memory leaks on program exit (another useful flag
49             // is _CRTDBG_DELAY_FREE_MEM_DF which doesn't free deallocated
50             // memory which may be used to simulate low-memory condition)
51             wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF);
52         }
53     } gs_enableLeakChecks;
54 #endif // __WXMSW__ && __WXDEBUG__
55
56 // ----------------------------------------------------------------------------
57 // private classes
58 // ----------------------------------------------------------------------------
59
60 // we need a dummy app object if the user doesn't want to create a real one
61 class wxDummyConsoleApp : public wxAppConsole
62 {
63 public:
64     wxDummyConsoleApp() { }
65
66     virtual int OnRun() { wxFAIL_MSG( _T("unreachable code") ); return 0; }
67
68     DECLARE_NO_COPY_CLASS(wxDummyConsoleApp)
69 };
70
71 // we need a special kind of auto pointer to wxApp which not only deletes the
72 // pointer it holds in its dtor but also resets the global application pointer
73 wxDECLARE_SCOPED_PTR(wxAppConsole, wxAppPtrBase)
74 wxDEFINE_SCOPED_PTR(wxAppConsole, wxAppPtrBase)
75
76 class wxAppPtr : public wxAppPtrBase
77 {
78 public:
79     wxEXPLICIT wxAppPtr(wxAppConsole *ptr = NULL) : wxAppPtrBase(ptr) { }
80     ~wxAppPtr()
81     {
82         if ( get() )
83         {
84             // the pointer is going to be deleted in the base class dtor, don't
85             // leave the dangling pointer!
86             wxApp::SetInstance(NULL);
87         }
88     }
89
90     void Set(wxAppConsole *ptr)
91     {
92         reset(ptr);
93
94         wxApp::SetInstance(ptr);
95     }
96
97     DECLARE_NO_COPY_CLASS(wxAppPtr)
98 };
99
100 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
101 // fails
102 class wxCallAppCleanup
103 {
104 public:
105     wxCallAppCleanup(wxAppConsole *app) : m_app(app) { }
106     ~wxCallAppCleanup() { if ( m_app ) m_app->CleanUp(); }
107
108     void Dismiss() { m_app = NULL; }
109
110 private:
111     wxAppConsole *m_app;
112 };
113
114 // another tiny class which simply exists to ensure that wxEntryCleanup is
115 // always called
116 class wxCleanupOnExit
117 {
118 public:
119     ~wxCleanupOnExit() { wxEntryCleanup(); }
120 };
121
122 // ----------------------------------------------------------------------------
123 // private functions
124 // ----------------------------------------------------------------------------
125
126 // suppress warnings about unused variables
127 static inline void Use(void *) { }
128
129 #define WX_SUPPRESS_UNUSED_WARN(x) Use(&x)
130
131 // ----------------------------------------------------------------------------
132 // initialization data
133 // ----------------------------------------------------------------------------
134
135 static struct InitData
136 {
137     InitData()
138     {
139         nInitCount = 0;
140
141 #if wxUSE_UNICODE
142         argc = 0;
143         // argv = NULL; -- not even really needed
144 #endif // wxUSE_UNICODE
145     }
146
147     // critical section protecting this struct
148     wxCRIT_SECT_DECLARE_MEMBER(csInit);
149
150     // number of times wxInitialize() was called minus the number of times
151     // wxUninitialize() was
152     size_t nInitCount;
153
154 #if wxUSE_UNICODE
155     int argc;
156
157     // if we receive the command line arguments as ASCII and have to convert
158     // them to Unicode ourselves (this is the case under Unix but not Windows,
159     // for example), we remember the converted argv here because we'll have to
160     // free it when doing cleanup to avoid memory leaks
161     wchar_t **argv;
162 #endif // wxUSE_UNICODE
163
164     DECLARE_NO_COPY_CLASS(InitData)
165 } gs_initData;
166
167 // ============================================================================
168 // implementation
169 // ============================================================================
170
171 // ----------------------------------------------------------------------------
172 // command line arguments ANSI -> Unicode conversion
173 // ----------------------------------------------------------------------------
174
175 #if wxUSE_UNICODE
176
177 static void ConvertArgsToUnicode(int argc, char **argv)
178 {
179     gs_initData.argv = new wchar_t *[argc + 1];
180     for ( int i = 0; i < argc; i++ )
181     {
182         gs_initData.argv[i] = wxStrdup(wxConvLocal.cMB2WX(argv[i]));
183     }
184
185     gs_initData.argc = argc;
186     gs_initData.argv[argc] = NULL;
187 }
188
189 static void FreeConvertedArgs()
190 {
191     if ( gs_initData.argv )
192     {
193         for ( int i = 0; i < gs_initData.argc; i++ )
194         {
195             free(gs_initData.argv[i]);
196         }
197
198         delete [] gs_initData.argv;
199         gs_initData.argv = NULL;
200         gs_initData.argc = 0;
201     }
202 }
203
204 #endif // wxUSE_UNICODE
205
206 // ----------------------------------------------------------------------------
207 // start up
208 // ----------------------------------------------------------------------------
209
210 // initialization which is always done (not customizable) before wxApp creation
211 static bool DoCommonPreInit()
212 {
213 #if wxUSE_LOG
214     // install temporary log sink: we can't use wxLogGui before wxApp is
215     // constructed and if we use wxLogStderr, all messages during
216     // initialization simply disappear under Windows
217     //
218     // note that we will delete this log target below
219     wxLog::SetActiveTarget(new wxLogBuffer);
220 #endif // wxUSE_LOG
221
222     return true;
223 }
224
225 // non customizable initialization done after wxApp creation and initialization
226 static bool DoCommonPostInit()
227 {
228     wxModule::RegisterModules();
229
230     if ( !wxModule::InitializeModules() )
231     {
232         wxLogError(_("Initialization failed in post init, aborting."));
233         return false;
234     }
235
236     return true;
237 }
238
239 bool wxEntryStart(int& argc, wxChar **argv)
240 {
241     // do minimal, always necessary, initialization
242     // --------------------------------------------
243
244     // initialize wxRTTI
245     if ( !DoCommonPreInit() )
246     {
247         return false;
248     }
249
250
251     // first of all, we need an application object
252     // -------------------------------------------
253
254     // the user might have already created it himself somehow
255     wxAppPtr app(wxTheApp);
256     if ( !app.get() )
257     {
258         // if not, he might have used IMPLEMENT_APP() to give us a function to
259         // create it
260         wxAppInitializerFunction fnCreate = wxApp::GetInitializerFunction();
261
262         if ( fnCreate )
263         {
264             // he did, try to create the custom wxApp object
265             app.Set((*fnCreate)());
266         }
267     }
268
269     if ( !app.get() )
270     {
271         // either IMPLEMENT_APP() was not used at all or it failed -- in any
272         // case we still need something
273         app.Set(new wxDummyConsoleApp);
274     }
275
276
277     // wxApp initialization: this can be customized
278     // --------------------------------------------
279
280     if ( !app->Initialize(argc, argv) )
281     {
282         return false;
283     }
284
285     wxCallAppCleanup callAppCleanup(app.get());
286
287     // for compatibility call the old initialization function too
288     if ( !app->OnInitGui() )
289         return false;
290
291
292     // common initialization after wxTheApp creation
293     // ---------------------------------------------
294
295     if ( !DoCommonPostInit() )
296         return false;
297
298
299     // prevent the smart pointer from destroying its contents
300     app.release();
301
302     // and the cleanup object from doing cleanup
303     callAppCleanup.Dismiss();
304
305 #if wxUSE_LOG
306     // now that we have a valid wxApp (wxLogGui would have crashed if we used
307     // it before now), we can delete the temporary sink we had created for the
308     // initialization messages -- the next time logging function is called, the
309     // sink will be recreated but this time wxAppTraits will be used
310     delete wxLog::SetActiveTarget(NULL);
311 #endif // wxUSE_LOG
312
313     return true;
314 }
315
316 #if wxUSE_UNICODE
317
318 // we provide a wxEntryStart() wrapper taking "char *" pointer too
319 bool wxEntryStart(int& argc, char **argv)
320 {
321     ConvertArgsToUnicode(argc, argv);
322
323     if ( !wxEntryStart(argc, gs_initData.argv) )
324     {
325         FreeConvertedArgs();
326
327         return false;
328     }
329
330     return true;
331 }
332
333 #endif // wxUSE_UNICODE
334
335 // ----------------------------------------------------------------------------
336 // clean up
337 // ----------------------------------------------------------------------------
338
339 // cleanup done before destroying wxTheApp
340 static void DoCommonPreCleanup()
341 {
342 #if wxUSE_LOG
343     // flush the logged messages if any and install a 'safer' log target: the
344     // default one (wxLogGui) can't be used after the resources are freed just
345     // below and the user supplied one might be even more unsafe (using any
346     // wxWidgets GUI function is unsafe starting from now)
347     wxLog::DontCreateOnDemand();
348
349     // this will flush the old messages if any
350     delete wxLog::SetActiveTarget(new wxLogStderr);
351 #endif // wxUSE_LOG
352 }
353
354 // cleanup done after destroying wxTheApp
355 static void DoCommonPostCleanup()
356 {
357     wxModule::CleanUpModules();
358
359     wxClassInfo::CleanUp();
360
361     // we can't do this in wxApp itself because it doesn't know if argv had
362     // been allocated
363 #if wxUSE_UNICODE
364     FreeConvertedArgs();
365 #endif // wxUSE_UNICODE
366
367     // use Set(NULL) and not Get() to avoid creating a message output object on
368     // demand when we just want to delete it
369     delete wxMessageOutput::Set(NULL);
370
371 #if wxUSE_LOG
372     // and now delete the last logger as well
373     delete wxLog::SetActiveTarget(NULL);
374 #endif // wxUSE_LOG
375 }
376
377 void wxEntryCleanup()
378 {
379     DoCommonPreCleanup();
380
381
382     // delete the application object
383     if ( wxTheApp )
384     {
385         wxTheApp->CleanUp();
386
387         delete wxTheApp;
388         wxApp::SetInstance(NULL);
389     }
390
391
392     DoCommonPostCleanup();
393 }
394
395 // ----------------------------------------------------------------------------
396 // wxEntry
397 // ----------------------------------------------------------------------------
398
399 // for MSW the real wxEntry is defined in msw/main.cpp
400 #ifndef __WXMSW__
401     #define wxEntryReal wxEntry
402 #endif // !__WXMSW__
403
404 int wxEntryReal(int& argc, wxChar **argv)
405 {
406     // library initialization
407     if ( !wxEntryStart(argc, argv) )
408     {
409 #if wxUSE_LOG
410         // flush any log messages explaining why we failed
411         delete wxLog::SetActiveTarget(NULL);
412 #endif
413         return -1;
414     }
415
416     // if wxEntryStart succeeded, we must call wxEntryCleanup even if the code
417     // below returns or throws
418     wxCleanupOnExit cleanupOnExit;
419
420     WX_SUPPRESS_UNUSED_WARN(cleanupOnExit);
421
422     wxTRY
423     {
424
425         // app initialization
426         if ( !wxTheApp->CallOnInit() )
427         {
428             // don't call OnExit() if OnInit() failed
429             return -1;
430         }
431
432         // ensure that OnExit() is called if OnInit() had succeeded
433         class CallOnExit
434         {
435         public:
436             ~CallOnExit() { wxTheApp->OnExit(); }
437         } callOnExit;
438
439         WX_SUPPRESS_UNUSED_WARN(callOnExit);
440
441         // app execution
442         return wxTheApp->OnRun();
443     }
444     wxCATCH_ALL( wxTheApp->OnUnhandledException(); return -1; )
445 }
446
447 #if wxUSE_UNICODE
448
449 // as with wxEntryStart, we provide an ANSI wrapper
450 int wxEntry(int& argc, char **argv)
451 {
452     ConvertArgsToUnicode(argc, argv);
453
454     return wxEntry(argc, gs_initData.argv);
455 }
456
457 #endif // wxUSE_UNICODE
458
459 // ----------------------------------------------------------------------------
460 // wxInitialize/wxUninitialize
461 // ----------------------------------------------------------------------------
462
463 bool wxInitialize(int argc, wxChar **argv)
464 {
465     wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit);
466
467     if ( gs_initData.nInitCount++ )
468     {
469         // already initialized
470         return true;
471     }
472
473     return wxEntryStart(argc, argv);
474 }
475
476 void wxUninitialize()
477 {
478     wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit);
479
480     if ( --gs_initData.nInitCount == 0 )
481     {
482         wxEntryCleanup();
483     }
484 }
485