]> git.saurik.com Git - wxWidgets.git/blame - src/msw/app.cpp
compilation fix
[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
2bda0e17 20#ifdef __GNUG__
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"
4bf78aae 54
4286a5b5
RR
55#include "wx/msw/private.h"
56
4bf78aae 57#if wxUSE_THREADS
bee503b0
VZ
58 #include "wx/thread.h"
59
60 // define the array of MSG strutures
61 WX_DECLARE_OBJARRAY(MSG, wxMsgArray);
62
63 #include "wx/arrimpl.cpp"
64
65 WX_DEFINE_OBJARRAY(wxMsgArray);
66#endif // wxUSE_THREADS
2bda0e17 67
8614c467
VZ
68#if wxUSE_TOOLTIPS
69 #include "wx/tooltip.h"
70#endif // wxUSE_TOOLTIPS
71
c42404a5
VZ
72// OLE is used for drag-and-drop, clipboard, OLE Automation..., but some
73// compilers don't support it (missing headers, libs, ...)
2bdf7154 74#if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__) || defined(__SALFORDC__)
e5c0b16a
VZ
75 #undef wxUSE_OLE
76
77 #define wxUSE_OLE 0
78#endif // broken compilers
79
80#if wxUSE_OLE
6e0d9d43 81 #include <ole2.h>
d05237ea 82#endif
ce3ed50d 83
2bda0e17 84#include <string.h>
a5e0e655 85#include <ctype.h>
2bda0e17 86
b39dbf34 87#if defined(__WIN95__) && !((defined(__GNUWIN32_OLD__) || defined(__WXMICROWIN__)) && !defined(__CYGWIN10__))
e5c0b16a 88 #include <commctrl.h>
2bda0e17
KB
89#endif
90
bdc72a22
VZ
91// ----------------------------------------------------------------------------
92// conditional compilation
93// ----------------------------------------------------------------------------
94
95// The macro _WIN32_IE is defined by commctrl.h (unless it had already been
96// defined before) and shows us what common control features are available
97// during the compile time (it doesn't mean that they will be available during
98// the run-time, use GetComCtl32Version() to test for them!). The possible
99// values are:
100//
101// 0x0200 for comctl32.dll 4.00 shipped with Win95/NT 4.0
102// 0x0300 4.70 IE 3.x
103// 0x0400 4.71 IE 4.0
104// 0x0401 4.72 IE 4.01 and Win98
105// 0x0500 5.00 IE 5.x and NT 5.0 (Win2000)
106
107#ifndef _WIN32_IE
108 // minimal set of features by default
109 #define _WIN32_IE 0x0200
110#endif
111
a4a2e5d2 112#if _WIN32_IE >= 0x0300 && \
7f93875d 113 (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \
e5898961
MB
114 !defined(__CYGWIN__) && !defined(__WXWINCE__) && \
115 (!defined(_MSC_VER) || (_MSC_VER > 1100))
036bc7d9
VZ
116 #include <shlwapi.h>
117#endif
118
e5c0b16a
VZ
119// ---------------------------------------------------------------------------
120// global variables
121// ---------------------------------------------------------------------------
122
cde9f08e 123extern wxList WXDLLEXPORT wxPendingDelete;
4676948b
JS
124
125#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
2bda0e17 126extern void wxSetKeyboardHook(bool doIt);
04ef50df 127#endif
2bda0e17 128
42e69d6b 129MSG s_currentMsg;
2bda0e17 130
193fe989
VZ
131// NB: all "NoRedraw" classes must have the same names as the "normal" classes
132// with NR suffix - wxWindow::MSWCreate() supposes this
03baf031
VZ
133const wxChar *wxCanvasClassName = wxT("wxWindowClass");
134const wxChar *wxCanvasClassNameNR = wxT("wxWindowClassNR");
2ffa221c
VZ
135const wxChar *wxMDIFrameClassName = wxT("wxMDIFrameClass");
136const wxChar *wxMDIFrameClassNameNoRedraw = wxT("wxMDIFrameClassNR");
137const wxChar *wxMDIChildFrameClassName = wxT("wxMDIChildFrameClass");
138const wxChar *wxMDIChildFrameClassNameNoRedraw = wxT("wxMDIChildFrameClassNR");
2bda0e17 139
57c208c5 140HBRUSH wxDisableButtonBrush = (HBRUSH) 0;
2bda0e17 141
94826170
VZ
142// ----------------------------------------------------------------------------
143// private functions
144// ----------------------------------------------------------------------------
2bda0e17 145
94826170 146LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
3b415ba4 147
e5c0b16a 148// ===========================================================================
e2478fde
VZ
149// wxGUIAppTraits implementation
150// ===========================================================================
151
152// private class which we use to pass parameters from BeforeChildWaitLoop() to
153// AfterChildWaitLoop()
154struct ChildWaitLoopData
155{
156 ChildWaitLoopData(wxWindowDisabler *wd_, wxWindow *winActive_)
157 {
158 wd = wd_;
159 winActive = winActive_;
160 }
161
162 wxWindowDisabler *wd;
163 wxWindow *winActive;
164};
165
166void *wxGUIAppTraits::BeforeChildWaitLoop()
167{
168 /*
169 We use a dirty hack here to disable all application windows (which we
170 must do because otherwise the calls to wxYield() could lead to some very
171 unexpected reentrancies in the users code) but to avoid losing
172 focus/activation entirely when the child process terminates which would
173 happen if we simply disabled everything using wxWindowDisabler. Indeed,
174 remember that Windows will never activate a disabled window and when the
175 last childs window is closed and Windows looks for a window to activate
176 all our windows are still disabled. There is no way to enable them in
177 time because we don't know when the childs windows are going to be
178 closed, so the solution we use here is to keep one special tiny frame
179 enabled all the time. Then when the child terminates it will get
180 activated and when we close it below -- after reenabling all the other
181 windows! -- the previously active window becomes activated again and
182 everything is ok.
183 */
184 wxBeginBusyCursor();
185
186 // first disable all existing windows
187 wxWindowDisabler *wd = new wxWindowDisabler;
188
189 // then create an "invisible" frame: it has minimal size, is positioned
190 // (hopefully) outside the screen and doesn't appear on the taskbar
191 wxWindow *winActive = new wxFrame
192 (
193 wxTheApp->GetTopWindow(),
fda7962d
JS
194 wxID_ANY,
195 wxEmptyString,
e2478fde
VZ
196 wxPoint(32600, 32600),
197 wxSize(1, 1),
198 wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR
199 );
200 winActive->Show();
201
202 return new ChildWaitLoopData(wd, winActive);
203}
204
205void wxGUIAppTraits::AlwaysYield()
206{
207 wxYield();
208}
209
210void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
211{
212 wxEndBusyCursor();
213
214 const ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig;
215
216 delete data->wd;
217
218 // finally delete the dummy frame and, as wd has been already destroyed and
219 // the other windows reenabled, the activation is going to return to the
220 // window which had had it before
221 data->winActive->Destroy();
222}
223
224bool wxGUIAppTraits::DoMessageFromThreadWait()
225{
226 return !wxTheApp || wxTheApp->DoMessage();
227}
228
229// ===========================================================================
230// wxApp implementation
e5c0b16a 231// ===========================================================================
589f0e3e 232
94826170
VZ
233int wxApp::m_nCmdShow = SW_SHOWNORMAL;
234
e5c0b16a 235// ---------------------------------------------------------------------------
e2478fde 236// wxWin macros
e5c0b16a
VZ
237// ---------------------------------------------------------------------------
238
f6bcfd97 239IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
e5c0b16a 240
f6bcfd97
BP
241BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
242 EVT_IDLE(wxApp::OnIdle)
243 EVT_END_SESSION(wxApp::OnEndSession)
244 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
245END_EVENT_TABLE()
e5c0b16a 246
94826170
VZ
247// class to ensure that wxAppBase::CleanUp() is called if our Initialize()
248// fails
249class wxCallBaseCleanup
250{
251public:
252 wxCallBaseCleanup(wxApp *app) : m_app(app) { }
253 ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
254
255 void Dismiss() { m_app = NULL; }
256
257private:
258 wxApp *m_app;
259};
260
e5c0b16a 261//// Initialize
05e2b077 262bool wxApp::Initialize(int& argc, wxChar **argv)
2bda0e17 263{
94826170
VZ
264 if ( !wxAppBase::Initialize(argc, argv) )
265 return false;
266
267 // ensure that base cleanup is done if we return too early
268 wxCallBaseCleanup callBaseCleanup(this);
269
f6bcfd97 270 // the first thing to do is to check if we're trying to run an Unicode
7c9955d1 271 // program under Win9x w/o MSLU emulation layer - if so, abort right now
dfc40ef3 272 // as it has no chance to work
eb5e4d9a 273#if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
f07dc2e2 274 if ( wxGetOsVersion() != wxWINDOWS_NT && wxGetOsVersion() != wxWINDOWS_CE )
f6bcfd97
BP
275 {
276 // note that we can use MessageBoxW() as it's implemented even under
277 // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs
278 // used by wxLocale are not
279 ::MessageBox
280 (
281 NULL,
f07dc2e2 282 _T("This program uses Unicode and requires Windows NT/2000/XP/CE.\nProgram aborted."),
f6bcfd97
BP
283 _T("wxWindows Fatal Error"),
284 MB_ICONERROR | MB_OK
285 );
286
287 return FALSE;
288 }
eb5e4d9a 289#endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
f6bcfd97 290
04ef50df 291#if defined(__WIN95__) && !defined(__WXMICROWIN__)
a5e0e655 292 InitCommonControls();
e5c0b16a 293#endif // __WIN95__
2bda0e17 294
8cb172b4 295#if wxUSE_OLE || wxUSE_DRAG_AND_DROP
c49245f8
VZ
296
297#ifdef __WIN16__
e5c0b16a 298 // for OLE, enlarge message queue to be as large as possible
aa0b7e1e 299 int iMsg = 96;
c49245f8
VZ
300 while (!SetMessageQueue(iMsg) && (iMsg -= 8))
301 ;
302#endif // Win16
8cb172b4 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
1f112209 317#if wxUSE_CTL3D
a5e0e655 318 if (!Ctl3dRegister(wxhInstance))
223d09f6 319 wxLogError(wxT("Cannot register CTL3D"));
2bda0e17 320
a5e0e655 321 Ctl3dAutoSubclass(wxhInstance);
1e6feb95 322#endif // wxUSE_CTL3D
2bda0e17 323
aa0b7e1e 324 RegisterWindowClasses();
2bda0e17 325
4676948b 326#if defined(__WXMICROWIN__) && !defined(__WXWINCE__)
aa0b7e1e 327 // Create the brush for disabling bitmap buttons
2bda0e17 328
42e69d6b 329 LOGBRUSH lb;
aa0b7e1e 330 lb.lbStyle = BS_PATTERN;
097f29c2 331 lb.lbColor = 0;
223d09f6 332 lb.lbHatch = (int)LoadBitmap( wxhInstance, wxT("wxDISABLE_BUTTON_BITMAP") );
3a5ffa81
VZ
333 if ( lb.lbHatch )
334 {
335 wxDisableButtonBrush = ::CreateBrushIndirect( & lb );
336 ::DeleteObject( (HGDIOBJ)lb.lbHatch );
337 }
338 //else: wxWindows resources are probably not linked in
04ef50df 339#endif
2bda0e17 340
aa0b7e1e 341#if wxUSE_PENWINDOWS
a5e0e655 342 wxRegisterPenWin();
aa0b7e1e 343#endif
2bda0e17 344
1bffa913 345 wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
2bda0e17 346
6e0d9d43 347 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
8cbd2bde 348 // PLEASE DO NOT ALTER THIS.
7fee680b 349#if defined(__VISUALC__) && defined(__WIN16__) && !defined(WXMAKINGDLL)
a5e0e655
VZ
350 extern char wxDummyChar;
351 if (wxDummyChar) wxDummyChar++;
aa0b7e1e 352#endif
a5e0e655 353
4676948b 354#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
aa0b7e1e 355 wxSetKeyboardHook(TRUE);
04ef50df 356#endif
2bda0e17 357
94826170
VZ
358 callBaseCleanup.Dismiss();
359
360 return true;
2bda0e17
KB
361}
362
42e69d6b
VZ
363// ---------------------------------------------------------------------------
364// RegisterWindowClasses
365// ---------------------------------------------------------------------------
589f0e3e 366
b782f2e0
VZ
367// TODO we should only register classes really used by the app. For this it
368// would be enough to just delay the class registration until an attempt
369// to create a window of this class is made.
bb6290e3 370bool wxApp::RegisterWindowClasses()
2bda0e17 371{
42e69d6b 372 WNDCLASS wndclass;
03baf031 373 wxZeroMemory(wndclass);
e5c0b16a 374
193fe989
VZ
375 // for each class we register one with CS_(V|H)REDRAW style and one
376 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
377 static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
378 static const long styleNoRedraw = CS_DBLCLKS;
379
42e69d6b 380 // the fields which are common to all classes
e5c0b16a 381 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
e5c0b16a 382 wndclass.hInstance = wxhInstance;
42e69d6b 383 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
42e69d6b
VZ
384
385 // Register the frame window class.
386 wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
03baf031 387 wndclass.lpszClassName = wxCanvasClassName;
b782f2e0 388 wndclass.style = styleNormal;
e5c0b16a 389
42e69d6b 390 if ( !RegisterClass(&wndclass) )
e5c0b16a 391 {
f6bcfd97 392 wxLogLastError(wxT("RegisterClass(frame)"));
e5c0b16a
VZ
393 }
394
193fe989 395 // "no redraw" frame
03baf031 396 wndclass.lpszClassName = wxCanvasClassNameNR;
193fe989
VZ
397 wndclass.style = styleNoRedraw;
398
399 if ( !RegisterClass(&wndclass) )
400 {
f6bcfd97 401 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
193fe989
VZ
402 }
403
e5c0b16a 404 // Register the MDI frame window class.
42e69d6b 405 wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
b782f2e0
VZ
406 wndclass.lpszClassName = wxMDIFrameClassName;
407 wndclass.style = styleNormal;
42e69d6b
VZ
408
409 if ( !RegisterClass(&wndclass) )
e5c0b16a 410 {
f6bcfd97 411 wxLogLastError(wxT("RegisterClass(MDI parent)"));
e5c0b16a
VZ
412 }
413
193fe989 414 // "no redraw" MDI frame
b782f2e0 415 wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
193fe989
VZ
416 wndclass.style = styleNoRedraw;
417
418 if ( !RegisterClass(&wndclass) )
419 {
f6bcfd97 420 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
193fe989
VZ
421 }
422
e5c0b16a 423 // Register the MDI child frame window class.
42e69d6b
VZ
424 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
425 wndclass.lpszClassName = wxMDIChildFrameClassName;
b782f2e0 426 wndclass.style = styleNormal;
42e69d6b
VZ
427
428 if ( !RegisterClass(&wndclass) )
e5c0b16a 429 {
f6bcfd97 430 wxLogLastError(wxT("RegisterClass(MDI child)"));
e5c0b16a
VZ
431 }
432
193fe989
VZ
433 // "no redraw" MDI child frame
434 wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
435 wndclass.style = styleNoRedraw;
436
437 if ( !RegisterClass(&wndclass) )
438 {
f6bcfd97 439 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
193fe989
VZ
440 }
441
e5c0b16a 442 return TRUE;
2bda0e17
KB
443}
444
9787a4b6
VZ
445// ---------------------------------------------------------------------------
446// UnregisterWindowClasses
447// ---------------------------------------------------------------------------
448
449bool wxApp::UnregisterWindowClasses()
450{
451 bool retval = TRUE;
452
c67d6888 453#ifndef __WXMICROWIN__
9787a4b6 454 // MDI frame window class.
03baf031 455 if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
9787a4b6
VZ
456 {
457 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
458
459 retval = FALSE;
460 }
461
462 // "no redraw" MDI frame
03baf031 463 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
9787a4b6
VZ
464 {
465 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
466
467 retval = FALSE;
468 }
469
470 // MDI child frame window class.
03baf031 471 if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
9787a4b6
VZ
472 {
473 wxLogLastError(wxT("UnregisterClass(MDI child)"));
474
475 retval = FALSE;
476 }
477
478 // "no redraw" MDI child frame
03baf031 479 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
9787a4b6
VZ
480 {
481 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
482
483 retval = FALSE;
484 }
485
03baf031
VZ
486 // canvas class name
487 if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
9787a4b6
VZ
488 {
489 wxLogLastError(wxT("UnregisterClass(canvas)"));
490
491 retval = FALSE;
492 }
493
03baf031 494 if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
9787a4b6
VZ
495 {
496 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
497
498 retval = FALSE;
499 }
03baf031
VZ
500#endif // __WXMICROWIN__
501
9787a4b6
VZ
502 return retval;
503}
504
bb6290e3 505void wxApp::CleanUp()
2bda0e17 506{
4676948b 507#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
e5c0b16a 508 wxSetKeyboardHook(FALSE);
04ef50df 509#endif
2bda0e17 510
47d67540 511#if wxUSE_PENWINDOWS
e5c0b16a 512 wxCleanUpPenWin();
2bda0e17
KB
513#endif
514
e5c0b16a 515 if ( wxDisableButtonBrush )
42e69d6b 516 ::DeleteObject( wxDisableButtonBrush );
e5c0b16a
VZ
517
518#if wxUSE_OLE
f07dc2e2
JS
519#ifdef __WXWINCE__
520 ::CoUninitialize();
521#else
e5c0b16a 522 ::OleUninitialize();
f07dc2e2 523#endif
5de5db0e 524#endif
2bda0e17 525
9787a4b6
VZ
526 // for an EXE the classes are unregistered when it terminates but DLL may
527 // be loaded several times (load/unload/load) into the same process in
528 // which case the registration will fail after the first time if we don't
529 // unregister the classes now
530 UnregisterWindowClasses();
9787a4b6 531
1f112209 532#if wxUSE_CTL3D
e5c0b16a 533 Ctl3dUnregister(wxhInstance);
2bda0e17
KB
534#endif
535
1bffa913 536 delete wxWinHandleHash;
94826170 537 wxWinHandleHash = NULL;
f8a3e080 538
94826170 539 wxAppBase::CleanUp();
2bda0e17
KB
540}
541
94826170
VZ
542// ----------------------------------------------------------------------------
543// wxApp ctor/dtor
544// ----------------------------------------------------------------------------
589f0e3e 545
bb6290e3 546wxApp::wxApp()
2bda0e17 547{
e5c0b16a 548 m_printMode = wxPRINT_WINDOWS;
2bda0e17
KB
549}
550
589f0e3e
JS
551wxApp::~wxApp()
552{
94826170
VZ
553 // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
554 // don't come from main(), so we have to free them
555
556 while ( argc )
e5c0b16a 557 {
94826170
VZ
558 // m_argv elements were allocated by wxStrdup()
559 free(argv[--argc]);
e5c0b16a 560 }
94826170
VZ
561
562 // but m_argv itself -- using new[]
563 delete [] argv;
589f0e3e
JS
564}
565
bb6290e3 566bool wxApp::Initialized()
2bda0e17
KB
567{
568#ifndef _WINDLL
e5c0b16a
VZ
569 if (GetTopWindow())
570 return TRUE;
571 else
572 return FALSE;
3b415ba4 573#else // Assume initialized if DLL (no way of telling)
e5c0b16a 574 return TRUE;
2bda0e17
KB
575#endif
576}
577
578/*
579 * Get and process a message, returning FALSE if WM_QUIT
bee503b0 580 * received (and also set the flag telling the app to exit the main loop)
2bda0e17
KB
581 *
582 */
bb6290e3 583bool wxApp::DoMessage()
2bda0e17 584{
bee503b0
VZ
585 BOOL rc = ::GetMessage(&s_currentMsg, (HWND) NULL, 0, 0);
586 if ( rc == 0 )
587 {
588 // got WM_QUIT
589 m_keepGoing = FALSE;
4a9968f9 590
bee503b0
VZ
591 return FALSE;
592 }
593 else if ( rc == -1 )
594 {
595 // should never happen, but let's test for it nevertheless
f6bcfd97 596 wxLogLastError(wxT("GetMessage"));
bee503b0
VZ
597 }
598 else
599 {
600#if wxUSE_THREADS
601 wxASSERT_MSG( wxThread::IsMain(),
223d09f6 602 wxT("only the main thread can process Windows messages") );
d50b2a58 603
bee503b0
VZ
604 static bool s_hadGuiLock = TRUE;
605 static wxMsgArray s_aSavedMessages;
606
607 // if a secondary thread owns is doing GUI calls, save all messages for
608 // later processing - we can't process them right now because it will
609 // lead to recursive library calls (and we're not reentrant)
610 if ( !wxGuiOwnedByMainThread() )
611 {
612 s_hadGuiLock = FALSE;
613
4a9968f9
VZ
614 // leave out WM_COMMAND messages: too dangerous, sometimes
615 // the message will be processed twice
616 if ( !wxIsWaitingForThread() ||
e5c0b16a 617 s_currentMsg.message != WM_COMMAND )
4a9968f9
VZ
618 {
619 s_aSavedMessages.Add(s_currentMsg);
620 }
bee503b0
VZ
621
622 return TRUE;
623 }
624 else
625 {
626 // have we just regained the GUI lock? if so, post all of the saved
627 // messages
628 //
629 // FIXME of course, it's not _exactly_ the same as processing the
630 // messages normally - expect some things to break...
631 if ( !s_hadGuiLock )
632 {
633 s_hadGuiLock = TRUE;
634
0a95f6d0 635 size_t count = s_aSavedMessages.GetCount();
bee503b0
VZ
636 for ( size_t n = 0; n < count; n++ )
637 {
638 MSG& msg = s_aSavedMessages[n];
639
0a95f6d0 640 DoMessage((WXMSG *)&msg);
bee503b0
VZ
641 }
642
643 s_aSavedMessages.Empty();
644 }
645 }
646#endif // wxUSE_THREADS
647
648 // Process the message
ed45e263 649 DoMessage((WXMSG *)&s_currentMsg);
bee503b0
VZ
650 }
651
652 return TRUE;
2bda0e17
KB
653}
654
ed45e263
VZ
655void wxApp::DoMessage(WXMSG *pMsg)
656{
657 if ( !ProcessMessage(pMsg) )
658 {
659 ::TranslateMessage((MSG *)pMsg);
660 ::DispatchMessage((MSG *)pMsg);
661 }
662}
663
2bda0e17
KB
664/*
665 * Keep trying to process messages until WM_QUIT
666 * received.
667 *
668 * If there are messages to be processed, they will all be
669 * processed and OnIdle will not be called.
670 * When there are no more messages, OnIdle is called.
671 * If OnIdle requests more time,
672 * it will be repeatedly called so long as there are no pending messages.
673 * A 'feature' of this is that once OnIdle has decided that no more processing
674 * is required, then it won't get processing time until further messages
675 * are processed (it'll sit in DoMessage).
676 */
677
bb6290e3 678int wxApp::MainLoop()
2bda0e17 679{
e5c0b16a 680 m_keepGoing = TRUE;
bee503b0 681
e5c0b16a
VZ
682 while ( m_keepGoing )
683 {
684#if wxUSE_THREADS
bee503b0 685 wxMutexGuiLeaveOrEnter();
e5c0b16a 686#endif // wxUSE_THREADS
bee503b0 687
b6c588e1
VZ
688 while ( !Pending() && ProcessIdle() )
689 ;
7214297d 690
b6c588e1 691 // a message came or no more idle processing to do
e5c0b16a
VZ
692 DoMessage();
693 }
2bda0e17 694
e5c0b16a 695 return s_currentMsg.wParam;
2bda0e17
KB
696}
697
bb6290e3 698void wxApp::ExitMainLoop()
2bda0e17 699{
1cbee0b4
VZ
700 // this will set m_keepGoing to FALSE a bit later
701 ::PostQuitMessage(0);
2bda0e17
KB
702}
703
bb6290e3 704bool wxApp::Pending()
2bda0e17 705{
b6c588e1 706 return ::PeekMessage(&s_currentMsg, 0, 0, 0, PM_NOREMOVE) != 0;
2bda0e17
KB
707}
708
bb6290e3 709void wxApp::Dispatch()
2bda0e17 710{
bee503b0 711 DoMessage();
2bda0e17
KB
712}
713
714/*
715 * Give all windows a chance to preprocess
716 * the message. Some may have accelerator tables, or have
717 * MDI complications.
718 */
2a47d3c1 719
d3f0a137 720bool wxApp::ProcessMessage(WXMSG *wxmsg)
2bda0e17 721{
d3f0a137 722 MSG *msg = (MSG *)wxmsg;
2a3caeb5
VZ
723 HWND hwnd = msg->hwnd;
724 wxWindow *wndThis = wxGetWindowFromHWND((WXHWND)hwnd);
2bda0e17 725
761989ff
VZ
726 // this may happen if the event occured in a standard modeless dialog (the
727 // only example of which I know of is the find/replace dialog) - then call
728 // IsDialogMessage() to make TAB navigation in it work
729 if ( !wndThis )
730 {
2a3caeb5
VZ
731 // we need to find the dialog containing this control as
732 // IsDialogMessage() just eats all the messages (i.e. returns TRUE for
733 // them) if we call it for the control itself
de7f0860 734 while ( hwnd && ::GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD )
2a3caeb5
VZ
735 {
736 hwnd = ::GetParent(hwnd);
737 }
738
de7f0860 739 return hwnd && ::IsDialogMessage(hwnd, msg) != 0;
761989ff
VZ
740 }
741
8614c467
VZ
742#if wxUSE_TOOLTIPS
743 // we must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to
744 // popup the tooltip bubbles
761989ff 745 if ( (msg->message == WM_MOUSEMOVE) )
834362a2 746 {
8614c467
VZ
747 wxToolTip *tt = wndThis->GetToolTip();
748 if ( tt )
749 {
750 tt->RelayEvent(wxmsg);
751 }
834362a2 752 }
8614c467 753#endif // wxUSE_TOOLTIPS
834362a2 754
a37d422a
VZ
755 // allow the window to prevent certain messages from being
756 // translated/processed (this is currently used by wxTextCtrl to always
757 // grab Ctrl-C/V/X, even if they are also accelerators in some parent)
758 if ( !wndThis->MSWShouldPreProcessMessage(wxmsg) )
759 {
760 return FALSE;
761 }
762
2a3caeb5 763 // try translations first: the accelerators override everything
8614c467 764 wxWindow *wnd;
42bcb12b 765
d3f0a137 766 for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
2bda0e17 767 {
2a3caeb5 768 if ( wnd->MSWTranslateMessage(wxmsg))
d3f0a137 769 return TRUE;
3bdc265d
VZ
770
771 // stop at first top level window, i.e. don't try to process the key
772 // strokes originating in a dialog using the accelerators of the parent
773 // frame - this doesn't make much sense
774 if ( wnd->IsTopLevel() )
2a3caeb5
VZ
775 break;
776 }
777
a37d422a
VZ
778 // now try the other hooks (kbd navigation is handled here): we start from
779 // wndThis->GetParent() because wndThis->MSWProcessMessage() was already
780 // called above
781 for ( wnd = wndThis->GetParent(); wnd; wnd = wnd->GetParent() )
2a3caeb5
VZ
782 {
783 if ( wnd->MSWProcessMessage(wxmsg) )
784 return TRUE;
57a7b7c1 785 }
d3f0a137 786
a37d422a 787 // no special preprocessing for this message, dispatch it normally
e5c0b16a 788 return FALSE;
2bda0e17
KB
789}
790
2b5f62a0
VZ
791// this is a temporary hack and will be replaced by using wxEventLoop in the
792// future
793//
794// it is needed to allow other event loops (currently only one: the modal
795// dialog one) to reset the OnIdle() semaphore because otherwise OnIdle()
796// wouldn't do anything while a modal dialog shown from OnIdle() call is shown.
797bool wxIsInOnIdleFlag = FALSE;
798
2bda0e17
KB
799void wxApp::OnIdle(wxIdleEvent& event)
800{
3222fde2 801 // Avoid recursion (via ProcessEvent default case)
2b5f62a0 802 if ( wxIsInOnIdleFlag )
3222fde2 803 return;
2bda0e17 804
2b5f62a0 805 wxIsInOnIdleFlag = TRUE;
955a9197
JS
806
807 wxAppBase::OnIdle(event);
c54f78a2 808
aef94d68
JS
809#if wxUSE_DC_CACHEING
810 // automated DC cache management: clear the cached DCs and bitmap
811 // if it's likely that the app has finished with them, that is, we
812 // get an idle event and we're not dragging anything.
4624defa 813 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
aef94d68
JS
814 wxDC::ClearCache();
815#endif // wxUSE_DC_CACHEING
816
2b5f62a0 817 wxIsInOnIdleFlag = FALSE;
2bda0e17
KB
818}
819
e2478fde
VZ
820void wxApp::WakeUpIdle()
821{
822 // Send the top window a dummy message so idle handler processing will
823 // start up again. Doing it this way ensures that the idle handler
824 // wakes up in the right thread (see also wxWakeUpMainThread() which does
825 // the same for the main app thread only)
826 wxWindow *topWindow = wxTheApp->GetTopWindow();
827 if ( topWindow )
828 {
829 if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
830 {
831 // should never happen
832 wxLogLastError(wxT("PostMessage(WM_NULL)"));
833 }
834 }
835}
836
57c208c5 837void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
387a3b02
JS
838{
839 if (GetTopWindow())
840 GetTopWindow()->Close(TRUE);
841}
842
843// Default behaviour: close the application with prompts. The
844// user can veto the close, and therefore the end session.
845void wxApp::OnQueryEndSession(wxCloseEvent& event)
846{
847 if (GetTopWindow())
848 {
849 if (!GetTopWindow()->Close(!event.CanVeto()))
850 event.Veto(TRUE);
851 }
852}
853
ef094fa0
JS
854typedef struct _WXADllVersionInfo
855{
856 DWORD cbSize;
857 DWORD dwMajorVersion; // Major version
858 DWORD dwMinorVersion; // Minor version
859 DWORD dwBuildNumber; // Build number
860 DWORD dwPlatformID; // DLLVER_PLATFORM_*
861} WXADLLVERSIONINFO;
862
863typedef HRESULT (CALLBACK* WXADLLGETVERSIONPROC)(WXADLLVERSIONINFO *);
864
6d167489
VZ
865/* static */
866int wxApp::GetComCtl32Version()
867{
4676948b 868#if defined(__WXMICROWIN__) || defined(__WXWINCE__)
04ef50df
JS
869 return 0;
870#else
6d167489 871 // cache the result
bdc72a22
VZ
872 static int s_verComCtl32 = -1;
873
874 wxCRIT_SECT_DECLARE(csComCtl32);
875 wxCRIT_SECT_LOCKER(lock, csComCtl32);
6d167489
VZ
876
877 if ( s_verComCtl32 == -1 )
878 {
bdc72a22 879 // initally assume no comctl32.dll at all
6d167489
VZ
880 s_verComCtl32 = 0;
881
bdc72a22
VZ
882 // do we have it?
883 HMODULE hModuleComCtl32 = ::GetModuleHandle(wxT("COMCTL32"));
ef094fa0
JS
884 BOOL bFreeComCtl32 = FALSE ;
885 if(!hModuleComCtl32)
886 {
887 hModuleComCtl32 = ::LoadLibrary(wxT("COMCTL32.DLL")) ;
888 if(hModuleComCtl32)
889 {
890 bFreeComCtl32 = TRUE ;
891 }
892 }
6d167489
VZ
893
894 // if so, then we can check for the version
bdc72a22 895 if ( hModuleComCtl32 )
bb6290e3 896 {
bdc72a22 897 // try to use DllGetVersion() if available in _headers_
ef094fa0 898 WXADLLGETVERSIONPROC pfnDllGetVersion = (WXADLLGETVERSIONPROC)
f6bcfd97 899 ::GetProcAddress(hModuleComCtl32, "DllGetVersion");
bdc72a22 900 if ( pfnDllGetVersion )
6d167489 901 {
ef094fa0 902 WXADLLVERSIONINFO dvi;
bdc72a22
VZ
903 dvi.cbSize = sizeof(dvi);
904
905 HRESULT hr = (*pfnDllGetVersion)(&dvi);
906 if ( FAILED(hr) )
907 {
908 wxLogApiError(_T("DllGetVersion"), hr);
909 }
910 else
911 {
912 // this is incompatible with _WIN32_IE values, but
913 // compatible with the other values returned by
914 // GetComCtl32Version()
915 s_verComCtl32 = 100*dvi.dwMajorVersion +
916 dvi.dwMinorVersion;
917 }
6d167489 918 }
bdc72a22
VZ
919 // DllGetVersion() unavailable either during compile or
920 // run-time, try to guess the version otherwise
921 if ( !s_verComCtl32 )
922 {
923 // InitCommonControlsEx is unique to 4.70 and later
924 FARPROC theProc = ::GetProcAddress
925 (
926 hModuleComCtl32,
a8ee71c7 927 "InitCommonControlsEx"
bdc72a22
VZ
928 );
929
930 if ( !theProc )
931 {
932 // not found, must be 4.00
933 s_verComCtl32 = 400;
934 }
935 else
936 {
937 // many symbols appeared in comctl32 4.71, could use
938 // any of them except may be DllInstall
939 theProc = ::GetProcAddress
940 (
941 hModuleComCtl32,
a8ee71c7 942 "InitializeFlatSB"
bdc72a22
VZ
943 );
944 if ( !theProc )
945 {
946 // not found, must be 4.70
947 s_verComCtl32 = 470;
948 }
949 else
950 {
951 // found, must be 4.71
952 s_verComCtl32 = 471;
953 }
954 }
6d167489 955 }
bb6290e3 956 }
ef094fa0
JS
957
958 if(bFreeComCtl32)
959 {
960 ::FreeLibrary(hModuleComCtl32) ;
961 }
bb6290e3 962 }
6d167489
VZ
963
964 return s_verComCtl32;
04ef50df 965#endif
bb6290e3
JS
966}
967
2bda0e17 968// Yield to incoming messages
cb2713bf 969
8461e4c2 970bool wxApp::Yield(bool onlyIfNeeded)
2bda0e17 971{
8461e4c2
VZ
972 // MT-FIXME
973 static bool s_inYield = FALSE;
974
e30285ab 975#if wxUSE_LOG
2ed3265e
VZ
976 // disable log flushing from here because a call to wxYield() shouldn't
977 // normally result in message boxes popping up &c
978 wxLog::Suspend();
e30285ab 979#endif // wxUSE_LOG
2ed3265e 980
8461e4c2
VZ
981 if ( s_inYield )
982 {
983 if ( !onlyIfNeeded )
984 {
985 wxFAIL_MSG( wxT("wxYield called recursively" ) );
986 }
33ac7e6f 987
8461e4c2
VZ
988 return FALSE;
989 }
990
991 s_inYield = TRUE;
cb2713bf 992
8e193f38
VZ
993 // we don't want to process WM_QUIT from here - it should be processed in
994 // the main event loop in order to stop it
e5c0b16a 995 MSG msg;
8e193f38
VZ
996 while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
997 msg.message != WM_QUIT )
e5c0b16a 998 {
5b615ed8
VZ
999#if wxUSE_THREADS
1000 wxMutexGuiLeaveOrEnter();
1001#endif // wxUSE_THREADS
1002
e5c0b16a
VZ
1003 if ( !wxTheApp->DoMessage() )
1004 break;
1005 }
8e193f38 1006
8461e4c2
VZ
1007 // if there are pending events, we must process them.
1008 ProcessPendingEvents();
e5c0b16a 1009
e30285ab 1010#if wxUSE_LOG
2ed3265e
VZ
1011 // let the logs be flashed again
1012 wxLog::Resume();
e30285ab 1013#endif // wxUSE_LOG
2ed3265e 1014
8461e4c2 1015 s_inYield = FALSE;
cb2713bf 1016
e5c0b16a 1017 return TRUE;
2bda0e17 1018}
094637f6 1019