still buggy but less buggy than before, more caching and less overhead

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15160 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2005-11-26 14:07:44 +00:00
parent 773be69904
commit 7f705589e2
5 changed files with 229 additions and 150 deletions
@@ -38,7 +38,7 @@ ClientLooper::MessageReceived(BMessage* message)
for (int32 i = 0; i < fViewCount; i++) {
// the client is slow
snooze(1000L);
// snooze(20000L);
// send the command to redraw a view
BMessage command(MSG_DRAWING_COMMAND);
command.AddInt32("token", i);
@@ -116,7 +116,19 @@ ViewLayer::AddChild(ViewLayer* layer)
if (fWindow) {
layer->AttachedToWindow(fWindow);
fWindow->MarkDirty(&layer->ScreenClipping());
// TODO: not correct... need something like
// ViewLayer::ClipToParent(BRect frame)
// {
// frame = frame & Bounds();
// ConvertToParent(&frame);
// fParent->ClipToParent(&frame);
// }
BRect dirty(layer->Frame());
dirty = dirty & Bounds();
ConvertToTop(&dirty);
BRegion dirtyRegion(dirty);
fWindow->MarkContentDirty(&dirtyRegion);
}
}
@@ -155,6 +167,7 @@ ViewLayer::RemoveChild(ViewLayer* layer)
}
if (fWindow) {
layer->DetachedFromWindow();
// TODO: handle exposed area
}
return true;
@@ -290,16 +303,14 @@ ViewLayer::SetName(const char* string)
fName.SetTo(string);
}
#define HW_MOVE 0
#if 0
// MoveBy
void
ViewLayer::MoveBy(int32 x, int32 y)
ViewLayer::MoveBy(int32 x, int32 y, BRegion* dirtyRegion)
{
if (x == 0 && y == 0)
return;
#if HW_MOVE
if (!fIsTopLayer && fWindow) {
// blit to new location (children as well)
BRect screenRect;
@@ -355,21 +366,46 @@ if (fParent) {
fFrame.OffsetBy(x, y);
_MoveScreenClipping(x, y, true);
}
#else // HW_MOVE
fFrame.OffsetBy(x, y);
_MoveScreenClipping(x, y, true);
if (!fIsTopLayer && fWindow) {
BRect screenRect(Bounds());
ConvertToTop(&screenRect);
screenRect = screenRect | screenRect.OffsetByCopy(-x, -y);
BRegion dirty(screenRect);
fWindow->MarkDirty(&dirty);
}
#endif // !HW_MOVE
}
#else // 0
// MoveBy
void
ViewLayer::MoveBy(int32 x, int32 y, BRegion* dirtyRegion)
{
if (x == 0 && y == 0)
return;
fFrame.OffsetBy(x, y);
InvalidateScreenClipping(true);
if (!fIsTopLayer && dirtyRegion) {
if (fParent) {
// clip to parent
BRect oldScreenRect(Bounds());
oldScreenRect.OffsetByCopy(-x, -y);
ConvertToParent(&oldScreenRect);
BRect screenRect(Bounds());
ConvertToParent(&screenRect);
// TODO: see AddLayer
BRect dirty = oldScreenRect | screenRect;
dirty = dirty & fParent->Bounds();
fParent->ConvertToTop(&dirty);
dirtyRegion->Include(dirty);
} else {
BRect screenRect(Bounds());
screenRect = screenRect | screenRect.OffsetByCopy(-x, -y);
ConvertToTop(&screenRect);
dirtyRegion->Include(screenRect);
}
}
}
#endif // 0
// ResizeBy
void
@@ -391,7 +427,7 @@ ViewLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion)
dirty.Exclude(oldBounds & Bounds());
}
_InvalidateScreenClipping(true);
InvalidateScreenClipping(true);
if (dirty.CountRects() > 0) {
// exclude children, they are expected to
@@ -418,14 +454,14 @@ ViewLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion)
// ScrollBy
void
ViewLayer::ScrollBy(int32 x, int32 y)
ViewLayer::ScrollBy(int32 x, int32 y, BRegion* dirtyRegion)
{
fScrollingOffset.x += x;
fScrollingOffset.y += y;
// TODO: CopyRegion...
// TODO: ...
_InvalidateScreenClipping(true);
InvalidateScreenClipping(true);
}
// ParentResized
@@ -463,7 +499,7 @@ ViewLayer::ParentResized(int32 x, int32 y, BRegion* dirtyRegion)
// MoveBy will change fFrame, so cache it
BRect oldFrame = fFrame;
MoveBy(newFrame.left - oldFrame.left,
newFrame.top - oldFrame.top);
newFrame.top - oldFrame.top, dirtyRegion);
ResizeBy(newFrame.Width() - oldFrame.Width(),
newFrame.Height() - oldFrame.Height(), dirtyRegion);
@@ -472,10 +508,11 @@ ViewLayer::ParentResized(int32 x, int32 y, BRegion* dirtyRegion)
// Draw
void
ViewLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, bool deep)
ViewLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping,
BRegion* windowContentClipping,bool deep)
{
// we can only draw within our own area
BRegion redraw(ScreenClipping());
BRegion redraw(ScreenClipping(windowContentClipping));
// add the current clipping
redraw.IntersectWith(effectiveClipping);
@@ -494,10 +531,11 @@ ViewLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, bool d
if (deep) {
// before passing the clipping on to children, exclude our
// own region from the available clipping
effectiveClipping->Exclude(&ScreenClipping());
effectiveClipping->Exclude(&ScreenClipping(windowContentClipping));
for (ViewLayer* child = FirstChild(); child; child = NextChild()) {
child->Draw(drawingEngine, effectiveClipping, deep);
child->Draw(drawingEngine, effectiveClipping,
windowContentClipping, deep);
}
}
}
@@ -587,25 +625,26 @@ ViewLayer::RebuildClipping(bool deep)
// ScreenClipping
BRegion&
ViewLayer::ScreenClipping() const
ViewLayer::ScreenClipping(BRegion* windowContentClipping, bool force) const
{
if (!fScreenClippingValid) {
if (!fScreenClippingValid || force) {
fScreenClipping = fLocalClipping;
ConvertToTop(&fScreenClipping);
fScreenClipping.IntersectWith(windowContentClipping);
fScreenClippingValid = true;
}
return fScreenClipping;
}
// _InvalidateScreenClipping
// InvalidateScreenClipping
void
ViewLayer::_InvalidateScreenClipping(bool deep)
ViewLayer::InvalidateScreenClipping(bool deep)
{
fScreenClippingValid = false;
if (deep) {
// invalidate the childrens screen clipping as well
for (ViewLayer* child = FirstChild(); child; child = NextChild()) {
child->_InvalidateScreenClipping(deep);
child->InvalidateScreenClipping(deep);
}
}
}
@@ -618,7 +657,7 @@ ViewLayer::_MoveScreenClipping(int32 x, int32 y, bool deep)
fScreenClipping.OffsetBy(x, y);
if (deep) {
// invalidate the childrens screen clipping as well
// move the childrens screen clipping as well
for (ViewLayer* child = FirstChild(); child; child = NextChild()) {
child->_MoveScreenClipping(x, y, deep);
}
+21 -13
View File
@@ -62,21 +62,27 @@ class ViewLayer {
inline const char* Name() const
{ return fName.String(); }
void MoveBy(int32 dx, int32 dy);
void ResizeBy(int32 dx, int32 dy, BRegion* dirtyRegion);
void ScrollBy(int32 dx, int32 dy);
void MoveBy( int32 dx, int32 dy,
BRegion* dirtyRegion);
void ParentResized(int32 dx, int32 dy,
BRegion* dirtyRegion);
void ResizeBy( int32 dx, int32 dy,
BRegion* dirtyRegion);
void ScrollBy( int32 dx, int32 dy,
BRegion* dirtyRegion);
void ParentResized( int32 dx, int32 dy,
BRegion* dirtyRegion);
// for background clearing
void Draw(DrawingEngine* drawingEngine,
BRegion* effectiveClipping,
bool deep = false);
void Draw( DrawingEngine* drawingEngine,
BRegion* effectiveClipping,
BRegion* windowContentClipping,
bool deep = false);
// to simulate drawing done from client side
void ClientDraw(DrawingEngine* drawingEngine,
BRegion* effectiveClipping);
// to simulate drawing triggered from client side
void ClientDraw( DrawingEngine* drawingEngine,
BRegion* effectiveClipping);
bool IsHidden() const;
void Hide();
@@ -84,13 +90,15 @@ class ViewLayer {
// clipping
void RebuildClipping(bool deep);
BRegion& ScreenClipping() const;
BRegion& ScreenClipping(BRegion* windowContentClipping,
bool force = false) const;
// debugging
void PrintToStream() const;
void InvalidateScreenClipping(bool deep);
private:
void _InvalidateScreenClipping(bool deep);
void _MoveScreenClipping(int32 x, int32 y,
bool deep);
@@ -18,12 +18,16 @@ WindowLayer::WindowLayer(BRect frame, const char* name,
DrawingEngine* drawingEngine, Desktop* desktop)
: BLooper(name),
fFrame(frame),
fVisibleRegion(),
fVisibleContentRegion(),
fBorderRegion(),
fBorderRegionValid(false),
fContentRegion(),
fContentRegionValid(false),
fEffectiveDrawingRegion(),
fEffectiveDrawingRegionValid(false),
fFocus(false),
@@ -103,10 +107,18 @@ WindowLayer::MessageReceived(BMessage* message)
void
WindowLayer::SetClipping(BRegion* stillAvailableOnScreen)
{
// this function is only called from the Desktop thread
// start from full region (as if the window was fully visible)
GetFullRegion(&fVisibleRegion);
// clip to region still available on screen
fVisibleRegion.IntersectWith(stillAvailableOnScreen);
GetContentRegion(&fVisibleContentRegion);
fVisibleContentRegion.IntersectWith(&fVisibleRegion);
fEffectiveDrawingRegionValid = false;
fTopLayer->InvalidateScreenClipping(true);
}
// GetFullRegion
@@ -123,45 +135,48 @@ WindowLayer::GetFullRegion(BRegion* region) const
// GetBorderRegion
void
WindowLayer::GetBorderRegion(BRegion* region) const
WindowLayer::GetBorderRegion(BRegion* region)
{
if (fBorderRegionValid) {
*region = fBorderRegion;
if (!fBorderRegionValid) {
// TODO: speed up by avoiding "Exclude()"
// start from the frame, extend to include decorator border
fBorderRegion.Set(BRect(fFrame.left - 4, fFrame.top - 4,
fFrame.right + 4, fFrame.bottom + 4));
fBorderRegion.Exclude(fFrame);
// add the title tab
fBorderRegion.Include(BRect(fFrame.left - 4, fFrame.top - 20,
(fFrame.left + fFrame.right) / 2, fFrame.top - 5));
// resize handle
// if (B_DOCUMENT_WINDOW_LOOK)
fBorderRegion.Include(BRect(fFrame.right - 10, fFrame.bottom - 10,
fFrame.right, fFrame.bottom));
fBorderRegionValid = true;
}
// TODO: speed up by avoiding "Exclude()"
// start from the frame, extend to include decorator border
region->Set(BRect(fFrame.left - 4, fFrame.top - 4,
fFrame.right + 4, fFrame.bottom + 4));
region->Exclude(fFrame);
// add the title tab
region->Include(BRect(fFrame.left - 4, fFrame.top - 20,
(fFrame.left + fFrame.right) / 2, fFrame.top - 5));
// resize handle
// if (B_DOCUMENT_WINDOW_LOOK)
region->Include(BRect(fFrame.right - 10, fFrame.bottom - 10,
fFrame.right, fFrame.bottom));
*region = fBorderRegion;
}
// GetContentRegion
void
WindowLayer::GetContentRegion(BRegion* region) const
WindowLayer::GetContentRegion(BRegion* region)
{
if (fContentRegionValid) {
*region = fContentRegion;
if (!fContentRegionValid) {
// TODO: speed up by avoiding "Exclude()"
// start from the frame, extend to include decorator border
fContentRegion.Set(fFrame);
// resize handle
// if (B_DOCUMENT_WINDOW_LOOK)
fContentRegion.Exclude(BRect(fFrame.right - 10, fFrame.bottom - 10,
fFrame.right, fFrame.bottom));
fContentRegionValid = true;
}
// TODO: speed up by avoiding "Exclude()"
// start from the frame, extend to include decorator border
region->Set(fFrame);
// resize handle
// if (B_DOCUMENT_WINDOW_LOOK)
region->Exclude(BRect(fFrame.right - 10, fFrame.bottom - 10,
fFrame.right, fFrame.bottom));
*region = fContentRegion;
}
// SetFocus
@@ -189,6 +204,8 @@ WindowLayer::SetFocus(bool focus)
void
WindowLayer::MoveBy(int32 x, int32 y)
{
// this function is only called from the desktop thread
if (x == 0 && y == 0)
return;
@@ -204,9 +221,11 @@ WindowLayer::MoveBy(int32 x, int32 y)
if (fPendingUpdateSession)
fPendingUpdateSession->MoveBy(x, y);
fTopLayer->MoveBy(x, y);
fEffectiveDrawingRegionValid = false;
// TODO: move a local dirty region!
fTopLayer->MoveBy(x, y, NULL);
// the desktop will take care of dirty regions
}
// ResizeBy
@@ -219,18 +238,21 @@ WindowLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion)
fFrame.right += x;
fFrame.bottom += y;
// put the previous border region into the dirty region as well
// to handle the part that was overlapping a layer
dirtyRegion->Include(&fBorderRegion);
fBorderRegionValid = false;
fContentRegionValid = false;
fEffectiveDrawingRegionValid = false;
// the border is dirty, put it into
// dirtyRegion for a start
GetBorderRegion(dirtyRegion);
// put the previous border region into the dirty region as well
// to handle the part that was overlapping a layer
// if B_DOCUMENT_WINDOW_LOOK
dirtyRegion->Include(&fBorderRegion);
BRegion newBorderRegion;
GetBorderRegion(&newBorderRegion);
dirtyRegion->Include(&newBorderRegion);
// TODO: should this be clipped to the content region?
fTopLayer->ResizeBy(x, y, dirtyRegion);
}
@@ -259,6 +281,19 @@ WindowLayer::MarkDirty(BRegion* regionOnScreen)
fDesktop->MarkDirty(regionOnScreen);
}
// MarkDirty
void
WindowLayer::MarkContentDirty(BRegion* regionOnScreen)
{
if (fDesktop && fDesktop->LockClipping()) {
regionOnScreen->IntersectWith(&fVisibleContentRegion);
fDesktop->MarkDirty(regionOnScreen);
fDesktop->UnlockClipping();
}
}
/*
// DirtyRegion
BRegion
WindowLayer::DirtyRegion()
@@ -270,7 +305,7 @@ WindowLayer::DirtyRegion()
}
return dirty;
}
*/
# pragma mark -
// _DrawContents
@@ -285,30 +320,23 @@ WindowLayer::_DrawContents(ViewLayer* layer)
if (!layer)
layer = fTopLayer;
if (!fContentRegionValid) {
GetContentRegion(&fContentRegion);
fContentRegionValid = true;
if (fDesktop->ReadLockClipping()) {
BRegion effectiveWindowClipping(fVisibleContentRegion);
effectiveWindowClipping.IntersectWith(fDesktop->DirtyRegion());
if (effectiveWindowClipping.Frame().IsValid()) {
// send UPDATE message to the client
_MarkContentDirty(&effectiveWindowClipping);
layer->Draw(fDrawingEngine, &effectiveWindowClipping,
&fVisibleContentRegion, true);
fDesktop->MarkClean(&fContentRegion);
}
fDesktop->ReadUnlockClipping();
}
BRegion effectiveWindowClipping(fContentRegion);
// TODO: simplify
// ideally, there would only be a local fDirtyRegion,
// that we need to intersect with. fDirtyRegion would
// already only include fVisibleRegion
effectiveWindowClipping.IntersectWith(&fVisibleRegion);
effectiveWindowClipping.IntersectWith(fDesktop->DirtyRegion());
if (effectiveWindowClipping.Frame().IsValid()) {
// send UPDATE message to the client here
_MarkContentDirty(&effectiveWindowClipping);
layer->Draw(fDrawingEngine, &effectiveWindowClipping, true);
fDesktop->MarkClean(&fContentRegion);
}
//else {
//printf(" nothing to do\n");
//}
}
// _DrawClient
@@ -319,22 +347,25 @@ WindowLayer::_DrawClient(int32 token)
if (!layer)
return;
BRegion effectiveClipping(layer->ScreenClipping());
if (fInUpdate) {
// enforce the dirty region of the update session
effectiveClipping.IntersectWith(&fCurrentUpdateSession->DirtyRegion());
} else {
printf("%s - _DrawClient(token: %ld) - not in update\n", Name(), token);
}
if (fDesktop->ReadLockClipping()) {
if (effectiveClipping.CountRects() > 0 && fDesktop->ReadLockClipping()) {
effectiveClipping.IntersectWith(&fVisibleRegion);
// TODO: This step seems too much
BRegion contentRegion;
GetContentRegion(&contentRegion);
effectiveClipping.IntersectWith(&contentRegion);
if (!fEffectiveDrawingRegionValid) {
fEffectiveDrawingRegion = fVisibleContentRegion;
if (fInUpdate) {
// enforce the dirty region of the update session
fEffectiveDrawingRegion.IntersectWith(&fCurrentUpdateSession->DirtyRegion());
} else {
printf("%s - _DrawClient(token: %ld) - not in update\n", Name(), token);
}
fEffectiveDrawingRegionValid = true;
}
layer->ClientDraw(fDrawingEngine, &effectiveClipping);
BRegion effectiveClipping(fEffectiveDrawingRegion);
effectiveClipping.IntersectWith(&layer->ScreenClipping(&fVisibleContentRegion));
if (effectiveClipping.CountRects() > 0) {
layer->ClientDraw(fDrawingEngine, &effectiveClipping);
}
fDesktop->ReadUnlockClipping();
}
@@ -348,34 +379,31 @@ WindowLayer::_DrawBorder()
#if SLOW_DRAWING
snooze(10000);
#endif
if (!fBorderRegionValid) {
GetBorderRegion(&fBorderRegion);
fBorderRegionValid = true;
}
// construct the region of the border that needs redrawing
BRegion dirtyBorderRegion(fBorderRegion);
// intersect with our visible region
dirtyBorderRegion.IntersectWith(&fVisibleRegion);
// intersect with the Desktop's dirty region
dirtyBorderRegion.IntersectWith(fDesktop->DirtyRegion());
if (dirtyBorderRegion.Frame().IsValid()) {
if (fDrawingEngine->Lock()) {
if (fFocus)
fDrawingEngine->SetHighColor(255, 203, 0, 255);
else
fDrawingEngine->SetHighColor(216, 216, 216, 0);
fDrawingEngine->FillRegion(&dirtyBorderRegion);
fDrawingEngine->MarkDirty(&dirtyBorderRegion);
fDrawingEngine->Unlock();
if (fDesktop->ReadLockClipping()) {
// construct the region of the border that needs redrawing
BRegion dirtyBorderRegion;
GetBorderRegion(&dirtyBorderRegion);
// intersect with our visible region
dirtyBorderRegion.IntersectWith(&fVisibleRegion);
// intersect with the Desktop's dirty region
dirtyBorderRegion.IntersectWith(fDesktop->DirtyRegion());
if (dirtyBorderRegion.Frame().IsValid()) {
if (fDrawingEngine->Lock()) {
if (fFocus)
fDrawingEngine->SetHighColor(255, 203, 0, 255);
else
fDrawingEngine->SetHighColor(216, 216, 216, 0);
fDrawingEngine->FillRegion(&dirtyBorderRegion);
fDrawingEngine->MarkDirty(&dirtyBorderRegion);
fDrawingEngine->Unlock();
}
fDesktop->MarkClean(&dirtyBorderRegion);
}
fDesktop->MarkClean(&dirtyBorderRegion);
fDesktop->ReadUnlockClipping();
}
//else {
//printf(" nothing to do\n");
//}
}
// _MarkContentDirty
@@ -52,8 +52,8 @@ class WindowLayer : public BLooper {
inline BRegion& VisibleRegion()
{ return fVisibleRegion; }
void GetFullRegion(BRegion* region) const;
void GetBorderRegion(BRegion* region) const;
void GetContentRegion(BRegion* region) const;
void GetBorderRegion(BRegion* region);
void GetContentRegion(BRegion* region);
void SetFocus(bool focus);
@@ -63,11 +63,12 @@ class WindowLayer : public BLooper {
void AddChild(ViewLayer* layer);
void MarkDirty(BRegion* regionOnScreen);
void MarkContentDirty(BRegion* regionOnScreen);
DrawingEngine* GetDrawingEngine() const
{ return fDrawingEngine; }
BRegion DirtyRegion();
// BRegion DirtyRegion();
private:
void _DrawContents(ViewLayer* layer = NULL);
@@ -84,12 +85,15 @@ class WindowLayer : public BLooper {
// Desktop thread, when using it, Desktop::LockClipping()
// has to be called
BRegion fVisibleRegion;
BRegion fVisibleContentRegion;
// caching local regions
BRegion fBorderRegion;
bool fBorderRegionValid;
BRegion fContentRegion;
bool fContentRegionValid;
BRegion fEffectiveDrawingRegion;
bool fEffectiveDrawingRegionValid;
bool fFocus;