added wxApp::Yield()
[wxWidgets.git] / src / gtk / app.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: app.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "app.h"
12 #endif
13
14 #include "wx/app.h"
15 #include "wx/gdicmn.h"
16 #include "wx/utils.h"
17 #include "wx/intl.h"
18 #include "wx/log.h"
19 #include "wx/memory.h"
20 #include "wx/font.h"
21 #include "wx/settings.h"
22 #include "wx/dialog.h"
23
24 #if wxUSE_WX_RESOURCES
25 #include "wx/resource.h"
26 #endif
27
28 #include "wx/module.h"
29 #include "wx/image.h"
30
31 #ifdef __WXUNIVERSAL__
32 #include "wx/univ/theme.h"
33 #include "wx/univ/renderer.h"
34 #endif
35
36 #if wxUSE_THREADS
37 #include "wx/thread.h"
38 #endif
39
40 #include <unistd.h>
41 #include "wx/gtk/win_gtk.h"
42
43 #include <gtk/gtk.h>
44
45
46 //-----------------------------------------------------------------------------
47 // global data
48 //-----------------------------------------------------------------------------
49
50 wxApp *wxTheApp = (wxApp *) NULL;
51 wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
52
53 extern bool g_isIdle;
54
55 bool g_mainThreadLocked = FALSE;
56 gint g_pendingTag = 0;
57
58 static GtkWidget *gs_RootWindow = (GtkWidget*) NULL;
59
60 //-----------------------------------------------------------------------------
61 // local functions
62 //-----------------------------------------------------------------------------
63
64 /* forward declaration */
65 gint wxapp_idle_callback( gpointer WXUNUSED(data) );
66 gint wxapp_pending_callback( gpointer WXUNUSED(data) );
67 void wxapp_install_idle_handler();
68
69 #if wxUSE_THREADS
70 gint wxapp_wakeup_timerout_callback( gpointer WXUNUSED(data) );
71 #endif
72
73 //-----------------------------------------------------------------------------
74 // wxExit
75 //-----------------------------------------------------------------------------
76
77 void wxExit()
78 {
79 gtk_main_quit();
80 }
81
82 //-----------------------------------------------------------------------------
83 // wxYield
84 //-----------------------------------------------------------------------------
85
86 bool wxApp::Yield(bool onlyIfNeeded)
87 {
88 // MT-FIXME
89 static bool s_inYield = FALSE;
90
91 if ( s_inYield )
92 {
93 if ( !onlyIfNeeded )
94 {
95 wxFAIL_MSG( wxT("wxYield called recursively" ) );
96 }
97
98 return FALSE;
99 }
100
101 #if wxUSE_THREADS
102 if ( !wxThread::IsMain() )
103 {
104 // can't call gtk_main_iteration() from other threads like this
105 return TRUE;
106 }
107 #endif // wxUSE_THREADS
108
109 s_inYield = TRUE;
110
111 if (!g_isIdle)
112 {
113 // We need to remove idle callbacks or the loop will
114 // never finish.
115 gtk_idle_remove( m_idleTag );
116 m_idleTag = 0;
117 g_isIdle = TRUE;
118 }
119
120 // disable log flushing from here because a call to wxYield() shouldn't
121 // normally result in message boxes popping up &c
122 wxLog::Suspend();
123
124 while (gtk_events_pending())
125 gtk_main_iteration();
126
127 /* it's necessary to call ProcessIdle() to update the frames sizes which
128 might have been changed (it also will update other things set from
129 OnUpdateUI() which is a nice (and desired) side effect) */
130 while ( ProcessIdle() )
131 {
132 }
133
134 // let the logs be flashed again
135 wxLog::Resume();
136
137 s_inYield = FALSE;
138
139 return TRUE;
140 }
141
142 //-----------------------------------------------------------------------------
143 // wxWakeUpIdle
144 //-----------------------------------------------------------------------------
145
146 void wxWakeUpIdle()
147 {
148 #if wxUSE_THREADS
149 if (!wxThread::IsMain())
150 wxMutexGuiEnter();
151 #endif
152
153 if (g_isIdle)
154 wxapp_install_idle_handler();
155
156 #if wxUSE_THREADS
157 if (!wxThread::IsMain())
158 wxMutexGuiLeave();
159 #endif
160 }
161
162 //-----------------------------------------------------------------------------
163 // local functions
164 //-----------------------------------------------------------------------------
165
166 gint wxapp_pending_callback( gpointer WXUNUSED(data) )
167 {
168 if (!wxTheApp) return TRUE;
169
170 // when getting called from GDK's time-out handler
171 // we are no longer within GDK's grab on the GUI
172 // thread so we must lock it here ourselves
173 gdk_threads_enter();
174
175 // Sent idle event to all who request them
176 wxTheApp->ProcessPendingEvents();
177
178 g_pendingTag = 0;
179
180 /* flush the logged messages if any */
181 #if wxUSE_LOG
182 wxLog::FlushActive();
183 #endif // wxUSE_LOG
184
185 // Release lock again
186 gdk_threads_leave();
187
188 // Return FALSE to indicate that no more idle events are
189 // to be sent (single shot instead of continuous stream)
190 return FALSE;
191 }
192
193 gint wxapp_idle_callback( gpointer WXUNUSED(data) )
194 {
195 if (!wxTheApp)
196 return TRUE;
197
198 #ifdef __WXDEBUG__
199 // don't generate the idle events while the assert modal dialog is shown,
200 // this completely confuses the apps which don't expect to be reentered
201 // from some safely-looking functions
202 if ( wxTheApp->IsInAssert() )
203 {
204 return TRUE;
205 }
206 #endif // __WXDEBUG__
207
208 // when getting called from GDK's time-out handler
209 // we are no longer within GDK's grab on the GUI
210 // thread so we must lock it here ourselves
211 gdk_threads_enter();
212
213 /* Indicate that we are now in idle mode - even so deeply
214 in idle mode that we don't get any idle events anymore.
215 this is like wxMSW where an idle event is sent only
216 once each time after the event queue has been completely
217 emptied */
218 g_isIdle = TRUE;
219 wxTheApp->m_idleTag = 0;
220
221 // Sent idle event to all who request them as long as they do
222 while (wxTheApp->ProcessIdle())
223 ;
224
225 // Release lock again
226 gdk_threads_leave();
227
228 // Return FALSE to indicate that no more idle events are
229 // to be sent (single shot instead of continuous stream)
230 return FALSE;
231 }
232
233 void wxapp_install_idle_handler()
234 {
235 wxASSERT_MSG( wxTheApp->m_idleTag == 0, wxT("attempt to install idle handler twice") );
236
237 g_isIdle = FALSE;
238
239 if (g_pendingTag == 0)
240 g_pendingTag = gtk_idle_add_priority( 900, wxapp_pending_callback, (gpointer) NULL );
241
242 /* This routine gets called by all event handlers
243 indicating that the idle is over. It may also
244 get called from other thread for sending events
245 to the main thread (and processing these in
246 idle time). Very low priority. */
247
248 wxTheApp->m_idleTag = gtk_idle_add_priority( 1000, wxapp_idle_callback, (gpointer) NULL );
249 }
250
251 #if wxUSE_THREADS
252
253 static int g_threadUninstallLevel = 0;
254
255 void wxapp_install_thread_wakeup()
256 {
257 g_threadUninstallLevel++;
258
259 if (g_threadUninstallLevel != 1) return;
260
261 if (wxTheApp->m_wakeUpTimerTag) return;
262
263 wxTheApp->m_wakeUpTimerTag = gtk_timeout_add( 50, wxapp_wakeup_timerout_callback, (gpointer) NULL );
264 }
265
266 void wxapp_uninstall_thread_wakeup()
267 {
268 g_threadUninstallLevel--;
269
270 if (g_threadUninstallLevel != 0) return;
271
272 if (!wxTheApp->m_wakeUpTimerTag) return;
273
274 gtk_timeout_remove( wxTheApp->m_wakeUpTimerTag );
275 wxTheApp->m_wakeUpTimerTag = 0;
276 }
277
278 gint wxapp_wakeup_timerout_callback( gpointer WXUNUSED(data) )
279 {
280 // when getting called from GDK's time-out handler
281 // we are no longer within GDK's grab on the GUI
282 // thread so we must lock it here ourselves
283 gdk_threads_enter();
284
285 wxapp_uninstall_thread_wakeup();
286
287 // unblock other threads wishing to do some GUI things
288 wxMutexGuiLeave();
289
290 g_mainThreadLocked = TRUE;
291
292 // wake up other threads
293 wxUsleep( 1 );
294
295 // block other thread again
296 wxMutexGuiEnter();
297
298 g_mainThreadLocked = FALSE;
299
300 wxapp_install_thread_wakeup();
301
302 // release lock again
303 gdk_threads_leave();
304
305 return TRUE;
306 }
307
308 #endif // wxUSE_THREADS
309
310 //-----------------------------------------------------------------------------
311 // wxApp
312 //-----------------------------------------------------------------------------
313
314 IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
315
316 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
317 EVT_IDLE(wxApp::OnIdle)
318 END_EVENT_TABLE()
319
320 wxApp::wxApp()
321 {
322 m_initialized = FALSE;
323 #ifdef __WXDEBUG__
324 m_isInAssert = FALSE;
325 #endif // __WXDEBUG__
326
327 m_idleTag = 0;
328 wxapp_install_idle_handler();
329
330 #if wxUSE_THREADS
331 m_wakeUpTimerTag = 0;
332 wxapp_install_thread_wakeup();
333 #endif
334
335 m_colorCube = (unsigned char*) NULL;
336
337 // this is NULL for a "regular" wxApp, but is set (and freed) by a wxGLApp
338 m_glVisualInfo = (void *) NULL;
339 }
340
341 wxApp::~wxApp()
342 {
343 if (m_idleTag) gtk_idle_remove( m_idleTag );
344
345 #if wxUSE_THREADS
346 wxapp_uninstall_thread_wakeup();
347 #endif
348
349 if (m_colorCube) free(m_colorCube);
350 }
351
352 bool wxApp::OnInitGui()
353 {
354 if ( !wxAppBase::OnInitGui() )
355 return FALSE;
356
357 GdkVisual *visual = gdk_visual_get_system();
358
359 // if this is a wxGLApp (derived from wxApp), and we've already
360 // chosen a specific visual, then derive the GdkVisual from that
361 if (m_glVisualInfo != NULL) {
362 #ifdef __WXGTK20__
363 /* seems gtk_widget_set_default_visual no longer exists? */
364 GdkVisual* vis = gtk_widget_get_default_visual();
365 #else
366 GdkVisual* vis = gdkx_visual_get(
367 ((XVisualInfo *) m_glVisualInfo) ->visualid );
368 gtk_widget_set_default_visual( vis );
369 #endif
370
371 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
372 gtk_widget_set_default_colormap( colormap );
373
374 visual = vis;
375 }
376
377 /* on some machines, the default visual is just 256 colours, so
378 we make sure we get the best. this can sometimes be wasteful,
379 of course, but what do these guys pay $30.000 for? */
380
381 else if ((gdk_visual_get_best() != gdk_visual_get_system()) &&
382 (m_useBestVisual))
383 {
384 #ifdef __WXGTK20__
385 /* seems gtk_widget_set_default_visual no longer exists? */
386 GdkVisual* vis = gtk_widget_get_default_visual();
387 #else
388 GdkVisual* vis = gdk_visual_get_best();
389 gtk_widget_set_default_visual( vis );
390 #endif
391
392 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
393 gtk_widget_set_default_colormap( colormap );
394
395 visual = vis;
396 }
397
398 /* Nothing to do for 15, 16, 24, 32 bit displays */
399 if (visual->depth > 8) return TRUE;
400
401 /* initialize color cube for 8-bit color reduction dithering */
402
403 GdkColormap *cmap = gtk_widget_get_default_colormap();
404
405 m_colorCube = (unsigned char*)malloc(32 * 32 * 32);
406
407 for (int r = 0; r < 32; r++)
408 {
409 for (int g = 0; g < 32; g++)
410 {
411 for (int b = 0; b < 32; b++)
412 {
413 int rr = (r << 3) | (r >> 2);
414 int gg = (g << 3) | (g >> 2);
415 int bb = (b << 3) | (b >> 2);
416
417 int index = -1;
418
419 GdkColor *colors = cmap->colors;
420 if (colors)
421 {
422 int max = 3 * 65536;
423
424 for (int i = 0; i < cmap->size; i++)
425 {
426 int rdiff = ((rr << 8) - colors[i].red);
427 int gdiff = ((gg << 8) - colors[i].green);
428 int bdiff = ((bb << 8) - colors[i].blue);
429 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
430 if (sum < max)
431 {
432 index = i; max = sum;
433 }
434 }
435 }
436 else
437 {
438 #if (GTK_MINOR_VERSION > 0)
439 /* assume 8-bit true or static colors. this really
440 exists. */
441 GdkVisual* vis = gdk_colormap_get_visual( cmap );
442 index = (r >> (5 - vis->red_prec)) << vis->red_shift;
443 index |= (g >> (5 - vis->green_prec)) << vis->green_shift;
444 index |= (b >> (5 - vis->blue_prec)) << vis->blue_shift;
445 #else
446 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
447 #endif
448 }
449 m_colorCube[ (r*1024) + (g*32) + b ] = index;
450 }
451 }
452 }
453
454 return TRUE;
455 }
456
457 bool wxApp::ProcessIdle()
458 {
459 wxIdleEvent event;
460 event.SetEventObject( this );
461 ProcessEvent( event );
462
463 return event.MoreRequested();
464 }
465
466 void wxApp::OnIdle( wxIdleEvent &event )
467 {
468 static bool s_inOnIdle = FALSE;
469
470 /* Avoid recursion (via ProcessEvent default case) */
471 if (s_inOnIdle)
472 return;
473
474 s_inOnIdle = TRUE;
475
476 /* Resend in the main thread events which have been prepared in other
477 threads */
478 ProcessPendingEvents();
479
480 /* 'Garbage' collection of windows deleted with Close(). */
481 DeletePendingObjects();
482
483 /* Send OnIdle events to all windows */
484 bool needMore = SendIdleEvents();
485
486 if (needMore)
487 event.RequestMore(TRUE);
488
489 s_inOnIdle = FALSE;
490 }
491
492 bool wxApp::SendIdleEvents()
493 {
494 bool needMore = FALSE;
495
496 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
497 while (node)
498 {
499 wxWindow* win = node->GetData();
500 if (SendIdleEvents(win))
501 needMore = TRUE;
502 node = node->GetNext();
503 }
504
505 return needMore;
506 }
507
508 bool wxApp::SendIdleEvents( wxWindow* win )
509 {
510 bool needMore = FALSE;
511
512 wxIdleEvent event;
513 event.SetEventObject(win);
514
515 win->GetEventHandler()->ProcessEvent(event);
516
517 win->OnInternalIdle();
518
519 if (event.MoreRequested())
520 needMore = TRUE;
521
522 wxNode* node = win->GetChildren().First();
523 while (node)
524 {
525 wxWindow* win = (wxWindow*) node->Data();
526 if (SendIdleEvents(win))
527 needMore = TRUE;
528
529 node = node->Next();
530 }
531 return needMore ;
532 }
533
534 int wxApp::MainLoop()
535 {
536 gtk_main();
537 return 0;
538 }
539
540 void wxApp::ExitMainLoop()
541 {
542 if (gtk_main_level() > 0)
543 gtk_main_quit();
544 }
545
546 bool wxApp::Initialized()
547 {
548 return m_initialized;
549 }
550
551 bool wxApp::Pending()
552 {
553 return (gtk_events_pending() > 0);
554 }
555
556 void wxApp::Dispatch()
557 {
558 gtk_main_iteration();
559 }
560
561 void wxApp::DeletePendingObjects()
562 {
563 wxNode *node = wxPendingDelete.First();
564 while (node)
565 {
566 wxObject *obj = (wxObject *)node->Data();
567
568 delete obj;
569
570 if (wxPendingDelete.Find(obj))
571 delete node;
572
573 node = wxPendingDelete.First();
574 }
575 }
576
577 bool wxApp::Initialize()
578 {
579 wxBuffer = new wxChar[BUFSIZ + 512];
580
581 wxClassInfo::InitializeClasses();
582
583 wxSystemSettings::Init();
584
585 #if wxUSE_INTL
586 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
587 #endif
588
589 // GL: I'm annoyed ... I don't know where to put this and I don't want to
590 // create a module for that as it's part of the core.
591 #if wxUSE_THREADS
592 wxPendingEvents = new wxList();
593 wxPendingEventsLocker = new wxCriticalSection();
594 #endif
595
596 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
597 wxTheColourDatabase->Initialize();
598
599 wxInitializeStockLists();
600 wxInitializeStockObjects();
601
602 #if wxUSE_WX_RESOURCES
603 wxInitializeResourceSystem();
604 #endif
605
606 wxModule::RegisterModules();
607 if (!wxModule::InitializeModules()) return FALSE;
608
609 return TRUE;
610 }
611
612 void wxApp::CleanUp()
613 {
614 wxModule::CleanUpModules();
615
616 #if wxUSE_WX_RESOURCES
617 wxCleanUpResourceSystem();
618 #endif
619
620 if (wxTheColourDatabase)
621 delete wxTheColourDatabase;
622
623 wxTheColourDatabase = (wxColourDatabase*) NULL;
624
625 wxDeleteStockObjects();
626
627 wxDeleteStockLists();
628
629 delete wxTheApp;
630 wxTheApp = (wxApp*) NULL;
631
632 // GL: I'm annoyed ... I don't know where to put this and I don't want to
633 // create a module for that as it's part of the core.
634 #if wxUSE_THREADS
635 delete wxPendingEvents;
636 delete wxPendingEventsLocker;
637 #endif
638
639 wxSystemSettings::Done();
640
641 delete[] wxBuffer;
642
643 wxClassInfo::CleanUpClasses();
644
645 // check for memory leaks
646 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
647 if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
648 {
649 wxLogDebug(wxT("There were memory leaks.\n"));
650 wxDebugContext::Dump();
651 wxDebugContext::PrintStatistics();
652 }
653 #endif // Debug
654
655 #if wxUSE_LOG
656 // do this as the very last thing because everything else can log messages
657 wxLog::DontCreateOnDemand();
658
659 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
660 if (oldLog)
661 delete oldLog;
662 #endif // wxUSE_LOG
663 }
664
665 //-----------------------------------------------------------------------------
666 // Access to the root window global
667 //-----------------------------------------------------------------------------
668
669 GtkWidget* wxGetRootWindow()
670 {
671 if (gs_RootWindow == NULL) {
672 gs_RootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
673 gtk_widget_realize( gs_RootWindow );
674 }
675 return gs_RootWindow;
676 }
677
678 //-----------------------------------------------------------------------------
679 // wxEntry
680 //-----------------------------------------------------------------------------
681
682
683 int wxEntryStart( int argc, char *argv[] )
684 {
685 #if wxUSE_THREADS
686 /* GTK 1.2 up to version 1.2.3 has broken threads */
687 if ((gtk_major_version == 1) &&
688 (gtk_minor_version == 2) &&
689 (gtk_micro_version < 4))
690 {
691 printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" );
692 }
693 else
694 {
695 g_thread_init(NULL);
696 }
697 #endif
698
699 gtk_set_locale();
700
701 // We should have the wxUSE_WCHAR_T test on the _outside_
702 #if wxUSE_WCHAR_T
703 #if defined(__WXGTK20__)
704 // gtk+ 2.0 supports Unicode through UTF-8 strings
705 wxConvCurrent = &wxConvUTF8;
706 #else
707 if (!wxOKlibc()) wxConvCurrent = &wxConvLocal;
708 #endif
709 #else
710 if (!wxOKlibc()) wxConvCurrent = (wxMBConv*) NULL;
711 #endif
712
713 gdk_threads_enter();
714
715 gtk_init( &argc, &argv );
716
717 wxSetDetectableAutoRepeat( TRUE );
718
719 if (!wxApp::Initialize())
720 {
721 gdk_threads_leave();
722 return -1;
723 }
724
725 return 0;
726 }
727
728
729 int wxEntryInitGui()
730 {
731 int retValue = 0;
732
733 if ( !wxTheApp->OnInitGui() )
734 retValue = -1;
735
736 wxGetRootWindow();
737
738 return retValue;
739 }
740
741
742 void wxEntryCleanup()
743 {
744 #if wxUSE_LOG
745 // flush the logged messages if any
746 wxLog *log = wxLog::GetActiveTarget();
747 if (log != NULL && log->HasPendingMessages())
748 log->Flush();
749
750 // continuing to use user defined log target is unsafe from now on because
751 // some resources may be already unavailable, so replace it by something
752 // more safe
753 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
754 if ( oldlog )
755 delete oldlog;
756 #endif // wxUSE_LOG
757
758 wxApp::CleanUp();
759
760 gdk_threads_leave();
761 }
762
763
764
765 int wxEntry( int argc, char *argv[] )
766 {
767 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
768 // This seems to be necessary since there are 'rogue'
769 // objects present at this point (perhaps global objects?)
770 // Setting a checkpoint will ignore them as far as the
771 // memory checking facility is concerned.
772 // Of course you may argue that memory allocated in globals should be
773 // checked, but this is a reasonable compromise.
774 wxDebugContext::SetCheckpoint();
775 #endif
776 int err = wxEntryStart(argc, argv);
777 if (err)
778 return err;
779
780 if (!wxTheApp)
781 {
782 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
783 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
784
785 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
786
787 wxObject *test_app = app_ini();
788
789 wxTheApp = (wxApp*) test_app;
790 }
791
792 wxCHECK_MSG( wxTheApp, -1, wxT("wxWindows error: no application object") );
793
794 wxTheApp->argc = argc;
795 #if wxUSE_UNICODE
796 wxTheApp->argv = new wxChar*[argc+1];
797 int mb_argc = 0;
798 while (mb_argc < argc)
799 {
800 wxTheApp->argv[mb_argc] = wxStrdup(wxConvLibc.cMB2WX(argv[mb_argc]));
801 mb_argc++;
802 }
803 wxTheApp->argv[mb_argc] = (wxChar *)NULL;
804 #else
805 wxTheApp->argv = argv;
806 #endif
807
808 wxString name(wxFileNameFromPath(argv[0]));
809 wxStripExtension( name );
810 wxTheApp->SetAppName( name );
811
812 int retValue;
813 retValue = wxEntryInitGui();
814
815 // Here frames insert themselves automatically into wxTopLevelWindows by
816 // getting created in OnInit().
817 if ( retValue == 0 )
818 {
819 if ( !wxTheApp->OnInit() )
820 retValue = -1;
821 }
822
823 if ( retValue == 0 )
824 {
825 /* delete pending toplevel windows (typically a single
826 dialog) so that, if there isn't any left, we don't
827 call OnRun() */
828 wxTheApp->DeletePendingObjects();
829
830 wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
831
832 if (wxTheApp->Initialized())
833 {
834 wxTheApp->OnRun();
835
836 wxWindow *topWindow = wxTheApp->GetTopWindow();
837 if (topWindow)
838 {
839 /* Forcibly delete the window. */
840 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
841 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
842 {
843 topWindow->Close( TRUE );
844 wxTheApp->DeletePendingObjects();
845 }
846 else
847 {
848 delete topWindow;
849 wxTheApp->SetTopWindow( (wxWindow*) NULL );
850 }
851 }
852
853 retValue = wxTheApp->OnExit();
854 }
855 }
856
857 wxEntryCleanup();
858
859 return retValue;
860 }
861
862 #ifndef __WXUNIVERSAL__
863
864 #include "wx/gtk/info.xpm"
865 #include "wx/gtk/error.xpm"
866 #include "wx/gtk/question.xpm"
867 #include "wx/gtk/warning.xpm"
868
869 wxIcon wxApp::GetStdIcon(int which) const
870 {
871 switch(which)
872 {
873 case wxICON_INFORMATION:
874 return wxIcon(info_xpm);
875
876 case wxICON_QUESTION:
877 return wxIcon(question_xpm);
878
879 case wxICON_EXCLAMATION:
880 return wxIcon(warning_xpm);
881
882 default:
883 wxFAIL_MSG(wxT("requested non existent standard icon"));
884 // still fall through
885
886 case wxICON_HAND:
887 return wxIcon(error_xpm);
888 }
889 }
890 #else
891 wxIcon wxApp::GetStdIcon(int which) const
892 {
893 return wxTheme::Get()->GetRenderer()->GetStdIcon(which);
894 }
895 #endif // !__WXUNIVERSAL__
896
897
898 #ifdef __WXDEBUG__
899
900 void wxApp::OnAssert(const wxChar *file, int line, const wxChar *msg)
901 {
902 m_isInAssert = TRUE;
903
904 wxAppBase::OnAssert(file, line, msg);
905
906 m_isInAssert = FALSE;
907 }
908
909 #endif // __WXDEBUG__
910