]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/dcclient.cpp
missing commit
[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// RCS-ID: $Id$
8// Copyright: (c) Julian Smart
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ===========================================================================
13// declarations
14// ===========================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
27#include "wx/dcclient.h"
28#include "wx/msw/dcclient.h"
29
30#ifndef WX_PRECOMP
31 #include "wx/string.h"
32 #include "wx/hashmap.h"
33 #include "wx/log.h"
34 #include "wx/window.h"
35#endif
36
37#include "wx/msw/private.h"
38
39// ----------------------------------------------------------------------------
40// local data structures
41// ----------------------------------------------------------------------------
42
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.
46class wxPaintDCInfo
47{
48public:
49 wxPaintDCInfo(HDC hdc)
50 : m_hdc(hdc)
51 {
52 }
53
54 // The derived class must perform some cleanup.
55 virtual ~wxPaintDCInfo() = 0;
56
57 WXHDC GetHDC() const { return (WXHDC)m_hdc; }
58
59protected:
60 const HDC m_hdc;
61
62 wxDECLARE_NO_COPY_CLASS(wxPaintDCInfo);
63};
64
65namespace
66{
67
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().
70class wxPaintDCInfoOur : public wxPaintDCInfo
71{
72public:
73 wxPaintDCInfoOur(wxWindow* win)
74 : wxPaintDCInfo(::BeginPaint(GetHwndOf(win), GetPaintStructPtr(m_ps))),
75 m_hwnd(GetHwndOf(win))
76 {
77 }
78
79 virtual ~wxPaintDCInfoOur()
80 {
81 ::EndPaint(m_hwnd, &m_ps);
82 }
83
84private:
85 // This helper is only needed in order to call it from the ctor initializer
86 // list.
87 static PAINTSTRUCT* GetPaintStructPtr(PAINTSTRUCT& ps)
88 {
89 wxZeroMemory(ps);
90 return &ps;
91 }
92
93 const HWND m_hwnd;
94 PAINTSTRUCT m_ps;
95
96 wxDECLARE_NO_COPY_CLASS(wxPaintDCInfoOur);
97};
98
99// This subclass contains information for the HDCs we receive from outside, as
100// WPARAM of WM_PAINT itself.
101class wxPaintDCInfoExternal : public wxPaintDCInfo
102{
103public:
104 wxPaintDCInfoExternal(HDC hdc)
105 : wxPaintDCInfo(hdc),
106 m_state(::SaveDC(hdc))
107 {
108 }
109
110 virtual ~wxPaintDCInfoExternal()
111 {
112 ::RestoreDC(m_hdc, m_state);
113 }
114
115private:
116 const int m_state;
117
118 wxDECLARE_NO_COPY_CLASS(wxPaintDCInfoExternal);
119};
120
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
123// over.
124//
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.
132WX_DECLARE_HASH_MAP(wxWindow *, wxPaintDCInfo *,
133 wxPointerHash, wxPointerEqual,
134 PaintDCInfos);
135
136PaintDCInfos gs_PaintDCInfos;
137
138} // anonymous namespace
139
140// ----------------------------------------------------------------------------
141// global variables
142// ----------------------------------------------------------------------------
143
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
151
152// ===========================================================================
153// implementation
154// ===========================================================================
155
156// ----------------------------------------------------------------------------
157// wxMSWWindowDCImpl
158// ----------------------------------------------------------------------------
159
160IMPLEMENT_ABSTRACT_CLASS(wxWindowDCImpl, wxMSWDCImpl)
161
162wxWindowDCImpl::wxWindowDCImpl( wxDC *owner ) :
163 wxMSWDCImpl( owner )
164{
165}
166
167wxWindowDCImpl::wxWindowDCImpl( wxDC *owner, wxWindow *window ) :
168 wxMSWDCImpl( owner )
169{
170 wxCHECK_RET( window, wxT("invalid window in wxWindowDCImpl") );
171
172 m_window = window;
173 m_hDC = (WXHDC) ::GetWindowDC(GetHwndOf(m_window));
174
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
177 InitDC();
178}
179
180void wxWindowDCImpl::InitDC()
181{
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);
185
186 // since we are a window dc we need to grab the palette from the window
187#if wxUSE_PALETTE
188 InitializePalette();
189#endif
190}
191
192void wxWindowDCImpl::DoGetSize(int *width, int *height) const
193{
194 wxCHECK_RET( m_window, wxT("wxWindowDCImpl without a window?") );
195
196 m_window->GetSize(width, height);
197}
198
199// ----------------------------------------------------------------------------
200// wxClientDCImpl
201// ----------------------------------------------------------------------------
202
203IMPLEMENT_ABSTRACT_CLASS(wxClientDCImpl, wxWindowDCImpl)
204
205wxClientDCImpl::wxClientDCImpl( wxDC *owner ) :
206 wxWindowDCImpl( owner )
207{
208}
209
210wxClientDCImpl::wxClientDCImpl( wxDC *owner, wxWindow *window ) :
211 wxWindowDCImpl( owner )
212{
213 wxCHECK_RET( window, wxT("invalid window in wxClientDCImpl") );
214
215 m_window = window;
216 m_hDC = (WXHDC)::GetDC(GetHwndOf(window));
217
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
220
221 InitDC();
222}
223
224void wxClientDCImpl::InitDC()
225{
226 wxWindowDCImpl::InitDC();
227
228 // in wxUniv build we must manually do some DC adjustments usually
229 // performed by Windows for us
230 //
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 )
237 {
238 // no need to shift DC origin if shift is null
239 SetDeviceOrigin(ptOrigin.x, ptOrigin.y);
240 }
241
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__
246}
247
248wxClientDCImpl::~wxClientDCImpl()
249{
250}
251
252void wxClientDCImpl::DoGetSize(int *width, int *height) const
253{
254 wxCHECK_RET( m_window, wxT("wxClientDCImpl without a window?") );
255
256 m_window->GetClientSize(width, height);
257}
258
259// ----------------------------------------------------------------------------
260// wxPaintDCImpl
261// ----------------------------------------------------------------------------
262
263IMPLEMENT_ABSTRACT_CLASS(wxPaintDCImpl, wxClientDCImpl)
264
265wxPaintDCImpl::wxPaintDCImpl( wxDC *owner ) :
266 wxClientDCImpl( owner )
267{
268}
269
270wxPaintDCImpl::wxPaintDCImpl( wxDC *owner, wxWindow *window ) :
271 wxClientDCImpl( owner )
272{
273 wxCHECK_RET( window, wxT("NULL canvas in wxPaintDCImpl ctor") );
274
275#ifdef wxHAS_PAINT_DEBUG
276 if ( g_isPainting <= 0 )
277 {
278 wxFAIL_MSG( wxT("wxPaintDCImpl may be created only in EVT_PAINT handler!") );
279
280 return;
281 }
282#endif // wxHAS_PAINT_DEBUG
283
284 // see comments in src/msw/window.cpp where this is defined
285 extern bool wxDidCreatePaintDC;
286
287 wxDidCreatePaintDC = true;
288
289
290 m_window = window;
291
292 // do we have a DC for this window in the cache?
293 m_hDC = FindDCInCache(m_window);
294 if ( !m_hDC )
295 {
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();
300 }
301
302 // Note: at this point m_hDC can be NULL under MicroWindows, when dragging.
303 if (!GetHDC())
304 return;
305
306 // (re)set the DC parameters.
307 InitDC();
308
309 // the HDC can have a clipping box (which we didn't set), make sure our
310 // DoGetClippingBox() checks for it
311 m_clipping = true;
312}
313
314wxPaintDCImpl::~wxPaintDCImpl()
315{
316 if ( m_hDC )
317 {
318 SelectOldObjects(m_hDC);
319 m_hDC = 0;
320 }
321}
322
323
324/* static */
325wxPaintDCInfo *wxPaintDCImpl::FindInCache(wxWindow *win)
326{
327 PaintDCInfos::const_iterator it = gs_PaintDCInfos.find( win );
328
329 return it != gs_PaintDCInfos.end() ? it->second : NULL;
330}
331
332/* static */
333WXHDC wxPaintDCImpl::FindDCInCache(wxWindow* win)
334{
335 wxPaintDCInfo* const info = FindInCache(win);
336
337 return info ? info->GetHDC() : 0;
338}
339
340/* static */
341void wxPaintDCImpl::EndPaint(wxWindow *win)
342{
343 wxPaintDCInfo *info = FindInCache(win);
344 if ( info )
345 {
346 gs_PaintDCInfos.erase(win);
347 delete info;
348 }
349}
350
351wxPaintDCInfo::~wxPaintDCInfo()
352{
353}
354
355/*
356 * wxPaintDCEx
357 */
358
359class wxPaintDCExImpl: public wxPaintDCImpl
360{
361public:
362 wxPaintDCExImpl( wxDC *owner, wxWindow *window, WXHDC dc );
363 ~wxPaintDCExImpl();
364};
365
366
367IMPLEMENT_ABSTRACT_CLASS(wxPaintDCEx,wxPaintDC)
368
369wxPaintDCEx::wxPaintDCEx(wxWindow *window, WXHDC dc)
370 : wxPaintDC(new wxPaintDCExImpl(this, window, dc))
371{
372}
373
374wxPaintDCExImpl::wxPaintDCExImpl(wxDC *owner, wxWindow *window, WXHDC dc)
375 : wxPaintDCImpl( owner )
376{
377 wxCHECK_RET( dc, wxT("wxPaintDCEx requires an existing device context") );
378
379 m_window = window;
380 m_hDC = dc;
381}
382
383wxPaintDCExImpl::~wxPaintDCExImpl()
384{
385 // prevent the base class dtor from ReleaseDC()ing it again
386 m_hDC = 0;
387}