]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/app.cpp
don't draw with NULL font
[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 "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, wxT("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 // wxUSE_THREADS
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( wxT("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 return event.MoreRequested();
418 }
419
420 void wxApp::OnIdle( wxIdleEvent &event )
421 {
422 static bool s_inOnIdle = FALSE;
423
424 /* Avoid recursion (via ProcessEvent default case) */
425 if (s_inOnIdle)
426 return;
427
428 s_inOnIdle = TRUE;
429
430 #if wxUSE_THREADS
431 /* Resend in the main thread events which have been prepared in other
432 threads */
433 ProcessPendingEvents();
434 #endif
435
436 /* 'Garbage' collection of windows deleted with Close(). */
437 DeletePendingObjects();
438
439 /* flush the logged messages if any */
440 #if wxUSE_LOG
441 wxLog *log = wxLog::GetActiveTarget();
442 if (log != NULL && log->HasPendingMessages())
443 log->Flush();
444 #endif // wxUSE_LOG
445
446 /* Send OnIdle events to all windows */
447 bool needMore = SendIdleEvents();
448
449 if (needMore)
450 event.RequestMore(TRUE);
451
452 s_inOnIdle = FALSE;
453 }
454
455 bool wxApp::SendIdleEvents()
456 {
457 bool needMore = FALSE;
458
459 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
460 while (node)
461 {
462 wxWindow* win = node->GetData();
463 if (SendIdleEvents(win))
464 needMore = TRUE;
465 node = node->GetNext();
466 }
467
468 return needMore;
469 }
470
471 bool wxApp::SendIdleEvents( wxWindow* win )
472 {
473 bool needMore = FALSE;
474
475 wxIdleEvent event;
476 event.SetEventObject(win);
477
478 win->ProcessEvent(event);
479
480 win->OnInternalIdle();
481
482 if (event.MoreRequested())
483 needMore = TRUE;
484
485 wxNode* node = win->GetChildren().First();
486 while (node)
487 {
488 wxWindow* win = (wxWindow*) node->Data();
489 if (SendIdleEvents(win))
490 needMore = TRUE;
491
492 node = node->Next();
493 }
494 return needMore ;
495 }
496
497 int wxApp::MainLoop()
498 {
499 gtk_main();
500 return 0;
501 }
502
503 void wxApp::ExitMainLoop()
504 {
505 gtk_main_quit();
506 }
507
508 bool wxApp::Initialized()
509 {
510 return m_initialized;
511 }
512
513 bool wxApp::Pending()
514 {
515 return (gtk_events_pending() > 0);
516 }
517
518 void wxApp::Dispatch()
519 {
520 gtk_main_iteration();
521 }
522
523 #if wxUSE_THREADS
524 void wxApp::ProcessPendingEvents()
525 {
526 wxNode *node = wxPendingEvents->First();
527 wxCriticalSectionLocker locker(*wxPendingEventsLocker);
528
529 while (node)
530 {
531 wxEvtHandler *handler = (wxEvtHandler *)node->Data();
532
533 handler->ProcessPendingEvents();
534
535 delete node;
536
537 node = wxPendingEvents->First();
538 }
539 }
540 #endif // wxUSE_THREADS
541
542 void wxApp::DeletePendingObjects()
543 {
544 wxNode *node = wxPendingDelete.First();
545 while (node)
546 {
547 wxObject *obj = (wxObject *)node->Data();
548
549 delete obj;
550
551 if (wxPendingDelete.Find(obj))
552 delete node;
553
554 node = wxPendingDelete.First();
555 }
556 }
557
558 bool wxApp::Initialize()
559 {
560 wxBuffer = new wxChar[BUFSIZ + 512];
561
562 wxClassInfo::InitializeClasses();
563
564 wxSystemSettings::Init();
565
566 // GL: I'm annoyed ... I don't know where to put this and I don't want to
567 // create a module for that as it's part of the core.
568 #if wxUSE_THREADS
569 wxPendingEvents = new wxList();
570 wxPendingEventsLocker = new wxCriticalSection();
571 #endif
572
573 /*
574 wxTheFontNameDirectory = new wxFontNameDirectory;
575 wxTheFontNameDirectory->Initialize();
576 */
577
578 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
579 wxTheColourDatabase->Initialize();
580
581 wxInitializeStockLists();
582 wxInitializeStockObjects();
583
584 #if wxUSE_WX_RESOURCES
585 wxTheResourceCache = new wxResourceCache( wxKEY_STRING );
586
587 wxInitializeResourceSystem();
588 #endif
589
590 wxModule::RegisterModules();
591 if (!wxModule::InitializeModules()) return FALSE;
592
593 return TRUE;
594 }
595
596 void wxApp::CleanUp()
597 {
598 wxModule::CleanUpModules();
599
600 #if wxUSE_WX_RESOURCES
601 wxFlushResources();
602
603 if (wxTheResourceCache)
604 delete wxTheResourceCache;
605 wxTheResourceCache = (wxResourceCache*) NULL;
606
607 wxCleanUpResourceSystem();
608 #endif
609
610 if (wxTheColourDatabase)
611 delete wxTheColourDatabase;
612 wxTheColourDatabase = (wxColourDatabase*) NULL;
613
614 /*
615 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
616 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
617 */
618
619 wxDeleteStockObjects();
620
621 wxDeleteStockLists();
622
623 delete wxTheApp;
624 wxTheApp = (wxApp*) NULL;
625
626 // GL: I'm annoyed ... I don't know where to put this and I don't want to
627 // create a module for that as it's part of the core.
628 #if wxUSE_THREADS
629 delete wxPendingEvents;
630 delete wxPendingEventsLocker;
631 #endif
632
633 wxSystemSettings::Done();
634
635 delete[] wxBuffer;
636
637 wxClassInfo::CleanUpClasses();
638
639 // check for memory leaks
640 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
641 if (wxDebugContext::CountObjectsLeft() > 0)
642 {
643 wxLogDebug(wxT("There were memory leaks.\n"));
644 wxDebugContext::Dump();
645 wxDebugContext::PrintStatistics();
646 }
647 #endif // Debug
648
649 #if wxUSE_LOG
650 // do this as the very last thing because everything else can log messages
651 wxLog::DontCreateOnDemand();
652
653 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
654 if (oldLog)
655 delete oldLog;
656 #endif // wxUSE_LOG
657 }
658
659 //-----------------------------------------------------------------------------
660 // wxEntry
661 //-----------------------------------------------------------------------------
662
663 int wxEntry( int argc, char *argv[] )
664 {
665 gtk_set_locale();
666
667 #if wxUSE_WCHAR_T
668 if (!wxOKlibc()) wxConvCurrent = &wxConvLocal;
669 #else
670 if (!wxOKlibc()) wxConvCurrent = (wxMBConv*) NULL;
671 #endif
672
673 gtk_init( &argc, &argv );
674
675 wxSetDetectableAutoRepeat( TRUE );
676
677 if (!wxApp::Initialize())
678 return -1;
679
680 if (!wxTheApp)
681 {
682 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
683 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
684
685 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
686
687 wxObject *test_app = app_ini();
688
689 wxTheApp = (wxApp*) test_app;
690 }
691
692 wxCHECK_MSG( wxTheApp, -1, wxT("wxWindows error: no application object") );
693
694 wxTheApp->argc = argc;
695 #if wxUSE_UNICODE
696 wxTheApp->argv = new wxChar*[argc+1];
697 int mb_argc = 0;
698 while (mb_argc < argc) {
699 wxTheApp->argv[mb_argc] = wxStrdup(wxConvLibc.cMB2WX(argv[mb_argc]));
700 mb_argc++;
701 }
702 wxTheApp->argv[mb_argc] = (wxChar *)NULL;
703 #else
704 wxTheApp->argv = argv;
705 #endif
706
707 wxString name(wxFileNameFromPath(argv[0]));
708 wxStripExtension( name );
709 wxTheApp->SetAppName( name );
710
711 int retValue = 0;
712
713 if ( !wxTheApp->OnInitGui() )
714 retValue = -1;
715
716 // Here frames insert themselves automatically into wxTopLevelWindows by
717 // getting created in OnInit().
718 if ( retValue == 0 )
719 {
720 if ( !wxTheApp->OnInit() )
721 retValue = -1;
722 }
723
724 if ( retValue == 0 )
725 {
726 /* delete pending toplevel windows (typically a single
727 dialog) so that, if there isn't any left, we don't
728 call OnRun() */
729 wxTheApp->DeletePendingObjects();
730
731 wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
732
733 if (wxTheApp->Initialized())
734 {
735 retValue = wxTheApp->OnRun();
736
737 wxWindow *topWindow = wxTheApp->GetTopWindow();
738 if (topWindow)
739 {
740 /* Forcibly delete the window. */
741 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
742 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
743 {
744 topWindow->Close( TRUE );
745 wxTheApp->DeletePendingObjects();
746 }
747 else
748 {
749 delete topWindow;
750 wxTheApp->SetTopWindow( (wxWindow*) NULL );
751 }
752 }
753 wxTheApp->OnExit();
754 }
755 }
756
757 #if wxUSE_LOG
758 // flush the logged messages if any
759 wxLog *log = wxLog::GetActiveTarget();
760 if (log != NULL && log->HasPendingMessages())
761 log->Flush();
762
763 // continuing to use user defined log target is unsafe from now on because
764 // some resources may be already unavailable, so replace it by something
765 // more safe
766 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
767 if ( oldlog )
768 delete oldlog;
769 #endif // wxUSE_LOG
770
771 wxApp::CleanUp();
772
773 return retValue;
774 }
775
776 #include "wx/gtk/info.xpm"
777 #include "wx/gtk/error.xpm"
778 #include "wx/gtk/question.xpm"
779 #include "wx/gtk/warning.xpm"
780
781 wxIcon
782 wxApp::GetStdIcon(int which) const
783 {
784 switch(which)
785 {
786 case wxICON_INFORMATION:
787 return wxIcon(info_xpm);
788
789 case wxICON_QUESTION:
790 return wxIcon(question_xpm);
791
792 case wxICON_EXCLAMATION:
793 return wxIcon(warning_xpm);
794
795 default:
796 wxFAIL_MSG(wxT("requested non existent standard icon"));
797 // still fall through
798
799 case wxICON_HAND:
800 return wxIcon(error_xpm);
801 }
802 }