]> git.saurik.com Git - wxWidgets.git/blame - src/msw/app.cpp
don't set resize mode to QUEUE, it seems to be wrong for a wxWindow in a native container
[wxWidgets.git] / src / msw / app.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
a71d815b 2// Name: src/msw/app.cpp
2bda0e17
KB
3// Purpose: wxApp
4// Author: Julian Smart
5// Modified by:
6// Created: 04/01/98
7// RCS-ID: $Id$
6c9a19aa 8// Copyright: (c) Julian Smart
65571936 9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
e5c0b16a
VZ
12// ===========================================================================
13// declarations
14// ===========================================================================
15
16// ---------------------------------------------------------------------------
17// headers
18// ---------------------------------------------------------------------------
19
2bda0e17 20// For compilers that support precompilation, includes "wx.h".
2bda0e17
KB
21#include "wx/wxprec.h"
22
23#if defined(__BORLANDC__)
e5c0b16a 24 #pragma hdrstop
2bda0e17
KB
25#endif
26
27#ifndef WX_PRECOMP
57bd4c60 28 #include "wx/msw/wrapcctl.h"
ad9835c9 29 #include "wx/dynarray.h"
e5c0b16a
VZ
30 #include "wx/frame.h"
31 #include "wx/app.h"
32 #include "wx/utils.h"
33 #include "wx/gdicmn.h"
34 #include "wx/pen.h"
35 #include "wx/brush.h"
36 #include "wx/cursor.h"
37 #include "wx/icon.h"
38 #include "wx/palette.h"
39 #include "wx/dc.h"
40 #include "wx/dialog.h"
41 #include "wx/msgdlg.h"
42 #include "wx/intl.h"
3a3dde0d 43 #include "wx/crt.h"
31f6de22 44 #include "wx/log.h"
02761f6c 45 #include "wx/module.h"
2bda0e17
KB
46#endif
47
e2478fde 48#include "wx/apptrait.h"
7104f65d 49#include "wx/filename.h"
9fc6c21c 50#include "wx/dynlib.h"
031943ac 51#include "wx/evtloop.h"
4bf78aae 52
4286a5b5 53#include "wx/msw/private.h"
360ae33f 54#include "wx/msw/ole/oleutils.h"
c2ca375c 55#include "wx/msw/private/timer.h"
4286a5b5 56
8614c467
VZ
57#if wxUSE_TOOLTIPS
58 #include "wx/tooltip.h"
59#endif // wxUSE_TOOLTIPS
60
c42404a5
VZ
61// OLE is used for drag-and-drop, clipboard, OLE Automation..., but some
62// compilers don't support it (missing headers, libs, ...)
2bdf7154 63#if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__) || defined(__SALFORDC__)
e5c0b16a
VZ
64 #undef wxUSE_OLE
65
66 #define wxUSE_OLE 0
67#endif // broken compilers
68
afafd942 69#if defined(__POCKETPC__) || defined(__SMARTPHONE__)
58b76be1
VZ
70 #include <ole2.h>
71 #include <aygshell.h>
afafd942
JS
72#endif
73
e5c0b16a 74#if wxUSE_OLE
6e0d9d43 75 #include <ole2.h>
d05237ea 76#endif
ce3ed50d 77
2bda0e17 78#include <string.h>
a5e0e655 79#include <ctype.h>
2bda0e17 80
261fb041 81#include "wx/msw/missing.h"
6046e57a 82
25a11614
VZ
83// instead of including <shlwapi.h> which is not part of the core SDK and not
84// shipped at all with other compilers, we always define the parts of it we
85// need here ourselves
86//
87// NB: DLLVER_PLATFORM_WINDOWS will be defined if shlwapi.h had been somehow
88// included already
89#ifndef DLLVER_PLATFORM_WINDOWS
90 // hopefully we don't need to change packing as DWORDs should be already
91 // correctly aligned
92 struct DLLVERSIONINFO
93 {
94 DWORD cbSize;
95 DWORD dwMajorVersion; // Major version
96 DWORD dwMinorVersion; // Minor version
97 DWORD dwBuildNumber; // Build number
98 DWORD dwPlatformID; // DLLVER_PLATFORM_*
99 };
100
101 typedef HRESULT (CALLBACK* DLLGETVERSIONPROC)(DLLVERSIONINFO *);
102#endif // defined(DLLVERSIONINFO)
103
238a6044 104
e5c0b16a
VZ
105// ---------------------------------------------------------------------------
106// global variables
107// ---------------------------------------------------------------------------
108
4676948b 109#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
2bda0e17 110extern void wxSetKeyboardHook(bool doIt);
04ef50df 111#endif
2bda0e17 112
193fe989
VZ
113// NB: all "NoRedraw" classes must have the same names as the "normal" classes
114// with NR suffix - wxWindow::MSWCreate() supposes this
46fa338b 115#ifdef __WXWINCE__
7a4d2469
RN
116WXDLLIMPEXP_CORE wxChar *wxCanvasClassName;
117WXDLLIMPEXP_CORE wxChar *wxCanvasClassNameNR;
46fa338b 118#else
7a4d2469
RN
119WXDLLIMPEXP_CORE const wxChar *wxCanvasClassName = wxT("wxWindowClass");
120WXDLLIMPEXP_CORE const wxChar *wxCanvasClassNameNR = wxT("wxWindowClassNR");
46fa338b 121#endif
7a4d2469
RN
122WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassName = wxT("wxMDIFrameClass");
123WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassNameNoRedraw = wxT("wxMDIFrameClassNR");
124WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassName = wxT("wxMDIChildFrameClass");
125WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassNameNoRedraw = wxT("wxMDIChildFrameClassNR");
2bda0e17 126
94826170
VZ
127// ----------------------------------------------------------------------------
128// private functions
129// ----------------------------------------------------------------------------
2bda0e17 130
94826170 131LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
3b415ba4 132
e5c0b16a 133// ===========================================================================
e2478fde
VZ
134// wxGUIAppTraits implementation
135// ===========================================================================
136
137// private class which we use to pass parameters from BeforeChildWaitLoop() to
138// AfterChildWaitLoop()
139struct ChildWaitLoopData
140{
141 ChildWaitLoopData(wxWindowDisabler *wd_, wxWindow *winActive_)
142 {
143 wd = wd_;
144 winActive = winActive_;
145 }
146
147 wxWindowDisabler *wd;
148 wxWindow *winActive;
149};
150
151void *wxGUIAppTraits::BeforeChildWaitLoop()
152{
153 /*
154 We use a dirty hack here to disable all application windows (which we
155 must do because otherwise the calls to wxYield() could lead to some very
156 unexpected reentrancies in the users code) but to avoid losing
157 focus/activation entirely when the child process terminates which would
158 happen if we simply disabled everything using wxWindowDisabler. Indeed,
159 remember that Windows will never activate a disabled window and when the
160 last childs window is closed and Windows looks for a window to activate
161 all our windows are still disabled. There is no way to enable them in
162 time because we don't know when the childs windows are going to be
163 closed, so the solution we use here is to keep one special tiny frame
164 enabled all the time. Then when the child terminates it will get
165 activated and when we close it below -- after reenabling all the other
166 windows! -- the previously active window becomes activated again and
167 everything is ok.
168 */
169 wxBeginBusyCursor();
170
171 // first disable all existing windows
172 wxWindowDisabler *wd = new wxWindowDisabler;
173
174 // then create an "invisible" frame: it has minimal size, is positioned
175 // (hopefully) outside the screen and doesn't appear on the taskbar
176 wxWindow *winActive = new wxFrame
177 (
178 wxTheApp->GetTopWindow(),
fda7962d
JS
179 wxID_ANY,
180 wxEmptyString,
e2478fde
VZ
181 wxPoint(32600, 32600),
182 wxSize(1, 1),
183 wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR
184 );
185 winActive->Show();
186
187 return new ChildWaitLoopData(wd, winActive);
188}
189
190void wxGUIAppTraits::AlwaysYield()
191{
192 wxYield();
193}
194
195void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
196{
197 wxEndBusyCursor();
198
0588f8d7 199 ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig;
e2478fde
VZ
200
201 delete data->wd;
202
203 // finally delete the dummy frame and, as wd has been already destroyed and
204 // the other windows reenabled, the activation is going to return to the
205 // window which had had it before
206 data->winActive->Destroy();
51036b44
VZ
207
208 // also delete the temporary data object itself
209 delete data;
e2478fde
VZ
210}
211
212bool wxGUIAppTraits::DoMessageFromThreadWait()
213{
1bf77ee5
VZ
214 // we should return false only if the app should exit, i.e. only if
215 // Dispatch() determines that the main event loop should terminate
2ddff00c 216 wxEventLoopBase * const evtLoop = wxEventLoop::GetActive();
031943ac
VZ
217 if ( !evtLoop || !evtLoop->Pending() )
218 {
219 // no events means no quit event
220 return true;
221 }
222
223 return evtLoop->Dispatch();
e2478fde
VZ
224}
225
e570a44b
VZ
226DWORD wxGUIAppTraits::WaitForThread(WXHANDLE hThread)
227{
535920ff
VZ
228 // if we don't have a running event loop, we shouldn't wait for the
229 // messages as we never remove them from the message queue and so we enter
230 // an infinite loop as MsgWaitForMultipleObjects() keeps returning
231 // WAIT_OBJECT_0 + 1
232 if ( !wxEventLoop::GetActive() )
233 return DoSimpleWaitForThread(hThread);
234
e570a44b
VZ
235 return ::MsgWaitForMultipleObjects
236 (
237 1, // number of objects to wait for
238 (HANDLE *)&hThread, // the objects
239 false, // wait for any objects, not all
240 INFINITE, // no timeout
261fb041
WS
241 QS_ALLINPUT | // return as soon as there are any events
242 QS_ALLPOSTMESSAGE
e570a44b
VZ
243 );
244}
245
8bb6b2c0 246wxPortId wxGUIAppTraits::GetToolkitVersion(int *majVer, int *minVer) const
a8eaaeb2 247{
8bb6b2c0
VZ
248 OSVERSIONINFO info;
249 wxZeroMemory(info);
250
251 // on Windows, the toolkit version is the same of the OS version
252 // as Windows integrates the OS kernel with the GUI toolkit.
253 info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
254 if ( ::GetVersionEx(&info) )
255 {
256 if ( majVer )
257 *majVer = info.dwMajorVersion;
258 if ( minVer )
259 *minVer = info.dwMinorVersion;
260 }
261
262#if defined(__WXHANDHELD__) || defined(__WXWINCE__)
263 return wxPORT_WINCE;
264#else
265 return wxPORT_MSW;
a8eaaeb2 266#endif
a8eaaeb2
VS
267}
268
a8ff046b
VZ
269#if wxUSE_TIMER
270
b46b1d59 271wxTimerImpl *wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
c2ca375c 272{
b46b1d59
VZ
273 return new wxMSWTimerImpl(timer);
274}
275
a8ff046b
VZ
276#endif // wxUSE_TIMER
277
2ddff00c 278wxEventLoopBase* wxGUIAppTraits::CreateEventLoop()
b46b1d59
VZ
279{
280 return new wxEventLoop;
5d262fdd 281}
c2ca375c 282
e2478fde
VZ
283// ===========================================================================
284// wxApp implementation
e5c0b16a 285// ===========================================================================
589f0e3e 286
94826170
VZ
287int wxApp::m_nCmdShow = SW_SHOWNORMAL;
288
e5c0b16a 289// ---------------------------------------------------------------------------
e2478fde 290// wxWin macros
e5c0b16a
VZ
291// ---------------------------------------------------------------------------
292
f6bcfd97 293IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
e5c0b16a 294
f6bcfd97
BP
295BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
296 EVT_IDLE(wxApp::OnIdle)
297 EVT_END_SESSION(wxApp::OnEndSession)
298 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
299END_EVENT_TABLE()
e5c0b16a 300
94826170
VZ
301// class to ensure that wxAppBase::CleanUp() is called if our Initialize()
302// fails
303class wxCallBaseCleanup
304{
305public:
306 wxCallBaseCleanup(wxApp *app) : m_app(app) { }
307 ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
308
309 void Dismiss() { m_app = NULL; }
310
311private:
312 wxApp *m_app;
313};
314
e5c0b16a 315//// Initialize
05e2b077 316bool wxApp::Initialize(int& argc, wxChar **argv)
2bda0e17 317{
94826170
VZ
318 if ( !wxAppBase::Initialize(argc, argv) )
319 return false;
320
321 // ensure that base cleanup is done if we return too early
322 wxCallBaseCleanup callBaseCleanup(this);
323
46fa338b
RR
324#ifdef __WXWINCE__
325 wxString tmp = GetAppName();
326 tmp += wxT("ClassName");
d6f2a891 327 wxCanvasClassName = wxStrdup( tmp.wc_str() );
46fa338b 328 tmp += wxT("NR");
d6f2a891 329 wxCanvasClassNameNR = wxStrdup( tmp.wc_str() );
46fa338b
RR
330 HWND hWnd = FindWindow( wxCanvasClassNameNR, NULL );
331 if (hWnd)
332 {
333 SetForegroundWindow( (HWND)(((DWORD)hWnd)|0x01) );
334 return false;
335 }
336#endif
337
a71d815b 338#if !defined(__WXMICROWIN__)
a5e0e655 339 InitCommonControls();
a71d815b 340#endif // !defined(__WXMICROWIN__)
2bda0e17 341
afafd942
JS
342#if defined(__SMARTPHONE__) || defined(__POCKETPC__)
343 SHInitExtraControls();
344#endif
345
d5ea3919
JS
346#ifndef __WXWINCE__
347 // Don't show a message box if a function such as SHGetFileInfo
348 // fails to find a device.
349 SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
350#endif
ad9835c9 351
360ae33f 352 wxOleInitialize();
2bda0e17 353
aa0b7e1e 354 RegisterWindowClasses();
2bda0e17 355
1bffa913 356 wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
2bda0e17 357
4676948b 358#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
77c46f00 359 wxSetKeyboardHook(true);
04ef50df 360#endif
2bda0e17 361
94826170
VZ
362 callBaseCleanup.Dismiss();
363
364 return true;
2bda0e17
KB
365}
366
42e69d6b
VZ
367// ---------------------------------------------------------------------------
368// RegisterWindowClasses
369// ---------------------------------------------------------------------------
589f0e3e 370
b782f2e0
VZ
371// TODO we should only register classes really used by the app. For this it
372// would be enough to just delay the class registration until an attempt
373// to create a window of this class is made.
bb6290e3 374bool wxApp::RegisterWindowClasses()
2bda0e17 375{
42e69d6b 376 WNDCLASS wndclass;
03baf031 377 wxZeroMemory(wndclass);
e5c0b16a 378
193fe989
VZ
379 // for each class we register one with CS_(V|H)REDRAW style and one
380 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
381 static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
382 static const long styleNoRedraw = CS_DBLCLKS;
383
42e69d6b 384 // the fields which are common to all classes
e5c0b16a 385 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
e5c0b16a 386 wndclass.hInstance = wxhInstance;
42e69d6b 387 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
42e69d6b 388
b9691677
VZ
389 // register the class for all normal windows
390 wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
03baf031 391 wndclass.lpszClassName = wxCanvasClassName;
b782f2e0 392 wndclass.style = styleNormal;
e5c0b16a 393
42e69d6b 394 if ( !RegisterClass(&wndclass) )
e5c0b16a 395 {
f6bcfd97 396 wxLogLastError(wxT("RegisterClass(frame)"));
e5c0b16a
VZ
397 }
398
193fe989 399 // "no redraw" frame
03baf031 400 wndclass.lpszClassName = wxCanvasClassNameNR;
193fe989
VZ
401 wndclass.style = styleNoRedraw;
402
403 if ( !RegisterClass(&wndclass) )
404 {
f6bcfd97 405 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
193fe989
VZ
406 }
407
e5c0b16a 408 // Register the MDI frame window class.
42e69d6b 409 wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
b782f2e0
VZ
410 wndclass.lpszClassName = wxMDIFrameClassName;
411 wndclass.style = styleNormal;
42e69d6b
VZ
412
413 if ( !RegisterClass(&wndclass) )
e5c0b16a 414 {
f6bcfd97 415 wxLogLastError(wxT("RegisterClass(MDI parent)"));
e5c0b16a
VZ
416 }
417
193fe989 418 // "no redraw" MDI frame
b782f2e0 419 wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
193fe989
VZ
420 wndclass.style = styleNoRedraw;
421
422 if ( !RegisterClass(&wndclass) )
423 {
f6bcfd97 424 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
193fe989
VZ
425 }
426
e5c0b16a 427 // Register the MDI child frame window class.
42e69d6b
VZ
428 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
429 wndclass.lpszClassName = wxMDIChildFrameClassName;
b782f2e0 430 wndclass.style = styleNormal;
42e69d6b
VZ
431
432 if ( !RegisterClass(&wndclass) )
e5c0b16a 433 {
f6bcfd97 434 wxLogLastError(wxT("RegisterClass(MDI child)"));
e5c0b16a
VZ
435 }
436
193fe989
VZ
437 // "no redraw" MDI child frame
438 wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
439 wndclass.style = styleNoRedraw;
440
441 if ( !RegisterClass(&wndclass) )
442 {
f6bcfd97 443 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
193fe989
VZ
444 }
445
77c46f00 446 return true;
2bda0e17
KB
447}
448
9787a4b6
VZ
449// ---------------------------------------------------------------------------
450// UnregisterWindowClasses
451// ---------------------------------------------------------------------------
452
453bool wxApp::UnregisterWindowClasses()
454{
77c46f00 455 bool retval = true;
9787a4b6 456
c67d6888 457#ifndef __WXMICROWIN__
9787a4b6 458 // MDI frame window class.
03baf031 459 if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
9787a4b6
VZ
460 {
461 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
462
77c46f00 463 retval = false;
9787a4b6
VZ
464 }
465
466 // "no redraw" MDI frame
03baf031 467 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
9787a4b6
VZ
468 {
469 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
470
77c46f00 471 retval = false;
9787a4b6
VZ
472 }
473
474 // MDI child frame window class.
03baf031 475 if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
9787a4b6
VZ
476 {
477 wxLogLastError(wxT("UnregisterClass(MDI child)"));
478
77c46f00 479 retval = false;
9787a4b6
VZ
480 }
481
482 // "no redraw" MDI child frame
03baf031 483 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
9787a4b6
VZ
484 {
485 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
486
77c46f00 487 retval = false;
9787a4b6
VZ
488 }
489
03baf031
VZ
490 // canvas class name
491 if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
9787a4b6
VZ
492 {
493 wxLogLastError(wxT("UnregisterClass(canvas)"));
494
77c46f00 495 retval = false;
9787a4b6
VZ
496 }
497
03baf031 498 if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
9787a4b6
VZ
499 {
500 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
501
77c46f00 502 retval = false;
9787a4b6 503 }
03baf031
VZ
504#endif // __WXMICROWIN__
505
9787a4b6
VZ
506 return retval;
507}
508
bb6290e3 509void wxApp::CleanUp()
2bda0e17 510{
7a9dfa3c
VZ
511 // all objects pending for deletion must be deleted first, otherwise we
512 // would crash when they use wxWinHandleHash (and UnregisterWindowClasses()
513 // call wouldn't succeed as long as any windows still exist), so call the
514 // base class method first and only then do our clean up
515 wxAppBase::CleanUp();
516
4676948b 517#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
77c46f00 518 wxSetKeyboardHook(false);
04ef50df 519#endif
2bda0e17 520
360ae33f 521 wxOleUninitialize();
2bda0e17 522
9787a4b6
VZ
523 // for an EXE the classes are unregistered when it terminates but DLL may
524 // be loaded several times (load/unload/load) into the same process in
525 // which case the registration will fail after the first time if we don't
526 // unregister the classes now
527 UnregisterWindowClasses();
9787a4b6 528
1bffa913 529 delete wxWinHandleHash;
94826170 530 wxWinHandleHash = NULL;
a71d815b 531
46fa338b
RR
532#ifdef __WXWINCE__
533 free( wxCanvasClassName );
534 free( wxCanvasClassNameNR );
535#endif
2bda0e17
KB
536}
537
94826170
VZ
538// ----------------------------------------------------------------------------
539// wxApp ctor/dtor
540// ----------------------------------------------------------------------------
589f0e3e 541
bb6290e3 542wxApp::wxApp()
2bda0e17 543{
e5c0b16a 544 m_printMode = wxPRINT_WINDOWS;
2bda0e17
KB
545}
546
589f0e3e
JS
547wxApp::~wxApp()
548{
589f0e3e
JS
549}
550
6046e57a
VZ
551// ----------------------------------------------------------------------------
552// wxApp idle handling
553// ----------------------------------------------------------------------------
554
cb3c7fdd 555void wxApp::OnIdle(wxIdleEvent& WXUNUSED(event))
2bda0e17 556{
aef94d68
JS
557#if wxUSE_DC_CACHEING
558 // automated DC cache management: clear the cached DCs and bitmap
559 // if it's likely that the app has finished with them, that is, we
560 // get an idle event and we're not dragging anything.
4624defa 561 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
888dde65 562 wxMSWDCImpl::ClearCache();
aef94d68 563#endif // wxUSE_DC_CACHEING
2bda0e17
KB
564}
565
e2478fde
VZ
566void wxApp::WakeUpIdle()
567{
568 // Send the top window a dummy message so idle handler processing will
569 // start up again. Doing it this way ensures that the idle handler
570 // wakes up in the right thread (see also wxWakeUpMainThread() which does
571 // the same for the main app thread only)
572 wxWindow *topWindow = wxTheApp->GetTopWindow();
573 if ( topWindow )
574 {
575 if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
576 {
577 // should never happen
578 wxLogLastError(wxT("PostMessage(WM_NULL)"));
579 }
580 }
581}
582
6046e57a
VZ
583// ----------------------------------------------------------------------------
584// other wxApp event hanlders
585// ----------------------------------------------------------------------------
586
57c208c5 587void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
387a3b02
JS
588{
589 if (GetTopWindow())
77c46f00 590 GetTopWindow()->Close(true);
387a3b02
JS
591}
592
593// Default behaviour: close the application with prompts. The
594// user can veto the close, and therefore the end session.
595void wxApp::OnQueryEndSession(wxCloseEvent& event)
596{
597 if (GetTopWindow())
598 {
599 if (!GetTopWindow()->Close(!event.CanVeto()))
77c46f00 600 event.Veto(true);
387a3b02
JS
601 }
602}
603
6046e57a 604// ----------------------------------------------------------------------------
5e9b921d 605// system DLL versions
6046e57a
VZ
606// ----------------------------------------------------------------------------
607
5e9b921d
VZ
608#if wxUSE_DYNLIB_CLASS
609
610namespace
611{
612
613// helper function: retrieve the DLL version by using DllGetVersion(), returns
614// 0 if the DLL doesn't export such function
615int CallDllGetVersion(wxDynamicLibrary& dll)
616{
617 // now check if the function is available during run-time
618 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dll );
619 if ( !pfnDllGetVersion )
620 return 0;
621
622 DLLVERSIONINFO dvi;
623 dvi.cbSize = sizeof(dvi);
624
625 HRESULT hr = (*pfnDllGetVersion)(&dvi);
626 if ( FAILED(hr) )
627 {
628 wxLogApiError(_T("DllGetVersion"), hr);
629
630 return 0;
631 }
632
633 return 100*dvi.dwMajorVersion + dvi.dwMinorVersion;
634}
635
636} // anonymous namespace
637
6d167489
VZ
638/* static */
639int wxApp::GetComCtl32Version()
640{
6d167489 641 // cache the result
9fc6c21c
VZ
642 //
643 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
644 // but as its value should be the same both times it doesn't matter
bdc72a22
VZ
645 static int s_verComCtl32 = -1;
646
6d167489
VZ
647 if ( s_verComCtl32 == -1 )
648 {
9fc6c21c
VZ
649 // we're prepared to handle the errors
650 wxLogNull noLog;
ad9835c9 651
5e9b921d 652 // the DLL should really be available
9fc6c21c 653 wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
5e9b921d
VZ
654 if ( !dllComCtl32.IsLoaded() )
655 {
656 s_verComCtl32 = 0;
657 return 0;
658 }
6d167489 659
5e9b921d
VZ
660 // try DllGetVersion() for recent DLLs
661 s_verComCtl32 = CallDllGetVersion(dllComCtl32);
662
663 // if DllGetVersion() is unavailable either during compile or
664 // run-time, try to guess the version otherwise
665 if ( !s_verComCtl32 )
bb6290e3 666 {
5e9b921d
VZ
667 // InitCommonControlsEx is unique to 4.70 and later
668 void *pfn = dllComCtl32.GetSymbol(_T("InitCommonControlsEx"));
669 if ( !pfn )
9fc6c21c 670 {
5e9b921d
VZ
671 // not found, must be 4.00
672 s_verComCtl32 = 400;
9fc6c21c 673 }
5e9b921d 674 else // 4.70+
9fc6c21c 675 {
5e9b921d
VZ
676 // many symbols appeared in comctl32 4.71, could use any of
677 // them except may be DllInstall()
678 pfn = dllComCtl32.GetSymbol(_T("InitializeFlatSB"));
9fc6c21c
VZ
679 if ( !pfn )
680 {
5e9b921d
VZ
681 // not found, must be 4.70
682 s_verComCtl32 = 470;
6d167489 683 }
5e9b921d 684 else
bdc72a22 685 {
5e9b921d
VZ
686 // found, must be 4.71 or later
687 s_verComCtl32 = 471;
6d167489 688 }
9fc6c21c 689 }
ef094fa0 690 }
bb6290e3 691 }
6d167489
VZ
692
693 return s_verComCtl32;
bb6290e3
JS
694}
695
5e9b921d
VZ
696/* static */
697int wxApp::GetShell32Version()
698{
699 static int s_verShell32 = -1;
700 if ( s_verShell32 == -1 )
701 {
702 // we're prepared to handle the errors
703 wxLogNull noLog;
704
705 wxDynamicLibrary dllShell32(_T("shell32.dll"), wxDL_VERBATIM);
706 if ( dllShell32.IsLoaded() )
707 {
708 s_verShell32 = CallDllGetVersion(dllShell32);
709
710 if ( !s_verShell32 )
711 {
712 // there doesn't seem to be any way to distinguish between 4.00
713 // and 4.70 (starting from 4.71 we have DllGetVersion()) so
714 // just assume it is 4.0
715 s_verShell32 = 400;
716 }
717 }
718 else // failed load the DLL?
719 {
720 s_verShell32 = 0;
721 }
722 }
723
724 return s_verShell32;
725}
726
727#else // !wxUSE_DYNLIB_CLASS
728
729/* static */
730int wxApp::GetComCtl32Version()
731{
732 return 0;
733}
734
735/* static */
736int wxApp::GetShell32Version()
737{
738 return 0;
739}
740
741#endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS
742
743// ----------------------------------------------------------------------------
2bda0e17 744// Yield to incoming messages
5e9b921d 745// ----------------------------------------------------------------------------
cb2713bf 746
8461e4c2 747bool wxApp::Yield(bool onlyIfNeeded)
2bda0e17 748{
8461e4c2 749 // MT-FIXME
77c46f00 750 static bool s_inYield = false;
8461e4c2 751
e30285ab 752#if wxUSE_LOG
2ed3265e
VZ
753 // disable log flushing from here because a call to wxYield() shouldn't
754 // normally result in message boxes popping up &c
755 wxLog::Suspend();
e30285ab 756#endif // wxUSE_LOG
2ed3265e 757
8461e4c2
VZ
758 if ( s_inYield )
759 {
760 if ( !onlyIfNeeded )
761 {
762 wxFAIL_MSG( wxT("wxYield called recursively" ) );
763 }
33ac7e6f 764
77c46f00 765 return false;
8461e4c2
VZ
766 }
767
77c46f00 768 s_inYield = true;
cb2713bf 769
8e193f38
VZ
770 // we don't want to process WM_QUIT from here - it should be processed in
771 // the main event loop in order to stop it
e5c0b16a 772 MSG msg;
8e193f38
VZ
773 while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
774 msg.message != WM_QUIT )
e5c0b16a 775 {
5b615ed8
VZ
776#if wxUSE_THREADS
777 wxMutexGuiLeaveOrEnter();
778#endif // wxUSE_THREADS
779
1bf77ee5 780 if ( !wxTheApp->Dispatch() )
e5c0b16a
VZ
781 break;
782 }
8e193f38 783
8461e4c2
VZ
784 // if there are pending events, we must process them.
785 ProcessPendingEvents();
e5c0b16a 786
e30285ab 787#if wxUSE_LOG
2ed3265e
VZ
788 // let the logs be flashed again
789 wxLog::Resume();
e30285ab 790#endif // wxUSE_LOG
2ed3265e 791
77c46f00 792 s_inYield = false;
cb2713bf 793
77c46f00 794 return true;
2bda0e17 795}
094637f6 796
6046e57a
VZ
797#if wxUSE_EXCEPTIONS
798
799// ----------------------------------------------------------------------------
800// exception handling
801// ----------------------------------------------------------------------------
802
803bool wxApp::OnExceptionInMainLoop()
804{
805 // ask the user about what to do: use the Win32 API function here as it
77ffb593 806 // could be dangerous to use any wxWidgets code in this state
6046e57a
VZ
807 switch (
808 ::MessageBox
809 (
810 NULL,
811 _T("An unhandled exception occurred. Press \"Abort\" to \
812terminate the program,\r\n\
813\"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
814 _T("Unhandled exception"),
815 MB_ABORTRETRYIGNORE |
a71d815b 816 MB_ICONERROR|
6046e57a
VZ
817 MB_TASKMODAL
818 )
819 )
820 {
821 case IDABORT:
822 throw;
823
824 default:
825 wxFAIL_MSG( _T("unexpected MessageBox() return code") );
826 // fall through
827
828 case IDRETRY:
829 return false;
830
831 case IDIGNORE:
832 return true;
833 }
834}
835
836#endif // wxUSE_EXCEPTIONS