]> git.saurik.com Git - wxWidgets.git/blame - src/msw/app.cpp
fixed signature of wxTimerProc to be conformant to what Windows expects it to be
[wxWidgets.git] / src / msw / app.cpp
CommitLineData
2bda0e17
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: app.cpp
3// Purpose: wxApp
4// Author: Julian Smart
5// Modified by:
6// Created: 04/01/98
7// RCS-ID: $Id$
6c9a19aa 8// Copyright: (c) Julian Smart
65571936 9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
e5c0b16a
VZ
12// ===========================================================================
13// declarations
14// ===========================================================================
15
16// ---------------------------------------------------------------------------
17// headers
18// ---------------------------------------------------------------------------
19
14f355c2 20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
e5c0b16a 21 #pragma implementation "app.h"
2bda0e17
KB
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
2bda0e17
KB
25#include "wx/wxprec.h"
26
27#if defined(__BORLANDC__)
e5c0b16a 28 #pragma hdrstop
2bda0e17
KB
29#endif
30
31#ifndef WX_PRECOMP
e5c0b16a
VZ
32 #include "wx/frame.h"
33 #include "wx/app.h"
34 #include "wx/utils.h"
35 #include "wx/gdicmn.h"
36 #include "wx/pen.h"
37 #include "wx/brush.h"
38 #include "wx/cursor.h"
39 #include "wx/icon.h"
40 #include "wx/palette.h"
41 #include "wx/dc.h"
42 #include "wx/dialog.h"
43 #include "wx/msgdlg.h"
44 #include "wx/intl.h"
45 #include "wx/dynarray.h"
72cdf4c9
VZ
46 #include "wx/wxchar.h"
47 #include "wx/icon.h"
31f6de22 48 #include "wx/log.h"
2bda0e17
KB
49#endif
50
e2478fde 51#include "wx/apptrait.h"
7104f65d 52#include "wx/filename.h"
2bda0e17 53#include "wx/module.h"
9fc6c21c 54#include "wx/dynlib.h"
4bf78aae 55
4286a5b5
RR
56#include "wx/msw/private.h"
57
8614c467
VZ
58#if wxUSE_TOOLTIPS
59 #include "wx/tooltip.h"
60#endif // wxUSE_TOOLTIPS
61
c42404a5
VZ
62// OLE is used for drag-and-drop, clipboard, OLE Automation..., but some
63// compilers don't support it (missing headers, libs, ...)
2bdf7154 64#if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__) || defined(__SALFORDC__)
e5c0b16a
VZ
65 #undef wxUSE_OLE
66
67 #define wxUSE_OLE 0
68#endif // broken compilers
69
70#if wxUSE_OLE
6e0d9d43 71 #include <ole2.h>
d05237ea 72#endif
ce3ed50d 73
2bda0e17 74#include <string.h>
a5e0e655 75#include <ctype.h>
2bda0e17 76
0d236fd0 77#include "wx/msw/wrapcctl.h"
bdc72a22 78
6046e57a
VZ
79// For MB_TASKMODAL
80#ifdef __WXWINCE__
81#include "wx/msw/wince/missing.h"
82#endif
83
9fc6c21c 84#if (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \
50165591 85 !defined(__CYGWIN__) && !defined(__DIGITALMARS__) && !defined(__WXWINCE__) && \
1bf77ee5 86 (!defined(_MSC_VER) || (_MSC_VER > 1100))
036bc7d9
VZ
87 #include <shlwapi.h>
88#endif
89
e5c0b16a
VZ
90// ---------------------------------------------------------------------------
91// global variables
92// ---------------------------------------------------------------------------
93
cde9f08e 94extern wxList WXDLLEXPORT wxPendingDelete;
4676948b
JS
95
96#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
2bda0e17 97extern void wxSetKeyboardHook(bool doIt);
04ef50df 98#endif
2bda0e17 99
193fe989
VZ
100// NB: all "NoRedraw" classes must have the same names as the "normal" classes
101// with NR suffix - wxWindow::MSWCreate() supposes this
46fa338b
RR
102#ifdef __WXWINCE__
103 wxChar *wxCanvasClassName;
104 wxChar *wxCanvasClassNameNR;
105#else
03baf031
VZ
106const wxChar *wxCanvasClassName = wxT("wxWindowClass");
107const wxChar *wxCanvasClassNameNR = wxT("wxWindowClassNR");
46fa338b 108#endif
2ffa221c
VZ
109const wxChar *wxMDIFrameClassName = wxT("wxMDIFrameClass");
110const wxChar *wxMDIFrameClassNameNoRedraw = wxT("wxMDIFrameClassNR");
111const wxChar *wxMDIChildFrameClassName = wxT("wxMDIChildFrameClass");
112const wxChar *wxMDIChildFrameClassNameNoRedraw = wxT("wxMDIChildFrameClassNR");
2bda0e17 113
57c208c5 114HBRUSH wxDisableButtonBrush = (HBRUSH) 0;
2bda0e17 115
94826170
VZ
116// ----------------------------------------------------------------------------
117// private functions
118// ----------------------------------------------------------------------------
2bda0e17 119
94826170 120LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
3b415ba4 121
e5c0b16a 122// ===========================================================================
e2478fde
VZ
123// wxGUIAppTraits implementation
124// ===========================================================================
125
126// private class which we use to pass parameters from BeforeChildWaitLoop() to
127// AfterChildWaitLoop()
128struct ChildWaitLoopData
129{
130 ChildWaitLoopData(wxWindowDisabler *wd_, wxWindow *winActive_)
131 {
132 wd = wd_;
133 winActive = winActive_;
134 }
135
136 wxWindowDisabler *wd;
137 wxWindow *winActive;
138};
139
140void *wxGUIAppTraits::BeforeChildWaitLoop()
141{
142 /*
143 We use a dirty hack here to disable all application windows (which we
144 must do because otherwise the calls to wxYield() could lead to some very
145 unexpected reentrancies in the users code) but to avoid losing
146 focus/activation entirely when the child process terminates which would
147 happen if we simply disabled everything using wxWindowDisabler. Indeed,
148 remember that Windows will never activate a disabled window and when the
149 last childs window is closed and Windows looks for a window to activate
150 all our windows are still disabled. There is no way to enable them in
151 time because we don't know when the childs windows are going to be
152 closed, so the solution we use here is to keep one special tiny frame
153 enabled all the time. Then when the child terminates it will get
154 activated and when we close it below -- after reenabling all the other
155 windows! -- the previously active window becomes activated again and
156 everything is ok.
157 */
158 wxBeginBusyCursor();
159
160 // first disable all existing windows
161 wxWindowDisabler *wd = new wxWindowDisabler;
162
163 // then create an "invisible" frame: it has minimal size, is positioned
164 // (hopefully) outside the screen and doesn't appear on the taskbar
165 wxWindow *winActive = new wxFrame
166 (
167 wxTheApp->GetTopWindow(),
fda7962d
JS
168 wxID_ANY,
169 wxEmptyString,
e2478fde
VZ
170 wxPoint(32600, 32600),
171 wxSize(1, 1),
172 wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR
173 );
174 winActive->Show();
175
176 return new ChildWaitLoopData(wd, winActive);
177}
178
179void wxGUIAppTraits::AlwaysYield()
180{
181 wxYield();
182}
183
184void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
185{
186 wxEndBusyCursor();
187
0588f8d7 188 ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig;
e2478fde
VZ
189
190 delete data->wd;
191
192 // finally delete the dummy frame and, as wd has been already destroyed and
193 // the other windows reenabled, the activation is going to return to the
194 // window which had had it before
195 data->winActive->Destroy();
51036b44
VZ
196
197 // also delete the temporary data object itself
198 delete data;
e2478fde
VZ
199}
200
201bool wxGUIAppTraits::DoMessageFromThreadWait()
202{
1bf77ee5
VZ
203 // we should return false only if the app should exit, i.e. only if
204 // Dispatch() determines that the main event loop should terminate
205 return !wxTheApp || wxTheApp->Dispatch();
e2478fde
VZ
206}
207
324899f6 208wxToolkitInfo& wxGUIAppTraits::GetToolkitInfo()
a8eaaeb2 209{
1bf77ee5 210 static wxToolkitInfo info;
324899f6
VS
211 wxToolkitInfo& baseInfo = wxAppTraits::GetToolkitInfo();
212 info.versionMajor = baseInfo.versionMajor;
213 info.versionMinor = baseInfo.versionMinor;
214 info.os = baseInfo.os;
a8eaaeb2
VS
215 info.shortName = _T("msw");
216 info.name = _T("wxMSW");
217#ifdef __WXUNIVERSAL__
218 info.shortName << _T("univ");
219 info.name << _T("/wxUniversal");
220#endif
324899f6 221 return info;
a8eaaeb2
VS
222}
223
e2478fde
VZ
224// ===========================================================================
225// wxApp implementation
e5c0b16a 226// ===========================================================================
589f0e3e 227
94826170
VZ
228int wxApp::m_nCmdShow = SW_SHOWNORMAL;
229
e5c0b16a 230// ---------------------------------------------------------------------------
e2478fde 231// wxWin macros
e5c0b16a
VZ
232// ---------------------------------------------------------------------------
233
f6bcfd97 234IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
e5c0b16a 235
f6bcfd97
BP
236BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
237 EVT_IDLE(wxApp::OnIdle)
238 EVT_END_SESSION(wxApp::OnEndSession)
239 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
240END_EVENT_TABLE()
e5c0b16a 241
94826170
VZ
242// class to ensure that wxAppBase::CleanUp() is called if our Initialize()
243// fails
244class wxCallBaseCleanup
245{
246public:
247 wxCallBaseCleanup(wxApp *app) : m_app(app) { }
248 ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
249
250 void Dismiss() { m_app = NULL; }
251
252private:
253 wxApp *m_app;
254};
255
e5c0b16a 256//// Initialize
05e2b077 257bool wxApp::Initialize(int& argc, wxChar **argv)
2bda0e17 258{
94826170
VZ
259 if ( !wxAppBase::Initialize(argc, argv) )
260 return false;
261
262 // ensure that base cleanup is done if we return too early
263 wxCallBaseCleanup callBaseCleanup(this);
264
46fa338b
RR
265#ifdef __WXWINCE__
266 wxString tmp = GetAppName();
267 tmp += wxT("ClassName");
268 wxCanvasClassName = wxStrdup( tmp.c_str() );
269 tmp += wxT("NR");
270 wxCanvasClassNameNR = wxStrdup( tmp.c_str() );
271 HWND hWnd = FindWindow( wxCanvasClassNameNR, NULL );
272 if (hWnd)
273 {
274 SetForegroundWindow( (HWND)(((DWORD)hWnd)|0x01) );
275 return false;
276 }
277#endif
278
f6bcfd97 279 // the first thing to do is to check if we're trying to run an Unicode
7c9955d1 280 // program under Win9x w/o MSLU emulation layer - if so, abort right now
dfc40ef3 281 // as it has no chance to work
eb5e4d9a 282#if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
f07dc2e2 283 if ( wxGetOsVersion() != wxWINDOWS_NT && wxGetOsVersion() != wxWINDOWS_CE )
f6bcfd97
BP
284 {
285 // note that we can use MessageBoxW() as it's implemented even under
286 // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs
287 // used by wxLocale are not
288 ::MessageBox
289 (
290 NULL,
f07dc2e2 291 _T("This program uses Unicode and requires Windows NT/2000/XP/CE.\nProgram aborted."),
77ffb593 292 _T("wxWidgets Fatal Error"),
f6bcfd97
BP
293 MB_ICONERROR | MB_OK
294 );
295
77c46f00 296 return false;
f6bcfd97 297 }
eb5e4d9a 298#endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
f6bcfd97 299
04ef50df 300#if defined(__WIN95__) && !defined(__WXMICROWIN__)
a5e0e655 301 InitCommonControls();
e5c0b16a 302#endif // __WIN95__
2bda0e17 303
8cb172b4 304#if wxUSE_OLE || wxUSE_DRAG_AND_DROP
c49245f8 305
abad5367 306#if wxUSE_OLE
a5e0e655 307 // we need to initialize OLE library
f07dc2e2
JS
308#ifdef __WXWINCE__
309 if ( FAILED(::CoInitializeEx(NULL, COINIT_MULTITHREADED)) )
310 wxLogError(_("Cannot initialize OLE"));
311#else
a5e0e655 312 if ( FAILED(::OleInitialize(NULL)) )
e5c0b16a 313 wxLogError(_("Cannot initialize OLE"));
abad5367 314#endif
f07dc2e2 315#endif
1e6feb95 316
c49245f8 317#endif // wxUSE_OLE
2bda0e17 318
1f112209 319#if wxUSE_CTL3D
a5e0e655 320 if (!Ctl3dRegister(wxhInstance))
223d09f6 321 wxLogError(wxT("Cannot register CTL3D"));
2bda0e17 322
a5e0e655 323 Ctl3dAutoSubclass(wxhInstance);
1e6feb95 324#endif // wxUSE_CTL3D
2bda0e17 325
aa0b7e1e 326 RegisterWindowClasses();
2bda0e17 327
ec91fc14 328#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
aa0b7e1e 329 // Create the brush for disabling bitmap buttons
42e69d6b 330 LOGBRUSH lb;
aa0b7e1e 331 lb.lbStyle = BS_PATTERN;
097f29c2 332 lb.lbColor = 0;
223d09f6 333 lb.lbHatch = (int)LoadBitmap( wxhInstance, wxT("wxDISABLE_BUTTON_BITMAP") );
3a5ffa81
VZ
334 if ( lb.lbHatch )
335 {
ec91fc14 336 wxDisableButtonBrush = ::CreateBrushIndirect( &lb );
3a5ffa81
VZ
337 ::DeleteObject( (HGDIOBJ)lb.lbHatch );
338 }
77ffb593 339 //else: wxWidgets resources are probably not linked in
ec91fc14 340#endif // !__WXMICROWIN__ && !__WXWINCE__
2bda0e17 341
aa0b7e1e 342#if wxUSE_PENWINDOWS
a5e0e655 343 wxRegisterPenWin();
aa0b7e1e 344#endif
2bda0e17 345
1bffa913 346 wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
2bda0e17 347
4676948b 348#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
77c46f00 349 wxSetKeyboardHook(true);
04ef50df 350#endif
2bda0e17 351
94826170
VZ
352 callBaseCleanup.Dismiss();
353
354 return true;
2bda0e17
KB
355}
356
42e69d6b
VZ
357// ---------------------------------------------------------------------------
358// RegisterWindowClasses
359// ---------------------------------------------------------------------------
589f0e3e 360
b782f2e0
VZ
361// TODO we should only register classes really used by the app. For this it
362// would be enough to just delay the class registration until an attempt
363// to create a window of this class is made.
bb6290e3 364bool wxApp::RegisterWindowClasses()
2bda0e17 365{
42e69d6b 366 WNDCLASS wndclass;
03baf031 367 wxZeroMemory(wndclass);
e5c0b16a 368
193fe989
VZ
369 // for each class we register one with CS_(V|H)REDRAW style and one
370 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
371 static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
372 static const long styleNoRedraw = CS_DBLCLKS;
373
42e69d6b 374 // the fields which are common to all classes
e5c0b16a 375 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
e5c0b16a 376 wndclass.hInstance = wxhInstance;
42e69d6b 377 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
42e69d6b
VZ
378
379 // Register the frame window class.
380 wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
03baf031 381 wndclass.lpszClassName = wxCanvasClassName;
b782f2e0 382 wndclass.style = styleNormal;
e5c0b16a 383
42e69d6b 384 if ( !RegisterClass(&wndclass) )
e5c0b16a 385 {
f6bcfd97 386 wxLogLastError(wxT("RegisterClass(frame)"));
e5c0b16a
VZ
387 }
388
193fe989 389 // "no redraw" frame
03baf031 390 wndclass.lpszClassName = wxCanvasClassNameNR;
193fe989
VZ
391 wndclass.style = styleNoRedraw;
392
393 if ( !RegisterClass(&wndclass) )
394 {
f6bcfd97 395 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
193fe989
VZ
396 }
397
e5c0b16a 398 // Register the MDI frame window class.
42e69d6b 399 wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
b782f2e0
VZ
400 wndclass.lpszClassName = wxMDIFrameClassName;
401 wndclass.style = styleNormal;
42e69d6b
VZ
402
403 if ( !RegisterClass(&wndclass) )
e5c0b16a 404 {
f6bcfd97 405 wxLogLastError(wxT("RegisterClass(MDI parent)"));
e5c0b16a
VZ
406 }
407
193fe989 408 // "no redraw" MDI frame
b782f2e0 409 wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
193fe989
VZ
410 wndclass.style = styleNoRedraw;
411
412 if ( !RegisterClass(&wndclass) )
413 {
f6bcfd97 414 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
193fe989
VZ
415 }
416
e5c0b16a 417 // Register the MDI child frame window class.
42e69d6b
VZ
418 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
419 wndclass.lpszClassName = wxMDIChildFrameClassName;
b782f2e0 420 wndclass.style = styleNormal;
42e69d6b
VZ
421
422 if ( !RegisterClass(&wndclass) )
e5c0b16a 423 {
f6bcfd97 424 wxLogLastError(wxT("RegisterClass(MDI child)"));
e5c0b16a
VZ
425 }
426
193fe989
VZ
427 // "no redraw" MDI child frame
428 wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
429 wndclass.style = styleNoRedraw;
430
431 if ( !RegisterClass(&wndclass) )
432 {
f6bcfd97 433 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
193fe989
VZ
434 }
435
77c46f00 436 return true;
2bda0e17
KB
437}
438
9787a4b6
VZ
439// ---------------------------------------------------------------------------
440// UnregisterWindowClasses
441// ---------------------------------------------------------------------------
442
443bool wxApp::UnregisterWindowClasses()
444{
77c46f00 445 bool retval = true;
9787a4b6 446
c67d6888 447#ifndef __WXMICROWIN__
9787a4b6 448 // MDI frame window class.
03baf031 449 if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
9787a4b6
VZ
450 {
451 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
452
77c46f00 453 retval = false;
9787a4b6
VZ
454 }
455
456 // "no redraw" MDI frame
03baf031 457 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
9787a4b6
VZ
458 {
459 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
460
77c46f00 461 retval = false;
9787a4b6
VZ
462 }
463
464 // MDI child frame window class.
03baf031 465 if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
9787a4b6
VZ
466 {
467 wxLogLastError(wxT("UnregisterClass(MDI child)"));
468
77c46f00 469 retval = false;
9787a4b6
VZ
470 }
471
472 // "no redraw" MDI child frame
03baf031 473 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
9787a4b6
VZ
474 {
475 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
476
77c46f00 477 retval = false;
9787a4b6
VZ
478 }
479
03baf031
VZ
480 // canvas class name
481 if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
9787a4b6
VZ
482 {
483 wxLogLastError(wxT("UnregisterClass(canvas)"));
484
77c46f00 485 retval = false;
9787a4b6
VZ
486 }
487
03baf031 488 if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
9787a4b6
VZ
489 {
490 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
491
77c46f00 492 retval = false;
9787a4b6 493 }
03baf031
VZ
494#endif // __WXMICROWIN__
495
9787a4b6
VZ
496 return retval;
497}
498
bb6290e3 499void wxApp::CleanUp()
2bda0e17 500{
7a9dfa3c
VZ
501 // all objects pending for deletion must be deleted first, otherwise we
502 // would crash when they use wxWinHandleHash (and UnregisterWindowClasses()
503 // call wouldn't succeed as long as any windows still exist), so call the
504 // base class method first and only then do our clean up
505 wxAppBase::CleanUp();
506
4676948b 507#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
77c46f00 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;
46fa338b
RR
538
539#ifdef __WXWINCE__
540 free( wxCanvasClassName );
541 free( wxCanvasClassNameNR );
542#endif
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
6046e57a
VZ
569// ----------------------------------------------------------------------------
570// wxApp idle handling
571// ----------------------------------------------------------------------------
572
2bda0e17
KB
573void wxApp::OnIdle(wxIdleEvent& event)
574{
955a9197 575 wxAppBase::OnIdle(event);
c54f78a2 576
aef94d68
JS
577#if wxUSE_DC_CACHEING
578 // automated DC cache management: clear the cached DCs and bitmap
579 // if it's likely that the app has finished with them, that is, we
580 // get an idle event and we're not dragging anything.
4624defa 581 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
aef94d68
JS
582 wxDC::ClearCache();
583#endif // wxUSE_DC_CACHEING
2bda0e17
KB
584}
585
e2478fde
VZ
586void wxApp::WakeUpIdle()
587{
588 // Send the top window a dummy message so idle handler processing will
589 // start up again. Doing it this way ensures that the idle handler
590 // wakes up in the right thread (see also wxWakeUpMainThread() which does
591 // the same for the main app thread only)
592 wxWindow *topWindow = wxTheApp->GetTopWindow();
593 if ( topWindow )
594 {
595 if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
596 {
597 // should never happen
598 wxLogLastError(wxT("PostMessage(WM_NULL)"));
599 }
600 }
601}
602
6046e57a
VZ
603// ----------------------------------------------------------------------------
604// other wxApp event hanlders
605// ----------------------------------------------------------------------------
606
57c208c5 607void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
387a3b02
JS
608{
609 if (GetTopWindow())
77c46f00 610 GetTopWindow()->Close(true);
387a3b02
JS
611}
612
613// Default behaviour: close the application with prompts. The
614// user can veto the close, and therefore the end session.
615void wxApp::OnQueryEndSession(wxCloseEvent& event)
616{
617 if (GetTopWindow())
618 {
619 if (!GetTopWindow()->Close(!event.CanVeto()))
77c46f00 620 event.Veto(true);
387a3b02
JS
621 }
622}
623
6046e57a
VZ
624// ----------------------------------------------------------------------------
625// miscellaneous
626// ----------------------------------------------------------------------------
627
6d167489
VZ
628/* static */
629int wxApp::GetComCtl32Version()
630{
fd7b70bd 631#if defined(__WXMICROWIN__) || defined(__WXWINCE__)
04ef50df
JS
632 return 0;
633#else
6d167489 634 // cache the result
9fc6c21c
VZ
635 //
636 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
637 // but as its value should be the same both times it doesn't matter
bdc72a22
VZ
638 static int s_verComCtl32 = -1;
639
6d167489
VZ
640 if ( s_verComCtl32 == -1 )
641 {
bdc72a22 642 // initally assume no comctl32.dll at all
6d167489
VZ
643 s_verComCtl32 = 0;
644
9fc6c21c
VZ
645 // we're prepared to handle the errors
646 wxLogNull noLog;
647
bdc72a22 648 // do we have it?
9fc6c21c 649 wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
6d167489
VZ
650
651 // if so, then we can check for the version
9fc6c21c 652 if ( dllComCtl32.IsLoaded() )
bb6290e3 653 {
548bf4b7 654#ifdef DLLVER_PLATFORM_WINDOWS
bdc72a22 655 // try to use DllGetVersion() if available in _headers_
9fc6c21c
VZ
656 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dllComCtl32 );
657 if ( pfnDllGetVersion )
658 {
659 DLLVERSIONINFO dvi;
660 dvi.cbSize = sizeof(dvi);
661
662 HRESULT hr = (*pfnDllGetVersion)(&dvi);
663 if ( FAILED(hr) )
6d167489 664 {
9fc6c21c
VZ
665 wxLogApiError(_T("DllGetVersion"), hr);
666 }
667 else
668 {
669 // this is incompatible with _WIN32_IE values, but
670 // compatible with the other values returned by
671 // GetComCtl32Version()
672 s_verComCtl32 = 100*dvi.dwMajorVersion +
673 dvi.dwMinorVersion;
674 }
675 }
548bf4b7 676#endif
bdc72a22 677
9fc6c21c
VZ
678 // if DllGetVersion() is unavailable either during compile or
679 // run-time, try to guess the version otherwise
680 if ( !s_verComCtl32 )
681 {
682 // InitCommonControlsEx is unique to 4.70 and later
683 void *pfn = dllComCtl32.GetSymbol(_T("InitCommonControlsEx"));
684 if ( !pfn )
685 {
686 // not found, must be 4.00
687 s_verComCtl32 = 400;
6d167489 688 }
9fc6c21c 689 else // 4.70+
bdc72a22 690 {
9fc6c21c
VZ
691 // many symbols appeared in comctl32 4.71, could use any of
692 // them except may be DllInstall()
693 pfn = dllComCtl32.GetSymbol(_T("InitializeFlatSB"));
694 if ( !pfn )
bdc72a22 695 {
9fc6c21c
VZ
696 // not found, must be 4.70
697 s_verComCtl32 = 470;
bdc72a22
VZ
698 }
699 else
700 {
9fc6c21c
VZ
701 // found, must be 4.71 or later
702 s_verComCtl32 = 471;
bdc72a22 703 }
6d167489 704 }
9fc6c21c 705 }
ef094fa0 706 }
bb6290e3 707 }
6d167489
VZ
708
709 return s_verComCtl32;
9fc6c21c 710#endif // Microwin/!Microwin
bb6290e3
JS
711}
712
2bda0e17 713// Yield to incoming messages
cb2713bf 714
8461e4c2 715bool wxApp::Yield(bool onlyIfNeeded)
2bda0e17 716{
8461e4c2 717 // MT-FIXME
77c46f00 718 static bool s_inYield = false;
8461e4c2 719
e30285ab 720#if wxUSE_LOG
2ed3265e
VZ
721 // disable log flushing from here because a call to wxYield() shouldn't
722 // normally result in message boxes popping up &c
723 wxLog::Suspend();
e30285ab 724#endif // wxUSE_LOG
2ed3265e 725
8461e4c2
VZ
726 if ( s_inYield )
727 {
728 if ( !onlyIfNeeded )
729 {
730 wxFAIL_MSG( wxT("wxYield called recursively" ) );
731 }
33ac7e6f 732
77c46f00 733 return false;
8461e4c2
VZ
734 }
735
77c46f00 736 s_inYield = true;
cb2713bf 737
8e193f38
VZ
738 // we don't want to process WM_QUIT from here - it should be processed in
739 // the main event loop in order to stop it
e5c0b16a 740 MSG msg;
8e193f38
VZ
741 while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
742 msg.message != WM_QUIT )
e5c0b16a 743 {
5b615ed8
VZ
744#if wxUSE_THREADS
745 wxMutexGuiLeaveOrEnter();
746#endif // wxUSE_THREADS
747
1bf77ee5 748 if ( !wxTheApp->Dispatch() )
e5c0b16a
VZ
749 break;
750 }
8e193f38 751
8461e4c2
VZ
752 // if there are pending events, we must process them.
753 ProcessPendingEvents();
e5c0b16a 754
e30285ab 755#if wxUSE_LOG
2ed3265e
VZ
756 // let the logs be flashed again
757 wxLog::Resume();
e30285ab 758#endif // wxUSE_LOG
2ed3265e 759
77c46f00 760 s_inYield = false;
cb2713bf 761
77c46f00 762 return true;
2bda0e17 763}
094637f6 764
6046e57a
VZ
765#if wxUSE_EXCEPTIONS
766
767// ----------------------------------------------------------------------------
768// exception handling
769// ----------------------------------------------------------------------------
770
771bool wxApp::OnExceptionInMainLoop()
772{
773 // ask the user about what to do: use the Win32 API function here as it
77ffb593 774 // could be dangerous to use any wxWidgets code in this state
6046e57a
VZ
775 switch (
776 ::MessageBox
777 (
778 NULL,
779 _T("An unhandled exception occurred. Press \"Abort\" to \
780terminate the program,\r\n\
781\"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
782 _T("Unhandled exception"),
783 MB_ABORTRETRYIGNORE |
784 MB_ICONERROR|
785 MB_TASKMODAL
786 )
787 )
788 {
789 case IDABORT:
790 throw;
791
792 default:
793 wxFAIL_MSG( _T("unexpected MessageBox() return code") );
794 // fall through
795
796 case IDRETRY:
797 return false;
798
799 case IDIGNORE:
800 return true;
801 }
802}
803
804#endif // wxUSE_EXCEPTIONS
51036b44
VZ
805
806// ----------------------------------------------------------------------------
807// deprecated event loop functions
808// ----------------------------------------------------------------------------
809
810#if WXWIN_COMPATIBILITY_2_4
811
812#include "wx/evtloop.h"
813
814void wxApp::DoMessage(WXMSG *pMsg)
815{
816 wxEventLoop *evtLoop = wxEventLoop::GetActive();
817 if ( evtLoop )
818 evtLoop->ProcessMessage(pMsg);
819}
820
821bool wxApp::DoMessage()
822{
823 wxEventLoop *evtLoop = wxEventLoop::GetActive();
824 return evtLoop ? evtLoop->Dispatch() : false;
825}
826
827bool wxApp::ProcessMessage(WXMSG* pMsg)
828{
829 wxEventLoop *evtLoop = wxEventLoop::GetActive();
830 return evtLoop && evtLoop->PreProcessMessage(pMsg);
831}
832
833#endif // WXWIN_COMPATIBILITY_2_4
834