]> git.saurik.com Git - wxWidgets.git/blob - src/x11/app.cpp
wx{V,H}SCROLL code is needed on all platforms
[wxWidgets.git] / src / x11 / app.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/x11/app.cpp
3 // Purpose: wxApp
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 17/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // for compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #include "wx/app.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/hash.h"
19 #include "wx/intl.h"
20 #include "wx/log.h"
21 #include "wx/utils.h"
22 #include "wx/frame.h"
23 #include "wx/icon.h"
24 #include "wx/dialog.h"
25 #include "wx/timer.h"
26 #include "wx/memory.h"
27 #include "wx/gdicmn.h"
28 #include "wx/module.h"
29 #endif
30
31 #include "wx/evtloop.h"
32 #include "wx/filename.h"
33
34 #include "wx/univ/theme.h"
35 #include "wx/univ/renderer.h"
36
37 #if wxUSE_THREADS
38 #include "wx/thread.h"
39 #endif
40
41 #include "wx/x11/private.h"
42
43 #include <string.h>
44
45 //------------------------------------------------------------------------
46 // global data
47 //------------------------------------------------------------------------
48
49 wxWindowHash *wxWidgetHashTable = NULL;
50 wxWindowHash *wxClientWidgetHashTable = NULL;
51
52 static bool g_showIconic = false;
53 static wxSize g_initialSize = wxDefaultSize;
54
55 // This is required for wxFocusEvent::SetWindow(). It will only
56 // work for focus events which we provoke ourselves (by calling
57 // SetFocus()). It will not work for those events, which X11
58 // generates itself.
59 static wxWindow *g_nextFocus = NULL;
60 static wxWindow *g_prevFocus = NULL;
61
62 //------------------------------------------------------------------------
63 // X11 error handling
64 //------------------------------------------------------------------------
65
66 #ifdef __WXDEBUG__
67 typedef int (*XErrorHandlerFunc)(Display *, XErrorEvent *);
68
69 XErrorHandlerFunc gs_pfnXErrorHandler = 0;
70
71 static int wxXErrorHandler(Display *dpy, XErrorEvent *xevent)
72 {
73 // just forward to the default handler for now
74 if (gs_pfnXErrorHandler)
75 return gs_pfnXErrorHandler(dpy, xevent);
76 else
77 return 0;
78 }
79 #endif // __WXDEBUG__
80
81 //------------------------------------------------------------------------
82 // wxApp
83 //------------------------------------------------------------------------
84
85 long wxApp::sm_lastMessageTime = 0;
86
87 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
88
89 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
90 EVT_IDLE(wxAppBase::OnIdle)
91 END_EVENT_TABLE()
92
93 bool wxApp::Initialize(int& argC, wxChar **argV)
94 {
95 #if defined(__WXDEBUG__) && !wxUSE_NANOX
96 // install the X error handler
97 gs_pfnXErrorHandler = XSetErrorHandler( wxXErrorHandler );
98 #endif // __WXDEBUG__
99
100 wxString displayName;
101 bool syncDisplay = false;
102
103 int argCOrig = argC;
104 for ( int i = 0; i < argCOrig; i++ )
105 {
106 if (wxStrcmp( argV[i], _T("-display") ) == 0)
107 {
108 if (i < (argC - 1))
109 {
110 argV[i++] = NULL;
111
112 displayName = argV[i];
113
114 argV[i] = NULL;
115 argC -= 2;
116 }
117 }
118 else if (wxStrcmp( argV[i], _T("-geometry") ) == 0)
119 {
120 if (i < (argC - 1))
121 {
122 argV[i++] = NULL;
123
124 int w, h;
125 if (wxSscanf(argV[i], _T("%dx%d"), &w, &h) != 2)
126 {
127 wxLogError( _("Invalid geometry specification '%s'"),
128 wxString(argV[i]).c_str() );
129 }
130 else
131 {
132 g_initialSize = wxSize(w, h);
133 }
134
135 argV[i] = NULL;
136 argC -= 2;
137 }
138 }
139 else if (wxStrcmp( argV[i], _T("-sync") ) == 0)
140 {
141 syncDisplay = true;
142
143 argV[i] = NULL;
144 argC--;
145 }
146 else if (wxStrcmp( argV[i], _T("-iconic") ) == 0)
147 {
148 g_showIconic = true;
149
150 argV[i] = NULL;
151 argC--;
152 }
153 }
154
155 if ( argC != argCOrig )
156 {
157 // remove the argumens we consumed
158 for ( int i = 0; i < argC; i++ )
159 {
160 while ( !argV[i] )
161 {
162 memmove(argV + i, argV + i + 1, argCOrig - i);
163 }
164 }
165 }
166
167 // open and set up the X11 display
168 if ( !wxSetDisplay(displayName) )
169 {
170 wxLogError(_("wxWidgets could not open display. Exiting."));
171 return false;
172 }
173
174 Display *dpy = wxGlobalDisplay();
175 if (syncDisplay)
176 XSynchronize(dpy, True);
177
178 XSelectInput(dpy, XDefaultRootWindow(dpy), PropertyChangeMask);
179
180 wxSetDetectableAutoRepeat( true );
181
182
183 if ( !wxAppBase::Initialize(argC, argV) )
184 return false;
185
186 #if wxUSE_UNICODE
187 // Glib's type system required by Pango
188 g_type_init();
189 #endif
190
191 #if wxUSE_INTL
192 wxFont::SetDefaultEncoding(wxLocale::GetSystemEncoding());
193 #endif
194
195 wxWidgetHashTable = new wxWindowHash;
196 wxClientWidgetHashTable = new wxWindowHash;
197
198 return true;
199 }
200
201 void wxApp::CleanUp()
202 {
203 delete wxWidgetHashTable;
204 wxWidgetHashTable = NULL;
205 delete wxClientWidgetHashTable;
206 wxClientWidgetHashTable = NULL;
207
208 wxAppBase::CleanUp();
209 }
210
211 wxApp::wxApp()
212 {
213 m_mainColormap = NULL;
214 m_topLevelWidget = NULL;
215 m_maxRequestSize = 0;
216 m_showIconic = false;
217 m_initialSize = wxDefaultSize;
218
219 #if !wxUSE_NANOX
220 m_visualInfo = NULL;
221 #endif
222 }
223
224 wxApp::~wxApp()
225 {
226 #if !wxUSE_NANOX
227 delete m_visualInfo;
228 #endif
229 }
230
231 #if !wxUSE_NANOX
232
233 //-----------------------------------------------------------------------
234 // X11 predicate function for exposure compression
235 //-----------------------------------------------------------------------
236
237 struct wxExposeInfo
238 {
239 Window window;
240 Bool found_non_matching;
241 };
242
243 extern "C"
244 Bool wxX11ExposePredicate (Display *display, XEvent *xevent, XPointer arg)
245 {
246 wxExposeInfo *info = (wxExposeInfo*) arg;
247
248 if (info->found_non_matching)
249 return FALSE;
250
251 if (xevent->xany.type != Expose)
252 {
253 info->found_non_matching = true;
254 return FALSE;
255 }
256
257 if (xevent->xexpose.window != info->window)
258 {
259 info->found_non_matching = true;
260 return FALSE;
261 }
262
263 return TRUE;
264 }
265
266 #endif // wxUSE_NANOX
267
268 //-----------------------------------------------------------------------
269 // Processes an X event, returning true if the event was processed.
270 //-----------------------------------------------------------------------
271
272 bool wxApp::ProcessXEvent(WXEvent* _event)
273 {
274 XEvent* event = (XEvent*) _event;
275
276 wxWindow* win = NULL;
277 Window window = XEventGetWindow(event);
278 #if 0
279 Window actualWindow = window;
280 #endif
281
282 // Find the first wxWindow that corresponds to this event window
283 // Because we're receiving events after a window
284 // has been destroyed, assume a 1:1 match between
285 // Window and wxWindow, so if it's not in the table,
286 // it must have been destroyed.
287
288 win = wxGetWindowFromTable(window);
289 if (!win)
290 {
291 #if wxUSE_TWO_WINDOWS
292 win = wxGetClientWindowFromTable(window);
293 if (!win)
294 #endif
295 return false;
296 }
297
298 #ifdef __WXDEBUG__
299 wxString windowClass = win->GetClassInfo()->GetClassName();
300 #endif
301
302 switch (event->type)
303 {
304 case Expose:
305 {
306 #if wxUSE_TWO_WINDOWS && !wxUSE_NANOX
307 if (event->xexpose.window != (Window)win->GetClientAreaWindow())
308 {
309 XEvent tmp_event;
310 wxExposeInfo info;
311 info.window = event->xexpose.window;
312 info.found_non_matching = false;
313 while (XCheckIfEvent( wxGlobalDisplay(), &tmp_event, wxX11ExposePredicate, (XPointer) &info ))
314 {
315 // Don't worry about optimizing redrawing the border etc.
316 }
317 win->NeedUpdateNcAreaInIdle();
318 }
319 else
320 #endif
321 {
322 win->GetUpdateRegion().Union( XExposeEventGetX(event), XExposeEventGetY(event),
323 XExposeEventGetWidth(event), XExposeEventGetHeight(event));
324 win->GetClearRegion().Union( XExposeEventGetX(event), XExposeEventGetY(event),
325 XExposeEventGetWidth(event), XExposeEventGetHeight(event));
326
327 #if !wxUSE_NANOX
328 XEvent tmp_event;
329 wxExposeInfo info;
330 info.window = event->xexpose.window;
331 info.found_non_matching = false;
332 while (XCheckIfEvent( wxGlobalDisplay(), &tmp_event, wxX11ExposePredicate, (XPointer) &info ))
333 {
334 win->GetUpdateRegion().Union( tmp_event.xexpose.x, tmp_event.xexpose.y,
335 tmp_event.xexpose.width, tmp_event.xexpose.height );
336
337 win->GetClearRegion().Union( tmp_event.xexpose.x, tmp_event.xexpose.y,
338 tmp_event.xexpose.width, tmp_event.xexpose.height );
339 }
340 #endif
341
342 // This simplifies the expose and clear areas to simple
343 // rectangles.
344 win->GetUpdateRegion() = win->GetUpdateRegion().GetBox();
345 win->GetClearRegion() = win->GetClearRegion().GetBox();
346
347 // If we only have one X11 window, always indicate
348 // that borders might have to be redrawn.
349 if (win->GetMainWindow() == win->GetClientAreaWindow())
350 win->NeedUpdateNcAreaInIdle();
351
352 // Only erase background, paint in idle time.
353 win->SendEraseEvents();
354
355 // EXPERIMENT
356 //win->Update();
357 }
358
359 return true;
360 }
361
362 #if !wxUSE_NANOX
363 case GraphicsExpose:
364 {
365 wxLogTrace( _T("expose"), _T("GraphicsExpose from %s"), win->GetName().c_str());
366
367 win->GetUpdateRegion().Union( event->xgraphicsexpose.x, event->xgraphicsexpose.y,
368 event->xgraphicsexpose.width, event->xgraphicsexpose.height);
369
370 win->GetClearRegion().Union( event->xgraphicsexpose.x, event->xgraphicsexpose.y,
371 event->xgraphicsexpose.width, event->xgraphicsexpose.height);
372
373 if (event->xgraphicsexpose.count == 0)
374 {
375 // Only erase background, paint in idle time.
376 win->SendEraseEvents();
377 // win->Update();
378 }
379
380 return true;
381 }
382 #endif
383
384 case KeyPress:
385 {
386 if (!win->IsEnabled())
387 return false;
388
389 wxKeyEvent keyEvent(wxEVT_KEY_DOWN);
390 wxTranslateKeyEvent(keyEvent, win, window, event);
391
392 // wxLogDebug( "OnKey from %s", win->GetName().c_str() );
393
394 // We didn't process wxEVT_KEY_DOWN, so send wxEVT_CHAR
395 if (win->GetEventHandler()->ProcessEvent( keyEvent ))
396 return true;
397
398 keyEvent.SetEventType(wxEVT_CHAR);
399 // Do the translation again, retaining the ASCII
400 // code.
401 wxTranslateKeyEvent(keyEvent, win, window, event, true);
402 if (win->GetEventHandler()->ProcessEvent( keyEvent ))
403 return true;
404
405 if ( (keyEvent.m_keyCode == WXK_TAB) &&
406 win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
407 {
408 wxNavigationKeyEvent new_event;
409 new_event.SetEventObject( win->GetParent() );
410 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
411 new_event.SetDirection( (keyEvent.m_keyCode == WXK_TAB) );
412 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
413 new_event.SetWindowChange( keyEvent.ControlDown() );
414 new_event.SetCurrentFocus( win );
415 return win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
416 }
417
418 return false;
419 }
420 case KeyRelease:
421 {
422 if (!win->IsEnabled())
423 return false;
424
425 wxKeyEvent keyEvent(wxEVT_KEY_UP);
426 wxTranslateKeyEvent(keyEvent, win, window, event);
427
428 return win->GetEventHandler()->ProcessEvent( keyEvent );
429 }
430 case ConfigureNotify:
431 {
432 #if wxUSE_NANOX
433 if (event->update.utype == GR_UPDATE_SIZE)
434 #endif
435 {
436 wxTopLevelWindow *tlw = wxDynamicCast(win, wxTopLevelWindow);
437 if ( tlw )
438 {
439 tlw->SetConfigureGeometry( XConfigureEventGetX(event), XConfigureEventGetY(event),
440 XConfigureEventGetWidth(event), XConfigureEventGetHeight(event) );
441 }
442
443 if ( tlw && tlw->IsShown() )
444 {
445 tlw->SetNeedResizeInIdle();
446 }
447 else
448 {
449 wxSizeEvent sizeEvent( wxSize(XConfigureEventGetWidth(event), XConfigureEventGetHeight(event)), win->GetId() );
450 sizeEvent.SetEventObject( win );
451
452 return win->GetEventHandler()->ProcessEvent( sizeEvent );
453 }
454 }
455 return false;
456 }
457 #if !wxUSE_NANOX
458 case PropertyNotify:
459 {
460 //wxLogDebug("PropertyNotify: %s", windowClass.c_str());
461 return HandlePropertyChange(_event);
462 }
463 case ClientMessage:
464 {
465 if (!win->IsEnabled())
466 return false;
467
468 Atom wm_delete_window = XInternAtom(wxGlobalDisplay(), "WM_DELETE_WINDOW", True);
469 Atom wm_protocols = XInternAtom(wxGlobalDisplay(), "WM_PROTOCOLS", True);
470
471 if (event->xclient.message_type == wm_protocols)
472 {
473 if ((Atom) (event->xclient.data.l[0]) == wm_delete_window)
474 {
475 win->Close(false);
476 return true;
477 }
478 }
479 return false;
480 }
481 #if 0
482 case DestroyNotify:
483 {
484 printf( "destroy from %s\n", win->GetName().c_str() );
485 break;
486 }
487 case CreateNotify:
488 {
489 printf( "create from %s\n", win->GetName().c_str() );
490 break;
491 }
492 case MapRequest:
493 {
494 printf( "map request from %s\n", win->GetName().c_str() );
495 break;
496 }
497 case ResizeRequest:
498 {
499 printf( "resize request from %s\n", win->GetName().c_str() );
500
501 Display *disp = (Display*) wxGetDisplay();
502 XEvent report;
503
504 // to avoid flicker
505 report = * event;
506 while( XCheckTypedWindowEvent (disp, actualWindow, ResizeRequest, &report));
507
508 wxSize sz = win->GetSize();
509 wxSizeEvent sizeEvent(sz, win->GetId());
510 sizeEvent.SetEventObject(win);
511
512 return win->GetEventHandler()->ProcessEvent( sizeEvent );
513 }
514 #endif
515 #endif
516 #if wxUSE_NANOX
517 case GR_EVENT_TYPE_CLOSE_REQ:
518 {
519 if (win)
520 {
521 win->Close(false);
522 return true;
523 }
524 return false;
525 break;
526 }
527 #endif
528 case EnterNotify:
529 case LeaveNotify:
530 case ButtonPress:
531 case ButtonRelease:
532 case MotionNotify:
533 {
534 if (!win->IsEnabled())
535 return false;
536
537 // Here we check if the top level window is
538 // disabled, which is one aspect of modality.
539 wxWindow *tlw = win;
540 while (tlw && !tlw->IsTopLevel())
541 tlw = tlw->GetParent();
542 if (tlw && !tlw->IsEnabled())
543 return false;
544
545 if (event->type == ButtonPress)
546 {
547 if ((win != wxWindow::FindFocus()) && win->AcceptsFocus())
548 {
549 // This might actually be done in wxWindow::SetFocus()
550 // and not here. TODO.
551 g_prevFocus = wxWindow::FindFocus();
552 g_nextFocus = win;
553
554 wxLogTrace( _T("focus"), _T("About to call SetFocus on %s of type %s due to button press"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() );
555
556 // Record the fact that this window is
557 // getting the focus, because we'll need to
558 // check if its parent is getting a bogus
559 // focus and duly ignore it.
560 // TODO: may need to have this code in SetFocus, too.
561 extern wxWindow* g_GettingFocus;
562 g_GettingFocus = win;
563 win->SetFocus();
564 }
565 }
566
567 #if !wxUSE_NANOX
568 if (event->type == LeaveNotify || event->type == EnterNotify)
569 {
570 // Throw out NotifyGrab and NotifyUngrab
571 if (event->xcrossing.mode != NotifyNormal)
572 return false;
573 }
574 #endif
575 wxMouseEvent wxevent;
576 wxTranslateMouseEvent(wxevent, win, window, event);
577 return win->GetEventHandler()->ProcessEvent( wxevent );
578 }
579 case FocusIn:
580 #if !wxUSE_NANOX
581 if ((event->xfocus.detail != NotifyPointer) &&
582 (event->xfocus.mode == NotifyNormal))
583 #endif
584 {
585 wxLogTrace( _T("focus"), _T("FocusIn from %s of type %s"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() );
586
587 extern wxWindow* g_GettingFocus;
588 if (g_GettingFocus && g_GettingFocus->GetParent() == win)
589 {
590 // Ignore this, this can be a spurious FocusIn
591 // caused by a child having its focus set.
592 g_GettingFocus = NULL;
593 wxLogTrace( _T("focus"), _T("FocusIn from %s of type %s being deliberately ignored"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() );
594 return true;
595 }
596 else
597 {
598 wxFocusEvent focusEvent(wxEVT_SET_FOCUS, win->GetId());
599 focusEvent.SetEventObject(win);
600 focusEvent.SetWindow( g_prevFocus );
601 g_prevFocus = NULL;
602
603 return win->GetEventHandler()->ProcessEvent(focusEvent);
604 }
605 }
606 return false;
607
608 case FocusOut:
609 #if !wxUSE_NANOX
610 if ((event->xfocus.detail != NotifyPointer) &&
611 (event->xfocus.mode == NotifyNormal))
612 #endif
613 {
614 wxLogTrace( _T("focus"), _T("FocusOut from %s of type %s"), win->GetName().c_str(), win->GetClassInfo()->GetClassName() );
615
616 wxFocusEvent focusEvent(wxEVT_KILL_FOCUS, win->GetId());
617 focusEvent.SetEventObject(win);
618 focusEvent.SetWindow( g_nextFocus );
619 g_nextFocus = NULL;
620 return win->GetEventHandler()->ProcessEvent(focusEvent);
621 }
622 return false;
623
624 #ifdef __WXDEBUG__
625 default:
626 //wxString eventName = wxGetXEventName(XEvent& event);
627 //wxLogDebug(wxT("Event %s not handled"), eventName.c_str());
628 break;
629 #endif // __WXDEBUG__
630 }
631
632 return false;
633 }
634
635 // This should be redefined in a derived class for
636 // handling property change events for XAtom IPC.
637 bool wxApp::HandlePropertyChange(WXEvent *event)
638 {
639 // by default do nothing special
640 // TODO: what to do for X11
641 // XtDispatchEvent((XEvent*) event);
642 return false;
643 }
644
645 void wxApp::WakeUpIdle()
646 {
647 // TODO: use wxMotif implementation?
648
649 // Wake up the idle handler processor, even if it is in another thread...
650 }
651
652
653 // Create display, and other initialization
654 bool wxApp::OnInitGui()
655 {
656 #if wxUSE_LOG
657 // Eventually this line will be removed, but for
658 // now we don't want to try popping up a dialog
659 // for error messages.
660 delete wxLog::SetActiveTarget(new wxLogStderr);
661 #endif
662
663 if (!wxAppBase::OnInitGui())
664 return false;
665
666 Display *dpy = wxGlobalDisplay();
667 GetMainColormap(dpy);
668
669 m_maxRequestSize = XMaxRequestSize(dpy);
670
671 #if !wxUSE_NANOX
672 m_visualInfo = new wxXVisualInfo;
673 wxFillXVisualInfo(m_visualInfo, dpy);
674 #endif
675
676 return true;
677 }
678
679 #if wxUSE_UNICODE
680
681 #include <pango/pango.h>
682 #include <pango/pangox.h>
683 #ifdef HAVE_PANGO_XFT
684 #include <pango/pangoxft.h>
685 #endif
686
687 PangoContext* wxApp::GetPangoContext()
688 {
689 static PangoContext *s_pangoContext = NULL;
690 if ( !s_pangoContext )
691 {
692 Display *dpy = wxGlobalDisplay();
693
694 #ifdef HAVE_PANGO_XFT
695 int xscreen = DefaultScreen(dpy);
696 static int use_xft = -1;
697 if (use_xft == -1)
698 {
699 wxString val = wxGetenv( L"GDK_USE_XFT" );
700 use_xft = val == L"1";
701 }
702
703 if (use_xft)
704 s_pangoContext = pango_xft_get_context(dpy, xscreen);
705 else
706 #endif // HAVE_PANGO_XFT
707 s_pangoContext = pango_x_get_context(dpy);
708
709 if (!PANGO_IS_CONTEXT(s_pangoContext))
710 wxLogError( wxT("No pango context.") );
711 }
712
713 return s_pangoContext;
714 }
715
716 #endif // wxUSE_UNICODE
717
718 WXColormap wxApp::GetMainColormap(WXDisplay* display)
719 {
720 if (!display) /* Must be called first with non-NULL display */
721 return m_mainColormap;
722
723 int defaultScreen = DefaultScreen((Display*) display);
724 Screen* screen = XScreenOfDisplay((Display*) display, defaultScreen);
725
726 Colormap c = DefaultColormapOfScreen(screen);
727
728 if (!m_mainColormap)
729 m_mainColormap = (WXColormap) c;
730
731 return (WXColormap) c;
732 }
733
734 Window wxGetWindowParent(Window window)
735 {
736 wxASSERT_MSG( window, _T("invalid window") );
737
738 return (Window) 0;
739
740 #ifndef __VMS
741 // VMS chokes on unreacheable code
742 Window parent, root = 0;
743 #if wxUSE_NANOX
744 int noChildren = 0;
745 #else
746 unsigned int noChildren = 0;
747 #endif
748 Window* children = NULL;
749
750 // #define XQueryTree(d,w,r,p,c,nc) GrQueryTree(w,p,c,nc)
751 int res = 1;
752 #if !wxUSE_NANOX
753 res =
754 #endif
755 XQueryTree((Display*) wxGetDisplay(), window, & root, & parent,
756 & children, & noChildren);
757 if (children)
758 XFree(children);
759 if (res)
760 return parent;
761 else
762 return (Window) 0;
763 #endif
764 }
765
766 void wxApp::Exit()
767 {
768 wxApp::CleanUp();
769
770 wxAppConsole::Exit();
771 }
772
773 // Yield to other processes
774
775 bool wxApp::Yield(bool onlyIfNeeded)
776 {
777 // Sometimes only 2 yields seem
778 // to do the trick, e.g. in the
779 // progress dialog
780 int i;
781 for (i = 0; i < 2; i++)
782 {
783 static bool s_inYield = false;
784
785 if ( s_inYield )
786 {
787 if ( !onlyIfNeeded )
788 {
789 wxFAIL_MSG( wxT("wxYield called recursively" ) );
790 }
791
792 return false;
793 }
794
795 s_inYield = true;
796
797 // Make sure we have an event loop object,
798 // or Pending/Dispatch will fail
799 wxEventLoop* eventLoop = wxEventLoop::GetActive();
800 wxEventLoop* newEventLoop = NULL;
801 if (!eventLoop)
802 {
803 newEventLoop = new wxEventLoop;
804 wxEventLoop::SetActive(newEventLoop);
805 }
806
807 // Call dispatch at least once so that sockets
808 // can be tested
809 wxTheApp->Dispatch();
810
811 while (wxTheApp && wxTheApp->Pending())
812 wxTheApp->Dispatch();
813
814 #if wxUSE_TIMER
815 wxTimer::NotifyTimers();
816 #endif
817 ProcessIdle();
818
819 if (newEventLoop)
820 {
821 wxEventLoop::SetActive(NULL);
822 delete newEventLoop;
823 }
824
825 s_inYield = false;
826 }
827
828 return true;
829 }
830
831 #ifdef __WXDEBUG__
832
833 void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
834 {
835 // While the GUI isn't working that well, just print out the
836 // message.
837 #if 1
838 wxAppBase::OnAssert(file, line, cond, msg);
839 #else
840 wxString msg2;
841 msg2.Printf("At file %s:%d: %s", file, line, msg);
842 wxLogDebug(msg2);
843 #endif
844 }
845
846 #endif // __WXDEBUG__