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