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