corrected painting implementation for wxDFB
authorVáclav Slavík <vslavik@fastmail.fm>
Wed, 13 Sep 2006 09:50:02 +0000 (09:50 +0000)
committerVáclav Slavík <vslavik@fastmail.fm>
Wed, 13 Sep 2006 09:50:02 +0000 (09:50 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@41185 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/dfb/dcclient.h
include/wx/dfb/toplevel.h
include/wx/dfb/window.h
include/wx/dfb/wrapdfb.h
src/dfb/dc.cpp
src/dfb/dcclient.cpp
src/dfb/toplevel.cpp
src/dfb/window.cpp
src/dfb/wrapdfb.cpp

index aac9a933c9dcf21f92469e2e96e5c65d1e081ded..a4006f9cc0d490cb192b6a9c83d90f2520a00ce2 100644 (file)
@@ -22,39 +22,31 @@ class WXDLLIMPEXP_CORE wxWindow;
 class WXDLLIMPEXP_CORE wxWindowDC : public wxDC
 {
 public:
-    wxWindowDC() {}
+    wxWindowDC() : m_win(NULL) {}
     wxWindowDC(wxWindow *win);
+    virtual ~wxWindowDC();
 
 protected:
     // initializes the DC for painting on given window; if rect!=NULL, then
     // for painting only on the given region of the window
     void InitForWin(wxWindow *win, const wxRect *rect);
 
+private:
+    wxWindow *m_win; // the window the DC paints on
+
     DECLARE_DYNAMIC_CLASS(wxWindowDC)
     DECLARE_NO_COPY_CLASS(wxWindowDC)
 };
 
-//-----------------------------------------------------------------------------
-// base class for wxClientDC and wxPaintDC
-//-----------------------------------------------------------------------------
-
-class WXDLLIMPEXP_CORE wxClientDCBase : public wxWindowDC
-{
-public:
-    wxClientDCBase() {}
-    wxClientDCBase(wxWindow *win);
-};
-
 //-----------------------------------------------------------------------------
 // wxClientDC
 //-----------------------------------------------------------------------------
 
-class WXDLLIMPEXP_CORE wxClientDC : public wxClientDCBase
+class WXDLLIMPEXP_CORE wxClientDC : public wxWindowDC
 {
 public:
     wxClientDC() {}
-    wxClientDC(wxWindow *win) : wxClientDCBase(win) {}
-    ~wxClientDC();
+    wxClientDC(wxWindow *win);
 
     DECLARE_DYNAMIC_CLASS(wxClientDC)
     DECLARE_NO_COPY_CLASS(wxClientDC)
@@ -65,12 +57,11 @@ public:
 // wxPaintDC
 //-----------------------------------------------------------------------------
 
-class WXDLLIMPEXP_CORE wxPaintDC : public wxClientDCBase
+class WXDLLIMPEXP_CORE wxPaintDC : public wxClientDC
 {
 public:
     wxPaintDC() {}
-    wxPaintDC(wxWindow *win) : wxClientDCBase(win) {}
-    ~wxPaintDC();
+    wxPaintDC(wxWindow *win) : wxClientDC(win) {}
 
     DECLARE_DYNAMIC_CLASS(wxPaintDC)
     DECLARE_NO_COPY_CLASS(wxPaintDC)
index d35f257c1bd62150b080e97fecab2cfb27a093d5..f15d9e4fd7d7a96ec056c3e9487bbf67ffbae8b2 100644 (file)
@@ -77,6 +77,10 @@ public:
 
     wxIDirectFBWindowPtr GetDirectFBWindow() const { return m_dfbwin; }
 
+    // Returns true if some invalidated area of the TLW is currently being
+    // painted
+    bool IsPainting() const { return m_isPainting; }
+
 protected:
     // common part of all ctors
     void Init();
@@ -88,7 +92,7 @@ protected:
     virtual void DoGetSize(int *width, int *height) const;
     virtual void DoMoveWindow(int x, int y, int width, int height);
 
-    virtual void DoRefreshRect(const wxRect& rect, bool eraseBack = true);
+    virtual void DoRefreshRect(const wxRect& rect);
 
 private:
     // do queued painting in idle time
@@ -119,7 +123,10 @@ protected:
     wxIDirectFBWindowPtr m_dfbwin;
 
 private:
+    // invalidated areas of the TLW that need repainting
     wxDfbQueuedPaintRequests *m_toPaint;
+    // are we currently painting some area of this TLW?
+    bool m_isPainting;
 
     friend class wxEventLoop; // for HandleDFBWindowEvent
 };
index e30d2ae436db5ca7e2d2ccf43324ba21eafd909b..f5bc1b15b248cb04ecc5563a407bd3283198a298 100644 (file)
@@ -140,11 +140,12 @@ protected:
     void InvalidateDfbSurface();
 
     // called by parent to render (part of) the window
-    void PaintWindow(const wxRect& rect, bool eraseBackground);
+    void PaintWindow(const wxRect& rect);
 
-    // implementation of Refresh()
-    void DoRefreshWindow(bool eraseBack = true);
-    virtual void DoRefreshRect(const wxRect& rect, bool eraseBack = true);
+    // refreshes the entire window (including non-client areas)
+    void DoRefreshWindow();
+    // refreshes given rectangle of the window (in window, _not_ client coords)
+    virtual void DoRefreshRect(const wxRect& rect);
 
     // DirectFB events handling
     void HandleKeyEvent(const wxDFBWindowEvent& event_);
@@ -177,5 +178,4 @@ private:
     DECLARE_EVENT_TABLE()
 };
 
-
 #endif // _WX_DFB_WINDOW_H_
index 30ef307513db7d45897e677647dde92905e5d789..bed40a9124242fb7d8ed2571a022836a24c6376d 100644 (file)
@@ -231,10 +231,11 @@ struct wxIDirectFBSurface : public wxDfbWrapper<IDirectFBSurface>
                                          (DFBSurfaceTextFlags)flags));
     }
 
-    bool Flip(const DFBRegion *region, int flags)
-    {
-        return Check(m_ptr->Flip(m_ptr, region, (DFBSurfaceFlipFlags)flags));
-    }
+    /**
+        Updates the front buffer from the back buffer. If @a region is not
+        NULL, only given rectangle is updated.
+     */
+    bool FlipToFront(const DFBRegion *region = NULL);
 
     wxIDirectFBSurfacePtr GetSubSurface(const DFBRectangle *rect)
     {
@@ -293,6 +294,10 @@ struct wxIDirectFBSurface : public wxDfbWrapper<IDirectFBSurface>
                     size of this surface.
      */
     wxIDirectFBSurfacePtr CreateCompatible(const wxSize& size = wxDefaultSize);
+
+private:
+    // this is private because we want user code to use FlipToFront()
+    bool Flip(const DFBRegion *region, int flags);
 };
 
 
index 72b7ff8138041bf83ab881e1a09f2f56dd6c1c1a..f5d6a1691ddcf77cefcdde57a929480a5964f6a2 100644 (file)
@@ -151,6 +151,10 @@ void wxDC::Clear()
 
     wxColour clr = m_backgroundBrush.GetColour();
     m_surface->Clear(clr.Red(), clr.Green(), clr.Blue(), clr.Alpha());
+
+    wxSize size(GetSize());
+    CalcBoundingBox(XDEV2LOG(0), YDEV2LOG(0));
+    CalcBoundingBox(XDEV2LOG(size.x), YDEV2LOG(size.y));
 }
 
 extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y,
index c51e6a509e39c347cb32f3f8d7779ccd7d4a26b4..160f3e336d8e123e15507ee29015cae49f24f6c8 100644 (file)
@@ -31,6 +31,8 @@
 
 #include "wx/dfb/private.h"
 
+#define TRACE_PAINT  _T("paint")
+
 // ===========================================================================
 // implementation
 // ===========================================================================
@@ -48,13 +50,12 @@ wxWindowDC::wxWindowDC(wxWindow *win)
 
 void wxWindowDC::InitForWin(wxWindow *win, const wxRect *rect)
 {
-    wxCHECK_RET( win, _T("invalid window") );
+    m_win = win;
 
-    // check if the rectangle covers full window and so is not needed:
-    if ( rect && *rect == wxRect(win->GetSize()) )
-        rect = NULL;
+    wxCHECK_RET( win, _T("invalid window") );
 
     // obtain the surface used for painting:
+    wxPoint origin;
     wxIDirectFBSurfacePtr surface;
 
     if ( !win->IsVisible() )
@@ -64,21 +65,37 @@ void wxWindowDC::InitForWin(wxWindow *win, const wxRect *rect)
         // we still need a valid DC so that e.g. text extents can be measured,
         // so let's create a dummy surface that has the same format as the real
         // one would have and let the code paint on it:
+        wxLogTrace(TRACE_PAINT, _T("%p ('%s'): creating dummy DC surface"),
+                   win, win->GetName().c_str());
         wxSize size(rect ? rect->GetSize() : win->GetSize());
         surface = win->GetDfbSurface()->CreateCompatible(size);
     }
-    else if ( !rect )
-    {
-        wxCHECK_RET( win->GetSize().x > 0 && win->GetSize().y > 0,
-                     _T("window has invalid size") );
-
-        surface = win->GetDfbSurface();
-    }
     else
     {
-        wxCHECK_RET( !rect || !rect->IsEmpty(), _T("invalid rectangle") );
-
-        DFBRectangle dfbrect = { rect->x, rect->y, rect->width, rect->height };
+        wxRect rectOrig(rect ? *rect : wxRect(win->GetSize()));
+
+        // compute painting rectangle after clipping if we're in PaintWindow
+        // code, otherwise paint on the entire window:
+        wxRect r(rectOrig);
+        if ( win->GetTLW()->IsPainting() )
+            r.Intersect(win->GetUpdateRegion().AsRect());
+
+        wxCHECK_RET( !r.IsEmpty(), _T("invalid painting rectangle") );
+
+        // if the DC was clipped thanks to rectPaint, we must adjust the origin
+        // accordingly; but we do *not* adjust for 'rect', because
+        // rect.GetPosition() has coordinates (0,0) in the DC:
+        origin.x = rectOrig.x - r.x;
+        origin.y = rectOrig.y - r.y;
+
+        wxLogTrace(TRACE_PAINT,
+                   _T("%p ('%s'): creating DC for area [%i,%i,%i,%i], clipped to [%i,%i,%i,%i], origin [%i,%i]"),
+                   win, win->GetName().c_str(),
+                   rectOrig.x, rectOrig.y, rectOrig.GetRight(), rectOrig.GetBottom(),
+                   r.x, r.y, r.GetRight(), r.GetBottom(),
+                   origin.x, origin.y);
+
+        DFBRectangle dfbrect = { r.x, r.y, r.width, r.height };
         surface = win->GetDfbSurface()->GetSubSurface(&dfbrect);
     }
 
@@ -89,20 +106,31 @@ void wxWindowDC::InitForWin(wxWindow *win, const wxRect *rect)
     SetFont(win->GetFont());
 
     // offset coordinates to account for subsurface's origin coordinates:
-    if ( rect )
-        SetDeviceOrigin(rect->x, rect->y);
+    SetDeviceOrigin(origin.x, origin.y);
 }
 
-//-----------------------------------------------------------------------------
-// base class for wxClientDC and wxPaintDC
-//-----------------------------------------------------------------------------
-
-wxClientDCBase::wxClientDCBase(wxWindow *win)
+wxWindowDC::~wxWindowDC()
 {
-    wxCHECK_RET( win, _T("invalid window") );
+    wxIDirectFBSurfacePtr surface(GetDirectFBSurface());
+    if ( !surface || !m_win )
+        return;
 
-    wxRect rect = win->GetClientRect();
-    InitForWin(win, &rect);
+    // painting on hidden window has no effect on TLW's surface, don't
+    // waste time flipping the dummy surface:
+    if ( !m_win->IsVisible() )
+        return;
+
+    // if no painting was done on the DC, we don't have to flip the surface:
+    if ( !m_isBBoxValid )
+        return;
+
+    if ( !m_win->GetTLW()->IsPainting() )
+    {
+        // FIXME: flip only modified parts of the surface
+        surface->FlipToFront();
+    }
+    // else: don't flip the surface, wxTLW will do it when it finishes
+    //       painting of its invalidated areas
 }
 
 //-----------------------------------------------------------------------------
@@ -111,15 +139,12 @@ wxClientDCBase::wxClientDCBase(wxWindow *win)
 
 IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
 
-wxClientDC::~wxClientDC()
+wxClientDC::wxClientDC(wxWindow *win)
 {
-    // flip to surface so that the changes become visible
-    wxIDirectFBSurfacePtr surface(GetDirectFBSurface());
+    wxCHECK_RET( win, _T("invalid window") );
 
-    // FIXME: do this only if the surface was modified (as opposed to e.g.
-    //        used only to obtain text metrics)
-    if ( surface )
-        surface->Flip(NULL, DSFLIP_NONE);
+    wxRect rect = win->GetClientRect();
+    InitForWin(win, &rect);
 }
 
 //-----------------------------------------------------------------------------
@@ -127,12 +152,3 @@ wxClientDC::~wxClientDC()
 //-----------------------------------------------------------------------------
 
 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxWindowDC)
-
-#warning "wxPaintDC ctor must respect m_updateRegion"
-
-wxPaintDC::~wxPaintDC()
-{
-    // NB: do *not* flip the surface: wxPaintDC is used with EVT_PAINT and the
-    //     surface will be flipped for the entire TLW once all children are
-    //     repainted
-}
index 41b05ce9b1a74273aa0ec8d5c72c339701c99bfa..3aebd23e4041ffb48ff497290429a1810a9586f1 100644 (file)
@@ -41,13 +41,10 @@ static wxDfbWindowsMap gs_dfbWindowsMap;
 
 struct wxDfbPaintRequest
 {
-    wxDfbPaintRequest(const wxRect& rect, bool eraseBackground)
-        : m_rect(rect), m_eraseBackground(eraseBackground) {}
-    wxDfbPaintRequest(const wxDfbPaintRequest& r)
-        : m_rect(r.m_rect), m_eraseBackground(r.m_eraseBackground) {}
+    wxDfbPaintRequest(const wxRect& rect) : m_rect(rect) {}
+    wxDfbPaintRequest(const wxDfbPaintRequest& r) : m_rect(r.m_rect) {}
 
     wxRect m_rect;
-    bool   m_eraseBackground;
 };
 
 WX_DEFINE_ARRAY_PTR(wxDfbPaintRequest*, wxDfbQueuedPaintRequestsList);
@@ -59,8 +56,8 @@ public:
     ~wxDfbQueuedPaintRequests() { Clear(); }
 
     // Adds paint request to the queue
-    void Add(const wxRect& rect, bool eraseBack)
-        { m_queue.push_back(new wxDfbPaintRequest(rect, eraseBack)); }
+    void Add(const wxRect& rect)
+        { m_queue.push_back(new wxDfbPaintRequest(rect)); }
 
     // Is the queue empty?
     bool IsEmpty() const { return m_queue.empty(); }
@@ -91,6 +88,7 @@ void wxTopLevelWindowDFB::Init()
     m_sizeSet = false;
     m_opacity = 255;
     m_toPaint = new wxDfbQueuedPaintRequests;
+    m_isPainting = false;
 }
 
 bool wxTopLevelWindowDFB::Create(wxWindow *parent,
@@ -148,7 +146,8 @@ bool wxTopLevelWindowDFB::Create(wxWindow *parent,
     if ( !m_dfbwin->SetOpacity(wxALPHA_TRANSPARENT) )
         return false;
 
-    wxWindow::Create(NULL, id, pos, size, style, name);
+    if ( !wxWindow::Create(NULL, id, pos, size, style, name) )
+        return false;
 
     SetParent(parent);
     if ( parent )
@@ -217,7 +216,8 @@ void wxTopLevelWindowDFB::DoMoveWindow(int x, int y, int width, int height)
     {
         m_dfbwin->Resize(width, height);
         // we must repaint the window after it changed size:
-        Refresh();
+        if ( IsShown() )
+            DoRefreshWindow();
     }
 }
 
@@ -375,23 +375,30 @@ void wxTopLevelWindowDFB::HandleQueuedPaintRequests()
     wxRect winRect(wxPoint(0, 0), GetSize());
     wxRect paintedRect;
 
+    // important note: all DCs created from now until m_isPainting is reset to
+    // false will not update the front buffer as this flag indicates that we'll
+    // blit the entire back buffer to front soon
+    m_isPainting = true;
+
     size_t cnt = requests.size();
+    wxLogTrace(TRACE_PAINT, _T("%p ('%s'): processing %i paint requests"),
+               this, GetName().c_str(), cnt);
+
     for ( size_t i = 0; i < cnt; ++i )
     {
         const wxDfbPaintRequest& request = *requests[i];
 
         wxRect clipped(request.m_rect);
-
-        wxLogTrace(TRACE_PAINT,
-                   _T("%p ('%s'): processing paint request [x=%i,y=%i,w=%i,h=%i]"),
-                   this, GetName().c_str(),
-                   clipped.x, clipped.y, clipped.width, clipped.height);
-
         clipped.Intersect(winRect);
         if ( clipped.IsEmpty() )
             continue; // nothing to refresh
 
-        PaintWindow(clipped, request.m_eraseBackground);
+        wxLogTrace(TRACE_PAINT,
+                   _T("%p ('%s'): processing paint request [%i,%i,%i,%i]"),
+                   this, GetName().c_str(),
+                   clipped.x, clipped.y, clipped.GetRight(), clipped.GetBottom());
+
+        PaintWindow(clipped);
 
         // remember rectangle covering all repainted areas:
         if ( paintedRect.IsEmpty() )
@@ -400,23 +407,49 @@ void wxTopLevelWindowDFB::HandleQueuedPaintRequests()
             paintedRect.Union(clipped);
     }
 
+    m_isPainting = false;
+
     m_toPaint->Clear();
 
     if ( paintedRect.IsEmpty() )
         return; // no painting occurred, no need to flip
 
-    // flip the surface to make the changes visible:
+    // Flip the surface to make the changes visible. Note that the rectangle we
+    // flip is *superset* of the union of repainted rectangles (created as
+    // "rectangles union" by wxRect::Union) and so some parts of the back
+    // buffer that we didn't touch in this HandleQueuedPaintRequests call will
+    // be copied to the front buffer as well. This is safe/correct thing to do
+    // *only* because wx always use wxIDirectFBSurface::FlipToFront() and so
+    // the back and front buffers contain the same data.
+    //
+    // Note that we do _not_ split m_toPaint into disjoint rectangles and
+    // do FlipToFront() for each of them, because that could result in visible
+    // updating of the screen; instead, we prefer to flip everything at once.
+
     DFBRegion r = {paintedRect.GetLeft(), paintedRect.GetTop(),
                    paintedRect.GetRight(), paintedRect.GetBottom()};
     DFBRegion *rptr = (winRect == paintedRect) ? NULL : &r;
 
-    GetDfbSurface()->Flip(rptr, DSFLIP_NONE);
+    GetDfbSurface()->FlipToFront(rptr);
+
+    wxLogTrace(TRACE_PAINT,
+               _T("%p ('%s'): flipped surface: [%i,%i,%i,%i]"),
+               this, GetName().c_str(),
+               paintedRect.x, paintedRect.y,
+               paintedRect.GetRight(), paintedRect.GetBottom());
 }
 
-void wxTopLevelWindowDFB::DoRefreshRect(const wxRect& rect, bool eraseBack)
+void wxTopLevelWindowDFB::DoRefreshRect(const wxRect& rect)
 {
+    wxASSERT_MSG( rect.width > 0 && rect.height > 0, _T("invalid rect") );
+
+    wxLogTrace(TRACE_PAINT,
+               _T("%p ('%s'): [TLW] refresh rect [%i,%i,%i,%i]"),
+               this, GetName().c_str(),
+               rect.x, rect.y, rect.GetRight(), rect.GetBottom());
+
     // defer painting until idle time or until Update() is called:
-    m_toPaint->Add(rect, eraseBack);
+    m_toPaint->Add(rect);
 }
 
 void wxTopLevelWindowDFB::Update()
index f2b090be72e044f10191c960c1c71af2afdcb366..30e38e98276ff49450b2bdf8d0c1363e77421ca5 100644 (file)
@@ -590,34 +590,56 @@ void wxWindowDFB::Clear()
     dc.Clear();
 }
 
-void wxWindowDFB::Refresh(bool eraseBack, const wxRect *rect)
+void wxWindowDFB::Refresh(bool WXUNUSED(eraseBack), const wxRect *rect)
 {
     if ( !IsShown() || IsFrozen() )
         return;
 
+    // NB[1]: We intentionally ignore the eraseBack argument here. This is
+    //        because of the way wxDFB's painting is implemented: the refresh
+    //        request is probagated up to wxTLW, which is then painted in
+    //        top-down order. This means that this window's area is first
+    //        painted by its parent and this window is then painted over it, so
+    //        it's not safe to not paint this window's background even if
+    //        eraseBack=false.
+    // NB[2]: wxWindow::Refresh() takes the rectangle in client coords, but
+    //        wxUniv translates it to window coords before passing it to
+    //        wxWindowDFB::Refresh(), so we can directly pass the rect to
+    //        DoRefreshRect (which takes window, not client, coords) here.
     if ( rect )
-        DoRefreshRect(*rect, eraseBack);
+        DoRefreshRect(*rect);
     else
-        DoRefreshWindow(eraseBack);
+        DoRefreshWindow();
 }
 
-void wxWindowDFB::DoRefreshWindow(bool eraseBack)
+void wxWindowDFB::DoRefreshWindow()
 {
-    DoRefreshRect(wxRect(wxPoint(0, 0), GetSize()), eraseBack);
+    // NB: DoRefreshRect() takes window coords, not client, so this is correct
+    DoRefreshRect(wxRect(GetSize()));
 }
 
-void wxWindowDFB::DoRefreshRect(const wxRect& rect, bool eraseBack)
+void wxWindowDFB::DoRefreshRect(const wxRect& rect)
 {
     wxWindow *parent = GetParent();
     wxCHECK_RET( parent, _T("no parent") );
 
+    // don't overlap outside of the window (NB: 'rect' is in window coords):
+    wxRect r(rect);
+    r.Intersect(wxRect(GetSize()));
+    if ( r.IsEmpty() )
+        return;
+
+    wxLogTrace(TRACE_PAINT,
+               _T("%p ('%s'): refresh rect [%i,%i,%i,%i]"),
+               this, GetName().c_str(),
+               rect.x, rect.y, rect.GetRight(), rect.GetBottom());
+
     // convert the refresh rectangle to parent's coordinates and
     // recursively refresh the parent:
-    wxRect r(rect);
     r.Offset(GetPosition());
     r.Offset(parent->GetClientAreaOrigin());
 
-    parent->DoRefreshRect(r, eraseBack);
+    parent->DoRefreshRect(r);
 }
 
 void wxWindowDFB::Update()
@@ -640,24 +662,21 @@ void wxWindowDFB::Thaw()
     if ( --m_frozenness == 0 )
     {
         if ( IsShown() )
-            Refresh();
+            DoRefreshWindow();
     }
 }
 
-void wxWindowDFB::PaintWindow(const wxRect& rect, bool eraseBackground)
+void wxWindowDFB::PaintWindow(const wxRect& rect)
 {
     wxCHECK_RET( !IsFrozen() && IsShown(), _T("shouldn't be called") );
 
     wxLogTrace(TRACE_PAINT,
-               _T("%p ('%s'): painting region [x=%i,y=%i,w=%i,h=%i]"),
+               _T("%p ('%s'): painting region [%i,%i,%i,%i]"),
                this, GetName().c_str(),
-               rect.x, rect.y, rect.width, rect.height);
+               rect.x, rect.y, rect.GetRight(), rect.GetBottom());
 
     m_updateRegion = rect;
 
-    // FIXME_DFB: don't waste time rendering the area if it's fully covered
-    //            by some children, go directly to rendering the children
-
 #if wxUSE_CARET
     // must hide caret temporarily, otherwise we'd get rendering artifacts
     wxCaret *caret = GetCaret();
@@ -665,27 +684,52 @@ void wxWindowDFB::PaintWindow(const wxRect& rect, bool eraseBackground)
         caret->Hide();
 #endif // wxUSE_CARET
 
-    if ( eraseBackground )
+    // FIXME_DFB: don't waste time rendering the area if it's fully covered
+    //            by some children, go directly to rendering the children
+
+    // NB: unconditionally send wxEraseEvent, because our implementation of
+    //     wxWindow::Refresh() ignores the eraseBack argument
+    wxWindowDC dc((wxWindow*)this);
+    wxEraseEvent eventEr(m_windowId, &dc);
+    eventEr.SetEventObject(this);
+    GetEventHandler()->ProcessEvent(eventEr);
+
+    wxRect clientRect(GetClientRect());
+
+    // only send wxNcPaintEvent if drawing at least part of nonclient area:
+    if ( !clientRect.Inside(rect) )
     {
-        wxWindowDC dc((wxWindow*)this);
-        wxEraseEvent eventEr(m_windowId, &dc);
-        eventEr.SetEventObject(this);
-        GetEventHandler()->ProcessEvent(eventEr);
+        wxNcPaintEvent eventNc(GetId());
+        eventNc.SetEventObject(this);
+        GetEventHandler()->ProcessEvent(eventNc);
+    }
+    else
+    {
+        wxLogTrace(TRACE_PAINT, _T("%p ('%s'): not sending wxNcPaintEvent"),
+                   this, GetName().c_str());
     }
 
-    wxNcPaintEvent eventNc(GetId());
-    eventNc.SetEventObject(this);
-    GetEventHandler()->ProcessEvent(eventNc);
-
-    wxPaintEvent eventPt(GetId());
-    eventPt.SetEventObject(this);
-    GetEventHandler()->ProcessEvent(eventPt);
+    // only send wxPaintEvent if drawing at least part of client area:
+    if ( rect.Intersects(clientRect) )
+    {
+        wxPaintEvent eventPt(GetId());
+        eventPt.SetEventObject(this);
+        GetEventHandler()->ProcessEvent(eventPt);
+    }
+    else
+    {
+        wxLogTrace(TRACE_PAINT, _T("%p ('%s'): not sending wxPaintEvent"),
+                   this, GetName().c_str());
+    }
 
 #if wxUSE_CARET
     if ( caret )
         caret->Show();
 #endif // wxUSE_CARET
 
+    m_updateRegion.Clear();
+
+    // paint the children:
     wxPoint origin = GetClientAreaOrigin();
     wxWindowList& children = GetChildren();
     for ( wxWindowList::iterator i = children.begin();
@@ -704,13 +748,10 @@ void wxWindowDFB::PaintWindow(const wxRect& rect, bool eraseBackground)
             continue;
 
         // and repaint it:
-        wxPoint childpos(child->GetPosition());
-        childrect.Offset(-childpos.x, -childpos.y);
-        childrect.Offset(-origin.x, -origin.y);
-        child->PaintWindow(childrect, eraseBackground);
+        childrect.Offset(-child->GetPosition());
+        childrect.Offset(-origin);
+        child->PaintWindow(childrect);
     }
-
-    m_updateRegion.Clear();
 }
 
 
index 873f040cdefac3b135e67b7ead116a94f5b38e0e..c23796696367b73be73d6991e29ef745cecd00aa 100644 (file)
@@ -166,3 +166,17 @@ wxIDirectFBSurfacePtr wxIDirectFBSurface::Clone()
 
     return snew;
 }
+
+bool wxIDirectFBSurface::Flip(const DFBRegion *region, int flags)
+{
+    return Check(m_ptr->Flip(m_ptr, region, (DFBSurfaceFlipFlags)flags));
+}
+
+bool wxIDirectFBSurface::FlipToFront(const DFBRegion *region)
+{
+    // Blit to the front buffer instead of exchanging front and back ones.
+    // Always doing this ensures that back and front buffer have same content
+    // and so painting to the back buffer will never lose any previous
+    // drawings:
+    return Flip(region, DSFLIP_BLIT);
+}