]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/dcclient.cpp
wxMessageBox off the main thread lost result code.
[wxWidgets.git] / src / msw / dcclient.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/msw/dcclient.cpp
3// Purpose: wxClientDC class
4// Author: Julian Smart
5// Modified by:
6// Created: 01/02/97
7// Copyright: (c) Julian Smart
8// Licence: wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11// ===========================================================================
12// declarations
13// ===========================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
19// For compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23 #pragma hdrstop
24#endif
25
26#include "wx/dcclient.h"
27#include "wx/msw/dcclient.h"
28
29#ifndef WX_PRECOMP
30 #include "wx/string.h"
31 #include "wx/hashmap.h"
32 #include "wx/log.h"
33 #include "wx/window.h"
34#endif
35
36#include "wx/msw/private.h"
37
38// ----------------------------------------------------------------------------
39// local data structures
40// ----------------------------------------------------------------------------
41
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
46{
47public:
48 wxPaintDCInfo(HDC hdc)
49 : m_hdc(hdc)
50 {
51 }
52
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);
62};
63
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 }
82
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 }
91
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
138
139// ----------------------------------------------------------------------------
140// global variables
141// ----------------------------------------------------------------------------
142
143#ifdef wxHAS_PAINT_DEBUG
144 // a global variable which we check to verify that wxPaintDC are only
145 // created in response to WM_PAINT message - doing this from elsewhere is a
146 // common programming error among wxWidgets programmers and might lead to
147 // very subtle and difficult to debug refresh/repaint bugs.
148 int g_isPainting = 0;
149#endif // wxHAS_PAINT_DEBUG
150
151// ===========================================================================
152// implementation
153// ===========================================================================
154
155// ----------------------------------------------------------------------------
156// wxMSWWindowDCImpl
157// ----------------------------------------------------------------------------
158
159IMPLEMENT_ABSTRACT_CLASS(wxWindowDCImpl, wxMSWDCImpl)
160
161wxWindowDCImpl::wxWindowDCImpl( wxDC *owner ) :
162 wxMSWDCImpl( owner )
163{
164}
165
166wxWindowDCImpl::wxWindowDCImpl( wxDC *owner, wxWindow *window ) :
167 wxMSWDCImpl( owner )
168{
169 wxCHECK_RET( window, wxT("invalid window in wxWindowDCImpl") );
170
171 m_window = window;
172 m_hDC = (WXHDC) ::GetWindowDC(GetHwndOf(m_window));
173
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
176 InitDC();
177}
178
179void wxWindowDCImpl::InitDC()
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);
184
185 // since we are a window dc we need to grab the palette from the window
186#if wxUSE_PALETTE
187 InitializePalette();
188#endif
189}
190
191void wxWindowDCImpl::DoGetSize(int *width, int *height) const
192{
193 wxCHECK_RET( m_window, wxT("wxWindowDCImpl without a window?") );
194
195 m_window->GetSize(width, height);
196}
197
198// ----------------------------------------------------------------------------
199// wxClientDCImpl
200// ----------------------------------------------------------------------------
201
202IMPLEMENT_ABSTRACT_CLASS(wxClientDCImpl, wxWindowDCImpl)
203
204wxClientDCImpl::wxClientDCImpl( wxDC *owner ) :
205 wxWindowDCImpl( owner )
206{
207}
208
209wxClientDCImpl::wxClientDCImpl( wxDC *owner, wxWindow *window ) :
210 wxWindowDCImpl( owner )
211{
212 wxCHECK_RET( window, wxT("invalid window in wxClientDCImpl") );
213
214 m_window = window;
215 m_hDC = (WXHDC)::GetDC(GetHwndOf(window));
216
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
219
220 InitDC();
221}
222
223void wxClientDCImpl::InitDC()
224{
225 wxWindowDCImpl::InitDC();
226
227 // in wxUniv build we must manually do some DC adjustments usually
228 // performed by Windows for us
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__)
234 wxPoint ptOrigin = m_window->GetClientAreaOrigin();
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
242 wxSize size = m_window->GetClientSize();
243 DoSetClippingRegion(0, 0, size.x, size.y);
244#endif // __WXUNIVERSAL__ || __WXWINCE__
245}
246
247wxClientDCImpl::~wxClientDCImpl()
248{
249}
250
251void wxClientDCImpl::DoGetSize(int *width, int *height) const
252{
253 wxCHECK_RET( m_window, wxT("wxClientDCImpl without a window?") );
254
255 m_window->GetClientSize(width, height);
256}
257
258// ----------------------------------------------------------------------------
259// wxPaintDCImpl
260// ----------------------------------------------------------------------------
261
262IMPLEMENT_ABSTRACT_CLASS(wxPaintDCImpl, wxClientDCImpl)
263
264wxPaintDCImpl::wxPaintDCImpl( wxDC *owner ) :
265 wxClientDCImpl( owner )
266{
267}
268
269wxPaintDCImpl::wxPaintDCImpl( wxDC *owner, wxWindow *window ) :
270 wxClientDCImpl( owner )
271{
272 wxCHECK_RET( window, wxT("NULL canvas in wxPaintDCImpl ctor") );
273
274#ifdef wxHAS_PAINT_DEBUG
275 if ( g_isPainting <= 0 )
276 {
277 wxFAIL_MSG( wxT("wxPaintDCImpl may be created only in EVT_PAINT handler!") );
278
279 return;
280 }
281#endif // wxHAS_PAINT_DEBUG
282
283 // see comments in src/msw/window.cpp where this is defined
284 extern bool wxDidCreatePaintDC;
285
286 wxDidCreatePaintDC = true;
287
288
289 m_window = window;
290
291 // do we have a DC for this window in the cache?
292 m_hDC = FindDCInCache(m_window);
293 if ( !m_hDC )
294 {
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();
299 }
300
301 // Note: at this point m_hDC can be NULL under MicroWindows, when dragging.
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
310 m_clipping = true;
311}
312
313wxPaintDCImpl::~wxPaintDCImpl()
314{
315 if ( m_hDC )
316 {
317 SelectOldObjects(m_hDC);
318 m_hDC = 0;
319 }
320}
321
322
323/* static */
324wxPaintDCInfo *wxPaintDCImpl::FindInCache(wxWindow *win)
325{
326 PaintDCInfos::const_iterator it = gs_PaintDCInfos.find( win );
327
328 return it != gs_PaintDCInfos.end() ? it->second : NULL;
329}
330
331/* static */
332WXHDC wxPaintDCImpl::FindDCInCache(wxWindow* win)
333{
334 wxPaintDCInfo* const info = FindInCache(win);
335
336 return info ? info->GetHDC() : 0;
337}
338
339/* static */
340void wxPaintDCImpl::EndPaint(wxWindow *win)
341{
342 wxPaintDCInfo *info = FindInCache(win);
343 if ( info )
344 {
345 gs_PaintDCInfos.erase(win);
346 delete info;
347 }
348}
349
350wxPaintDCInfo::~wxPaintDCInfo()
351{
352}
353
354/*
355 * wxPaintDCEx
356 */
357
358class wxPaintDCExImpl: public wxPaintDCImpl
359{
360public:
361 wxPaintDCExImpl( wxDC *owner, wxWindow *window, WXHDC dc );
362 ~wxPaintDCExImpl();
363};
364
365
366IMPLEMENT_ABSTRACT_CLASS(wxPaintDCEx,wxPaintDC)
367
368wxPaintDCEx::wxPaintDCEx(wxWindow *window, WXHDC dc)
369 : wxPaintDC(new wxPaintDCExImpl(this, window, dc))
370{
371}
372
373wxPaintDCExImpl::wxPaintDCExImpl(wxDC *owner, wxWindow *window, WXHDC dc)
374 : wxPaintDCImpl( owner )
375{
376 wxCHECK_RET( dc, wxT("wxPaintDCEx requires an existing device context") );
377
378 m_window = window;
379 m_hDC = dc;
380}
381
382wxPaintDCExImpl::~wxPaintDCExImpl()
383{
384 // prevent the base class dtor from ReleaseDC()ing it again
385 m_hDC = 0;
386}