1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        wx/dcbuffer.h
3 // Purpose:     wxBufferedDC class
4 // Author:      Ron Lee <ron@debian.org>
5 // Modified by: Vadim Zeitlin (refactored, added bg preservation)
6 // Created:     16/03/02
7 // RCS-ID:      $Id: dcbuffer.h 61872 2009-09-09 22:37:05Z VZ $
8 // Copyright:   (c) Ron Lee
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11 
12 #ifndef _WX_DCBUFFER_H_
13 #define _WX_DCBUFFER_H_
14 
15 #include "wx/dcmemory.h"
16 #include "wx/dcclient.h"
17 #include "wx/window.h"
18 
19 // Split platforms into two groups - those which have well-working
20 // double-buffering by default, and those which do not.
21 #if defined(__WXMAC__) || defined(__WXGTK20__) || defined(__WXDFB__)
22     #define wxALWAYS_NATIVE_DOUBLE_BUFFER       1
23 #else
24     #define wxALWAYS_NATIVE_DOUBLE_BUFFER       0
25 #endif
26 
27 
28 // ----------------------------------------------------------------------------
29 // Double buffering helper.
30 // ----------------------------------------------------------------------------
31 
32 // Assumes the buffer bitmap covers the entire scrolled window,
33 // and prepares the window DC accordingly
34 #define wxBUFFER_VIRTUAL_AREA       0x01
35 
36 // Assumes the buffer bitmap only covers the client area;
37 // does not prepare the window DC
38 #define wxBUFFER_CLIENT_AREA        0x02
39 
40 class WXDLLEXPORT wxBufferedDC : public wxMemoryDC
41 {
42 public:
43     // Default ctor, must subsequently call Init for two stage construction.
wxBufferedDC()44     wxBufferedDC()
45         : m_dc(NULL),
46           m_buffer(NULL),
47           m_style(0)
48     {
49     }
50 
51     // Construct a wxBufferedDC using a user supplied buffer.
52     wxBufferedDC(wxDC *dc,
53                  wxBitmap& buffer = wxNullBitmap,
54                  int style = wxBUFFER_CLIENT_AREA)
m_dc(NULL)55         : m_dc(NULL), m_buffer(NULL)
56     {
57         Init(dc, buffer, style);
58     }
59 
60     // Construct a wxBufferedDC with an internal buffer of 'area'
61     // (where area is usually something like the size of the window
62     // being buffered)
63     wxBufferedDC(wxDC *dc, const wxSize& area, int style = wxBUFFER_CLIENT_AREA)
m_dc(NULL)64         : m_dc(NULL), m_buffer(NULL)
65     {
66         Init(dc, area, style);
67     }
68 
69     // The usually desired  action in the dtor is to blit the buffer.
~wxBufferedDC()70     virtual ~wxBufferedDC()
71     {
72         if ( m_dc )
73             UnMask();
74     }
75 
76     // These reimplement the actions of the ctors for two stage creation
77     void Init(wxDC *dc,
78               wxBitmap& buffer = wxNullBitmap,
79               int style = wxBUFFER_CLIENT_AREA)
80     {
81         InitCommon(dc, style);
82 
83         m_buffer = &buffer;
84 
85         UseBuffer();
86     }
87 
88     void Init(wxDC *dc, const wxSize &area, int style = wxBUFFER_CLIENT_AREA)
89     {
90         InitCommon(dc, style);
91 
92         UseBuffer(area.x, area.y);
93     }
94 
95     // Blits the buffer to the dc, and detaches the dc from the buffer (so it
96     // can be effectively used once only).
97     //
98     // Usually called in the dtor or by the dtor of derived classes if the
99     // BufferedDC must blit before the derived class (which may own the dc it's
100     // blitting to) is destroyed.
UnMask()101     void UnMask()
102     {
103         wxCHECK_RET( m_dc, wxT("no underlying wxDC?") );
104         wxASSERT_MSG( m_buffer && m_buffer->IsOk(), wxT("invalid backing store") );
105 
106         wxCoord x = 0,
107                 y = 0;
108 
109         if ( m_style & wxBUFFER_CLIENT_AREA )
110             GetDeviceOrigin(&x, &y);
111 
112         m_dc->Blit(0, 0, m_buffer->GetWidth(), m_buffer->GetHeight(),
113                    this, -x, -y );
114         m_dc = NULL;
115     }
116 
117     // Set and get the style
SetStyle(int style)118     void SetStyle(int style) { m_style = style; }
GetStyle()119     int GetStyle() const { return m_style; }
120 
121 private:
122     // common part of Init()s
InitCommon(wxDC * dc,int style)123     void InitCommon(wxDC *dc, int style)
124     {
125         wxASSERT_MSG( !m_dc, wxT("wxBufferedDC already initialised") );
126 
127         m_dc = dc;
128         m_style = style;
129 
130         // inherit the same layout direction as the original DC
131         if (dc && dc->IsOk())
132             SetLayoutDirection(dc->GetLayoutDirection());
133     }
134 
135     // check that the bitmap is valid and use it
136     void UseBuffer(wxCoord w = -1, wxCoord h = -1);
137 
138     // the underlying DC to which we copy everything drawn on this one in
139     // UnMask()
140     //
141     // NB: Without the existence of a wxNullDC, this must be a pointer, else it
142     //     could probably be a reference.
143     wxDC *m_dc;
144 
145     // the buffer (selected in this DC), initially invalid
146     wxBitmap *m_buffer;
147 
148     // the buffering style
149     int m_style;
150 
151     DECLARE_DYNAMIC_CLASS(wxBufferedDC)
152     DECLARE_NO_COPY_CLASS(wxBufferedDC)
153 };
154 
155 
156 // ----------------------------------------------------------------------------
157 // Double buffered PaintDC.
158 // ----------------------------------------------------------------------------
159 
160 // Creates a double buffered wxPaintDC, optionally allowing the
161 // user to specify their own buffer to use.
162 class WXDLLEXPORT wxBufferedPaintDC : public wxBufferedDC
163 {
164 public:
165     // If no bitmap is supplied by the user, a temporary one will be created.
166     wxBufferedPaintDC(wxWindow *window, wxBitmap& buffer, int style = wxBUFFER_CLIENT_AREA)
m_paintdc(window)167         : m_paintdc(window)
168     {
169         // If we're buffering the virtual window, scale the paint DC as well
170         if (style & wxBUFFER_VIRTUAL_AREA)
171             window->PrepareDC( m_paintdc );
172 
173         if( buffer.IsOk() )
174             Init(&m_paintdc, buffer, style);
175         else
176             Init(&m_paintdc, GetBufferedSize(window, style), style);
177     }
178 
179     // If no bitmap is supplied by the user, a temporary one will be created.
180     wxBufferedPaintDC(wxWindow *window, int style = wxBUFFER_CLIENT_AREA)
m_paintdc(window)181         : m_paintdc(window)
182     {
183         // If we're using the virtual window, scale the paint DC as well
184         if (style & wxBUFFER_VIRTUAL_AREA)
185             window->PrepareDC( m_paintdc );
186 
187         Init(&m_paintdc, GetBufferedSize(window, style), style);
188     }
189 
190     // default copy ctor ok.
191 
~wxBufferedPaintDC()192     virtual ~wxBufferedPaintDC()
193     {
194         // We must UnMask here, else by the time the base class
195         // does it, the PaintDC will have already been destroyed.
196         UnMask();
197     }
198 
199 protected:
200     // return the size needed by the buffer: this depends on whether we're
201     // buffering just the currently shown part or the total (scrolled) window
GetBufferedSize(wxWindow * window,int style)202     static wxSize GetBufferedSize(wxWindow *window, int style)
203     {
204         return style & wxBUFFER_VIRTUAL_AREA ? window->GetVirtualSize()
205                                              : window->GetClientSize();
206     }
207 
208 private:
209     wxPaintDC m_paintdc;
210 
211     DECLARE_ABSTRACT_CLASS(wxBufferedPaintDC)
212     DECLARE_NO_COPY_CLASS(wxBufferedPaintDC)
213 };
214 
215 
216 
217 //
218 // wxAutoBufferedPaintDC is a wxPaintDC in toolkits which have double-
219 // buffering by default. Otherwise it is a wxBufferedPaintDC. Thus,
220 // you can only expect it work with a simple constructor that
221 // accepts single wxWindow* argument.
222 //
223 #if wxALWAYS_NATIVE_DOUBLE_BUFFER
224     #define wxAutoBufferedPaintDCBase           wxPaintDC
225 #else
226     #define wxAutoBufferedPaintDCBase           wxBufferedPaintDC
227 #endif
228 
229 
230 #ifdef __WXDEBUG__
231 
232 class wxAutoBufferedPaintDC : public wxAutoBufferedPaintDCBase
233 {
234 public:
235 
wxAutoBufferedPaintDC(wxWindow * win)236     wxAutoBufferedPaintDC(wxWindow* win)
237         : wxAutoBufferedPaintDCBase(win)
238     {
239         TestWinStyle(win);
240     }
241 
~wxAutoBufferedPaintDC()242     virtual ~wxAutoBufferedPaintDC() { }
243 
244 private:
245 
TestWinStyle(wxWindow * win)246     void TestWinStyle(wxWindow* win)
247     {
248         // Help the user to get the double-buffering working properly.
249         wxASSERT_MSG( win->GetBackgroundStyle() == wxBG_STYLE_CUSTOM,
250                       wxT("In constructor, you need to call SetBackgroundStyle(wxBG_STYLE_CUSTOM), ")
251                       wxT("and also, if needed, paint the background manually in the paint event handler."));
252     }
253 
254     DECLARE_NO_COPY_CLASS(wxAutoBufferedPaintDC)
255 };
256 
257 #else // !__WXDEBUG__
258 
259 // In release builds, just use typedef
260 typedef wxAutoBufferedPaintDCBase wxAutoBufferedPaintDC;
261 
262 #endif
263 
264 
265 // Check if the window is natively double buffered and will return a wxPaintDC
266 // if it is, a wxBufferedPaintDC otherwise.  It is the caller's responsibility
267 // to delete the wxDC pointer when finished with it.
wxAutoBufferedPaintDCFactory(wxWindow * window)268 inline wxDC* wxAutoBufferedPaintDCFactory(wxWindow* window)
269 {
270     if ( window->IsDoubleBuffered() )
271         return new wxPaintDC(window);
272     else
273         return new wxBufferedPaintDC(window);
274 }
275 
276 #endif  // _WX_DCBUFFER_H_
277