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