removed wxApp::Initialized() (replaced with a dummy version in wxApp itself); wxApp...
[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 void wxApp::OnIdle(wxIdleEvent& event)
553 {
554 wxAppBase::OnIdle(event);
555
556 #if wxUSE_DC_CACHEING
557 // automated DC cache management: clear the cached DCs and bitmap
558 // if it's likely that the app has finished with them, that is, we
559 // get an idle event and we're not dragging anything.
560 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
561 wxDC::ClearCache();
562 #endif // wxUSE_DC_CACHEING
563 }
564
565 void wxApp::WakeUpIdle()
566 {
567 // Send the top window a dummy message so idle handler processing will
568 // start up again. Doing it this way ensures that the idle handler
569 // wakes up in the right thread (see also wxWakeUpMainThread() which does
570 // the same for the main app thread only)
571 wxWindow *topWindow = wxTheApp->GetTopWindow();
572 if ( topWindow )
573 {
574 if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
575 {
576 // should never happen
577 wxLogLastError(wxT("PostMessage(WM_NULL)"));
578 }
579 }
580 }
581
582 void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
583 {
584 if (GetTopWindow())
585 GetTopWindow()->Close(TRUE);
586 }
587
588 // Default behaviour: close the application with prompts. The
589 // user can veto the close, and therefore the end session.
590 void wxApp::OnQueryEndSession(wxCloseEvent& event)
591 {
592 if (GetTopWindow())
593 {
594 if (!GetTopWindow()->Close(!event.CanVeto()))
595 event.Veto(TRUE);
596 }
597 }
598
599 /* static */
600 int wxApp::GetComCtl32Version()
601 {
602 //FIX ME FOR DIGITALMARS!!
603 #if defined(__WXMICROWIN__) || defined(__WXWINCE__) || defined(__DIGITALMARS__)
604 return 0;
605 #else
606 // cache the result
607 //
608 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
609 // but as its value should be the same both times it doesn't matter
610 static int s_verComCtl32 = -1;
611
612 if ( s_verComCtl32 == -1 )
613 {
614 // initally assume no comctl32.dll at all
615 s_verComCtl32 = 0;
616
617 // we're prepared to handle the errors
618 wxLogNull noLog;
619
620 // do we have it?
621 wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
622
623 // if so, then we can check for the version
624 if ( dllComCtl32.IsLoaded() )
625 {
626 #ifdef DLLVER_PLATFORM_WINDOWS
627 // try to use DllGetVersion() if available in _headers_
628 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dllComCtl32 );
629 if ( pfnDllGetVersion )
630 {
631 DLLVERSIONINFO dvi;
632 dvi.cbSize = sizeof(dvi);
633
634 HRESULT hr = (*pfnDllGetVersion)(&dvi);
635 if ( FAILED(hr) )
636 {
637 wxLogApiError(_T("DllGetVersion"), hr);
638 }
639 else
640 {
641 // this is incompatible with _WIN32_IE values, but
642 // compatible with the other values returned by
643 // GetComCtl32Version()
644 s_verComCtl32 = 100*dvi.dwMajorVersion +
645 dvi.dwMinorVersion;
646 }
647 }
648 #endif
649
650 // if DllGetVersion() is unavailable either during compile or
651 // run-time, try to guess the version otherwise
652 if ( !s_verComCtl32 )
653 {
654 // InitCommonControlsEx is unique to 4.70 and later
655 void *pfn = dllComCtl32.GetSymbol(_T("InitCommonControlsEx"));
656 if ( !pfn )
657 {
658 // not found, must be 4.00
659 s_verComCtl32 = 400;
660 }
661 else // 4.70+
662 {
663 // many symbols appeared in comctl32 4.71, could use any of
664 // them except may be DllInstall()
665 pfn = dllComCtl32.GetSymbol(_T("InitializeFlatSB"));
666 if ( !pfn )
667 {
668 // not found, must be 4.70
669 s_verComCtl32 = 470;
670 }
671 else
672 {
673 // found, must be 4.71 or later
674 s_verComCtl32 = 471;
675 }
676 }
677 }
678 }
679 }
680
681 return s_verComCtl32;
682 #endif // Microwin/!Microwin
683 }
684
685 // Yield to incoming messages
686
687 bool wxApp::Yield(bool onlyIfNeeded)
688 {
689 // MT-FIXME
690 static bool s_inYield = FALSE;
691
692 #if wxUSE_LOG
693 // disable log flushing from here because a call to wxYield() shouldn't
694 // normally result in message boxes popping up &c
695 wxLog::Suspend();
696 #endif // wxUSE_LOG
697
698 if ( s_inYield )
699 {
700 if ( !onlyIfNeeded )
701 {
702 wxFAIL_MSG( wxT("wxYield called recursively" ) );
703 }
704
705 return FALSE;
706 }
707
708 s_inYield = TRUE;
709
710 // we don't want to process WM_QUIT from here - it should be processed in
711 // the main event loop in order to stop it
712 MSG msg;
713 while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
714 msg.message != WM_QUIT )
715 {
716 #if wxUSE_THREADS
717 wxMutexGuiLeaveOrEnter();
718 #endif // wxUSE_THREADS
719
720 if ( !wxTheApp->Dispatch() )
721 break;
722 }
723
724 // if there are pending events, we must process them.
725 ProcessPendingEvents();
726
727 #if wxUSE_LOG
728 // let the logs be flashed again
729 wxLog::Resume();
730 #endif // wxUSE_LOG
731
732 s_inYield = FALSE;
733
734 return TRUE;
735 }
736