]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dcclient.cpp
wxMessageBox off the main thread lost result code.
[wxWidgets.git] / src / msw / dcclient.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
df91131c 2// Name: src/msw/dcclient.cpp
2bda0e17
KB
3// Purpose: wxClientDC class
4// Author: Julian Smart
5// Modified by:
6// Created: 01/02/97
6c9a19aa 7// Copyright: (c) Julian Smart
65571936 8// Licence: wxWindows licence
2bda0e17
KB
9/////////////////////////////////////////////////////////////////////////////
10
c6eba8f8
VZ
11// ===========================================================================
12// declarations
13// ===========================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
2bda0e17
KB
19// For compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
c6eba8f8 23 #pragma hdrstop
2bda0e17
KB
24#endif
25
df91131c 26#include "wx/dcclient.h"
888dde65 27#include "wx/msw/dcclient.h"
df91131c
WS
28
29#ifndef WX_PRECOMP
30 #include "wx/string.h"
ddc8faa9 31 #include "wx/hashmap.h"
e4db172a 32 #include "wx/log.h"
cdccdfab 33 #include "wx/window.h"
df91131c
WS
34#endif
35
c6eba8f8
VZ
36#include "wx/msw/private.h"
37
3a5ffa81 38// ----------------------------------------------------------------------------
ddc8faa9 39// local data structures
3a5ffa81
VZ
40// ----------------------------------------------------------------------------
41
ddc8faa9
VZ
42// This is a base class for two concrete subclasses below and contains HDC
43// cached for the duration of the WM_PAINT processing together with some
44// bookkeeping information.
45class wxPaintDCInfo
3a5ffa81 46{
ddc8faa9
VZ
47public:
48 wxPaintDCInfo(HDC hdc)
49 : m_hdc(hdc)
3a5ffa81 50 {
3a5ffa81
VZ
51 }
52
ddc8faa9
VZ
53 // The derived class must perform some cleanup.
54 virtual ~wxPaintDCInfo() = 0;
55
56 WXHDC GetHDC() const { return (WXHDC)m_hdc; }
57
58protected:
59 const HDC m_hdc;
60
61 wxDECLARE_NO_COPY_CLASS(wxPaintDCInfo);
3a5ffa81
VZ
62};
63
ddc8faa9
VZ
64namespace
65{
66
67// This subclass contains information for the HDCs we create ourselves, i.e.
68// those for which we call BeginPaint() -- and hence need to call EndPaint().
69class wxPaintDCInfoOur : public wxPaintDCInfo
70{
71public:
72 wxPaintDCInfoOur(wxWindow* win)
73 : wxPaintDCInfo(::BeginPaint(GetHwndOf(win), GetPaintStructPtr(m_ps))),
74 m_hwnd(GetHwndOf(win))
75 {
76 }
77
78 virtual ~wxPaintDCInfoOur()
79 {
80 ::EndPaint(m_hwnd, &m_ps);
81 }
3a5ffa81 82
ddc8faa9
VZ
83private:
84 // This helper is only needed in order to call it from the ctor initializer
85 // list.
86 static PAINTSTRUCT* GetPaintStructPtr(PAINTSTRUCT& ps)
87 {
88 wxZeroMemory(ps);
89 return &ps;
90 }
3a5ffa81 91
ddc8faa9
VZ
92 const HWND m_hwnd;
93 PAINTSTRUCT m_ps;
94
95 wxDECLARE_NO_COPY_CLASS(wxPaintDCInfoOur);
96};
97
98// This subclass contains information for the HDCs we receive from outside, as
99// WPARAM of WM_PAINT itself.
100class wxPaintDCInfoExternal : public wxPaintDCInfo
101{
102public:
103 wxPaintDCInfoExternal(HDC hdc)
104 : wxPaintDCInfo(hdc),
105 m_state(::SaveDC(hdc))
106 {
107 }
108
109 virtual ~wxPaintDCInfoExternal()
110 {
111 ::RestoreDC(m_hdc, m_state);
112 }
113
114private:
115 const int m_state;
116
117 wxDECLARE_NO_COPY_CLASS(wxPaintDCInfoExternal);
118};
119
120// The global map containing HDC to use for the given window. The entries in
121// this map only exist during WM_PAINT processing and are destroyed when it is
122// over.
123//
124// It is needed because in some circumstances it can happen that more than one
125// wxPaintDC is created for the same window during its WM_PAINT handling (and
126// as this can happen implicitly, e.g. by calling a function in some library,
127// this can be quite difficult to find) but we need to reuse the same HDC for
128// all of them because we can't call BeginPaint() more than once. So we cache
129// the first HDC created for the window in this map and then reuse it later if
130// needed. And, of course, remove it from the map when the painting is done.
131WX_DECLARE_HASH_MAP(wxWindow *, wxPaintDCInfo *,
132 wxPointerHash, wxPointerEqual,
133 PaintDCInfos);
134
135PaintDCInfos gs_PaintDCInfos;
136
137} // anonymous namespace
2bda0e17 138
c6eba8f8
VZ
139// ----------------------------------------------------------------------------
140// global variables
141// ----------------------------------------------------------------------------
142
657a8a35 143#ifdef wxHAS_PAINT_DEBUG
c6eba8f8 144 // a global variable which we check to verify that wxPaintDC are only
a0d9c6cb 145 // created in response to WM_PAINT message - doing this from elsewhere is a
77ffb593 146 // common programming error among wxWidgets programmers and might lead to
c6eba8f8 147 // very subtle and difficult to debug refresh/repaint bugs.
edccf428 148 int g_isPainting = 0;
657a8a35 149#endif // wxHAS_PAINT_DEBUG
c6eba8f8
VZ
150
151// ===========================================================================
152// implementation
153// ===========================================================================
e6460682 154
c6eba8f8 155// ----------------------------------------------------------------------------
888dde65 156// wxMSWWindowDCImpl
c6eba8f8
VZ
157// ----------------------------------------------------------------------------
158
888dde65
RR
159IMPLEMENT_ABSTRACT_CLASS(wxWindowDCImpl, wxMSWDCImpl)
160
161wxWindowDCImpl::wxWindowDCImpl( wxDC *owner ) :
162 wxMSWDCImpl( owner )
2bda0e17 163{
2bda0e17
KB
164}
165
f0875501 166wxWindowDCImpl::wxWindowDCImpl( wxDC *owner, wxWindow *window ) :
888dde65 167 wxMSWDCImpl( owner )
2bda0e17 168{
9a83f860 169 wxCHECK_RET( window, wxT("invalid window in wxWindowDCImpl") );
a91b47e8 170
888dde65
RR
171 m_window = window;
172 m_hDC = (WXHDC) ::GetWindowDC(GetHwndOf(m_window));
2bda0e17 173
7ba4fbeb
VZ
174 // m_bOwnsDC was already set to false in the base class ctor, so the DC
175 // will be released (and not deleted) in ~wxDC
7ba4fbeb
VZ
176 InitDC();
177}
edccf428 178
888dde65 179void wxWindowDCImpl::InitDC()
7ba4fbeb
VZ
180{
181 // the background mode is only used for text background and is set in
182 // DrawText() to OPAQUE as required, otherwise always TRANSPARENT,
183 ::SetBkMode(GetHdc(), TRANSPARENT);
c6eba8f8 184
574c939e
KB
185 // since we are a window dc we need to grab the palette from the window
186#if wxUSE_PALETTE
187 InitializePalette();
188#endif
2bda0e17
KB
189}
190
888dde65 191void wxWindowDCImpl::DoGetSize(int *width, int *height) const
994a3786 192{
9a83f860 193 wxCHECK_RET( m_window, wxT("wxWindowDCImpl without a window?") );
994a3786 194
888dde65 195 m_window->GetSize(width, height);
994a3786
VZ
196}
197
c6eba8f8 198// ----------------------------------------------------------------------------
888dde65 199// wxClientDCImpl
c6eba8f8 200// ----------------------------------------------------------------------------
e6460682 201
888dde65
RR
202IMPLEMENT_ABSTRACT_CLASS(wxClientDCImpl, wxWindowDCImpl)
203
204wxClientDCImpl::wxClientDCImpl( wxDC *owner ) :
205 wxWindowDCImpl( owner )
2bda0e17 206{
2bda0e17
KB
207}
208
888dde65
RR
209wxClientDCImpl::wxClientDCImpl( wxDC *owner, wxWindow *window ) :
210 wxWindowDCImpl( owner )
2bda0e17 211{
9a83f860 212 wxCHECK_RET( window, wxT("invalid window in wxClientDCImpl") );
a91b47e8 213
888dde65
RR
214 m_window = window;
215 m_hDC = (WXHDC)::GetDC(GetHwndOf(window));
2bda0e17 216
7ba4fbeb
VZ
217 // m_bOwnsDC was already set to false in the base class ctor, so the DC
218 // will be released (and not deleted) in ~wxDC
2bda0e17 219
7ba4fbeb 220 InitDC();
2bda0e17
KB
221}
222
888dde65 223void wxClientDCImpl::InitDC()
1e6feb95 224{
888dde65 225 wxWindowDCImpl::InitDC();
1e6feb95
VZ
226
227 // in wxUniv build we must manually do some DC adjustments usually
228 // performed by Windows for us
1fa6ebf7
VZ
229 //
230 // we also need to take the menu/toolbar manually into account under
231 // Windows CE because they're just another control there, not anything
232 // special as usually under Windows
233#if defined(__WXUNIVERSAL__) || defined(__WXWINCE__)
888dde65 234 wxPoint ptOrigin = m_window->GetClientAreaOrigin();
1e6feb95
VZ
235 if ( ptOrigin.x || ptOrigin.y )
236 {
237 // no need to shift DC origin if shift is null
238 SetDeviceOrigin(ptOrigin.x, ptOrigin.y);
239 }
240
241 // clip the DC to avoid overwriting the non client area
c7d6c563
VS
242 wxSize size = m_window->GetClientSize();
243 DoSetClippingRegion(0, 0, size.x, size.y);
1fa6ebf7 244#endif // __WXUNIVERSAL__ || __WXWINCE__
1e6feb95
VZ
245}
246
888dde65 247wxClientDCImpl::~wxClientDCImpl()
1e6feb95
VZ
248{
249}
250
888dde65 251void wxClientDCImpl::DoGetSize(int *width, int *height) const
994a3786 252{
9a83f860 253 wxCHECK_RET( m_window, wxT("wxClientDCImpl without a window?") );
994a3786 254
888dde65 255 m_window->GetClientSize(width, height);
994a3786
VZ
256}
257
c6eba8f8 258// ----------------------------------------------------------------------------
888dde65 259// wxPaintDCImpl
c6eba8f8 260// ----------------------------------------------------------------------------
e6460682 261
888dde65 262IMPLEMENT_ABSTRACT_CLASS(wxPaintDCImpl, wxClientDCImpl)
2bda0e17 263
888dde65
RR
264wxPaintDCImpl::wxPaintDCImpl( wxDC *owner ) :
265 wxClientDCImpl( owner )
c6eba8f8 266{
c6eba8f8
VZ
267}
268
888dde65
RR
269wxPaintDCImpl::wxPaintDCImpl( wxDC *owner, wxWindow *window ) :
270 wxClientDCImpl( owner )
2bda0e17 271{
888dde65 272 wxCHECK_RET( window, wxT("NULL canvas in wxPaintDCImpl ctor") );
3a5ffa81 273
657a8a35 274#ifdef wxHAS_PAINT_DEBUG
edccf428 275 if ( g_isPainting <= 0 )
3a5ffa81 276 {
888dde65 277 wxFAIL_MSG( wxT("wxPaintDCImpl may be created only in EVT_PAINT handler!") );
2bda0e17 278
3a5ffa81
VZ
279 return;
280 }
4b6a582b 281#endif // wxHAS_PAINT_DEBUG
c6eba8f8 282
4877e9bf
VZ
283 // see comments in src/msw/window.cpp where this is defined
284 extern bool wxDidCreatePaintDC;
285
286 wxDidCreatePaintDC = true;
287
288
888dde65 289 m_window = window;
83626bfa 290
3a5ffa81 291 // do we have a DC for this window in the cache?
ddc8faa9
VZ
292 m_hDC = FindDCInCache(m_window);
293 if ( !m_hDC )
3a5ffa81 294 {
ddc8faa9
VZ
295 // not in cache, create a new one
296 wxPaintDCInfoOur* const info = new wxPaintDCInfoOur(m_window);
297 gs_PaintDCInfos[m_window] = info;
298 m_hDC = info->GetHDC();
3a5ffa81 299 }
a91b47e8 300
5adad466 301 // Note: at this point m_hDC can be NULL under MicroWindows, when dragging.
27539df8
VZ
302 if (!GetHDC())
303 return;
304
305 // (re)set the DC parameters.
306 InitDC();
307
308 // the HDC can have a clipping box (which we didn't set), make sure our
309 // DoGetClippingBox() checks for it
e9f8a82e 310 m_clipping = true;
2bda0e17
KB
311}
312
888dde65 313wxPaintDCImpl::~wxPaintDCImpl()
2bda0e17 314{
3a5ffa81
VZ
315 if ( m_hDC )
316 {
edccf428 317 SelectOldObjects(m_hDC);
ddc8faa9
VZ
318 m_hDC = 0;
319 }
320}
edccf428 321
3a5ffa81 322
ddc8faa9
VZ
323/* static */
324wxPaintDCInfo *wxPaintDCImpl::FindInCache(wxWindow *win)
325{
326 PaintDCInfos::const_iterator it = gs_PaintDCInfos.find( win );
3a5ffa81 327
ddc8faa9
VZ
328 return it != gs_PaintDCInfos.end() ? it->second : NULL;
329}
2bc1aa11 330
ddc8faa9
VZ
331/* static */
332WXHDC wxPaintDCImpl::FindDCInCache(wxWindow* win)
333{
334 wxPaintDCInfo* const info = FindInCache(win);
edccf428 335
ddc8faa9 336 return info ? info->GetHDC() : 0;
2bda0e17 337}
81d66cf3 338
ddc8faa9
VZ
339/* static */
340void wxPaintDCImpl::EndPaint(wxWindow *win)
3a5ffa81 341{
ddc8faa9
VZ
342 wxPaintDCInfo *info = FindInCache(win);
343 if ( info )
3a5ffa81 344 {
ddc8faa9
VZ
345 gs_PaintDCInfos.erase(win);
346 delete info;
3a5ffa81 347 }
3a5ffa81 348}
63da7df7 349
ddc8faa9 350wxPaintDCInfo::~wxPaintDCInfo()
63da7df7 351{
63da7df7
JS
352}
353
c6151f2a
JS
354/*
355 * wxPaintDCEx
356 */
d71cc120 357
888dde65 358class wxPaintDCExImpl: public wxPaintDCImpl
c6151f2a 359{
888dde65
RR
360public:
361 wxPaintDCExImpl( wxDC *owner, wxWindow *window, WXHDC dc );
362 ~wxPaintDCExImpl();
888dde65 363};
c6151f2a 364
c6151f2a 365
888dde65
RR
366IMPLEMENT_ABSTRACT_CLASS(wxPaintDCEx,wxPaintDC)
367
f0875501
VZ
368wxPaintDCEx::wxPaintDCEx(wxWindow *window, WXHDC dc)
369 : wxPaintDC(new wxPaintDCExImpl(this, window, dc))
888dde65 370{
c6151f2a
JS
371}
372
f0875501
VZ
373wxPaintDCExImpl::wxPaintDCExImpl(wxDC *owner, wxWindow *window, WXHDC dc)
374 : wxPaintDCImpl( owner )
c6151f2a 375{
ddc8faa9 376 wxCHECK_RET( dc, wxT("wxPaintDCEx requires an existing device context") );
888dde65 377
ddc8faa9 378 m_window = window;
025f5d14 379 m_hDC = dc;
c6151f2a 380}
888dde65 381
ddc8faa9
VZ
382wxPaintDCExImpl::~wxPaintDCExImpl()
383{
384 // prevent the base class dtor from ReleaseDC()ing it again
385 m_hDC = 0;
386}