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