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