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