]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/app.cpp
e399efa119ee5ea0e3a61c461a2a9b78b679a9aa
[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 wxResourceCache *wxTheResourceCache;
51 extern bool g_isIdle;
52
53 unsigned char g_palette[64*3] =
54 {
55 0x0, 0x0, 0x0,
56 0xff, 0xff, 0xff,
57 0xff, 0x0, 0x0,
58 0xff, 0xff, 0x0,
59 0x0, 0xff, 0x0,
60 0x0, 0x0, 0xff,
61 0x0, 0xff, 0xff,
62 0x99, 0x99, 0x99,
63 0xff, 0x88, 0x0,
64 0x88, 0x0, 0x0,
65 0x0, 0x88, 0x88,
66 0x88, 0x88, 0x0,
67 0xff, 0xcc, 0x97,
68 0xbb, 0xbb, 0xbb,
69 0x9f, 0x6b, 0x42,
70 0x55, 0x55, 0x55,
71 0xdd, 0xdd, 0xdd,
72 0x77, 0x77, 0x77,
73 0x33, 0x33, 0x33,
74 0xcc, 0x0, 0x0,
75 0xff, 0x44, 0x0,
76 0xff, 0xcc, 0x0,
77 0xcc, 0xcc, 0x0,
78 0x60, 0x60, 0x0,
79 0x0, 0x43, 0x0,
80 0x0, 0x7f, 0x0,
81 0x0, 0xcc, 0x0,
82 0x0, 0x44, 0x44,
83 0x0, 0x0, 0x44,
84 0x0, 0x0, 0x88,
85 0xef, 0xb1, 0x7b,
86 0xdf, 0x98, 0x5f,
87 0xbf, 0x87, 0x56,
88 0x7f, 0x57, 0x26,
89 0x5f, 0x39, 0xc,
90 0x3f, 0x1c, 0x0,
91 0x21, 0x0, 0x0,
92 0x0, 0x43, 0x87,
93 0x2d, 0x70, 0xaf,
94 0x5a, 0x9e, 0xd7,
95 0x87, 0xcc, 0xff,
96 0xff, 0xe0, 0xba,
97 0x21, 0x43, 0xf,
98 0x3d, 0x5d, 0x25,
99 0x59, 0x78, 0x3a,
100 0x75, 0x93, 0x4f,
101 0x91, 0xae, 0x64,
102 0xad, 0xc8, 0x7a,
103 0xf0, 0xa8, 0xef,
104 0xd0, 0x88, 0xd0,
105 0xaf, 0x66, 0xaf,
106 0x8e, 0x44, 0x8e,
107 0x6d, 0x22, 0x6d,
108 0x4b, 0x0, 0x4b,
109 0xff, 0xc0, 0xbc,
110 0xff, 0x93, 0x91,
111 0xff, 0x66, 0x67,
112 0xd8, 0xf2, 0xbf,
113 0xff, 0xc9, 0x68,
114 0xff, 0x96, 0x67,
115 0xa5, 0x60, 0xff,
116 0x51, 0xff, 0x99,
117 0x3f, 0xa5, 0x63,
118 0x98, 0x90, 0x67
119 };
120
121 //-----------------------------------------------------------------------------
122 // local functions
123 //-----------------------------------------------------------------------------
124
125 extern void wxFlushResources();
126
127 /* forward declaration */
128 gint wxapp_idle_callback( gpointer WXUNUSED(data) );
129 void wxapp_install_idle_handler();
130
131 #if wxUSE_THREADS
132 gint wxapp_wakeup_timerout_callback( gpointer WXUNUSED(data) );
133 #endif
134
135 //-----------------------------------------------------------------------------
136 // wxExit
137 //-----------------------------------------------------------------------------
138
139 void wxExit()
140 {
141 gtk_main_quit();
142 }
143
144 //-----------------------------------------------------------------------------
145 // wxYield
146 //-----------------------------------------------------------------------------
147
148 bool wxYield()
149 {
150 bool has_idle = (wxTheApp->m_idleTag != 0);
151
152 if (has_idle)
153 {
154 /* We need to temporarily remove idle callbacks or the loop will
155 never finish. */
156 gtk_idle_remove( wxTheApp->m_idleTag );
157 wxTheApp->m_idleTag = 0;
158 }
159
160 while (gtk_events_pending())
161 gtk_main_iteration();
162
163 /* it's necessary to call ProcessIdle() to update the frames sizes which
164 might have been changed (it also will update other things set from
165 OnUpdateUI() which is a nice (and desired) side effect) */
166 while (wxTheApp->ProcessIdle()) { }
167
168 if (has_idle)
169 {
170 /* re-add idle handler */
171 wxTheApp->m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
172 }
173
174 return TRUE;
175 }
176
177 //-----------------------------------------------------------------------------
178 // wxWakeUpIdle
179 //-----------------------------------------------------------------------------
180
181 void wxWakeUpIdle()
182 {
183 if (g_isIdle)
184 wxapp_install_idle_handler();
185 }
186
187 //-----------------------------------------------------------------------------
188 // local functions
189 //-----------------------------------------------------------------------------
190
191 gint wxapp_idle_callback( gpointer WXUNUSED(data) )
192 {
193 if (!wxTheApp) return TRUE;
194
195 #if (GTK_MINOR_VERSION > 0)
196 /* when getting called from GDK's idle handler we
197 are no longer within GDK's grab on the GUI
198 thread so we must lock it here ourselves */
199 GDK_THREADS_ENTER ();
200 #endif
201
202 /* sent idle event to all who request them */
203 while (wxTheApp->ProcessIdle()) { }
204
205 /* we don't want any more idle events until the next event is
206 sent to wxGTK */
207 gtk_idle_remove( wxTheApp->m_idleTag );
208 wxTheApp->m_idleTag = 0;
209
210 /* indicate that we are now in idle mode - even so deeply
211 in idle mode that we don't get any idle events anymore.
212 this is like wxMSW where an idle event is sent only
213 once each time after the event queue has been completely
214 emptied */
215 g_isIdle = TRUE;
216
217 #if (GTK_MINOR_VERSION > 0)
218 /* release lock again */
219 GDK_THREADS_LEAVE ();
220 #endif
221
222 return TRUE;
223 }
224
225 void wxapp_install_idle_handler()
226 {
227 wxASSERT_MSG( wxTheApp->m_idleTag == 0, wxT("attempt to install idle handler twice") );
228
229 /* This routine gets called by all event handlers
230 indicating that the idle is over. It may also
231 get called from other thread for sending events
232 to the main thread (and processing these in
233 idle time). */
234
235 #if wxUSE_THREADS
236 if (!wxThread::IsMain())
237 GDK_THREADS_ENTER ();
238 #endif
239
240 wxTheApp->m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
241
242 g_isIdle = FALSE;
243
244 #if wxUSE_THREADS
245 if (!wxThread::IsMain())
246 GDK_THREADS_LEAVE ();
247 #endif
248 }
249
250 #if wxUSE_THREADS
251
252 void wxapp_install_thread_wakeup()
253 {
254 if (wxTheApp->m_wakeUpTimerTag) return;
255
256 wxTheApp->m_wakeUpTimerTag = gtk_timeout_add( 100, wxapp_wakeup_timerout_callback, (gpointer) NULL );
257 }
258
259 void wxapp_uninstall_thread_wakeup()
260 {
261 if (!wxTheApp->m_wakeUpTimerTag) return;
262
263 gtk_timeout_remove( wxTheApp->m_wakeUpTimerTag );
264 wxTheApp->m_wakeUpTimerTag = 0;
265 }
266
267 gint wxapp_wakeup_timerout_callback( gpointer WXUNUSED(data) )
268 {
269 wxapp_uninstall_thread_wakeup();
270
271 #if (GTK_MINOR_VERSION > 0)
272 // when getting called from GDK's time-out handler
273 // we are no longer within GDK's grab on the GUI
274 // thread so we must lock it here ourselves
275 GDK_THREADS_ENTER ();
276 #endif
277
278 // unblock other threads wishing to do some GUI things
279 wxMutexGuiLeave();
280
281 // wake up other threads
282 wxUsleep( 1 );
283
284 // block other thread again
285 wxMutexGuiEnter();
286
287 #if (GTK_MINOR_VERSION > 0)
288 // release lock again
289 GDK_THREADS_LEAVE ();
290 #endif
291
292 wxapp_install_thread_wakeup();
293
294 return TRUE;
295 }
296
297 #endif // wxUSE_THREADS
298
299 //-----------------------------------------------------------------------------
300 // wxApp
301 //-----------------------------------------------------------------------------
302
303 IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
304
305 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
306 EVT_IDLE(wxApp::OnIdle)
307 END_EVENT_TABLE()
308
309 wxApp::wxApp()
310 {
311 wxTheApp = this;
312
313 m_topWindow = (wxWindow *) NULL;
314 m_exitOnFrameDelete = TRUE;
315
316 m_idleTag = gtk_idle_add( wxapp_idle_callback, (gpointer) NULL );
317
318 #if wxUSE_THREADS
319 m_wakeUpTimerTag = 0;
320 wxapp_install_thread_wakeup();
321 #endif
322
323 m_colorCube = (unsigned char*) NULL;
324 }
325
326 wxApp::~wxApp()
327 {
328 if (m_idleTag) gtk_idle_remove( m_idleTag );
329
330 #if wxUSE_THREADS
331 wxapp_uninstall_thread_wakeup();
332 #endif
333
334 if (m_colorCube) free(m_colorCube);
335 }
336
337 bool wxApp::OnInitGui()
338 {
339 GdkVisual *visual = gdk_visual_get_system();
340
341 /* on some machines, the default visual is just 256 colours, so
342 we make sure we get the best. this can sometimes be wasteful,
343 of course, but what do these guys pay $30.000 for? */
344 /*
345 if (gdk_visual_get_best() != gdk_visual_get_system())
346 {
347 GdkVisual* vis = gdk_visual_get_best();
348 gtk_widget_set_default_visual( vis );
349
350 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
351 gtk_widget_set_default_colormap( colormap );
352
353 visual = vis;
354 }
355 */
356
357 /* Nothing to do for 15, 16, 24, 32 bit displays */
358 if (visual->depth > 8) return TRUE;
359
360 /* this initiates the standard palette as defined by GdkImlib
361 in the GNOME libraries. it ensures that all GNOME applications
362 use the same 64 colormap entries on 8-bit displays so you
363 can use several rather graphics-heavy applications at the
364 same time.
365 NOTE: this doesn't really seem to work this way... */
366
367 /*
368 GdkColormap *cmap = gdk_colormap_new( gdk_visual_get_system(), TRUE );
369
370 for (int i = 0; i < 64; i++)
371 {
372 GdkColor col;
373 col.red = g_palette[i*3 + 0] << 8;
374 col.green = g_palette[i*3 + 1] << 8;
375 col.blue = g_palette[i*3 + 2] << 8;
376 col.pixel = 0;
377
378 gdk_color_alloc( cmap, &col );
379 }
380
381 gtk_widget_set_default_colormap( cmap );
382 */
383
384 /* initialize color cube for 8-bit color reduction dithering */
385
386 GdkColormap *cmap = gtk_widget_get_default_colormap();
387
388 m_colorCube = (unsigned char*)malloc(32 * 32 * 32);
389
390 for (int r = 0; r < 32; r++)
391 {
392 for (int g = 0; g < 32; g++)
393 {
394 for (int b = 0; b < 32; b++)
395 {
396 int rr = (r << 3) | (r >> 2);
397 int gg = (g << 3) | (g >> 2);
398 int bb = (b << 3) | (b >> 2);
399
400 int index = -1;
401
402 GdkColor *colors = cmap->colors;
403 if (colors)
404 {
405 int max = 3 * 65536;
406
407 for (int i = 0; i < cmap->size; i++)
408 {
409 int rdiff = ((rr << 8) - colors[i].red);
410 int gdiff = ((gg << 8) - colors[i].green);
411 int bdiff = ((bb << 8) - colors[i].blue);
412 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
413 if (sum < max)
414 {
415 index = i; max = sum;
416 }
417 }
418 }
419 else
420 {
421 #if (GTK_MINOR_VERSION > 0)
422 /* assume 8-bit true or static colors. this really
423 exists. */
424 GdkVisual* vis = gdk_colormap_get_visual( cmap );
425 index = (r >> (5 - vis->red_prec)) << vis->red_shift;
426 index |= (g >> (5 - vis->green_prec)) << vis->green_shift;
427 index |= (b >> (5 - vis->blue_prec)) << vis->blue_shift;
428 #else
429 wxFAIL_MSG( wxT("Unsupported graphics hardware") );
430 #endif
431 }
432 m_colorCube[ (r*1024) + (g*32) + b ] = index;
433 }
434 }
435 }
436
437 return TRUE;
438 }
439
440 bool wxApp::ProcessIdle()
441 {
442 wxIdleEvent event;
443 event.SetEventObject( this );
444 ProcessEvent( event );
445
446 return event.MoreRequested();
447 }
448
449 void wxApp::OnIdle( wxIdleEvent &event )
450 {
451 static bool s_inOnIdle = FALSE;
452
453 /* Avoid recursion (via ProcessEvent default case) */
454 if (s_inOnIdle)
455 return;
456
457 s_inOnIdle = TRUE;
458
459 /* Resend in the main thread events which have been prepared in other
460 threads */
461 ProcessPendingEvents();
462
463 /* 'Garbage' collection of windows deleted with Close(). */
464 DeletePendingObjects();
465
466 /* flush the logged messages if any */
467 #if wxUSE_LOG
468 wxLog *log = wxLog::GetActiveTarget();
469 if (log != NULL && log->HasPendingMessages())
470 log->Flush();
471 #endif // wxUSE_LOG
472
473 /* Send OnIdle events to all windows */
474 bool needMore = SendIdleEvents();
475
476 if (needMore)
477 event.RequestMore(TRUE);
478
479 s_inOnIdle = FALSE;
480 }
481
482 bool wxApp::SendIdleEvents()
483 {
484 bool needMore = FALSE;
485
486 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
487 while (node)
488 {
489 wxWindow* win = node->GetData();
490 if (SendIdleEvents(win))
491 needMore = TRUE;
492 node = node->GetNext();
493 }
494
495 return needMore;
496 }
497
498 bool wxApp::SendIdleEvents( wxWindow* win )
499 {
500 bool needMore = FALSE;
501
502 wxIdleEvent event;
503 event.SetEventObject(win);
504
505 win->ProcessEvent(event);
506
507 win->OnInternalIdle();
508
509 if (event.MoreRequested())
510 needMore = TRUE;
511
512 wxNode* node = win->GetChildren().First();
513 while (node)
514 {
515 wxWindow* win = (wxWindow*) node->Data();
516 if (SendIdleEvents(win))
517 needMore = TRUE;
518
519 node = node->Next();
520 }
521 return needMore ;
522 }
523
524 int wxApp::MainLoop()
525 {
526 gtk_main();
527 return 0;
528 }
529
530 void wxApp::ExitMainLoop()
531 {
532 gtk_main_quit();
533 }
534
535 bool wxApp::Initialized()
536 {
537 return m_initialized;
538 }
539
540 bool wxApp::Pending()
541 {
542 return (gtk_events_pending() > 0);
543 }
544
545 void wxApp::Dispatch()
546 {
547 gtk_main_iteration();
548 }
549
550 void wxApp::DeletePendingObjects()
551 {
552 wxNode *node = wxPendingDelete.First();
553 while (node)
554 {
555 wxObject *obj = (wxObject *)node->Data();
556
557 delete obj;
558
559 if (wxPendingDelete.Find(obj))
560 delete node;
561
562 node = wxPendingDelete.First();
563 }
564 }
565
566 bool wxApp::Initialize()
567 {
568 wxBuffer = new wxChar[BUFSIZ + 512];
569
570 wxClassInfo::InitializeClasses();
571
572 wxSystemSettings::Init();
573
574 // GL: I'm annoyed ... I don't know where to put this and I don't want to
575 // create a module for that as it's part of the core.
576 #if wxUSE_THREADS
577 wxPendingEvents = new wxList();
578 wxPendingEventsLocker = new wxCriticalSection();
579 #endif
580
581 /*
582 wxTheFontNameDirectory = new wxFontNameDirectory;
583 wxTheFontNameDirectory->Initialize();
584 */
585
586 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
587 wxTheColourDatabase->Initialize();
588
589 wxInitializeStockLists();
590 wxInitializeStockObjects();
591
592 #if wxUSE_WX_RESOURCES
593 wxTheResourceCache = new wxResourceCache( wxKEY_STRING );
594
595 wxInitializeResourceSystem();
596 #endif
597
598 wxModule::RegisterModules();
599 if (!wxModule::InitializeModules()) return FALSE;
600
601 return TRUE;
602 }
603
604 void wxApp::CleanUp()
605 {
606 wxModule::CleanUpModules();
607
608 #if wxUSE_WX_RESOURCES
609 wxFlushResources();
610
611 if (wxTheResourceCache)
612 delete wxTheResourceCache;
613 wxTheResourceCache = (wxResourceCache*) NULL;
614
615 wxCleanUpResourceSystem();
616 #endif
617
618 if (wxTheColourDatabase)
619 delete wxTheColourDatabase;
620 wxTheColourDatabase = (wxColourDatabase*) NULL;
621
622 /*
623 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
624 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
625 */
626
627 wxDeleteStockObjects();
628
629 wxDeleteStockLists();
630
631 delete wxTheApp;
632 wxTheApp = (wxApp*) NULL;
633
634 // GL: I'm annoyed ... I don't know where to put this and I don't want to
635 // create a module for that as it's part of the core.
636 #if wxUSE_THREADS
637 delete wxPendingEvents;
638 delete wxPendingEventsLocker;
639 #endif
640
641 wxSystemSettings::Done();
642
643 delete[] wxBuffer;
644
645 wxClassInfo::CleanUpClasses();
646
647 // check for memory leaks
648 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
649 if (wxDebugContext::CountObjectsLeft() > 0)
650 {
651 wxLogDebug(wxT("There were memory leaks.\n"));
652 wxDebugContext::Dump();
653 wxDebugContext::PrintStatistics();
654 }
655 #endif // Debug
656
657 #if wxUSE_LOG
658 // do this as the very last thing because everything else can log messages
659 wxLog::DontCreateOnDemand();
660
661 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
662 if (oldLog)
663 delete oldLog;
664 #endif // wxUSE_LOG
665 }
666
667 //-----------------------------------------------------------------------------
668 // wxEntry
669 //-----------------------------------------------------------------------------
670
671 int wxEntry( int argc, char *argv[] )
672 {
673 gtk_set_locale();
674
675 #if wxUSE_WCHAR_T
676 if (!wxOKlibc()) wxConvCurrent = &wxConvLocal;
677 #else
678 if (!wxOKlibc()) wxConvCurrent = (wxMBConv*) NULL;
679 #endif
680
681 gtk_init( &argc, &argv );
682
683 wxSetDetectableAutoRepeat( TRUE );
684
685 if (!wxApp::Initialize())
686 return -1;
687
688 if (!wxTheApp)
689 {
690 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
691 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
692
693 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
694
695 wxObject *test_app = app_ini();
696
697 wxTheApp = (wxApp*) test_app;
698 }
699
700 wxCHECK_MSG( wxTheApp, -1, wxT("wxWindows error: no application object") );
701
702 wxTheApp->argc = argc;
703 #if wxUSE_UNICODE
704 wxTheApp->argv = new wxChar*[argc+1];
705 int mb_argc = 0;
706 while (mb_argc < argc) {
707 wxTheApp->argv[mb_argc] = wxStrdup(wxConvLibc.cMB2WX(argv[mb_argc]));
708 mb_argc++;
709 }
710 wxTheApp->argv[mb_argc] = (wxChar *)NULL;
711 #else
712 wxTheApp->argv = argv;
713 #endif
714
715 wxString name(wxFileNameFromPath(argv[0]));
716 wxStripExtension( name );
717 wxTheApp->SetAppName( name );
718
719 int retValue = 0;
720
721 if ( !wxTheApp->OnInitGui() )
722 retValue = -1;
723
724 // Here frames insert themselves automatically into wxTopLevelWindows by
725 // getting created in OnInit().
726 if ( retValue == 0 )
727 {
728 if ( !wxTheApp->OnInit() )
729 retValue = -1;
730 }
731
732 if ( retValue == 0 )
733 {
734 /* delete pending toplevel windows (typically a single
735 dialog) so that, if there isn't any left, we don't
736 call OnRun() */
737 wxTheApp->DeletePendingObjects();
738
739 wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
740
741 if (wxTheApp->Initialized())
742 {
743 retValue = wxTheApp->OnRun();
744
745 wxWindow *topWindow = wxTheApp->GetTopWindow();
746 if (topWindow)
747 {
748 /* Forcibly delete the window. */
749 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
750 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
751 {
752 topWindow->Close( TRUE );
753 wxTheApp->DeletePendingObjects();
754 }
755 else
756 {
757 delete topWindow;
758 wxTheApp->SetTopWindow( (wxWindow*) NULL );
759 }
760 }
761 wxTheApp->OnExit();
762 }
763 }
764
765 #if wxUSE_LOG
766 // flush the logged messages if any
767 wxLog *log = wxLog::GetActiveTarget();
768 if (log != NULL && log->HasPendingMessages())
769 log->Flush();
770
771 // continuing to use user defined log target is unsafe from now on because
772 // some resources may be already unavailable, so replace it by something
773 // more safe
774 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
775 if ( oldlog )
776 delete oldlog;
777 #endif // wxUSE_LOG
778
779 wxApp::CleanUp();
780
781 return retValue;
782 }
783
784 #include "wx/gtk/info.xpm"
785 #include "wx/gtk/error.xpm"
786 #include "wx/gtk/question.xpm"
787 #include "wx/gtk/warning.xpm"
788
789 wxIcon
790 wxApp::GetStdIcon(int which) const
791 {
792 switch(which)
793 {
794 case wxICON_INFORMATION:
795 return wxIcon(info_xpm);
796
797 case wxICON_QUESTION:
798 return wxIcon(question_xpm);
799
800 case wxICON_EXCLAMATION:
801 return wxIcon(warning_xpm);
802
803 default:
804 wxFAIL_MSG(wxT("requested non existent standard icon"));
805 // still fall through
806
807 case wxICON_HAND:
808 return wxIcon(error_xpm);
809 }
810 }