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