]> git.saurik.com Git - wxWidgets.git/blame - src/os2/dcclient.cpp
a fix for the last fix
[wxWidgets.git] / src / os2 / dcclient.cpp
CommitLineData
0e320a79
DW
1/////////////////////////////////////////////////////////////////////////////
2// Name: dcclient.cpp
3// Purpose: wxClientDC class
f0a56ab0 4// Author: David Webster
0e320a79 5// Modified by:
f0a56ab0 6// Created: 09/21/99
0e320a79 7// RCS-ID: $Id$
f0a56ab0 8// Copyright: (c) David Webster
23e4b7d8 9// Licence: wxWindows licence
0e320a79
DW
10/////////////////////////////////////////////////////////////////////////////
11
23e4b7d8
DW
12// ===========================================================================
13// declarations
14// ===========================================================================
0e320a79 15
23e4b7d8
DW
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
0e320a79 19
23e4b7d8
DW
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
0e320a79 22
23e4b7d8
DW
23#include "wx/string.h"
24#include "wx/log.h"
25#include "wx/window.h"
0e320a79 26
ce44c50e 27#include "wx/os2/private.h"
0e320a79 28
23e4b7d8 29#include "wx/dcclient.h"
0e320a79 30
23e4b7d8
DW
31// ----------------------------------------------------------------------------
32// array/list types
33// ----------------------------------------------------------------------------
0e320a79 34
23e4b7d8 35struct WXDLLEXPORT wxPaintDCInfo
0e320a79 36{
e99762c0
DW
37 wxPaintDCInfo( wxWindow* pWin
38 ,wxDC* pDC
39 )
23e4b7d8 40 {
e99762c0
DW
41 m_hWnd = pWin->GetHWND();
42 m_hDC = pDC->GetHDC();
43 m_nCount = 1;
23e4b7d8 44 }
0e320a79 45
e99762c0
DW
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
0e320a79 50
23e4b7d8 51#include "wx/arrimpl.cpp"
1408104d 52
23e4b7d8 53WX_DEFINE_OBJARRAY(wxArrayDCInfo);
1408104d 54
23e4b7d8
DW
55// ----------------------------------------------------------------------------
56// macros
57// ----------------------------------------------------------------------------
0e320a79 58
23e4b7d8
DW
59 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
60 IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
61 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxWindowDC)
0e320a79 62
23e4b7d8
DW
63// ----------------------------------------------------------------------------
64// global variables
65// ----------------------------------------------------------------------------
1408104d 66
ce44c50e 67static RECT g_paintStruct;
1408104d 68
23e4b7d8
DW
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__
1408104d 76
23e4b7d8
DW
77// ===========================================================================
78// implementation
79// ===========================================================================
1408104d 80
23e4b7d8
DW
81// ----------------------------------------------------------------------------
82// wxWindowDC
83// ----------------------------------------------------------------------------
0e320a79 84
23e4b7d8 85wxWindowDC::wxWindowDC()
0e320a79 86{
26ac77db 87 m_pCanvas = NULL;
23e4b7d8 88}
0e320a79 89
e99762c0
DW
90wxWindowDC::wxWindowDC(
91 wxWindow* pTheCanvas
92)
0e320a79 93{
26ac77db
DW
94 ERRORID vError;
95 wxString sError;
1408104d 96
e99762c0
DW
97 m_pCanvas = pTheCanvas;
98 m_hDC = (WXHDC) ::WinOpenWindowDC(GetWinHwnd(pTheCanvas) );
26ac77db 99 m_nDCCount++;
23e4b7d8 100 //
26ac77db
DW
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
23e4b7d8 105 //
26ac77db
DW
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 ))
7e99520b 121 {
26ac77db
DW
122 vError = ::WinGetLastError(vHabmain);
123 sError = wxPMErrorToStr(vError);
124 wxLogError("Unable to set current color table. Error: %s\n", sError);
7e99520b 125 }
5afb9458
DW
126 ::GpiCreateLogColorTable( m_hPS
127 ,0L
128 ,LCOLF_RGB
129 ,0L
130 ,0L
131 ,NULL
132 );
26ac77db 133 SetBackground(wxBrush(m_pCanvas->GetBackgroundColour(), wxSOLID));
5afb9458
DW
134 ::WinQueryWindowRect( GetWinHwnd(m_pCanvas)
135 ,&m_vRclPaint
136 );
26ac77db 137}
1408104d 138
26ac77db
DW
139wxWindowDC::~wxWindowDC()
140{
141 if (m_pCanvas && m_hDC)
142 {
143 SelectOldObjects(m_hDC);
144
145 //
146 // In PM one does not explicitly close or release an open WindowDC
147 // They automatically close with the window, unless explicitly detached
148 // but we need to destroy our PS
149 //
150 if(m_hPS)
151 {
152 ::GpiAssociate(m_hPS, NULLHANDLE);
153 ::GpiDestroyPS(m_hPS);
154 }
155 m_hPS = NULLHANDLE;
156 m_hDC = NULLHANDLE;
157 }
158 m_nDCCount--;
23e4b7d8 159}
0e320a79 160
23e4b7d8
DW
161// ----------------------------------------------------------------------------
162// wxClientDC
163// ----------------------------------------------------------------------------
0e320a79 164
23e4b7d8 165wxClientDC::wxClientDC()
0e320a79 166{
26ac77db 167 m_pCanvas = NULL;
23e4b7d8 168}
0e320a79 169
e99762c0
DW
170wxClientDC::wxClientDC(
171 wxWindow* pTheCanvas
172)
0e320a79 173{
7e99520b 174 SIZEL vSizl = { 0,0};
26ac77db
DW
175 ERRORID vError;
176 wxString sError;
0e320a79 177
e99762c0 178 m_pCanvas = pTheCanvas;
1408104d 179
7e99520b
DW
180 //
181 // default under PM is that Window and Client DC's are the same
182 //
e99762c0 183 m_hDC = (WXHDC) ::WinOpenWindowDC(GetWinHwnd(pTheCanvas));
7e99520b
DW
184 m_hPS = ::GpiCreatePS( wxGetInstance()
185 ,m_hDC
f44fdfb0 186 ,&vSizl
7e99520b
DW
187 ,PU_PELS | GPIF_LONG | GPIA_ASSOC
188 );
189
26ac77db
DW
190 // Set the wxWindows color table
191 if (!::GpiCreateLogColorTable( m_hPS
192 ,0L
193 ,LCOLF_CONSECRGB
194 ,0L
195 ,(LONG)wxTheColourDatabase->m_nSize
196 ,(PLONG)wxTheColourDatabase->m_palTable
197 ))
198 {
199 vError = ::WinGetLastError(vHabmain);
200 sError = wxPMErrorToStr(vError);
201 wxLogError("Unable to set current color table. Error: %s\n", sError);
202 }
5afb9458
DW
203 ::GpiCreateLogColorTable( m_hPS
204 ,0L
205 ,LCOLF_RGB
206 ,0L
207 ,0L
208 ,NULL
209 );
7e99520b
DW
210 //
211 // Default mode is BM_LEAVEALONE so we make no call Set the mix
212 //
213 SetBackground(wxBrush( m_pCanvas->GetBackgroundColour()
214 ,wxSOLID
215 )
216 );
5afb9458
DW
217 //
218 // Set the DC/PS rectangle
219 //
220 ::WinQueryWindowRect( GetWinHwnd(m_pCanvas)
221 ,&m_vRclPaint
222 );
e99762c0 223} // end of wxClientDC::wxClientDC
0e320a79 224
23e4b7d8 225wxClientDC::~wxClientDC()
0e320a79 226{
26ac77db
DW
227 if ( m_pCanvas && GetHdc() )
228 {
229 SelectOldObjects(m_hDC);
ce44c50e 230
26ac77db
DW
231 //
232 // We don't explicitly release Device contexts in PM and
233 // the cached micro PS is already gone
234 //
235 m_hDC = 0;
236 }
e99762c0 237} // end of wxClientDC::~wxClientDC
0e320a79 238
23e4b7d8
DW
239// ----------------------------------------------------------------------------
240// wxPaintDC
241// ----------------------------------------------------------------------------
242
243// VZ: initial implementation (by JACS) only remembered the last wxPaintDC
244// created and tried to reuse - this was supposed to take care of a
245// situation when a derived class OnPaint() calls base class OnPaint()
246// because in this case ::BeginPaint() shouldn't be called second time.
247//
248// I'm not sure how useful this is, however we must remember the HWND
249// associated with the last HDC as well - otherwise we may (and will!) try
250// to reuse the HDC for another HWND which is a nice recipe for disaster.
251//
252// So we store a list of windows for which we already have the DC and not
253// just one single hDC. This seems to work, but I'm really not sure about
254// the usefullness of the whole idea - IMHO it's much better to not call
255// base class OnPaint() at all, or, if we really want to allow it, add a
256// "wxPaintDC *" parameter to wxPaintEvent which should be used if it's
257// !NULL instead of creating a new DC.
258
259wxArrayDCInfo wxPaintDC::ms_cache;
260
261wxPaintDC::wxPaintDC()
262{
f6bcfd97 263 m_pCanvas = NULL;
23e4b7d8
DW
264 m_hDC = 0;
265}
0e320a79 266
7e99520b
DW
267wxPaintDC::wxPaintDC(
268 wxWindow* pCanvas
269)
0e320a79 270{
f44fdfb0 271 wxCHECK_RET(pCanvas, wxT("NULL canvas in wxPaintDC ctor"));
26ac77db 272 RECTL vRect;
1408104d 273
23e4b7d8 274#ifdef __WXDEBUG__
7e99520b 275 if (g_isPainting <= 0)
23e4b7d8 276 {
223d09f6 277 wxFAIL_MSG( wxT("wxPaintDC may be created only in EVT_PAINT handler!") );
23e4b7d8
DW
278 return;
279 }
280#endif // __WXDEBUG__
0e320a79 281
7e99520b 282 m_pCanvas = pCanvas;
1408104d 283
7e99520b
DW
284 //
285 // Do we have a DC for this window in the cache?
286 //
287 wxPaintDCInfo* pInfo = FindInCache();
288
289 if (pInfo)
0e320a79 290 {
e99762c0
DW
291 m_hDC = pInfo->m_hDC;
292 pInfo->m_nCount++;
23e4b7d8
DW
293 }
294 else // not in cache, create a new one
295 {
7e99520b
DW
296 HPS hPS;
297
298 hPS = ::WinBeginPaint( GetWinHwnd(m_pCanvas)
299 ,NULLHANDLE
300 ,&g_paintStruct
301 );
302 if(hPS)
303 {
8d854fa9
DW
304 POINTL vPoint[2];
305 LONG lControl;
306 LONG lColor;
307
7e99520b
DW
308 m_hOldPS = m_hPS;
309 m_hPS = hPS;
26ac77db
DW
310 ::GpiCreateLogColorTable( m_hPS
311 ,0L
312 ,LCOLF_CONSECRGB
313 ,0L
314 ,(LONG)wxTheColourDatabase->m_nSize
315 ,(PLONG)wxTheColourDatabase->m_palTable
316 );
317 ::GpiCreateLogColorTable( m_hPS
318 ,0L
319 ,LCOLF_RGB
320 ,0L
321 ,0L
322 ,NULL
323 );
8d854fa9
DW
324
325 ::WinFillRect(hPS, &g_paintStruct, m_pCanvas->GetBackgroundColour().GetPixel());
eeff964a
DW
326 ::WinQueryWindowRect( GetWinHwnd(m_pCanvas)
327 ,&m_vRclPaint
328 );
7e99520b 329 }
e99762c0 330
7e99520b
DW
331 m_bIsPaintTime = TRUE;
332 m_hDC = (WXHDC) -1; // to satisfy those anonizmous efforts
f6bcfd97 333 ms_cache.Add(new wxPaintDCInfo(m_pCanvas, this));
0e320a79 334 }
f6bcfd97 335 SetBackground(wxBrush(m_pCanvas->GetBackgroundColour(), wxSOLID));
0e320a79
DW
336}
337
23e4b7d8 338wxPaintDC::~wxPaintDC()
0e320a79 339{
23e4b7d8
DW
340 if ( m_hDC )
341 {
342 SelectOldObjects(m_hDC);
0e320a79 343
e99762c0
DW
344 size_t nIndex;
345 wxPaintDCInfo* pInfo = FindInCache(&nIndex);
0e320a79 346
e99762c0 347 wxCHECK_RET( pInfo, wxT("existing DC should have a cache entry") );
0e320a79 348
e99762c0 349 if ( !--pInfo->m_nCount )
23e4b7d8 350 {
ce44c50e 351 ::WinEndPaint(m_hPS);
f44fdfb0 352 m_hPS = m_hOldPS;
7e99520b 353 m_bIsPaintTime = FALSE;
e99762c0 354 ms_cache.Remove(nIndex);
23e4b7d8
DW
355 }
356 //else: cached DC entry is still in use
0e320a79 357
23e4b7d8
DW
358 // prevent the base class dtor from ReleaseDC()ing it again
359 m_hDC = 0;
0e320a79
DW
360 }
361}
362
e99762c0
DW
363wxPaintDCInfo* wxPaintDC::FindInCache(
364 size_t* pIndex
365) const
0e320a79 366{
e99762c0
DW
367 wxPaintDCInfo* pInfo = NULL;
368 size_t nCache = ms_cache.GetCount();
369
370 for (size_t n = 0; n < nCache; n++)
0e320a79 371 {
e99762c0
DW
372 pInfo = &ms_cache[n];
373 if (pInfo->m_hWnd == m_pCanvas->GetHWND())
23e4b7d8 374 {
e99762c0
DW
375 if (pIndex)
376 *pIndex = n;
23e4b7d8
DW
377 break;
378 }
0e320a79 379 }
e99762c0
DW
380 return pInfo;
381} // end of wxPaintDC::FindInCache
0e320a79 382