| 1 | ///////////////////////////////////////////////////////////////////////////// |
| 2 | // Name: src/dfb/dcclient.cpp |
| 3 | // Purpose: wxWindowDCImpl, wxClientDCImpl and wxPaintDC |
| 4 | // Author: Vaclav Slavik |
| 5 | // Created: 2006-08-10 |
| 6 | // RCS-ID: $Id$ |
| 7 | // Copyright: (c) 2006 REA Elektronik GmbH |
| 8 | // Licence: wxWindows licence |
| 9 | ///////////////////////////////////////////////////////////////////////////// |
| 10 | |
| 11 | // =========================================================================== |
| 12 | // declarations |
| 13 | // =========================================================================== |
| 14 | |
| 15 | // --------------------------------------------------------------------------- |
| 16 | // headers |
| 17 | // --------------------------------------------------------------------------- |
| 18 | |
| 19 | // For compilers that support precompilation, includes "wx.h". |
| 20 | #include "wx/wxprec.h" |
| 21 | |
| 22 | #ifdef __BORLANDC__ |
| 23 | #pragma hdrstop |
| 24 | #endif |
| 25 | |
| 26 | #ifndef WX_PRECOMP |
| 27 | #include "wx/window.h" |
| 28 | #include "wx/nonownedwnd.h" |
| 29 | #endif |
| 30 | |
| 31 | #include "wx/dfb/dcclient.h" |
| 32 | #include "wx/dfb/private.h" |
| 33 | |
| 34 | #define TRACE_PAINT "paint" |
| 35 | |
| 36 | // =========================================================================== |
| 37 | // implementation |
| 38 | // =========================================================================== |
| 39 | |
| 40 | //----------------------------------------------------------------------------- |
| 41 | // helpers |
| 42 | //----------------------------------------------------------------------------- |
| 43 | |
| 44 | // Returns subrect of the window that is not outside of its parent's |
| 45 | // boundaries ("hidden behind its borders"), recursively: |
| 46 | static wxRect GetUncoveredWindowArea(wxWindow *win) |
| 47 | { |
| 48 | wxRect r(win->GetSize()); |
| 49 | |
| 50 | if ( win->IsTopLevel() ) |
| 51 | return r; |
| 52 | |
| 53 | wxWindow *parent = win->GetParent(); |
| 54 | if ( !parent ) |
| 55 | return r; |
| 56 | |
| 57 | // intersect with parent's uncovered area, after offsetting it into win's |
| 58 | // coordinates; this will remove parts of 'r' that are outside of the |
| 59 | // parent's area: |
| 60 | wxRect rp(GetUncoveredWindowArea(parent)); |
| 61 | |
| 62 | // normal windows cannot extend out of its parent's client area: |
| 63 | if ( !win->CanBeOutsideClientArea() ) |
| 64 | rp.Intersect(parent->GetClientRect()); |
| 65 | |
| 66 | rp.Offset(-win->GetPosition()); |
| 67 | rp.Offset(-parent->GetClientAreaOrigin()); |
| 68 | r.Intersect(rp); |
| 69 | |
| 70 | return r; |
| 71 | } |
| 72 | |
| 73 | // creates a dummy surface that has the same format as the real window's |
| 74 | // surface, but is not visible and so can be painted on even if the window |
| 75 | // is hidden |
| 76 | static |
| 77 | wxIDirectFBSurfacePtr CreateDummySurface(wxWindow *win, const wxRect *rect) |
| 78 | { |
| 79 | wxLogTrace(TRACE_PAINT, "%p ('%s'): creating dummy DC surface", |
| 80 | win, win->GetName().c_str()); |
| 81 | wxSize size(rect ? rect->GetSize() : win->GetSize()); |
| 82 | |
| 83 | // we can't create a surface of 0 size but the size of the window may be 0, |
| 84 | // so ensure that we have at least a single pixel to draw on |
| 85 | size.IncTo(wxSize(1, 1)); |
| 86 | |
| 87 | return win->GetDfbSurface()->CreateCompatible |
| 88 | ( |
| 89 | size, |
| 90 | wxIDirectFBSurface::CreateCompatible_NoBackBuffer |
| 91 | ); |
| 92 | } |
| 93 | |
| 94 | //----------------------------------------------------------------------------- |
| 95 | // wxWindowDCImpl |
| 96 | //----------------------------------------------------------------------------- |
| 97 | |
| 98 | IMPLEMENT_ABSTRACT_CLASS(wxWindowDCImpl, wxDFBDCImpl) |
| 99 | |
| 100 | wxWindowDCImpl::wxWindowDCImpl(wxDC *owner, wxWindow *win) |
| 101 | : wxDFBDCImpl(owner) |
| 102 | { |
| 103 | InitForWin(win, NULL); |
| 104 | } |
| 105 | |
| 106 | void wxWindowDCImpl::InitForWin(wxWindow *win, const wxRect *rect) |
| 107 | { |
| 108 | wxCHECK_RET( win, "invalid window" ); |
| 109 | |
| 110 | m_window = win; |
| 111 | |
| 112 | // obtain the surface used for painting: |
| 113 | wxPoint origin; |
| 114 | wxIDirectFBSurfacePtr surface; |
| 115 | |
| 116 | wxRect rectOrig(rect ? *rect : wxRect(win->GetSize())); |
| 117 | wxRect r; |
| 118 | |
| 119 | if ( !win->IsShownOnScreen() ) |
| 120 | { |
| 121 | // leave 'r' rectangle empty to indicate the window is not visible, |
| 122 | // see below (below "create the surface:") for how is this case handled |
| 123 | } |
| 124 | else |
| 125 | { |
| 126 | // compute painting rectangle after clipping if we're in PaintWindow |
| 127 | // code, otherwise paint on the entire window: |
| 128 | r = rectOrig; |
| 129 | |
| 130 | const wxRegion& updateRegion = win->GetUpdateRegion(); |
| 131 | if ( win->GetTLW()->IsPainting() && !updateRegion.IsEmpty() ) |
| 132 | { |
| 133 | r.Intersect(updateRegion.AsRect()); |
| 134 | wxCHECK_RET( !r.IsEmpty(), "invalid painting rectangle" ); |
| 135 | |
| 136 | // parent TLW will flip the entire surface when painting is done |
| 137 | m_shouldFlip = false; |
| 138 | } |
| 139 | else |
| 140 | { |
| 141 | // One of two things happened: |
| 142 | // (1) the TLW is not being painted by PaintWindow() now; or |
| 143 | // (2) we're drawing on some window other than the one that is |
| 144 | // currently painted on by PaintWindow() |
| 145 | // In either case, we need to flip the surface when we're done |
| 146 | // painting and we don't have to use updateRegion for clipping. |
| 147 | // OTOH, if the window is (partially) hidden by being |
| 148 | // out of its parent's area, we must clip the surface accordingly. |
| 149 | r.Intersect(GetUncoveredWindowArea(win)); |
| 150 | m_shouldFlip = true; // paint the results immediately |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | // create the surface: |
| 155 | if ( r.IsEmpty() ) |
| 156 | { |
| 157 | // we're painting on invisible window: the changes won't have any |
| 158 | // effect, as the window will be repainted anyhow when it is shown, |
| 159 | // but we still need a valid DC so that e.g. text extents can be |
| 160 | // measured, so let's create a dummy surface that has the same |
| 161 | // format as the real one would have and let the code paint on it: |
| 162 | surface = CreateDummySurface(win, rect); |
| 163 | |
| 164 | // painting on hidden window has no effect on TLW's surface, don't |
| 165 | // waste time flipping the dummy surface: |
| 166 | m_shouldFlip = false; |
| 167 | } |
| 168 | else |
| 169 | { |
| 170 | m_winRect = r; |
| 171 | DFBRectangle dfbrect = { r.x, r.y, r.width, r.height }; |
| 172 | surface = win->GetDfbSurface()->GetSubSurface(&dfbrect); |
| 173 | |
| 174 | // if the DC was clipped thanks to rectPaint, we must adjust the |
| 175 | // origin accordingly; but we do *not* adjust for 'rect', because |
| 176 | // rect.GetPosition() has coordinates (0,0) in the DC: |
| 177 | origin.x = rectOrig.x - r.x; |
| 178 | origin.y = rectOrig.y - r.y; |
| 179 | |
| 180 | // m_shouldFlip was set in the "if" block above this one |
| 181 | } |
| 182 | |
| 183 | if ( !surface ) |
| 184 | return; |
| 185 | |
| 186 | wxLogTrace(TRACE_PAINT, |
| 187 | "%p ('%s'): creating DC for area [%i,%i,%i,%i], clipped to [%i,%i,%i,%i], origin [%i,%i]", |
| 188 | win, win->GetName().c_str(), |
| 189 | rectOrig.x, rectOrig.y, rectOrig.GetRight(), rectOrig.GetBottom(), |
| 190 | r.x, r.y, r.GetRight(), r.GetBottom(), |
| 191 | origin.x, origin.y); |
| 192 | |
| 193 | DFBInit(surface); |
| 194 | SetFont(win->GetFont()); |
| 195 | |
| 196 | // offset coordinates to account for subsurface's origin coordinates: |
| 197 | SetDeviceOrigin(origin.x, origin.y); |
| 198 | } |
| 199 | |
| 200 | wxWindowDCImpl::~wxWindowDCImpl() |
| 201 | { |
| 202 | wxIDirectFBSurfacePtr surface(GetDirectFBSurface()); |
| 203 | if ( !surface ) |
| 204 | return; |
| 205 | |
| 206 | // if no painting was done on the DC, we don't have to flip the surface: |
| 207 | if ( !m_isBBoxValid ) |
| 208 | return; |
| 209 | |
| 210 | if ( m_shouldFlip ) |
| 211 | { |
| 212 | // paint overlays on top of the surface being drawn to by this DC |
| 213 | // before showing anything on the screen: |
| 214 | GetWindow()->PaintOverlays(m_winRect); |
| 215 | |
| 216 | DFBSurfaceCapabilities caps = DSCAPS_NONE; |
| 217 | surface->GetCapabilities(&caps); |
| 218 | if ( caps & DSCAPS_DOUBLE ) |
| 219 | { |
| 220 | // FIXME: flip only modified parts of the surface |
| 221 | surface->FlipToFront(); |
| 222 | } |
| 223 | // else: the surface is not double-buffered and so cannot be flipped |
| 224 | } |
| 225 | // else: don't flip the surface, wxTLW will do it when it finishes |
| 226 | // painting of its invalidated areas |
| 227 | } |
| 228 | |
| 229 | //----------------------------------------------------------------------------- |
| 230 | // wxClientDCImpl |
| 231 | //----------------------------------------------------------------------------- |
| 232 | |
| 233 | IMPLEMENT_ABSTRACT_CLASS(wxClientDCImpl, wxWindowDCImpl) |
| 234 | |
| 235 | wxClientDCImpl::wxClientDCImpl(wxDC *owner, wxWindow *win) |
| 236 | : wxWindowDCImpl(owner, win) |
| 237 | { |
| 238 | wxCHECK_RET( win, "invalid window" ); |
| 239 | |
| 240 | wxRect rect = win->GetClientRect(); |
| 241 | InitForWin(win, &rect); |
| 242 | } |
| 243 | |
| 244 | //----------------------------------------------------------------------------- |
| 245 | // wxPaintDC |
| 246 | //----------------------------------------------------------------------------- |
| 247 | |
| 248 | IMPLEMENT_ABSTRACT_CLASS(wxPaintDCImpl, wxWindowDCImpl) |