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