corrected painting implementation for wxDFB
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@41185 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -22,39 +22,31 @@ class WXDLLIMPEXP_CORE wxWindow;
|
|||||||
class WXDLLIMPEXP_CORE wxWindowDC : public wxDC
|
class WXDLLIMPEXP_CORE wxWindowDC : public wxDC
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
wxWindowDC() {}
|
wxWindowDC() : m_win(NULL) {}
|
||||||
wxWindowDC(wxWindow *win);
|
wxWindowDC(wxWindow *win);
|
||||||
|
virtual ~wxWindowDC();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// initializes the DC for painting on given window; if rect!=NULL, then
|
// initializes the DC for painting on given window; if rect!=NULL, then
|
||||||
// for painting only on the given region of the window
|
// for painting only on the given region of the window
|
||||||
void InitForWin(wxWindow *win, const wxRect *rect);
|
void InitForWin(wxWindow *win, const wxRect *rect);
|
||||||
|
|
||||||
|
private:
|
||||||
|
wxWindow *m_win; // the window the DC paints on
|
||||||
|
|
||||||
DECLARE_DYNAMIC_CLASS(wxWindowDC)
|
DECLARE_DYNAMIC_CLASS(wxWindowDC)
|
||||||
DECLARE_NO_COPY_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
|
// wxClientDC
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
class WXDLLIMPEXP_CORE wxClientDC : public wxClientDCBase
|
class WXDLLIMPEXP_CORE wxClientDC : public wxWindowDC
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
wxClientDC() {}
|
wxClientDC() {}
|
||||||
wxClientDC(wxWindow *win) : wxClientDCBase(win) {}
|
wxClientDC(wxWindow *win);
|
||||||
~wxClientDC();
|
|
||||||
|
|
||||||
DECLARE_DYNAMIC_CLASS(wxClientDC)
|
DECLARE_DYNAMIC_CLASS(wxClientDC)
|
||||||
DECLARE_NO_COPY_CLASS(wxClientDC)
|
DECLARE_NO_COPY_CLASS(wxClientDC)
|
||||||
@@ -65,12 +57,11 @@ public:
|
|||||||
// wxPaintDC
|
// wxPaintDC
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
class WXDLLIMPEXP_CORE wxPaintDC : public wxClientDCBase
|
class WXDLLIMPEXP_CORE wxPaintDC : public wxClientDC
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
wxPaintDC() {}
|
wxPaintDC() {}
|
||||||
wxPaintDC(wxWindow *win) : wxClientDCBase(win) {}
|
wxPaintDC(wxWindow *win) : wxClientDC(win) {}
|
||||||
~wxPaintDC();
|
|
||||||
|
|
||||||
DECLARE_DYNAMIC_CLASS(wxPaintDC)
|
DECLARE_DYNAMIC_CLASS(wxPaintDC)
|
||||||
DECLARE_NO_COPY_CLASS(wxPaintDC)
|
DECLARE_NO_COPY_CLASS(wxPaintDC)
|
||||||
|
@@ -77,6 +77,10 @@ public:
|
|||||||
|
|
||||||
wxIDirectFBWindowPtr GetDirectFBWindow() const { return m_dfbwin; }
|
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:
|
protected:
|
||||||
// common part of all ctors
|
// common part of all ctors
|
||||||
void Init();
|
void Init();
|
||||||
@@ -88,7 +92,7 @@ protected:
|
|||||||
virtual void DoGetSize(int *width, int *height) const;
|
virtual void DoGetSize(int *width, int *height) const;
|
||||||
virtual void DoMoveWindow(int x, int y, int width, int height);
|
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:
|
private:
|
||||||
// do queued painting in idle time
|
// do queued painting in idle time
|
||||||
@@ -119,7 +123,10 @@ protected:
|
|||||||
wxIDirectFBWindowPtr m_dfbwin;
|
wxIDirectFBWindowPtr m_dfbwin;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// invalidated areas of the TLW that need repainting
|
||||||
wxDfbQueuedPaintRequests *m_toPaint;
|
wxDfbQueuedPaintRequests *m_toPaint;
|
||||||
|
// are we currently painting some area of this TLW?
|
||||||
|
bool m_isPainting;
|
||||||
|
|
||||||
friend class wxEventLoop; // for HandleDFBWindowEvent
|
friend class wxEventLoop; // for HandleDFBWindowEvent
|
||||||
};
|
};
|
||||||
|
@@ -140,11 +140,12 @@ protected:
|
|||||||
void InvalidateDfbSurface();
|
void InvalidateDfbSurface();
|
||||||
|
|
||||||
// called by parent to render (part of) the window
|
// called by parent to render (part of) the window
|
||||||
void PaintWindow(const wxRect& rect, bool eraseBackground);
|
void PaintWindow(const wxRect& rect);
|
||||||
|
|
||||||
// implementation of Refresh()
|
// refreshes the entire window (including non-client areas)
|
||||||
void DoRefreshWindow(bool eraseBack = true);
|
void DoRefreshWindow();
|
||||||
virtual void DoRefreshRect(const wxRect& rect, bool eraseBack = true);
|
// refreshes given rectangle of the window (in window, _not_ client coords)
|
||||||
|
virtual void DoRefreshRect(const wxRect& rect);
|
||||||
|
|
||||||
// DirectFB events handling
|
// DirectFB events handling
|
||||||
void HandleKeyEvent(const wxDFBWindowEvent& event_);
|
void HandleKeyEvent(const wxDFBWindowEvent& event_);
|
||||||
@@ -177,5 +178,4 @@ private:
|
|||||||
DECLARE_EVENT_TABLE()
|
DECLARE_EVENT_TABLE()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // _WX_DFB_WINDOW_H_
|
#endif // _WX_DFB_WINDOW_H_
|
||||||
|
@@ -231,10 +231,11 @@ struct wxIDirectFBSurface : public wxDfbWrapper<IDirectFBSurface>
|
|||||||
(DFBSurfaceTextFlags)flags));
|
(DFBSurfaceTextFlags)flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Flip(const DFBRegion *region, int flags)
|
/**
|
||||||
{
|
Updates the front buffer from the back buffer. If @a region is not
|
||||||
return Check(m_ptr->Flip(m_ptr, region, (DFBSurfaceFlipFlags)flags));
|
NULL, only given rectangle is updated.
|
||||||
}
|
*/
|
||||||
|
bool FlipToFront(const DFBRegion *region = NULL);
|
||||||
|
|
||||||
wxIDirectFBSurfacePtr GetSubSurface(const DFBRectangle *rect)
|
wxIDirectFBSurfacePtr GetSubSurface(const DFBRectangle *rect)
|
||||||
{
|
{
|
||||||
@@ -293,6 +294,10 @@ struct wxIDirectFBSurface : public wxDfbWrapper<IDirectFBSurface>
|
|||||||
size of this surface.
|
size of this surface.
|
||||||
*/
|
*/
|
||||||
wxIDirectFBSurfacePtr CreateCompatible(const wxSize& size = wxDefaultSize);
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -151,6 +151,10 @@ void wxDC::Clear()
|
|||||||
|
|
||||||
wxColour clr = m_backgroundBrush.GetColour();
|
wxColour clr = m_backgroundBrush.GetColour();
|
||||||
m_surface->Clear(clr.Red(), clr.Green(), clr.Blue(), clr.Alpha());
|
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,
|
extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y,
|
||||||
|
@@ -31,6 +31,8 @@
|
|||||||
|
|
||||||
#include "wx/dfb/private.h"
|
#include "wx/dfb/private.h"
|
||||||
|
|
||||||
|
#define TRACE_PAINT _T("paint")
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
// implementation
|
// implementation
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@@ -48,13 +50,12 @@ wxWindowDC::wxWindowDC(wxWindow *win)
|
|||||||
|
|
||||||
void wxWindowDC::InitForWin(wxWindow *win, const wxRect *rect)
|
void wxWindowDC::InitForWin(wxWindow *win, const wxRect *rect)
|
||||||
{
|
{
|
||||||
|
m_win = win;
|
||||||
|
|
||||||
wxCHECK_RET( win, _T("invalid window") );
|
wxCHECK_RET( win, _T("invalid window") );
|
||||||
|
|
||||||
// check if the rectangle covers full window and so is not needed:
|
|
||||||
if ( rect && *rect == wxRect(win->GetSize()) )
|
|
||||||
rect = NULL;
|
|
||||||
|
|
||||||
// obtain the surface used for painting:
|
// obtain the surface used for painting:
|
||||||
|
wxPoint origin;
|
||||||
wxIDirectFBSurfacePtr surface;
|
wxIDirectFBSurfacePtr surface;
|
||||||
|
|
||||||
if ( !win->IsVisible() )
|
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,
|
// 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
|
// 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:
|
// 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());
|
wxSize size(rect ? rect->GetSize() : win->GetSize());
|
||||||
surface = win->GetDfbSurface()->CreateCompatible(size);
|
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
|
else
|
||||||
{
|
{
|
||||||
wxCHECK_RET( !rect || !rect->IsEmpty(), _T("invalid rectangle") );
|
wxRect rectOrig(rect ? *rect : wxRect(win->GetSize()));
|
||||||
|
|
||||||
DFBRectangle dfbrect = { rect->x, rect->y, rect->width, rect->height };
|
// 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);
|
surface = win->GetDfbSurface()->GetSubSurface(&dfbrect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,20 +106,31 @@ void wxWindowDC::InitForWin(wxWindow *win, const wxRect *rect)
|
|||||||
SetFont(win->GetFont());
|
SetFont(win->GetFont());
|
||||||
|
|
||||||
// offset coordinates to account for subsurface's origin coordinates:
|
// offset coordinates to account for subsurface's origin coordinates:
|
||||||
if ( rect )
|
SetDeviceOrigin(origin.x, origin.y);
|
||||||
SetDeviceOrigin(rect->x, rect->y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
wxWindowDC::~wxWindowDC()
|
||||||
// base class for wxClientDC and wxPaintDC
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
wxClientDCBase::wxClientDCBase(wxWindow *win)
|
|
||||||
{
|
{
|
||||||
wxCHECK_RET( win, _T("invalid window") );
|
wxIDirectFBSurfacePtr surface(GetDirectFBSurface());
|
||||||
|
if ( !surface || !m_win )
|
||||||
|
return;
|
||||||
|
|
||||||
wxRect rect = win->GetClientRect();
|
// painting on hidden window has no effect on TLW's surface, don't
|
||||||
InitForWin(win, &rect);
|
// 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)
|
IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
|
||||||
|
|
||||||
wxClientDC::~wxClientDC()
|
wxClientDC::wxClientDC(wxWindow *win)
|
||||||
{
|
{
|
||||||
// flip to surface so that the changes become visible
|
wxCHECK_RET( win, _T("invalid window") );
|
||||||
wxIDirectFBSurfacePtr surface(GetDirectFBSurface());
|
|
||||||
|
|
||||||
// FIXME: do this only if the surface was modified (as opposed to e.g.
|
wxRect rect = win->GetClientRect();
|
||||||
// used only to obtain text metrics)
|
InitForWin(win, &rect);
|
||||||
if ( surface )
|
|
||||||
surface->Flip(NULL, DSFLIP_NONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@@ -127,12 +152,3 @@ wxClientDC::~wxClientDC()
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxWindowDC)
|
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
|
|
||||||
}
|
|
||||||
|
@@ -41,13 +41,10 @@ static wxDfbWindowsMap gs_dfbWindowsMap;
|
|||||||
|
|
||||||
struct wxDfbPaintRequest
|
struct wxDfbPaintRequest
|
||||||
{
|
{
|
||||||
wxDfbPaintRequest(const wxRect& rect, bool eraseBackground)
|
wxDfbPaintRequest(const wxRect& rect) : m_rect(rect) {}
|
||||||
: m_rect(rect), m_eraseBackground(eraseBackground) {}
|
wxDfbPaintRequest(const wxDfbPaintRequest& r) : m_rect(r.m_rect) {}
|
||||||
wxDfbPaintRequest(const wxDfbPaintRequest& r)
|
|
||||||
: m_rect(r.m_rect), m_eraseBackground(r.m_eraseBackground) {}
|
|
||||||
|
|
||||||
wxRect m_rect;
|
wxRect m_rect;
|
||||||
bool m_eraseBackground;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
WX_DEFINE_ARRAY_PTR(wxDfbPaintRequest*, wxDfbQueuedPaintRequestsList);
|
WX_DEFINE_ARRAY_PTR(wxDfbPaintRequest*, wxDfbQueuedPaintRequestsList);
|
||||||
@@ -59,8 +56,8 @@ public:
|
|||||||
~wxDfbQueuedPaintRequests() { Clear(); }
|
~wxDfbQueuedPaintRequests() { Clear(); }
|
||||||
|
|
||||||
// Adds paint request to the queue
|
// Adds paint request to the queue
|
||||||
void Add(const wxRect& rect, bool eraseBack)
|
void Add(const wxRect& rect)
|
||||||
{ m_queue.push_back(new wxDfbPaintRequest(rect, eraseBack)); }
|
{ m_queue.push_back(new wxDfbPaintRequest(rect)); }
|
||||||
|
|
||||||
// Is the queue empty?
|
// Is the queue empty?
|
||||||
bool IsEmpty() const { return m_queue.empty(); }
|
bool IsEmpty() const { return m_queue.empty(); }
|
||||||
@@ -91,6 +88,7 @@ void wxTopLevelWindowDFB::Init()
|
|||||||
m_sizeSet = false;
|
m_sizeSet = false;
|
||||||
m_opacity = 255;
|
m_opacity = 255;
|
||||||
m_toPaint = new wxDfbQueuedPaintRequests;
|
m_toPaint = new wxDfbQueuedPaintRequests;
|
||||||
|
m_isPainting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxTopLevelWindowDFB::Create(wxWindow *parent,
|
bool wxTopLevelWindowDFB::Create(wxWindow *parent,
|
||||||
@@ -148,7 +146,8 @@ bool wxTopLevelWindowDFB::Create(wxWindow *parent,
|
|||||||
if ( !m_dfbwin->SetOpacity(wxALPHA_TRANSPARENT) )
|
if ( !m_dfbwin->SetOpacity(wxALPHA_TRANSPARENT) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
wxWindow::Create(NULL, id, pos, size, style, name);
|
if ( !wxWindow::Create(NULL, id, pos, size, style, name) )
|
||||||
|
return false;
|
||||||
|
|
||||||
SetParent(parent);
|
SetParent(parent);
|
||||||
if ( parent )
|
if ( parent )
|
||||||
@@ -217,7 +216,8 @@ void wxTopLevelWindowDFB::DoMoveWindow(int x, int y, int width, int height)
|
|||||||
{
|
{
|
||||||
m_dfbwin->Resize(width, height);
|
m_dfbwin->Resize(width, height);
|
||||||
// we must repaint the window after it changed size:
|
// 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 winRect(wxPoint(0, 0), GetSize());
|
||||||
wxRect paintedRect;
|
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();
|
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 )
|
for ( size_t i = 0; i < cnt; ++i )
|
||||||
{
|
{
|
||||||
const wxDfbPaintRequest& request = *requests[i];
|
const wxDfbPaintRequest& request = *requests[i];
|
||||||
|
|
||||||
wxRect clipped(request.m_rect);
|
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);
|
clipped.Intersect(winRect);
|
||||||
if ( clipped.IsEmpty() )
|
if ( clipped.IsEmpty() )
|
||||||
continue; // nothing to refresh
|
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:
|
// remember rectangle covering all repainted areas:
|
||||||
if ( paintedRect.IsEmpty() )
|
if ( paintedRect.IsEmpty() )
|
||||||
@@ -400,23 +407,49 @@ void wxTopLevelWindowDFB::HandleQueuedPaintRequests()
|
|||||||
paintedRect.Union(clipped);
|
paintedRect.Union(clipped);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_isPainting = false;
|
||||||
|
|
||||||
m_toPaint->Clear();
|
m_toPaint->Clear();
|
||||||
|
|
||||||
if ( paintedRect.IsEmpty() )
|
if ( paintedRect.IsEmpty() )
|
||||||
return; // no painting occurred, no need to flip
|
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(),
|
DFBRegion r = {paintedRect.GetLeft(), paintedRect.GetTop(),
|
||||||
paintedRect.GetRight(), paintedRect.GetBottom()};
|
paintedRect.GetRight(), paintedRect.GetBottom()};
|
||||||
DFBRegion *rptr = (winRect == paintedRect) ? NULL : &r;
|
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:
|
// defer painting until idle time or until Update() is called:
|
||||||
m_toPaint->Add(rect, eraseBack);
|
m_toPaint->Add(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxTopLevelWindowDFB::Update()
|
void wxTopLevelWindowDFB::Update()
|
||||||
|
@@ -590,34 +590,56 @@ void wxWindowDFB::Clear()
|
|||||||
dc.Clear();
|
dc.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxWindowDFB::Refresh(bool eraseBack, const wxRect *rect)
|
void wxWindowDFB::Refresh(bool WXUNUSED(eraseBack), const wxRect *rect)
|
||||||
{
|
{
|
||||||
if ( !IsShown() || IsFrozen() )
|
if ( !IsShown() || IsFrozen() )
|
||||||
return;
|
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 )
|
if ( rect )
|
||||||
DoRefreshRect(*rect, eraseBack);
|
DoRefreshRect(*rect);
|
||||||
else
|
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();
|
wxWindow *parent = GetParent();
|
||||||
wxCHECK_RET( parent, _T("no parent") );
|
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
|
// convert the refresh rectangle to parent's coordinates and
|
||||||
// recursively refresh the parent:
|
// recursively refresh the parent:
|
||||||
wxRect r(rect);
|
|
||||||
r.Offset(GetPosition());
|
r.Offset(GetPosition());
|
||||||
r.Offset(parent->GetClientAreaOrigin());
|
r.Offset(parent->GetClientAreaOrigin());
|
||||||
|
|
||||||
parent->DoRefreshRect(r, eraseBack);
|
parent->DoRefreshRect(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxWindowDFB::Update()
|
void wxWindowDFB::Update()
|
||||||
@@ -640,24 +662,21 @@ void wxWindowDFB::Thaw()
|
|||||||
if ( --m_frozenness == 0 )
|
if ( --m_frozenness == 0 )
|
||||||
{
|
{
|
||||||
if ( IsShown() )
|
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") );
|
wxCHECK_RET( !IsFrozen() && IsShown(), _T("shouldn't be called") );
|
||||||
|
|
||||||
wxLogTrace(TRACE_PAINT,
|
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(),
|
this, GetName().c_str(),
|
||||||
rect.x, rect.y, rect.width, rect.height);
|
rect.x, rect.y, rect.GetRight(), rect.GetBottom());
|
||||||
|
|
||||||
m_updateRegion = rect;
|
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
|
#if wxUSE_CARET
|
||||||
// must hide caret temporarily, otherwise we'd get rendering artifacts
|
// must hide caret temporarily, otherwise we'd get rendering artifacts
|
||||||
wxCaret *caret = GetCaret();
|
wxCaret *caret = GetCaret();
|
||||||
@@ -665,27 +684,52 @@ void wxWindowDFB::PaintWindow(const wxRect& rect, bool eraseBackground)
|
|||||||
caret->Hide();
|
caret->Hide();
|
||||||
#endif // wxUSE_CARET
|
#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);
|
wxWindowDC dc((wxWindow*)this);
|
||||||
wxEraseEvent eventEr(m_windowId, &dc);
|
wxEraseEvent eventEr(m_windowId, &dc);
|
||||||
eventEr.SetEventObject(this);
|
eventEr.SetEventObject(this);
|
||||||
GetEventHandler()->ProcessEvent(eventEr);
|
GetEventHandler()->ProcessEvent(eventEr);
|
||||||
}
|
|
||||||
|
|
||||||
|
wxRect clientRect(GetClientRect());
|
||||||
|
|
||||||
|
// only send wxNcPaintEvent if drawing at least part of nonclient area:
|
||||||
|
if ( !clientRect.Inside(rect) )
|
||||||
|
{
|
||||||
wxNcPaintEvent eventNc(GetId());
|
wxNcPaintEvent eventNc(GetId());
|
||||||
eventNc.SetEventObject(this);
|
eventNc.SetEventObject(this);
|
||||||
GetEventHandler()->ProcessEvent(eventNc);
|
GetEventHandler()->ProcessEvent(eventNc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wxLogTrace(TRACE_PAINT, _T("%p ('%s'): not sending wxNcPaintEvent"),
|
||||||
|
this, GetName().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// only send wxPaintEvent if drawing at least part of client area:
|
||||||
|
if ( rect.Intersects(clientRect) )
|
||||||
|
{
|
||||||
wxPaintEvent eventPt(GetId());
|
wxPaintEvent eventPt(GetId());
|
||||||
eventPt.SetEventObject(this);
|
eventPt.SetEventObject(this);
|
||||||
GetEventHandler()->ProcessEvent(eventPt);
|
GetEventHandler()->ProcessEvent(eventPt);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wxLogTrace(TRACE_PAINT, _T("%p ('%s'): not sending wxPaintEvent"),
|
||||||
|
this, GetName().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
#if wxUSE_CARET
|
#if wxUSE_CARET
|
||||||
if ( caret )
|
if ( caret )
|
||||||
caret->Show();
|
caret->Show();
|
||||||
#endif // wxUSE_CARET
|
#endif // wxUSE_CARET
|
||||||
|
|
||||||
|
m_updateRegion.Clear();
|
||||||
|
|
||||||
|
// paint the children:
|
||||||
wxPoint origin = GetClientAreaOrigin();
|
wxPoint origin = GetClientAreaOrigin();
|
||||||
wxWindowList& children = GetChildren();
|
wxWindowList& children = GetChildren();
|
||||||
for ( wxWindowList::iterator i = children.begin();
|
for ( wxWindowList::iterator i = children.begin();
|
||||||
@@ -704,13 +748,10 @@ void wxWindowDFB::PaintWindow(const wxRect& rect, bool eraseBackground)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// and repaint it:
|
// and repaint it:
|
||||||
wxPoint childpos(child->GetPosition());
|
childrect.Offset(-child->GetPosition());
|
||||||
childrect.Offset(-childpos.x, -childpos.y);
|
childrect.Offset(-origin);
|
||||||
childrect.Offset(-origin.x, -origin.y);
|
child->PaintWindow(childrect);
|
||||||
child->PaintWindow(childrect, eraseBackground);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_updateRegion.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -166,3 +166,17 @@ wxIDirectFBSurfacePtr wxIDirectFBSurface::Clone()
|
|||||||
|
|
||||||
return snew;
|
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);
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user