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: app.cpp 61713 2009-08-20 00:01:55Z VZ $ 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 49wxWindowHash *wxWidgetHashTable = NULL; 50wxWindowHash *wxClientWidgetHashTable = NULL; 51 52static bool g_showIconic = false; 53static 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. 59static wxWindow *g_nextFocus = NULL; 60static wxWindow *g_prevFocus = NULL; 61 62//------------------------------------------------------------------------ 63// X11 error handling 64//------------------------------------------------------------------------ 65 66#ifdef __WXDEBUG__ 67typedef int (*XErrorHandlerFunc)(Display *, XErrorEvent *); 68 69XErrorHandlerFunc gs_pfnXErrorHandler = 0; 70 71static 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 85long wxApp::sm_lastMessageTime = 0; 86 87IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler) 88 89BEGIN_EVENT_TABLE(wxApp, wxEvtHandler) 90 EVT_IDLE(wxAppBase::OnIdle) 91END_EVENT_TABLE() 92 93bool 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 < (argCOrig - 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 < (argCOrig - 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 arguments 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)*sizeof(wxChar *)); 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 201void wxApp::CleanUp() 202{ 203 delete wxWidgetHashTable; 204 wxWidgetHashTable = NULL; 205 delete wxClientWidgetHashTable; 206 wxClientWidgetHashTable = NULL; 207 208 wxAppBase::CleanUp(); 209} 210 211wxApp::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 224wxApp::~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 237struct wxExposeInfo 238{ 239 Window window; 240 Bool found_non_matching; 241}; 242 243extern "C" 244Bool 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 272bool 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 if (wxTranslateKeyEvent(keyEvent, win, window, event, true) && 402 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. 637bool 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 645void 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 654bool 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 687PangoContext* 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 718WXColormap 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 734Window 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 766void wxApp::Exit() 767{ 768 wxApp::CleanUp(); 769 770 wxAppConsole::Exit(); 771} 772 773// Yield to other processes 774 775bool 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 wxEventLoopGuarantor dummyLoopIfNeeded; 800 801 // Call dispatch at least once so that sockets 802 // can be tested 803 wxTheApp->Dispatch(); 804 805 while (wxTheApp && wxTheApp->Pending()) 806 wxTheApp->Dispatch(); 807 808#if wxUSE_TIMER 809 wxTimer::NotifyTimers(); 810#endif 811 ProcessIdle(); 812 813 s_inYield = false; 814 } 815 816 return true; 817} 818 819#ifdef __WXDEBUG__ 820 821void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg) 822{ 823 // While the GUI isn't working that well, just print out the 824 // message. 825#if 1 826 wxAppBase::OnAssert(file, line, cond, msg); 827#else 828 wxString msg2; 829 msg2.Printf("At file %s:%d: %s", file, line, msg); 830 wxLogDebug(msg2); 831#endif 832} 833 834#endif // __WXDEBUG__ 835