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