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