+// This is a base class for two concrete subclasses below and contains HDC
+// cached for the duration of the WM_PAINT processing together with some
+// bookkeeping information.
+class wxPaintDCInfo
+{
+public:
+ wxPaintDCInfo(HDC hdc)
+ : m_hdc(hdc)
+ {
+ }
+
+ // The derived class must perform some cleanup.
+ virtual ~wxPaintDCInfo() = 0;
+
+ WXHDC GetHDC() const { return (WXHDC)m_hdc; }
+
+protected:
+ const HDC m_hdc;
+
+ wxDECLARE_NO_COPY_CLASS(wxPaintDCInfo);
+};
+
+namespace
+{
+
+// This subclass contains information for the HDCs we create ourselves, i.e.
+// those for which we call BeginPaint() -- and hence need to call EndPaint().
+class wxPaintDCInfoOur : public wxPaintDCInfo
+{
+public:
+ wxPaintDCInfoOur(wxWindow* win)
+ : wxPaintDCInfo(::BeginPaint(GetHwndOf(win), GetPaintStructPtr(m_ps))),
+ m_hwnd(GetHwndOf(win))
+ {
+ }
+
+ virtual ~wxPaintDCInfoOur()
+ {
+ ::EndPaint(m_hwnd, &m_ps);
+ }
+
+private:
+ // This helper is only needed in order to call it from the ctor initializer
+ // list.
+ static PAINTSTRUCT* GetPaintStructPtr(PAINTSTRUCT& ps)
+ {
+ wxZeroMemory(ps);
+ return &ps;
+ }
+
+ const HWND m_hwnd;
+ PAINTSTRUCT m_ps;
+
+ wxDECLARE_NO_COPY_CLASS(wxPaintDCInfoOur);
+};
+
+// This subclass contains information for the HDCs we receive from outside, as
+// WPARAM of WM_PAINT itself.
+class wxPaintDCInfoExternal : public wxPaintDCInfo
+{
+public:
+ wxPaintDCInfoExternal(HDC hdc)
+ : wxPaintDCInfo(hdc),
+ m_state(::SaveDC(hdc))
+ {
+ }
+
+ virtual ~wxPaintDCInfoExternal()
+ {
+ ::RestoreDC(m_hdc, m_state);
+ }
+
+private:
+ const int m_state;
+
+ wxDECLARE_NO_COPY_CLASS(wxPaintDCInfoExternal);
+};
+
+// The global map containing HDC to use for the given window. The entries in
+// this map only exist during WM_PAINT processing and are destroyed when it is
+// over.
+//
+// It is needed because in some circumstances it can happen that more than one
+// wxPaintDC is created for the same window during its WM_PAINT handling (and
+// as this can happen implicitly, e.g. by calling a function in some library,
+// this can be quite difficult to find) but we need to reuse the same HDC for
+// all of them because we can't call BeginPaint() more than once. So we cache
+// the first HDC created for the window in this map and then reuse it later if
+// needed. And, of course, remove it from the map when the painting is done.
+WX_DECLARE_HASH_MAP(wxWindow *, wxPaintDCInfo *,
+ wxPointerHash, wxPointerEqual,
+ PaintDCInfos);
+
+PaintDCInfos gs_PaintDCInfos;
+
+} // anonymous namespace
+
+// ----------------------------------------------------------------------------
+// global variables
+// ----------------------------------------------------------------------------
+
+#ifdef wxHAS_PAINT_DEBUG
+ // a global variable which we check to verify that wxPaintDC are only
+ // created in response to WM_PAINT message - doing this from elsewhere is a
+ // common programming error among wxWidgets programmers and might lead to
+ // very subtle and difficult to debug refresh/repaint bugs.
+ int g_isPainting = 0;
+#endif // wxHAS_PAINT_DEBUG
+
+// ===========================================================================
+// implementation
+// ===========================================================================
+
+// ----------------------------------------------------------------------------
+// wxMSWWindowDCImpl
+// ----------------------------------------------------------------------------
+
+IMPLEMENT_ABSTRACT_CLASS(wxWindowDCImpl, wxMSWDCImpl)
+
+wxWindowDCImpl::wxWindowDCImpl( wxDC *owner ) :
+ wxMSWDCImpl( owner )
+{
+}
+
+wxWindowDCImpl::wxWindowDCImpl( wxDC *owner, wxWindow *window ) :
+ wxMSWDCImpl( owner )
+{
+ wxCHECK_RET( window, wxT("invalid window in wxWindowDCImpl") );
+
+ m_window = window;
+ m_hDC = (WXHDC) ::GetWindowDC(GetHwndOf(m_window));
+
+ // m_bOwnsDC was already set to false in the base class ctor, so the DC
+ // will be released (and not deleted) in ~wxDC
+ InitDC();
+}
+
+void wxWindowDCImpl::InitDC()
+{
+ // the background mode is only used for text background and is set in
+ // DrawText() to OPAQUE as required, otherwise always TRANSPARENT,
+ ::SetBkMode(GetHdc(), TRANSPARENT);
+
+ // since we are a window dc we need to grab the palette from the window
+#if wxUSE_PALETTE
+ InitializePalette();