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