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