]> git.saurik.com Git - wxWidgets.git/blob - src/common/init.cpp
wxMessageBox off the main thread lost result code.
[wxWidgets.git] / src / common / init.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/init.cpp
3 // Purpose: initialisation for the library
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 04.10.99
7 // Copyright: (c) Vadim Zeitlin
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 #include "wx/wxprec.h"
20
21 #ifdef __BORLANDC__
22 #pragma hdrstop
23 #endif //__BORLANDC__
24
25 #ifndef WX_PRECOMP
26 #include "wx/app.h"
27 #include "wx/filefn.h"
28 #include "wx/log.h"
29 #include "wx/intl.h"
30 #include "wx/module.h"
31 #endif
32
33 #include "wx/init.h"
34 #include "wx/thread.h"
35
36 #include "wx/scopedptr.h"
37 #include "wx/except.h"
38
39 #if defined(__WINDOWS__)
40 #include "wx/msw/private.h"
41 #include "wx/msw/msvcrt.h"
42
43 #ifdef wxCrtSetDbgFlag
44 static struct EnableMemLeakChecking
45 {
46 EnableMemLeakChecking()
47 {
48 // 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 // wxCrtSetDbgFlag
55 #endif // __WINDOWS__
56
57 #if wxUSE_UNICODE && defined(__WXOSX__)
58 #include <locale.h>
59 #endif
60
61 // ----------------------------------------------------------------------------
62 // private classes
63 // ----------------------------------------------------------------------------
64
65 // we need a dummy app object if the user doesn't want to create a real one
66 class wxDummyConsoleApp : public wxAppConsole
67 {
68 public:
69 wxDummyConsoleApp() { }
70
71 virtual int OnRun() { wxFAIL_MSG( wxT("unreachable code") ); return 0; }
72 virtual bool DoYield(bool, long) { return true; }
73
74 wxDECLARE_NO_COPY_CLASS(wxDummyConsoleApp);
75 };
76
77 // we need a special kind of auto pointer to wxApp which not only deletes the
78 // pointer it holds in its dtor but also resets the global application pointer
79 wxDECLARE_SCOPED_PTR(wxAppConsole, wxAppPtrBase)
80 wxDEFINE_SCOPED_PTR(wxAppConsole, wxAppPtrBase)
81
82 class wxAppPtr : public wxAppPtrBase
83 {
84 public:
85 wxEXPLICIT wxAppPtr(wxAppConsole *ptr = NULL) : wxAppPtrBase(ptr) { }
86 ~wxAppPtr()
87 {
88 if ( get() )
89 {
90 // the pointer is going to be deleted in the base class dtor, don't
91 // leave the dangling pointer!
92 wxApp::SetInstance(NULL);
93 }
94 }
95
96 void Set(wxAppConsole *ptr)
97 {
98 reset(ptr);
99
100 wxApp::SetInstance(ptr);
101 }
102
103 wxDECLARE_NO_COPY_CLASS(wxAppPtr);
104 };
105
106 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
107 // fails
108 class wxCallAppCleanup
109 {
110 public:
111 wxCallAppCleanup(wxAppConsole *app) : m_app(app) { }
112 ~wxCallAppCleanup() { if ( m_app ) m_app->CleanUp(); }
113
114 void Dismiss() { m_app = NULL; }
115
116 private:
117 wxAppConsole *m_app;
118 };
119
120 // ----------------------------------------------------------------------------
121 // private functions
122 // ----------------------------------------------------------------------------
123
124 // suppress warnings about unused variables
125 static inline void Use(void *) { }
126
127 #define WX_SUPPRESS_UNUSED_WARN(x) Use(&x)
128
129 // ----------------------------------------------------------------------------
130 // initialization data
131 // ----------------------------------------------------------------------------
132
133 static struct InitData
134 {
135 InitData()
136 {
137 nInitCount = 0;
138
139 #if wxUSE_UNICODE
140 argc = 0;
141 // argv = NULL; -- not even really needed
142 #endif // wxUSE_UNICODE
143 }
144
145 // critical section protecting this struct
146 wxCRIT_SECT_DECLARE_MEMBER(csInit);
147
148 // number of times wxInitialize() was called minus the number of times
149 // wxUninitialize() was
150 size_t nInitCount;
151
152 #if wxUSE_UNICODE
153 int argc;
154
155 // if we receive the command line arguments as ASCII and have to convert
156 // them to Unicode ourselves (this is the case under Unix but not Windows,
157 // for example), we remember the converted argv here because we'll have to
158 // free it when doing cleanup to avoid memory leaks
159 wchar_t **argv;
160 #endif // wxUSE_UNICODE
161
162 wxDECLARE_NO_COPY_CLASS(InitData);
163 } gs_initData;
164
165 // ============================================================================
166 // implementation
167 // ============================================================================
168
169 // ----------------------------------------------------------------------------
170 // command line arguments ANSI -> Unicode conversion
171 // ----------------------------------------------------------------------------
172
173 #if wxUSE_UNICODE
174
175 static void ConvertArgsToUnicode(int argc, char **argv)
176 {
177 gs_initData.argv = new wchar_t *[argc + 1];
178 int wargc = 0;
179 for ( int i = 0; i < argc; i++ )
180 {
181 #ifdef __DARWIN__
182 wxWCharBuffer buf(wxConvFileName->cMB2WX(argv[i]));
183 #else
184 wxWCharBuffer buf(wxConvLocal.cMB2WX(argv[i]));
185 #endif
186 if ( !buf )
187 {
188 wxLogWarning(_("Command line argument %d couldn't be converted to Unicode and will be ignored."),
189 i);
190 }
191 else // converted ok
192 {
193 gs_initData.argv[wargc++] = wxStrdup(buf);
194 }
195 }
196
197 gs_initData.argc = wargc;
198 gs_initData.argv[wargc] = NULL;
199 }
200
201 static void FreeConvertedArgs()
202 {
203 if ( gs_initData.argv )
204 {
205 for ( int i = 0; i < gs_initData.argc; i++ )
206 {
207 free(gs_initData.argv[i]);
208 }
209
210 wxDELETEA(gs_initData.argv);
211 gs_initData.argc = 0;
212 }
213 }
214
215 #endif // wxUSE_UNICODE
216
217 // ----------------------------------------------------------------------------
218 // start up
219 // ----------------------------------------------------------------------------
220
221 // initialization which is always done (not customizable) before wxApp creation
222 static bool DoCommonPreInit()
223 {
224 #if wxUSE_UNICODE && defined(__WXOSX__)
225 // In OS X and iOS, wchar_t CRT functions convert to char* and fail under
226 // some locales. The safest fix is to set LC_CTYPE to UTF-8 to ensure that
227 // they can handle any input.
228 //
229 // Note that this must be done for any app, Cocoa or console, whether or
230 // not it uses wxLocale.
231 //
232 // See http://stackoverflow.com/questions/11713745/why-does-the-printf-family-of-functions-care-about-locale
233 setlocale(LC_CTYPE, "UTF-8");
234 #endif // wxUSE_UNICODE && defined(__WXOSX__)
235
236 #if wxUSE_LOG
237 // Reset logging in case we were cleaned up and are being reinitialized.
238 wxLog::DoCreateOnDemand();
239
240 // force wxLog to create a log target now: we do it because wxTheApp
241 // doesn't exist yet so wxLog will create a special log target which is
242 // safe to use even when the GUI is not available while without this call
243 // we could create wxApp in wxEntryStart() below, then log an error about
244 // e.g. failure to establish connection to the X server and wxLog would
245 // send it to wxLogGui (because wxTheApp does exist already) which, of
246 // course, can't be used in this case
247 //
248 // notice also that this does nothing if the user had set up a custom log
249 // target before -- which is fine as we want to give him this possibility
250 // (as it's impossible to override logging by overriding wxAppTraits::
251 // CreateLogTarget() before wxApp is created) and we just assume he knows
252 // what he is doing
253 wxLog::GetActiveTarget();
254 #endif // wxUSE_LOG
255
256 #ifdef __WINDOWS__
257 // GUI applications obtain HINSTANCE in their WinMain() but we also need to
258 // initialize the global wxhInstance variable for the console programs as
259 // they may need it too, so set it here if it wasn't done yet
260 if ( !wxGetInstance() )
261 {
262 wxSetInstance(::GetModuleHandle(NULL));
263 }
264 #endif // __WINDOWS__
265
266 return true;
267 }
268
269 // non customizable initialization done after wxApp creation and initialization
270 static bool DoCommonPostInit()
271 {
272 wxModule::RegisterModules();
273
274 if ( !wxModule::InitializeModules() )
275 {
276 wxLogError(_("Initialization failed in post init, aborting."));
277 return false;
278 }
279
280 return true;
281 }
282
283 bool wxEntryStart(int& argc, wxChar **argv)
284 {
285 // do minimal, always necessary, initialization
286 // --------------------------------------------
287
288 // initialize wxRTTI
289 if ( !DoCommonPreInit() )
290 return false;
291
292
293 // first of all, we need an application object
294 // -------------------------------------------
295
296 // the user might have already created it himself somehow
297 wxAppPtr app(wxTheApp);
298 if ( !app.get() )
299 {
300 // if not, he might have used IMPLEMENT_APP() to give us a function to
301 // create it
302 wxAppInitializerFunction fnCreate = wxApp::GetInitializerFunction();
303
304 if ( fnCreate )
305 {
306 // he did, try to create the custom wxApp object
307 app.Set((*fnCreate)());
308 }
309 }
310
311 if ( !app.get() )
312 {
313 // either IMPLEMENT_APP() was not used at all or it failed -- in any
314 // case we still need something
315 app.Set(new wxDummyConsoleApp);
316 }
317
318
319 // wxApp initialization: this can be customized
320 // --------------------------------------------
321
322 if ( !app->Initialize(argc, argv) )
323 return false;
324
325 // remember, possibly modified (e.g. due to removal of toolkit-specific
326 // parameters), command line arguments in member variables
327 app->argc = argc;
328 app->argv = argv;
329
330 wxCallAppCleanup callAppCleanup(app.get());
331
332
333 // common initialization after wxTheApp creation
334 // ---------------------------------------------
335
336 if ( !DoCommonPostInit() )
337 return false;
338
339
340 // prevent the smart pointer from destroying its contents
341 app.release();
342
343 // and the cleanup object from doing cleanup
344 callAppCleanup.Dismiss();
345
346 #if wxUSE_LOG
347 // now that we have a valid wxApp (wxLogGui would have crashed if we used
348 // it before now), we can delete the temporary sink we had created for the
349 // initialization messages -- the next time logging function is called, the
350 // sink will be recreated but this time wxAppTraits will be used
351 delete wxLog::SetActiveTarget(NULL);
352 #endif // wxUSE_LOG
353
354 return true;
355 }
356
357 #if wxUSE_UNICODE
358
359 // we provide a wxEntryStart() wrapper taking "char *" pointer too
360 bool wxEntryStart(int& argc, char **argv)
361 {
362 ConvertArgsToUnicode(argc, argv);
363
364 if ( !wxEntryStart(gs_initData.argc, gs_initData.argv) )
365 {
366 FreeConvertedArgs();
367
368 return false;
369 }
370
371 return true;
372 }
373
374 #endif // wxUSE_UNICODE
375
376 // ----------------------------------------------------------------------------
377 // clean up
378 // ----------------------------------------------------------------------------
379
380 // cleanup done before destroying wxTheApp
381 static void DoCommonPreCleanup()
382 {
383 #if wxUSE_LOG
384 // flush the logged messages if any and don't use the current probably
385 // unsafe log target any more: the default one (wxLogGui) can't be used
386 // after the resources are freed which happens when we return and the user
387 // supplied one might be even more unsafe (using any wxWidgets GUI function
388 // is unsafe starting from now)
389 //
390 // notice that wxLog will still recreate a default log target if any
391 // messages are logged but that one will be safe to use until the very end
392 delete wxLog::SetActiveTarget(NULL);
393 #endif // wxUSE_LOG
394 }
395
396 // cleanup done after destroying wxTheApp
397 static void DoCommonPostCleanup()
398 {
399 wxModule::CleanUpModules();
400
401 // we can't do this in wxApp itself because it doesn't know if argv had
402 // been allocated
403 #if wxUSE_UNICODE
404 FreeConvertedArgs();
405 #endif // wxUSE_UNICODE
406
407 // use Set(NULL) and not Get() to avoid creating a message output object on
408 // demand when we just want to delete it
409 delete wxMessageOutput::Set(NULL);
410
411 #if wxUSE_LOG
412 // call this first as it has a side effect: in addition to flushing all
413 // logs for this thread, it also flushes everything logged from other
414 // threads
415 wxLog::FlushActive();
416
417 // and now delete the last logger as well
418 //
419 // we still don't disable log target auto-vivification even if any log
420 // objects created now will result in memory leaks because it seems better
421 // to leak memory which doesn't matter much considering the application is
422 // exiting anyhow than to not show messages which could still be logged
423 // from the user code (e.g. static dtors and such)
424 delete wxLog::SetActiveTarget(NULL);
425 #endif // wxUSE_LOG
426 }
427
428 void wxEntryCleanup()
429 {
430 DoCommonPreCleanup();
431
432
433 // delete the application object
434 if ( wxTheApp )
435 {
436 wxTheApp->CleanUp();
437
438 // reset the global pointer to it to NULL before destroying it as in
439 // some circumstances this can result in executing the code using
440 // wxTheApp and using half-destroyed object is no good
441 wxAppConsole * const app = wxApp::GetInstance();
442 wxApp::SetInstance(NULL);
443 delete app;
444 }
445
446
447 DoCommonPostCleanup();
448 }
449
450 // ----------------------------------------------------------------------------
451 // wxEntry
452 // ----------------------------------------------------------------------------
453
454 // for MSW the real wxEntry is defined in msw/main.cpp
455 #ifndef __WINDOWS__
456 #define wxEntryReal wxEntry
457 #endif // !__WINDOWS__
458
459 int wxEntryReal(int& argc, wxChar **argv)
460 {
461 // library initialization
462 wxInitializer initializer(argc, argv);
463
464 if ( !initializer.IsOk() )
465 {
466 #if wxUSE_LOG
467 // flush any log messages explaining why we failed
468 delete wxLog::SetActiveTarget(NULL);
469 #endif
470 return -1;
471 }
472
473 wxTRY
474 {
475 #if 0 // defined(__WXOSX__) && wxOSX_USE_COCOA_OR_IPHONE
476 // everything done in OnRun using native callbacks
477 #else
478 // app initialization
479 if ( !wxTheApp->CallOnInit() )
480 {
481 // don't call OnExit() if OnInit() failed
482 return -1;
483 }
484
485 // ensure that OnExit() is called if OnInit() had succeeded
486 class CallOnExit
487 {
488 public:
489 ~CallOnExit() { wxTheApp->OnExit(); }
490 } callOnExit;
491
492 WX_SUPPRESS_UNUSED_WARN(callOnExit);
493 #endif
494 // app execution
495 return wxTheApp->OnRun();
496 }
497 wxCATCH_ALL( wxTheApp->OnUnhandledException(); return -1; )
498 }
499
500 #if wxUSE_UNICODE
501
502 // as with wxEntryStart, we provide an ANSI wrapper
503 int wxEntry(int& argc, char **argv)
504 {
505 ConvertArgsToUnicode(argc, argv);
506
507 return wxEntry(gs_initData.argc, gs_initData.argv);
508 }
509
510 #endif // wxUSE_UNICODE
511
512 // ----------------------------------------------------------------------------
513 // wxInitialize/wxUninitialize
514 // ----------------------------------------------------------------------------
515
516 bool wxInitialize()
517 {
518 return wxInitialize(0, (wxChar**)NULL);
519 }
520
521 bool wxInitialize(int argc, wxChar **argv)
522 {
523 wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit);
524
525 if ( gs_initData.nInitCount++ )
526 {
527 // already initialized
528 return true;
529 }
530
531 return wxEntryStart(argc, argv);
532 }
533
534 #if wxUSE_UNICODE
535 bool wxInitialize(int argc, char **argv)
536 {
537 wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit);
538
539 if ( gs_initData.nInitCount++ )
540 {
541 // already initialized
542 return true;
543 }
544
545 return wxEntryStart(argc, argv);
546 }
547 #endif // wxUSE_UNICODE
548
549 void wxUninitialize()
550 {
551 wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit);
552
553 if ( --gs_initData.nInitCount == 0 )
554 {
555 wxEntryCleanup();
556 }
557 }