]> git.saurik.com Git - wxWidgets.git/blame - src/os2/dcclient.cpp
Fixed buffer overrun in call to wxStripMenuCodes()
[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 }
26ac77db
DW
126 SetBackground(wxBrush(m_pCanvas->GetBackgroundColour(), wxSOLID));
127}
1408104d 128
26ac77db
DW
129wxWindowDC::~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--;
23e4b7d8 149}
0e320a79 150
23e4b7d8
DW
151// ----------------------------------------------------------------------------
152// wxClientDC
153// ----------------------------------------------------------------------------
0e320a79 154
23e4b7d8 155wxClientDC::wxClientDC()
0e320a79 156{
26ac77db 157 m_pCanvas = NULL;
23e4b7d8 158}
0e320a79 159
e99762c0
DW
160wxClientDC::wxClientDC(
161 wxWindow* pTheCanvas
162)
0e320a79 163{
7e99520b 164 SIZEL vSizl = { 0,0};
26ac77db
DW
165 ERRORID vError;
166 wxString sError;
0e320a79 167
e99762c0 168 m_pCanvas = pTheCanvas;
1408104d 169
7e99520b
DW
170 //
171 // default under PM is that Window and Client DC's are the same
172 //
e99762c0 173 m_hDC = (WXHDC) ::WinOpenWindowDC(GetWinHwnd(pTheCanvas));
7e99520b
DW
174 m_hPS = ::GpiCreatePS( wxGetInstance()
175 ,m_hDC
f44fdfb0 176 ,&vSizl
7e99520b
DW
177 ,PU_PELS | GPIF_LONG | GPIA_ASSOC
178 );
179
26ac77db
DW
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 }
7e99520b
DW
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 );
e99762c0 200} // end of wxClientDC::wxClientDC
0e320a79 201
23e4b7d8 202wxClientDC::~wxClientDC()
0e320a79 203{
26ac77db
DW
204 if ( m_pCanvas && GetHdc() )
205 {
206 SelectOldObjects(m_hDC);
ce44c50e 207
26ac77db
DW
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 }
e99762c0 214} // end of wxClientDC::~wxClientDC
0e320a79 215
23e4b7d8
DW
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
236wxArrayDCInfo wxPaintDC::ms_cache;
237
238wxPaintDC::wxPaintDC()
239{
f6bcfd97 240 m_pCanvas = NULL;
23e4b7d8
DW
241 m_hDC = 0;
242}
0e320a79 243
7e99520b
DW
244wxPaintDC::wxPaintDC(
245 wxWindow* pCanvas
246)
0e320a79 247{
f44fdfb0 248 wxCHECK_RET(pCanvas, wxT("NULL canvas in wxPaintDC ctor"));
26ac77db 249 RECTL vRect;
1408104d 250
23e4b7d8 251#ifdef __WXDEBUG__
7e99520b 252 if (g_isPainting <= 0)
23e4b7d8 253 {
223d09f6 254 wxFAIL_MSG( wxT("wxPaintDC may be created only in EVT_PAINT handler!") );
23e4b7d8
DW
255 return;
256 }
257#endif // __WXDEBUG__
0e320a79 258
7e99520b 259 m_pCanvas = pCanvas;
1408104d 260
7e99520b
DW
261 //
262 // Do we have a DC for this window in the cache?
263 //
264 wxPaintDCInfo* pInfo = FindInCache();
265
266 if (pInfo)
0e320a79 267 {
e99762c0
DW
268 m_hDC = pInfo->m_hDC;
269 pInfo->m_nCount++;
23e4b7d8
DW
270 }
271 else // not in cache, create a new one
272 {
7e99520b
DW
273 HPS hPS;
274
275 hPS = ::WinBeginPaint( GetWinHwnd(m_pCanvas)
276 ,NULLHANDLE
277 ,&g_paintStruct
278 );
279 if(hPS)
280 {
8d854fa9
DW
281 POINTL vPoint[2];
282 LONG lControl;
283 LONG lColor;
284
7e99520b
DW
285 m_hOldPS = m_hPS;
286 m_hPS = hPS;
26ac77db
DW
287 ::GpiCreateLogColorTable( m_hPS
288 ,0L
289 ,LCOLF_CONSECRGB
290 ,0L
291 ,(LONG)wxTheColourDatabase->m_nSize
292 ,(PLONG)wxTheColourDatabase->m_palTable
293 );
294 ::GpiCreateLogColorTable( m_hPS
295 ,0L
296 ,LCOLF_RGB
297 ,0L
298 ,0L
299 ,NULL
300 );
8d854fa9
DW
301
302 ::WinFillRect(hPS, &g_paintStruct, m_pCanvas->GetBackgroundColour().GetPixel());
eeff964a
DW
303 ::WinQueryWindowRect( GetWinHwnd(m_pCanvas)
304 ,&m_vRclPaint
305 );
7e99520b 306 }
e99762c0 307
7e99520b
DW
308 m_bIsPaintTime = TRUE;
309 m_hDC = (WXHDC) -1; // to satisfy those anonizmous efforts
f6bcfd97 310 ms_cache.Add(new wxPaintDCInfo(m_pCanvas, this));
0e320a79 311 }
f6bcfd97 312 SetBackground(wxBrush(m_pCanvas->GetBackgroundColour(), wxSOLID));
0e320a79
DW
313}
314
23e4b7d8 315wxPaintDC::~wxPaintDC()
0e320a79 316{
23e4b7d8
DW
317 if ( m_hDC )
318 {
319 SelectOldObjects(m_hDC);
0e320a79 320
e99762c0
DW
321 size_t nIndex;
322 wxPaintDCInfo* pInfo = FindInCache(&nIndex);
0e320a79 323
e99762c0 324 wxCHECK_RET( pInfo, wxT("existing DC should have a cache entry") );
0e320a79 325
e99762c0 326 if ( !--pInfo->m_nCount )
23e4b7d8 327 {
ce44c50e 328 ::WinEndPaint(m_hPS);
f44fdfb0 329 m_hPS = m_hOldPS;
7e99520b 330 m_bIsPaintTime = FALSE;
e99762c0 331 ms_cache.Remove(nIndex);
23e4b7d8
DW
332 }
333 //else: cached DC entry is still in use
0e320a79 334
23e4b7d8
DW
335 // prevent the base class dtor from ReleaseDC()ing it again
336 m_hDC = 0;
0e320a79
DW
337 }
338}
339
e99762c0
DW
340wxPaintDCInfo* wxPaintDC::FindInCache(
341 size_t* pIndex
342) const
0e320a79 343{
e99762c0
DW
344 wxPaintDCInfo* pInfo = NULL;
345 size_t nCache = ms_cache.GetCount();
346
347 for (size_t n = 0; n < nCache; n++)
0e320a79 348 {
e99762c0
DW
349 pInfo = &ms_cache[n];
350 if (pInfo->m_hWnd == m_pCanvas->GetHWND())
23e4b7d8 351 {
e99762c0
DW
352 if (pIndex)
353 *pIndex = n;
23e4b7d8
DW
354 break;
355 }
0e320a79 356 }
e99762c0
DW
357 return pInfo;
358} // end of wxPaintDC::FindInCache
0e320a79 359