]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dcclient.cpp
Fix asserts when removing the menu item starting radio group in wxOSX.
[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"
e4db172a 32 #include "wx/log.h"
cdccdfab 33 #include "wx/window.h"
df91131c
WS
34#endif
35
c6eba8f8
VZ
36#include "wx/msw/private.h"
37
3a5ffa81
VZ
38// ----------------------------------------------------------------------------
39// array/list types
40// ----------------------------------------------------------------------------
41
42struct WXDLLEXPORT wxPaintDCInfo
43{
888dde65 44 wxPaintDCInfo(wxWindow *win, wxPaintDCImpl *dc)
3a5ffa81
VZ
45 {
46 hwnd = win->GetHWND();
47 hdc = dc->GetHDC();
48 count = 1;
49 }
50
51 WXHWND hwnd; // window for this DC
52 WXHDC hdc; // the DC handle
53 size_t count; // usage count
54};
55
56#include "wx/arrimpl.cpp"
57
259c43f6 58WX_DEFINE_OBJARRAY(wxArrayDCInfo)
3a5ffa81 59
c6eba8f8
VZ
60// ----------------------------------------------------------------------------
61// macros
62// ----------------------------------------------------------------------------
2bda0e17 63
c6eba8f8
VZ
64// ----------------------------------------------------------------------------
65// global variables
66// ----------------------------------------------------------------------------
67
68static PAINTSTRUCT g_paintStruct;
69
657a8a35 70#ifdef wxHAS_PAINT_DEBUG
c6eba8f8 71 // a global variable which we check to verify that wxPaintDC are only
a0d9c6cb 72 // created in response to WM_PAINT message - doing this from elsewhere is a
77ffb593 73 // common programming error among wxWidgets programmers and might lead to
c6eba8f8 74 // very subtle and difficult to debug refresh/repaint bugs.
edccf428 75 int g_isPainting = 0;
657a8a35 76#endif // wxHAS_PAINT_DEBUG
c6eba8f8
VZ
77
78// ===========================================================================
79// implementation
80// ===========================================================================
e6460682 81
c6eba8f8 82// ----------------------------------------------------------------------------
888dde65 83// wxMSWWindowDCImpl
c6eba8f8
VZ
84// ----------------------------------------------------------------------------
85
888dde65
RR
86IMPLEMENT_ABSTRACT_CLASS(wxWindowDCImpl, wxMSWDCImpl)
87
88wxWindowDCImpl::wxWindowDCImpl( wxDC *owner ) :
89 wxMSWDCImpl( owner )
2bda0e17 90{
2bda0e17
KB
91}
92
f0875501 93wxWindowDCImpl::wxWindowDCImpl( wxDC *owner, wxWindow *window ) :
888dde65 94 wxMSWDCImpl( owner )
2bda0e17 95{
9a83f860 96 wxCHECK_RET( window, wxT("invalid window in wxWindowDCImpl") );
a91b47e8 97
888dde65
RR
98 m_window = window;
99 m_hDC = (WXHDC) ::GetWindowDC(GetHwndOf(m_window));
2bda0e17 100
7ba4fbeb
VZ
101 // m_bOwnsDC was already set to false in the base class ctor, so the DC
102 // will be released (and not deleted) in ~wxDC
7ba4fbeb
VZ
103 InitDC();
104}
edccf428 105
888dde65 106void wxWindowDCImpl::InitDC()
7ba4fbeb
VZ
107{
108 // the background mode is only used for text background and is set in
109 // DrawText() to OPAQUE as required, otherwise always TRANSPARENT,
110 ::SetBkMode(GetHdc(), TRANSPARENT);
c6eba8f8 111
574c939e
KB
112 // since we are a window dc we need to grab the palette from the window
113#if wxUSE_PALETTE
114 InitializePalette();
115#endif
2bda0e17
KB
116}
117
888dde65 118void wxWindowDCImpl::DoGetSize(int *width, int *height) const
994a3786 119{
9a83f860 120 wxCHECK_RET( m_window, wxT("wxWindowDCImpl without a window?") );
994a3786 121
888dde65 122 m_window->GetSize(width, height);
994a3786
VZ
123}
124
c6eba8f8 125// ----------------------------------------------------------------------------
888dde65 126// wxClientDCImpl
c6eba8f8 127// ----------------------------------------------------------------------------
e6460682 128
888dde65
RR
129IMPLEMENT_ABSTRACT_CLASS(wxClientDCImpl, wxWindowDCImpl)
130
131wxClientDCImpl::wxClientDCImpl( wxDC *owner ) :
132 wxWindowDCImpl( owner )
2bda0e17 133{
2bda0e17
KB
134}
135
888dde65
RR
136wxClientDCImpl::wxClientDCImpl( wxDC *owner, wxWindow *window ) :
137 wxWindowDCImpl( owner )
2bda0e17 138{
9a83f860 139 wxCHECK_RET( window, wxT("invalid window in wxClientDCImpl") );
a91b47e8 140
888dde65
RR
141 m_window = window;
142 m_hDC = (WXHDC)::GetDC(GetHwndOf(window));
2bda0e17 143
7ba4fbeb
VZ
144 // m_bOwnsDC was already set to false in the base class ctor, so the DC
145 // will be released (and not deleted) in ~wxDC
2bda0e17 146
7ba4fbeb 147 InitDC();
2bda0e17
KB
148}
149
888dde65 150void wxClientDCImpl::InitDC()
1e6feb95 151{
888dde65 152 wxWindowDCImpl::InitDC();
1e6feb95
VZ
153
154 // in wxUniv build we must manually do some DC adjustments usually
155 // performed by Windows for us
1fa6ebf7
VZ
156 //
157 // we also need to take the menu/toolbar manually into account under
158 // Windows CE because they're just another control there, not anything
159 // special as usually under Windows
160#if defined(__WXUNIVERSAL__) || defined(__WXWINCE__)
888dde65 161 wxPoint ptOrigin = m_window->GetClientAreaOrigin();
1e6feb95
VZ
162 if ( ptOrigin.x || ptOrigin.y )
163 {
164 // no need to shift DC origin if shift is null
165 SetDeviceOrigin(ptOrigin.x, ptOrigin.y);
166 }
167
168 // clip the DC to avoid overwriting the non client area
c7d6c563
VS
169 wxSize size = m_window->GetClientSize();
170 DoSetClippingRegion(0, 0, size.x, size.y);
1fa6ebf7 171#endif // __WXUNIVERSAL__ || __WXWINCE__
1e6feb95
VZ
172}
173
888dde65 174wxClientDCImpl::~wxClientDCImpl()
1e6feb95
VZ
175{
176}
177
888dde65 178void wxClientDCImpl::DoGetSize(int *width, int *height) const
994a3786 179{
9a83f860 180 wxCHECK_RET( m_window, wxT("wxClientDCImpl without a window?") );
994a3786 181
888dde65 182 m_window->GetClientSize(width, height);
994a3786
VZ
183}
184
c6eba8f8 185// ----------------------------------------------------------------------------
888dde65 186// wxPaintDCImpl
c6eba8f8 187// ----------------------------------------------------------------------------
e6460682 188
3a5ffa81 189// VZ: initial implementation (by JACS) only remembered the last wxPaintDC
7ba4fbeb 190// created and tried to reuse it - this was supposed to take care of a
3a5ffa81
VZ
191// situation when a derived class OnPaint() calls base class OnPaint()
192// because in this case ::BeginPaint() shouldn't be called second time.
193//
194// I'm not sure how useful this is, however we must remember the HWND
195// associated with the last HDC as well - otherwise we may (and will!) try
196// to reuse the HDC for another HWND which is a nice recipe for disaster.
197//
198// So we store a list of windows for which we already have the DC and not
199// just one single hDC. This seems to work, but I'm really not sure about
200// the usefullness of the whole idea - IMHO it's much better to not call
85833f5c 201// base class OnPaint() at all, or, if we really want to allow it, add a
3a5ffa81
VZ
202// "wxPaintDC *" parameter to wxPaintEvent which should be used if it's
203// !NULL instead of creating a new DC.
204
888dde65 205IMPLEMENT_ABSTRACT_CLASS(wxPaintDCImpl, wxClientDCImpl)
2bda0e17 206
888dde65
RR
207wxArrayDCInfo wxPaintDCImpl::ms_cache;
208
209wxPaintDCImpl::wxPaintDCImpl( wxDC *owner ) :
210 wxClientDCImpl( owner )
c6eba8f8 211{
c6eba8f8
VZ
212}
213
888dde65
RR
214wxPaintDCImpl::wxPaintDCImpl( wxDC *owner, wxWindow *window ) :
215 wxClientDCImpl( owner )
2bda0e17 216{
888dde65 217 wxCHECK_RET( window, wxT("NULL canvas in wxPaintDCImpl ctor") );
3a5ffa81 218
657a8a35 219#ifdef wxHAS_PAINT_DEBUG
edccf428 220 if ( g_isPainting <= 0 )
3a5ffa81 221 {
888dde65 222 wxFAIL_MSG( wxT("wxPaintDCImpl may be created only in EVT_PAINT handler!") );
2bda0e17 223
3a5ffa81
VZ
224 return;
225 }
4b6a582b 226#endif // wxHAS_PAINT_DEBUG
c6eba8f8 227
4877e9bf
VZ
228 // see comments in src/msw/window.cpp where this is defined
229 extern bool wxDidCreatePaintDC;
230
231 wxDidCreatePaintDC = true;
232
233
888dde65 234 m_window = window;
83626bfa 235
3a5ffa81
VZ
236 // do we have a DC for this window in the cache?
237 wxPaintDCInfo *info = FindInCache();
238 if ( info )
239 {
240 m_hDC = info->hdc;
241 info->count++;
242 }
243 else // not in cache, create a new one
244 {
888dde65 245 m_hDC = (WXHDC)::BeginPaint(GetHwndOf(m_window), &g_paintStruct);
1fa6ebf7 246 if (m_hDC)
888dde65 247 ms_cache.Add(new wxPaintDCInfo(m_window, this));
3a5ffa81 248 }
a91b47e8 249
5adad466 250 // Note: at this point m_hDC can be NULL under MicroWindows, when dragging.
27539df8
VZ
251 if (!GetHDC())
252 return;
253
254 // (re)set the DC parameters.
255 InitDC();
256
257 // the HDC can have a clipping box (which we didn't set), make sure our
258 // DoGetClippingBox() checks for it
e9f8a82e 259 m_clipping = true;
2bda0e17
KB
260}
261
888dde65 262wxPaintDCImpl::~wxPaintDCImpl()
2bda0e17 263{
3a5ffa81
VZ
264 if ( m_hDC )
265 {
edccf428
VZ
266 SelectOldObjects(m_hDC);
267
3a5ffa81
VZ
268 size_t index;
269 wxPaintDCInfo *info = FindInCache(&index);
270
223d09f6 271 wxCHECK_RET( info, wxT("existing DC should have a cache entry") );
3a5ffa81 272
8d7eaf91 273 if ( --info->count == 0 )
3a5ffa81 274 {
888dde65 275 ::EndPaint(GetHwndOf(m_window), &g_paintStruct);
3a5ffa81 276
b54e41c5 277 ms_cache.RemoveAt(index);
2bc1aa11
JS
278
279 // Reduce the number of bogus reports of non-freed memory
280 // at app exit
281 if (ms_cache.IsEmpty())
282 ms_cache.Clear();
3a5ffa81
VZ
283 }
284 //else: cached DC entry is still in use
edccf428
VZ
285
286 // prevent the base class dtor from ReleaseDC()ing it again
287 m_hDC = 0;
1c089c47 288 }
2bda0e17 289}
81d66cf3 290
888dde65 291wxPaintDCInfo *wxPaintDCImpl::FindInCache(size_t *index) const
3a5ffa81
VZ
292{
293 wxPaintDCInfo *info = NULL;
294 size_t nCache = ms_cache.GetCount();
295 for ( size_t n = 0; n < nCache; n++ )
296 {
968bed8c 297 wxPaintDCInfo *info1 = &ms_cache[n];
888dde65 298 if ( info1->hwnd == m_window->GetHWND() )
3a5ffa81 299 {
968bed8c 300 info = info1;
3a5ffa81
VZ
301 if ( index )
302 *index = n;
303 break;
304 }
305 }
306
307 return info;
308}
63da7df7
JS
309
310// find the entry for this DC in the cache (keyed by the window)
888dde65 311WXHDC wxPaintDCImpl::FindDCInCache(wxWindow* win)
63da7df7 312{
63da7df7
JS
313 size_t nCache = ms_cache.GetCount();
314 for ( size_t n = 0; n < nCache; n++ )
315 {
999836aa 316 wxPaintDCInfo *info = &ms_cache[n];
63da7df7
JS
317 if ( info->hwnd == win->GetHWND() )
318 {
319 return info->hdc;
320 }
321 }
322 return 0;
323}
324
c6151f2a
JS
325/*
326 * wxPaintDCEx
327 */
d71cc120 328
888dde65 329// TODO: don't duplicate wxPaintDCImpl code here!!
fbaf7d14 330
888dde65 331class wxPaintDCExImpl: public wxPaintDCImpl
c6151f2a 332{
888dde65
RR
333public:
334 wxPaintDCExImpl( wxDC *owner, wxWindow *window, WXHDC dc );
335 ~wxPaintDCExImpl();
f0875501 336
888dde65
RR
337 int m_saveState;
338};
c6151f2a 339
c6151f2a 340
888dde65
RR
341IMPLEMENT_ABSTRACT_CLASS(wxPaintDCEx,wxPaintDC)
342
f0875501
VZ
343wxPaintDCEx::wxPaintDCEx(wxWindow *window, WXHDC dc)
344 : wxPaintDC(new wxPaintDCExImpl(this, window, dc))
888dde65 345{
c6151f2a
JS
346}
347
f0875501
VZ
348wxPaintDCExImpl::wxPaintDCExImpl(wxDC *owner, wxWindow *window, WXHDC dc)
349 : wxPaintDCImpl( owner )
c6151f2a 350{
888dde65 351 wxCHECK_RET( dc, wxT("wxPaintDCEx requires an existing device context") );
c6151f2a 352
888dde65 353 m_saveState = 0;
f0875501 354
888dde65 355 m_window = window;
c6151f2a 356
888dde65
RR
357 wxPaintDCInfo *info = FindInCache();
358 if ( info )
359 {
360 m_hDC = info->hdc;
361 info->count++;
362 }
363 else // not in cache, create a new one
364 {
365 m_hDC = dc;
366 ms_cache.Add(new wxPaintDCInfo(m_window, this));
367 m_saveState = SaveDC((HDC) dc);
368 }
369}
c6151f2a 370
888dde65
RR
371wxPaintDCExImpl::~wxPaintDCExImpl()
372{
373 size_t index;
374 wxPaintDCInfo *info = FindInCache(&index);
375
376 wxCHECK_RET( info, wxT("existing DC should have a cache entry") );
c6151f2a 377
888dde65
RR
378 if ( --info->count == 0 )
379 {
380 RestoreDC((HDC) m_hDC, m_saveState);
381 ms_cache.RemoveAt(index);
382
383 // Reduce the number of bogus reports of non-freed memory
384 // at app exit
385 if (ms_cache.IsEmpty())
386 ms_cache.Clear();
387 }
388 //else: cached DC entry is still in use
389
390 // prevent the base class dtor from ReleaseDC()ing it again
391 m_hDC = 0;
c6151f2a 392}
888dde65
RR
393
394