fixed cleanup order to behave correctly in presence of exceptions
[wxWidgets.git] / src / msw / app.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: app.cpp
3 // Purpose: wxApp
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "app.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #if defined(__BORLANDC__)
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/frame.h"
33 #include "wx/app.h"
34 #include "wx/utils.h"
35 #include "wx/gdicmn.h"
36 #include "wx/pen.h"
37 #include "wx/brush.h"
38 #include "wx/cursor.h"
39 #include "wx/icon.h"
40 #include "wx/palette.h"
41 #include "wx/dc.h"
42 #include "wx/dialog.h"
43 #include "wx/msgdlg.h"
44 #include "wx/intl.h"
45 #include "wx/dynarray.h"
46 #include "wx/wxchar.h"
47 #include "wx/icon.h"
48 #include "wx/log.h"
49 #endif
50
51 #include "wx/apptrait.h"
52 #include "wx/filename.h"
53 #include "wx/module.h"
54 #include "wx/dynlib.h"
55
56 #include "wx/msw/private.h"
57
58 #if wxUSE_TOOLTIPS
59 #include "wx/tooltip.h"
60 #endif // wxUSE_TOOLTIPS
61
62 // OLE is used for drag-and-drop, clipboard, OLE Automation..., but some
63 // compilers don't support it (missing headers, libs, ...)
64 #if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__) || defined(__SALFORDC__)
65 #undef wxUSE_OLE
66
67 #define wxUSE_OLE 0
68 #endif // broken compilers
69
70 #if wxUSE_OLE
71 #include <ole2.h>
72 #endif
73
74 #include <string.h>
75 #include <ctype.h>
76
77 #include "wx/msw/wrapcctl.h"
78
79 #if (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \
80 !defined(__CYGWIN__) && !defined(__DIGITALMARS__) && !defined(__WXWINCE__) && \
81 (!defined(_MSC_VER) || (_MSC_VER > 1100))
82 #include <shlwapi.h>
83 #endif
84
85 // ---------------------------------------------------------------------------
86 // global variables
87 // ---------------------------------------------------------------------------
88
89 extern wxList WXDLLEXPORT wxPendingDelete;
90
91 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
92 extern void wxSetKeyboardHook(bool doIt);
93 #endif
94
95 // NB: all "NoRedraw" classes must have the same names as the "normal" classes
96 // with NR suffix - wxWindow::MSWCreate() supposes this
97 const wxChar *wxCanvasClassName = wxT("wxWindowClass");
98 const wxChar *wxCanvasClassNameNR = wxT("wxWindowClassNR");
99 const wxChar *wxMDIFrameClassName = wxT("wxMDIFrameClass");
100 const wxChar *wxMDIFrameClassNameNoRedraw = wxT("wxMDIFrameClassNR");
101 const wxChar *wxMDIChildFrameClassName = wxT("wxMDIChildFrameClass");
102 const wxChar *wxMDIChildFrameClassNameNoRedraw = wxT("wxMDIChildFrameClassNR");
103
104 HBRUSH wxDisableButtonBrush = (HBRUSH) 0;
105
106 // ----------------------------------------------------------------------------
107 // private functions
108 // ----------------------------------------------------------------------------
109
110 LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
111
112 // ===========================================================================
113 // wxGUIAppTraits implementation
114 // ===========================================================================
115
116 // private class which we use to pass parameters from BeforeChildWaitLoop() to
117 // AfterChildWaitLoop()
118 struct ChildWaitLoopData
119 {
120 ChildWaitLoopData(wxWindowDisabler *wd_, wxWindow *winActive_)
121 {
122 wd = wd_;
123 winActive = winActive_;
124 }
125
126 wxWindowDisabler *wd;
127 wxWindow *winActive;
128 };
129
130 void *wxGUIAppTraits::BeforeChildWaitLoop()
131 {
132 /*
133 We use a dirty hack here to disable all application windows (which we
134 must do because otherwise the calls to wxYield() could lead to some very
135 unexpected reentrancies in the users code) but to avoid losing
136 focus/activation entirely when the child process terminates which would
137 happen if we simply disabled everything using wxWindowDisabler. Indeed,
138 remember that Windows will never activate a disabled window and when the
139 last childs window is closed and Windows looks for a window to activate
140 all our windows are still disabled. There is no way to enable them in
141 time because we don't know when the childs windows are going to be
142 closed, so the solution we use here is to keep one special tiny frame
143 enabled all the time. Then when the child terminates it will get
144 activated and when we close it below -- after reenabling all the other
145 windows! -- the previously active window becomes activated again and
146 everything is ok.
147 */
148 wxBeginBusyCursor();
149
150 // first disable all existing windows
151 wxWindowDisabler *wd = new wxWindowDisabler;
152
153 // then create an "invisible" frame: it has minimal size, is positioned
154 // (hopefully) outside the screen and doesn't appear on the taskbar
155 wxWindow *winActive = new wxFrame
156 (
157 wxTheApp->GetTopWindow(),
158 wxID_ANY,
159 wxEmptyString,
160 wxPoint(32600, 32600),
161 wxSize(1, 1),
162 wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR
163 );
164 winActive->Show();
165
166 return new ChildWaitLoopData(wd, winActive);
167 }
168
169 void wxGUIAppTraits::AlwaysYield()
170 {
171 wxYield();
172 }
173
174 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
175 {
176 wxEndBusyCursor();
177
178 const ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig;
179
180 delete data->wd;
181
182 // finally delete the dummy frame and, as wd has been already destroyed and
183 // the other windows reenabled, the activation is going to return to the
184 // window which had had it before
185 data->winActive->Destroy();
186 }
187
188 bool wxGUIAppTraits::DoMessageFromThreadWait()
189 {
190 // we should return false only if the app should exit, i.e. only if
191 // Dispatch() determines that the main event loop should terminate
192 return !wxTheApp || wxTheApp->Dispatch();
193 }
194
195 wxToolkitInfo& wxGUIAppTraits::GetToolkitInfo()
196 {
197 static wxToolkitInfo info;
198 wxToolkitInfo& baseInfo = wxAppTraits::GetToolkitInfo();
199 info.versionMajor = baseInfo.versionMajor;
200 info.versionMinor = baseInfo.versionMinor;
201 info.os = baseInfo.os;
202 info.shortName = _T("msw");
203 info.name = _T("wxMSW");
204 #ifdef __WXUNIVERSAL__
205 info.shortName << _T("univ");
206 info.name << _T("/wxUniversal");
207 #endif
208 return info;
209 }
210
211 // ===========================================================================
212 // wxApp implementation
213 // ===========================================================================
214
215 int wxApp::m_nCmdShow = SW_SHOWNORMAL;
216
217 // ---------------------------------------------------------------------------
218 // wxWin macros
219 // ---------------------------------------------------------------------------
220
221 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
222
223 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
224 EVT_IDLE(wxApp::OnIdle)
225 EVT_END_SESSION(wxApp::OnEndSession)
226 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
227 END_EVENT_TABLE()
228
229 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
230 // fails
231 class wxCallBaseCleanup
232 {
233 public:
234 wxCallBaseCleanup(wxApp *app) : m_app(app) { }
235 ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
236
237 void Dismiss() { m_app = NULL; }
238
239 private:
240 wxApp *m_app;
241 };
242
243 //// Initialize
244 bool wxApp::Initialize(int& argc, wxChar **argv)
245 {
246 if ( !wxAppBase::Initialize(argc, argv) )
247 return false;
248
249 // ensure that base cleanup is done if we return too early
250 wxCallBaseCleanup callBaseCleanup(this);
251
252 // the first thing to do is to check if we're trying to run an Unicode
253 // program under Win9x w/o MSLU emulation layer - if so, abort right now
254 // as it has no chance to work
255 #if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
256 if ( wxGetOsVersion() != wxWINDOWS_NT && wxGetOsVersion() != wxWINDOWS_CE )
257 {
258 // note that we can use MessageBoxW() as it's implemented even under
259 // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs
260 // used by wxLocale are not
261 ::MessageBox
262 (
263 NULL,
264 _T("This program uses Unicode and requires Windows NT/2000/XP/CE.\nProgram aborted."),
265 _T("wxWindows Fatal Error"),
266 MB_ICONERROR | MB_OK
267 );
268
269 return FALSE;
270 }
271 #endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
272
273 #if defined(__WIN95__) && !defined(__WXMICROWIN__)
274 InitCommonControls();
275 #endif // __WIN95__
276
277 #if wxUSE_OLE || wxUSE_DRAG_AND_DROP
278
279 #ifdef __WIN16__
280 // for OLE, enlarge message queue to be as large as possible
281 int iMsg = 96;
282 while (!SetMessageQueue(iMsg) && (iMsg -= 8))
283 ;
284 #endif // Win16
285
286 #if wxUSE_OLE
287 // we need to initialize OLE library
288 #ifdef __WXWINCE__
289 if ( FAILED(::CoInitializeEx(NULL, COINIT_MULTITHREADED)) )
290 wxLogError(_("Cannot initialize OLE"));
291 #else
292 if ( FAILED(::OleInitialize(NULL)) )
293 wxLogError(_("Cannot initialize OLE"));
294 #endif
295 #endif
296
297 #endif // wxUSE_OLE
298
299 #if wxUSE_CTL3D
300 if (!Ctl3dRegister(wxhInstance))
301 wxLogError(wxT("Cannot register CTL3D"));
302
303 Ctl3dAutoSubclass(wxhInstance);
304 #endif // wxUSE_CTL3D
305
306 RegisterWindowClasses();
307
308 #if defined(__WXMICROWIN__) && !defined(__WXWINCE__)
309 // Create the brush for disabling bitmap buttons
310
311 LOGBRUSH lb;
312 lb.lbStyle = BS_PATTERN;
313 lb.lbColor = 0;
314 lb.lbHatch = (int)LoadBitmap( wxhInstance, wxT("wxDISABLE_BUTTON_BITMAP") );
315 if ( lb.lbHatch )
316 {
317 wxDisableButtonBrush = ::CreateBrushIndirect( & lb );
318 ::DeleteObject( (HGDIOBJ)lb.lbHatch );
319 }
320 //else: wxWindows resources are probably not linked in
321 #endif
322
323 #if wxUSE_PENWINDOWS
324 wxRegisterPenWin();
325 #endif
326
327 wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
328
329 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
330 // PLEASE DO NOT ALTER THIS.
331 #if defined(__VISUALC__) && defined(__WIN16__) && !defined(WXMAKINGDLL)
332 extern char wxDummyChar;
333 if (wxDummyChar) wxDummyChar++;
334 #endif
335
336 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
337 wxSetKeyboardHook(TRUE);
338 #endif
339
340 callBaseCleanup.Dismiss();
341
342 return true;
343 }
344
345 // ---------------------------------------------------------------------------
346 // RegisterWindowClasses
347 // ---------------------------------------------------------------------------
348
349 // TODO we should only register classes really used by the app. For this it
350 // would be enough to just delay the class registration until an attempt
351 // to create a window of this class is made.
352 bool wxApp::RegisterWindowClasses()
353 {
354 WNDCLASS wndclass;
355 wxZeroMemory(wndclass);
356
357 // for each class we register one with CS_(V|H)REDRAW style and one
358 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
359 static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
360 static const long styleNoRedraw = CS_DBLCLKS;
361
362 // the fields which are common to all classes
363 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
364 wndclass.hInstance = wxhInstance;
365 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
366
367 // Register the frame window class.
368 wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
369 wndclass.lpszClassName = wxCanvasClassName;
370 wndclass.style = styleNormal;
371
372 if ( !RegisterClass(&wndclass) )
373 {
374 wxLogLastError(wxT("RegisterClass(frame)"));
375 }
376
377 // "no redraw" frame
378 wndclass.lpszClassName = wxCanvasClassNameNR;
379 wndclass.style = styleNoRedraw;
380
381 if ( !RegisterClass(&wndclass) )
382 {
383 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
384 }
385
386 // Register the MDI frame window class.
387 wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
388 wndclass.lpszClassName = wxMDIFrameClassName;
389 wndclass.style = styleNormal;
390
391 if ( !RegisterClass(&wndclass) )
392 {
393 wxLogLastError(wxT("RegisterClass(MDI parent)"));
394 }
395
396 // "no redraw" MDI frame
397 wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
398 wndclass.style = styleNoRedraw;
399
400 if ( !RegisterClass(&wndclass) )
401 {
402 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
403 }
404
405 // Register the MDI child frame window class.
406 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
407 wndclass.lpszClassName = wxMDIChildFrameClassName;
408 wndclass.style = styleNormal;
409
410 if ( !RegisterClass(&wndclass) )
411 {
412 wxLogLastError(wxT("RegisterClass(MDI child)"));
413 }
414
415 // "no redraw" MDI child frame
416 wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
417 wndclass.style = styleNoRedraw;
418
419 if ( !RegisterClass(&wndclass) )
420 {
421 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
422 }
423
424 return TRUE;
425 }
426
427 // ---------------------------------------------------------------------------
428 // UnregisterWindowClasses
429 // ---------------------------------------------------------------------------
430
431 bool wxApp::UnregisterWindowClasses()
432 {
433 bool retval = TRUE;
434
435 #ifndef __WXMICROWIN__
436 // MDI frame window class.
437 if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
438 {
439 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
440
441 retval = FALSE;
442 }
443
444 // "no redraw" MDI frame
445 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
446 {
447 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
448
449 retval = FALSE;
450 }
451
452 // MDI child frame window class.
453 if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
454 {
455 wxLogLastError(wxT("UnregisterClass(MDI child)"));
456
457 retval = FALSE;
458 }
459
460 // "no redraw" MDI child frame
461 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
462 {
463 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
464
465 retval = FALSE;
466 }
467
468 // canvas class name
469 if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
470 {
471 wxLogLastError(wxT("UnregisterClass(canvas)"));
472
473 retval = FALSE;
474 }
475
476 if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
477 {
478 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
479
480 retval = FALSE;
481 }
482 #endif // __WXMICROWIN__
483
484 return retval;
485 }
486
487 void wxApp::CleanUp()
488 {
489 // all objects pending for deletion must be deleted first, otherwise we
490 // would crash when they use wxWinHandleHash (and UnregisterWindowClasses()
491 // call wouldn't succeed as long as any windows still exist), so call the
492 // base class method first and only then do our clean up
493 wxAppBase::CleanUp();
494
495 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
496 wxSetKeyboardHook(FALSE);
497 #endif
498
499 #if wxUSE_PENWINDOWS
500 wxCleanUpPenWin();
501 #endif
502
503 if ( wxDisableButtonBrush )
504 ::DeleteObject( wxDisableButtonBrush );
505
506 #if wxUSE_OLE
507 #ifdef __WXWINCE__
508 ::CoUninitialize();
509 #else
510 ::OleUninitialize();
511 #endif
512 #endif
513
514 // for an EXE the classes are unregistered when it terminates but DLL may
515 // be loaded several times (load/unload/load) into the same process in
516 // which case the registration will fail after the first time if we don't
517 // unregister the classes now
518 UnregisterWindowClasses();
519
520 #if wxUSE_CTL3D
521 Ctl3dUnregister(wxhInstance);
522 #endif
523
524 delete wxWinHandleHash;
525 wxWinHandleHash = NULL;
526 }
527
528 // ----------------------------------------------------------------------------
529 // wxApp ctor/dtor
530 // ----------------------------------------------------------------------------
531
532 wxApp::wxApp()
533 {
534 m_printMode = wxPRINT_WINDOWS;
535 }
536
537 wxApp::~wxApp()
538 {
539 // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
540 // don't come from main(), so we have to free them
541
542 while ( argc )
543 {
544 // m_argv elements were allocated by wxStrdup()
545 free(argv[--argc]);
546 }
547
548 // but m_argv itself -- using new[]
549 delete [] argv;
550 }
551
552 bool wxApp::Initialized()
553 {
554 #ifndef _WINDLL
555 if (GetTopWindow())
556 return TRUE;
557 else
558 return FALSE;
559 #else // Assume initialized if DLL (no way of telling)
560 return TRUE;
561 #endif
562 }
563
564 void wxApp::OnIdle(wxIdleEvent& event)
565 {
566 wxAppBase::OnIdle(event);
567
568 #if wxUSE_DC_CACHEING
569 // automated DC cache management: clear the cached DCs and bitmap
570 // if it's likely that the app has finished with them, that is, we
571 // get an idle event and we're not dragging anything.
572 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
573 wxDC::ClearCache();
574 #endif // wxUSE_DC_CACHEING
575 }
576
577 void wxApp::WakeUpIdle()
578 {
579 // Send the top window a dummy message so idle handler processing will
580 // start up again. Doing it this way ensures that the idle handler
581 // wakes up in the right thread (see also wxWakeUpMainThread() which does
582 // the same for the main app thread only)
583 wxWindow *topWindow = wxTheApp->GetTopWindow();
584 if ( topWindow )
585 {
586 if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
587 {
588 // should never happen
589 wxLogLastError(wxT("PostMessage(WM_NULL)"));
590 }
591 }
592 }
593
594 void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
595 {
596 if (GetTopWindow())
597 GetTopWindow()->Close(TRUE);
598 }
599
600 // Default behaviour: close the application with prompts. The
601 // user can veto the close, and therefore the end session.
602 void wxApp::OnQueryEndSession(wxCloseEvent& event)
603 {
604 if (GetTopWindow())
605 {
606 if (!GetTopWindow()->Close(!event.CanVeto()))
607 event.Veto(TRUE);
608 }
609 }
610
611 /* static */
612 int wxApp::GetComCtl32Version()
613 {
614 //FIX ME FOR DIGITALMARS!!
615 #if defined(__WXMICROWIN__) || defined(__WXWINCE__) || defined(__DIGITALMARS__)
616 return 0;
617 #else
618 // cache the result
619 //
620 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
621 // but as its value should be the same both times it doesn't matter
622 static int s_verComCtl32 = -1;
623
624 if ( s_verComCtl32 == -1 )
625 {
626 // initally assume no comctl32.dll at all
627 s_verComCtl32 = 0;
628
629 // we're prepared to handle the errors
630 wxLogNull noLog;
631
632 // do we have it?
633 wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
634
635 // if so, then we can check for the version
636 if ( dllComCtl32.IsLoaded() )
637 {
638 #ifdef DLLVER_PLATFORM_WINDOWS
639 // try to use DllGetVersion() if available in _headers_
640 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dllComCtl32 );
641 if ( pfnDllGetVersion )
642 {
643 DLLVERSIONINFO dvi;
644 dvi.cbSize = sizeof(dvi);
645
646 HRESULT hr = (*pfnDllGetVersion)(&dvi);
647 if ( FAILED(hr) )
648 {
649 wxLogApiError(_T("DllGetVersion"), hr);
650 }
651 else
652 {
653 // this is incompatible with _WIN32_IE values, but
654 // compatible with the other values returned by
655 // GetComCtl32Version()
656 s_verComCtl32 = 100*dvi.dwMajorVersion +
657 dvi.dwMinorVersion;
658 }
659 }
660 #endif
661
662 // if DllGetVersion() is unavailable either during compile or
663 // run-time, try to guess the version otherwise
664 if ( !s_verComCtl32 )
665 {
666 // InitCommonControlsEx is unique to 4.70 and later
667 void *pfn = dllComCtl32.GetSymbol(_T("InitCommonControlsEx"));
668 if ( !pfn )
669 {
670 // not found, must be 4.00
671 s_verComCtl32 = 400;
672 }
673 else // 4.70+
674 {
675 // many symbols appeared in comctl32 4.71, could use any of
676 // them except may be DllInstall()
677 pfn = dllComCtl32.GetSymbol(_T("InitializeFlatSB"));
678 if ( !pfn )
679 {
680 // not found, must be 4.70
681 s_verComCtl32 = 470;
682 }
683 else
684 {
685 // found, must be 4.71 or later
686 s_verComCtl32 = 471;
687 }
688 }
689 }
690 }
691 }
692
693 return s_verComCtl32;
694 #endif // Microwin/!Microwin
695 }
696
697 // Yield to incoming messages
698
699 bool wxApp::Yield(bool onlyIfNeeded)
700 {
701 // MT-FIXME
702 static bool s_inYield = FALSE;
703
704 #if wxUSE_LOG
705 // disable log flushing from here because a call to wxYield() shouldn't
706 // normally result in message boxes popping up &c
707 wxLog::Suspend();
708 #endif // wxUSE_LOG
709
710 if ( s_inYield )
711 {
712 if ( !onlyIfNeeded )
713 {
714 wxFAIL_MSG( wxT("wxYield called recursively" ) );
715 }
716
717 return FALSE;
718 }
719
720 s_inYield = TRUE;
721
722 // we don't want to process WM_QUIT from here - it should be processed in
723 // the main event loop in order to stop it
724 MSG msg;
725 while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
726 msg.message != WM_QUIT )
727 {
728 #if wxUSE_THREADS
729 wxMutexGuiLeaveOrEnter();
730 #endif // wxUSE_THREADS
731
732 if ( !wxTheApp->Dispatch() )
733 break;
734 }
735
736 // if there are pending events, we must process them.
737 ProcessPendingEvents();
738
739 #if wxUSE_LOG
740 // let the logs be flashed again
741 wxLog::Resume();
742 #endif // wxUSE_LOG
743
744 s_inYield = FALSE;
745
746 return TRUE;
747 }
748