1///////////////////////////////////////////////////////////////////////////// 2// Name: src/os2/dcclient.cpp 3// Purpose: wxClientDC class 4// Author: David Webster 5// Modified by: 6// Created: 09/21/99 7// RCS-ID: $Id: dcclient.cpp 39615 2006-06-07 13:26:00Z ABX $ 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/dcclient.h" 24 25#ifndef WX_PRECOMP 26 #include "wx/string.h" 27 #include "wx/log.h" 28 #include "wx/app.h" 29 #include "wx/window.h" 30#endif 31 32#include "wx/os2/private.h" 33 34// ---------------------------------------------------------------------------- 35// array/list types 36// ---------------------------------------------------------------------------- 37 38struct WXDLLEXPORT wxPaintDCInfo 39{ 40 wxPaintDCInfo( wxWindow* pWin 41 ,wxDC* pDC 42 ) 43 { 44 m_hWnd = pWin->GetHWND(); 45 m_hDC = pDC->GetHDC(); 46 m_nCount = 1; 47 } 48 49 WXHWND m_hWnd; // window for this DC 50 WXHDC m_hDC; // the DC handle 51 size_t m_nCount; // usage count 52}; // end of wxPaintDCInfot 53 54#include "wx/arrimpl.cpp" 55 56WX_DEFINE_OBJARRAY(wxArrayDCInfo); 57 58// ---------------------------------------------------------------------------- 59// macros 60// ---------------------------------------------------------------------------- 61 62 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC) 63 IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC) 64 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxWindowDC) 65 66// ---------------------------------------------------------------------------- 67// global variables 68// ---------------------------------------------------------------------------- 69 70static RECT g_paintStruct; 71 72#ifdef __WXDEBUG__ 73 // a global variable which we check to verify that wxPaintDC are only 74 // created in resopnse to WM_PAINT message - doing this from elsewhere is a 75 // common programming error among wxWidgets programmers and might lead to 76 // very subtle and difficult to debug refresh/repaint bugs. 77 int g_isPainting = 0; 78#endif // __WXDEBUG__ 79 80// =========================================================================== 81// implementation 82// =========================================================================== 83 84// ---------------------------------------------------------------------------- 85// wxWindowDC 86// ---------------------------------------------------------------------------- 87 88wxWindowDC::wxWindowDC() 89{ 90 m_pCanvas = NULL; 91 m_PageSize.cx = m_PageSize.cy = 0; 92 93} 94 95wxWindowDC::wxWindowDC( 96 wxWindow* pTheCanvas 97) 98{ 99 ERRORID vError; 100 wxString sError; 101 int nWidth, nHeight; 102 103 m_pCanvas = pTheCanvas; 104 DoGetSize(&nWidth, &nHeight); 105 m_PageSize.cx = nWidth; 106 m_PageSize.cy = nHeight; 107 m_hDC = (WXHDC) ::WinOpenWindowDC(GetWinHwnd(pTheCanvas) ); 108 109 // 110 // default under PM is that Window and Client DC's are the same 111 // so we offer a separate Presentation Space to use for the 112 // entire window. Otherwise, calling BeginPaint will just create 113 // chached-micro client presentation space 114 // 115 m_hPS = ::GpiCreatePS( vHabmain 116 ,m_hDC 117 ,&m_PageSize 118 ,PU_PELS | GPIF_LONG | GPIA_ASSOC 119 ); 120 if (!m_hPS) 121 { 122 vError = ::WinGetLastError(vHabmain); 123 sError = wxPMErrorToStr(vError); 124 wxLogError(_T("Unable to create presentation space. Error: %s\n"), sError.c_str()); 125 } 126 ::GpiAssociate(m_hPS, NULLHANDLE); 127 ::GpiAssociate(m_hPS, m_hDC); 128 129 // 130 // Set the wxWidgets color table 131 // 132 if (!::GpiCreateLogColorTable( m_hPS 133 ,0L 134 ,LCOLF_CONSECRGB 135 ,0L 136 ,(LONG)wxTheColourDatabase->m_nSize 137 ,(PLONG)wxTheColourDatabase->m_palTable 138 )) 139 { 140 vError = ::WinGetLastError(vHabmain); 141 sError = wxPMErrorToStr(vError); 142 wxLogError(_T("Unable to set current color table (3). Error: %s\n"), sError.c_str()); 143 } 144 ::GpiCreateLogColorTable( m_hPS 145 ,0L 146 ,LCOLF_RGB 147 ,0L 148 ,0L 149 ,NULL 150 ); 151 ::WinQueryWindowRect( GetWinHwnd(m_pCanvas) 152 ,&m_vRclPaint 153 ); 154 InitDC(); 155} // end of wxWindowDC::wxWindowDC 156 157void wxWindowDC::InitDC() 158{ 159 160 // 161 // The background mode is only used for text background and is set in 162 // DrawText() to OPAQUE as required, otherwise always TRANSPARENT, 163 // 164 ::GpiSetBackMix(GetHPS(), BM_LEAVEALONE); 165 166 // 167 // Default bg colour is pne of the window 168 // 169 SetBackground(wxBrush(m_pCanvas->GetBackgroundColour(), wxSOLID)); 170 171 m_pen.SetColour(*wxBLACK); 172 m_brush.SetColour(*wxWHITE); 173 InitializePalette(); 174 wxFont* pFont = new wxFont( 10, wxMODERN, wxNORMAL, wxBOLD ); 175 SetFont(*pFont); 176 delete pFont; 177 // 178 // OS/2 default vertical character alignment needs to match the other OS's 179 // 180 ::GpiSetTextAlignment((HPS)GetHPS(), TA_NORMAL_HORIZ, TA_BOTTOM); 181 182} // end of wxWindowDC::InitDC 183 184void wxWindowDC::DoGetSize( 185 int* pnWidth 186, int* pnHeight 187) const 188{ 189 wxCHECK_RET( m_pCanvas, _T("wxWindowDC without a window?") ); 190 m_pCanvas->GetSize( pnWidth 191 ,pnHeight 192 ); 193} // end of wxWindowDC::DoGetSize 194 195// ---------------------------------------------------------------------------- 196// wxClientDC 197// ---------------------------------------------------------------------------- 198 199wxClientDC::wxClientDC() 200{ 201 m_pCanvas = NULL; 202} 203 204wxClientDC::wxClientDC( 205 wxWindow* pTheCanvas 206) 207{ 208 SIZEL vSizl = { 0,0}; 209 ERRORID vError; 210 wxString sError; 211 212 m_pCanvas = pTheCanvas; 213 214 // 215 // default under PM is that Window and Client DC's are the same 216 // 217 m_hDC = (WXHDC) ::WinOpenWindowDC(GetWinHwnd(pTheCanvas)); 218 m_hPS = ::GpiCreatePS( wxGetInstance() 219 ,m_hDC 220 ,&vSizl 221 ,PU_PELS | GPIF_LONG | GPIA_ASSOC 222 ); 223 224 // Set the wxWidgets color table 225 if (!::GpiCreateLogColorTable( m_hPS 226 ,0L 227 ,LCOLF_CONSECRGB 228 ,0L 229 ,(LONG)wxTheColourDatabase->m_nSize 230 ,(PLONG)wxTheColourDatabase->m_palTable 231 )) 232 { 233 vError = ::WinGetLastError(vHabmain); 234 sError = wxPMErrorToStr(vError); 235 wxLogError(_T("Unable to set current color table (4). Error: %s\n"), sError.c_str()); 236 } 237 ::GpiCreateLogColorTable( m_hPS 238 ,0L 239 ,LCOLF_RGB 240 ,0L 241 ,0L 242 ,NULL 243 ); 244 // 245 // Set the DC/PS rectangle 246 // 247 ::WinQueryWindowRect( GetWinHwnd(m_pCanvas) 248 ,&m_vRclPaint 249 ); 250 InitDC(); 251} // end of wxClientDC::wxClientDC 252 253void wxClientDC::InitDC() 254{ 255 wxWindowDC::InitDC(); 256 257 // in wxUniv build we must manually do some DC adjustments usually 258 // performed by Windows for us 259#ifdef __WXUNIVERSAL__ 260 wxPoint ptOrigin = m_pCanvas->GetClientAreaOrigin(); 261 if ( ptOrigin.x || ptOrigin.y ) 262 { 263 // no need to shift DC origin if shift is null 264 SetDeviceOrigin(ptOrigin.x, ptOrigin.y); 265 } 266 267 // clip the DC to avoid overwriting the non client area 268 SetClippingRegion(wxPoint(0, 0), m_pCanvas->GetClientSize()); 269#endif // __WXUNIVERSAL__ 270} // end of wxClientDC::InitDC 271 272wxClientDC::~wxClientDC() 273{ 274} // end of wxClientDC::~wxClientDC 275 276void wxClientDC::DoGetSize( 277 int* pnWidth 278, int* pnHeight 279) const 280{ 281 wxCHECK_RET( m_pCanvas, _T("wxWindowDC without a window?") ); 282 m_pCanvas->GetClientSize( pnWidth 283 ,pnHeight 284 ); 285} // end of wxClientDC::DoGetSize 286 287// ---------------------------------------------------------------------------- 288// wxPaintDC 289// ---------------------------------------------------------------------------- 290 291wxArrayDCInfo wxPaintDC::ms_cache; 292 293wxPaintDC::wxPaintDC() 294{ 295 m_pCanvas = NULL; 296 m_hDC = 0; 297} 298 299wxPaintDC::wxPaintDC( 300 wxWindow* pCanvas 301) 302{ 303 wxCHECK_RET(pCanvas, wxT("NULL canvas in wxPaintDC ctor")); 304 305#ifdef __WXDEBUG__ 306 if (g_isPainting <= 0) 307 { 308 wxFAIL_MSG( wxT("wxPaintDC may be created only in EVT_PAINT handler!") ); 309 return; 310 } 311#endif // __WXDEBUG__ 312 313 m_pCanvas = pCanvas; 314 315 // 316 // Do we have a DC for this window in the cache? 317 // 318 wxPaintDCInfo* pInfo = FindInCache(); 319 320 if (pInfo) 321 { 322 m_hDC = pInfo->m_hDC; 323 pInfo->m_nCount++; 324 } 325 else // not in cache, create a new one 326 { 327 HPS hPS; 328 329 m_hDC = ::WinOpenWindowDC(GetWinHwnd(m_pCanvas)); 330 hPS = ::WinBeginPaint( GetWinHwnd(m_pCanvas) 331 ,NULLHANDLE 332 ,&g_paintStruct 333 ); 334 if(hPS) 335 { 336 ::GpiAssociate(hPS, m_hDC); 337 m_hOldPS = m_hPS; 338 m_hPS = hPS; 339 ::GpiCreateLogColorTable( m_hPS 340 ,0L 341 ,LCOLF_CONSECRGB 342 ,0L 343 ,(LONG)wxTheColourDatabase->m_nSize 344 ,(PLONG)wxTheColourDatabase->m_palTable 345 ); 346 ::GpiCreateLogColorTable( m_hPS 347 ,0L 348 ,LCOLF_RGB 349 ,0L 350 ,0L 351 ,NULL 352 ); 353 354 ::WinFillRect(hPS, &g_paintStruct, m_pCanvas->GetBackgroundColour().GetPixel()); 355 ::WinQueryWindowRect( GetWinHwnd(m_pCanvas) 356 ,&m_vRclPaint 357 ); 358 } 359 360 m_bIsPaintTime = true; 361 ms_cache.Add(new wxPaintDCInfo(m_pCanvas, this)); 362 } 363 InitDC(); 364} // end of wxPaintDC::wxPaintDC 365 366wxPaintDC::~wxPaintDC() 367{ 368 if ( m_hDC ) 369 { 370 SelectOldObjects(m_hDC); 371 372 size_t nIndex; 373 wxPaintDCInfo* pInfo = FindInCache(&nIndex); 374 375 wxCHECK_RET( pInfo, wxT("existing DC should have a cache entry") ); 376 377 if ( !--pInfo->m_nCount ) 378 { 379 ::WinEndPaint(m_hPS); 380 m_hPS = m_hOldPS; 381 m_bIsPaintTime = false; 382 ms_cache.RemoveAt(nIndex); 383 } 384 //else: cached DC entry is still in use 385 386 // prevent the base class dtor from ReleaseDC()ing it again 387 m_hDC = 0; 388 } 389} 390 391wxPaintDCInfo* wxPaintDC::FindInCache( 392 size_t* pIndex 393) const 394{ 395 wxPaintDCInfo* pInfo = NULL; 396 size_t nCache = ms_cache.GetCount(); 397 398 for (size_t n = 0; n < nCache; n++) 399 { 400 pInfo = &ms_cache[n]; 401 if (pInfo->m_hWnd == m_pCanvas->GetHWND()) 402 { 403 if (pIndex) 404 *pIndex = n; 405 break; 406 } 407 } 408 return pInfo; 409} // end of wxPaintDC::FindInCache 410 411// find the entry for this DC in the cache (keyed by the window) 412WXHDC wxPaintDC::FindDCInCache( 413 wxWindow* pWin 414) 415{ 416 wxPaintDCInfo* pInfo = NULL; 417 size_t nCache = ms_cache.GetCount(); 418 419 for (size_t n = 0; n < nCache; n++) 420 { 421 pInfo = &ms_cache[n]; 422 if (pInfo->m_hWnd == pWin->GetHWND()) 423 { 424 return pInfo->m_hDC; 425 } 426 } 427 return 0; 428} // end of wxPaintDC::FindInCache 429