1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/dcclient.cpp
3 // Purpose: wxClientDC class
4 // Author: Julian Smart
7 // Copyright: (c) Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // ===========================================================================
13 // ===========================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
26 #include "wx/dcclient.h"
27 #include "wx/msw/dcclient.h"
30 #include "wx/string.h"
31 #include "wx/hashmap.h"
33 #include "wx/window.h"
36 #include "wx/msw/private.h"
38 // ----------------------------------------------------------------------------
39 // local data structures
40 // ----------------------------------------------------------------------------
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.
48 wxPaintDCInfo(HDC hdc
)
53 // The derived class must perform some cleanup.
54 virtual ~wxPaintDCInfo() = 0;
56 WXHDC
GetHDC() const { return (WXHDC
)m_hdc
; }
61 wxDECLARE_NO_COPY_CLASS(wxPaintDCInfo
);
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().
69 class wxPaintDCInfoOur
: public wxPaintDCInfo
72 wxPaintDCInfoOur(wxWindow
* win
)
73 : wxPaintDCInfo(::BeginPaint(GetHwndOf(win
), GetPaintStructPtr(m_ps
))),
74 m_hwnd(GetHwndOf(win
))
78 virtual ~wxPaintDCInfoOur()
80 ::EndPaint(m_hwnd
, &m_ps
);
84 // This helper is only needed in order to call it from the ctor initializer
86 static PAINTSTRUCT
* GetPaintStructPtr(PAINTSTRUCT
& ps
)
95 wxDECLARE_NO_COPY_CLASS(wxPaintDCInfoOur
);
98 // This subclass contains information for the HDCs we receive from outside, as
99 // WPARAM of WM_PAINT itself.
100 class wxPaintDCInfoExternal
: public wxPaintDCInfo
103 wxPaintDCInfoExternal(HDC hdc
)
104 : wxPaintDCInfo(hdc
),
105 m_state(::SaveDC(hdc
))
109 virtual ~wxPaintDCInfoExternal()
111 ::RestoreDC(m_hdc
, m_state
);
117 wxDECLARE_NO_COPY_CLASS(wxPaintDCInfoExternal
);
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
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.
131 WX_DECLARE_HASH_MAP(wxWindow
*, wxPaintDCInfo
*,
132 wxPointerHash
, wxPointerEqual
,
135 PaintDCInfos gs_PaintDCInfos
;
137 } // anonymous namespace
139 // ----------------------------------------------------------------------------
141 // ----------------------------------------------------------------------------
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
151 // ===========================================================================
153 // ===========================================================================
155 // ----------------------------------------------------------------------------
157 // ----------------------------------------------------------------------------
159 IMPLEMENT_ABSTRACT_CLASS(wxWindowDCImpl
, wxMSWDCImpl
)
161 wxWindowDCImpl::wxWindowDCImpl( wxDC
*owner
) :
166 wxWindowDCImpl::wxWindowDCImpl( wxDC
*owner
, wxWindow
*window
) :
169 wxCHECK_RET( window
, wxT("invalid window in wxWindowDCImpl") );
172 m_hDC
= (WXHDC
) ::GetWindowDC(GetHwndOf(m_window
));
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
179 void wxWindowDCImpl::InitDC()
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
);
185 // since we are a window dc we need to grab the palette from the window
191 void wxWindowDCImpl::DoGetSize(int *width
, int *height
) const
193 wxCHECK_RET( m_window
, wxT("wxWindowDCImpl without a window?") );
195 m_window
->GetSize(width
, height
);
198 // ----------------------------------------------------------------------------
200 // ----------------------------------------------------------------------------
202 IMPLEMENT_ABSTRACT_CLASS(wxClientDCImpl
, wxWindowDCImpl
)
204 wxClientDCImpl::wxClientDCImpl( wxDC
*owner
) :
205 wxWindowDCImpl( owner
)
209 wxClientDCImpl::wxClientDCImpl( wxDC
*owner
, wxWindow
*window
) :
210 wxWindowDCImpl( owner
)
212 wxCHECK_RET( window
, wxT("invalid window in wxClientDCImpl") );
215 m_hDC
= (WXHDC
)::GetDC(GetHwndOf(window
));
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
223 void wxClientDCImpl::InitDC()
225 wxWindowDCImpl::InitDC();
227 // in wxUniv build we must manually do some DC adjustments usually
228 // performed by Windows for us
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
)
237 // no need to shift DC origin if shift is null
238 SetDeviceOrigin(ptOrigin
.x
, ptOrigin
.y
);
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__
247 wxClientDCImpl::~wxClientDCImpl()
251 void wxClientDCImpl::DoGetSize(int *width
, int *height
) const
253 wxCHECK_RET( m_window
, wxT("wxClientDCImpl without a window?") );
255 m_window
->GetClientSize(width
, height
);
258 // ----------------------------------------------------------------------------
260 // ----------------------------------------------------------------------------
262 IMPLEMENT_ABSTRACT_CLASS(wxPaintDCImpl
, wxClientDCImpl
)
264 wxPaintDCImpl::wxPaintDCImpl( wxDC
*owner
) :
265 wxClientDCImpl( owner
)
269 wxPaintDCImpl::wxPaintDCImpl( wxDC
*owner
, wxWindow
*window
) :
270 wxClientDCImpl( owner
)
272 wxCHECK_RET( window
, wxT("NULL canvas in wxPaintDCImpl ctor") );
274 #ifdef wxHAS_PAINT_DEBUG
275 if ( g_isPainting
<= 0 )
277 wxFAIL_MSG( wxT("wxPaintDCImpl may be created only in EVT_PAINT handler!") );
281 #endif // wxHAS_PAINT_DEBUG
283 // see comments in src/msw/window.cpp where this is defined
284 extern bool wxDidCreatePaintDC
;
286 wxDidCreatePaintDC
= true;
291 // do we have a DC for this window in the cache?
292 m_hDC
= FindDCInCache(m_window
);
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();
301 // Note: at this point m_hDC can be NULL under MicroWindows, when dragging.
305 // (re)set the DC parameters.
308 // the HDC can have a clipping box (which we didn't set), make sure our
309 // DoGetClippingBox() checks for it
313 wxPaintDCImpl::~wxPaintDCImpl()
317 SelectOldObjects(m_hDC
);
324 wxPaintDCInfo
*wxPaintDCImpl::FindInCache(wxWindow
*win
)
326 PaintDCInfos::const_iterator it
= gs_PaintDCInfos
.find( win
);
328 return it
!= gs_PaintDCInfos
.end() ? it
->second
: NULL
;
332 WXHDC
wxPaintDCImpl::FindDCInCache(wxWindow
* win
)
334 wxPaintDCInfo
* const info
= FindInCache(win
);
336 return info
? info
->GetHDC() : 0;
340 void wxPaintDCImpl::EndPaint(wxWindow
*win
)
342 wxPaintDCInfo
*info
= FindInCache(win
);
345 gs_PaintDCInfos
.erase(win
);
350 wxPaintDCInfo::~wxPaintDCInfo()
358 class wxPaintDCExImpl
: public wxPaintDCImpl
361 wxPaintDCExImpl( wxDC
*owner
, wxWindow
*window
, WXHDC dc
);
366 IMPLEMENT_ABSTRACT_CLASS(wxPaintDCEx
,wxPaintDC
)
368 wxPaintDCEx::wxPaintDCEx(wxWindow
*window
, WXHDC dc
)
369 : wxPaintDC(new wxPaintDCExImpl(this, window
, dc
))
373 wxPaintDCExImpl::wxPaintDCExImpl(wxDC
*owner
, wxWindow
*window
, WXHDC dc
)
374 : wxPaintDCImpl( owner
)
376 wxCHECK_RET( dc
, wxT("wxPaintDCEx requires an existing device context") );
382 wxPaintDCExImpl::~wxPaintDCExImpl()
384 // prevent the base class dtor from ReleaseDC()ing it again