]> git.saurik.com Git - wxWidgets.git/blob - src/os2/dcclient.cpp
a5cc0f7fee148674cea5da049c6b2f2b076c0ad9
[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* pWin
38 ,wxDC* pDC
39 )
40 {
41 m_hWnd = pWin->GetHWND();
42 m_hDC = pDC->GetHDC();
43 m_nCount = 1;
44 }
45
46 WXHWND m_hWnd; // window for this DC
47 WXHDC m_hDC; // the DC handle
48 size_t m_nCount; // usage count
49 }; // end of wxPaintDCInfot
50
51 #include "wx/arrimpl.cpp"
52
53 WX_DEFINE_OBJARRAY(wxArrayDCInfo);
54
55 // ----------------------------------------------------------------------------
56 // macros
57 // ----------------------------------------------------------------------------
58
59 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
60 IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
61 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxWindowDC)
62
63 // ----------------------------------------------------------------------------
64 // global variables
65 // ----------------------------------------------------------------------------
66
67 static RECT g_paintStruct;
68
69 #ifdef __WXDEBUG__
70 // a global variable which we check to verify that wxPaintDC are only
71 // created in resopnse to WM_PAINT message - doing this from elsewhere is a
72 // common programming error among wxWindows programmers and might lead to
73 // very subtle and difficult to debug refresh/repaint bugs.
74 int g_isPainting = 0;
75 #endif // __WXDEBUG__
76
77 // ===========================================================================
78 // implementation
79 // ===========================================================================
80
81 // ----------------------------------------------------------------------------
82 // wxWindowDC
83 // ----------------------------------------------------------------------------
84
85 wxWindowDC::wxWindowDC()
86 {
87 m_pCanvas = NULL;
88 }
89
90 wxWindowDC::wxWindowDC(
91 wxWindow* pTheCanvas
92 )
93 {
94 ERRORID vError;
95 wxString sError;
96
97 m_pCanvas = pTheCanvas;
98 m_hDC = (WXHDC) ::WinOpenWindowDC(GetWinHwnd(pTheCanvas) );
99 m_nDCCount++;
100 //
101 // default under PM is that Window and Client DC's are the same
102 // so we offer a separate Presentation Space to use for the
103 // entire window. Otherwise, calling BeginPaint will just create
104 // chached-micro client presentation space
105 //
106 m_hPS = GpiCreatePS( m_hab
107 ,m_hDC
108 ,&m_PageSize
109 ,PU_PELS | GPIF_LONG | GPIA_ASSOC
110 );
111 ::GpiAssociate(m_hPS, NULLHANDLE);
112 ::GpiAssociate(m_hPS, m_hDC);
113 // Set the wxWindows color table
114 if (!::GpiCreateLogColorTable( m_hPS
115 ,0L
116 ,LCOLF_CONSECRGB
117 ,0L
118 ,(LONG)wxTheColourDatabase->m_nSize
119 ,(PLONG)wxTheColourDatabase->m_palTable
120 ))
121 {
122 vError = ::WinGetLastError(vHabmain);
123 sError = wxPMErrorToStr(vError);
124 wxLogError("Unable to set current color table. Error: %s\n", sError);
125 }
126 SetBackground(wxBrush(m_pCanvas->GetBackgroundColour(), wxSOLID));
127 }
128
129 wxWindowDC::~wxWindowDC()
130 {
131 if (m_pCanvas && m_hDC)
132 {
133 SelectOldObjects(m_hDC);
134
135 //
136 // In PM one does not explicitly close or release an open WindowDC
137 // They automatically close with the window, unless explicitly detached
138 // but we need to destroy our PS
139 //
140 if(m_hPS)
141 {
142 ::GpiAssociate(m_hPS, NULLHANDLE);
143 ::GpiDestroyPS(m_hPS);
144 }
145 m_hPS = NULLHANDLE;
146 m_hDC = NULLHANDLE;
147 }
148 m_nDCCount--;
149 }
150
151 // ----------------------------------------------------------------------------
152 // wxClientDC
153 // ----------------------------------------------------------------------------
154
155 wxClientDC::wxClientDC()
156 {
157 m_pCanvas = NULL;
158 }
159
160 wxClientDC::wxClientDC(
161 wxWindow* pTheCanvas
162 )
163 {
164 SIZEL vSizl = { 0,0};
165 ERRORID vError;
166 wxString sError;
167
168 m_pCanvas = pTheCanvas;
169
170 //
171 // default under PM is that Window and Client DC's are the same
172 //
173 m_hDC = (WXHDC) ::WinOpenWindowDC(GetWinHwnd(pTheCanvas));
174 m_hPS = ::GpiCreatePS( wxGetInstance()
175 ,m_hDC
176 ,&vSizl
177 ,PU_PELS | GPIF_LONG | GPIA_ASSOC
178 );
179
180 // Set the wxWindows color table
181 if (!::GpiCreateLogColorTable( m_hPS
182 ,0L
183 ,LCOLF_CONSECRGB
184 ,0L
185 ,(LONG)wxTheColourDatabase->m_nSize
186 ,(PLONG)wxTheColourDatabase->m_palTable
187 ))
188 {
189 vError = ::WinGetLastError(vHabmain);
190 sError = wxPMErrorToStr(vError);
191 wxLogError("Unable to set current color table. Error: %s\n", sError);
192 }
193 //
194 // Default mode is BM_LEAVEALONE so we make no call Set the mix
195 //
196 SetBackground(wxBrush( m_pCanvas->GetBackgroundColour()
197 ,wxSOLID
198 )
199 );
200 } // end of wxClientDC::wxClientDC
201
202 wxClientDC::~wxClientDC()
203 {
204 if ( m_pCanvas && GetHdc() )
205 {
206 SelectOldObjects(m_hDC);
207
208 //
209 // We don't explicitly release Device contexts in PM and
210 // the cached micro PS is already gone
211 //
212 m_hDC = 0;
213 }
214 } // end of wxClientDC::~wxClientDC
215
216 // ----------------------------------------------------------------------------
217 // wxPaintDC
218 // ----------------------------------------------------------------------------
219
220 // VZ: initial implementation (by JACS) only remembered the last wxPaintDC
221 // created and tried to reuse - this was supposed to take care of a
222 // situation when a derived class OnPaint() calls base class OnPaint()
223 // because in this case ::BeginPaint() shouldn't be called second time.
224 //
225 // I'm not sure how useful this is, however we must remember the HWND
226 // associated with the last HDC as well - otherwise we may (and will!) try
227 // to reuse the HDC for another HWND which is a nice recipe for disaster.
228 //
229 // So we store a list of windows for which we already have the DC and not
230 // just one single hDC. This seems to work, but I'm really not sure about
231 // the usefullness of the whole idea - IMHO it's much better to not call
232 // base class OnPaint() at all, or, if we really want to allow it, add a
233 // "wxPaintDC *" parameter to wxPaintEvent which should be used if it's
234 // !NULL instead of creating a new DC.
235
236 wxArrayDCInfo wxPaintDC::ms_cache;
237
238 wxPaintDC::wxPaintDC()
239 {
240 m_pCanvas = NULL;
241 m_hDC = 0;
242 }
243
244 wxPaintDC::wxPaintDC(
245 wxWindow* pCanvas
246 )
247 {
248 wxCHECK_RET(pCanvas, wxT("NULL canvas in wxPaintDC ctor"));
249 RECTL vRect;
250
251 #ifdef __WXDEBUG__
252 if (g_isPainting <= 0)
253 {
254 wxFAIL_MSG( wxT("wxPaintDC may be created only in EVT_PAINT handler!") );
255 return;
256 }
257 #endif // __WXDEBUG__
258
259 m_pCanvas = pCanvas;
260
261 //
262 // Do we have a DC for this window in the cache?
263 //
264 wxPaintDCInfo* pInfo = FindInCache();
265
266 if (pInfo)
267 {
268 m_hDC = pInfo->m_hDC;
269 pInfo->m_nCount++;
270 }
271 else // not in cache, create a new one
272 {
273 SIZEL vSizl = { 0,0};
274 HPS hPS;
275 HRGN hRgn;
276
277 memset(&g_paintStruct, '\0', sizeof(RECTL));
278 if (!::WinQueryUpdateRect(GetWinHwnd(m_pCanvas), &g_paintStruct))
279 {
280 wxLogLastError("CreateRectRgn");
281 // return;
282 }
283 m_hDC = (WXHDC) ::WinOpenWindowDC(GetWinHwnd(m_pCanvas));
284 m_hPS = ::GpiCreatePS( wxGetInstance()
285 ,m_hDC
286 ,&vSizl
287 ,PU_PELS | GPIF_LONG | GPIA_ASSOC
288 );
289
290 // Set the wxWindows color table
291 ::GpiCreateLogColorTable( m_hPS
292 ,0L
293 ,LCOLF_CONSECRGB
294 ,0L
295 ,(LONG)wxTheColourDatabase->m_nSize
296 ,(PLONG)wxTheColourDatabase->m_palTable
297 );
298 ::GpiCreateLogColorTable( m_hPS
299 ,0L
300 ,LCOLF_RGB
301 ,0L
302 ,0L
303 ,NULL
304 );
305
306 #if 0
307 hPS = ::WinBeginPaint( GetWinHwnd(m_pCanvas)
308 ,NULLHANDLE
309 ,&g_paintStruct
310 );
311 if(hPS)
312 {
313 m_hOldPS = m_hPS;
314 m_hPS = hPS;
315 ::GpiCreateLogColorTable( m_hPS
316 ,0L
317 ,LCOLF_CONSECRGB
318 ,0L
319 ,(LONG)wxTheColourDatabase->m_nSize
320 ,(PLONG)wxTheColourDatabase->m_palTable
321 );
322 ::GpiCreateLogColorTable( m_hPS
323 ,0L
324 ,LCOLF_RGB
325 ,0L
326 ,0L
327 ,NULL
328 );
329 }
330 #endif
331
332 m_bIsPaintTime = TRUE;
333 m_hDC = (WXHDC) -1; // to satisfy those anonizmous efforts
334 m_vRclPaint = g_paintStruct;
335 ms_cache.Add(new wxPaintDCInfo(m_pCanvas, this));
336 }
337 SetBackground(wxBrush(m_pCanvas->GetBackgroundColour(), wxSOLID));
338 }
339
340 wxPaintDC::~wxPaintDC()
341 {
342 if ( m_hDC )
343 {
344 SelectOldObjects(m_hDC);
345
346 size_t nIndex;
347 wxPaintDCInfo* pInfo = FindInCache(&nIndex);
348
349 wxCHECK_RET( pInfo, wxT("existing DC should have a cache entry") );
350
351 if ( !--pInfo->m_nCount )
352 {
353 ::WinEndPaint(m_hPS);
354 m_hPS = m_hOldPS;
355 m_bIsPaintTime = FALSE;
356 ms_cache.Remove(nIndex);
357 }
358 //else: cached DC entry is still in use
359
360 // prevent the base class dtor from ReleaseDC()ing it again
361 m_hDC = 0;
362 }
363 }
364
365 wxPaintDCInfo* wxPaintDC::FindInCache(
366 size_t* pIndex
367 ) const
368 {
369 wxPaintDCInfo* pInfo = NULL;
370 size_t nCache = ms_cache.GetCount();
371
372 for (size_t n = 0; n < nCache; n++)
373 {
374 pInfo = &ms_cache[n];
375 if (pInfo->m_hWnd == m_pCanvas->GetHWND())
376 {
377 if (pIndex)
378 *pIndex = n;
379 break;
380 }
381 }
382 return pInfo;
383 } // end of wxPaintDC::FindInCache
384