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