]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/app.cpp
use the new wxSystemSettings API everywhere
[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 #if wxUSE_INTL
584 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
585 #endif
586
587 // GL: I'm annoyed ... I don't know where to put this and I don't want to
588 // create a module for that as it's part of the core.
589 #if wxUSE_THREADS
590 wxPendingEvents = new wxList();
591 wxPendingEventsLocker = new wxCriticalSection();
592 #endif
593
594 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
595 wxTheColourDatabase->Initialize();
596
597 wxInitializeStockLists();
598 wxInitializeStockObjects();
599
600 #if wxUSE_WX_RESOURCES
601 wxInitializeResourceSystem();
602 #endif
603
604 wxModule::RegisterModules();
605 if (!wxModule::InitializeModules()) return FALSE;
606
607 return TRUE;
608 }
609
610 void wxApp::CleanUp()
611 {
612 wxModule::CleanUpModules();
613
614 #if wxUSE_WX_RESOURCES
615 wxCleanUpResourceSystem();
616 #endif
617
618 if (wxTheColourDatabase)
619 delete wxTheColourDatabase;
620
621 wxTheColourDatabase = (wxColourDatabase*) NULL;
622
623 wxDeleteStockObjects();
624
625 wxDeleteStockLists();
626
627 delete wxTheApp;
628 wxTheApp = (wxApp*) NULL;
629
630 // GL: I'm annoyed ... I don't know where to put this and I don't want to
631 // create a module for that as it's part of the core.
632 #if wxUSE_THREADS
633 delete wxPendingEvents;
634 delete wxPendingEventsLocker;
635 #endif
636
637 delete[] wxBuffer;
638
639 wxClassInfo::CleanUpClasses();
640
641 // check for memory leaks
642 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
643 if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
644 {
645 wxLogDebug(wxT("There were memory leaks.\n"));
646 wxDebugContext::Dump();
647 wxDebugContext::PrintStatistics();
648 }
649 #endif // Debug
650
651 #if wxUSE_LOG
652 // do this as the very last thing because everything else can log messages
653 wxLog::DontCreateOnDemand();
654
655 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
656 if (oldLog)
657 delete oldLog;
658 #endif // wxUSE_LOG
659 }
660
661 //-----------------------------------------------------------------------------
662 // Access to the root window global
663 //-----------------------------------------------------------------------------
664
665 GtkWidget* wxGetRootWindow()
666 {
667 if (gs_RootWindow == NULL) {
668 gs_RootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
669 gtk_widget_realize( gs_RootWindow );
670 }
671 return gs_RootWindow;
672 }
673
674 //-----------------------------------------------------------------------------
675 // wxEntry
676 //-----------------------------------------------------------------------------
677
678 // NB: argc and argv may be changed here, pass by reference!
679 int wxEntryStart( int& argc, char *argv[] )
680 {
681 #if wxUSE_THREADS
682 /* GTK 1.2 up to version 1.2.3 has broken threads */
683 if ((gtk_major_version == 1) &&
684 (gtk_minor_version == 2) &&
685 (gtk_micro_version < 4))
686 {
687 printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" );
688 }
689 else
690 {
691 g_thread_init(NULL);
692 }
693 #endif
694
695 gtk_set_locale();
696
697 // We should have the wxUSE_WCHAR_T test on the _outside_
698 #if wxUSE_WCHAR_T
699 #if defined(__WXGTK20__)
700 // gtk+ 2.0 supports Unicode through UTF-8 strings
701 wxConvCurrent = &wxConvUTF8;
702 #else
703 if (!wxOKlibc()) wxConvCurrent = &wxConvLocal;
704 #endif
705 #else
706 if (!wxOKlibc()) wxConvCurrent = (wxMBConv*) NULL;
707 #endif
708
709 gdk_threads_enter();
710
711 gtk_init( &argc, &argv );
712
713 wxSetDetectableAutoRepeat( TRUE );
714
715 if (!wxApp::Initialize())
716 {
717 gdk_threads_leave();
718 return -1;
719 }
720
721 return 0;
722 }
723
724
725 int wxEntryInitGui()
726 {
727 int retValue = 0;
728
729 if ( !wxTheApp->OnInitGui() )
730 retValue = -1;
731
732 wxGetRootWindow();
733
734 return retValue;
735 }
736
737
738 void wxEntryCleanup()
739 {
740 #if wxUSE_LOG
741 // flush the logged messages if any
742 wxLog *log = wxLog::GetActiveTarget();
743 if (log != NULL && log->HasPendingMessages())
744 log->Flush();
745
746 // continuing to use user defined log target is unsafe from now on because
747 // some resources may be already unavailable, so replace it by something
748 // more safe
749 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
750 if ( oldlog )
751 delete oldlog;
752 #endif // wxUSE_LOG
753
754 wxApp::CleanUp();
755
756 gdk_threads_leave();
757 }
758
759
760
761 int wxEntry( int argc, char *argv[] )
762 {
763 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
764 // This seems to be necessary since there are 'rogue'
765 // objects present at this point (perhaps global objects?)
766 // Setting a checkpoint will ignore them as far as the
767 // memory checking facility is concerned.
768 // Of course you may argue that memory allocated in globals should be
769 // checked, but this is a reasonable compromise.
770 wxDebugContext::SetCheckpoint();
771 #endif
772 int err = wxEntryStart(argc, argv);
773 if (err)
774 return err;
775
776 if (!wxTheApp)
777 {
778 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
779 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
780
781 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
782
783 wxObject *test_app = app_ini();
784
785 wxTheApp = (wxApp*) test_app;
786 }
787
788 wxCHECK_MSG( wxTheApp, -1, wxT("wxWindows error: no application object") );
789
790 wxTheApp->argc = argc;
791 #if wxUSE_UNICODE
792 wxTheApp->argv = new wxChar*[argc+1];
793 int mb_argc = 0;
794 while (mb_argc < argc)
795 {
796 wxTheApp->argv[mb_argc] = wxStrdup(wxConvLibc.cMB2WX(argv[mb_argc]));
797 mb_argc++;
798 }
799 wxTheApp->argv[mb_argc] = (wxChar *)NULL;
800 #else
801 wxTheApp->argv = argv;
802 #endif
803
804 wxString name(wxFileNameFromPath(argv[0]));
805 wxStripExtension( name );
806 wxTheApp->SetAppName( name );
807
808 int retValue;
809 retValue = wxEntryInitGui();
810
811 // Here frames insert themselves automatically into wxTopLevelWindows by
812 // getting created in OnInit().
813 if ( retValue == 0 )
814 {
815 if ( !wxTheApp->OnInit() )
816 retValue = -1;
817 }
818
819 if ( retValue == 0 )
820 {
821 /* delete pending toplevel windows (typically a single
822 dialog) so that, if there isn't any left, we don't
823 call OnRun() */
824 wxTheApp->DeletePendingObjects();
825
826 wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
827
828 if (wxTheApp->Initialized())
829 {
830 wxTheApp->OnRun();
831
832 wxWindow *topWindow = wxTheApp->GetTopWindow();
833 if (topWindow)
834 {
835 /* Forcibly delete the window. */
836 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
837 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
838 {
839 topWindow->Close( TRUE );
840 wxTheApp->DeletePendingObjects();
841 }
842 else
843 {
844 delete topWindow;
845 wxTheApp->SetTopWindow( (wxWindow*) NULL );
846 }
847 }
848
849 retValue = wxTheApp->OnExit();
850 }
851 }
852
853 wxEntryCleanup();
854
855 return retValue;
856 }
857
858 #ifndef __WXUNIVERSAL__
859
860 #include "wx/gtk/info.xpm"
861 #include "wx/gtk/error.xpm"
862 #include "wx/gtk/question.xpm"
863 #include "wx/gtk/warning.xpm"
864
865 wxIcon wxApp::GetStdIcon(int which) const
866 {
867 switch(which)
868 {
869 case wxICON_INFORMATION:
870 return wxIcon(info_xpm);
871
872 case wxICON_QUESTION:
873 return wxIcon(question_xpm);
874
875 case wxICON_EXCLAMATION:
876 return wxIcon(warning_xpm);
877
878 default:
879 wxFAIL_MSG(wxT("requested non existent standard icon"));
880 // still fall through
881
882 case wxICON_HAND:
883 return wxIcon(error_xpm);
884 }
885 }
886 #else
887 wxIcon wxApp::GetStdIcon(int which) const
888 {
889 return wxTheme::Get()->GetRenderer()->GetStdIcon(which);
890 }
891 #endif // !__WXUNIVERSAL__
892
893
894 #ifdef __WXDEBUG__
895
896 void wxApp::OnAssert(const wxChar *file, int line, const wxChar *msg)
897 {
898 m_isInAssert = TRUE;
899
900 wxAppBase::OnAssert(file, line, msg);
901
902 m_isInAssert = FALSE;
903 }
904
905 #endif // __WXDEBUG__
906