~ubuntu-dev/wxwidgets2.6/upstream-debian

« back to all changes in this revision

Viewing changes to src/msw/app.cpp

  • Committer: Daniel T Chen
  • Date: 2006-06-26 10:15:11 UTC
  • Revision ID: crimsun@ubuntu.com-20060626101511-a4436cec4c6d9b35
ImportĀ DebianĀ 2.6.3.2.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/////////////////////////////////////////////////////////////////////////////
 
2
// Name:        app.cpp
 
3
// Purpose:     wxApp
 
4
// Author:      Julian Smart
 
5
// Modified by:
 
6
// Created:     04/01/98
 
7
// RCS-ID:      $Id: app.cpp,v 1.238.2.2 2006/02/11 14:57:10 JS Exp $
 
8
// Copyright:   (c) Julian Smart
 
9
// Licence:     wxWindows licence
 
10
/////////////////////////////////////////////////////////////////////////////
 
11
 
 
12
// ===========================================================================
 
13
// declarations
 
14
// ===========================================================================
 
15
 
 
16
// ---------------------------------------------------------------------------
 
17
// headers
 
18
// ---------------------------------------------------------------------------
 
19
 
 
20
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
 
21
    #pragma implementation "app.h"
 
22
#endif
 
23
 
 
24
// For compilers that support precompilation, includes "wx.h".
 
25
#include "wx/wxprec.h"
 
26
 
 
27
#if defined(__BORLANDC__)
 
28
    #pragma hdrstop
 
29
#endif
 
30
 
 
31
#ifndef WX_PRECOMP
 
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"
 
46
    #include "wx/wxchar.h"
 
47
    #include "wx/icon.h"
 
48
    #include "wx/log.h"
 
49
#endif
 
50
 
 
51
#include "wx/apptrait.h"
 
52
#include "wx/filename.h"
 
53
#include "wx/module.h"
 
54
#include "wx/dynlib.h"
 
55
 
 
56
#include "wx/msw/private.h"
 
57
#include "wx/msw/ole/oleutils.h"
 
58
 
 
59
#if wxUSE_TOOLTIPS
 
60
    #include "wx/tooltip.h"
 
61
#endif // wxUSE_TOOLTIPS
 
62
 
 
63
// OLE is used for drag-and-drop, clipboard, OLE Automation..., but some
 
64
// compilers don't support it (missing headers, libs, ...)
 
65
#if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__) || defined(__SALFORDC__)
 
66
    #undef wxUSE_OLE
 
67
 
 
68
    #define  wxUSE_OLE 0
 
69
#endif // broken compilers
 
70
 
 
71
#if defined(__POCKETPC__) || defined(__SMARTPHONE__)
 
72
    #include <ole2.h>
 
73
    #include <aygshell.h>
 
74
#endif
 
75
 
 
76
#if wxUSE_OLE
 
77
    #include <ole2.h>
 
78
#endif
 
79
 
 
80
#include <string.h>
 
81
#include <ctype.h>
 
82
 
 
83
#include "wx/msw/wrapcctl.h"
 
84
 
 
85
// For MB_TASKMODAL
 
86
#ifdef __WXWINCE__
 
87
#include "wx/msw/wince/missing.h"
 
88
#endif
 
89
 
 
90
// instead of including <shlwapi.h> which is not part of the core SDK and not
 
91
// shipped at all with other compilers, we always define the parts of it we
 
92
// need here ourselves
 
93
//
 
94
// NB: DLLVER_PLATFORM_WINDOWS will be defined if shlwapi.h had been somehow
 
95
//     included already
 
96
#ifndef DLLVER_PLATFORM_WINDOWS
 
97
    // hopefully we don't need to change packing as DWORDs should be already
 
98
    // correctly aligned
 
99
    struct DLLVERSIONINFO
 
100
    {
 
101
        DWORD cbSize;
 
102
        DWORD dwMajorVersion;                   // Major version
 
103
        DWORD dwMinorVersion;                   // Minor version
 
104
        DWORD dwBuildNumber;                    // Build number
 
105
        DWORD dwPlatformID;                     // DLLVER_PLATFORM_*
 
106
    };
 
107
 
 
108
    typedef HRESULT (CALLBACK* DLLGETVERSIONPROC)(DLLVERSIONINFO *);
 
109
#endif // defined(DLLVERSIONINFO)
 
110
 
 
111
 
 
112
// ---------------------------------------------------------------------------
 
113
// global variables
 
114
// ---------------------------------------------------------------------------
 
115
 
 
116
extern wxList WXDLLEXPORT wxPendingDelete;
 
117
 
 
118
#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
 
119
extern void wxSetKeyboardHook(bool doIt);
 
120
#endif
 
121
 
 
122
// NB: all "NoRedraw" classes must have the same names as the "normal" classes
 
123
//     with NR suffix - wxWindow::MSWCreate() supposes this
 
124
#ifdef __WXWINCE__
 
125
WXDLLIMPEXP_CORE       wxChar *wxCanvasClassName;
 
126
WXDLLIMPEXP_CORE       wxChar *wxCanvasClassNameNR;
 
127
#else
 
128
WXDLLIMPEXP_CORE const wxChar *wxCanvasClassName        = wxT("wxWindowClass");
 
129
WXDLLIMPEXP_CORE const wxChar *wxCanvasClassNameNR      = wxT("wxWindowClassNR");
 
130
#endif
 
131
WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassName      = wxT("wxMDIFrameClass");
 
132
WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassNameNoRedraw = wxT("wxMDIFrameClassNR");
 
133
WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassName = wxT("wxMDIChildFrameClass");
 
134
WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassNameNoRedraw = wxT("wxMDIChildFrameClassNR");
 
135
 
 
136
// ----------------------------------------------------------------------------
 
137
// private functions
 
138
// ----------------------------------------------------------------------------
 
139
 
 
140
LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
 
141
 
 
142
// ===========================================================================
 
143
// wxGUIAppTraits implementation
 
144
// ===========================================================================
 
145
 
 
146
// private class which we use to pass parameters from BeforeChildWaitLoop() to
 
147
// AfterChildWaitLoop()
 
148
struct ChildWaitLoopData
 
149
{
 
150
    ChildWaitLoopData(wxWindowDisabler *wd_, wxWindow *winActive_)
 
151
    {
 
152
        wd = wd_;
 
153
        winActive = winActive_;
 
154
    }
 
155
 
 
156
    wxWindowDisabler *wd;
 
157
    wxWindow *winActive;
 
158
};
 
159
 
 
160
void *wxGUIAppTraits::BeforeChildWaitLoop()
 
161
{
 
162
    /*
 
163
       We use a dirty hack here to disable all application windows (which we
 
164
       must do because otherwise the calls to wxYield() could lead to some very
 
165
       unexpected reentrancies in the users code) but to avoid losing
 
166
       focus/activation entirely when the child process terminates which would
 
167
       happen if we simply disabled everything using wxWindowDisabler. Indeed,
 
168
       remember that Windows will never activate a disabled window and when the
 
169
       last childs window is closed and Windows looks for a window to activate
 
170
       all our windows are still disabled. There is no way to enable them in
 
171
       time because we don't know when the childs windows are going to be
 
172
       closed, so the solution we use here is to keep one special tiny frame
 
173
       enabled all the time. Then when the child terminates it will get
 
174
       activated and when we close it below -- after reenabling all the other
 
175
       windows! -- the previously active window becomes activated again and
 
176
       everything is ok.
 
177
     */
 
178
    wxBeginBusyCursor();
 
179
 
 
180
    // first disable all existing windows
 
181
    wxWindowDisabler *wd = new wxWindowDisabler;
 
182
 
 
183
    // then create an "invisible" frame: it has minimal size, is positioned
 
184
    // (hopefully) outside the screen and doesn't appear on the taskbar
 
185
    wxWindow *winActive = new wxFrame
 
186
                    (
 
187
                        wxTheApp->GetTopWindow(),
 
188
                        wxID_ANY,
 
189
                        wxEmptyString,
 
190
                        wxPoint(32600, 32600),
 
191
                        wxSize(1, 1),
 
192
                        wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR
 
193
                    );
 
194
    winActive->Show();
 
195
 
 
196
    return new ChildWaitLoopData(wd, winActive);
 
197
}
 
198
 
 
199
void wxGUIAppTraits::AlwaysYield()
 
200
{
 
201
    wxYield();
 
202
}
 
203
 
 
204
void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
 
205
{
 
206
    wxEndBusyCursor();
 
207
 
 
208
    ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig;
 
209
 
 
210
    delete data->wd;
 
211
 
 
212
    // finally delete the dummy frame and, as wd has been already destroyed and
 
213
    // the other windows reenabled, the activation is going to return to the
 
214
    // window which had had it before
 
215
    data->winActive->Destroy();
 
216
 
 
217
    // also delete the temporary data object itself
 
218
    delete data;
 
219
}
 
220
 
 
221
bool wxGUIAppTraits::DoMessageFromThreadWait()
 
222
{
 
223
    // we should return false only if the app should exit, i.e. only if
 
224
    // Dispatch() determines that the main event loop should terminate
 
225
    return !wxTheApp || wxTheApp->Dispatch();
 
226
}
 
227
 
 
228
wxToolkitInfo& wxGUIAppTraits::GetToolkitInfo()
 
229
{
 
230
    static wxToolkitInfo info;
 
231
    wxToolkitInfo& baseInfo = wxAppTraits::GetToolkitInfo();
 
232
    info.versionMajor = baseInfo.versionMajor;
 
233
    info.versionMinor = baseInfo.versionMinor;
 
234
    info.os = baseInfo.os;
 
235
    info.shortName = _T("msw");
 
236
    info.name = _T("wxMSW");
 
237
#ifdef __WXUNIVERSAL__
 
238
    info.shortName << _T("univ");
 
239
    info.name << _T("/wxUniversal");
 
240
#endif
 
241
    return info;
 
242
}
 
243
 
 
244
// ===========================================================================
 
245
// wxApp implementation
 
246
// ===========================================================================
 
247
 
 
248
int wxApp::m_nCmdShow = SW_SHOWNORMAL;
 
249
 
 
250
// ---------------------------------------------------------------------------
 
251
// wxWin macros
 
252
// ---------------------------------------------------------------------------
 
253
 
 
254
IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
 
255
 
 
256
BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
 
257
    EVT_IDLE(wxApp::OnIdle)
 
258
    EVT_END_SESSION(wxApp::OnEndSession)
 
259
    EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
 
260
END_EVENT_TABLE()
 
261
 
 
262
// class to ensure that wxAppBase::CleanUp() is called if our Initialize()
 
263
// fails
 
264
class wxCallBaseCleanup
 
265
{
 
266
public:
 
267
    wxCallBaseCleanup(wxApp *app) : m_app(app) { }
 
268
    ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
 
269
 
 
270
    void Dismiss() { m_app = NULL; }
 
271
 
 
272
private:
 
273
    wxApp *m_app;
 
274
};
 
275
 
 
276
//// Initialize
 
277
bool wxApp::Initialize(int& argc, wxChar **argv)
 
278
{
 
279
    if ( !wxAppBase::Initialize(argc, argv) )
 
280
        return false;
 
281
 
 
282
    // ensure that base cleanup is done if we return too early
 
283
    wxCallBaseCleanup callBaseCleanup(this);
 
284
 
 
285
#ifdef __WXWINCE__
 
286
    wxString tmp = GetAppName();
 
287
    tmp += wxT("ClassName");
 
288
    wxCanvasClassName = wxStrdup( tmp.c_str() );
 
289
    tmp += wxT("NR");
 
290
    wxCanvasClassNameNR = wxStrdup( tmp.c_str() );
 
291
    HWND hWnd = FindWindow( wxCanvasClassNameNR, NULL );
 
292
    if (hWnd)
 
293
    {
 
294
        SetForegroundWindow( (HWND)(((DWORD)hWnd)|0x01) );
 
295
        return false;
 
296
    }
 
297
#endif
 
298
 
 
299
#if defined(__WIN95__) && !defined(__WXMICROWIN__)
 
300
    InitCommonControls();
 
301
#endif // __WIN95__
 
302
 
 
303
#if defined(__SMARTPHONE__) || defined(__POCKETPC__)
 
304
    SHInitExtraControls();
 
305
#endif
 
306
 
 
307
#ifndef __WXWINCE__
 
308
    // Don't show a message box if a function such as SHGetFileInfo
 
309
    // fails to find a device.
 
310
    SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
 
311
#endif
 
312
    
 
313
    wxOleInitialize();
 
314
 
 
315
    RegisterWindowClasses();
 
316
 
 
317
    wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
 
318
 
 
319
#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
 
320
    wxSetKeyboardHook(true);
 
321
#endif
 
322
 
 
323
    callBaseCleanup.Dismiss();
 
324
 
 
325
    return true;
 
326
}
 
327
 
 
328
// ---------------------------------------------------------------------------
 
329
// RegisterWindowClasses
 
330
// ---------------------------------------------------------------------------
 
331
 
 
332
// TODO we should only register classes really used by the app. For this it
 
333
//      would be enough to just delay the class registration until an attempt
 
334
//      to create a window of this class is made.
 
335
bool wxApp::RegisterWindowClasses()
 
336
{
 
337
    WNDCLASS wndclass;
 
338
    wxZeroMemory(wndclass);
 
339
 
 
340
    // for each class we register one with CS_(V|H)REDRAW style and one
 
341
    // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
 
342
    static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
 
343
    static const long styleNoRedraw = CS_DBLCLKS;
 
344
 
 
345
    // the fields which are common to all classes
 
346
    wndclass.lpfnWndProc   = (WNDPROC)wxWndProc;
 
347
    wndclass.hInstance     = wxhInstance;
 
348
    wndclass.hCursor       = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
 
349
 
 
350
    // register the class for all normal windows
 
351
    wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
 
352
    wndclass.lpszClassName = wxCanvasClassName;
 
353
    wndclass.style         = styleNormal;
 
354
 
 
355
    if ( !RegisterClass(&wndclass) )
 
356
    {
 
357
        wxLogLastError(wxT("RegisterClass(frame)"));
 
358
    }
 
359
 
 
360
    // "no redraw" frame
 
361
    wndclass.lpszClassName = wxCanvasClassNameNR;
 
362
    wndclass.style         = styleNoRedraw;
 
363
 
 
364
    if ( !RegisterClass(&wndclass) )
 
365
    {
 
366
        wxLogLastError(wxT("RegisterClass(no redraw frame)"));
 
367
    }
 
368
 
 
369
    // Register the MDI frame window class.
 
370
    wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
 
371
    wndclass.lpszClassName = wxMDIFrameClassName;
 
372
    wndclass.style         = styleNormal;
 
373
 
 
374
    if ( !RegisterClass(&wndclass) )
 
375
    {
 
376
        wxLogLastError(wxT("RegisterClass(MDI parent)"));
 
377
    }
 
378
 
 
379
    // "no redraw" MDI frame
 
380
    wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
 
381
    wndclass.style         = styleNoRedraw;
 
382
 
 
383
    if ( !RegisterClass(&wndclass) )
 
384
    {
 
385
        wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
 
386
    }
 
387
 
 
388
    // Register the MDI child frame window class.
 
389
    wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
 
390
    wndclass.lpszClassName = wxMDIChildFrameClassName;
 
391
    wndclass.style         = styleNormal;
 
392
 
 
393
    if ( !RegisterClass(&wndclass) )
 
394
    {
 
395
        wxLogLastError(wxT("RegisterClass(MDI child)"));
 
396
    }
 
397
 
 
398
    // "no redraw" MDI child frame
 
399
    wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
 
400
    wndclass.style         = styleNoRedraw;
 
401
 
 
402
    if ( !RegisterClass(&wndclass) )
 
403
    {
 
404
        wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
 
405
    }
 
406
 
 
407
    return true;
 
408
}
 
409
 
 
410
// ---------------------------------------------------------------------------
 
411
// UnregisterWindowClasses
 
412
// ---------------------------------------------------------------------------
 
413
 
 
414
bool wxApp::UnregisterWindowClasses()
 
415
{
 
416
    bool retval = true;
 
417
 
 
418
#ifndef __WXMICROWIN__
 
419
    // MDI frame window class.
 
420
    if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
 
421
    {
 
422
        wxLogLastError(wxT("UnregisterClass(MDI parent)"));
 
423
 
 
424
        retval = false;
 
425
    }
 
426
 
 
427
    // "no redraw" MDI frame
 
428
    if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
 
429
    {
 
430
        wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
 
431
 
 
432
        retval = false;
 
433
    }
 
434
 
 
435
    // MDI child frame window class.
 
436
    if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
 
437
    {
 
438
        wxLogLastError(wxT("UnregisterClass(MDI child)"));
 
439
 
 
440
        retval = false;
 
441
    }
 
442
 
 
443
    // "no redraw" MDI child frame
 
444
    if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
 
445
    {
 
446
        wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
 
447
 
 
448
        retval = false;
 
449
    }
 
450
 
 
451
    // canvas class name
 
452
    if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
 
453
    {
 
454
        wxLogLastError(wxT("UnregisterClass(canvas)"));
 
455
 
 
456
        retval = false;
 
457
    }
 
458
 
 
459
    if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
 
460
    {
 
461
        wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
 
462
 
 
463
        retval = false;
 
464
    }
 
465
#endif // __WXMICROWIN__
 
466
 
 
467
    return retval;
 
468
}
 
469
 
 
470
void wxApp::CleanUp()
 
471
{
 
472
    // all objects pending for deletion must be deleted first, otherwise we
 
473
    // would crash when they use wxWinHandleHash (and UnregisterWindowClasses()
 
474
    // call wouldn't succeed as long as any windows still exist), so call the
 
475
    // base class method first and only then do our clean up
 
476
    wxAppBase::CleanUp();
 
477
 
 
478
#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
 
479
    wxSetKeyboardHook(false);
 
480
#endif
 
481
 
 
482
    wxOleUninitialize();
 
483
 
 
484
    // for an EXE the classes are unregistered when it terminates but DLL may
 
485
    // be loaded several times (load/unload/load) into the same process in
 
486
    // which case the registration will fail after the first time if we don't
 
487
    // unregister the classes now
 
488
    UnregisterWindowClasses();
 
489
 
 
490
    delete wxWinHandleHash;
 
491
    wxWinHandleHash = NULL;
 
492
    
 
493
#ifdef __WXWINCE__
 
494
    free( wxCanvasClassName );
 
495
    free( wxCanvasClassNameNR );
 
496
#endif
 
497
}
 
498
 
 
499
// ----------------------------------------------------------------------------
 
500
// wxApp ctor/dtor
 
501
// ----------------------------------------------------------------------------
 
502
 
 
503
wxApp::wxApp()
 
504
{
 
505
    m_printMode = wxPRINT_WINDOWS;
 
506
}
 
507
 
 
508
wxApp::~wxApp()
 
509
{
 
510
    // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
 
511
    // don't come from main(), so we have to free them
 
512
 
 
513
    while ( argc )
 
514
    {
 
515
        // m_argv elements were allocated by wxStrdup()
 
516
        free(argv[--argc]);
 
517
    }
 
518
 
 
519
    // but m_argv itself -- using new[]
 
520
    delete [] argv;
 
521
}
 
522
 
 
523
// ----------------------------------------------------------------------------
 
524
// wxApp idle handling
 
525
// ----------------------------------------------------------------------------
 
526
 
 
527
void wxApp::OnIdle(wxIdleEvent& event)
 
528
{
 
529
    wxAppBase::OnIdle(event);
 
530
 
 
531
#if wxUSE_DC_CACHEING
 
532
    // automated DC cache management: clear the cached DCs and bitmap
 
533
    // if it's likely that the app has finished with them, that is, we
 
534
    // get an idle event and we're not dragging anything.
 
535
    if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
 
536
        wxDC::ClearCache();
 
537
#endif // wxUSE_DC_CACHEING
 
538
}
 
539
 
 
540
void wxApp::WakeUpIdle()
 
541
{
 
542
    // Send the top window a dummy message so idle handler processing will
 
543
    // start up again.  Doing it this way ensures that the idle handler
 
544
    // wakes up in the right thread (see also wxWakeUpMainThread() which does
 
545
    // the same for the main app thread only)
 
546
    wxWindow *topWindow = wxTheApp->GetTopWindow();
 
547
    if ( topWindow )
 
548
    {
 
549
        if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
 
550
        {
 
551
            // should never happen
 
552
            wxLogLastError(wxT("PostMessage(WM_NULL)"));
 
553
        }
 
554
    }
 
555
}
 
556
 
 
557
// ----------------------------------------------------------------------------
 
558
// other wxApp event hanlders
 
559
// ----------------------------------------------------------------------------
 
560
 
 
561
void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
 
562
{
 
563
    if (GetTopWindow())
 
564
        GetTopWindow()->Close(true);
 
565
}
 
566
 
 
567
// Default behaviour: close the application with prompts. The
 
568
// user can veto the close, and therefore the end session.
 
569
void wxApp::OnQueryEndSession(wxCloseEvent& event)
 
570
{
 
571
    if (GetTopWindow())
 
572
    {
 
573
        if (!GetTopWindow()->Close(!event.CanVeto()))
 
574
            event.Veto(true);
 
575
    }
 
576
}
 
577
 
 
578
// ----------------------------------------------------------------------------
 
579
// miscellaneous
 
580
// ----------------------------------------------------------------------------
 
581
 
 
582
/* static */
 
583
int wxApp::GetComCtl32Version()
 
584
{
 
585
#if defined(__WXMICROWIN__) || defined(__WXWINCE__)
 
586
    return 0;
 
587
#else
 
588
    // cache the result
 
589
    //
 
590
    // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
 
591
    //     but as its value should be the same both times it doesn't matter
 
592
    static int s_verComCtl32 = -1;
 
593
 
 
594
    if ( s_verComCtl32 == -1 )
 
595
    {
 
596
        // initally assume no comctl32.dll at all
 
597
        s_verComCtl32 = 0;
 
598
 
 
599
        // we're prepared to handle the errors
 
600
        wxLogNull noLog;
 
601
 
 
602
#if wxUSE_DYNLIB_CLASS
 
603
        // do we have it?
 
604
        wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
 
605
 
 
606
        // if so, then we can check for the version
 
607
        if ( dllComCtl32.IsLoaded() )
 
608
        {
 
609
            // now check if the function is available during run-time
 
610
            wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dllComCtl32 );
 
611
            if ( pfnDllGetVersion )
 
612
            {
 
613
                DLLVERSIONINFO dvi;
 
614
                dvi.cbSize = sizeof(dvi);
 
615
 
 
616
                HRESULT hr = (*pfnDllGetVersion)(&dvi);
 
617
                if ( FAILED(hr) )
 
618
                {
 
619
                    wxLogApiError(_T("DllGetVersion"), hr);
 
620
                }
 
621
                else
 
622
                {
 
623
                    // this is incompatible with _WIN32_IE values, but
 
624
                    // compatible with the other values returned by
 
625
                    // GetComCtl32Version()
 
626
                    s_verComCtl32 = 100*dvi.dwMajorVersion +
 
627
                                        dvi.dwMinorVersion;
 
628
                }
 
629
            }
 
630
 
 
631
            // if DllGetVersion() is unavailable either during compile or
 
632
            // run-time, try to guess the version otherwise
 
633
            if ( !s_verComCtl32 )
 
634
            {
 
635
                // InitCommonControlsEx is unique to 4.70 and later
 
636
                void *pfn = dllComCtl32.GetSymbol(_T("InitCommonControlsEx"));
 
637
                if ( !pfn )
 
638
                {
 
639
                    // not found, must be 4.00
 
640
                    s_verComCtl32 = 400;
 
641
                }
 
642
                else // 4.70+
 
643
                {
 
644
                    // many symbols appeared in comctl32 4.71, could use any of
 
645
                    // them except may be DllInstall()
 
646
                    pfn = dllComCtl32.GetSymbol(_T("InitializeFlatSB"));
 
647
                    if ( !pfn )
 
648
                    {
 
649
                        // not found, must be 4.70
 
650
                        s_verComCtl32 = 470;
 
651
                    }
 
652
                    else
 
653
                    {
 
654
                        // found, must be 4.71 or later
 
655
                        s_verComCtl32 = 471;
 
656
                    }
 
657
                }
 
658
            }
 
659
        }
 
660
#endif        
 
661
    }
 
662
 
 
663
    return s_verComCtl32;
 
664
#endif // Microwin/!Microwin
 
665
}
 
666
 
 
667
// Yield to incoming messages
 
668
 
 
669
bool wxApp::Yield(bool onlyIfNeeded)
 
670
{
 
671
    // MT-FIXME
 
672
    static bool s_inYield = false;
 
673
 
 
674
#if wxUSE_LOG
 
675
    // disable log flushing from here because a call to wxYield() shouldn't
 
676
    // normally result in message boxes popping up &c
 
677
    wxLog::Suspend();
 
678
#endif // wxUSE_LOG
 
679
 
 
680
    if ( s_inYield )
 
681
    {
 
682
        if ( !onlyIfNeeded )
 
683
        {
 
684
            wxFAIL_MSG( wxT("wxYield called recursively" ) );
 
685
        }
 
686
 
 
687
        return false;
 
688
    }
 
689
 
 
690
    s_inYield = true;
 
691
 
 
692
    // we don't want to process WM_QUIT from here - it should be processed in
 
693
    // the main event loop in order to stop it
 
694
    MSG msg;
 
695
    while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
 
696
            msg.message != WM_QUIT )
 
697
    {
 
698
#if wxUSE_THREADS
 
699
        wxMutexGuiLeaveOrEnter();
 
700
#endif // wxUSE_THREADS
 
701
 
 
702
        if ( !wxTheApp->Dispatch() )
 
703
            break;
 
704
    }
 
705
 
 
706
    // if there are pending events, we must process them.
 
707
    ProcessPendingEvents();
 
708
 
 
709
#if wxUSE_LOG
 
710
    // let the logs be flashed again
 
711
    wxLog::Resume();
 
712
#endif // wxUSE_LOG
 
713
 
 
714
    s_inYield = false;
 
715
 
 
716
    return true;
 
717
}
 
718
 
 
719
#if wxUSE_EXCEPTIONS
 
720
 
 
721
// ----------------------------------------------------------------------------
 
722
// exception handling
 
723
// ----------------------------------------------------------------------------
 
724
 
 
725
bool wxApp::OnExceptionInMainLoop()
 
726
{
 
727
    // ask the user about what to do: use the Win32 API function here as it
 
728
    // could be dangerous to use any wxWidgets code in this state
 
729
    switch (
 
730
            ::MessageBox
 
731
              (
 
732
                NULL,
 
733
                _T("An unhandled exception occurred. Press \"Abort\" to \
 
734
terminate the program,\r\n\
 
735
\"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
 
736
                _T("Unhandled exception"),
 
737
                MB_ABORTRETRYIGNORE |
 
738
                MB_ICONERROR| 
 
739
                MB_TASKMODAL
 
740
              )
 
741
           )
 
742
    {
 
743
        case IDABORT:
 
744
            throw;
 
745
 
 
746
        default:
 
747
            wxFAIL_MSG( _T("unexpected MessageBox() return code") );
 
748
            // fall through
 
749
 
 
750
        case IDRETRY:
 
751
            return false;
 
752
 
 
753
        case IDIGNORE:
 
754
            return true;
 
755
    }
 
756
}
 
757
 
 
758
#endif // wxUSE_EXCEPTIONS
 
759
 
 
760
// ----------------------------------------------------------------------------
 
761
// deprecated event loop functions
 
762
// ----------------------------------------------------------------------------
 
763
 
 
764
#if WXWIN_COMPATIBILITY_2_4
 
765
 
 
766
#include "wx/evtloop.h"
 
767
 
 
768
void wxApp::DoMessage(WXMSG *pMsg)
 
769
{
 
770
    wxEventLoop *evtLoop = wxEventLoop::GetActive();
 
771
    if ( evtLoop )
 
772
        evtLoop->ProcessMessage(pMsg);
 
773
}
 
774
 
 
775
bool wxApp::DoMessage()
 
776
{
 
777
    wxEventLoop *evtLoop = wxEventLoop::GetActive();
 
778
    return evtLoop ? evtLoop->Dispatch() : false;
 
779
}
 
780
 
 
781
bool wxApp::ProcessMessage(WXMSG* pMsg)
 
782
{
 
783
    wxEventLoop *evtLoop = wxEventLoop::GetActive();
 
784
    return evtLoop && evtLoop->PreProcessMessage(pMsg);
 
785
}
 
786
 
 
787
#endif // WXWIN_COMPATIBILITY_2_4
 
788