1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxClientDC class 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // =========================================================================== 
  14 // =========================================================================== 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  21     #pragma implementation "dcclient.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  31 #include "wx/string.h" 
  33 #include "wx/window.h" 
  35 #include "wx/msw/private.h" 
  37 #include "wx/dcclient.h" 
  39 // ---------------------------------------------------------------------------- 
  41 // ---------------------------------------------------------------------------- 
  43 struct WXDLLEXPORT wxPaintDCInfo
 
  45     wxPaintDCInfo(wxWindow 
*win
, wxDC 
*dc
) 
  47         hwnd 
= win
->GetHWND(); 
  52     WXHWND    hwnd
;       // window for this DC 
  53     WXHDC     hdc
;        // the DC handle 
  54     size_t    count
;      // usage count 
  57 #include "wx/arrimpl.cpp" 
  59 WX_DEFINE_OBJARRAY(wxArrayDCInfo
); 
  61 // ---------------------------------------------------------------------------- 
  63 // ---------------------------------------------------------------------------- 
  65 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
) 
  66 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
, wxWindowDC
) 
  67 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
, wxClientDC
) 
  68 IMPLEMENT_CLASS(wxPaintDCEx
, wxPaintDC
) 
  70 // ---------------------------------------------------------------------------- 
  72 // ---------------------------------------------------------------------------- 
  74 static PAINTSTRUCT g_paintStruct
; 
  77     // a global variable which we check to verify that wxPaintDC are only 
  78     // created in resopnse to WM_PAINT message - doing this from elsewhere is a 
  79     // common programming error among wxWindows programmers and might lead to 
  80     // very subtle and difficult to debug refresh/repaint bugs. 
  84 // =========================================================================== 
  86 // =========================================================================== 
  88 // ---------------------------------------------------------------------------- 
  90 // ---------------------------------------------------------------------------- 
  92 wxWindowDC::wxWindowDC() 
  97 wxWindowDC::wxWindowDC(wxWindow 
*canvas
) 
  99     wxCHECK_RET( canvas
, _T("invalid window in wxWindowDC") ); 
 102     m_hDC 
= (WXHDC
) ::GetWindowDC(GetHwndOf(m_canvas
)); 
 104     // m_bOwnsDC was already set to false in the base class ctor, so the DC 
 105     // will be released (and not deleted) in ~wxDC 
 109 void wxWindowDC::InitDC() 
 111     // the background mode is only used for text background and is set in 
 112     // DrawText() to OPAQUE as required, otherwise always TRANSPARENT, 
 113     ::SetBkMode(GetHdc(), TRANSPARENT
); 
 115     // default bg colour is pne of the window 
 116     SetBackground(wxBrush(m_canvas
->GetBackgroundColour(), wxSOLID
)); 
 118     // since we are a window dc we need to grab the palette from the window 
 124 void wxWindowDC::DoGetSize(int *width
, int *height
) const 
 126     wxCHECK_RET( m_canvas
, _T("wxWindowDC without a window?") ); 
 128     m_canvas
->GetSize(width
, height
); 
 131 // ---------------------------------------------------------------------------- 
 133 // ---------------------------------------------------------------------------- 
 135 wxClientDC::wxClientDC() 
 140 wxClientDC::wxClientDC(wxWindow 
*canvas
) 
 142     wxCHECK_RET( canvas
, _T("invalid window in wxClientDC") ); 
 145     m_hDC 
= (WXHDC
)::GetDC(GetHwndOf(m_canvas
)); 
 147     // m_bOwnsDC was already set to false in the base class ctor, so the DC 
 148     // will be released (and not deleted) in ~wxDC 
 153 void wxClientDC::InitDC() 
 155     wxWindowDC::InitDC(); 
 157     // in wxUniv build we must manually do some DC adjustments usually 
 158     // performed by Windows for us 
 160     // we also need to take the menu/toolbar manually into account under 
 161     // Windows CE because they're just another control there, not anything 
 162     // special as usually under Windows 
 163 #if defined(__WXUNIVERSAL__) || defined(__WXWINCE__) 
 164     wxPoint ptOrigin 
= m_canvas
->GetClientAreaOrigin(); 
 165     if ( ptOrigin
.x 
|| ptOrigin
.y 
) 
 167         // no need to shift DC origin if shift is null 
 168         SetDeviceOrigin(ptOrigin
.x
, ptOrigin
.y
); 
 171     // clip the DC to avoid overwriting the non client area 
 172     SetClippingRegion(wxPoint(0, 0), m_canvas
->GetClientSize()); 
 173 #endif // __WXUNIVERSAL__ || __WXWINCE__ 
 176 wxClientDC::~wxClientDC() 
 180 void wxClientDC::DoGetSize(int *width
, int *height
) const 
 182     wxCHECK_RET( m_canvas
, _T("wxClientDC without a window?") ); 
 184     m_canvas
->GetClientSize(width
, height
); 
 187 // ---------------------------------------------------------------------------- 
 189 // ---------------------------------------------------------------------------- 
 191 // VZ: initial implementation (by JACS) only remembered the last wxPaintDC 
 192 //     created and tried to reuse it - this was supposed to take care of a 
 193 //     situation when a derived class OnPaint() calls base class OnPaint() 
 194 //     because in this case ::BeginPaint() shouldn't be called second time. 
 196 //     I'm not sure how useful this is, however we must remember the HWND 
 197 //     associated with the last HDC as well - otherwise we may (and will!) try 
 198 //     to reuse the HDC for another HWND which is a nice recipe for disaster. 
 200 //     So we store a list of windows for which we already have the DC and not 
 201 //     just one single hDC. This seems to work, but I'm really not sure about 
 202 //     the usefullness of the whole idea - IMHO it's much better to not call 
 203 //     base class OnPaint() at all, or, if we really want to allow it, add a 
 204 //     "wxPaintDC *" parameter to wxPaintEvent which should be used if it's 
 205 //     !NULL instead of creating a new DC. 
 207 wxArrayDCInfo 
wxPaintDC::ms_cache
; 
 209 wxPaintDC::wxPaintDC() 
 214 wxPaintDC::wxPaintDC(wxWindow 
*canvas
) 
 216     wxCHECK_RET( canvas
, wxT("NULL canvas in wxPaintDC ctor") ); 
 219     if ( g_isPainting 
<= 0 ) 
 221         wxFAIL_MSG( wxT("wxPaintDC may be created only in EVT_PAINT handler!") ); 
 225 #endif // __WXDEBUG__ 
 229     // do we have a DC for this window in the cache? 
 230     wxPaintDCInfo 
*info 
= FindInCache(); 
 236     else // not in cache, create a new one 
 238         m_hDC 
= (WXHDC
)::BeginPaint(GetHwndOf(m_canvas
), &g_paintStruct
); 
 240             ms_cache
.Add(new wxPaintDCInfo(m_canvas
, this)); 
 243     // (re)set the DC parameters. 
 244     // Note: at this point m_hDC can be NULL under MicroWindows, when dragging. 
 249 wxPaintDC::~wxPaintDC() 
 253         SelectOldObjects(m_hDC
); 
 256         wxPaintDCInfo 
*info 
= FindInCache(&index
); 
 258         wxCHECK_RET( info
, wxT("existing DC should have a cache entry") ); 
 260         if ( !--info
->count 
) 
 262             ::EndPaint(GetHwndOf(m_canvas
), &g_paintStruct
); 
 264             ms_cache
.RemoveAt(index
); 
 266             // Reduce the number of bogus reports of non-freed memory 
 268             if (ms_cache
.IsEmpty()) 
 271         //else: cached DC entry is still in use 
 273         // prevent the base class dtor from ReleaseDC()ing it again 
 278 wxPaintDCInfo 
*wxPaintDC::FindInCache(size_t *index
) const 
 280     wxPaintDCInfo 
*info 
= NULL
; 
 281     size_t nCache 
= ms_cache
.GetCount(); 
 282     for ( size_t n 
= 0; n 
< nCache
; n
++ ) 
 284         wxPaintDCInfo 
*info1 
= &ms_cache
[n
]; 
 285         if ( info1
->hwnd 
== m_canvas
->GetHWND() ) 
 297 // find the entry for this DC in the cache (keyed by the window) 
 298 WXHDC 
wxPaintDC::FindDCInCache(wxWindow
* win
) 
 300     size_t nCache 
= ms_cache
.GetCount(); 
 301     for ( size_t n 
= 0; n 
< nCache
; n
++ ) 
 303         wxPaintDCInfo 
*info 
= &ms_cache
[n
]; 
 304         if ( info
->hwnd 
== win
->GetHWND() ) 
 316 // TODO: don't duplicate wxPaintDC code here!! 
 318 wxPaintDCEx::wxPaintDCEx(wxWindow 
*canvas
, WXHDC dc
) : saveState(0) 
 320     wxCHECK_RET( dc
, wxT("wxPaintDCEx requires an existing device context") ); 
 324     wxPaintDCInfo 
*info 
= FindInCache(); 
 330     else // not in cache, create a new one 
 333         ms_cache
.Add(new wxPaintDCInfo(m_canvas
, this)); 
 334         saveState 
= SaveDC((HDC
) dc
); 
 338 wxPaintDCEx::~wxPaintDCEx() 
 341     wxPaintDCInfo 
*info 
= FindInCache(&index
); 
 343     wxCHECK_RET( info
, wxT("existing DC should have a cache entry") ); 
 345     if ( !--info
->count 
) 
 347         RestoreDC((HDC
) m_hDC
, saveState
); 
 348         ms_cache
.RemoveAt(index
); 
 350         // Reduce the number of bogus reports of non-freed memory 
 352         if (ms_cache
.IsEmpty()) 
 355     //else: cached DC entry is still in use 
 357     // prevent the base class dtor from ReleaseDC()ing it again