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