]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/app.cpp
Added wxOKlibc(), which checks for glibc2.0, which incorrectly does UTF-8
[wxWidgets.git] / src / gtk1 / app.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: app.cpp
3// Purpose:
4// Author: Robert Roebling
32e9da8b 5// Id: $Id$
01111366 6// Copyright: (c) 1998 Robert Roebling, Julian Smart
8bbe427f 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
10#ifdef __GNUG__
afb74891 11 #pragma implementation "app.h"
c801d85f
KB
12#endif
13
14#include "wx/app.h"
15#include "wx/gdicmn.h"
16#include "wx/utils.h"
c801d85f
KB
17#include "wx/intl.h"
18#include "wx/log.h"
46dc76ba 19#include "wx/memory.h"
a3622daa
VZ
20#include "wx/font.h"
21#include "wx/settings.h"
0d2a2b60 22#include "wx/dialog.h"
afb74891 23
06cfab17 24#if wxUSE_WX_RESOURCES
afb74891 25 #include "wx/resource.h"
f5abe911 26#endif
afb74891 27
031b2a7b 28#include "wx/module.h"
4bc67cc5 29#include "wx/image.h"
afb74891 30
f3855ef0 31#include "wx/thread.h"
afb74891 32
c801d85f
KB
33#include "unistd.h"
34
afb74891
VZ
35#include <glib.h>
36#include <gdk/gdk.h>
37#include <gtk/gtk.h>
24178e4a 38
83624f79
RR
39#include "wx/gtk/win_gtk.h"
40
c801d85f
KB
41//-----------------------------------------------------------------------------
42// global data
43//-----------------------------------------------------------------------------
44
c67daf87 45wxApp *wxTheApp = (wxApp *) NULL;
c801d85f
KB
46wxAppInitializerFunction wxApp::m_appInitFn = (wxAppInitializerFunction) NULL;
47
48extern wxList wxPendingDelete;
7214297d 49#if wxUSE_THREADS
4d3a259a
GL
50extern wxList *wxPendingEvents;
51extern wxCriticalSection *wxPendingEventsLocker;
7214297d 52#endif
a3622daa 53extern wxResourceCache *wxTheResourceCache;
c801d85f 54
01111366
RR
55unsigned char g_palette[64*3] =
56{
57 0x0, 0x0, 0x0,
58 0xff, 0xff, 0xff,
59 0xff, 0x0, 0x0,
60 0xff, 0xff, 0x0,
61 0x0, 0xff, 0x0,
62 0x0, 0x0, 0xff,
63 0x0, 0xff, 0xff,
64 0x99, 0x99, 0x99,
65 0xff, 0x88, 0x0,
66 0x88, 0x0, 0x0,
67 0x0, 0x88, 0x88,
68 0x88, 0x88, 0x0,
69 0xff, 0xcc, 0x97,
70 0xbb, 0xbb, 0xbb,
71 0x9f, 0x6b, 0x42,
72 0x55, 0x55, 0x55,
73 0xdd, 0xdd, 0xdd,
74 0x77, 0x77, 0x77,
75 0x33, 0x33, 0x33,
76 0xcc, 0x0, 0x0,
77 0xff, 0x44, 0x0,
78 0xff, 0xcc, 0x0,
79 0xcc, 0xcc, 0x0,
80 0x60, 0x60, 0x0,
81 0x0, 0x43, 0x0,
82 0x0, 0x7f, 0x0,
83 0x0, 0xcc, 0x0,
84 0x0, 0x44, 0x44,
85 0x0, 0x0, 0x44,
86 0x0, 0x0, 0x88,
87 0xef, 0xb1, 0x7b,
88 0xdf, 0x98, 0x5f,
89 0xbf, 0x87, 0x56,
90 0x7f, 0x57, 0x26,
91 0x5f, 0x39, 0xc,
92 0x3f, 0x1c, 0x0,
93 0x21, 0x0, 0x0,
94 0x0, 0x43, 0x87,
95 0x2d, 0x70, 0xaf,
96 0x5a, 0x9e, 0xd7,
97 0x87, 0xcc, 0xff,
98 0xff, 0xe0, 0xba,
99 0x21, 0x43, 0xf,
100 0x3d, 0x5d, 0x25,
101 0x59, 0x78, 0x3a,
102 0x75, 0x93, 0x4f,
103 0x91, 0xae, 0x64,
104 0xad, 0xc8, 0x7a,
e0253070 105 0xf0, 0xa8, 0xef,
01111366
RR
106 0xd0, 0x88, 0xd0,
107 0xaf, 0x66, 0xaf,
108 0x8e, 0x44, 0x8e,
109 0x6d, 0x22, 0x6d,
e0253070 110 0x4b, 0x0, 0x4b,
01111366
RR
111 0xff, 0xc0, 0xbc,
112 0xff, 0x93, 0x91,
113 0xff, 0x66, 0x67,
114 0xd8, 0xf2, 0xbf,
115 0xff, 0xc9, 0x68,
116 0xff, 0x96, 0x67,
117 0xa5, 0x60, 0xff,
118 0x51, 0xff, 0x99,
119 0x3f, 0xa5, 0x63,
120 0x98, 0x90, 0x67
121};
122
c801d85f
KB
123//-----------------------------------------------------------------------------
124// local functions
125//-----------------------------------------------------------------------------
126
127extern void wxFlushResources(void);
128
129//-----------------------------------------------------------------------------
130// global functions
131//-----------------------------------------------------------------------------
132
60acb947 133void wxExit()
c801d85f 134{
ec758a20 135 gtk_main_quit();
ff7b1510 136}
c801d85f 137
53a8af59
KB
138// forward decl
139gint wxapp_idle_callback( gpointer WXUNUSED(data) );
140
60acb947 141bool wxYield()
c801d85f 142{
5f12ae5c
VZ
143 // it's necessary to call ProcessIdle() to update the frames sizes which
144 // might have been changed (it also will update other things set from
145 // OnUpdateUI() which is a nice (and desired) side effect)
e146b8c8 146 for ( wxWindowList::Node *node = wxTopLevelWindows.GetFirst();
5f12ae5c
VZ
147 node;
148 node = node->GetNext() )
149 {
e146b8c8 150 wxWindow *win = node->GetData();
5f12ae5c
VZ
151 win->OnInternalIdle();
152 }
153
53a8af59
KB
154 // We need to temporarily remove idle callbacks or the loop will
155 // never finish.
156 gtk_idle_remove( wxTheApp->m_idleTag );
8801832d 157
53a8af59 158 while (gtk_events_pending())
5f12ae5c
VZ
159 gtk_main_iteration();
160
53a8af59 161 wxTheApp->m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
ec758a20 162 return TRUE;
ff7b1510 163}
c801d85f
KB
164
165//-----------------------------------------------------------------------------
166// wxApp
167//-----------------------------------------------------------------------------
168
169IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
170
53010e52
RR
171BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
172 EVT_IDLE(wxApp::OnIdle)
173END_EVENT_TABLE()
174
c801d85f
KB
175gint wxapp_idle_callback( gpointer WXUNUSED(data) )
176{
afb74891
VZ
177 if (wxTheApp)
178 {
179 while (wxTheApp->ProcessIdle())
180 {
181 }
182 }
183
f3855ef0 184 wxMutexGuiLeave();
afb74891 185 wxUsleep(10);
f3855ef0 186 wxMutexGuiEnter();
afb74891 187
ec758a20 188 return TRUE;
ff7b1510 189}
c801d85f
KB
190
191wxApp::wxApp()
192{
0d2a2b60 193 wxTheApp = this;
60acb947 194
ec758a20
RR
195 m_topWindow = (wxWindow *) NULL;
196 m_exitOnFrameDelete = TRUE;
60acb947 197
0d2a2b60 198 m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
60acb947 199
f6fcbb63 200 m_colorCube = (unsigned char*) NULL;
ff7b1510 201}
c801d85f 202
60acb947 203wxApp::~wxApp()
c801d85f 204{
ec758a20 205 gtk_idle_remove( m_idleTag );
60acb947 206
f6fcbb63 207 if (m_colorCube) free(m_colorCube);
ff7b1510 208}
c801d85f 209
0d2a2b60 210bool wxApp::OnInitGui()
c801d85f 211{
f6fcbb63
RR
212 /* Nothing to do for 15, 16, 24, 32 bit displays */
213
214 GdkVisual *visual = gdk_visual_get_system();
215 if (visual->depth > 8) return TRUE;
60acb947 216
0d2a2b60
RR
217 /* this initiates the standard palette as defined by GdkImlib
218 in the GNOME libraries. it ensures that all GNOME applications
219 use the same 64 colormap entries on 8-bit displays so you
220 can use several rather graphics-heavy applications at the
221 same time.
8801832d 222 NOTE: this doesn't really seem to work this way... */
bbe0af5b 223
0d2a2b60
RR
224 /*
225 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
bbe0af5b 226
0d2a2b60
RR
227 for (int i = 0; i < 64; i++)
228 {
229 GdkColor col;
230 col.red = g_palette[i*3 + 0] << 8;
231 col.green = g_palette[i*3 + 1] << 8;
232 col.blue = g_palette[i*3 + 2] << 8;
233 col.pixel = 0;
234
235 gdk_color_alloc( cmap, &col );
236 }
60acb947 237
0d2a2b60
RR
238 gtk_widget_set_default_colormap( cmap );
239 */
60acb947 240
f6fcbb63 241 /* initialize color cube for 8-bit color reduction dithering */
60acb947 242
f6fcbb63 243 GdkColormap *cmap = gtk_widget_get_default_colormap();
60acb947 244
f6fcbb63
RR
245 m_colorCube = (unsigned char*)malloc(32 * 32 * 32);
246
247 for (int r = 0; r < 32; r++)
248 {
8801832d
VZ
249 for (int g = 0; g < 32; g++)
250 {
251 for (int b = 0; b < 32; b++)
252 {
253 int rr = (r << 3) | (r >> 2);
254 int gg = (g << 3) | (g >> 2);
255 int bb = (b << 3) | (b >> 2);
60acb947 256
f6fcbb63
RR
257 GdkColor *colors = cmap->colors;
258 int max = 3 * (65536);
259 int index = -1;
260
261 for (int i = 0; i < cmap->size; i++)
262 {
263 int rdiff = ((rr << 8) - colors[i].red);
264 int gdiff = ((gg << 8)- colors[i].green);
265 int bdiff = ((bb << 8)- colors[i].blue);
266 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
267 if (sum < max) { index = i; max = sum; }
268 }
60acb947 269
8801832d
VZ
270 m_colorCube[ (r*1024) + (g*32) + b ] = index;
271 }
272 }
f6fcbb63 273 }
c801d85f 274
60acb947 275
bbe0af5b
RR
276 return TRUE;
277}
278
60acb947 279bool wxApp::ProcessIdle()
53010e52 280{
ec758a20
RR
281 wxIdleEvent event;
282 event.SetEventObject( this );
283 ProcessEvent( event );
0cf2cb36 284
ec758a20 285 return event.MoreRequested();
ff7b1510 286}
53010e52
RR
287
288void wxApp::OnIdle( wxIdleEvent &event )
c801d85f 289{
ec758a20 290 static bool inOnIdle = FALSE;
53010e52 291
d524867f 292 /* Avoid recursion (via ProcessEvent default case) */
ec758a20
RR
293 if (inOnIdle)
294 return;
53010e52 295
ec758a20 296 inOnIdle = TRUE;
53010e52 297
d345e841 298#if wxUSE_THREADS
7214297d
GL
299 /* Resend in the main thread events which have been prepared in other
300 threads */
301 ProcessPendingEvents();
d345e841 302#endif
7214297d 303
d524867f 304 /* 'Garbage' collection of windows deleted with Close(). */
ec758a20 305 DeletePendingObjects();
53010e52 306
d524867f
RR
307 /* flush the logged messages if any */
308 wxLog *log = wxLog::GetActiveTarget();
309 if (log != NULL && log->HasPendingMessages())
310 log->Flush();
53010e52 311
d524867f 312 /* Send OnIdle events to all windows */
ec758a20 313 bool needMore = SendIdleEvents();
53010e52 314
ec758a20
RR
315 if (needMore)
316 event.RequestMore(TRUE);
53010e52 317
ec758a20 318 inOnIdle = FALSE;
ff7b1510 319}
53010e52 320
60acb947 321bool wxApp::SendIdleEvents()
53010e52
RR
322{
323 bool needMore = FALSE;
e0253070 324
e146b8c8 325 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
ec758a20
RR
326 while (node)
327 {
e146b8c8 328 wxWindow* win = node->GetData();
f3855ef0 329 if (SendIdleEvents(win))
53010e52 330 needMore = TRUE;
e146b8c8 331 node = node->GetNext();
ec758a20 332 }
e146b8c8 333
53010e52 334 return needMore;
ff7b1510 335}
53010e52
RR
336
337bool wxApp::SendIdleEvents( wxWindow* win )
338{
339 bool needMore = FALSE;
340
8bbe427f
VZ
341 wxIdleEvent event;
342 event.SetEventObject(win);
60acb947 343
9390a202 344 win->OnInternalIdle();
60acb947 345
8bbe427f 346 win->ProcessEvent(event);
53010e52
RR
347
348 if (event.MoreRequested())
349 needMore = TRUE;
350
8bbe427f
VZ
351 wxNode* node = win->GetChildren().First();
352 while (node)
353 {
354 wxWindow* win = (wxWindow*) node->Data();
355 if (SendIdleEvents(win))
53010e52
RR
356 needMore = TRUE;
357
8bbe427f
VZ
358 node = node->Next();
359 }
53010e52 360 return needMore ;
ff7b1510 361}
c801d85f 362
60acb947 363int wxApp::MainLoop()
c801d85f 364{
ec758a20
RR
365 gtk_main();
366 return 0;
ff7b1510 367}
c801d85f 368
60acb947 369void wxApp::ExitMainLoop()
c801d85f 370{
ec758a20 371 gtk_main_quit();
ff7b1510 372}
c801d85f 373
60acb947 374bool wxApp::Initialized()
c801d85f 375{
ec758a20 376 return m_initialized;
ff7b1510 377}
c801d85f 378
60acb947 379bool wxApp::Pending()
c801d85f 380{
8801832d 381 return gtk_events_pending();
ff7b1510 382}
c801d85f 383
60acb947 384void wxApp::Dispatch()
c801d85f 385{
8801832d 386 gtk_main_iteration();
ff7b1510 387}
c801d85f 388
7214297d
GL
389#if wxUSE_THREADS
390void wxApp::ProcessPendingEvents()
391{
4d3a259a
GL
392 wxNode *node = wxPendingEvents->First();
393 wxCriticalSectionLocker locker(*wxPendingEventsLocker);
7214297d
GL
394
395 while (node)
396 {
397 wxEvtHandler *handler = (wxEvtHandler *)node->Data();
398
399 handler->ProcessPendingEvents();
e146b8c8 400
7214297d
GL
401 delete node;
402
4d3a259a 403 node = wxPendingEvents->First();
7214297d
GL
404 }
405}
8801832d 406#endif // wxUSE_THREADS
7214297d 407
60acb947 408void wxApp::DeletePendingObjects()
c801d85f 409{
ec758a20
RR
410 wxNode *node = wxPendingDelete.First();
411 while (node)
412 {
413 wxObject *obj = (wxObject *)node->Data();
0cf2cb36 414
ec758a20 415 delete obj;
c801d85f 416
ec758a20
RR
417 if (wxPendingDelete.Member(obj))
418 delete node;
c801d85f 419
ec758a20
RR
420 node = wxPendingDelete.First();
421 }
ff7b1510 422}
c801d85f 423
60acb947 424wxWindow *wxApp::GetTopWindow()
c801d85f 425{
e146b8c8
VZ
426 if (m_topWindow)
427 return m_topWindow;
428 else if (wxTopLevelWindows.GetCount() > 0)
429 return wxTopLevelWindows.GetFirst()->GetData();
430 else
431 return NULL;
ff7b1510 432}
c801d85f
KB
433
434void wxApp::SetTopWindow( wxWindow *win )
435{
ec758a20 436 m_topWindow = win;
ff7b1510 437}
c801d85f 438
60acb947 439bool wxApp::Initialize()
c801d85f 440{
9cc7a35d 441 wxBuffer = new wxChar[BUFSIZ + 512];
0d2a2b60
RR
442
443 wxClassInfo::InitializeClasses();
60acb947 444
0d2a2b60 445 wxSystemSettings::Init();
60acb947 446
4d3a259a
GL
447 // GL: I'm annoyed ... I don't know where to put this and I don't want to
448 // create a module for that as it's part of the core.
449#if wxUSE_THREADS
450 wxPendingEvents = new wxList();
451 wxPendingEventsLocker = new wxCriticalSection();
452#endif
453
36b3b54a 454/*
0d2a2b60
RR
455 wxTheFontNameDirectory = new wxFontNameDirectory;
456 wxTheFontNameDirectory->Initialize();
36b3b54a 457*/
c801d85f 458
0d2a2b60
RR
459 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
460 wxTheColourDatabase->Initialize();
a3622daa 461
0d2a2b60
RR
462 wxInitializeStockLists();
463 wxInitializeStockObjects();
c801d85f 464
06cfab17 465#if wxUSE_WX_RESOURCES
0d2a2b60 466 wxTheResourceCache = new wxResourceCache( wxKEY_STRING );
60acb947 467
0d2a2b60 468 wxInitializeResourceSystem();
f5abe911 469#endif
0cf2cb36 470
0d2a2b60 471 wxImage::InitStandardHandlers();
e0253070 472
0d2a2b60
RR
473 /* no global cursor under X
474 g_globalCursor = new wxCursor; */
60acb947 475
0d2a2b60
RR
476 wxModule::RegisterModules();
477 if (!wxModule::InitializeModules()) return FALSE;
60acb947 478
0d2a2b60 479 return TRUE;
ff7b1510 480}
c801d85f 481
60acb947 482void wxApp::CleanUp()
c801d85f 483{
0d2a2b60 484 wxModule::CleanUpModules();
0cf2cb36 485
06cfab17 486#if wxUSE_WX_RESOURCES
ec758a20 487 wxFlushResources();
a3622daa 488
60acb947
VZ
489 if (wxTheResourceCache)
490 delete wxTheResourceCache;
bbe0af5b 491 wxTheResourceCache = (wxResourceCache*) NULL;
60acb947 492
f5abe911
RR
493 wxCleanUpResourceSystem();
494#endif
a3622daa 495
60acb947
VZ
496 if (wxTheColourDatabase)
497 delete wxTheColourDatabase;
0d2a2b60 498 wxTheColourDatabase = (wxColourDatabase*) NULL;
60acb947 499
36b3b54a 500/*
0d2a2b60
RR
501 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
502 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
36b3b54a 503*/
60acb947 504
0d2a2b60
RR
505 wxDeleteStockObjects();
506
ec758a20 507 wxDeleteStockLists();
a3622daa 508
ec758a20 509 wxImage::CleanUpHandlers();
0cf2cb36 510
0d2a2b60
RR
511 delete wxTheApp;
512 wxTheApp = (wxApp*) NULL;
513
4d3a259a
GL
514 // GL: I'm annoyed ... I don't know where to put this and I don't want to
515 // create a module for that as it's part of the core.
516#if wxUSE_THREADS
517 delete wxPendingEvents;
518 delete wxPendingEventsLocker;
519#endif
520
3e61c765 521 wxSystemSettings::Done();
60acb947 522
3e61c765
RR
523 delete[] wxBuffer;
524
525 wxClassInfo::CleanUpClasses();
60acb947
VZ
526
527 // check for memory leaks
0d2a2b60
RR
528#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
529 if (wxDebugContext::CountObjectsLeft() > 0)
530 {
9cc7a35d 531 wxLogDebug(_T("There were memory leaks.\n"));
0d2a2b60
RR
532 wxDebugContext::Dump();
533 wxDebugContext::PrintStatistics();
534 }
8801832d 535#endif // Debug
0d2a2b60 536
60acb947 537 // do this as the very last thing because everything else can log messages
0d2a2b60 538 wxLog::DontCreateOnDemand();
60acb947 539
0d2a2b60 540 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
60acb947
VZ
541 if (oldLog)
542 delete oldLog;
ff7b1510 543}
0cf2cb36 544
c801d85f
KB
545wxLog *wxApp::CreateLogTarget()
546{
0d2a2b60 547 return new wxLogGui;
c801d85f
KB
548}
549
550//-----------------------------------------------------------------------------
551// wxEntry
552//-----------------------------------------------------------------------------
553
554int wxEntry( int argc, char *argv[] )
555{
0d2a2b60 556 gtk_set_locale();
c801d85f 557
0d2a2b60 558 gtk_init( &argc, &argv );
0cf2cb36 559
60acb947
VZ
560 if (!wxApp::Initialize())
561 return -1;
0cf2cb36 562
ec758a20 563 if (!wxTheApp)
c801d85f 564 {
60acb947 565 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
9cc7a35d 566 _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
0cf2cb36 567
ec758a20 568 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
0cf2cb36 569
ec758a20 570 wxObject *test_app = app_ini();
0cf2cb36 571
ec758a20
RR
572 wxTheApp = (wxApp*) test_app;
573 }
0cf2cb36 574
9cc7a35d 575 wxCHECK_MSG( wxTheApp, -1, _T("wxWindows error: no application object") );
c801d85f 576
ec758a20
RR
577 wxTheApp->argc = argc;
578 wxTheApp->argv = argv;
0cf2cb36 579
8801832d 580 wxString name(wxFileNameFromPath(argv[0]));
ec758a20
RR
581 wxStripExtension( name );
582 wxTheApp->SetAppName( name );
e0253070 583
0151c3eb
VZ
584 int retValue = 0;
585
586 if ( !wxTheApp->OnInitGui() )
587 retValue = -1;
c801d85f 588
8801832d
VZ
589 // Here frames insert themselves automatically into wxTopLevelWindows by
590 // getting created in OnInit().
0151c3eb
VZ
591 if ( retValue == 0 )
592 {
593 if ( !wxTheApp->OnInit() )
594 retValue = -1;
595 }
0cf2cb36 596
0151c3eb
VZ
597 if ( retValue == 0 )
598 {
599 wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
0cf2cb36 600
0151c3eb
VZ
601 if (wxTheApp->Initialized())
602 retValue = wxTheApp->OnRun();
0cf2cb36 603
0151c3eb
VZ
604 wxWindow *topWindow = wxTheApp->GetTopWindow();
605 if (topWindow)
0d2a2b60 606 {
0151c3eb
VZ
607 // Forcibly delete the window.
608 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
609 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
610 {
611 topWindow->Close( TRUE );
612 wxTheApp->DeletePendingObjects();
613 }
614 else
615 {
616 delete topWindow;
617 wxTheApp->SetTopWindow( (wxWindow*) NULL );
618 }
0d2a2b60 619 }
e0253070 620
0151c3eb
VZ
621 wxTheApp->OnExit();
622 }
0cf2cb36 623
60acb947 624 // flush the logged messages if any
0d2a2b60
RR
625 wxLog *log = wxLog::GetActiveTarget();
626 if (log != NULL && log->HasPendingMessages())
627 log->Flush();
628
60acb947
VZ
629 // continuing to use user defined log target is unsafe from now on because
630 // some resources may be already unavailable, so replace it by something
631 // more safe
632 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
633 if ( oldlog )
634 delete oldlog;
635
0d2a2b60 636 wxApp::CleanUp();
184b5d99 637
ec758a20 638 return retValue;
ff7b1510 639}
1a56f55c 640