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
* pWin
41 m_hWnd
= pWin
->GetHWND();
42 m_hDC
= pDC
->GetHDC();
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
51 #include "wx/arrimpl.cpp"
53 WX_DEFINE_OBJARRAY(wxArrayDCInfo
);
55 // ----------------------------------------------------------------------------
57 // ----------------------------------------------------------------------------
59 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC
, wxDC
)
60 IMPLEMENT_DYNAMIC_CLASS(wxClientDC
, wxWindowDC
)
61 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC
, wxWindowDC
)
63 // ----------------------------------------------------------------------------
65 // ----------------------------------------------------------------------------
67 static RECT g_paintStruct
;
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.
77 // ===========================================================================
79 // ===========================================================================
81 // ----------------------------------------------------------------------------
83 // ----------------------------------------------------------------------------
85 wxWindowDC::wxWindowDC()
90 wxWindowDC::wxWindowDC(
97 m_pCanvas
= pTheCanvas
;
98 m_hDC
= (WXHDC
) ::WinOpenWindowDC(GetWinHwnd(pTheCanvas
) );
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
106 m_hPS
= GpiCreatePS( m_hab
109 ,PU_PELS
| GPIF_LONG
| GPIA_ASSOC
111 ::GpiAssociate(m_hPS
, NULLHANDLE
);
112 ::GpiAssociate(m_hPS
, m_hDC
);
113 // Set the wxWindows color table
114 if (!::GpiCreateLogColorTable( m_hPS
118 ,(LONG
)wxTheColourDatabase
->m_nSize
119 ,(PLONG
)wxTheColourDatabase
->m_palTable
122 vError
= ::WinGetLastError(vHabmain
);
123 sError
= wxPMErrorToStr(vError
);
124 wxLogError("Unable to set current color table. Error: %s\n", sError
);
126 ::GpiCreateLogColorTable( m_hPS
133 SetBackground(wxBrush(m_pCanvas
->GetBackgroundColour(), wxSOLID
));
134 ::WinQueryWindowRect( GetWinHwnd(m_pCanvas
)
139 wxWindowDC::~wxWindowDC()
141 if (m_pCanvas
&& m_hDC
)
143 SelectOldObjects(m_hDC
);
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
152 ::GpiAssociate(m_hPS
, NULLHANDLE
);
153 ::GpiDestroyPS(m_hPS
);
161 // ----------------------------------------------------------------------------
163 // ----------------------------------------------------------------------------
165 wxClientDC::wxClientDC()
170 wxClientDC::wxClientDC(
174 SIZEL vSizl
= { 0,0};
178 m_pCanvas
= pTheCanvas
;
181 // default under PM is that Window and Client DC's are the same
183 m_hDC
= (WXHDC
) ::WinOpenWindowDC(GetWinHwnd(pTheCanvas
));
184 m_hPS
= ::GpiCreatePS( wxGetInstance()
187 ,PU_PELS
| GPIF_LONG
| GPIA_ASSOC
190 // Set the wxWindows color table
191 if (!::GpiCreateLogColorTable( m_hPS
195 ,(LONG
)wxTheColourDatabase
->m_nSize
196 ,(PLONG
)wxTheColourDatabase
->m_palTable
199 vError
= ::WinGetLastError(vHabmain
);
200 sError
= wxPMErrorToStr(vError
);
201 wxLogError("Unable to set current color table. Error: %s\n", sError
);
203 ::GpiCreateLogColorTable( m_hPS
211 // Default mode is BM_LEAVEALONE so we make no call Set the mix
213 SetBackground(wxBrush( m_pCanvas
->GetBackgroundColour()
218 // Set the DC/PS rectangle
220 ::WinQueryWindowRect( GetWinHwnd(m_pCanvas
)
223 } // end of wxClientDC::wxClientDC
225 wxClientDC::~wxClientDC()
227 if ( m_pCanvas
&& GetHdc() )
229 SelectOldObjects(m_hDC
);
232 // We don't explicitly release Device contexts in PM and
233 // the cached micro PS is already gone
237 } // end of wxClientDC::~wxClientDC
239 // ----------------------------------------------------------------------------
241 // ----------------------------------------------------------------------------
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.
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.
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.
259 wxArrayDCInfo
wxPaintDC::ms_cache
;
261 wxPaintDC::wxPaintDC()
267 wxPaintDC::wxPaintDC(
271 wxCHECK_RET(pCanvas
, wxT("NULL canvas in wxPaintDC ctor"));
275 if (g_isPainting
<= 0)
277 wxFAIL_MSG( wxT("wxPaintDC may be created only in EVT_PAINT handler!") );
280 #endif // __WXDEBUG__
285 // Do we have a DC for this window in the cache?
287 wxPaintDCInfo
* pInfo
= FindInCache();
291 m_hDC
= pInfo
->m_hDC
;
294 else // not in cache, create a new one
298 hPS
= ::WinBeginPaint( GetWinHwnd(m_pCanvas
)
310 ::GpiCreateLogColorTable( m_hPS
314 ,(LONG
)wxTheColourDatabase
->m_nSize
315 ,(PLONG
)wxTheColourDatabase
->m_palTable
317 ::GpiCreateLogColorTable( m_hPS
325 ::WinFillRect(hPS
, &g_paintStruct
, m_pCanvas
->GetBackgroundColour().GetPixel());
326 ::WinQueryWindowRect( GetWinHwnd(m_pCanvas
)
331 m_bIsPaintTime
= TRUE
;
332 m_hDC
= (WXHDC
) -1; // to satisfy those anonizmous efforts
333 ms_cache
.Add(new wxPaintDCInfo(m_pCanvas
, this));
335 SetBackground(wxBrush(m_pCanvas
->GetBackgroundColour(), wxSOLID
));
338 wxPaintDC::~wxPaintDC()
342 SelectOldObjects(m_hDC
);
345 wxPaintDCInfo
* pInfo
= FindInCache(&nIndex
);
347 wxCHECK_RET( pInfo
, wxT("existing DC should have a cache entry") );
349 if ( !--pInfo
->m_nCount
)
351 ::WinEndPaint(m_hPS
);
353 m_bIsPaintTime
= FALSE
;
354 ms_cache
.Remove(nIndex
);
356 //else: cached DC entry is still in use
358 // prevent the base class dtor from ReleaseDC()ing it again
363 wxPaintDCInfo
* wxPaintDC::FindInCache(
367 wxPaintDCInfo
* pInfo
= NULL
;
368 size_t nCache
= ms_cache
.GetCount();
370 for (size_t n
= 0; n
< nCache
; n
++)
372 pInfo
= &ms_cache
[n
];
373 if (pInfo
->m_hWnd
== m_pCanvas
->GetHWND())
381 } // end of wxPaintDC::FindInCache