]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/app.cpp
typo in dcclient.cpp corrected (wxUSE_SPLINE => wxUSE_SPLINES)
[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
7214297d 48#if wxUSE_THREADS
4d3a259a
GL
49extern wxList *wxPendingEvents;
50extern wxCriticalSection *wxPendingEventsLocker;
7214297d 51#endif
a3622daa 52extern wxResourceCache *wxTheResourceCache;
acfd422a 53extern bool g_isIdle;
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
acfd422a 138/* forward declaration */
53a8af59
KB
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
acfd422a
RR
154 if (wxTheApp->m_idleTag)
155 {
156 /* We need to temporarily remove idle callbacks or the loop will
157 never finish. */
158 gtk_idle_remove( wxTheApp->m_idleTag );
159 wxTheApp->m_idleTag = 0;
160
161 while (gtk_events_pending())
162 gtk_main_iteration();
163
164 /* re-add idle handler */
165 wxTheApp->m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
166 }
167 else
168 {
169 while (gtk_events_pending())
170 gtk_main_iteration();
171 }
172
173 return TRUE;
174}
175
176gint wxapp_idle_callback( gpointer WXUNUSED(data) )
177{
178 if (!wxTheApp) return TRUE;
179
180 /* sent idle event to all who request them */
181 while (wxTheApp->ProcessIdle()) { }
182
183 /* we don't want any more idle events until the next event is
184 sent to wxGTK */
53a8af59 185 gtk_idle_remove( wxTheApp->m_idleTag );
acfd422a
RR
186 wxTheApp->m_idleTag = 0;
187
188 /* indicate that we are now in idle mode - even so deeply
189 in idle mode that we don't get any idle events anymore.
190 this is like wxMSW where an idle event is sent only
191 once each time after the event queue has been completely
192 emptied */
193 g_isIdle = TRUE;
194
b9a535f5 195 /* wake up other threads */
053dcf1a 196
b9a535f5
RR
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
f03fc89f
VZ
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
f03fc89f
VZ
290 int index = -1;
291
f6fcbb63 292 GdkColor *colors = cmap->colors;
f03fc89f
VZ
293 if(colors)
294 {
295 int max = 3 * 65536;
296
297 for (int i = 0; i < cmap->size; i++)
298 {
299 int rdiff = ((rr << 8) - colors[i].red);
300 int gdiff = ((gg << 8) - colors[i].green);
301 int bdiff = ((bb << 8) - colors[i].blue);
302 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
303 if (sum < max)
304 {
305 index = i; max = sum;
306 }
307 }
f6fcbb63 308 }
f03fc89f 309
8801832d
VZ
310 m_colorCube[ (r*1024) + (g*32) + b ] = index;
311 }
312 }
f6fcbb63 313 }
c801d85f 314
bbe0af5b
RR
315 return TRUE;
316}
317
60acb947 318bool wxApp::ProcessIdle()
53010e52 319{
ec758a20
RR
320 wxIdleEvent event;
321 event.SetEventObject( this );
322 ProcessEvent( event );
0cf2cb36 323
ec758a20 324 return event.MoreRequested();
ff7b1510 325}
53010e52
RR
326
327void wxApp::OnIdle( wxIdleEvent &event )
c801d85f 328{
ec758a20 329 static bool inOnIdle = FALSE;
53010e52 330
d524867f 331 /* Avoid recursion (via ProcessEvent default case) */
ec758a20
RR
332 if (inOnIdle)
333 return;
53010e52 334
ec758a20 335 inOnIdle = TRUE;
53010e52 336
d345e841 337#if wxUSE_THREADS
7214297d
GL
338 /* Resend in the main thread events which have been prepared in other
339 threads */
340 ProcessPendingEvents();
d345e841 341#endif
7214297d 342
d524867f 343 /* 'Garbage' collection of windows deleted with Close(). */
ec758a20 344 DeletePendingObjects();
53010e52 345
d524867f
RR
346 /* flush the logged messages if any */
347 wxLog *log = wxLog::GetActiveTarget();
348 if (log != NULL && log->HasPendingMessages())
349 log->Flush();
53010e52 350
d524867f 351 /* Send OnIdle events to all windows */
ec758a20 352 bool needMore = SendIdleEvents();
53010e52 353
ec758a20
RR
354 if (needMore)
355 event.RequestMore(TRUE);
53010e52 356
ec758a20 357 inOnIdle = FALSE;
ff7b1510 358}
53010e52 359
60acb947 360bool wxApp::SendIdleEvents()
53010e52
RR
361{
362 bool needMore = FALSE;
e0253070 363
e146b8c8 364 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
ec758a20
RR
365 while (node)
366 {
e146b8c8 367 wxWindow* win = node->GetData();
f3855ef0 368 if (SendIdleEvents(win))
53010e52 369 needMore = TRUE;
e146b8c8 370 node = node->GetNext();
ec758a20 371 }
e146b8c8 372
53010e52 373 return needMore;
ff7b1510 374}
53010e52
RR
375
376bool wxApp::SendIdleEvents( wxWindow* win )
377{
378 bool needMore = FALSE;
379
8bbe427f
VZ
380 wxIdleEvent event;
381 event.SetEventObject(win);
60acb947 382
9390a202 383 win->OnInternalIdle();
60acb947 384
8bbe427f 385 win->ProcessEvent(event);
53010e52
RR
386
387 if (event.MoreRequested())
388 needMore = TRUE;
389
8bbe427f
VZ
390 wxNode* node = win->GetChildren().First();
391 while (node)
392 {
393 wxWindow* win = (wxWindow*) node->Data();
394 if (SendIdleEvents(win))
53010e52
RR
395 needMore = TRUE;
396
8bbe427f
VZ
397 node = node->Next();
398 }
53010e52 399 return needMore ;
ff7b1510 400}
c801d85f 401
60acb947 402int wxApp::MainLoop()
c801d85f 403{
ec758a20
RR
404 gtk_main();
405 return 0;
ff7b1510 406}
c801d85f 407
60acb947 408void wxApp::ExitMainLoop()
c801d85f 409{
ec758a20 410 gtk_main_quit();
ff7b1510 411}
c801d85f 412
60acb947 413bool wxApp::Initialized()
c801d85f 414{
ec758a20 415 return m_initialized;
ff7b1510 416}
c801d85f 417
60acb947 418bool wxApp::Pending()
c801d85f 419{
acfd422a 420 return (gtk_events_pending() > 0);
ff7b1510 421}
c801d85f 422
60acb947 423void wxApp::Dispatch()
c801d85f 424{
8801832d 425 gtk_main_iteration();
ff7b1510 426}
c801d85f 427
7214297d
GL
428#if wxUSE_THREADS
429void wxApp::ProcessPendingEvents()
430{
4d3a259a
GL
431 wxNode *node = wxPendingEvents->First();
432 wxCriticalSectionLocker locker(*wxPendingEventsLocker);
7214297d
GL
433
434 while (node)
435 {
436 wxEvtHandler *handler = (wxEvtHandler *)node->Data();
437
438 handler->ProcessPendingEvents();
e146b8c8 439
7214297d
GL
440 delete node;
441
4d3a259a 442 node = wxPendingEvents->First();
7214297d
GL
443 }
444}
8801832d 445#endif // wxUSE_THREADS
7214297d 446
60acb947 447void wxApp::DeletePendingObjects()
c801d85f 448{
ec758a20
RR
449 wxNode *node = wxPendingDelete.First();
450 while (node)
451 {
452 wxObject *obj = (wxObject *)node->Data();
0cf2cb36 453
ec758a20 454 delete obj;
c801d85f 455
f03fc89f
VZ
456 if (wxPendingDelete.Find(obj))
457 delete node;
c801d85f 458
ec758a20
RR
459 node = wxPendingDelete.First();
460 }
ff7b1510 461}
c801d85f 462
60acb947 463wxWindow *wxApp::GetTopWindow()
c801d85f 464{
e146b8c8
VZ
465 if (m_topWindow)
466 return m_topWindow;
467 else if (wxTopLevelWindows.GetCount() > 0)
468 return wxTopLevelWindows.GetFirst()->GetData();
469 else
470 return NULL;
ff7b1510 471}
c801d85f
KB
472
473void wxApp::SetTopWindow( wxWindow *win )
474{
ec758a20 475 m_topWindow = win;
ff7b1510 476}
c801d85f 477
60acb947 478bool wxApp::Initialize()
c801d85f 479{
9cc7a35d 480 wxBuffer = new wxChar[BUFSIZ + 512];
0d2a2b60
RR
481
482 wxClassInfo::InitializeClasses();
60acb947 483
0d2a2b60 484 wxSystemSettings::Init();
60acb947 485
4d3a259a
GL
486 // GL: I'm annoyed ... I don't know where to put this and I don't want to
487 // create a module for that as it's part of the core.
488#if wxUSE_THREADS
489 wxPendingEvents = new wxList();
490 wxPendingEventsLocker = new wxCriticalSection();
491#endif
492
36b3b54a 493/*
0d2a2b60
RR
494 wxTheFontNameDirectory = new wxFontNameDirectory;
495 wxTheFontNameDirectory->Initialize();
36b3b54a 496*/
c801d85f 497
0d2a2b60
RR
498 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
499 wxTheColourDatabase->Initialize();
a3622daa 500
0d2a2b60
RR
501 wxInitializeStockLists();
502 wxInitializeStockObjects();
c801d85f 503
06cfab17 504#if wxUSE_WX_RESOURCES
0d2a2b60 505 wxTheResourceCache = new wxResourceCache( wxKEY_STRING );
60acb947 506
0d2a2b60 507 wxInitializeResourceSystem();
f5abe911 508#endif
0cf2cb36 509
0d2a2b60 510 wxImage::InitStandardHandlers();
e0253070 511
0d2a2b60
RR
512 /* no global cursor under X
513 g_globalCursor = new wxCursor; */
60acb947 514
0d2a2b60
RR
515 wxModule::RegisterModules();
516 if (!wxModule::InitializeModules()) return FALSE;
60acb947 517
0d2a2b60 518 return TRUE;
ff7b1510 519}
c801d85f 520
60acb947 521void wxApp::CleanUp()
c801d85f 522{
0d2a2b60 523 wxModule::CleanUpModules();
0cf2cb36 524
06cfab17 525#if wxUSE_WX_RESOURCES
ec758a20 526 wxFlushResources();
a3622daa 527
60acb947
VZ
528 if (wxTheResourceCache)
529 delete wxTheResourceCache;
bbe0af5b 530 wxTheResourceCache = (wxResourceCache*) NULL;
60acb947 531
f5abe911
RR
532 wxCleanUpResourceSystem();
533#endif
a3622daa 534
60acb947
VZ
535 if (wxTheColourDatabase)
536 delete wxTheColourDatabase;
0d2a2b60 537 wxTheColourDatabase = (wxColourDatabase*) NULL;
60acb947 538
36b3b54a 539/*
0d2a2b60
RR
540 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
541 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
36b3b54a 542*/
60acb947 543
0d2a2b60
RR
544 wxDeleteStockObjects();
545
ec758a20 546 wxDeleteStockLists();
a3622daa 547
ec758a20 548 wxImage::CleanUpHandlers();
0cf2cb36 549
0d2a2b60
RR
550 delete wxTheApp;
551 wxTheApp = (wxApp*) NULL;
552
4d3a259a
GL
553 // GL: I'm annoyed ... I don't know where to put this and I don't want to
554 // create a module for that as it's part of the core.
555#if wxUSE_THREADS
556 delete wxPendingEvents;
557 delete wxPendingEventsLocker;
558#endif
559
3e61c765 560 wxSystemSettings::Done();
60acb947 561
3e61c765
RR
562 delete[] wxBuffer;
563
564 wxClassInfo::CleanUpClasses();
60acb947
VZ
565
566 // check for memory leaks
0d2a2b60
RR
567#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
568 if (wxDebugContext::CountObjectsLeft() > 0)
569 {
9cc7a35d 570 wxLogDebug(_T("There were memory leaks.\n"));
0d2a2b60
RR
571 wxDebugContext::Dump();
572 wxDebugContext::PrintStatistics();
573 }
8801832d 574#endif // Debug
0d2a2b60 575
60acb947 576 // do this as the very last thing because everything else can log messages
0d2a2b60 577 wxLog::DontCreateOnDemand();
60acb947 578
0d2a2b60 579 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
60acb947
VZ
580 if (oldLog)
581 delete oldLog;
ff7b1510 582}
0cf2cb36 583
c801d85f
KB
584wxLog *wxApp::CreateLogTarget()
585{
0d2a2b60 586 return new wxLogGui;
c801d85f
KB
587}
588
589//-----------------------------------------------------------------------------
590// wxEntry
591//-----------------------------------------------------------------------------
592
593int wxEntry( int argc, char *argv[] )
594{
0d2a2b60 595 gtk_set_locale();
c801d85f 596
0d2a2b60 597 gtk_init( &argc, &argv );
0cf2cb36 598
60acb947
VZ
599 if (!wxApp::Initialize())
600 return -1;
0cf2cb36 601
ec758a20 602 if (!wxTheApp)
c801d85f 603 {
60acb947 604 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
9cc7a35d 605 _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
0cf2cb36 606
ec758a20 607 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
0cf2cb36 608
ec758a20 609 wxObject *test_app = app_ini();
0cf2cb36 610
ec758a20
RR
611 wxTheApp = (wxApp*) test_app;
612 }
0cf2cb36 613
9cc7a35d 614 wxCHECK_MSG( wxTheApp, -1, _T("wxWindows error: no application object") );
c801d85f 615
ec758a20
RR
616 wxTheApp->argc = argc;
617 wxTheApp->argv = argv;
0cf2cb36 618
8801832d 619 wxString name(wxFileNameFromPath(argv[0]));
ec758a20
RR
620 wxStripExtension( name );
621 wxTheApp->SetAppName( name );
e0253070 622
0151c3eb
VZ
623 int retValue = 0;
624
625 if ( !wxTheApp->OnInitGui() )
626 retValue = -1;
c801d85f 627
8801832d
VZ
628 // Here frames insert themselves automatically into wxTopLevelWindows by
629 // getting created in OnInit().
0151c3eb
VZ
630 if ( retValue == 0 )
631 {
632 if ( !wxTheApp->OnInit() )
633 retValue = -1;
634 }
0cf2cb36 635
0151c3eb
VZ
636 if ( retValue == 0 )
637 {
638 wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
0cf2cb36 639
0151c3eb
VZ
640 if (wxTheApp->Initialized())
641 retValue = wxTheApp->OnRun();
0cf2cb36 642
0151c3eb
VZ
643 wxWindow *topWindow = wxTheApp->GetTopWindow();
644 if (topWindow)
0d2a2b60 645 {
0151c3eb
VZ
646 // Forcibly delete the window.
647 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
648 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
649 {
650 topWindow->Close( TRUE );
651 wxTheApp->DeletePendingObjects();
652 }
653 else
654 {
655 delete topWindow;
656 wxTheApp->SetTopWindow( (wxWindow*) NULL );
657 }
0d2a2b60 658 }
e0253070 659
0151c3eb
VZ
660 wxTheApp->OnExit();
661 }
0cf2cb36 662
60acb947 663 // flush the logged messages if any
0d2a2b60
RR
664 wxLog *log = wxLog::GetActiveTarget();
665 if (log != NULL && log->HasPendingMessages())
666 log->Flush();
667
60acb947
VZ
668 // continuing to use user defined log target is unsafe from now on because
669 // some resources may be already unavailable, so replace it by something
670 // more safe
671 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
672 if ( oldlog )
673 delete oldlog;
674
0d2a2b60 675 wxApp::CleanUp();
184b5d99 676
ec758a20 677 return retValue;
ff7b1510 678}
1a56f55c 679