1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxClientDC class 
   4 // Author:      David Webster 
   8 // Copyright:   (c) David Webster 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // =========================================================================== 
  14 // =========================================================================== 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  23 #include "wx/string.h" 
  25 #include "wx/window.h" 
  27 #include "wx/os2/private.h" 
  29 #include "wx/dcclient.h" 
  31 // ---------------------------------------------------------------------------- 
  33 // ---------------------------------------------------------------------------- 
  35 struct WXDLLEXPORT wxPaintDCInfo
 
  37     wxPaintDCInfo(wxWindow 
*win
, wxDC 
*dc
) 
  39         hwnd 
= win
->GetHWND(); 
  44     WXHWND    hwnd
;       // window for this DC 
  45     WXHDC     hdc
;        // the DC handle 
  46     size_t    count
;      // usage count 
  49 #include "wx/arrimpl.cpp" 
  51 WX_DEFINE_OBJARRAY(wxArrayDCInfo
); 
  53 // ---------------------------------------------------------------------------- 
  55 // ---------------------------------------------------------------------------- 
  57     IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
) 
  58     IMPLEMENT_DYNAMIC_CLASS(wxClientDC
, wxWindowDC
) 
  59     IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
, wxWindowDC
) 
  61 // ---------------------------------------------------------------------------- 
  63 // ---------------------------------------------------------------------------- 
  65 static RECT        g_paintStruct
; 
  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. 
  75 // =========================================================================== 
  77 // =========================================================================== 
  79 // ---------------------------------------------------------------------------- 
  81 // ---------------------------------------------------------------------------- 
  83 wxWindowDC::wxWindowDC() 
  88 wxWindowDC::wxWindowDC(wxWindow 
*the_canvas
) 
  90   m_pCanvas 
= the_canvas
; 
  91   m_hDC 
= (WXHDC
) ::WinOpenWindowDC(GetWinHwnd(the_canvas
) ); 
  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 
  99    m_hPS 
= GpiCreatePS( m_hab
 
 102                        ,PU_PELS 
| GPIF_LONG 
| GPIA_ASSOC
 
 104   ::GpiAssociate(m_hPS
, NULLHANDLE
); 
 105   ::GpiAssociate(m_hPS
, m_hDC
); 
 106   SetBackground(wxBrush(m_pCanvas
->GetBackgroundColour(), wxSOLID
)); 
 109 wxWindowDC::~wxWindowDC() 
 111   if (m_pCanvas 
&& m_hDC
) 
 113     SelectOldObjects(m_hDC
); 
 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 
 122         ::GpiAssociate(m_hPS
, NULLHANDLE
); 
 123         ::GpiDestroyPS(m_hPS
); 
 132 // ---------------------------------------------------------------------------- 
 134 // ---------------------------------------------------------------------------- 
 136 wxClientDC::wxClientDC() 
 141 wxClientDC::wxClientDC(wxWindow 
*the_canvas
) 
 143     SIZEL                           vSizl 
= { 0,0}; 
 145     m_pCanvas 
= the_canvas
; 
 148     // default under PM is that Window and Client DC's are the same 
 150     m_hDC 
= (WXHDC
) ::WinOpenWindowDC(GetWinHwnd(the_canvas
)); 
 151     m_hPS 
= ::GpiCreatePS( wxGetInstance() 
 154                           ,PU_PELS 
| GPIF_LONG 
| GPIA_ASSOC
 
 158     // Default mode is BM_LEAVEALONE so we make no call Set the mix 
 160     SetBackground(wxBrush( m_pCanvas
->GetBackgroundColour() 
 166 wxClientDC::~wxClientDC() 
 168   if ( m_pCanvas 
&& GetHdc() ) 
 170     SelectOldObjects(m_hDC
); 
 172     // We don't explicitly release Device contexts in PM and 
 173     // the cached micro PS is already gone 
 179 // ---------------------------------------------------------------------------- 
 181 // ---------------------------------------------------------------------------- 
 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. 
 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. 
 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. 
 199 wxArrayDCInfo 
wxPaintDC::ms_cache
; 
 201 wxPaintDC::wxPaintDC() 
 207 wxPaintDC::wxPaintDC( 
 211     wxCHECK_RET( canvas
, wxT("NULL canvas in wxPaintDC ctor") ); 
 214     if (g_isPainting 
<= 0) 
 216         wxFAIL_MSG( wxT("wxPaintDC may be created only in EVT_PAINT handler!") ); 
 219 #endif // __WXDEBUG__ 
 224     // Do we have a DC for this window in the cache? 
 226     wxPaintDCInfo
*                  pInfo 
= FindInCache(); 
 233     else // not in cache, create a new one 
 237         hPS 
= ::WinBeginPaint( GetWinHwnd(m_pCanvas
) 
 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)); 
 251     SetBackground(wxBrush(m_pCanvas
->GetBackgroundColour(), wxSOLID
)); 
 254 wxPaintDC::~wxPaintDC() 
 258         SelectOldObjects(m_hDC
); 
 261         wxPaintDCInfo 
*info 
= FindInCache(&index
); 
 263         wxCHECK_RET( info
, wxT("existing DC should have a cache entry") ); 
 265         if ( !--info
->count 
) 
 267             ::WinEndPaint(m_hPS
); 
 269             m_bIsPaintTime 
= FALSE
; 
 270             ms_cache
.Remove(index
); 
 272         //else: cached DC entry is still in use 
 274         // prevent the base class dtor from ReleaseDC()ing it again 
 279 wxPaintDCInfo 
*wxPaintDC::FindInCache(size_t *index
) const 
 281     wxPaintDCInfo 
*info 
= NULL
; 
 282     size_t nCache 
= ms_cache
.GetCount(); 
 283     for ( size_t n 
= 0; n 
< nCache
; n
++ ) 
 286         if ( info
->hwnd 
== m_pCanvas
->GetHWND() )