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