removed wxMsgArray definition (now in evtloop.cpp) and OnIdle() sempaphore (shouldn...
[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 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
490 wxSetKeyboardHook(FALSE);
491 #endif
492
493 #if wxUSE_PENWINDOWS
494 wxCleanUpPenWin();
495 #endif
496
497 if ( wxDisableButtonBrush )
498 ::DeleteObject( wxDisableButtonBrush );
499
500 #if wxUSE_OLE
501 #ifdef __WXWINCE__
502 ::CoUninitialize();
503 #else
504 ::OleUninitialize();
505 #endif
506 #endif
507
508 // for an EXE the classes are unregistered when it terminates but DLL may
509 // be loaded several times (load/unload/load) into the same process in
510 // which case the registration will fail after the first time if we don't
511 // unregister the classes now
512 UnregisterWindowClasses();
513
514 #if wxUSE_CTL3D
515 Ctl3dUnregister(wxhInstance);
516 #endif
517
518 delete wxWinHandleHash;
519 wxWinHandleHash = NULL;
520
521 wxAppBase::CleanUp();
522 }
523
524 // ----------------------------------------------------------------------------
525 // wxApp ctor/dtor
526 // ----------------------------------------------------------------------------
527
528 wxApp::wxApp()
529 {
530 m_printMode = wxPRINT_WINDOWS;
531 }
532
533 wxApp::~wxApp()
534 {
535 // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
536 // don't come from main(), so we have to free them
537
538 while ( argc )
539 {
540 // m_argv elements were allocated by wxStrdup()
541 free(argv[--argc]);
542 }
543
544 // but m_argv itself -- using new[]
545 delete [] argv;
546 }
547
548 bool wxApp::Initialized()
549 {
550 #ifndef _WINDLL
551 if (GetTopWindow())
552 return TRUE;
553 else
554 return FALSE;
555 #else // Assume initialized if DLL (no way of telling)
556 return TRUE;
557 #endif
558 }
559
560 void wxApp::OnIdle(wxIdleEvent& event)
561 {
562 wxAppBase::OnIdle(event);
563
564 #if wxUSE_DC_CACHEING
565 // automated DC cache management: clear the cached DCs and bitmap
566 // if it's likely that the app has finished with them, that is, we
567 // get an idle event and we're not dragging anything.
568 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
569 wxDC::ClearCache();
570 #endif // wxUSE_DC_CACHEING
571 }
572
573 void wxApp::WakeUpIdle()
574 {
575 // Send the top window a dummy message so idle handler processing will
576 // start up again. Doing it this way ensures that the idle handler
577 // wakes up in the right thread (see also wxWakeUpMainThread() which does
578 // the same for the main app thread only)
579 wxWindow *topWindow = wxTheApp->GetTopWindow();
580 if ( topWindow )
581 {
582 if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
583 {
584 // should never happen
585 wxLogLastError(wxT("PostMessage(WM_NULL)"));
586 }
587 }
588 }
589
590 void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
591 {
592 if (GetTopWindow())
593 GetTopWindow()->Close(TRUE);
594 }
595
596 // Default behaviour: close the application with prompts. The
597 // user can veto the close, and therefore the end session.
598 void wxApp::OnQueryEndSession(wxCloseEvent& event)
599 {
600 if (GetTopWindow())
601 {
602 if (!GetTopWindow()->Close(!event.CanVeto()))
603 event.Veto(TRUE);
604 }
605 }
606
607 /* static */
608 int wxApp::GetComCtl32Version()
609 {
610 //FIX ME FOR DIGITALMARS!!
611 #if defined(__WXMICROWIN__) || defined(__WXWINCE__) || defined(__DIGITALMARS__)
612 return 0;
613 #else
614 // cache the result
615 //
616 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
617 // but as its value should be the same both times it doesn't matter
618 static int s_verComCtl32 = -1;
619
620 if ( s_verComCtl32 == -1 )
621 {
622 // initally assume no comctl32.dll at all
623 s_verComCtl32 = 0;
624
625 // we're prepared to handle the errors
626 wxLogNull noLog;
627
628 // do we have it?
629 wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
630
631 // if so, then we can check for the version
632 if ( dllComCtl32.IsLoaded() )
633 {
634 #ifdef DLLVER_PLATFORM_WINDOWS
635 // try to use DllGetVersion() if available in _headers_
636 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dllComCtl32 );
637 if ( pfnDllGetVersion )
638 {
639 DLLVERSIONINFO dvi;
640 dvi.cbSize = sizeof(dvi);
641
642 HRESULT hr = (*pfnDllGetVersion)(&dvi);
643 if ( FAILED(hr) )
644 {
645 wxLogApiError(_T("DllGetVersion"), hr);
646 }
647 else
648 {
649 // this is incompatible with _WIN32_IE values, but
650 // compatible with the other values returned by
651 // GetComCtl32Version()
652 s_verComCtl32 = 100*dvi.dwMajorVersion +
653 dvi.dwMinorVersion;
654 }
655 }
656 #endif
657
658 // if DllGetVersion() is unavailable either during compile or
659 // run-time, try to guess the version otherwise
660 if ( !s_verComCtl32 )
661 {
662 // InitCommonControlsEx is unique to 4.70 and later
663 void *pfn = dllComCtl32.GetSymbol(_T("InitCommonControlsEx"));
664 if ( !pfn )
665 {
666 // not found, must be 4.00
667 s_verComCtl32 = 400;
668 }
669 else // 4.70+
670 {
671 // many symbols appeared in comctl32 4.71, could use any of
672 // them except may be DllInstall()
673 pfn = dllComCtl32.GetSymbol(_T("InitializeFlatSB"));
674 if ( !pfn )
675 {
676 // not found, must be 4.70
677 s_verComCtl32 = 470;
678 }
679 else
680 {
681 // found, must be 4.71 or later
682 s_verComCtl32 = 471;
683 }
684 }
685 }
686 }
687 }
688
689 return s_verComCtl32;
690 #endif // Microwin/!Microwin
691 }
692
693 // Yield to incoming messages
694
695 bool wxApp::Yield(bool onlyIfNeeded)
696 {
697 // MT-FIXME
698 static bool s_inYield = FALSE;
699
700 #if wxUSE_LOG
701 // disable log flushing from here because a call to wxYield() shouldn't
702 // normally result in message boxes popping up &c
703 wxLog::Suspend();
704 #endif // wxUSE_LOG
705
706 if ( s_inYield )
707 {
708 if ( !onlyIfNeeded )
709 {
710 wxFAIL_MSG( wxT("wxYield called recursively" ) );
711 }
712
713 return FALSE;
714 }
715
716 s_inYield = TRUE;
717
718 // we don't want to process WM_QUIT from here - it should be processed in
719 // the main event loop in order to stop it
720 MSG msg;
721 while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
722 msg.message != WM_QUIT )
723 {
724 #if wxUSE_THREADS
725 wxMutexGuiLeaveOrEnter();
726 #endif // wxUSE_THREADS
727
728 if ( !wxTheApp->Dispatch() )
729 break;
730 }
731
732 // if there are pending events, we must process them.
733 ProcessPendingEvents();
734
735 #if wxUSE_LOG
736 // let the logs be flashed again
737 wxLog::Resume();
738 #endif // wxUSE_LOG
739
740 s_inYield = FALSE;
741
742 return TRUE;
743 }
744