]> git.saurik.com Git - wxWidgets.git/blame - src/msw/app.cpp
Applied [ 1059554 ] patch for [1028659] fixes a couple of bugs with menus
[wxWidgets.git] / src / msw / app.cpp
CommitLineData
2bda0e17
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: app.cpp
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
14f355c2 20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
e5c0b16a 21 #pragma implementation "app.h"
2bda0e17
KB
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
2bda0e17
KB
25#include "wx/wxprec.h"
26
27#if defined(__BORLANDC__)
e5c0b16a 28 #pragma hdrstop
2bda0e17
KB
29#endif
30
31#ifndef WX_PRECOMP
e5c0b16a
VZ
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"
72cdf4c9
VZ
46 #include "wx/wxchar.h"
47 #include "wx/icon.h"
31f6de22 48 #include "wx/log.h"
2bda0e17
KB
49#endif
50
e2478fde 51#include "wx/apptrait.h"
7104f65d 52#include "wx/filename.h"
2bda0e17 53#include "wx/module.h"
9fc6c21c 54#include "wx/dynlib.h"
4bf78aae 55
4286a5b5
RR
56#include "wx/msw/private.h"
57
8614c467
VZ
58#if wxUSE_TOOLTIPS
59 #include "wx/tooltip.h"
60#endif // wxUSE_TOOLTIPS
61
c42404a5
VZ
62// OLE is used for drag-and-drop, clipboard, OLE Automation..., but some
63// compilers don't support it (missing headers, libs, ...)
2bdf7154 64#if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__) || defined(__SALFORDC__)
e5c0b16a
VZ
65 #undef wxUSE_OLE
66
67 #define wxUSE_OLE 0
68#endif // broken compilers
69
70#if wxUSE_OLE
6e0d9d43 71 #include <ole2.h>
d05237ea 72#endif
ce3ed50d 73
2bda0e17 74#include <string.h>
a5e0e655 75#include <ctype.h>
2bda0e17 76
0d236fd0 77#include "wx/msw/wrapcctl.h"
bdc72a22 78
6046e57a
VZ
79// For MB_TASKMODAL
80#ifdef __WXWINCE__
81#include "wx/msw/wince/missing.h"
82#endif
83
9fc6c21c 84#if (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \
50165591 85 !defined(__CYGWIN__) && !defined(__DIGITALMARS__) && !defined(__WXWINCE__) && \
1bf77ee5 86 (!defined(_MSC_VER) || (_MSC_VER > 1100))
036bc7d9
VZ
87 #include <shlwapi.h>
88#endif
89
e5c0b16a
VZ
90// ---------------------------------------------------------------------------
91// global variables
92// ---------------------------------------------------------------------------
93
cde9f08e 94extern wxList WXDLLEXPORT wxPendingDelete;
4676948b
JS
95
96#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
2bda0e17 97extern void wxSetKeyboardHook(bool doIt);
04ef50df 98#endif
2bda0e17 99
193fe989
VZ
100// NB: all "NoRedraw" classes must have the same names as the "normal" classes
101// with NR suffix - wxWindow::MSWCreate() supposes this
46fa338b 102#ifdef __WXWINCE__
7a4d2469
RN
103WXDLLIMPEXP_CORE wxChar *wxCanvasClassName;
104WXDLLIMPEXP_CORE wxChar *wxCanvasClassNameNR;
46fa338b 105#else
7a4d2469
RN
106WXDLLIMPEXP_CORE const wxChar *wxCanvasClassName = wxT("wxWindowClass");
107WXDLLIMPEXP_CORE const wxChar *wxCanvasClassNameNR = wxT("wxWindowClassNR");
46fa338b 108#endif
7a4d2469
RN
109WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassName = wxT("wxMDIFrameClass");
110WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassNameNoRedraw = wxT("wxMDIFrameClassNR");
111WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassName = wxT("wxMDIChildFrameClass");
112WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassNameNoRedraw = wxT("wxMDIChildFrameClassNR");
2bda0e17 113
94826170
VZ
114// ----------------------------------------------------------------------------
115// private functions
116// ----------------------------------------------------------------------------
2bda0e17 117
94826170 118LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
3b415ba4 119
e5c0b16a 120// ===========================================================================
e2478fde
VZ
121// wxGUIAppTraits implementation
122// ===========================================================================
123
124// private class which we use to pass parameters from BeforeChildWaitLoop() to
125// AfterChildWaitLoop()
126struct 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
138void *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(),
fda7962d
JS
166 wxID_ANY,
167 wxEmptyString,
e2478fde
VZ
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
177void wxGUIAppTraits::AlwaysYield()
178{
179 wxYield();
180}
181
182void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
183{
184 wxEndBusyCursor();
185
0588f8d7 186 ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig;
e2478fde
VZ
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();
51036b44
VZ
194
195 // also delete the temporary data object itself
196 delete data;
e2478fde
VZ
197}
198
199bool wxGUIAppTraits::DoMessageFromThreadWait()
200{
1bf77ee5
VZ
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();
e2478fde
VZ
204}
205
324899f6 206wxToolkitInfo& wxGUIAppTraits::GetToolkitInfo()
a8eaaeb2 207{
1bf77ee5 208 static wxToolkitInfo info;
324899f6
VS
209 wxToolkitInfo& baseInfo = wxAppTraits::GetToolkitInfo();
210 info.versionMajor = baseInfo.versionMajor;
211 info.versionMinor = baseInfo.versionMinor;
212 info.os = baseInfo.os;
a8eaaeb2
VS
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
324899f6 219 return info;
a8eaaeb2
VS
220}
221
e2478fde
VZ
222// ===========================================================================
223// wxApp implementation
e5c0b16a 224// ===========================================================================
589f0e3e 225
94826170
VZ
226int wxApp::m_nCmdShow = SW_SHOWNORMAL;
227
e5c0b16a 228// ---------------------------------------------------------------------------
e2478fde 229// wxWin macros
e5c0b16a
VZ
230// ---------------------------------------------------------------------------
231
f6bcfd97 232IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
e5c0b16a 233
f6bcfd97
BP
234BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
235 EVT_IDLE(wxApp::OnIdle)
236 EVT_END_SESSION(wxApp::OnEndSession)
237 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
238END_EVENT_TABLE()
e5c0b16a 239
94826170
VZ
240// class to ensure that wxAppBase::CleanUp() is called if our Initialize()
241// fails
242class wxCallBaseCleanup
243{
244public:
245 wxCallBaseCleanup(wxApp *app) : m_app(app) { }
246 ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
247
248 void Dismiss() { m_app = NULL; }
249
250private:
251 wxApp *m_app;
252};
253
e5c0b16a 254//// Initialize
05e2b077 255bool wxApp::Initialize(int& argc, wxChar **argv)
2bda0e17 256{
94826170
VZ
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
46fa338b
RR
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
f6bcfd97 277 // the first thing to do is to check if we're trying to run an Unicode
7c9955d1 278 // program under Win9x w/o MSLU emulation layer - if so, abort right now
dfc40ef3 279 // as it has no chance to work
eb5e4d9a 280#if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
f07dc2e2 281 if ( wxGetOsVersion() != wxWINDOWS_NT && wxGetOsVersion() != wxWINDOWS_CE )
f6bcfd97
BP
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,
f07dc2e2 289 _T("This program uses Unicode and requires Windows NT/2000/XP/CE.\nProgram aborted."),
77ffb593 290 _T("wxWidgets Fatal Error"),
f6bcfd97
BP
291 MB_ICONERROR | MB_OK
292 );
293
77c46f00 294 return false;
f6bcfd97 295 }
eb5e4d9a 296#endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
f6bcfd97 297
04ef50df 298#if defined(__WIN95__) && !defined(__WXMICROWIN__)
a5e0e655 299 InitCommonControls();
e5c0b16a 300#endif // __WIN95__
2bda0e17 301
8cb172b4 302#if wxUSE_OLE || wxUSE_DRAG_AND_DROP
c49245f8 303
abad5367 304#if wxUSE_OLE
a5e0e655 305 // we need to initialize OLE library
f07dc2e2
JS
306#ifdef __WXWINCE__
307 if ( FAILED(::CoInitializeEx(NULL, COINIT_MULTITHREADED)) )
308 wxLogError(_("Cannot initialize OLE"));
309#else
a5e0e655 310 if ( FAILED(::OleInitialize(NULL)) )
e5c0b16a 311 wxLogError(_("Cannot initialize OLE"));
abad5367 312#endif
f07dc2e2 313#endif
1e6feb95 314
c49245f8 315#endif // wxUSE_OLE
2bda0e17 316
aa0b7e1e 317 RegisterWindowClasses();
2bda0e17 318
aa0b7e1e 319#if wxUSE_PENWINDOWS
a5e0e655 320 wxRegisterPenWin();
aa0b7e1e 321#endif
2bda0e17 322
1bffa913 323 wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
2bda0e17 324
4676948b 325#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
77c46f00 326 wxSetKeyboardHook(true);
04ef50df 327#endif
2bda0e17 328
94826170
VZ
329 callBaseCleanup.Dismiss();
330
331 return true;
2bda0e17
KB
332}
333
42e69d6b
VZ
334// ---------------------------------------------------------------------------
335// RegisterWindowClasses
336// ---------------------------------------------------------------------------
589f0e3e 337
b782f2e0
VZ
338// TODO we should only register classes really used by the app. For this it
339// would be enough to just delay the class registration until an attempt
340// to create a window of this class is made.
bb6290e3 341bool wxApp::RegisterWindowClasses()
2bda0e17 342{
42e69d6b 343 WNDCLASS wndclass;
03baf031 344 wxZeroMemory(wndclass);
e5c0b16a 345
193fe989
VZ
346 // for each class we register one with CS_(V|H)REDRAW style and one
347 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
348 static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
349 static const long styleNoRedraw = CS_DBLCLKS;
350
42e69d6b 351 // the fields which are common to all classes
e5c0b16a 352 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
e5c0b16a 353 wndclass.hInstance = wxhInstance;
42e69d6b 354 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
42e69d6b 355
b9691677
VZ
356 // register the class for all normal windows
357 wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
03baf031 358 wndclass.lpszClassName = wxCanvasClassName;
b782f2e0 359 wndclass.style = styleNormal;
e5c0b16a 360
42e69d6b 361 if ( !RegisterClass(&wndclass) )
e5c0b16a 362 {
f6bcfd97 363 wxLogLastError(wxT("RegisterClass(frame)"));
e5c0b16a
VZ
364 }
365
193fe989 366 // "no redraw" frame
03baf031 367 wndclass.lpszClassName = wxCanvasClassNameNR;
193fe989
VZ
368 wndclass.style = styleNoRedraw;
369
370 if ( !RegisterClass(&wndclass) )
371 {
f6bcfd97 372 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
193fe989
VZ
373 }
374
e5c0b16a 375 // Register the MDI frame window class.
42e69d6b 376 wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
b782f2e0
VZ
377 wndclass.lpszClassName = wxMDIFrameClassName;
378 wndclass.style = styleNormal;
42e69d6b
VZ
379
380 if ( !RegisterClass(&wndclass) )
e5c0b16a 381 {
f6bcfd97 382 wxLogLastError(wxT("RegisterClass(MDI parent)"));
e5c0b16a
VZ
383 }
384
193fe989 385 // "no redraw" MDI frame
b782f2e0 386 wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
193fe989
VZ
387 wndclass.style = styleNoRedraw;
388
389 if ( !RegisterClass(&wndclass) )
390 {
f6bcfd97 391 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
193fe989
VZ
392 }
393
e5c0b16a 394 // Register the MDI child frame window class.
42e69d6b
VZ
395 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
396 wndclass.lpszClassName = wxMDIChildFrameClassName;
b782f2e0 397 wndclass.style = styleNormal;
42e69d6b
VZ
398
399 if ( !RegisterClass(&wndclass) )
e5c0b16a 400 {
f6bcfd97 401 wxLogLastError(wxT("RegisterClass(MDI child)"));
e5c0b16a
VZ
402 }
403
193fe989
VZ
404 // "no redraw" MDI child frame
405 wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
406 wndclass.style = styleNoRedraw;
407
408 if ( !RegisterClass(&wndclass) )
409 {
f6bcfd97 410 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
193fe989
VZ
411 }
412
77c46f00 413 return true;
2bda0e17
KB
414}
415
9787a4b6
VZ
416// ---------------------------------------------------------------------------
417// UnregisterWindowClasses
418// ---------------------------------------------------------------------------
419
420bool wxApp::UnregisterWindowClasses()
421{
77c46f00 422 bool retval = true;
9787a4b6 423
c67d6888 424#ifndef __WXMICROWIN__
9787a4b6 425 // MDI frame window class.
03baf031 426 if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
9787a4b6
VZ
427 {
428 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
429
77c46f00 430 retval = false;
9787a4b6
VZ
431 }
432
433 // "no redraw" MDI frame
03baf031 434 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
9787a4b6
VZ
435 {
436 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
437
77c46f00 438 retval = false;
9787a4b6
VZ
439 }
440
441 // MDI child frame window class.
03baf031 442 if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
9787a4b6
VZ
443 {
444 wxLogLastError(wxT("UnregisterClass(MDI child)"));
445
77c46f00 446 retval = false;
9787a4b6
VZ
447 }
448
449 // "no redraw" MDI child frame
03baf031 450 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
9787a4b6
VZ
451 {
452 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
453
77c46f00 454 retval = false;
9787a4b6
VZ
455 }
456
03baf031
VZ
457 // canvas class name
458 if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
9787a4b6
VZ
459 {
460 wxLogLastError(wxT("UnregisterClass(canvas)"));
461
77c46f00 462 retval = false;
9787a4b6
VZ
463 }
464
03baf031 465 if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
9787a4b6
VZ
466 {
467 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
468
77c46f00 469 retval = false;
9787a4b6 470 }
03baf031
VZ
471#endif // __WXMICROWIN__
472
9787a4b6
VZ
473 return retval;
474}
475
bb6290e3 476void wxApp::CleanUp()
2bda0e17 477{
7a9dfa3c
VZ
478 // all objects pending for deletion must be deleted first, otherwise we
479 // would crash when they use wxWinHandleHash (and UnregisterWindowClasses()
480 // call wouldn't succeed as long as any windows still exist), so call the
481 // base class method first and only then do our clean up
482 wxAppBase::CleanUp();
483
4676948b 484#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
77c46f00 485 wxSetKeyboardHook(false);
04ef50df 486#endif
2bda0e17 487
47d67540 488#if wxUSE_PENWINDOWS
e5c0b16a 489 wxCleanUpPenWin();
2bda0e17
KB
490#endif
491
e5c0b16a 492#if wxUSE_OLE
f07dc2e2
JS
493#ifdef __WXWINCE__
494 ::CoUninitialize();
495#else
e5c0b16a 496 ::OleUninitialize();
f07dc2e2 497#endif
5de5db0e 498#endif
2bda0e17 499
9787a4b6
VZ
500 // for an EXE the classes are unregistered when it terminates but DLL may
501 // be loaded several times (load/unload/load) into the same process in
502 // which case the registration will fail after the first time if we don't
503 // unregister the classes now
504 UnregisterWindowClasses();
9787a4b6 505
1bffa913 506 delete wxWinHandleHash;
94826170 507 wxWinHandleHash = NULL;
46fa338b
RR
508
509#ifdef __WXWINCE__
510 free( wxCanvasClassName );
511 free( wxCanvasClassNameNR );
512#endif
2bda0e17
KB
513}
514
94826170
VZ
515// ----------------------------------------------------------------------------
516// wxApp ctor/dtor
517// ----------------------------------------------------------------------------
589f0e3e 518
bb6290e3 519wxApp::wxApp()
2bda0e17 520{
e5c0b16a 521 m_printMode = wxPRINT_WINDOWS;
2bda0e17
KB
522}
523
589f0e3e
JS
524wxApp::~wxApp()
525{
94826170
VZ
526 // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
527 // don't come from main(), so we have to free them
528
529 while ( argc )
e5c0b16a 530 {
94826170
VZ
531 // m_argv elements were allocated by wxStrdup()
532 free(argv[--argc]);
e5c0b16a 533 }
94826170
VZ
534
535 // but m_argv itself -- using new[]
536 delete [] argv;
589f0e3e
JS
537}
538
6046e57a
VZ
539// ----------------------------------------------------------------------------
540// wxApp idle handling
541// ----------------------------------------------------------------------------
542
2bda0e17
KB
543void wxApp::OnIdle(wxIdleEvent& event)
544{
955a9197 545 wxAppBase::OnIdle(event);
c54f78a2 546
aef94d68
JS
547#if wxUSE_DC_CACHEING
548 // automated DC cache management: clear the cached DCs and bitmap
549 // if it's likely that the app has finished with them, that is, we
550 // get an idle event and we're not dragging anything.
4624defa 551 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
aef94d68
JS
552 wxDC::ClearCache();
553#endif // wxUSE_DC_CACHEING
2bda0e17
KB
554}
555
e2478fde
VZ
556void wxApp::WakeUpIdle()
557{
558 // Send the top window a dummy message so idle handler processing will
559 // start up again. Doing it this way ensures that the idle handler
560 // wakes up in the right thread (see also wxWakeUpMainThread() which does
561 // the same for the main app thread only)
562 wxWindow *topWindow = wxTheApp->GetTopWindow();
563 if ( topWindow )
564 {
565 if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
566 {
567 // should never happen
568 wxLogLastError(wxT("PostMessage(WM_NULL)"));
569 }
570 }
571}
572
6046e57a
VZ
573// ----------------------------------------------------------------------------
574// other wxApp event hanlders
575// ----------------------------------------------------------------------------
576
57c208c5 577void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
387a3b02
JS
578{
579 if (GetTopWindow())
77c46f00 580 GetTopWindow()->Close(true);
387a3b02
JS
581}
582
583// Default behaviour: close the application with prompts. The
584// user can veto the close, and therefore the end session.
585void wxApp::OnQueryEndSession(wxCloseEvent& event)
586{
587 if (GetTopWindow())
588 {
589 if (!GetTopWindow()->Close(!event.CanVeto()))
77c46f00 590 event.Veto(true);
387a3b02
JS
591 }
592}
593
6046e57a
VZ
594// ----------------------------------------------------------------------------
595// miscellaneous
596// ----------------------------------------------------------------------------
597
6d167489
VZ
598/* static */
599int wxApp::GetComCtl32Version()
600{
fd7b70bd 601#if defined(__WXMICROWIN__) || defined(__WXWINCE__)
04ef50df
JS
602 return 0;
603#else
6d167489 604 // cache the result
9fc6c21c
VZ
605 //
606 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
607 // but as its value should be the same both times it doesn't matter
bdc72a22
VZ
608 static int s_verComCtl32 = -1;
609
6d167489
VZ
610 if ( s_verComCtl32 == -1 )
611 {
bdc72a22 612 // initally assume no comctl32.dll at all
6d167489
VZ
613 s_verComCtl32 = 0;
614
9fc6c21c
VZ
615 // we're prepared to handle the errors
616 wxLogNull noLog;
617
bdc72a22 618 // do we have it?
9fc6c21c 619 wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
6d167489
VZ
620
621 // if so, then we can check for the version
9fc6c21c 622 if ( dllComCtl32.IsLoaded() )
bb6290e3 623 {
548bf4b7 624#ifdef DLLVER_PLATFORM_WINDOWS
bdc72a22 625 // try to use DllGetVersion() if available in _headers_
9fc6c21c
VZ
626 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dllComCtl32 );
627 if ( pfnDllGetVersion )
628 {
629 DLLVERSIONINFO dvi;
630 dvi.cbSize = sizeof(dvi);
631
632 HRESULT hr = (*pfnDllGetVersion)(&dvi);
633 if ( FAILED(hr) )
6d167489 634 {
9fc6c21c
VZ
635 wxLogApiError(_T("DllGetVersion"), hr);
636 }
637 else
638 {
639 // this is incompatible with _WIN32_IE values, but
640 // compatible with the other values returned by
641 // GetComCtl32Version()
642 s_verComCtl32 = 100*dvi.dwMajorVersion +
643 dvi.dwMinorVersion;
644 }
645 }
548bf4b7 646#endif
bdc72a22 647
9fc6c21c
VZ
648 // if DllGetVersion() is unavailable either during compile or
649 // run-time, try to guess the version otherwise
650 if ( !s_verComCtl32 )
651 {
652 // InitCommonControlsEx is unique to 4.70 and later
653 void *pfn = dllComCtl32.GetSymbol(_T("InitCommonControlsEx"));
654 if ( !pfn )
655 {
656 // not found, must be 4.00
657 s_verComCtl32 = 400;
6d167489 658 }
9fc6c21c 659 else // 4.70+
bdc72a22 660 {
9fc6c21c
VZ
661 // many symbols appeared in comctl32 4.71, could use any of
662 // them except may be DllInstall()
663 pfn = dllComCtl32.GetSymbol(_T("InitializeFlatSB"));
664 if ( !pfn )
bdc72a22 665 {
9fc6c21c
VZ
666 // not found, must be 4.70
667 s_verComCtl32 = 470;
bdc72a22
VZ
668 }
669 else
670 {
9fc6c21c
VZ
671 // found, must be 4.71 or later
672 s_verComCtl32 = 471;
bdc72a22 673 }
6d167489 674 }
9fc6c21c 675 }
ef094fa0 676 }
bb6290e3 677 }
6d167489
VZ
678
679 return s_verComCtl32;
9fc6c21c 680#endif // Microwin/!Microwin
bb6290e3
JS
681}
682
2bda0e17 683// Yield to incoming messages
cb2713bf 684
8461e4c2 685bool wxApp::Yield(bool onlyIfNeeded)
2bda0e17 686{
8461e4c2 687 // MT-FIXME
77c46f00 688 static bool s_inYield = false;
8461e4c2 689
e30285ab 690#if wxUSE_LOG
2ed3265e
VZ
691 // disable log flushing from here because a call to wxYield() shouldn't
692 // normally result in message boxes popping up &c
693 wxLog::Suspend();
e30285ab 694#endif // wxUSE_LOG
2ed3265e 695
8461e4c2
VZ
696 if ( s_inYield )
697 {
698 if ( !onlyIfNeeded )
699 {
700 wxFAIL_MSG( wxT("wxYield called recursively" ) );
701 }
33ac7e6f 702
77c46f00 703 return false;
8461e4c2
VZ
704 }
705
77c46f00 706 s_inYield = true;
cb2713bf 707
8e193f38
VZ
708 // we don't want to process WM_QUIT from here - it should be processed in
709 // the main event loop in order to stop it
e5c0b16a 710 MSG msg;
8e193f38
VZ
711 while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
712 msg.message != WM_QUIT )
e5c0b16a 713 {
5b615ed8
VZ
714#if wxUSE_THREADS
715 wxMutexGuiLeaveOrEnter();
716#endif // wxUSE_THREADS
717
1bf77ee5 718 if ( !wxTheApp->Dispatch() )
e5c0b16a
VZ
719 break;
720 }
8e193f38 721
8461e4c2
VZ
722 // if there are pending events, we must process them.
723 ProcessPendingEvents();
e5c0b16a 724
e30285ab 725#if wxUSE_LOG
2ed3265e
VZ
726 // let the logs be flashed again
727 wxLog::Resume();
e30285ab 728#endif // wxUSE_LOG
2ed3265e 729
77c46f00 730 s_inYield = false;
cb2713bf 731
77c46f00 732 return true;
2bda0e17 733}
094637f6 734
6046e57a
VZ
735#if wxUSE_EXCEPTIONS
736
737// ----------------------------------------------------------------------------
738// exception handling
739// ----------------------------------------------------------------------------
740
741bool wxApp::OnExceptionInMainLoop()
742{
743 // ask the user about what to do: use the Win32 API function here as it
77ffb593 744 // could be dangerous to use any wxWidgets code in this state
6046e57a
VZ
745 switch (
746 ::MessageBox
747 (
748 NULL,
749 _T("An unhandled exception occurred. Press \"Abort\" to \
750terminate the program,\r\n\
751\"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
752 _T("Unhandled exception"),
753 MB_ABORTRETRYIGNORE |
754 MB_ICONERROR|
755 MB_TASKMODAL
756 )
757 )
758 {
759 case IDABORT:
760 throw;
761
762 default:
763 wxFAIL_MSG( _T("unexpected MessageBox() return code") );
764 // fall through
765
766 case IDRETRY:
767 return false;
768
769 case IDIGNORE:
770 return true;
771 }
772}
773
774#endif // wxUSE_EXCEPTIONS
51036b44
VZ
775
776// ----------------------------------------------------------------------------
777// deprecated event loop functions
778// ----------------------------------------------------------------------------
779
780#if WXWIN_COMPATIBILITY_2_4
781
782#include "wx/evtloop.h"
783
784void wxApp::DoMessage(WXMSG *pMsg)
785{
786 wxEventLoop *evtLoop = wxEventLoop::GetActive();
787 if ( evtLoop )
788 evtLoop->ProcessMessage(pMsg);
789}
790
791bool wxApp::DoMessage()
792{
793 wxEventLoop *evtLoop = wxEventLoop::GetActive();
794 return evtLoop ? evtLoop->Dispatch() : false;
795}
796
797bool wxApp::ProcessMessage(WXMSG* pMsg)
798{
799 wxEventLoop *evtLoop = wxEventLoop::GetActive();
800 return evtLoop && evtLoop->PreProcessMessage(pMsg);
801}
802
803#endif // WXWIN_COMPATIBILITY_2_4
804