]> git.saurik.com Git - wxWidgets.git/blame - src/msw/app.cpp
fixed linker errors
[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"
31f6de22 52#include "wx/cmdline.h"
7104f65d 53#include "wx/filename.h"
2bda0e17 54#include "wx/module.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
04ef50df 92#ifndef __WXMICROWIN__
6e0d9d43 93#include "wx/msw/msvcrt.h"
04ef50df 94#endif
370382c7 95
bdc72a22
VZ
96// ----------------------------------------------------------------------------
97// conditional compilation
98// ----------------------------------------------------------------------------
99
100// The macro _WIN32_IE is defined by commctrl.h (unless it had already been
101// defined before) and shows us what common control features are available
102// during the compile time (it doesn't mean that they will be available during
103// the run-time, use GetComCtl32Version() to test for them!). The possible
104// values are:
105//
106// 0x0200 for comctl32.dll 4.00 shipped with Win95/NT 4.0
107// 0x0300 4.70 IE 3.x
108// 0x0400 4.71 IE 4.0
109// 0x0401 4.72 IE 4.01 and Win98
110// 0x0500 5.00 IE 5.x and NT 5.0 (Win2000)
111
112#ifndef _WIN32_IE
113 // minimal set of features by default
114 #define _WIN32_IE 0x0200
115#endif
116
a4a2e5d2 117#if _WIN32_IE >= 0x0300 && \
7f93875d
JS
118 (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \
119 !defined(__CYGWIN__)
036bc7d9
VZ
120 #include <shlwapi.h>
121#endif
122
e5c0b16a
VZ
123// ---------------------------------------------------------------------------
124// global variables
125// ---------------------------------------------------------------------------
126
837e5743 127extern wxChar *wxBuffer;
cde9f08e 128extern wxList WXDLLEXPORT wxPendingDelete;
04ef50df 129#ifndef __WXMICROWIN__
2bda0e17 130extern void wxSetKeyboardHook(bool doIt);
04ef50df 131#endif
2bda0e17 132
42e69d6b 133MSG s_currentMsg;
2bda0e17 134
193fe989
VZ
135// NB: all "NoRedraw" classes must have the same names as the "normal" classes
136// with NR suffix - wxWindow::MSWCreate() supposes this
03baf031
VZ
137const wxChar *wxCanvasClassName = wxT("wxWindowClass");
138const wxChar *wxCanvasClassNameNR = wxT("wxWindowClassNR");
2ffa221c
VZ
139const wxChar *wxMDIFrameClassName = wxT("wxMDIFrameClass");
140const wxChar *wxMDIFrameClassNameNoRedraw = wxT("wxMDIFrameClassNR");
141const wxChar *wxMDIChildFrameClassName = wxT("wxMDIChildFrameClass");
142const wxChar *wxMDIChildFrameClassNameNoRedraw = wxT("wxMDIChildFrameClassNR");
2bda0e17 143
57c208c5
JS
144HICON wxSTD_FRAME_ICON = (HICON) NULL;
145HICON wxSTD_MDICHILDFRAME_ICON = (HICON) NULL;
146HICON wxSTD_MDIPARENTFRAME_ICON = (HICON) NULL;
2bda0e17 147
57c208c5
JS
148HICON wxDEFAULT_FRAME_ICON = (HICON) NULL;
149HICON wxDEFAULT_MDICHILDFRAME_ICON = (HICON) NULL;
150HICON wxDEFAULT_MDIPARENTFRAME_ICON = (HICON) NULL;
2bda0e17 151
57c208c5 152HBRUSH wxDisableButtonBrush = (HBRUSH) 0;
2bda0e17 153
3135f4a7 154LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
2bda0e17 155
bd3277fe
VZ
156// FIXME wxUSE_ON_FATAL_EXCEPTION is only supported for VC++ now because it
157// needs compiler support for Win32 SEH. Others (especially Borland)
158// probably have it too, but I'm not sure about how it works
f6bcfd97
BP
159// JACS: get 'Cannot use __try in functions that require unwinding
160// in Unicode mode, so disabling.
161#if !defined(__VISUALC__) || defined(__WIN16__) || defined(UNICODE)
bd3277fe
VZ
162 #undef wxUSE_ON_FATAL_EXCEPTION
163 #define wxUSE_ON_FATAL_EXCEPTION 0
164#endif // VC++
165
3b415ba4
VZ
166#if wxUSE_ON_FATAL_EXCEPTION
167 static bool gs_handleExceptions = FALSE;
168#endif
169
e5c0b16a 170// ===========================================================================
e2478fde
VZ
171// wxGUIAppTraits implementation
172// ===========================================================================
173
174// private class which we use to pass parameters from BeforeChildWaitLoop() to
175// AfterChildWaitLoop()
176struct ChildWaitLoopData
177{
178 ChildWaitLoopData(wxWindowDisabler *wd_, wxWindow *winActive_)
179 {
180 wd = wd_;
181 winActive = winActive_;
182 }
183
184 wxWindowDisabler *wd;
185 wxWindow *winActive;
186};
187
188void *wxGUIAppTraits::BeforeChildWaitLoop()
189{
190 /*
191 We use a dirty hack here to disable all application windows (which we
192 must do because otherwise the calls to wxYield() could lead to some very
193 unexpected reentrancies in the users code) but to avoid losing
194 focus/activation entirely when the child process terminates which would
195 happen if we simply disabled everything using wxWindowDisabler. Indeed,
196 remember that Windows will never activate a disabled window and when the
197 last childs window is closed and Windows looks for a window to activate
198 all our windows are still disabled. There is no way to enable them in
199 time because we don't know when the childs windows are going to be
200 closed, so the solution we use here is to keep one special tiny frame
201 enabled all the time. Then when the child terminates it will get
202 activated and when we close it below -- after reenabling all the other
203 windows! -- the previously active window becomes activated again and
204 everything is ok.
205 */
206 wxBeginBusyCursor();
207
208 // first disable all existing windows
209 wxWindowDisabler *wd = new wxWindowDisabler;
210
211 // then create an "invisible" frame: it has minimal size, is positioned
212 // (hopefully) outside the screen and doesn't appear on the taskbar
213 wxWindow *winActive = new wxFrame
214 (
215 wxTheApp->GetTopWindow(),
216 -1,
217 _T(""),
218 wxPoint(32600, 32600),
219 wxSize(1, 1),
220 wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR
221 );
222 winActive->Show();
223
224 return new ChildWaitLoopData(wd, winActive);
225}
226
227void wxGUIAppTraits::AlwaysYield()
228{
229 wxYield();
230}
231
232void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
233{
234 wxEndBusyCursor();
235
236 const ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig;
237
238 delete data->wd;
239
240 // finally delete the dummy frame and, as wd has been already destroyed and
241 // the other windows reenabled, the activation is going to return to the
242 // window which had had it before
243 data->winActive->Destroy();
244}
245
246bool wxGUIAppTraits::DoMessageFromThreadWait()
247{
248 return !wxTheApp || wxTheApp->DoMessage();
249}
250
251// ===========================================================================
252// wxApp implementation
e5c0b16a 253// ===========================================================================
589f0e3e 254
e5c0b16a 255// ---------------------------------------------------------------------------
e2478fde 256// wxWin macros
e5c0b16a
VZ
257// ---------------------------------------------------------------------------
258
f6bcfd97 259IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
e5c0b16a 260
f6bcfd97
BP
261BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
262 EVT_IDLE(wxApp::OnIdle)
263 EVT_END_SESSION(wxApp::OnEndSession)
264 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
265END_EVENT_TABLE()
e5c0b16a 266
e5c0b16a 267//// Initialize
589f0e3e 268bool wxApp::Initialize()
2bda0e17 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
f6bcfd97
BP
274 if ( wxGetOsVersion() != wxWINDOWS_NT )
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,
eb5e4d9a 282 _T("This program uses Unicode and requires Windows NT/2000/XP.\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
837e5743 291 wxBuffer = new wxChar[1500]; // FIXME
589f0e3e 292
aa0b7e1e 293 wxClassInfo::InitializeClasses();
589f0e3e 294
4d3a259a 295#if wxUSE_THREADS
8e193f38 296 wxPendingEventsLocker = new wxCriticalSection;
4d3a259a
GL
297#endif
298
aa0b7e1e
JS
299 wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING);
300 wxTheColourDatabase->Initialize();
589f0e3e 301
aa0b7e1e
JS
302 wxInitializeStockLists();
303 wxInitializeStockObjects();
589f0e3e 304
aa0b7e1e 305 wxBitmap::InitStandardHandlers();
2bda0e17 306
04ef50df 307#if defined(__WIN95__) && !defined(__WXMICROWIN__)
a5e0e655 308 InitCommonControls();
e5c0b16a 309#endif // __WIN95__
2bda0e17 310
8cb172b4 311#if wxUSE_OLE || wxUSE_DRAG_AND_DROP
c49245f8
VZ
312
313#ifdef __WIN16__
e5c0b16a 314 // for OLE, enlarge message queue to be as large as possible
aa0b7e1e 315 int iMsg = 96;
c49245f8
VZ
316 while (!SetMessageQueue(iMsg) && (iMsg -= 8))
317 ;
318#endif // Win16
8cb172b4 319
abad5367 320#if wxUSE_OLE
a5e0e655
VZ
321 // we need to initialize OLE library
322 if ( FAILED(::OleInitialize(NULL)) )
e5c0b16a 323 wxLogError(_("Cannot initialize OLE"));
abad5367 324#endif
1e6feb95 325
c49245f8 326#endif // wxUSE_OLE
2bda0e17 327
1f112209 328#if wxUSE_CTL3D
a5e0e655 329 if (!Ctl3dRegister(wxhInstance))
223d09f6 330 wxLogError(wxT("Cannot register CTL3D"));
2bda0e17 331
a5e0e655 332 Ctl3dAutoSubclass(wxhInstance);
1e6feb95 333#endif // wxUSE_CTL3D
2bda0e17 334
87a1e308
VZ
335 // VZ: these icons are not in wx.rc anyhow (but should they?)!
336#if 0
223d09f6
KB
337 wxSTD_FRAME_ICON = LoadIcon(wxhInstance, wxT("wxSTD_FRAME"));
338 wxSTD_MDIPARENTFRAME_ICON = LoadIcon(wxhInstance, wxT("wxSTD_MDIPARENTFRAME"));
339 wxSTD_MDICHILDFRAME_ICON = LoadIcon(wxhInstance, wxT("wxSTD_MDICHILDFRAME"));
2bda0e17 340
223d09f6
KB
341 wxDEFAULT_FRAME_ICON = LoadIcon(wxhInstance, wxT("wxDEFAULT_FRAME"));
342 wxDEFAULT_MDIPARENTFRAME_ICON = LoadIcon(wxhInstance, wxT("wxDEFAULT_MDIPARENTFRAME"));
343 wxDEFAULT_MDICHILDFRAME_ICON = LoadIcon(wxhInstance, wxT("wxDEFAULT_MDICHILDFRAME"));
87a1e308 344#endif // 0
2bda0e17 345
aa0b7e1e 346 RegisterWindowClasses();
2bda0e17 347
04ef50df 348#ifndef __WXMICROWIN__
aa0b7e1e 349 // Create the brush for disabling bitmap buttons
2bda0e17 350
42e69d6b 351 LOGBRUSH lb;
aa0b7e1e 352 lb.lbStyle = BS_PATTERN;
097f29c2 353 lb.lbColor = 0;
223d09f6 354 lb.lbHatch = (int)LoadBitmap( wxhInstance, wxT("wxDISABLE_BUTTON_BITMAP") );
3a5ffa81
VZ
355 if ( lb.lbHatch )
356 {
357 wxDisableButtonBrush = ::CreateBrushIndirect( & lb );
358 ::DeleteObject( (HGDIOBJ)lb.lbHatch );
359 }
360 //else: wxWindows resources are probably not linked in
04ef50df 361#endif
2bda0e17 362
aa0b7e1e 363#if wxUSE_PENWINDOWS
a5e0e655 364 wxRegisterPenWin();
aa0b7e1e 365#endif
2bda0e17 366
1bffa913 367 wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
2bda0e17 368
6e0d9d43 369 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
8cbd2bde 370 // PLEASE DO NOT ALTER THIS.
7fee680b 371#if defined(__VISUALC__) && defined(__WIN16__) && !defined(WXMAKINGDLL)
a5e0e655
VZ
372 extern char wxDummyChar;
373 if (wxDummyChar) wxDummyChar++;
aa0b7e1e 374#endif
a5e0e655 375
04ef50df 376#ifndef __WXMICROWIN__
aa0b7e1e 377 wxSetKeyboardHook(TRUE);
04ef50df 378#endif
2bda0e17 379
aa0b7e1e
JS
380 wxModule::RegisterModules();
381 if (!wxModule::InitializeModules())
382 return FALSE;
383 return TRUE;
2bda0e17
KB
384}
385
42e69d6b
VZ
386// ---------------------------------------------------------------------------
387// RegisterWindowClasses
388// ---------------------------------------------------------------------------
589f0e3e 389
b782f2e0
VZ
390// TODO we should only register classes really used by the app. For this it
391// would be enough to just delay the class registration until an attempt
392// to create a window of this class is made.
bb6290e3 393bool wxApp::RegisterWindowClasses()
2bda0e17 394{
42e69d6b 395 WNDCLASS wndclass;
03baf031 396 wxZeroMemory(wndclass);
e5c0b16a 397
193fe989
VZ
398 // for each class we register one with CS_(V|H)REDRAW style and one
399 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
400 static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
401 static const long styleNoRedraw = CS_DBLCLKS;
402
42e69d6b 403 // the fields which are common to all classes
e5c0b16a 404 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
e5c0b16a 405 wndclass.hInstance = wxhInstance;
42e69d6b 406 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
42e69d6b
VZ
407
408 // Register the frame window class.
409 wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
03baf031 410 wndclass.lpszClassName = wxCanvasClassName;
b782f2e0 411 wndclass.style = styleNormal;
e5c0b16a 412
42e69d6b 413 if ( !RegisterClass(&wndclass) )
e5c0b16a 414 {
f6bcfd97 415 wxLogLastError(wxT("RegisterClass(frame)"));
e5c0b16a
VZ
416 }
417
193fe989 418 // "no redraw" frame
03baf031 419 wndclass.lpszClassName = wxCanvasClassNameNR;
193fe989
VZ
420 wndclass.style = styleNoRedraw;
421
422 if ( !RegisterClass(&wndclass) )
423 {
f6bcfd97 424 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
193fe989
VZ
425 }
426
e5c0b16a 427 // Register the MDI frame window class.
42e69d6b 428 wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
b782f2e0
VZ
429 wndclass.lpszClassName = wxMDIFrameClassName;
430 wndclass.style = styleNormal;
42e69d6b
VZ
431
432 if ( !RegisterClass(&wndclass) )
e5c0b16a 433 {
f6bcfd97 434 wxLogLastError(wxT("RegisterClass(MDI parent)"));
e5c0b16a
VZ
435 }
436
193fe989 437 // "no redraw" MDI frame
b782f2e0 438 wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
193fe989
VZ
439 wndclass.style = styleNoRedraw;
440
441 if ( !RegisterClass(&wndclass) )
442 {
f6bcfd97 443 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
193fe989
VZ
444 }
445
e5c0b16a 446 // Register the MDI child frame window class.
42e69d6b
VZ
447 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
448 wndclass.lpszClassName = wxMDIChildFrameClassName;
b782f2e0 449 wndclass.style = styleNormal;
42e69d6b
VZ
450
451 if ( !RegisterClass(&wndclass) )
e5c0b16a 452 {
f6bcfd97 453 wxLogLastError(wxT("RegisterClass(MDI child)"));
e5c0b16a
VZ
454 }
455
193fe989
VZ
456 // "no redraw" MDI child frame
457 wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
458 wndclass.style = styleNoRedraw;
459
460 if ( !RegisterClass(&wndclass) )
461 {
f6bcfd97 462 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
193fe989
VZ
463 }
464
e5c0b16a 465 return TRUE;
2bda0e17
KB
466}
467
9787a4b6
VZ
468// ---------------------------------------------------------------------------
469// UnregisterWindowClasses
470// ---------------------------------------------------------------------------
471
472bool wxApp::UnregisterWindowClasses()
473{
474 bool retval = TRUE;
475
c67d6888 476#ifndef __WXMICROWIN__
9787a4b6 477 // MDI frame window class.
03baf031 478 if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
9787a4b6
VZ
479 {
480 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
481
482 retval = FALSE;
483 }
484
485 // "no redraw" MDI frame
03baf031 486 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
9787a4b6
VZ
487 {
488 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
489
490 retval = FALSE;
491 }
492
493 // MDI child frame window class.
03baf031 494 if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
9787a4b6
VZ
495 {
496 wxLogLastError(wxT("UnregisterClass(MDI child)"));
497
498 retval = FALSE;
499 }
500
501 // "no redraw" MDI child frame
03baf031 502 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
9787a4b6
VZ
503 {
504 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
505
506 retval = FALSE;
507 }
508
03baf031
VZ
509 // canvas class name
510 if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
9787a4b6
VZ
511 {
512 wxLogLastError(wxT("UnregisterClass(canvas)"));
513
514 retval = FALSE;
515 }
516
03baf031 517 if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
9787a4b6
VZ
518 {
519 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
520
521 retval = FALSE;
522 }
03baf031
VZ
523#endif // __WXMICROWIN__
524
9787a4b6
VZ
525 return retval;
526}
527
42e69d6b
VZ
528// ---------------------------------------------------------------------------
529// Convert Windows to argc, argv style
530// ---------------------------------------------------------------------------
589f0e3e 531
31f6de22 532void wxApp::ConvertToStandardCommandArgs(const char* lpCmdLine)
589f0e3e 533{
31f6de22
VZ
534 // break the command line in words
535 wxArrayString args =
536 wxCmdLineParser::ConvertStringToArgs(wxConvertMB2WX(lpCmdLine));
589f0e3e 537
31f6de22
VZ
538 // +1 here for the program name
539 argc = args.GetCount() + 1;
589f0e3e 540
31f6de22
VZ
541 // and +1 here for the terminating NULL
542 argv = new wxChar *[argc + 1];
da36f544 543
31f6de22
VZ
544 argv[0] = new wxChar[260]; // 260 is MAX_PATH value from windef.h
545 ::GetModuleFileName(wxhInstance, argv[0], 260);
589f0e3e 546
7104f65d
VZ
547 // also set the app name from argv[0]
548 wxString name;
549 wxFileName::SplitPath(argv[0], NULL, &name, NULL);
550
b35191eb
VZ
551 // but don't override the name already set by the user code, if any
552 if ( GetAppName().empty() )
553 SetAppName(name);
7104f65d
VZ
554
555 // copy all the other arguments to wxApp::argv[]
31f6de22 556 for ( int i = 1; i < argc; i++ )
a5e0e655 557 {
31f6de22 558 argv[i] = copystring(args[i - 1]);
a5e0e655 559 }
a5e0e655 560
31f6de22
VZ
561 // argv[] must be NULL-terminated
562 argv[argc] = NULL;
589f0e3e
JS
563}
564
565//// Cleans up any wxWindows internal structures left lying around
566
bb6290e3 567void wxApp::CleanUp()
2bda0e17 568{
e5c0b16a
VZ
569 //// COMMON CLEANUP
570
546db2a8 571#if wxUSE_LOG
e5c0b16a
VZ
572 // flush the logged messages if any and install a 'safer' log target: the
573 // default one (wxLogGui) can't be used after the resources are freed just
574 // below and the user suppliedo ne might be even more unsafe (using any
575 // wxWindows GUI function is unsafe starting from now)
576 wxLog::DontCreateOnDemand();
f5e5bd66 577
e5c0b16a
VZ
578 // this will flush the old messages if any
579 delete wxLog::SetActiveTarget(new wxLogStderr);
546db2a8 580#endif // wxUSE_LOG
f5e5bd66 581
e5c0b16a
VZ
582 // One last chance for pending objects to be cleaned up
583 wxTheApp->DeletePendingObjects();
f5e5bd66 584
e5c0b16a 585 wxModule::CleanUpModules();
2bda0e17 586
42e69d6b 587 wxDeleteStockObjects();
589f0e3e 588
e5c0b16a
VZ
589 // Destroy all GDI lists, etc.
590 wxDeleteStockLists();
589f0e3e 591
e5c0b16a
VZ
592 delete wxTheColourDatabase;
593 wxTheColourDatabase = NULL;
589f0e3e 594
e5c0b16a 595 wxBitmap::CleanUpHandlers();
589f0e3e 596
e5c0b16a
VZ
597 delete[] wxBuffer;
598 wxBuffer = NULL;
589f0e3e 599
e5c0b16a 600 //// WINDOWS-SPECIFIC CLEANUP
2bda0e17 601
04ef50df 602#ifndef __WXMICROWIN__
e5c0b16a 603 wxSetKeyboardHook(FALSE);
04ef50df 604#endif
2bda0e17 605
47d67540 606#if wxUSE_PENWINDOWS
e5c0b16a 607 wxCleanUpPenWin();
2bda0e17
KB
608#endif
609
e5c0b16a
VZ
610 if (wxSTD_FRAME_ICON)
611 DestroyIcon(wxSTD_FRAME_ICON);
612 if (wxSTD_MDICHILDFRAME_ICON)
613 DestroyIcon(wxSTD_MDICHILDFRAME_ICON);
614 if (wxSTD_MDIPARENTFRAME_ICON)
615 DestroyIcon(wxSTD_MDIPARENTFRAME_ICON);
616
617 if (wxDEFAULT_FRAME_ICON)
618 DestroyIcon(wxDEFAULT_FRAME_ICON);
619 if (wxDEFAULT_MDICHILDFRAME_ICON)
620 DestroyIcon(wxDEFAULT_MDICHILDFRAME_ICON);
621 if (wxDEFAULT_MDIPARENTFRAME_ICON)
622 DestroyIcon(wxDEFAULT_MDIPARENTFRAME_ICON);
623
624 if ( wxDisableButtonBrush )
42e69d6b 625 ::DeleteObject( wxDisableButtonBrush );
e5c0b16a
VZ
626
627#if wxUSE_OLE
628 ::OleUninitialize();
5de5db0e 629#endif
2bda0e17 630
9787a4b6
VZ
631#ifdef WXMAKINGDLL
632 // for an EXE the classes are unregistered when it terminates but DLL may
633 // be loaded several times (load/unload/load) into the same process in
634 // which case the registration will fail after the first time if we don't
635 // unregister the classes now
636 UnregisterWindowClasses();
637#endif // WXMAKINGDLL
638
1f112209 639#if wxUSE_CTL3D
e5c0b16a 640 Ctl3dUnregister(wxhInstance);
2bda0e17
KB
641#endif
642
1bffa913 643 delete wxWinHandleHash;
083f7497 644 wxWinHandleHash = NULL; // Set to null in case anything later tries to ref it.
d50b2a58 645
4d3a259a 646 delete wxPendingEvents;
083f7497 647 wxPendingEvents = NULL; // Set to null because wxAppBase::wxEvtHandler is destroyed later.
1e6feb95 648
8e193f38 649#if wxUSE_THREADS
4d3a259a 650 delete wxPendingEventsLocker;
083f7497 651 wxPendingEventsLocker = NULL; // Set to null because wxAppBase::wxEvtHandler is destroyed later.
1e6feb95 652 // If we don't do the following, we get an apparent memory leak
f80eabe5 653#if wxUSE_VALIDATORS
63863e09 654 ((wxEvtHandler&) wxDefaultValidator).ClearEventLocker();
1e6feb95
VZ
655#endif // wxUSE_VALIDATORS
656#endif // wxUSE_THREADS
4d3a259a 657
e5c0b16a 658 wxClassInfo::CleanUpClasses();
0c32066b 659
e5c0b16a
VZ
660 delete wxTheApp;
661 wxTheApp = NULL;
184b5d99
JS
662
663#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
e5c0b16a
VZ
664 // At this point we want to check if there are any memory
665 // blocks that aren't part of the wxDebugContext itself,
666 // as a special case. Then when dumping we need to ignore
667 // wxDebugContext, too.
d13c32e9 668 if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
e5c0b16a 669 {
5fa399c9 670 wxLogMessage(wxT("There were memory leaks."));
e5c0b16a
VZ
671 wxDebugContext::Dump();
672 wxDebugContext::PrintStatistics();
673 }
674 // wxDebugContext::SetStream(NULL, NULL);
184b5d99
JS
675#endif
676
546db2a8 677#if wxUSE_LOG
e5c0b16a
VZ
678 // do it as the very last thing because everything else can log messages
679 delete wxLog::SetActiveTarget(NULL);
546db2a8 680#endif // wxUSE_LOG
2bda0e17
KB
681}
682
7ece89c6
RD
683//----------------------------------------------------------------------
684// Entry point helpers, used by wxPython
685//----------------------------------------------------------------------
686
f6bcfd97 687int WXDLLEXPORT wxEntryStart( int WXUNUSED(argc), char** WXUNUSED(argv) )
7ece89c6
RD
688{
689 return wxApp::Initialize();
690}
691
f6bcfd97 692int WXDLLEXPORT wxEntryInitGui()
7ece89c6 693{
1e6feb95 694 return wxTheApp->OnInitGui();
7ece89c6
RD
695}
696
697void WXDLLEXPORT wxEntryCleanup()
698{
699 wxApp::CleanUp();
700}
701
702
2bda0e17
KB
703#if !defined(_WINDLL) || (defined(_WINDLL) && defined(WXMAKINGDLL))
704
e5c0b16a
VZ
705// temporarily disable this warning which would be generated in release builds
706// because of __try
3f4a0c5b 707#ifdef __VISUALC__
f8a3e080
VZ
708 #pragma warning(disable: 4715) // not all control paths return a value
709#endif // Visual C++
710
7ece89c6
RD
711//----------------------------------------------------------------------
712// Main wxWindows entry point
713//----------------------------------------------------------------------
a5e0e655
VZ
714int wxEntry(WXHINSTANCE hInstance,
715 WXHINSTANCE WXUNUSED(hPrevInstance),
716 char *lpCmdLine,
717 int nCmdShow,
718 bool enterLoop)
2bda0e17 719{
6e0d9d43
VZ
720 // do check for memory leaks on program exit
721 // (another useful flag is _CRTDBG_DELAY_FREE_MEM_DF which doesn't free
722 // deallocated memory which may be used to simulate low-memory condition)
04ef50df 723#ifndef __WXMICROWIN__
6e0d9d43 724 wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF);
04ef50df
JS
725#endif
726
6418cb93
SC
727#ifdef __MWERKS__
728#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
729 // This seems to be necessary since there are 'rogue'
730 // objects present at this point (perhaps global objects?)
731 // Setting a checkpoint will ignore them as far as the
732 // memory checking facility is concerned.
733 // Of course you may argue that memory allocated in globals should be
734 // checked, but this is a reasonable compromise.
735 wxDebugContext::SetCheckpoint();
736#endif
737#endif
3b415ba4
VZ
738
739 // take everything into a try-except block to be able to call
740 // OnFatalException() if necessary
3b415ba4 741#if wxUSE_ON_FATAL_EXCEPTION
3f4a0c5b 742 __try {
a5e0e655 743#endif
e5c0b16a 744 wxhInstance = (HINSTANCE) hInstance;
2bda0e17 745
7ece89c6 746 if (!wxEntryStart(0,0))
e5c0b16a 747 return 0;
2bda0e17 748
e5c0b16a
VZ
749 // create the application object or ensure that one already exists
750 if (!wxTheApp)
751 {
752 // The app may have declared a global application object, but we recommend
753 // the IMPLEMENT_APP macro is used instead, which sets an initializer
754 // function for delayed, dynamic app object construction.
755 wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
223d09f6 756 wxT("No initializer - use IMPLEMENT_APP macro.") );
f8a3e080 757
8cb172b4 758 wxTheApp = (wxApp*) (*wxApp::GetInitializerFunction()) ();
e5c0b16a
VZ
759 }
760
223d09f6 761 wxCHECK_MSG( wxTheApp, 0, wxT("You have to define an instance of wxApp!") );
e5c0b16a
VZ
762
763 // save the WinMain() parameters
232b0051 764 if (lpCmdLine) // MicroWindows passes NULL
3ac59f21 765 wxTheApp->ConvertToStandardCommandArgs(lpCmdLine);
e5c0b16a 766 wxTheApp->m_nCmdShow = nCmdShow;
a5e0e655 767
36edded9
JS
768 // We really don't want timestamps by default, because it means
769 // we can't simply double-click on the error message and get to that
770 // line in the source. So VC++ at least, let's have a sensible default.
771#ifdef __VISUALC__
e30285ab 772#if wxUSE_LOG
36edded9 773 wxLog::SetTimestamp(NULL);
e30285ab
VZ
774#endif // wxUSE_LOG
775#endif // __VISUALC__
36edded9 776
6afafc42 777 // init the app
1cbee0b4 778 int retValue = wxEntryInitGui() && wxTheApp->OnInit() ? 0 : -1;
6afafc42
VZ
779
780 if ( retValue == 0 )
e5c0b16a
VZ
781 {
782 if ( enterLoop )
783 {
6afafc42 784 // run the main loop
2b5f62a0 785 wxTheApp->OnRun();
e5c0b16a
VZ
786 }
787 else
6afafc42
VZ
788 {
789 // we want to initialize, but not run or exit immediately.
e5c0b16a 790 return 1;
6afafc42 791 }
e5c0b16a
VZ
792 }
793 //else: app initialization failed, so we skipped OnRun()
794
795 wxWindow *topWindow = wxTheApp->GetTopWindow();
796 if ( topWindow )
797 {
798 // Forcibly delete the window.
799 if ( topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
800 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
801 {
802 topWindow->Close(TRUE);
803 wxTheApp->DeletePendingObjects();
804 }
805 else
806 {
807 delete topWindow;
808 wxTheApp->SetTopWindow(NULL);
809 }
810 }
811
2b5f62a0 812 retValue = wxTheApp->OnExit();
e5c0b16a 813
7ece89c6 814 wxEntryCleanup();
e5c0b16a
VZ
815
816 return retValue;
817
3b415ba4 818#if wxUSE_ON_FATAL_EXCEPTION
e5c0b16a 819 }
3b415ba4
VZ
820 __except ( gs_handleExceptions ? EXCEPTION_EXECUTE_HANDLER
821 : EXCEPTION_CONTINUE_SEARCH ) {
822 if ( wxTheApp )
f6bcfd97
BP
823 {
824 // give the user a chance to do something special about this
e5c0b16a 825 wxTheApp->OnFatalException();
f6bcfd97 826 }
e5c0b16a
VZ
827
828 ::ExitProcess(3); // the same exit code as abort()
829
830 // NOTREACHED
831 }
3b415ba4 832#endif // wxUSE_ON_FATAL_EXCEPTION
2bda0e17
KB
833}
834
f8a3e080 835// restore warning state
3f4a0c5b 836#ifdef __VISUALC__
f8a3e080
VZ
837 #pragma warning(default: 4715) // not all control paths return a value
838#endif // Visual C++
839
2bda0e17
KB
840#else /* _WINDLL */
841
7ece89c6
RD
842//----------------------------------------------------------------------
843// Entry point for wxWindows + the App in a DLL
844//----------------------------------------------------------------------
589f0e3e 845
2bda0e17
KB
846int wxEntry(WXHINSTANCE hInstance)
847{
e5c0b16a 848 wxhInstance = (HINSTANCE) hInstance;
7ece89c6 849 wxEntryStart(0, 0);
2bda0e17 850
e5c0b16a
VZ
851 // The app may have declared a global application object, but we recommend
852 // the IMPLEMENT_APP macro is used instead, which sets an initializer function
853 // for delayed, dynamic app object construction.
854 if (!wxTheApp)
a5e0e655 855 {
e5c0b16a
VZ
856 wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
857 "No initializer - use IMPLEMENT_APP macro." );
2bda0e17 858
e5c0b16a
VZ
859 wxTheApp = (* wxApp::GetInitializerFunction()) ();
860 }
2bda0e17 861
e5c0b16a 862 wxCHECK_MSG( wxTheApp, 0, "You have to define an instance of wxApp!" );
2bda0e17 863
e5c0b16a
VZ
864 wxTheApp->argc = 0;
865 wxTheApp->argv = NULL;
2bda0e17 866
7ece89c6 867 wxEntryInitGui();
2bda0e17 868
e5c0b16a 869 wxTheApp->OnInit();
2bda0e17 870
e5c0b16a
VZ
871 wxWindow *topWindow = wxTheApp->GetTopWindow();
872 if ( topWindow && topWindow->GetHWND())
873 {
874 topWindow->Show(TRUE);
875 }
2bda0e17 876
e5c0b16a 877 return 1;
2bda0e17
KB
878}
879#endif // _WINDLL
880
589f0e3e
JS
881//// Static member initialization
882
bb6290e3 883wxApp::wxApp()
2bda0e17 884{
e5c0b16a
VZ
885 argc = 0;
886 argv = NULL;
e5c0b16a 887 m_printMode = wxPRINT_WINDOWS;
e5c0b16a 888 m_auto3D = TRUE;
2bda0e17
KB
889}
890
589f0e3e
JS
891wxApp::~wxApp()
892{
e5c0b16a
VZ
893 // Delete command-line args
894 int i;
895 for (i = 0; i < argc; i++)
896 {
897 delete[] argv[i];
898 }
899 delete[] argv;
589f0e3e
JS
900}
901
bb6290e3 902bool wxApp::Initialized()
2bda0e17
KB
903{
904#ifndef _WINDLL
e5c0b16a
VZ
905 if (GetTopWindow())
906 return TRUE;
907 else
908 return FALSE;
3b415ba4 909#else // Assume initialized if DLL (no way of telling)
e5c0b16a 910 return TRUE;
2bda0e17
KB
911#endif
912}
913
914/*
915 * Get and process a message, returning FALSE if WM_QUIT
bee503b0 916 * received (and also set the flag telling the app to exit the main loop)
2bda0e17
KB
917 *
918 */
bb6290e3 919bool wxApp::DoMessage()
2bda0e17 920{
bee503b0
VZ
921 BOOL rc = ::GetMessage(&s_currentMsg, (HWND) NULL, 0, 0);
922 if ( rc == 0 )
923 {
924 // got WM_QUIT
925 m_keepGoing = FALSE;
4a9968f9 926
bee503b0
VZ
927 return FALSE;
928 }
929 else if ( rc == -1 )
930 {
931 // should never happen, but let's test for it nevertheless
f6bcfd97 932 wxLogLastError(wxT("GetMessage"));
bee503b0
VZ
933 }
934 else
935 {
936#if wxUSE_THREADS
937 wxASSERT_MSG( wxThread::IsMain(),
223d09f6 938 wxT("only the main thread can process Windows messages") );
d50b2a58 939
bee503b0
VZ
940 static bool s_hadGuiLock = TRUE;
941 static wxMsgArray s_aSavedMessages;
942
943 // if a secondary thread owns is doing GUI calls, save all messages for
944 // later processing - we can't process them right now because it will
945 // lead to recursive library calls (and we're not reentrant)
946 if ( !wxGuiOwnedByMainThread() )
947 {
948 s_hadGuiLock = FALSE;
949
4a9968f9
VZ
950 // leave out WM_COMMAND messages: too dangerous, sometimes
951 // the message will be processed twice
952 if ( !wxIsWaitingForThread() ||
e5c0b16a 953 s_currentMsg.message != WM_COMMAND )
4a9968f9
VZ
954 {
955 s_aSavedMessages.Add(s_currentMsg);
956 }
bee503b0
VZ
957
958 return TRUE;
959 }
960 else
961 {
962 // have we just regained the GUI lock? if so, post all of the saved
963 // messages
964 //
965 // FIXME of course, it's not _exactly_ the same as processing the
966 // messages normally - expect some things to break...
967 if ( !s_hadGuiLock )
968 {
969 s_hadGuiLock = TRUE;
970
0a95f6d0 971 size_t count = s_aSavedMessages.GetCount();
bee503b0
VZ
972 for ( size_t n = 0; n < count; n++ )
973 {
974 MSG& msg = s_aSavedMessages[n];
975
0a95f6d0 976 DoMessage((WXMSG *)&msg);
bee503b0
VZ
977 }
978
979 s_aSavedMessages.Empty();
980 }
981 }
982#endif // wxUSE_THREADS
983
984 // Process the message
ed45e263 985 DoMessage((WXMSG *)&s_currentMsg);
bee503b0
VZ
986 }
987
988 return TRUE;
2bda0e17
KB
989}
990
ed45e263
VZ
991void wxApp::DoMessage(WXMSG *pMsg)
992{
993 if ( !ProcessMessage(pMsg) )
994 {
995 ::TranslateMessage((MSG *)pMsg);
996 ::DispatchMessage((MSG *)pMsg);
997 }
998}
999
2bda0e17
KB
1000/*
1001 * Keep trying to process messages until WM_QUIT
1002 * received.
1003 *
1004 * If there are messages to be processed, they will all be
1005 * processed and OnIdle will not be called.
1006 * When there are no more messages, OnIdle is called.
1007 * If OnIdle requests more time,
1008 * it will be repeatedly called so long as there are no pending messages.
1009 * A 'feature' of this is that once OnIdle has decided that no more processing
1010 * is required, then it won't get processing time until further messages
1011 * are processed (it'll sit in DoMessage).
1012 */
1013
bb6290e3 1014int wxApp::MainLoop()
2bda0e17 1015{
e5c0b16a 1016 m_keepGoing = TRUE;
bee503b0 1017
e5c0b16a
VZ
1018 while ( m_keepGoing )
1019 {
1020#if wxUSE_THREADS
bee503b0 1021 wxMutexGuiLeaveOrEnter();
e5c0b16a 1022#endif // wxUSE_THREADS
bee503b0 1023
b6c588e1
VZ
1024 while ( !Pending() && ProcessIdle() )
1025 ;
7214297d 1026
b6c588e1 1027 // a message came or no more idle processing to do
e5c0b16a
VZ
1028 DoMessage();
1029 }
2bda0e17 1030
e5c0b16a 1031 return s_currentMsg.wParam;
2bda0e17
KB
1032}
1033
1034// Returns TRUE if more time is needed.
bb6290e3 1035bool wxApp::ProcessIdle()
2bda0e17
KB
1036{
1037 wxIdleEvent event;
1038 event.SetEventObject(this);
1039 ProcessEvent(event);
1040
1041 return event.MoreRequested();
1042}
1043
bb6290e3 1044void wxApp::ExitMainLoop()
2bda0e17 1045{
1cbee0b4
VZ
1046 // this will set m_keepGoing to FALSE a bit later
1047 ::PostQuitMessage(0);
2bda0e17
KB
1048}
1049
bb6290e3 1050bool wxApp::Pending()
2bda0e17 1051{
b6c588e1 1052 return ::PeekMessage(&s_currentMsg, 0, 0, 0, PM_NOREMOVE) != 0;
2bda0e17
KB
1053}
1054
bb6290e3 1055void wxApp::Dispatch()
2bda0e17 1056{
bee503b0 1057 DoMessage();
2bda0e17
KB
1058}
1059
1060/*
1061 * Give all windows a chance to preprocess
1062 * the message. Some may have accelerator tables, or have
1063 * MDI complications.
1064 */
2a47d3c1 1065
d3f0a137 1066bool wxApp::ProcessMessage(WXMSG *wxmsg)
2bda0e17 1067{
d3f0a137 1068 MSG *msg = (MSG *)wxmsg;
2a3caeb5
VZ
1069 HWND hwnd = msg->hwnd;
1070 wxWindow *wndThis = wxGetWindowFromHWND((WXHWND)hwnd);
2bda0e17 1071
761989ff
VZ
1072 // this may happen if the event occured in a standard modeless dialog (the
1073 // only example of which I know of is the find/replace dialog) - then call
1074 // IsDialogMessage() to make TAB navigation in it work
1075 if ( !wndThis )
1076 {
2a3caeb5
VZ
1077 // we need to find the dialog containing this control as
1078 // IsDialogMessage() just eats all the messages (i.e. returns TRUE for
1079 // them) if we call it for the control itself
de7f0860 1080 while ( hwnd && ::GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD )
2a3caeb5
VZ
1081 {
1082 hwnd = ::GetParent(hwnd);
1083 }
1084
de7f0860 1085 return hwnd && ::IsDialogMessage(hwnd, msg) != 0;
761989ff
VZ
1086 }
1087
8614c467
VZ
1088#if wxUSE_TOOLTIPS
1089 // we must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to
1090 // popup the tooltip bubbles
761989ff 1091 if ( (msg->message == WM_MOUSEMOVE) )
834362a2 1092 {
8614c467
VZ
1093 wxToolTip *tt = wndThis->GetToolTip();
1094 if ( tt )
1095 {
1096 tt->RelayEvent(wxmsg);
1097 }
834362a2 1098 }
8614c467 1099#endif // wxUSE_TOOLTIPS
834362a2 1100
a37d422a
VZ
1101 // allow the window to prevent certain messages from being
1102 // translated/processed (this is currently used by wxTextCtrl to always
1103 // grab Ctrl-C/V/X, even if they are also accelerators in some parent)
1104 if ( !wndThis->MSWShouldPreProcessMessage(wxmsg) )
1105 {
1106 return FALSE;
1107 }
1108
2a3caeb5 1109 // try translations first: the accelerators override everything
8614c467 1110 wxWindow *wnd;
42bcb12b 1111
d3f0a137 1112 for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
2bda0e17 1113 {
2a3caeb5 1114 if ( wnd->MSWTranslateMessage(wxmsg))
d3f0a137 1115 return TRUE;
3bdc265d
VZ
1116
1117 // stop at first top level window, i.e. don't try to process the key
1118 // strokes originating in a dialog using the accelerators of the parent
1119 // frame - this doesn't make much sense
1120 if ( wnd->IsTopLevel() )
2a3caeb5
VZ
1121 break;
1122 }
1123
a37d422a
VZ
1124 // now try the other hooks (kbd navigation is handled here): we start from
1125 // wndThis->GetParent() because wndThis->MSWProcessMessage() was already
1126 // called above
1127 for ( wnd = wndThis->GetParent(); wnd; wnd = wnd->GetParent() )
2a3caeb5
VZ
1128 {
1129 if ( wnd->MSWProcessMessage(wxmsg) )
1130 return TRUE;
57a7b7c1 1131 }
d3f0a137 1132
a37d422a 1133 // no special preprocessing for this message, dispatch it normally
e5c0b16a 1134 return FALSE;
2bda0e17
KB
1135}
1136
2b5f62a0
VZ
1137// this is a temporary hack and will be replaced by using wxEventLoop in the
1138// future
1139//
1140// it is needed to allow other event loops (currently only one: the modal
1141// dialog one) to reset the OnIdle() semaphore because otherwise OnIdle()
1142// wouldn't do anything while a modal dialog shown from OnIdle() call is shown.
1143bool wxIsInOnIdleFlag = FALSE;
1144
2bda0e17
KB
1145void wxApp::OnIdle(wxIdleEvent& event)
1146{
3222fde2 1147 // Avoid recursion (via ProcessEvent default case)
2b5f62a0 1148 if ( wxIsInOnIdleFlag )
3222fde2 1149 return;
2bda0e17 1150
2b5f62a0 1151 wxIsInOnIdleFlag = TRUE;
2bda0e17 1152
52e52bea
GRG
1153 // If there are pending events, we must process them: pending events
1154 // are either events to the threads other than main or events posted
1155 // with wxPostEvent() functions
1156 // GRG: I have moved this here so that all pending events are processed
1157 // before starting to delete any objects. This behaves better (in
1158 // particular, wrt wxPostEvent) and is coherent with wxGTK's current
1159 // behaviour. Changed Feb/2000 before 2.1.14
1160 ProcessPendingEvents();
1161
3222fde2
VZ
1162 // 'Garbage' collection of windows deleted with Close().
1163 DeletePendingObjects();
2bda0e17 1164
546db2a8 1165#if wxUSE_LOG
3222fde2 1166 // flush the logged messages if any
2ed3265e 1167 wxLog::FlushActive();
546db2a8 1168#endif // wxUSE_LOG
c54f78a2 1169
aef94d68
JS
1170#if wxUSE_DC_CACHEING
1171 // automated DC cache management: clear the cached DCs and bitmap
1172 // if it's likely that the app has finished with them, that is, we
1173 // get an idle event and we're not dragging anything.
4624defa 1174 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
aef94d68
JS
1175 wxDC::ClearCache();
1176#endif // wxUSE_DC_CACHEING
1177
3222fde2
VZ
1178 // Send OnIdle events to all windows
1179 if ( SendIdleEvents() )
1180 {
1181 // SendIdleEvents() returns TRUE if at least one window requested more
1182 // idle events
1183 event.RequestMore(TRUE);
1184 }
2bda0e17 1185
2b5f62a0 1186 wxIsInOnIdleFlag = FALSE;
2bda0e17
KB
1187}
1188
1189// Send idle event to all top-level windows
bb6290e3 1190bool wxApp::SendIdleEvents()
2bda0e17
KB
1191{
1192 bool needMore = FALSE;
e146b8c8 1193
f1d534df 1194 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
3222fde2
VZ
1195 while (node)
1196 {
e146b8c8 1197 wxWindow* win = node->GetData();
3222fde2 1198 if (SendIdleEvents(win))
2bda0e17 1199 needMore = TRUE;
e146b8c8 1200 node = node->GetNext();
3222fde2
VZ
1201 }
1202
2bda0e17
KB
1203 return needMore;
1204}
1205
1206// Send idle event to window and all subwindows
1207bool wxApp::SendIdleEvents(wxWindow* win)
1208{
e5c0b16a
VZ
1209 wxIdleEvent event;
1210 event.SetEventObject(win);
1211 win->GetEventHandler()->ProcessEvent(event);
2bda0e17 1212
d162a7ee 1213 bool needMore = event.MoreRequested();
2bda0e17 1214
d162a7ee
VZ
1215 wxWindowList::Node *node = win->GetChildren().GetFirst();
1216 while ( node )
e5c0b16a 1217 {
d162a7ee 1218 wxWindow *win = node->GetData();
e5c0b16a
VZ
1219 if (SendIdleEvents(win))
1220 needMore = TRUE;
2bda0e17 1221
a0f3867a 1222 node = node->GetNext();
e5c0b16a 1223 }
d162a7ee 1224
42e69d6b 1225 return needMore;
2bda0e17
KB
1226}
1227
e2478fde
VZ
1228void wxApp::WakeUpIdle()
1229{
1230 // Send the top window a dummy message so idle handler processing will
1231 // start up again. Doing it this way ensures that the idle handler
1232 // wakes up in the right thread (see also wxWakeUpMainThread() which does
1233 // the same for the main app thread only)
1234 wxWindow *topWindow = wxTheApp->GetTopWindow();
1235 if ( topWindow )
1236 {
1237 if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
1238 {
1239 // should never happen
1240 wxLogLastError(wxT("PostMessage(WM_NULL)"));
1241 }
1242 }
1243}
1244
bb6290e3 1245void wxApp::DeletePendingObjects()
2bda0e17 1246{
a0f3867a 1247 wxNode *node = wxPendingDelete.GetFirst();
e5c0b16a
VZ
1248 while (node)
1249 {
a0f3867a 1250 wxObject *obj = node->GetData();
d50b2a58 1251
e5c0b16a 1252 delete obj;
2bda0e17 1253
e5c0b16a
VZ
1254 if (wxPendingDelete.Member(obj))
1255 delete node;
2bda0e17 1256
e5c0b16a
VZ
1257 // Deleting one object may have deleted other pending
1258 // objects, so start from beginning of list again.
a0f3867a 1259 node = wxPendingDelete.GetFirst();
e5c0b16a 1260 }
2bda0e17
KB
1261}
1262
57c208c5 1263void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
387a3b02
JS
1264{
1265 if (GetTopWindow())
1266 GetTopWindow()->Close(TRUE);
1267}
1268
1269// Default behaviour: close the application with prompts. The
1270// user can veto the close, and therefore the end session.
1271void wxApp::OnQueryEndSession(wxCloseEvent& event)
1272{
1273 if (GetTopWindow())
1274 {
1275 if (!GetTopWindow()->Close(!event.CanVeto()))
1276 event.Veto(TRUE);
1277 }
1278}
1279
ef094fa0
JS
1280typedef struct _WXADllVersionInfo
1281{
1282 DWORD cbSize;
1283 DWORD dwMajorVersion; // Major version
1284 DWORD dwMinorVersion; // Minor version
1285 DWORD dwBuildNumber; // Build number
1286 DWORD dwPlatformID; // DLLVER_PLATFORM_*
1287} WXADLLVERSIONINFO;
1288
1289typedef HRESULT (CALLBACK* WXADLLGETVERSIONPROC)(WXADLLVERSIONINFO *);
1290
6d167489
VZ
1291/* static */
1292int wxApp::GetComCtl32Version()
1293{
04ef50df
JS
1294#ifdef __WXMICROWIN__
1295 return 0;
1296#else
6d167489 1297 // cache the result
bdc72a22
VZ
1298 static int s_verComCtl32 = -1;
1299
1300 wxCRIT_SECT_DECLARE(csComCtl32);
1301 wxCRIT_SECT_LOCKER(lock, csComCtl32);
6d167489
VZ
1302
1303 if ( s_verComCtl32 == -1 )
1304 {
bdc72a22 1305 // initally assume no comctl32.dll at all
6d167489
VZ
1306 s_verComCtl32 = 0;
1307
bdc72a22
VZ
1308 // do we have it?
1309 HMODULE hModuleComCtl32 = ::GetModuleHandle(wxT("COMCTL32"));
ef094fa0
JS
1310 BOOL bFreeComCtl32 = FALSE ;
1311 if(!hModuleComCtl32)
1312 {
1313 hModuleComCtl32 = ::LoadLibrary(wxT("COMCTL32.DLL")) ;
1314 if(hModuleComCtl32)
1315 {
1316 bFreeComCtl32 = TRUE ;
1317 }
1318 }
6d167489
VZ
1319
1320 // if so, then we can check for the version
bdc72a22 1321 if ( hModuleComCtl32 )
bb6290e3 1322 {
bdc72a22 1323 // try to use DllGetVersion() if available in _headers_
ef094fa0 1324 WXADLLGETVERSIONPROC pfnDllGetVersion = (WXADLLGETVERSIONPROC)
f6bcfd97 1325 ::GetProcAddress(hModuleComCtl32, "DllGetVersion");
bdc72a22 1326 if ( pfnDllGetVersion )
6d167489 1327 {
ef094fa0 1328 WXADLLVERSIONINFO dvi;
bdc72a22
VZ
1329 dvi.cbSize = sizeof(dvi);
1330
1331 HRESULT hr = (*pfnDllGetVersion)(&dvi);
1332 if ( FAILED(hr) )
1333 {
1334 wxLogApiError(_T("DllGetVersion"), hr);
1335 }
1336 else
1337 {
1338 // this is incompatible with _WIN32_IE values, but
1339 // compatible with the other values returned by
1340 // GetComCtl32Version()
1341 s_verComCtl32 = 100*dvi.dwMajorVersion +
1342 dvi.dwMinorVersion;
1343 }
6d167489 1344 }
bdc72a22
VZ
1345 // DllGetVersion() unavailable either during compile or
1346 // run-time, try to guess the version otherwise
1347 if ( !s_verComCtl32 )
1348 {
1349 // InitCommonControlsEx is unique to 4.70 and later
1350 FARPROC theProc = ::GetProcAddress
1351 (
1352 hModuleComCtl32,
a8ee71c7 1353 "InitCommonControlsEx"
bdc72a22
VZ
1354 );
1355
1356 if ( !theProc )
1357 {
1358 // not found, must be 4.00
1359 s_verComCtl32 = 400;
1360 }
1361 else
1362 {
1363 // many symbols appeared in comctl32 4.71, could use
1364 // any of them except may be DllInstall
1365 theProc = ::GetProcAddress
1366 (
1367 hModuleComCtl32,
a8ee71c7 1368 "InitializeFlatSB"
bdc72a22
VZ
1369 );
1370 if ( !theProc )
1371 {
1372 // not found, must be 4.70
1373 s_verComCtl32 = 470;
1374 }
1375 else
1376 {
1377 // found, must be 4.71
1378 s_verComCtl32 = 471;
1379 }
1380 }
6d167489 1381 }
bb6290e3 1382 }
ef094fa0
JS
1383
1384 if(bFreeComCtl32)
1385 {
1386 ::FreeLibrary(hModuleComCtl32) ;
1387 }
bb6290e3 1388 }
6d167489
VZ
1389
1390 return s_verComCtl32;
04ef50df 1391#endif
bb6290e3
JS
1392}
1393
2bda0e17 1394// Yield to incoming messages
cb2713bf 1395
8461e4c2 1396bool wxApp::Yield(bool onlyIfNeeded)
2bda0e17 1397{
8461e4c2
VZ
1398 // MT-FIXME
1399 static bool s_inYield = FALSE;
1400
e30285ab 1401#if wxUSE_LOG
2ed3265e
VZ
1402 // disable log flushing from here because a call to wxYield() shouldn't
1403 // normally result in message boxes popping up &c
1404 wxLog::Suspend();
e30285ab 1405#endif // wxUSE_LOG
2ed3265e 1406
8461e4c2
VZ
1407 if ( s_inYield )
1408 {
1409 if ( !onlyIfNeeded )
1410 {
1411 wxFAIL_MSG( wxT("wxYield called recursively" ) );
1412 }
33ac7e6f 1413
8461e4c2
VZ
1414 return FALSE;
1415 }
1416
1417 s_inYield = TRUE;
cb2713bf 1418
8e193f38
VZ
1419 // we don't want to process WM_QUIT from here - it should be processed in
1420 // the main event loop in order to stop it
e5c0b16a 1421 MSG msg;
8e193f38
VZ
1422 while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
1423 msg.message != WM_QUIT )
e5c0b16a 1424 {
5b615ed8
VZ
1425#if wxUSE_THREADS
1426 wxMutexGuiLeaveOrEnter();
1427#endif // wxUSE_THREADS
1428
e5c0b16a
VZ
1429 if ( !wxTheApp->DoMessage() )
1430 break;
1431 }
8e193f38 1432
8461e4c2
VZ
1433 // if there are pending events, we must process them.
1434 ProcessPendingEvents();
e5c0b16a 1435
e30285ab 1436#if wxUSE_LOG
2ed3265e
VZ
1437 // let the logs be flashed again
1438 wxLog::Resume();
e30285ab 1439#endif // wxUSE_LOG
2ed3265e 1440
8461e4c2 1441 s_inYield = FALSE;
cb2713bf 1442
e5c0b16a 1443 return TRUE;
2bda0e17 1444}
094637f6 1445
3b415ba4
VZ
1446bool wxHandleFatalExceptions(bool doit)
1447{
1448#if wxUSE_ON_FATAL_EXCEPTION
1449 // assume this can only be called from the main thread
1450 gs_handleExceptions = doit;
1451
1452 return TRUE;
1453#else
8461e4c2
VZ
1454 wxFAIL_MSG(_T("set wxUSE_ON_FATAL_EXCEPTION to 1 to use this function"));
1455
1456 (void)doit;
3b415ba4
VZ
1457 return FALSE;
1458#endif
1459}
1460
9779893b
RD
1461//-----------------------------------------------------------------------------
1462
2bda0e17
KB
1463// For some reason, with MSVC++ 1.5, WinMain isn't linked in properly
1464// if in a separate file. So include it here to ensure it's linked.
b39dbf34 1465#if (defined(__VISUALC__) && !defined(__WIN32__)) || (defined(__GNUWIN32__) && !defined(__WINE__) && !defined(WXMAKINGDLL))
e5c0b16a 1466#include "main.cpp"
2bda0e17 1467#endif