a4beb03e4ad8943cd8a6b471f11a7726bbb19685
[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, _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 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 wxImage::InitStandardHandlers();
591
592 wxModule::RegisterModules();
593 if (!wxModule::InitializeModules()) return FALSE;
594
595 return TRUE;
596 }
597
598 void wxApp::CleanUp()
599 {
600 wxModule::CleanUpModules();
601
602 #if wxUSE_WX_RESOURCES
603 wxFlushResources();
604
605 if (wxTheResourceCache)
606 delete wxTheResourceCache;
607 wxTheResourceCache = (wxResourceCache*) NULL;
608
609 wxCleanUpResourceSystem();
610 #endif
611
612 if (wxTheColourDatabase)
613 delete wxTheColourDatabase;
614 wxTheColourDatabase = (wxColourDatabase*) NULL;
615
616 /*
617 if (wxTheFontNameDirectory) delete wxTheFontNameDirectory;
618 wxTheFontNameDirectory = (wxFontNameDirectory*) NULL;
619 */
620
621 wxDeleteStockObjects();
622
623 wxDeleteStockLists();
624
625 wxImage::CleanUpHandlers();
626
627 delete wxTheApp;
628 wxTheApp = (wxApp*) NULL;
629
630 // GL: I'm annoyed ... I don't know where to put this and I don't want to
631 // create a module for that as it's part of the core.
632 #if wxUSE_THREADS
633 delete wxPendingEvents;
634 delete wxPendingEventsLocker;
635 #endif
636
637 wxSystemSettings::Done();
638
639 delete[] wxBuffer;
640
641 wxClassInfo::CleanUpClasses();
642
643 // check for memory leaks
644 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
645 if (wxDebugContext::CountObjectsLeft() > 0)
646 {
647 wxLogDebug(_T("There were memory leaks.\n"));
648 wxDebugContext::Dump();
649 wxDebugContext::PrintStatistics();
650 }
651 #endif // Debug
652
653 #if wxUSE_LOG
654 // do this as the very last thing because everything else can log messages
655 wxLog::DontCreateOnDemand();
656
657 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
658 if (oldLog)
659 delete oldLog;
660 }
661
662 #endif // wxUSE_LOG
663
664 //-----------------------------------------------------------------------------
665 // wxEntry
666 //-----------------------------------------------------------------------------
667
668 int wxEntry( int argc, char *argv[] )
669 {
670 gtk_set_locale();
671
672 #if wxUSE_WCHAR_T
673 if (!wxOKlibc()) wxConvCurrent = &wxConvLocal;
674 #else
675 if (!wxOKlibc()) wxConvCurrent = (wxMBConv*) NULL;
676 #endif
677
678 gtk_init( &argc, &argv );
679
680 wxSetDetectableAutoRepeat( TRUE );
681
682 if (!wxApp::Initialize())
683 return -1;
684
685 if (!wxTheApp)
686 {
687 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
688 _T("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
689
690 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
691
692 wxObject *test_app = app_ini();
693
694 wxTheApp = (wxApp*) test_app;
695 }
696
697 wxCHECK_MSG( wxTheApp, -1, _T("wxWindows error: no application object") );
698
699 wxTheApp->argc = argc;
700 #if wxUSE_UNICODE
701 wxTheApp->argv = new wxChar*[argc+1];
702 int mb_argc = 0;
703 while (mb_argc < argc) {
704 wxTheApp->argv[mb_argc] = wxStrdup(wxConvLibc.cMB2WX(argv[mb_argc]));
705 mb_argc++;
706 }
707 wxTheApp->argv[mb_argc] = (wxChar *)NULL;
708 #else
709 wxTheApp->argv = argv;
710 #endif
711
712 wxString name(wxFileNameFromPath(argv[0]));
713 wxStripExtension( name );
714 wxTheApp->SetAppName( name );
715
716 int retValue = 0;
717
718 if ( !wxTheApp->OnInitGui() )
719 retValue = -1;
720
721 // Here frames insert themselves automatically into wxTopLevelWindows by
722 // getting created in OnInit().
723 if ( retValue == 0 )
724 {
725 if ( !wxTheApp->OnInit() )
726 retValue = -1;
727 }
728
729 if ( retValue == 0 )
730 {
731 /* delete pending toplevel windows (typically a single
732 dialog) so that, if there isn't any left, we don't
733 call OnRun() */
734 wxTheApp->DeletePendingObjects();
735
736 wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
737
738 if (wxTheApp->Initialized())
739 {
740 retValue = wxTheApp->OnRun();
741
742 wxWindow *topWindow = wxTheApp->GetTopWindow();
743 if (topWindow)
744 {
745 /* Forcibly delete the window. */
746 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
747 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
748 {
749 topWindow->Close( TRUE );
750 wxTheApp->DeletePendingObjects();
751 }
752 else
753 {
754 delete topWindow;
755 wxTheApp->SetTopWindow( (wxWindow*) NULL );
756 }
757 }
758 wxTheApp->OnExit();
759 }
760 }
761
762 #if wxUSE_LOG
763 // flush the logged messages if any
764 wxLog *log = wxLog::GetActiveTarget();
765 if (log != NULL && log->HasPendingMessages())
766 log->Flush();
767
768 // continuing to use user defined log target is unsafe from now on because
769 // some resources may be already unavailable, so replace it by something
770 // more safe
771 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
772 if ( oldlog )
773 delete oldlog;
774 #endif // wxUSE_LOG
775
776 wxApp::CleanUp();
777
778 return retValue;
779 }
780
781 #include "wx/gtk/info.xpm"
782 #include "wx/gtk/error.xpm"
783 #include "wx/gtk/question.xpm"
784 #include "wx/gtk/warning.xpm"
785
786 wxIcon
787 wxApp::GetStdIcon(int which) const
788 {
789 switch(which)
790 {
791 case wxICON_INFORMATION:
792 return wxIcon(info_xpm);
793
794 case wxICON_QUESTION:
795 return wxIcon(question_xpm);
796
797 case wxICON_EXCLAMATION:
798 return wxIcon(warning_xpm);
799
800 default:
801 wxFAIL_MSG(_T("requested non existent standard icon"));
802 // still fall through
803
804 case wxICON_HAND:
805 return wxIcon(error_xpm);
806 }
807 }