Some additions to the 12-bit patch.
[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 "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 #ifdef __WXUNIVERSAL__
32 #include "wx/univ/theme.h"
33 #include "wx/univ/renderer.h"
34 #endif
35
36 #if wxUSE_THREADS
37 #include "wx/thread.h"
38 #endif
39
40 #include <unistd.h>
41 #include "wx/gtk/win_gtk.h"
42
43 #include <gtk/gtk.h>
44
45
46 //-----------------------------------------------------------------------------
47 // global data
48 //-----------------------------------------------------------------------------
49
50 wxApp *wxTheApp = (wxApp *) NULL;
51 wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
52
53 extern bool g_isIdle;
54
55 bool g_mainThreadLocked = FALSE;
56 gint g_pendingTag = 0;
57
58 static GtkWidget *gs_RootWindow = (GtkWidget*) NULL;
59
60 //-----------------------------------------------------------------------------
61 // local functions
62 //-----------------------------------------------------------------------------
63
64 extern "C"
65 {
66 gint wxapp_idle_callback( gpointer WXUNUSED(data) );
67 gint wxapp_pending_callback( gpointer WXUNUSED(data) );
68 }
69
70 void wxapp_install_thread_wakeup();
71 void wxapp_uninstall_thread_wakeup();
72 void wxapp_install_idle_handler();
73
74 //-----------------------------------------------------------------------------
75 // wxExit
76 //-----------------------------------------------------------------------------
77
78 void wxExit()
79 {
80 gtk_main_quit();
81 }
82
83 //-----------------------------------------------------------------------------
84 // wxYield
85 //-----------------------------------------------------------------------------
86
87 bool wxApp::Yield(bool onlyIfNeeded)
88 {
89 // MT-FIXME
90 static bool s_inYield = FALSE;
91
92 if ( s_inYield )
93 {
94 if ( !onlyIfNeeded )
95 {
96 wxFAIL_MSG( wxT("wxYield called recursively" ) );
97 }
98
99 return FALSE;
100 }
101
102 #if wxUSE_THREADS
103 if ( !wxThread::IsMain() )
104 {
105 // can't call gtk_main_iteration() from other threads like this
106 return TRUE;
107 }
108 #endif // wxUSE_THREADS
109
110 s_inYield = TRUE;
111
112 if (!g_isIdle)
113 {
114 // We need to remove idle callbacks or the loop will
115 // never finish.
116 gtk_idle_remove( m_idleTag );
117 m_idleTag = 0;
118 g_isIdle = TRUE;
119 }
120
121 // disable log flushing from here because a call to wxYield() shouldn't
122 // normally result in message boxes popping up &c
123 wxLog::Suspend();
124
125 while (gtk_events_pending())
126 gtk_main_iteration();
127
128 /* it's necessary to call ProcessIdle() to update the frames sizes which
129 might have been changed (it also will update other things set from
130 OnUpdateUI() which is a nice (and desired) side effect) */
131 while ( ProcessIdle() )
132 {
133 }
134
135 // let the logs be flashed again
136 wxLog::Resume();
137
138 s_inYield = FALSE;
139
140 return TRUE;
141 }
142
143 //-----------------------------------------------------------------------------
144 // wxWakeUpIdle
145 //-----------------------------------------------------------------------------
146
147 void wxWakeUpIdle()
148 {
149 #if wxUSE_THREADS
150 if (!wxThread::IsMain())
151 wxMutexGuiEnter();
152 #endif
153
154 if (g_isIdle)
155 wxapp_install_idle_handler();
156
157 #if wxUSE_THREADS
158 if (!wxThread::IsMain())
159 wxMutexGuiLeave();
160 #endif
161 }
162
163 //-----------------------------------------------------------------------------
164 // local functions
165 //-----------------------------------------------------------------------------
166
167 void wxapp_install_idle_handler()
168 {
169 wxASSERT_MSG( wxTheApp->m_idleTag == 0, wxT("attempt to install idle handler twice") );
170
171 g_isIdle = FALSE;
172
173 if (g_pendingTag == 0)
174 g_pendingTag = gtk_idle_add_priority( 900, wxapp_pending_callback, (gpointer) NULL );
175
176 /* This routine gets called by all event handlers
177 indicating that the idle is over. It may also
178 get called from other thread for sending events
179 to the main thread (and processing these in
180 idle time). Very low priority. */
181
182 wxTheApp->m_idleTag = gtk_idle_add_priority( 1000, wxapp_idle_callback, (gpointer) NULL );
183 }
184
185 // the callback functions must be extern "C" to comply with GTK+ declarations
186 extern "C"
187 {
188
189 gint wxapp_pending_callback( gpointer WXUNUSED(data) )
190 {
191 if (!wxTheApp) return TRUE;
192
193 // when getting called from GDK's time-out handler
194 // we are no longer within GDK's grab on the GUI
195 // thread so we must lock it here ourselves
196 gdk_threads_enter();
197
198 // Sent idle event to all who request them
199 wxTheApp->ProcessPendingEvents();
200
201 g_pendingTag = 0;
202
203 /* flush the logged messages if any */
204 #if wxUSE_LOG
205 wxLog::FlushActive();
206 #endif // wxUSE_LOG
207
208 // Release lock again
209 gdk_threads_leave();
210
211 // Return FALSE to indicate that no more idle events are
212 // to be sent (single shot instead of continuous stream)
213 return FALSE;
214 }
215
216 gint wxapp_idle_callback( gpointer WXUNUSED(data) )
217 {
218 if (!wxTheApp)
219 return TRUE;
220
221 #ifdef __WXDEBUG__
222 // don't generate the idle events while the assert modal dialog is shown,
223 // this completely confuses the apps which don't expect to be reentered
224 // from some safely-looking functions
225 if ( wxTheApp->IsInAssert() )
226 {
227 return TRUE;
228 }
229 #endif // __WXDEBUG__
230
231 // when getting called from GDK's time-out handler
232 // we are no longer within GDK's grab on the GUI
233 // thread so we must lock it here ourselves
234 gdk_threads_enter();
235
236 /* Indicate that we are now in idle mode - even so deeply
237 in idle mode that we don't get any idle events anymore.
238 this is like wxMSW where an idle event is sent only
239 once each time after the event queue has been completely
240 emptied */
241 g_isIdle = TRUE;
242 wxTheApp->m_idleTag = 0;
243
244 // Sent idle event to all who request them as long as they do
245 while (wxTheApp->ProcessIdle())
246 ;
247
248 // Release lock again
249 gdk_threads_leave();
250
251 // Return FALSE to indicate that no more idle events are
252 // to be sent (single shot instead of continuous stream)
253 return FALSE;
254 }
255
256 #if wxUSE_THREADS
257
258 gint wxapp_wakeup_timerout_callback( gpointer WXUNUSED(data) )
259 {
260 // when getting called from GDK's time-out handler
261 // we are no longer within GDK's grab on the GUI
262 // thread so we must lock it here ourselves
263 gdk_threads_enter();
264
265 wxapp_uninstall_thread_wakeup();
266
267 // unblock other threads wishing to do some GUI things
268 wxMutexGuiLeave();
269
270 g_mainThreadLocked = TRUE;
271
272 // wake up other threads
273 wxUsleep( 1 );
274
275 // block other thread again
276 wxMutexGuiEnter();
277
278 g_mainThreadLocked = FALSE;
279
280 wxapp_install_thread_wakeup();
281
282 // release lock again
283 gdk_threads_leave();
284
285 return TRUE;
286 }
287
288 #endif // wxUSE_THREADS
289
290 } // extern "C"
291
292 #if wxUSE_THREADS
293
294 static int g_threadUninstallLevel = 0;
295
296 void wxapp_install_thread_wakeup()
297 {
298 g_threadUninstallLevel++;
299
300 if (g_threadUninstallLevel != 1) return;
301
302 if (wxTheApp->m_wakeUpTimerTag) return;
303
304 wxTheApp->m_wakeUpTimerTag = gtk_timeout_add( 50, wxapp_wakeup_timerout_callback, (gpointer) NULL );
305 }
306
307 void wxapp_uninstall_thread_wakeup()
308 {
309 g_threadUninstallLevel--;
310
311 if (g_threadUninstallLevel != 0) return;
312
313 if (!wxTheApp->m_wakeUpTimerTag) return;
314
315 gtk_timeout_remove( wxTheApp->m_wakeUpTimerTag );
316 wxTheApp->m_wakeUpTimerTag = 0;
317 }
318
319 #endif // wxUSE_THREADS
320
321 //-----------------------------------------------------------------------------
322 // Access to the root window global
323 //-----------------------------------------------------------------------------
324
325 GtkWidget* wxGetRootWindow()
326 {
327 if (gs_RootWindow == NULL)
328 {
329 gs_RootWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
330 gtk_widget_realize( gs_RootWindow );
331 }
332 return gs_RootWindow;
333 }
334
335 //-----------------------------------------------------------------------------
336 // wxApp
337 //-----------------------------------------------------------------------------
338
339 IMPLEMENT_DYNAMIC_CLASS(wxApp,wxEvtHandler)
340
341 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
342 EVT_IDLE(wxApp::OnIdle)
343 END_EVENT_TABLE()
344
345 wxApp::wxApp()
346 {
347 m_initialized = FALSE;
348 #ifdef __WXDEBUG__
349 m_isInAssert = FALSE;
350 #endif // __WXDEBUG__
351
352 m_idleTag = 0;
353 wxapp_install_idle_handler();
354
355 #if wxUSE_THREADS
356 m_wakeUpTimerTag = 0;
357 wxapp_install_thread_wakeup();
358 #endif
359
360 m_colorCube = (unsigned char*) NULL;
361
362 // this is NULL for a "regular" wxApp, but is set (and freed) by a wxGLApp
363 m_glVisualInfo = (void *) NULL;
364 }
365
366 wxApp::~wxApp()
367 {
368 if (m_idleTag) gtk_idle_remove( m_idleTag );
369
370 #if wxUSE_THREADS
371 wxapp_uninstall_thread_wakeup();
372 #endif
373
374 if (m_colorCube) free(m_colorCube);
375 }
376
377 bool wxApp::OnInitGui()
378 {
379 if ( !wxAppBase::OnInitGui() )
380 return FALSE;
381
382 GdkVisual *visual = gdk_visual_get_system();
383
384 // if this is a wxGLApp (derived from wxApp), and we've already
385 // chosen a specific visual, then derive the GdkVisual from that
386 if (m_glVisualInfo != NULL)
387 {
388 #ifdef __WXGTK20__
389 // seems gtk_widget_set_default_visual no longer exists?
390 GdkVisual* vis = gtk_widget_get_default_visual();
391 #else
392 GdkVisual* vis = gdkx_visual_get(
393 ((XVisualInfo *) m_glVisualInfo) ->visualid );
394 gtk_widget_set_default_visual( vis );
395 #endif
396
397 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
398 gtk_widget_set_default_colormap( colormap );
399
400 visual = vis;
401 }
402
403 // On some machines, the default visual is just 256 colours, so
404 // we make sure we get the best. This can sometimes be wasteful.
405
406 else
407 if ((gdk_visual_get_best() != gdk_visual_get_system()) && (m_useBestVisual))
408 {
409 #ifdef __WXGTK20__
410 /* seems gtk_widget_set_default_visual no longer exists? */
411 GdkVisual* vis = gtk_widget_get_default_visual();
412 #else
413 GdkVisual* vis = gdk_visual_get_best();
414 gtk_widget_set_default_visual( vis );
415 #endif
416
417 GdkColormap *colormap = gdk_colormap_new( vis, FALSE );
418 gtk_widget_set_default_colormap( colormap );
419
420 visual = vis;
421 }
422
423 // Nothing to do for 15, 16, 24, 32 bit displays
424 if (visual->depth > 8) return TRUE;
425
426 // initialize color cube for 8-bit color reduction dithering
427
428 GdkColormap *cmap = gtk_widget_get_default_colormap();
429
430 m_colorCube = (unsigned char*)malloc(32 * 32 * 32);
431
432 for (int r = 0; r < 32; r++)
433 {
434 for (int g = 0; g < 32; g++)
435 {
436 for (int b = 0; b < 32; b++)
437 {
438 int rr = (r << 3) | (r >> 2);
439 int gg = (g << 3) | (g >> 2);
440 int bb = (b << 3) | (b >> 2);
441
442 int index = -1;
443
444 GdkColor *colors = cmap->colors;
445 if (colors)
446 {
447 int max = 3 * 65536;
448
449 for (int i = 0; i < cmap->size; i++)
450 {
451 int rdiff = ((rr << 8) - colors[i].red);
452 int gdiff = ((gg << 8) - colors[i].green);
453 int bdiff = ((bb << 8) - colors[i].blue);
454 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
455 if (sum < max)
456 {
457 index = i; max = sum;
458 }
459 }
460 }
461 else
462 {
463 // assume 8-bit true or static colors. this really exists
464 GdkVisual* vis = gdk_colormap_get_visual( cmap );
465 index = (r >> (5 - vis->red_prec)) << vis->red_shift;
466 index |= (g >> (5 - vis->green_prec)) << vis->green_shift;
467 index |= (b >> (5 - vis->blue_prec)) << vis->blue_shift;
468 }
469 m_colorCube[ (r*1024) + (g*32) + b ] = index;
470 }
471 }
472 }
473
474 return TRUE;
475 }
476
477 GdkVisual *wxApp::GetGdkVisual()
478 {
479 GdkVisual *visual = NULL;
480
481 if (m_glVisualInfo)
482 visual = gdkx_visual_get( ((XVisualInfo *) wxTheApp->m_glVisualInfo)->visualid );
483 else
484 visual = gdk_window_get_visual( wxGetRootWindow()->window );
485
486 wxASSERT( visual );
487
488 return visual;
489 }
490
491 bool wxApp::ProcessIdle()
492 {
493 wxIdleEvent event;
494 event.SetEventObject( this );
495 ProcessEvent( event );
496
497 return event.MoreRequested();
498 }
499
500 void wxApp::OnIdle( wxIdleEvent &event )
501 {
502 static bool s_inOnIdle = FALSE;
503
504 /* Avoid recursion (via ProcessEvent default case) */
505 if (s_inOnIdle)
506 return;
507
508 s_inOnIdle = TRUE;
509
510 /* Resend in the main thread events which have been prepared in other
511 threads */
512 ProcessPendingEvents();
513
514 /* 'Garbage' collection of windows deleted with Close(). */
515 DeletePendingObjects();
516
517 /* Send OnIdle events to all windows */
518 bool needMore = SendIdleEvents();
519
520 if (needMore)
521 event.RequestMore(TRUE);
522
523 s_inOnIdle = FALSE;
524 }
525
526 bool wxApp::SendIdleEvents()
527 {
528 bool needMore = FALSE;
529
530 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
531 while (node)
532 {
533 wxWindow* win = node->GetData();
534 if (SendIdleEvents(win))
535 needMore = TRUE;
536 node = node->GetNext();
537 }
538
539 return needMore;
540 }
541
542 bool wxApp::SendIdleEvents( wxWindow* win )
543 {
544 bool needMore = FALSE;
545
546 wxIdleEvent event;
547 event.SetEventObject(win);
548
549 win->GetEventHandler()->ProcessEvent(event);
550
551 win->OnInternalIdle();
552
553 if (event.MoreRequested())
554 needMore = TRUE;
555
556 wxNode* node = win->GetChildren().First();
557 while (node)
558 {
559 wxWindow* win = (wxWindow*) node->Data();
560 if (SendIdleEvents(win))
561 needMore = TRUE;
562
563 node = node->Next();
564 }
565 return needMore ;
566 }
567
568 int wxApp::MainLoop()
569 {
570 gtk_main();
571 return 0;
572 }
573
574 void wxApp::ExitMainLoop()
575 {
576 if (gtk_main_level() > 0)
577 gtk_main_quit();
578 }
579
580 bool wxApp::Initialized()
581 {
582 return m_initialized;
583 }
584
585 bool wxApp::Pending()
586 {
587 return (gtk_events_pending() > 0);
588 }
589
590 void wxApp::Dispatch()
591 {
592 gtk_main_iteration();
593 }
594
595 void wxApp::DeletePendingObjects()
596 {
597 wxNode *node = wxPendingDelete.First();
598 while (node)
599 {
600 wxObject *obj = (wxObject *)node->Data();
601
602 delete obj;
603
604 if (wxPendingDelete.Find(obj))
605 delete node;
606
607 node = wxPendingDelete.First();
608 }
609 }
610
611 bool wxApp::Initialize()
612 {
613 wxBuffer = new wxChar[BUFSIZ + 512];
614
615 wxClassInfo::InitializeClasses();
616
617 #if wxUSE_INTL
618 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
619 #endif
620
621 // GL: I'm annoyed ... I don't know where to put this and I don't want to
622 // create a module for that as it's part of the core.
623 #if wxUSE_THREADS
624 wxPendingEvents = new wxList();
625 wxPendingEventsLocker = new wxCriticalSection();
626 #endif
627
628 wxTheColourDatabase = new wxColourDatabase( wxKEY_STRING );
629 wxTheColourDatabase->Initialize();
630
631 wxInitializeStockLists();
632 wxInitializeStockObjects();
633
634 #if wxUSE_WX_RESOURCES
635 wxInitializeResourceSystem();
636 #endif
637
638 wxModule::RegisterModules();
639 if (!wxModule::InitializeModules()) return FALSE;
640
641 return TRUE;
642 }
643
644 void wxApp::CleanUp()
645 {
646 wxModule::CleanUpModules();
647
648 #if wxUSE_WX_RESOURCES
649 wxCleanUpResourceSystem();
650 #endif
651
652 if (wxTheColourDatabase)
653 delete wxTheColourDatabase;
654
655 wxTheColourDatabase = (wxColourDatabase*) NULL;
656
657 wxDeleteStockObjects();
658
659 wxDeleteStockLists();
660
661 delete wxTheApp;
662 wxTheApp = (wxApp*) NULL;
663
664 // GL: I'm annoyed ... I don't know where to put this and I don't want to
665 // create a module for that as it's part of the core.
666 #if wxUSE_THREADS
667 delete wxPendingEvents;
668 delete wxPendingEventsLocker;
669 #endif
670
671 delete[] wxBuffer;
672
673 wxClassInfo::CleanUpClasses();
674
675 // check for memory leaks
676 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
677 if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
678 {
679 wxLogDebug(wxT("There were memory leaks.\n"));
680 wxDebugContext::Dump();
681 wxDebugContext::PrintStatistics();
682 }
683 #endif // Debug
684
685 #if wxUSE_LOG
686 // do this as the very last thing because everything else can log messages
687 wxLog::DontCreateOnDemand();
688
689 wxLog *oldLog = wxLog::SetActiveTarget( (wxLog*) NULL );
690 if (oldLog)
691 delete oldLog;
692 #endif // wxUSE_LOG
693 }
694
695 //-----------------------------------------------------------------------------
696 // wxEntry
697 //-----------------------------------------------------------------------------
698
699 // NB: argc and argv may be changed here, pass by reference!
700 int wxEntryStart( int& argc, char *argv[] )
701 {
702 #if wxUSE_THREADS
703 // GTK 1.2 up to version 1.2.3 has broken threads
704 if ((gtk_major_version == 1) &&
705 (gtk_minor_version == 2) &&
706 (gtk_micro_version < 4))
707 {
708 printf( "wxWindows warning: GUI threading disabled due to outdated GTK version\n" );
709 }
710 else
711 {
712 g_thread_init(NULL);
713 }
714 #endif
715
716 gtk_set_locale();
717
718 // We should have the wxUSE_WCHAR_T test on the _outside_
719 #if wxUSE_WCHAR_T
720 #if defined(__WXGTK20__)
721 // gtk+ 2.0 supports Unicode through UTF-8 strings
722 wxConvCurrent = &wxConvUTF8;
723 #else
724 if (!wxOKlibc()) wxConvCurrent = &wxConvLocal;
725 #endif
726 #else
727 if (!wxOKlibc()) wxConvCurrent = (wxMBConv*) NULL;
728 #endif
729
730 gdk_threads_enter();
731
732 gtk_init( &argc, &argv );
733
734 wxSetDetectableAutoRepeat( TRUE );
735
736 if (!wxApp::Initialize())
737 {
738 gdk_threads_leave();
739 return -1;
740 }
741
742 return 0;
743 }
744
745
746 int wxEntryInitGui()
747 {
748 int retValue = 0;
749
750 if ( !wxTheApp->OnInitGui() )
751 retValue = -1;
752
753 wxGetRootWindow();
754
755 return retValue;
756 }
757
758
759 void wxEntryCleanup()
760 {
761 #if wxUSE_LOG
762 // flush the logged messages if any
763 wxLog *log = wxLog::GetActiveTarget();
764 if (log != NULL && log->HasPendingMessages())
765 log->Flush();
766
767 // continuing to use user defined log target is unsafe from now on because
768 // some resources may be already unavailable, so replace it by something
769 // more safe
770 wxLog *oldlog = wxLog::SetActiveTarget(new wxLogStderr);
771 if ( oldlog )
772 delete oldlog;
773 #endif // wxUSE_LOG
774
775 wxApp::CleanUp();
776
777 gdk_threads_leave();
778 }
779
780
781 int wxEntry( int argc, char *argv[] )
782 {
783 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
784 // This seems to be necessary since there are 'rogue'
785 // objects present at this point (perhaps global objects?)
786 // Setting a checkpoint will ignore them as far as the
787 // memory checking facility is concerned.
788 // Of course you may argue that memory allocated in globals should be
789 // checked, but this is a reasonable compromise.
790 wxDebugContext::SetCheckpoint();
791 #endif
792 int err = wxEntryStart(argc, argv);
793 if (err)
794 return err;
795
796 if (!wxTheApp)
797 {
798 wxCHECK_MSG( wxApp::GetInitializerFunction(), -1,
799 wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n") );
800
801 wxAppInitializerFunction app_ini = wxApp::GetInitializerFunction();
802
803 wxObject *test_app = app_ini();
804
805 wxTheApp = (wxApp*) test_app;
806 }
807
808 wxCHECK_MSG( wxTheApp, -1, wxT("wxWindows error: no application object") );
809
810 wxTheApp->argc = argc;
811 #if wxUSE_UNICODE
812 wxTheApp->argv = new wxChar*[argc+1];
813 int mb_argc = 0;
814 while (mb_argc < argc)
815 {
816 wxTheApp->argv[mb_argc] = wxStrdup(wxConvLibc.cMB2WX(argv[mb_argc]));
817 mb_argc++;
818 }
819 wxTheApp->argv[mb_argc] = (wxChar *)NULL;
820 #else
821 wxTheApp->argv = argv;
822 #endif
823
824 wxString name(wxFileNameFromPath(argv[0]));
825 wxStripExtension( name );
826 wxTheApp->SetAppName( name );
827
828 int retValue;
829 retValue = wxEntryInitGui();
830
831 // Here frames insert themselves automatically into wxTopLevelWindows by
832 // getting created in OnInit().
833 if ( retValue == 0 )
834 {
835 if ( !wxTheApp->OnInit() )
836 retValue = -1;
837 }
838
839 if ( retValue == 0 )
840 {
841 /* delete pending toplevel windows (typically a single
842 dialog) so that, if there isn't any left, we don't
843 call OnRun() */
844 wxTheApp->DeletePendingObjects();
845
846 wxTheApp->m_initialized = wxTopLevelWindows.GetCount() != 0;
847
848 if (wxTheApp->Initialized())
849 {
850 wxTheApp->OnRun();
851
852 wxWindow *topWindow = wxTheApp->GetTopWindow();
853 if (topWindow)
854 {
855 /* Forcibly delete the window. */
856 if (topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
857 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
858 {
859 topWindow->Close( TRUE );
860 wxTheApp->DeletePendingObjects();
861 }
862 else
863 {
864 delete topWindow;
865 wxTheApp->SetTopWindow( (wxWindow*) NULL );
866 }
867 }
868
869 retValue = wxTheApp->OnExit();
870 }
871 }
872
873 wxEntryCleanup();
874
875 return retValue;
876 }
877
878 #ifndef __WXUNIVERSAL__
879
880 // XPM hack: make the arrays const
881 #define static static const
882
883 #include "wx/gtk/info.xpm"
884 #include "wx/gtk/error.xpm"
885 #include "wx/gtk/question.xpm"
886 #include "wx/gtk/warning.xpm"
887
888 #undef static
889
890 wxIcon wxApp::GetStdIcon(int which) const
891 {
892 switch(which)
893 {
894 case wxICON_INFORMATION:
895 return wxIcon(info_xpm);
896
897 case wxICON_QUESTION:
898 return wxIcon(question_xpm);
899
900 case wxICON_EXCLAMATION:
901 return wxIcon(warning_xpm);
902
903 default:
904 wxFAIL_MSG(wxT("requested non existent standard icon"));
905 // still fall through
906
907 case wxICON_HAND:
908 return wxIcon(error_xpm);
909 }
910 }
911 #else
912 wxIcon wxApp::GetStdIcon(int which) const
913 {
914 return wxTheme::Get()->GetRenderer()->GetStdIcon(which);
915 }
916 #endif // !__WXUNIVERSAL__
917
918
919 #ifdef __WXDEBUG__
920
921 void wxApp::OnAssert(const wxChar *file, int line, const wxChar *msg)
922 {
923 m_isInAssert = TRUE;
924
925 wxAppBase::OnAssert(file, line, msg);
926
927 m_isInAssert = FALSE;
928 }
929
930 #endif // __WXDEBUG__
931