made default background colour BTNFACE (so that panels don't have to erase their...
[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 // For MB_TASKMODAL
80 #ifdef __WXWINCE__
81 #include "wx/msw/wince/missing.h"
82 #endif
83
84 #if (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \
85 !defined(__CYGWIN__) && !defined(__DIGITALMARS__) && !defined(__WXWINCE__) && \
86 (!defined(_MSC_VER) || (_MSC_VER > 1100))
87 #include <shlwapi.h>
88 #endif
89
90 // ---------------------------------------------------------------------------
91 // global variables
92 // ---------------------------------------------------------------------------
93
94 extern wxList WXDLLEXPORT wxPendingDelete;
95
96 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
97 extern void wxSetKeyboardHook(bool doIt);
98 #endif
99
100 // NB: all "NoRedraw" classes must have the same names as the "normal" classes
101 // with NR suffix - wxWindow::MSWCreate() supposes this
102 #ifdef __WXWINCE__
103 wxChar *wxCanvasClassName;
104 wxChar *wxCanvasClassNameNR;
105 #else
106 const wxChar *wxCanvasClassName = wxT("wxWindowClass");
107 const wxChar *wxCanvasClassNameNR = wxT("wxWindowClassNR");
108 #endif
109 const wxChar *wxMDIFrameClassName = wxT("wxMDIFrameClass");
110 const wxChar *wxMDIFrameClassNameNoRedraw = wxT("wxMDIFrameClassNR");
111 const wxChar *wxMDIChildFrameClassName = wxT("wxMDIChildFrameClass");
112 const wxChar *wxMDIChildFrameClassNameNoRedraw = wxT("wxMDIChildFrameClassNR");
113
114 // ----------------------------------------------------------------------------
115 // private functions
116 // ----------------------------------------------------------------------------
117
118 LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
119
120 // ===========================================================================
121 // wxGUIAppTraits implementation
122 // ===========================================================================
123
124 // private class which we use to pass parameters from BeforeChildWaitLoop() to
125 // AfterChildWaitLoop()
126 struct ChildWaitLoopData
127 {
128 ChildWaitLoopData(wxWindowDisabler *wd_, wxWindow *winActive_)
129 {
130 wd = wd_;
131 winActive = winActive_;
132 }
133
134 wxWindowDisabler *wd;
135 wxWindow *winActive;
136 };
137
138 void *wxGUIAppTraits::BeforeChildWaitLoop()
139 {
140 /*
141 We use a dirty hack here to disable all application windows (which we
142 must do because otherwise the calls to wxYield() could lead to some very
143 unexpected reentrancies in the users code) but to avoid losing
144 focus/activation entirely when the child process terminates which would
145 happen if we simply disabled everything using wxWindowDisabler. Indeed,
146 remember that Windows will never activate a disabled window and when the
147 last childs window is closed and Windows looks for a window to activate
148 all our windows are still disabled. There is no way to enable them in
149 time because we don't know when the childs windows are going to be
150 closed, so the solution we use here is to keep one special tiny frame
151 enabled all the time. Then when the child terminates it will get
152 activated and when we close it below -- after reenabling all the other
153 windows! -- the previously active window becomes activated again and
154 everything is ok.
155 */
156 wxBeginBusyCursor();
157
158 // first disable all existing windows
159 wxWindowDisabler *wd = new wxWindowDisabler;
160
161 // then create an "invisible" frame: it has minimal size, is positioned
162 // (hopefully) outside the screen and doesn't appear on the taskbar
163 wxWindow *winActive = new wxFrame
164 (
165 wxTheApp->GetTopWindow(),
166 wxID_ANY,
167 wxEmptyString,
168 wxPoint(32600, 32600),
169 wxSize(1, 1),
170 wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR
171 );
172 winActive->Show();
173
174 return new ChildWaitLoopData(wd, winActive);
175 }
176
177 void wxGUIAppTraits::AlwaysYield()
178 {
179 wxYield();
180 }
181
182 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
183 {
184 wxEndBusyCursor();
185
186 ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig;
187
188 delete data->wd;
189
190 // finally delete the dummy frame and, as wd has been already destroyed and
191 // the other windows reenabled, the activation is going to return to the
192 // window which had had it before
193 data->winActive->Destroy();
194
195 // also delete the temporary data object itself
196 delete data;
197 }
198
199 bool wxGUIAppTraits::DoMessageFromThreadWait()
200 {
201 // we should return false only if the app should exit, i.e. only if
202 // Dispatch() determines that the main event loop should terminate
203 return !wxTheApp || wxTheApp->Dispatch();
204 }
205
206 wxToolkitInfo& wxGUIAppTraits::GetToolkitInfo()
207 {
208 static wxToolkitInfo info;
209 wxToolkitInfo& baseInfo = wxAppTraits::GetToolkitInfo();
210 info.versionMajor = baseInfo.versionMajor;
211 info.versionMinor = baseInfo.versionMinor;
212 info.os = baseInfo.os;
213 info.shortName = _T("msw");
214 info.name = _T("wxMSW");
215 #ifdef __WXUNIVERSAL__
216 info.shortName << _T("univ");
217 info.name << _T("/wxUniversal");
218 #endif
219 return info;
220 }
221
222 // ===========================================================================
223 // wxApp implementation
224 // ===========================================================================
225
226 int wxApp::m_nCmdShow = SW_SHOWNORMAL;
227
228 // ---------------------------------------------------------------------------
229 // wxWin macros
230 // ---------------------------------------------------------------------------
231
232 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
233
234 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
235 EVT_IDLE(wxApp::OnIdle)
236 EVT_END_SESSION(wxApp::OnEndSession)
237 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
238 END_EVENT_TABLE()
239
240 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
241 // fails
242 class wxCallBaseCleanup
243 {
244 public:
245 wxCallBaseCleanup(wxApp *app) : m_app(app) { }
246 ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
247
248 void Dismiss() { m_app = NULL; }
249
250 private:
251 wxApp *m_app;
252 };
253
254 //// Initialize
255 bool wxApp::Initialize(int& argc, wxChar **argv)
256 {
257 if ( !wxAppBase::Initialize(argc, argv) )
258 return false;
259
260 // ensure that base cleanup is done if we return too early
261 wxCallBaseCleanup callBaseCleanup(this);
262
263 #ifdef __WXWINCE__
264 wxString tmp = GetAppName();
265 tmp += wxT("ClassName");
266 wxCanvasClassName = wxStrdup( tmp.c_str() );
267 tmp += wxT("NR");
268 wxCanvasClassNameNR = wxStrdup( tmp.c_str() );
269 HWND hWnd = FindWindow( wxCanvasClassNameNR, NULL );
270 if (hWnd)
271 {
272 SetForegroundWindow( (HWND)(((DWORD)hWnd)|0x01) );
273 return false;
274 }
275 #endif
276
277 // the first thing to do is to check if we're trying to run an Unicode
278 // program under Win9x w/o MSLU emulation layer - if so, abort right now
279 // as it has no chance to work
280 #if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
281 if ( wxGetOsVersion() != wxWINDOWS_NT && wxGetOsVersion() != wxWINDOWS_CE )
282 {
283 // note that we can use MessageBoxW() as it's implemented even under
284 // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs
285 // used by wxLocale are not
286 ::MessageBox
287 (
288 NULL,
289 _T("This program uses Unicode and requires Windows NT/2000/XP/CE.\nProgram aborted."),
290 _T("wxWidgets Fatal Error"),
291 MB_ICONERROR | MB_OK
292 );
293
294 return false;
295 }
296 #endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
297
298 #if defined(__WIN95__) && !defined(__WXMICROWIN__)
299 InitCommonControls();
300 #endif // __WIN95__
301
302 #if wxUSE_OLE || wxUSE_DRAG_AND_DROP
303
304 #if wxUSE_OLE
305 // we need to initialize OLE library
306 #ifdef __WXWINCE__
307 if ( FAILED(::CoInitializeEx(NULL, COINIT_MULTITHREADED)) )
308 wxLogError(_("Cannot initialize OLE"));
309 #else
310 if ( FAILED(::OleInitialize(NULL)) )
311 wxLogError(_("Cannot initialize OLE"));
312 #endif
313 #endif
314
315 #endif // wxUSE_OLE
316
317 #if wxUSE_CTL3D
318 if (!Ctl3dRegister(wxhInstance))
319 wxLogError(wxT("Cannot register CTL3D"));
320
321 Ctl3dAutoSubclass(wxhInstance);
322 #endif // wxUSE_CTL3D
323
324 RegisterWindowClasses();
325
326 #if wxUSE_PENWINDOWS
327 wxRegisterPenWin();
328 #endif
329
330 wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
331
332 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
333 wxSetKeyboardHook(true);
334 #endif
335
336 callBaseCleanup.Dismiss();
337
338 return true;
339 }
340
341 // ---------------------------------------------------------------------------
342 // RegisterWindowClasses
343 // ---------------------------------------------------------------------------
344
345 // TODO we should only register classes really used by the app. For this it
346 // would be enough to just delay the class registration until an attempt
347 // to create a window of this class is made.
348 bool wxApp::RegisterWindowClasses()
349 {
350 WNDCLASS wndclass;
351 wxZeroMemory(wndclass);
352
353 // for each class we register one with CS_(V|H)REDRAW style and one
354 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
355 static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
356 static const long styleNoRedraw = CS_DBLCLKS;
357
358 // the fields which are common to all classes
359 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
360 wndclass.hInstance = wxhInstance;
361 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
362
363 // register the class for all normal windows
364 wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
365 wndclass.lpszClassName = wxCanvasClassName;
366 wndclass.style = styleNormal;
367
368 if ( !RegisterClass(&wndclass) )
369 {
370 wxLogLastError(wxT("RegisterClass(frame)"));
371 }
372
373 // "no redraw" frame
374 wndclass.lpszClassName = wxCanvasClassNameNR;
375 wndclass.style = styleNoRedraw;
376
377 if ( !RegisterClass(&wndclass) )
378 {
379 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
380 }
381
382 // Register the MDI frame window class.
383 wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
384 wndclass.lpszClassName = wxMDIFrameClassName;
385 wndclass.style = styleNormal;
386
387 if ( !RegisterClass(&wndclass) )
388 {
389 wxLogLastError(wxT("RegisterClass(MDI parent)"));
390 }
391
392 // "no redraw" MDI frame
393 wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
394 wndclass.style = styleNoRedraw;
395
396 if ( !RegisterClass(&wndclass) )
397 {
398 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
399 }
400
401 // Register the MDI child frame window class.
402 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
403 wndclass.lpszClassName = wxMDIChildFrameClassName;
404 wndclass.style = styleNormal;
405
406 if ( !RegisterClass(&wndclass) )
407 {
408 wxLogLastError(wxT("RegisterClass(MDI child)"));
409 }
410
411 // "no redraw" MDI child frame
412 wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
413 wndclass.style = styleNoRedraw;
414
415 if ( !RegisterClass(&wndclass) )
416 {
417 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
418 }
419
420 return true;
421 }
422
423 // ---------------------------------------------------------------------------
424 // UnregisterWindowClasses
425 // ---------------------------------------------------------------------------
426
427 bool wxApp::UnregisterWindowClasses()
428 {
429 bool retval = true;
430
431 #ifndef __WXMICROWIN__
432 // MDI frame window class.
433 if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
434 {
435 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
436
437 retval = false;
438 }
439
440 // "no redraw" MDI frame
441 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
442 {
443 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
444
445 retval = false;
446 }
447
448 // MDI child frame window class.
449 if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
450 {
451 wxLogLastError(wxT("UnregisterClass(MDI child)"));
452
453 retval = false;
454 }
455
456 // "no redraw" MDI child frame
457 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
458 {
459 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
460
461 retval = false;
462 }
463
464 // canvas class name
465 if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
466 {
467 wxLogLastError(wxT("UnregisterClass(canvas)"));
468
469 retval = false;
470 }
471
472 if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
473 {
474 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
475
476 retval = false;
477 }
478 #endif // __WXMICROWIN__
479
480 return retval;
481 }
482
483 void wxApp::CleanUp()
484 {
485 // all objects pending for deletion must be deleted first, otherwise we
486 // would crash when they use wxWinHandleHash (and UnregisterWindowClasses()
487 // call wouldn't succeed as long as any windows still exist), so call the
488 // base class method first and only then do our clean up
489 wxAppBase::CleanUp();
490
491 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
492 wxSetKeyboardHook(false);
493 #endif
494
495 #if wxUSE_PENWINDOWS
496 wxCleanUpPenWin();
497 #endif
498
499 #if wxUSE_OLE
500 #ifdef __WXWINCE__
501 ::CoUninitialize();
502 #else
503 ::OleUninitialize();
504 #endif
505 #endif
506
507 // for an EXE the classes are unregistered when it terminates but DLL may
508 // be loaded several times (load/unload/load) into the same process in
509 // which case the registration will fail after the first time if we don't
510 // unregister the classes now
511 UnregisterWindowClasses();
512
513 #if wxUSE_CTL3D
514 Ctl3dUnregister(wxhInstance);
515 #endif
516
517 delete wxWinHandleHash;
518 wxWinHandleHash = NULL;
519
520 #ifdef __WXWINCE__
521 free( wxCanvasClassName );
522 free( wxCanvasClassNameNR );
523 #endif
524 }
525
526 // ----------------------------------------------------------------------------
527 // wxApp ctor/dtor
528 // ----------------------------------------------------------------------------
529
530 wxApp::wxApp()
531 {
532 m_printMode = wxPRINT_WINDOWS;
533 }
534
535 wxApp::~wxApp()
536 {
537 // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
538 // don't come from main(), so we have to free them
539
540 while ( argc )
541 {
542 // m_argv elements were allocated by wxStrdup()
543 free(argv[--argc]);
544 }
545
546 // but m_argv itself -- using new[]
547 delete [] argv;
548 }
549
550 // ----------------------------------------------------------------------------
551 // wxApp idle handling
552 // ----------------------------------------------------------------------------
553
554 void wxApp::OnIdle(wxIdleEvent& event)
555 {
556 wxAppBase::OnIdle(event);
557
558 #if wxUSE_DC_CACHEING
559 // automated DC cache management: clear the cached DCs and bitmap
560 // if it's likely that the app has finished with them, that is, we
561 // get an idle event and we're not dragging anything.
562 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
563 wxDC::ClearCache();
564 #endif // wxUSE_DC_CACHEING
565 }
566
567 void wxApp::WakeUpIdle()
568 {
569 // Send the top window a dummy message so idle handler processing will
570 // start up again. Doing it this way ensures that the idle handler
571 // wakes up in the right thread (see also wxWakeUpMainThread() which does
572 // the same for the main app thread only)
573 wxWindow *topWindow = wxTheApp->GetTopWindow();
574 if ( topWindow )
575 {
576 if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
577 {
578 // should never happen
579 wxLogLastError(wxT("PostMessage(WM_NULL)"));
580 }
581 }
582 }
583
584 // ----------------------------------------------------------------------------
585 // other wxApp event hanlders
586 // ----------------------------------------------------------------------------
587
588 void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
589 {
590 if (GetTopWindow())
591 GetTopWindow()->Close(true);
592 }
593
594 // Default behaviour: close the application with prompts. The
595 // user can veto the close, and therefore the end session.
596 void wxApp::OnQueryEndSession(wxCloseEvent& event)
597 {
598 if (GetTopWindow())
599 {
600 if (!GetTopWindow()->Close(!event.CanVeto()))
601 event.Veto(true);
602 }
603 }
604
605 // ----------------------------------------------------------------------------
606 // miscellaneous
607 // ----------------------------------------------------------------------------
608
609 /* static */
610 int wxApp::GetComCtl32Version()
611 {
612 #if defined(__WXMICROWIN__) || defined(__WXWINCE__)
613 return 0;
614 #else
615 // cache the result
616 //
617 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
618 // but as its value should be the same both times it doesn't matter
619 static int s_verComCtl32 = -1;
620
621 if ( s_verComCtl32 == -1 )
622 {
623 // initally assume no comctl32.dll at all
624 s_verComCtl32 = 0;
625
626 // we're prepared to handle the errors
627 wxLogNull noLog;
628
629 // do we have it?
630 wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
631
632 // if so, then we can check for the version
633 if ( dllComCtl32.IsLoaded() )
634 {
635 #ifdef DLLVER_PLATFORM_WINDOWS
636 // try to use DllGetVersion() if available in _headers_
637 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dllComCtl32 );
638 if ( pfnDllGetVersion )
639 {
640 DLLVERSIONINFO dvi;
641 dvi.cbSize = sizeof(dvi);
642
643 HRESULT hr = (*pfnDllGetVersion)(&dvi);
644 if ( FAILED(hr) )
645 {
646 wxLogApiError(_T("DllGetVersion"), hr);
647 }
648 else
649 {
650 // this is incompatible with _WIN32_IE values, but
651 // compatible with the other values returned by
652 // GetComCtl32Version()
653 s_verComCtl32 = 100*dvi.dwMajorVersion +
654 dvi.dwMinorVersion;
655 }
656 }
657 #endif
658
659 // if DllGetVersion() is unavailable either during compile or
660 // run-time, try to guess the version otherwise
661 if ( !s_verComCtl32 )
662 {
663 // InitCommonControlsEx is unique to 4.70 and later
664 void *pfn = dllComCtl32.GetSymbol(_T("InitCommonControlsEx"));
665 if ( !pfn )
666 {
667 // not found, must be 4.00
668 s_verComCtl32 = 400;
669 }
670 else // 4.70+
671 {
672 // many symbols appeared in comctl32 4.71, could use any of
673 // them except may be DllInstall()
674 pfn = dllComCtl32.GetSymbol(_T("InitializeFlatSB"));
675 if ( !pfn )
676 {
677 // not found, must be 4.70
678 s_verComCtl32 = 470;
679 }
680 else
681 {
682 // found, must be 4.71 or later
683 s_verComCtl32 = 471;
684 }
685 }
686 }
687 }
688 }
689
690 return s_verComCtl32;
691 #endif // Microwin/!Microwin
692 }
693
694 // Yield to incoming messages
695
696 bool wxApp::Yield(bool onlyIfNeeded)
697 {
698 // MT-FIXME
699 static bool s_inYield = false;
700
701 #if wxUSE_LOG
702 // disable log flushing from here because a call to wxYield() shouldn't
703 // normally result in message boxes popping up &c
704 wxLog::Suspend();
705 #endif // wxUSE_LOG
706
707 if ( s_inYield )
708 {
709 if ( !onlyIfNeeded )
710 {
711 wxFAIL_MSG( wxT("wxYield called recursively" ) );
712 }
713
714 return false;
715 }
716
717 s_inYield = true;
718
719 // we don't want to process WM_QUIT from here - it should be processed in
720 // the main event loop in order to stop it
721 MSG msg;
722 while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
723 msg.message != WM_QUIT )
724 {
725 #if wxUSE_THREADS
726 wxMutexGuiLeaveOrEnter();
727 #endif // wxUSE_THREADS
728
729 if ( !wxTheApp->Dispatch() )
730 break;
731 }
732
733 // if there are pending events, we must process them.
734 ProcessPendingEvents();
735
736 #if wxUSE_LOG
737 // let the logs be flashed again
738 wxLog::Resume();
739 #endif // wxUSE_LOG
740
741 s_inYield = false;
742
743 return true;
744 }
745
746 #if wxUSE_EXCEPTIONS
747
748 // ----------------------------------------------------------------------------
749 // exception handling
750 // ----------------------------------------------------------------------------
751
752 bool wxApp::OnExceptionInMainLoop()
753 {
754 // ask the user about what to do: use the Win32 API function here as it
755 // could be dangerous to use any wxWidgets code in this state
756 switch (
757 ::MessageBox
758 (
759 NULL,
760 _T("An unhandled exception occurred. Press \"Abort\" to \
761 terminate the program,\r\n\
762 \"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
763 _T("Unhandled exception"),
764 MB_ABORTRETRYIGNORE |
765 MB_ICONERROR|
766 MB_TASKMODAL
767 )
768 )
769 {
770 case IDABORT:
771 throw;
772
773 default:
774 wxFAIL_MSG( _T("unexpected MessageBox() return code") );
775 // fall through
776
777 case IDRETRY:
778 return false;
779
780 case IDIGNORE:
781 return true;
782 }
783 }
784
785 #endif // wxUSE_EXCEPTIONS
786
787 // ----------------------------------------------------------------------------
788 // deprecated event loop functions
789 // ----------------------------------------------------------------------------
790
791 #if WXWIN_COMPATIBILITY_2_4
792
793 #include "wx/evtloop.h"
794
795 void wxApp::DoMessage(WXMSG *pMsg)
796 {
797 wxEventLoop *evtLoop = wxEventLoop::GetActive();
798 if ( evtLoop )
799 evtLoop->ProcessMessage(pMsg);
800 }
801
802 bool wxApp::DoMessage()
803 {
804 wxEventLoop *evtLoop = wxEventLoop::GetActive();
805 return evtLoop ? evtLoop->Dispatch() : false;
806 }
807
808 bool wxApp::ProcessMessage(WXMSG* pMsg)
809 {
810 wxEventLoop *evtLoop = wxEventLoop::GetActive();
811 return evtLoop && evtLoop->PreProcessMessage(pMsg);
812 }
813
814 #endif // WXWIN_COMPATIBILITY_2_4
815