]> git.saurik.com Git - wxWidgets.git/blob - src/msw/dcclient.cpp
multi line static controls now calculate their width and height correctly
[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 #if !USE_SHARED_LIBRARY
66 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
67 IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
68 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxWindowDC)
69 #endif
70
71 // ----------------------------------------------------------------------------
72 // global variables
73 // ----------------------------------------------------------------------------
74
75 static PAINTSTRUCT g_paintStruct;
76
77 #ifdef __WXDEBUG__
78 // a global variable which we check to verify that wxPaintDC are only
79 // created in resopnse to WM_PAINT message - doing this from elsewhere is a
80 // common programming error among wxWindows programmers and might lead to
81 // very subtle and difficult to debug refresh/repaint bugs.
82 int g_isPainting = 0;
83 #endif // __WXDEBUG__
84
85 // ===========================================================================
86 // implementation
87 // ===========================================================================
88
89 // ----------------------------------------------------------------------------
90 // wxWindowDC
91 // ----------------------------------------------------------------------------
92
93 wxWindowDC::wxWindowDC()
94 {
95 m_canvas = NULL;
96 }
97
98 wxWindowDC::wxWindowDC(wxWindow *the_canvas)
99 {
100 m_canvas = the_canvas;
101 m_hDC = (WXHDC) ::GetWindowDC(GetWinHwnd(the_canvas) );
102 m_hDCCount++;
103
104 SetBackground(wxBrush(m_canvas->GetBackgroundColour(), wxSOLID));
105 }
106
107 wxWindowDC::~wxWindowDC()
108 {
109 if (m_canvas && m_hDC)
110 {
111 SelectOldObjects(m_hDC);
112
113 if ( !::ReleaseDC(GetWinHwnd(m_canvas), GetHdc()) )
114 {
115 wxLogLastError("ReleaseDC");
116 }
117
118 m_hDC = 0;
119 }
120
121 m_hDCCount--;
122 }
123
124 // ----------------------------------------------------------------------------
125 // wxClientDC
126 // ----------------------------------------------------------------------------
127
128 wxClientDC::wxClientDC()
129 {
130 m_canvas = NULL;
131 }
132
133 wxClientDC::wxClientDC(wxWindow *the_canvas)
134 {
135 m_canvas = the_canvas;
136 m_hDC = (WXHDC) ::GetDC(GetWinHwnd(the_canvas));
137
138 SetBackground(wxBrush(m_canvas->GetBackgroundColour(), wxSOLID));
139 }
140
141 wxClientDC::~wxClientDC()
142 {
143 if ( m_canvas && GetHdc() )
144 {
145 SelectOldObjects(m_hDC);
146
147 ::ReleaseDC(GetWinHwnd(m_canvas), GetHdc());
148 m_hDC = 0;
149 }
150 }
151
152 // ----------------------------------------------------------------------------
153 // wxPaintDC
154 // ----------------------------------------------------------------------------
155
156 // VZ: initial implementation (by JACS) only remembered the last wxPaintDC
157 // created and tried to reuse - this was supposed to take care of a
158 // situation when a derived class OnPaint() calls base class OnPaint()
159 // because in this case ::BeginPaint() shouldn't be called second time.
160 //
161 // I'm not sure how useful this is, however we must remember the HWND
162 // associated with the last HDC as well - otherwise we may (and will!) try
163 // to reuse the HDC for another HWND which is a nice recipe for disaster.
164 //
165 // So we store a list of windows for which we already have the DC and not
166 // just one single hDC. This seems to work, but I'm really not sure about
167 // the usefullness of the whole idea - IMHO it's much better to not call
168 // base class OnPaint() at all, or, if we really want to allow it, add a
169 // "wxPaintDC *" parameter to wxPaintEvent which should be used if it's
170 // !NULL instead of creating a new DC.
171
172 wxArrayDCInfo wxPaintDC::ms_cache;
173
174 wxPaintDC::wxPaintDC()
175 {
176 m_canvas = NULL;
177 m_hDC = 0;
178 }
179
180 wxPaintDC::wxPaintDC(wxWindow *canvas)
181 {
182 wxCHECK_RET( canvas, _T("NULL canvas in wxPaintDC ctor") );
183
184 #ifdef __WXDEBUG__
185 if ( g_isPainting <= 0 )
186 {
187 wxFAIL_MSG( _T("wxPaintDC may be created only in EVT_PAINT handler!") );
188
189 return;
190 }
191 #endif // __WXDEBUG__
192
193 m_canvas = canvas;
194
195 // do we have a DC for this window in the cache?
196 wxPaintDCInfo *info = FindInCache();
197 if ( info )
198 {
199 m_hDC = info->hdc;
200 info->count++;
201 }
202 else // not in cache, create a new one
203 {
204 m_hDC = (WXHDC)::BeginPaint(GetWinHwnd(m_canvas), &g_paintStruct);
205 ms_cache.Add(new wxPaintDCInfo(m_canvas, this));
206 }
207
208 SetBackground(wxBrush(m_canvas->GetBackgroundColour(), wxSOLID));
209 }
210
211 wxPaintDC::~wxPaintDC()
212 {
213 if ( m_hDC )
214 {
215 SelectOldObjects(m_hDC);
216
217 size_t index;
218 wxPaintDCInfo *info = FindInCache(&index);
219
220 wxCHECK_RET( info, _T("existing DC should have a cache entry") );
221
222 if ( !--info->count )
223 {
224 ::EndPaint(GetWinHwnd(m_canvas), &g_paintStruct);
225
226 ms_cache.Remove(index);
227 }
228 //else: cached DC entry is still in use
229
230 // prevent the base class dtor from ReleaseDC()ing it again
231 m_hDC = 0;
232 }
233 }
234
235 wxPaintDCInfo *wxPaintDC::FindInCache(size_t *index) const
236 {
237 wxPaintDCInfo *info = NULL;
238 size_t nCache = ms_cache.GetCount();
239 for ( size_t n = 0; n < nCache; n++ )
240 {
241 info = &ms_cache[n];
242 if ( info->hwnd == m_canvas->GetHWND() )
243 {
244 if ( index )
245 *index = n;
246 break;
247 }
248 }
249
250 return info;
251 }