]> git.saurik.com Git - wxWidgets.git/blob - src/msw/dcclient.cpp
Frame and Window coding
[wxWidgets.git] / src / msw / dcclient.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: 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 and Markus Holzem
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "dcclient.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #include "wx/string.h"
32 #include "wx/log.h"
33 #include "wx/window.h"
34
35 #include "wx/msw/private.h"
36
37 #include "wx/dcclient.h"
38
39 // ----------------------------------------------------------------------------
40 // array/list types
41 // ----------------------------------------------------------------------------
42
43 struct WXDLLEXPORT wxPaintDCInfo
44 {
45 wxPaintDCInfo(wxWindow *win, wxDC *dc)
46 {
47 hwnd = win->GetHWND();
48 hdc = dc->GetHDC();
49 count = 1;
50 }
51
52 WXHWND hwnd; // window for this DC
53 WXHDC hdc; // the DC handle
54 size_t count; // usage count
55 };
56
57 #include "wx/arrimpl.cpp"
58
59 WX_DEFINE_OBJARRAY(wxArrayDCInfo);
60
61 // ----------------------------------------------------------------------------
62 // macros
63 // ----------------------------------------------------------------------------
64
65 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
66 IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
67 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxWindowDC)
68
69 // ----------------------------------------------------------------------------
70 // global variables
71 // ----------------------------------------------------------------------------
72
73 static PAINTSTRUCT g_paintStruct;
74
75 #ifdef __WXDEBUG__
76 // a global variable which we check to verify that wxPaintDC are only
77 // created in resopnse to WM_PAINT message - doing this from elsewhere is a
78 // common programming error among wxWindows programmers and might lead to
79 // very subtle and difficult to debug refresh/repaint bugs.
80 int g_isPainting = 0;
81 #endif // __WXDEBUG__
82
83 // ===========================================================================
84 // implementation
85 // ===========================================================================
86
87 // ----------------------------------------------------------------------------
88 // wxWindowDC
89 // ----------------------------------------------------------------------------
90
91 wxWindowDC::wxWindowDC()
92 {
93 m_canvas = NULL;
94 }
95
96 wxWindowDC::wxWindowDC(wxWindow *the_canvas)
97 {
98 m_canvas = the_canvas;
99 m_hDC = (WXHDC) ::GetWindowDC(GetWinHwnd(the_canvas) );
100 m_hDCCount++;
101
102 SetBackground(wxBrush(m_canvas->GetBackgroundColour(), wxSOLID));
103 }
104
105 wxWindowDC::~wxWindowDC()
106 {
107 if (m_canvas && m_hDC)
108 {
109 SelectOldObjects(m_hDC);
110
111 if ( !::ReleaseDC(GetWinHwnd(m_canvas), GetHdc()) )
112 {
113 wxLogLastError("ReleaseDC");
114 }
115
116 m_hDC = 0;
117 }
118
119 m_hDCCount--;
120 }
121
122 // ----------------------------------------------------------------------------
123 // wxClientDC
124 // ----------------------------------------------------------------------------
125
126 wxClientDC::wxClientDC()
127 {
128 m_canvas = NULL;
129 }
130
131 wxClientDC::wxClientDC(wxWindow *the_canvas)
132 {
133 m_canvas = the_canvas;
134 m_hDC = (WXHDC) ::GetDC(GetWinHwnd(the_canvas));
135
136 // the background mode is only used for text background
137 // and is set in DrawText() to OPAQUE as required, other-
138 // wise always TRANSPARENT, RR
139 ::SetBkMode( GetHdc(), TRANSPARENT );
140
141 SetBackground(wxBrush(m_canvas->GetBackgroundColour(), wxSOLID));
142 }
143
144 wxClientDC::~wxClientDC()
145 {
146 if ( m_canvas && GetHdc() )
147 {
148 SelectOldObjects(m_hDC);
149
150 ::ReleaseDC(GetWinHwnd(m_canvas), GetHdc());
151 m_hDC = 0;
152 }
153 }
154
155 // ----------------------------------------------------------------------------
156 // wxPaintDC
157 // ----------------------------------------------------------------------------
158
159 // VZ: initial implementation (by JACS) only remembered the last wxPaintDC
160 // created and tried to reuse - this was supposed to take care of a
161 // situation when a derived class OnPaint() calls base class OnPaint()
162 // because in this case ::BeginPaint() shouldn't be called second time.
163 //
164 // I'm not sure how useful this is, however we must remember the HWND
165 // associated with the last HDC as well - otherwise we may (and will!) try
166 // to reuse the HDC for another HWND which is a nice recipe for disaster.
167 //
168 // So we store a list of windows for which we already have the DC and not
169 // just one single hDC. This seems to work, but I'm really not sure about
170 // the usefullness of the whole idea - IMHO it's much better to not call
171 // base class OnPaint() at all, or, if we really want to allow it, add a
172 // "wxPaintDC *" parameter to wxPaintEvent which should be used if it's
173 // !NULL instead of creating a new DC.
174
175 wxArrayDCInfo wxPaintDC::ms_cache;
176
177 wxPaintDC::wxPaintDC()
178 {
179 m_canvas = NULL;
180 m_hDC = 0;
181 }
182
183 wxPaintDC::wxPaintDC(wxWindow *canvas)
184 {
185 wxCHECK_RET( canvas, wxT("NULL canvas in wxPaintDC ctor") );
186
187 #ifdef __WXDEBUG__
188 if ( g_isPainting <= 0 )
189 {
190 wxFAIL_MSG( wxT("wxPaintDC may be created only in EVT_PAINT handler!") );
191
192 return;
193 }
194 #endif // __WXDEBUG__
195
196 m_canvas = canvas;
197
198 // do we have a DC for this window in the cache?
199 wxPaintDCInfo *info = FindInCache();
200 if ( info )
201 {
202 m_hDC = info->hdc;
203 info->count++;
204 }
205 else // not in cache, create a new one
206 {
207 m_hDC = (WXHDC)::BeginPaint(GetWinHwnd(m_canvas), &g_paintStruct);
208 ms_cache.Add(new wxPaintDCInfo(m_canvas, this));
209 }
210
211 // the background mode is only used for text background
212 // and is set in DrawText() to OPAQUE as required, other-
213 // wise always TRANSPARENT, RR
214 ::SetBkMode( GetHdc(), TRANSPARENT );
215
216 SetBackground(wxBrush(m_canvas->GetBackgroundColour(), wxSOLID));
217 }
218
219 wxPaintDC::~wxPaintDC()
220 {
221 if ( m_hDC )
222 {
223 SelectOldObjects(m_hDC);
224
225 size_t index;
226 wxPaintDCInfo *info = FindInCache(&index);
227
228 wxCHECK_RET( info, wxT("existing DC should have a cache entry") );
229
230 if ( !--info->count )
231 {
232 ::EndPaint(GetWinHwnd(m_canvas), &g_paintStruct);
233
234 ms_cache.Remove(index);
235
236 // Reduce the number of bogus reports of non-freed memory
237 // at app exit
238 if (ms_cache.IsEmpty())
239 ms_cache.Clear();
240 }
241 //else: cached DC entry is still in use
242
243 // prevent the base class dtor from ReleaseDC()ing it again
244 m_hDC = 0;
245 }
246 }
247
248 wxPaintDCInfo *wxPaintDC::FindInCache(size_t *index) const
249 {
250 wxPaintDCInfo *info = NULL;
251 size_t nCache = ms_cache.GetCount();
252 for ( size_t n = 0; n < nCache; n++ )
253 {
254 info = &ms_cache[n];
255 if ( info->hwnd == m_canvas->GetHWND() )
256 {
257 if ( index )
258 *index = n;
259 break;
260 }
261 }
262
263 return info;
264 }