1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "app.h"
19 #include "wx/gdicmn.h"
21 #include "wx/dialog.h"
23 #include "wx/module.h"
24 #include "wx/memory.h"
27 #include "wx/evtloop.h"
29 #include "wx/filename.h"
32 #include "wx/univ/theme.h"
33 #include "wx/univ/renderer.h"
36 #include "wx/thread.h"
39 #include "wx/x11/private.h"
43 //------------------------------------------------------------------------
45 //------------------------------------------------------------------------
47 extern wxList wxPendingDelete
;
49 wxHashTable
*wxWidgetHashTable
= NULL
;
50 wxHashTable
*wxClientWidgetHashTable
= NULL
;
52 // This is set within wxEntryStart -- too early on
53 // to put these in wxTheApp
54 static bool g_showIconic
= FALSE
;
55 static wxSize g_initialSize
= wxDefaultSize
;
57 // This is required for wxFocusEvent::SetWindow(). It will only
58 // work for focus events which we provoke ourselves (by calling
59 // SetFocus()). It will not work for those events, which X11
61 static wxWindow
*g_nextFocus
= NULL
;
62 static wxWindow
*g_prevFocus
= NULL
;
64 //------------------------------------------------------------------------
66 //------------------------------------------------------------------------
69 typedef int (*XErrorHandlerFunc
)(Display
*, XErrorEvent
*);
71 XErrorHandlerFunc gs_pfnXErrorHandler
= 0;
73 static int wxXErrorHandler(Display
*dpy
, XErrorEvent
*xevent
)
75 // just forward to the default handler for now
76 if (gs_pfnXErrorHandler
)
77 return gs_pfnXErrorHandler(dpy
, xevent
);
83 //------------------------------------------------------------------------
85 //------------------------------------------------------------------------
87 long wxApp
::sm_lastMessageTime
= 0;
88 WXDisplay
*wxApp
::ms_display
= NULL
;
90 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
92 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
93 EVT_IDLE(wxApp
::OnIdle
)
96 bool wxApp
::Initialize(int argc
, wxChar
**argv
)
98 if ( !wxAppBase
::Initialize(argc
, argv
) )
102 wxFont
::SetDefaultEncoding(wxLocale
::GetSystemEncoding());
105 wxWidgetHashTable
= new wxHashTable(wxKEY_INTEGER
);
106 wxClientWidgetHashTable
= new wxHashTable(wxKEY_INTEGER
);
111 void wxApp
::CleanUp()
113 delete wxWidgetHashTable
;
114 wxWidgetHashTable
= NULL
;
115 delete wxClientWidgetHashTable
;
116 wxClientWidgetHashTable
= NULL
;
118 wxAppBase
::CleanUp();
121 // NB: argc and argv may be changed here, pass by reference!
122 int wxEntryStart( int& argc
, char *argv
[] )
126 // install the X error handler
127 gs_pfnXErrorHandler
= XSetErrorHandler( wxXErrorHandler
);
129 #endif // __WXDEBUG__
131 char *displayName
= NULL
;
132 bool syncDisplay
= FALSE
;
135 for (i
= 0; i
< argc
; i
++)
137 if (strcmp( argv
[i
], "-display") == 0)
142 displayName
= argv
[i
];
146 else if (strcmp( argv
[i
], "-geometry") == 0)
152 if (sscanf(argv
[i
], "%dx%d", &w
, &h
) != 2)
154 wxLogError( _("Invalid geometry specification '%s'"), wxString
::FromAscii(argv
[i
]).c_str() );
158 g_initialSize
= wxSize(w
, h
);
163 else if (strcmp( argv
[i
], "-sync") == 0)
168 else if (strcmp( argv
[i
], "-iconic") == 0)
178 Display
* xdisplay
= XOpenDisplay( displayName
);
181 wxLogError( _("wxWindows could not open display. Exiting.") );
186 XSynchronize(xdisplay
, True
);
188 wxApp
::ms_display
= (WXDisplay
*) xdisplay
;
190 XSelectInput( xdisplay
, XDefaultRootWindow(xdisplay
), PropertyChangeMask
);
193 wxSetDetectableAutoRepeat( TRUE
);
196 // Glib's type system required by Pango
200 if (!wxApp
::Initialize())
210 if ( !wxTheApp
->OnInitGui() )
217 int wxEntry( int argc
, char *argv
[] )
219 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
220 // This seems to be necessary since there are 'rogue'
221 // objects present at this point (perhaps global objects?)
222 // Setting a checkpoint will ignore them as far as the
223 // memory checking facility is concerned.
224 // Of course you may argue that memory allocated in globals should be
225 // checked, but this is a reasonable compromise.
226 wxDebugContext
::SetCheckpoint();
228 int err
= wxEntryStart(argc
, argv
);
234 if (!wxApp
::GetInitializerFunction())
236 printf( "wxWindows error: No initializer - use IMPLEMENT_APP macro.\n" );
240 wxTheApp
= (wxApp
*) (* wxApp
::GetInitializerFunction()) ();
245 printf( "wxWindows error: wxTheApp == NULL\n" );
249 // Command line argument stuff
250 wxTheApp
->argc
= argc
;
252 wxTheApp
->argv
= new wxChar
*[argc
+1];
254 while (mb_argc
< argc
)
256 wxString tmp
= wxString
::FromAscii( argv
[mb_argc
] );
257 wxTheApp
->argv
[mb_argc
] = wxStrdup( tmp
.c_str() );
260 wxTheApp
->argv
[mb_argc
] = (wxChar
*)NULL
;
262 wxTheApp
->argv
= argv
;
265 if (wxTheApp
->argc
> 0)
267 wxFileName
fname( wxTheApp
->argv
[0] );
268 wxTheApp
->SetAppName( fname
.GetName() );
271 wxTheApp
->m_showIconic
= g_showIconic
;
272 wxTheApp
->m_initialSize
= g_initialSize
;
275 retValue
= wxEntryInitGui();
277 // Here frames insert themselves automatically into wxTopLevelWindows by
278 // getting created in OnInit().
281 if ( !wxTheApp
->OnInit() )
287 if (wxTheApp
->Initialized()) retValue
= wxTheApp
->OnRun();
290 // flush the logged messages if any
291 wxLog
*pLog
= wxLog
::GetActiveTarget();
292 if ( pLog
!= NULL
&& pLog
->HasPendingMessages() )
295 delete wxLog
::SetActiveTarget(new wxLogStderr
); // So dialog boxes aren't used
296 // for further messages
298 if (wxTheApp
->GetTopWindow())
300 delete wxTheApp
->GetTopWindow();
301 wxTheApp
->SetTopWindow(NULL
);
304 wxTheApp
->DeletePendingObjects();
315 // TODO: parse the command line
319 m_mainColormap
= (WXColormap
) NULL
;
320 m_topLevelWidget
= (WXWindow
) NULL
;
321 m_maxRequestSize
= 0;
323 m_showIconic
= FALSE
;
324 m_initialSize
= wxDefaultSize
;
338 bool wxApp
::Initialized()
346 int wxApp
::MainLoop()
349 m_mainLoop
= new wxEventLoop
;
351 rt
= m_mainLoop
->Run();
359 //-----------------------------------------------------------------------
360 // X11 predicate function for exposure compression
361 //-----------------------------------------------------------------------
366 Bool found_non_matching
;
369 static Bool
expose_predicate (Display
*display
, XEvent
*xevent
, XPointer arg
)
371 wxExposeInfo
*info
= (wxExposeInfo
*) arg
;
373 if (info
->found_non_matching
)
376 if (xevent
->xany
.type
!= Expose
)
378 info
->found_non_matching
= TRUE
;
382 if (xevent
->xexpose
.window
!= info
->window
)
384 info
->found_non_matching
= TRUE
;
393 //-----------------------------------------------------------------------
394 // Processes an X event, returning TRUE if the event was processed.
395 //-----------------------------------------------------------------------
397 bool wxApp
::ProcessXEvent(WXEvent
* _event
)
399 XEvent
* event
= (XEvent
*) _event
;
401 wxWindow
* win
= NULL
;
402 Window window
= XEventGetWindow(event
);
404 Window actualWindow
= window
;
407 // Find the first wxWindow that corresponds to this event window
408 // Because we're receiving events after a window
409 // has been destroyed, assume a 1:1 match between
410 // Window and wxWindow, so if it's not in the table,
411 // it must have been destroyed.
413 win
= wxGetWindowFromTable(window
);
416 #if wxUSE_TWO_WINDOWS
417 win
= wxGetClientWindowFromTable(window
);
424 wxString windowClass
= win
->GetClassInfo()->GetClassName();
431 #if wxUSE_TWO_WINDOWS && !wxUSE_NANOX
432 if (event
->xexpose
.window
!= (Window
)win
->GetClientAreaWindow())
436 info
.window
= event
->xexpose
.window
;
437 info
.found_non_matching
= FALSE
;
438 while (XCheckIfEvent( wxGlobalDisplay(), &tmp_event
, expose_predicate
, (XPointer
) &info
))
440 // Don't worry about optimizing redrawing the border etc.
442 win
->NeedUpdateNcAreaInIdle();
447 win
->GetUpdateRegion().Union( XExposeEventGetX(event
), XExposeEventGetY(event
),
448 XExposeEventGetWidth(event
), XExposeEventGetHeight(event
));
449 win
->GetClearRegion().Union( XExposeEventGetX(event
), XExposeEventGetY(event
),
450 XExposeEventGetWidth(event
), XExposeEventGetHeight(event
));
455 info
.window
= event
->xexpose
.window
;
456 info
.found_non_matching
= FALSE
;
457 while (XCheckIfEvent( wxGlobalDisplay(), &tmp_event
, expose_predicate
, (XPointer
) &info
))
459 win
->GetUpdateRegion().Union( tmp_event
.xexpose
.x
, tmp_event
.xexpose
.y
,
460 tmp_event
.xexpose
.width
, tmp_event
.xexpose
.height
);
462 win
->GetClearRegion().Union( tmp_event
.xexpose
.x
, tmp_event
.xexpose
.y
,
463 tmp_event
.xexpose
.width
, tmp_event
.xexpose
.height
);
467 // This simplifies the expose and clear areas to simple
469 win
->GetUpdateRegion() = win
->GetUpdateRegion().GetBox();
470 win
->GetClearRegion() = win
->GetClearRegion().GetBox();
472 // If we only have one X11 window, always indicate
473 // that borders might have to be redrawn.
474 if (win
->GetMainWindow() == win
->GetClientAreaWindow())
475 win
->NeedUpdateNcAreaInIdle();
477 // Only erase background, paint in idle time.
478 win
->SendEraseEvents();
490 printf( "GraphicExpose event\n" );
492 wxLogTrace( _T("expose"), _T("GraphicsExpose from %s"), win
->GetName().c_str());
494 win
->GetUpdateRegion().Union( event
->xgraphicsexpose
.x
, event
->xgraphicsexpose
.y
,
495 event
->xgraphicsexpose
.width
, event
->xgraphicsexpose
.height
);
497 win
->GetClearRegion().Union( event
->xgraphicsexpose
.x
, event
->xgraphicsexpose
.y
,
498 event
->xgraphicsexpose
.width
, event
->xgraphicsexpose
.height
);
500 if (event
->xgraphicsexpose
.count
== 0)
502 // Only erase background, paint in idle time.
503 win
->SendEraseEvents();
513 if (!win
->IsEnabled())
516 wxKeyEvent
keyEvent(wxEVT_KEY_DOWN
);
517 wxTranslateKeyEvent(keyEvent
, win
, window
, event
);
519 // wxLogDebug( "OnKey from %s", win->GetName().c_str() );
521 // We didn't process wxEVT_KEY_DOWN, so send wxEVT_CHAR
522 if (win
->GetEventHandler()->ProcessEvent( keyEvent
))
525 keyEvent
.SetEventType(wxEVT_CHAR
);
526 // Do the translation again, retaining the ASCII
528 wxTranslateKeyEvent(keyEvent
, win
, window
, event
, TRUE
);
529 if (win
->GetEventHandler()->ProcessEvent( keyEvent
))
532 if ( (keyEvent
.m_keyCode
== WXK_TAB
) &&
533 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
535 wxNavigationKeyEvent new_event
;
536 new_event
.SetEventObject( win
->GetParent() );
537 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
538 new_event
.SetDirection( (keyEvent
.m_keyCode
== WXK_TAB
) );
539 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
540 new_event
.SetWindowChange( keyEvent
.ControlDown() );
541 new_event
.SetCurrentFocus( win
);
542 return win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
549 if (!win
->IsEnabled())
552 wxKeyEvent
keyEvent(wxEVT_KEY_UP
);
553 wxTranslateKeyEvent(keyEvent
, win
, window
, event
);
555 return win
->GetEventHandler()->ProcessEvent( keyEvent
);
557 case ConfigureNotify
:
560 if (event
->update
.utype
== GR_UPDATE_SIZE
)
563 if (win
->IsTopLevel())
565 wxTopLevelWindow
*tlw
= (wxTopLevelWindow
*) win
;
566 tlw
->SetConfigureGeometry( XConfigureEventGetX(event
), XConfigureEventGetY(event
),
567 XConfigureEventGetWidth(event
), XConfigureEventGetHeight(event
) );
570 if (win
->IsTopLevel() && win
->IsShown())
572 wxTopLevelWindowX11
*tlw
= (wxTopLevelWindowX11
*) win
;
573 tlw
->SetNeedResizeInIdle();
577 wxSizeEvent
sizeEvent( wxSize(XConfigureEventGetWidth(event
), XConfigureEventGetHeight(event
)), win
->GetId() );
578 sizeEvent
.SetEventObject( win
);
580 return win
->GetEventHandler()->ProcessEvent( sizeEvent
);
589 //wxLogDebug("PropertyNotify: %s", windowClass.c_str());
590 return HandlePropertyChange(_event
);
594 if (!win
->IsEnabled())
597 Atom wm_delete_window
= XInternAtom(wxGlobalDisplay(), "WM_DELETE_WINDOW", True
);
598 Atom wm_protocols
= XInternAtom(wxGlobalDisplay(), "WM_PROTOCOLS", True
);
600 if (event
->xclient
.message_type
== wm_protocols
)
602 if ((Atom
) (event
->xclient
.data
.l
[0]) == wm_delete_window
)
613 printf( "destroy from %s\n", win
->GetName().c_str() );
618 printf( "create from %s\n", win
->GetName().c_str() );
623 printf( "map request from %s\n", win
->GetName().c_str() );
628 printf( "resize request from %s\n", win
->GetName().c_str() );
630 Display
*disp
= (Display
*) wxGetDisplay();
635 while( XCheckTypedWindowEvent (disp
, actualWindow
, ResizeRequest
, &report
));
637 wxSize sz
= win
->GetSize();
638 wxSizeEvent
sizeEvent(sz
, win
->GetId());
639 sizeEvent
.SetEventObject(win
);
641 return win
->GetEventHandler()->ProcessEvent( sizeEvent
);
646 case GR_EVENT_TYPE_CLOSE_REQ
:
663 if (!win
->IsEnabled())
666 // Here we check if the top level window is
667 // disabled, which is one aspect of modality.
669 while (tlw
&& !tlw
->IsTopLevel())
670 tlw
= tlw
->GetParent();
671 if (tlw
&& !tlw
->IsEnabled())
674 if (event
->type
== ButtonPress
)
676 if ((win
!= wxWindow
::FindFocus()) && win
->AcceptsFocus())
678 // This might actually be done in wxWindow::SetFocus()
679 // and not here. TODO.
680 g_prevFocus
= wxWindow
::FindFocus();
683 wxLogTrace( _T("focus"), _T("About to call SetFocus on %s of type %s due to button press"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() );
685 // Record the fact that this window is
686 // getting the focus, because we'll need to
687 // check if its parent is getting a bogus
688 // focus and duly ignore it.
689 // TODO: may need to have this code in SetFocus, too.
690 extern wxWindow
* g_GettingFocus
;
691 g_GettingFocus
= win
;
697 if (event
->type
== LeaveNotify
|| event
->type
== EnterNotify
)
699 // Throw out NotifyGrab and NotifyUngrab
700 if (event
->xcrossing
.mode
!= NotifyNormal
)
704 wxMouseEvent wxevent
;
705 wxTranslateMouseEvent(wxevent
, win
, window
, event
);
706 return win
->GetEventHandler()->ProcessEvent( wxevent
);
711 if ((event
->xfocus
.detail
!= NotifyPointer
) &&
712 (event
->xfocus
.mode
== NotifyNormal
))
715 wxLogTrace( _T("focus"), _T("FocusIn from %s of type %s"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() );
717 extern wxWindow
* g_GettingFocus
;
718 if (g_GettingFocus
&& g_GettingFocus
->GetParent() == win
)
720 // Ignore this, this can be a spurious FocusIn
721 // caused by a child having its focus set.
722 g_GettingFocus
= NULL
;
723 wxLogTrace( _T("focus"), _T("FocusIn from %s of type %s being deliberately ignored"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() );
728 wxFocusEvent
focusEvent(wxEVT_SET_FOCUS
, win
->GetId());
729 focusEvent
.SetEventObject(win
);
730 focusEvent
.SetWindow( g_prevFocus
);
733 return win
->GetEventHandler()->ProcessEvent(focusEvent
);
742 if ((event
->xfocus
.detail
!= NotifyPointer
) &&
743 (event
->xfocus
.mode
== NotifyNormal
))
746 wxLogTrace( _T("focus"), _T("FocusOut from %s of type %s"), win
->GetName().c_str(), win
->GetClassInfo()->GetClassName() );
748 wxFocusEvent
focusEvent(wxEVT_KILL_FOCUS
, win
->GetId());
749 focusEvent
.SetEventObject(win
);
750 focusEvent
.SetWindow( g_nextFocus
);
752 return win
->GetEventHandler()->ProcessEvent(focusEvent
);
760 //wxString eventName = wxGetXEventName(XEvent& event);
761 //wxLogDebug(wxT("Event %s not handled"), eventName.c_str());
770 // Returns TRUE if more time is needed.
771 // Note that this duplicates wxEventLoopImpl::SendIdleEvent
772 // but ProcessIdle may be needed by apps, so is kept.
773 bool wxApp
::ProcessIdle()
776 event
.SetEventObject(this);
779 return event
.MoreRequested();
782 void wxApp
::ExitMainLoop()
788 // Is a message/event pending?
789 bool wxApp
::Pending()
791 return wxEventLoop
::GetActive()->Pending();
794 // Dispatch a message.
795 void wxApp
::Dispatch()
797 wxEventLoop
::GetActive()->Dispatch();
800 // This should be redefined in a derived class for
801 // handling property change events for XAtom IPC.
802 bool wxApp
::HandlePropertyChange(WXEvent
*event
)
804 // by default do nothing special
805 // TODO: what to do for X11
806 // XtDispatchEvent((XEvent*) event);
810 void wxApp
::OnIdle(wxIdleEvent
& event
)
812 static bool s_inOnIdle
= FALSE
;
814 // Avoid recursion (via ProcessEvent default case)
820 // Resend in the main thread events which have been prepared in other
822 ProcessPendingEvents();
824 // 'Garbage' collection of windows deleted with Close()
825 DeletePendingObjects();
827 // Send OnIdle events to all windows
828 bool needMore
= SendIdleEvents();
831 event
.RequestMore(TRUE
);
836 void wxApp
::WakeUpIdle()
838 // TODO: use wxMotif implementation?
840 // Wake up the idle handler processor, even if it is in another thread...
844 // Send idle event to all top-level windows
845 bool wxApp
::SendIdleEvents()
847 bool needMore
= FALSE
;
849 wxWindowList
::Node
* node
= wxTopLevelWindows
.GetFirst();
852 wxWindow
* win
= node
->GetData();
853 if (SendIdleEvents(win
))
855 node
= node
->GetNext();
861 // Send idle event to window and all subwindows
862 bool wxApp
::SendIdleEvents(wxWindow
* win
)
864 bool needMore
= FALSE
;
867 event
.SetEventObject(win
);
869 win
->GetEventHandler()->ProcessEvent(event
);
871 if (event
.MoreRequested())
874 wxWindowListNode
* node
= win
->GetChildren().GetFirst();
877 wxWindow
* win
= (wxWindow
*) node
->GetData();
878 if (SendIdleEvents(win
))
881 node
= node
->GetNext();
884 win
->OnInternalIdle();
889 // Create display, and other initialization
890 bool wxApp
::OnInitGui()
892 // Eventually this line will be removed, but for
893 // now we don't want to try popping up a dialog
894 // for error messages.
895 delete wxLog
::SetActiveTarget(new wxLogStderr
);
897 if (!wxAppBase
::OnInitGui())
900 GetMainColormap( wxApp
::GetDisplay() );
902 m_maxRequestSize
= XMaxRequestSize( (Display
*) wxApp
::GetDisplay() );
905 m_visualInfo
= new wxXVisualInfo
;
906 wxFillXVisualInfo( m_visualInfo
, (Display
*) wxApp
::GetDisplay() );
914 #include <pango/pango.h>
915 #include <pango/pangox.h>
916 #include <pango/pangoxft.h>
918 PangoContext
* wxApp
::GetPangoContext()
920 static PangoContext
*ret
= NULL
;
924 Display
*xdisplay
= (Display
*) wxApp
::GetDisplay();
927 int xscreen
= DefaultScreen(xdisplay
);
928 static int use_xft
= -1;
931 wxString val
= wxGetenv( L
"GDK_USE_XFT" );
932 use_xft
= (val
== L
"1");
936 ret
= pango_xft_get_context( xdisplay
, xscreen
);
939 ret
= pango_x_get_context( xdisplay
);
941 if (!PANGO_IS_CONTEXT(ret
))
942 wxLogError( wxT("No pango context.") );
948 WXColormap wxApp
::GetMainColormap(WXDisplay
* display
)
950 if (!display
) /* Must be called first with non-NULL display */
951 return m_mainColormap
;
953 int defaultScreen
= DefaultScreen((Display
*) display
);
954 Screen
* screen
= XScreenOfDisplay((Display
*) display
, defaultScreen
);
956 Colormap c
= DefaultColormapOfScreen(screen
);
959 m_mainColormap
= (WXColormap
) c
;
961 return (WXColormap
) c
;
964 Window
wxGetWindowParent(Window window
)
966 wxASSERT_MSG( window
, "invalid window" );
970 Window parent
, root
= 0;
974 unsigned int noChildren
= 0;
976 Window
* children
= NULL
;
978 // #define XQueryTree(d,w,r,p,c,nc) GrQueryTree(w,p,c,nc)
983 XQueryTree((Display
*) wxGetDisplay(), window
, & root
, & parent
,
984 & children
, & noChildren
);
997 wxAppConsole
::Exit();
1000 // Yield to other processes
1002 bool wxApp
::Yield(bool onlyIfNeeded
)
1004 // Sometimes only 2 yields seem
1005 // to do the trick, e.g. in the
1008 for (i
= 0; i
< 2; i
++)
1010 bool s_inYield
= FALSE
;
1014 if ( !onlyIfNeeded
)
1016 wxFAIL_MSG( wxT("wxYield called recursively" ) );
1024 // Make sure we have an event loop object,
1025 // or Pending/Dispatch will fail
1026 wxEventLoop
* eventLoop
= wxEventLoop
::GetActive();
1027 wxEventLoop
* newEventLoop
= NULL
;
1030 newEventLoop
= new wxEventLoop
;
1031 wxEventLoop
::SetActive(newEventLoop
);
1034 // Call dispatch at least once so that sockets
1036 wxTheApp
->Dispatch();
1038 while (wxTheApp
&& wxTheApp
->Pending())
1039 wxTheApp
->Dispatch();
1042 wxTimer
::NotifyTimers();
1048 wxEventLoop
::SetActive(NULL
);
1049 delete newEventLoop
;
1060 void wxApp
::OnAssert(const wxChar
*file
, int line
, const wxChar
* cond
, const wxChar
*msg
)
1062 // While the GUI isn't working that well, just print out the
1065 wxAppBase
::OnAssert(file
, line
, cond
, msg
);
1068 msg2
.Printf("At file %s:%d: %s", file
, line
, msg
);
1073 #endif // __WXDEBUG__