]> git.saurik.com Git - wxWidgets.git/blob - src/os2/dcclient.cpp
Busy cursor don't need wxYield(), SendIdleEvents()
[wxWidgets.git] / src / os2 / dcclient.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dcclient.cpp
3 // Purpose: wxClientDC class
4 // Author: David Webster
5 // Modified by:
6 // Created: 09/21/99
7 // RCS-ID: $Id$
8 // Copyright: (c) David Webster
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 #include "wx/string.h"
24 #include "wx/log.h"
25 #include "wx/window.h"
26
27 #include "wx/os2/private.h"
28
29 #include "wx/dcclient.h"
30
31 // ----------------------------------------------------------------------------
32 // array/list types
33 // ----------------------------------------------------------------------------
34
35 struct WXDLLEXPORT wxPaintDCInfo
36 {
37 wxPaintDCInfo(wxWindow *win, wxDC *dc)
38 {
39 hwnd = win->GetHWND();
40 hdc = dc->GetHDC();
41 count = 1;
42 }
43
44 WXHWND hwnd; // window for this DC
45 WXHDC hdc; // the DC handle
46 size_t count; // usage count
47 };
48
49 #include "wx/arrimpl.cpp"
50
51 WX_DEFINE_OBJARRAY(wxArrayDCInfo);
52
53 // ----------------------------------------------------------------------------
54 // macros
55 // ----------------------------------------------------------------------------
56
57 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
58 IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
59 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxWindowDC)
60
61 // ----------------------------------------------------------------------------
62 // global variables
63 // ----------------------------------------------------------------------------
64
65 static RECT g_paintStruct;
66
67 #ifdef __WXDEBUG__
68 // a global variable which we check to verify that wxPaintDC are only
69 // created in resopnse to WM_PAINT message - doing this from elsewhere is a
70 // common programming error among wxWindows programmers and might lead to
71 // very subtle and difficult to debug refresh/repaint bugs.
72 int g_isPainting = 0;
73 #endif // __WXDEBUG__
74
75 // ===========================================================================
76 // implementation
77 // ===========================================================================
78
79 // ----------------------------------------------------------------------------
80 // wxWindowDC
81 // ----------------------------------------------------------------------------
82
83 wxWindowDC::wxWindowDC()
84 {
85 m_pCanvas = NULL;
86 }
87
88 wxWindowDC::wxWindowDC(wxWindow *the_canvas)
89 {
90 m_pCanvas = the_canvas;
91 m_hDC = (WXHDC) ::WinOpenWindowDC(GetWinHwnd(the_canvas) );
92 m_nDCCount++;
93 //
94 // default under PM is that Window and Client DC's are the same
95 // so we offer a separate Presentation Space to use for the
96 // entire window. Otherwise, calling BeginPaint will just create
97 // chached-micro client presentation space
98 //
99 m_hPS = GpiCreatePS( m_hab
100 ,m_hDC
101 ,&m_PageSize
102 ,PU_PELS | GPIF_LONG | GPIA_ASSOC
103 );
104 ::GpiAssociate(m_hPS, NULLHANDLE);
105 ::GpiAssociate(m_hPS, m_hDC);
106 SetBackground(wxBrush(m_pCanvas->GetBackgroundColour(), wxSOLID));
107 }
108
109 wxWindowDC::~wxWindowDC()
110 {
111 if (m_pCanvas && m_hDC)
112 {
113 SelectOldObjects(m_hDC);
114
115 //
116 // In PM one does not explicitly close or release an open WindowDC
117 // They automatically close with the window, unless explicitly detached
118 // but we need to destroy our PS
119 //
120 if(m_hPS)
121 {
122 ::GpiAssociate(m_hPS, NULLHANDLE);
123 ::GpiDestroyPS(m_hPS);
124 }
125 m_hPS = NULLHANDLE;
126 m_hDC = NULLHANDLE;
127 }
128
129 m_nDCCount--;
130 }
131
132 // ----------------------------------------------------------------------------
133 // wxClientDC
134 // ----------------------------------------------------------------------------
135
136 wxClientDC::wxClientDC()
137 {
138 m_pCanvas = NULL;
139 }
140
141 wxClientDC::wxClientDC(wxWindow *the_canvas)
142 {
143 SIZEL vSizl = { 0,0};
144
145 m_pCanvas = the_canvas;
146
147 //
148 // default under PM is that Window and Client DC's are the same
149 //
150 m_hDC = (WXHDC) ::WinOpenWindowDC(GetWinHwnd(the_canvas));
151 m_hPS = ::GpiCreatePS( wxGetInstance()
152 ,m_hDC
153 ,&vSizl
154 ,PU_PELS | GPIF_LONG | GPIA_ASSOC
155 );
156
157 //
158 // Default mode is BM_LEAVEALONE so we make no call Set the mix
159 //
160 SetBackground(wxBrush( m_pCanvas->GetBackgroundColour()
161 ,wxSOLID
162 )
163 );
164 }
165
166 wxClientDC::~wxClientDC()
167 {
168 if ( m_pCanvas && GetHdc() )
169 {
170 SelectOldObjects(m_hDC);
171
172 // We don't explicitly release Device contexts in PM and
173 // the cached micro PS is already gone
174
175 m_hDC = 0;
176 }
177 }
178
179 // ----------------------------------------------------------------------------
180 // wxPaintDC
181 // ----------------------------------------------------------------------------
182
183 // VZ: initial implementation (by JACS) only remembered the last wxPaintDC
184 // created and tried to reuse - this was supposed to take care of a
185 // situation when a derived class OnPaint() calls base class OnPaint()
186 // because in this case ::BeginPaint() shouldn't be called second time.
187 //
188 // I'm not sure how useful this is, however we must remember the HWND
189 // associated with the last HDC as well - otherwise we may (and will!) try
190 // to reuse the HDC for another HWND which is a nice recipe for disaster.
191 //
192 // So we store a list of windows for which we already have the DC and not
193 // just one single hDC. This seems to work, but I'm really not sure about
194 // the usefullness of the whole idea - IMHO it's much better to not call
195 // base class OnPaint() at all, or, if we really want to allow it, add a
196 // "wxPaintDC *" parameter to wxPaintEvent which should be used if it's
197 // !NULL instead of creating a new DC.
198
199 wxArrayDCInfo wxPaintDC::ms_cache;
200
201 wxPaintDC::wxPaintDC()
202 {
203 m_pCanvas = NULL;
204 m_hDC = 0;
205 }
206
207 wxPaintDC::wxPaintDC(
208 wxWindow* pCanvas
209 )
210 {
211 wxCHECK_RET(pCanvas, wxT("NULL canvas in wxPaintDC ctor"));
212
213 #ifdef __WXDEBUG__
214 if (g_isPainting <= 0)
215 {
216 wxFAIL_MSG( wxT("wxPaintDC may be created only in EVT_PAINT handler!") );
217 return;
218 }
219 #endif // __WXDEBUG__
220
221 m_pCanvas = pCanvas;
222
223 //
224 // Do we have a DC for this window in the cache?
225 //
226 wxPaintDCInfo* pInfo = FindInCache();
227
228 if (pInfo)
229 {
230 m_hDC = pInfo->hdc;
231 pInfo->count++;
232 }
233 else // not in cache, create a new one
234 {
235 HPS hPS;
236
237 hPS = ::WinBeginPaint( GetWinHwnd(m_pCanvas)
238 ,NULLHANDLE
239 ,&g_paintStruct
240 );
241 if(hPS)
242 {
243 m_hOldPS = m_hPS;
244 m_hPS = hPS;
245 }
246 m_bIsPaintTime = TRUE;
247 m_hDC = (WXHDC) -1; // to satisfy those anonizmous efforts
248 m_vRclPaint = g_paintStruct;
249 ms_cache.Add(new wxPaintDCInfo(m_pCanvas, this));
250 }
251 SetBackground(wxBrush(m_pCanvas->GetBackgroundColour(), wxSOLID));
252 }
253
254 wxPaintDC::~wxPaintDC()
255 {
256 if ( m_hDC )
257 {
258 SelectOldObjects(m_hDC);
259
260 size_t index;
261 wxPaintDCInfo *info = FindInCache(&index);
262
263 wxCHECK_RET( info, wxT("existing DC should have a cache entry") );
264
265 if ( !--info->count )
266 {
267 ::WinEndPaint(m_hPS);
268 m_hPS = m_hOldPS;
269 m_bIsPaintTime = FALSE;
270 ms_cache.Remove(index);
271 }
272 //else: cached DC entry is still in use
273
274 // prevent the base class dtor from ReleaseDC()ing it again
275 m_hDC = 0;
276 }
277 }
278
279 wxPaintDCInfo *wxPaintDC::FindInCache(size_t *index) const
280 {
281 wxPaintDCInfo *info = NULL;
282 size_t nCache = ms_cache.GetCount();
283 for ( size_t n = 0; n < nCache; n++ )
284 {
285 info = &ms_cache[n];
286 if ( info->hwnd == m_pCanvas->GetHWND() )
287 {
288 if ( index )
289 *index = n;
290 break;
291 }
292 }
293
294 return info;
295 }