missing extern "C" added to fix linking problems with some GTK+ versions
[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 #include "wx/gtk/win_gtk.h"
37
38 #include <gtk/gtk.h>
39
40
41 //-----------------------------------------------------------------------------
42 // global data
43 //-----------------------------------------------------------------------------
44
45 wxApp *wxTheApp = (wxApp *) NULL;
46 wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
47
48 extern bool g_isIdle;
49
50 bool g_mainThreadLocked = FALSE;
51 gint g_pendingTag = 0;
52
53 static GtkWidget *gs_RootWindow = (GtkWidget*) NULL;
54
55 //-----------------------------------------------------------------------------
56 // local functions
57 //-----------------------------------------------------------------------------
58
59 /* forward declaration */
60 gint wxapp_idle_callback( gpointer WXUNUSED(data) );
61 gint wxapp_pending_callback( gpointer WXUNUSED(data) );
62 void wxapp_install_idle_handler();
63
64 #if wxUSE_THREADS
65 gint wxapp_wakeup_timerout_callback( gpointer WXUNUSED(data) );
66 #endif
67
68 //-----------------------------------------------------------------------------
69 // wxExit
70 //-----------------------------------------------------------------------------
71
72 void wxExit()
73 {
74 gtk_main_quit();
75 }
76
77 //-----------------------------------------------------------------------------
78 // wxYield
79 //-----------------------------------------------------------------------------
80
81 static bool gs_inYield = FALSE;
82
83 bool wxYield()
84 {
85 #if wxUSE_THREADS
86 if ( !wxThread::IsMain() )
87 {
88 // can't call gtk_main_iteration() from other threads like this
89 return TRUE;
90 }
91 #endif // wxUSE_THREADS
92
93 #ifdef __WXDEBUG__
94 if (gs_inYield)
95 wxFAIL_MSG( wxT("wxYield called recursively" ) );
96 #endif
97
98 gs_inYield = TRUE;
99
100 if (!g_isIdle)
101 {
102 // We need to remove idle callbacks or the loop will
103 // never finish.
104 gtk_idle_remove( wxTheApp->m_idleTag );
105 wxTheApp->m_idleTag = 0;
106 g_isIdle = TRUE;
107 }
108
109 // disable log flushing from here because a call to wxYield() shouldn't
110 // normally result in message boxes popping up &c
111 wxLog::Suspend();
112
113 while (gtk_events_pending())
114 gtk_main_iteration();
115
116 /* it's necessary to call ProcessIdle() to update the frames sizes which
117 might have been changed (it also will update other things set from
118 OnUpdateUI() which is a nice (and desired) side effect) */
119 while (wxTheApp->ProcessIdle()) { }
120
121 // let the logs be flashed again
122 wxLog::Resume();
123
124 gs_inYield = FALSE;
125
126 return TRUE;
127 }
128
129 //-----------------------------------------------------------------------------
130 // wxYieldIfNeeded
131 // Like wxYield, but fails silently if the yield is recursive.
132 //-----------------------------------------------------------------------------
133
134 bool wxYieldIfNeeded()
135 {
136 if (gs_inYield)
137 return FALSE;
138
139 return wxYield();
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 #include "wx/gtk/info.xpm"
863 #include "wx/gtk/error.xpm"
864 #include "wx/gtk/question.xpm"
865 #include "wx/gtk/warning.xpm"
866
867 wxIcon
868 wxApp::GetStdIcon(int which) const
869 {
870 switch(which)
871 {
872 case wxICON_INFORMATION:
873 return wxIcon(info_xpm);
874
875 case wxICON_QUESTION:
876 return wxIcon(question_xpm);
877
878 case wxICON_EXCLAMATION:
879 return wxIcon(warning_xpm);
880
881 default:
882 wxFAIL_MSG(wxT("requested non existent standard icon"));
883 // still fall through
884
885 case wxICON_HAND:
886 return wxIcon(error_xpm);
887 }
888 }
889
890 #ifdef __WXDEBUG__
891
892 void wxApp::OnAssert(const wxChar *file, int line, const wxChar *msg)
893 {
894 m_isInAssert = TRUE;
895
896 wxAppBase::OnAssert(file, line, msg);
897
898 m_isInAssert = FALSE;
899 }
900
901 #endif // __WXDEBUG__
902