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