1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/dcclient.cpp
3 // Purpose: wxClientDC class
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
27 #include "wx/dcclient.h"
28 #include "wx/msw/dcclient.h"
31 #include "wx/string.h"
32 #include "wx/hashmap.h"
34 #include "wx/window.h"
37 #include "wx/msw/private.h"
39 // ----------------------------------------------------------------------------
40 // local data structures
41 // ----------------------------------------------------------------------------
43 // This is a base class for two concrete subclasses below and contains HDC
44 // cached for the duration of the WM_PAINT processing together with some
45 // bookkeeping information.
49 wxPaintDCInfo(HDC hdc
)
54 // The derived class must perform some cleanup.
55 virtual ~wxPaintDCInfo() = 0;
57 WXHDC
GetHDC() const { return (WXHDC
)m_hdc
; }
62 wxDECLARE_NO_COPY_CLASS(wxPaintDCInfo
);
68 // This subclass contains information for the HDCs we create ourselves, i.e.
69 // those for which we call BeginPaint() -- and hence need to call EndPaint().
70 class wxPaintDCInfoOur
: public wxPaintDCInfo
73 wxPaintDCInfoOur(wxWindow
* win
)
74 : wxPaintDCInfo(::BeginPaint(GetHwndOf(win
), GetPaintStructPtr(m_ps
))),
75 m_hwnd(GetHwndOf(win
))
79 virtual ~wxPaintDCInfoOur()
81 ::EndPaint(m_hwnd
, &m_ps
);
85 // This helper is only needed in order to call it from the ctor initializer
87 static PAINTSTRUCT
* GetPaintStructPtr(PAINTSTRUCT
& ps
)
96 wxDECLARE_NO_COPY_CLASS(wxPaintDCInfoOur
);
99 // This subclass contains information for the HDCs we receive from outside, as
100 // WPARAM of WM_PAINT itself.
101 class wxPaintDCInfoExternal
: public wxPaintDCInfo
104 wxPaintDCInfoExternal(HDC hdc
)
105 : wxPaintDCInfo(hdc
),
106 m_state(::SaveDC(hdc
))
110 virtual ~wxPaintDCInfoExternal()
112 ::RestoreDC(m_hdc
, m_state
);
118 wxDECLARE_NO_COPY_CLASS(wxPaintDCInfoExternal
);
121 // The global map containing HDC to use for the given window. The entries in
122 // this map only exist during WM_PAINT processing and are destroyed when it is
125 // It is needed because in some circumstances it can happen that more than one
126 // wxPaintDC is created for the same window during its WM_PAINT handling (and
127 // as this can happen implicitly, e.g. by calling a function in some library,
128 // this can be quite difficult to find) but we need to reuse the same HDC for
129 // all of them because we can't call BeginPaint() more than once. So we cache
130 // the first HDC created for the window in this map and then reuse it later if
131 // needed. And, of course, remove it from the map when the painting is done.
132 WX_DECLARE_HASH_MAP(wxWindow
*, wxPaintDCInfo
*,
133 wxPointerHash
, wxPointerEqual
,
136 PaintDCInfos gs_PaintDCInfos
;
138 } // anonymous namespace
140 // ----------------------------------------------------------------------------
142 // ----------------------------------------------------------------------------
144 #ifdef wxHAS_PAINT_DEBUG
145 // a global variable which we check to verify that wxPaintDC are only
146 // created in response to WM_PAINT message - doing this from elsewhere is a
147 // common programming error among wxWidgets programmers and might lead to
148 // very subtle and difficult to debug refresh/repaint bugs.
149 int g_isPainting
= 0;
150 #endif // wxHAS_PAINT_DEBUG
152 // ===========================================================================
154 // ===========================================================================
156 // ----------------------------------------------------------------------------
158 // ----------------------------------------------------------------------------
160 IMPLEMENT_ABSTRACT_CLASS(wxWindowDCImpl
, wxMSWDCImpl
)
162 wxWindowDCImpl::wxWindowDCImpl( wxDC
*owner
) :
167 wxWindowDCImpl::wxWindowDCImpl( wxDC
*owner
, wxWindow
*window
) :
170 wxCHECK_RET( window
, wxT("invalid window in wxWindowDCImpl") );
173 m_hDC
= (WXHDC
) ::GetWindowDC(GetHwndOf(m_window
));
175 // m_bOwnsDC was already set to false in the base class ctor, so the DC
176 // will be released (and not deleted) in ~wxDC
180 void wxWindowDCImpl::InitDC()
182 // the background mode is only used for text background and is set in
183 // DrawText() to OPAQUE as required, otherwise always TRANSPARENT,
184 ::SetBkMode(GetHdc(), TRANSPARENT
);
186 // since we are a window dc we need to grab the palette from the window
192 void wxWindowDCImpl::DoGetSize(int *width
, int *height
) const
194 wxCHECK_RET( m_window
, wxT("wxWindowDCImpl without a window?") );
196 m_window
->GetSize(width
, height
);
199 // ----------------------------------------------------------------------------
201 // ----------------------------------------------------------------------------
203 IMPLEMENT_ABSTRACT_CLASS(wxClientDCImpl
, wxWindowDCImpl
)
205 wxClientDCImpl::wxClientDCImpl( wxDC
*owner
) :
206 wxWindowDCImpl( owner
)
210 wxClientDCImpl::wxClientDCImpl( wxDC
*owner
, wxWindow
*window
) :
211 wxWindowDCImpl( owner
)
213 wxCHECK_RET( window
, wxT("invalid window in wxClientDCImpl") );
216 m_hDC
= (WXHDC
)::GetDC(GetHwndOf(window
));
218 // m_bOwnsDC was already set to false in the base class ctor, so the DC
219 // will be released (and not deleted) in ~wxDC
224 void wxClientDCImpl::InitDC()
226 wxWindowDCImpl::InitDC();
228 // in wxUniv build we must manually do some DC adjustments usually
229 // performed by Windows for us
231 // we also need to take the menu/toolbar manually into account under
232 // Windows CE because they're just another control there, not anything
233 // special as usually under Windows
234 #if defined(__WXUNIVERSAL__) || defined(__WXWINCE__)
235 wxPoint ptOrigin
= m_window
->GetClientAreaOrigin();
236 if ( ptOrigin
.x
|| ptOrigin
.y
)
238 // no need to shift DC origin if shift is null
239 SetDeviceOrigin(ptOrigin
.x
, ptOrigin
.y
);
242 // clip the DC to avoid overwriting the non client area
243 wxSize size
= m_window
->GetClientSize();
244 DoSetClippingRegion(0, 0, size
.x
, size
.y
);
245 #endif // __WXUNIVERSAL__ || __WXWINCE__
248 wxClientDCImpl::~wxClientDCImpl()
252 void wxClientDCImpl::DoGetSize(int *width
, int *height
) const
254 wxCHECK_RET( m_window
, wxT("wxClientDCImpl without a window?") );
256 m_window
->GetClientSize(width
, height
);
259 // ----------------------------------------------------------------------------
261 // ----------------------------------------------------------------------------
263 IMPLEMENT_ABSTRACT_CLASS(wxPaintDCImpl
, wxClientDCImpl
)
265 wxPaintDCImpl::wxPaintDCImpl( wxDC
*owner
) :
266 wxClientDCImpl( owner
)
270 wxPaintDCImpl::wxPaintDCImpl( wxDC
*owner
, wxWindow
*window
) :
271 wxClientDCImpl( owner
)
273 wxCHECK_RET( window
, wxT("NULL canvas in wxPaintDCImpl ctor") );
275 #ifdef wxHAS_PAINT_DEBUG
276 if ( g_isPainting
<= 0 )
278 wxFAIL_MSG( wxT("wxPaintDCImpl may be created only in EVT_PAINT handler!") );
282 #endif // wxHAS_PAINT_DEBUG
284 // see comments in src/msw/window.cpp where this is defined
285 extern bool wxDidCreatePaintDC
;
287 wxDidCreatePaintDC
= true;
292 // do we have a DC for this window in the cache?
293 m_hDC
= FindDCInCache(m_window
);
296 // not in cache, create a new one
297 wxPaintDCInfoOur
* const info
= new wxPaintDCInfoOur(m_window
);
298 gs_PaintDCInfos
[m_window
] = info
;
299 m_hDC
= info
->GetHDC();
302 // Note: at this point m_hDC can be NULL under MicroWindows, when dragging.
306 // (re)set the DC parameters.
309 // the HDC can have a clipping box (which we didn't set), make sure our
310 // DoGetClippingBox() checks for it
314 wxPaintDCImpl::~wxPaintDCImpl()
318 SelectOldObjects(m_hDC
);
325 wxPaintDCInfo
*wxPaintDCImpl::FindInCache(wxWindow
*win
)
327 PaintDCInfos::const_iterator it
= gs_PaintDCInfos
.find( win
);
329 return it
!= gs_PaintDCInfos
.end() ? it
->second
: NULL
;
333 WXHDC
wxPaintDCImpl::FindDCInCache(wxWindow
* win
)
335 wxPaintDCInfo
* const info
= FindInCache(win
);
337 return info
? info
->GetHDC() : 0;
341 void wxPaintDCImpl::EndPaint(wxWindow
*win
)
343 wxPaintDCInfo
*info
= FindInCache(win
);
346 gs_PaintDCInfos
.erase(win
);
351 wxPaintDCInfo::~wxPaintDCInfo()
359 class wxPaintDCExImpl
: public wxPaintDCImpl
362 wxPaintDCExImpl( wxDC
*owner
, wxWindow
*window
, WXHDC dc
);
367 IMPLEMENT_ABSTRACT_CLASS(wxPaintDCEx
,wxPaintDC
)
369 wxPaintDCEx::wxPaintDCEx(wxWindow
*window
, WXHDC dc
)
370 : wxPaintDC(new wxPaintDCExImpl(this, window
, dc
))
374 wxPaintDCExImpl::wxPaintDCExImpl(wxDC
*owner
, wxWindow
*window
, WXHDC dc
)
375 : wxPaintDCImpl( owner
)
377 wxCHECK_RET( dc
, wxT("wxPaintDCEx requires an existing device context") );
381 m_hDC
= FindDCInCache(m_window
);
384 // not in cache, record it there
385 gs_PaintDCInfos
[m_window
] = new wxPaintDCInfoExternal(dc
);
391 wxPaintDCExImpl::~wxPaintDCExImpl()
393 // prevent the base class dtor from ReleaseDC()ing it again