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