diff --git a/src/tests/servers/app/newerClipping/ClientLooper.cpp b/src/tests/servers/app/newerClipping/ClientLooper.cpp new file mode 100644 index 0000000000..28b5492f4b --- /dev/null +++ b/src/tests/servers/app/newerClipping/ClientLooper.cpp @@ -0,0 +1,68 @@ + +#include + +#include +#include +#include + +#include "WindowLayer.h" + +#include "ClientLooper.h" + +#define SLOW_DRAWING 0 + +// constructor +ClientLooper::ClientLooper(const char* name, WindowLayer* serverWindow) + : BLooper(""), + fServerWindow(serverWindow), + fViewCount(0) +{ + BString clientName(name); + clientName << " client"; + SetName(clientName.String()); +} + +// destructor +ClientLooper::~ClientLooper() +{ +} + +// MessageReceived +void +ClientLooper::MessageReceived(BMessage* message) +{ + switch (message->what) { + case MSG_UPDATE: + + fServerWindow->PostMessage(MSG_BEGIN_UPDATE); + + for (int32 i = 0; i < fViewCount; i++) { + // the client is slow + snooze(1000L); + // send the command to redraw a view + BMessage command(MSG_DRAWING_COMMAND); + command.AddInt32("token", i); + fServerWindow->PostMessage(&command); + } + + fServerWindow->PostMessage(MSG_END_UPDATE); + + break; + case MSG_VIEWS_ADDED: { + int32 count; + if (message->FindInt32("count", &count) >= B_OK) { + fViewCount += count; + } + break; + } + case MSG_VIEWS_REMOVED: { + int32 count; + if (message->FindInt32("count", &count) >= B_OK) + fViewCount -= count; + break; + } + default: + BLooper::MessageReceived(message); + break; + } +} diff --git a/src/tests/servers/app/newerClipping/ClientLooper.h b/src/tests/servers/app/newerClipping/ClientLooper.h new file mode 100644 index 0000000000..43c4cf9f00 --- /dev/null +++ b/src/tests/servers/app/newerClipping/ClientLooper.h @@ -0,0 +1,28 @@ + +#ifndef CLIENT_LOOPER_H +#define CLIENT_LOOPER_H + +#include + +class WindowLayer; + +enum { + MSG_UPDATE = 'updt', + MSG_VIEWS_ADDED = 'vwad', + MSG_VIEWS_REMOVED = 'vwrm', +}; + +class ClientLooper : public BLooper { + public: + ClientLooper(const char* name, + WindowLayer* serverWindow); + virtual ~ClientLooper(); + + virtual void MessageReceived(BMessage* message); + + private: + WindowLayer* fServerWindow; + int32 fViewCount; +}; + +#endif // CLIENT_LOOPER_H diff --git a/src/tests/servers/app/newerClipping/Desktop.cpp b/src/tests/servers/app/newerClipping/Desktop.cpp index 9d8f162d3c..5ab9fb76ca 100644 --- a/src/tests/servers/app/newerClipping/Desktop.cpp +++ b/src/tests/servers/app/newerClipping/Desktop.cpp @@ -114,6 +114,8 @@ Desktop::MouseDown(BPoint where, uint32 buttons) // complete redraw #if RUN_WITH_FRAME_BUFFER if (fDrawingEngine->Lock()) { + fDirtyRegion.MakeEmpty(); + BRegion region(fDrawingEngine->Bounds()); fDrawingEngine->Unlock(); @@ -123,6 +125,7 @@ Desktop::MouseDown(BPoint where, uint32 buttons) _SetBackground(®ion); } #else + fDirtyRegion.MakeEmpty(); fDrawingEngine->MarkDirty(); #endif } @@ -156,10 +159,13 @@ Desktop::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage) if (dx != 0 || dy != 0) { if (fClickedWindow) { +//bigtime_t now = system_time(); if (fResizing) { ResizeWindowBy(fClickedWindow, dx, dy); +//printf("resizing: %lld\n", system_time() - now); } else { MoveWindowBy(fClickedWindow, dx, dy); +//printf("moving: %lld\n", system_time() - now); } } } @@ -355,9 +361,9 @@ Desktop::MoveWindowBy(WindowLayer* window, int32 x, int32 y) if (LockClipping()) { // the dirty region starts with the visible area of the window being moved BRegion newDirtyRegion(window->VisibleRegion()); - BRegion alreadyDirtyRegion(fDirtyRegion); // we have to move along the part of the current dirty region // that intersects with the window being moved + BRegion alreadyDirtyRegion(fDirtyRegion); alreadyDirtyRegion.IntersectWith(&window->VisibleRegion()); window->MoveBy(x, y); diff --git a/src/tests/servers/app/newerClipping/Desktop.h b/src/tests/servers/app/newerClipping/Desktop.h index dd35765512..e085f65116 100644 --- a/src/tests/servers/app/newerClipping/Desktop.h +++ b/src/tests/servers/app/newerClipping/Desktop.h @@ -65,7 +65,8 @@ class Desktop : public BLooper { void ReadUnlockClipping() { fClippingLock.WriteUnlock(); } # endif #else - bool ReadLockClipping() { return fClippingLock.LockWithTimeout(10000) >= B_OK; } + bool ReadLockClipping() { return fClippingLock.Lock(); } + bool ReadLockClippingWithTimeout() { return fClippingLock.LockWithTimeout(10000) >= B_OK; } void ReadUnlockClipping() { fClippingLock.Unlock(); } #endif diff --git a/src/tests/servers/app/newerClipping/ViewLayer.cpp b/src/tests/servers/app/newerClipping/ViewLayer.cpp index 68e469c88c..b5568d43e6 100644 --- a/src/tests/servers/app/newerClipping/ViewLayer.cpp +++ b/src/tests/servers/app/newerClipping/ViewLayer.cpp @@ -1,500 +1,627 @@ - -#include - -#include // for resize modes - -#include "Desktop.h" -#include "DrawingEngine.h" -#include "WindowLayer.h" - -#include "ViewLayer.h" - -extern BWindow* wind; - -// constructor -ViewLayer::ViewLayer(BRect frame, const char* name, - uint32 resizeMode, uint32 flags, - rgb_color viewColor) - : fName(name), - - fFrame(frame), - fScrollingOffset(0.0, 0.0), - - fViewColor(viewColor), - - fResizeMode(resizeMode), - fFlags(flags), - fShowLevel(1), - - fWindow(NULL), - fParent(NULL), - - fFirstChild(NULL), - fPreviousSibling(NULL), - fNextSibling(NULL), - fLastChild(NULL), - - fCurrentChild(NULL), - - fLocalClipping(Bounds()), - fScreenClipping(), - fScreenClippingValid(false) -{ - fFrame.left = float((int32)fFrame.left); - fFrame.top = float((int32)fFrame.top); - fFrame.right = float((int32)fFrame.right); - fFrame.bottom = float((int32)fFrame.bottom); -} - -// destructor -ViewLayer::~ViewLayer() -{ - // iterate over children and delete each one - ViewLayer* layer = fFirstChild; - while (layer) { - ViewLayer* toast = layer; - layer = layer->fNextSibling; - delete toast; - } -} - -// Bounds -BRect -ViewLayer::Bounds() const -{ - BRect bounds(fScrollingOffset.x, fScrollingOffset.y, - fScrollingOffset.x + fFrame.Width(), - fScrollingOffset.y + fFrame.Height()); - return bounds; -} - -// AttachedToWindow -void -ViewLayer::AttachedToWindow(WindowLayer* window) -{ - fWindow = window; - for (ViewLayer* child = FirstChild(); child; child = NextChild()) - child->AttachedToWindow(window); -} - - -// DetachedFromWindow -void -ViewLayer::DetachedFromWindow() -{ - fWindow = NULL; - for (ViewLayer* child = FirstChild(); child; child = NextChild()) - child->DetachedFromWindow(); -} - -// AddChild -void -ViewLayer::AddChild(ViewLayer* layer) -{ - if (layer->fParent) { - printf("ViewLayer::AddChild() - ViewLayer already has a parent\n"); - return; - } - - layer->fParent = this; - - if (!fLastChild) { - // no children yet - fFirstChild = layer; - } else { - // append layer to formerly last child - fLastChild->fNextSibling = layer; - layer->fPreviousSibling = fLastChild; - } - fLastChild = layer; - - RebuildClipping(false); - - if (fWindow) { - layer->AttachedToWindow(fWindow); - fWindow->MarkDirty(&layer->ScreenClipping()); - } -} - -// RemoveChild -bool -ViewLayer::RemoveChild(ViewLayer* layer) -{ - if (layer->fParent != this) { - printf("ViewLayer::RemoveChild(%p - %s) - ViewLayer is not child of this (%p) layer!\n", layer, layer ? layer->Name() : NULL, this); - return false; - } - - layer->fParent = NULL; - - if (fLastChild == layer) - fLastChild = layer->fPreviousSibling; - // layer->fNextSibling would be NULL - - if (fFirstChild == layer ) - fFirstChild = layer->fNextSibling; - // layer->fPreviousSibling would be NULL - - // connect child before and after layer - if (layer->fPreviousSibling) - layer->fPreviousSibling->fNextSibling = layer->fNextSibling; - - if (layer->fNextSibling) - layer->fNextSibling->fPreviousSibling = layer->fPreviousSibling; - - // layer has no siblings anymore - layer->fPreviousSibling = NULL; - layer->fNextSibling = NULL; - - if (fParent) { - RebuildClipping(false); - } - if (fWindow) { - layer->DetachedFromWindow(); - } - - return true; -} - -// FirstChild -ViewLayer* -ViewLayer::FirstChild() const -{ - fCurrentChild = fFirstChild; - return fCurrentChild; -} - -// PreviousChild -ViewLayer* -ViewLayer::PreviousChild() const -{ - fCurrentChild = fCurrentChild->fPreviousSibling; - return fCurrentChild; -} - -// NextChild -ViewLayer* -ViewLayer::NextChild() const -{ - fCurrentChild = fCurrentChild->fNextSibling; - return fCurrentChild; -} - -// LastChild -ViewLayer* -ViewLayer::LastChild() const -{ - fCurrentChild = fLastChild; - return fCurrentChild; -} - -// TopLayer -ViewLayer* -ViewLayer::TopLayer() -{ - if (fParent) - return fParent->TopLayer(); - - return this; -} - -// CountChildren -uint32 -ViewLayer::CountChildren() const -{ - uint32 count = 0; - if (ViewLayer* layer = fFirstChild) { - count++; - while (layer->fNextSibling) { - count++; - layer = layer->fNextSibling; - } - } - return count; -} - -// ConvertToParent -void -ViewLayer::ConvertToParent(BPoint* point) const -{ - // remove scrolling offset and convert to parent coordinate space - point->x += fFrame.left - fScrollingOffset.x; - point->y += fFrame.top - fScrollingOffset.y; -} - -// ConvertToParent -void -ViewLayer::ConvertToParent(BRect* rect) const -{ - // remove scrolling offset and convert to parent coordinate space - rect->OffsetBy(fFrame.left - fScrollingOffset.x, - fFrame.top - fScrollingOffset.y); -} - -// ConvertToParent -void -ViewLayer::ConvertToParent(BRegion* region) const -{ - // remove scrolling offset and convert to parent coordinate space - region->OffsetBy(fFrame.left - fScrollingOffset.x, - fFrame.top - fScrollingOffset.y); -} - -// ConvertToTop -void -ViewLayer::ConvertToTop(BPoint* point) const -{ - ConvertToParent(point); - - if (fParent) - fParent->ConvertToTop(point); -} - -// ConvertToTop -void -ViewLayer::ConvertToTop(BRect* rect) const -{ - ConvertToParent(rect); - - if (fParent) - fParent->ConvertToTop(rect); -} - -// ConvertToTop -void -ViewLayer::ConvertToTop(BRegion* region) const -{ - ConvertToParent(region); - - if (fParent) - fParent->ConvertToTop(region); -} - -// SetName -void -ViewLayer::SetName(const char* string) -{ - fName.SetTo(string); -} - -// MoveBy -void -ViewLayer::MoveBy(int32 x, int32 y) -{ - fFrame.OffsetBy(x, y); - - _InvalidateScreenClipping(true); - // TODO: ... -} - -// ResizeBy -void -ViewLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion) -{ - BRect oldBounds(Bounds()); - - fFrame.right += x; - fFrame.bottom += y; - - // layout the children - for (ViewLayer* child = FirstChild(); child; child = NextChild()) - child->ParentResized(x, y, dirtyRegion); - - // TODO: the dirty region must not include children! - BRegion dirty(Bounds()); - if (!(fFlags & B_FULL_UPDATE_ON_RESIZE)) - dirty.Exclude(oldBounds); - - if (dirty.CountRects() > 0) { - ConvertToTop(&dirty); - dirtyRegion->Include(&dirty); - } - - RebuildClipping(false); - _InvalidateScreenClipping(true); -} - -// ScrollBy -void -ViewLayer::ScrollBy(int32 x, int32 y) -{ - fScrollingOffset.x += x; - fScrollingOffset.y += y; - // TODO: CopyRegion... - // TODO: ... - - _InvalidateScreenClipping(true); -} - -// ParentResized -void -ViewLayer::ParentResized(int32 x, int32 y, BRegion* dirtyRegion) -{ - uint16 rm = fResizeMode & 0x0000FFFF; - BRect newFrame = fFrame; - - // follow with left side - if ((rm & 0x0F00U) == _VIEW_RIGHT_ << 8) - newFrame.left += x; - else if ((rm & 0x0F00U) == _VIEW_CENTER_ << 8) - newFrame.left += x / 2; - - // follow with right side - if ((rm & 0x000FU) == _VIEW_RIGHT_) - newFrame.right += x; - else if ((rm & 0x000FU) == _VIEW_CENTER_) - newFrame.right += x / 2; - - // follow with top side - if ((rm & 0xF000U) == _VIEW_BOTTOM_ << 12) - newFrame.top += y; - else if ((rm & 0xF000U) == _VIEW_CENTER_ << 12) - newFrame.top += y / 2; - - // follow with bottom side - if ((rm & 0x00F0U) == _VIEW_BOTTOM_ << 4) - newFrame.bottom += y; - else if ((rm & 0x00F0U) == _VIEW_CENTER_ << 4) - newFrame.bottom += y / 2; - - if (newFrame != fFrame) { - // MoveBy will change fFrame, so cache it - BRect oldFrame = fFrame; - MoveBy(newFrame.left - oldFrame.left, - newFrame.top - oldFrame.top); - - ResizeBy(newFrame.Width() - oldFrame.Width(), - newFrame.Height() - oldFrame.Height(), dirtyRegion); - } -} - -// Draw -void -ViewLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, bool deep) -{ - // we can only draw within our own area - BRegion redraw(ScreenClipping()); - // add the current clipping - redraw.IntersectWith(effectiveClipping); - - if (drawingEngine->Lock()) { - drawingEngine->ConstrainClippingRegion(&redraw); - - // fill visible region with white - drawingEngine->SetHighColor(255, 255, 255); - BRect b(Bounds()); - ConvertToTop(&b); - drawingEngine->FillRect(b); - - // draw a frame with the view color - b.OffsetTo(0.0, 0.0); - ConvertToTop(&b); - drawingEngine->SetHighColor(fViewColor); - drawingEngine->StrokeRect(b); - drawingEngine->StrokeLine(b.LeftTop(), b.RightBottom()); - - drawingEngine->ConstrainClippingRegion(NULL); - - drawingEngine->MarkDirty(&redraw); - drawingEngine->Unlock(); - } - - // let children draw - if (deep) { - // before passing the clipping on to children, exclude our - // own region from the available clipping - effectiveClipping->Exclude(&ScreenClipping()); - - for (ViewLayer* child = FirstChild(); child; child = NextChild()) { - child->Draw(drawingEngine, effectiveClipping, deep); - } - } -} - -// IsHidden -bool -ViewLayer::IsHidden() const -{ - // if we're explicitely hidden, then we're hidden... - if (fShowLevel < 1) - return true; - - // ...but if we're not hidden, we might still be hidden if our parent is - if (fParent) - return fParent->IsHidden(); - - // nope, definitely not hidden - return false; -} - -// Hide -void -ViewLayer::Hide() -{ - fShowLevel--; - - // TODO: track regions -} - -// Show -void -ViewLayer::Show() -{ - fShowLevel++; - - // TODO: track regions -} - -// PrintToStream -void -ViewLayer::PrintToStream() const -{ -} - -// RebuildClipping -void -ViewLayer::RebuildClipping(bool deep) -{ - // remember current local clipping in dirty region - BRegion oldLocalClipping(fLocalClipping); - - // the clipping spans over the bounds area - fLocalClipping.Set(Bounds()); - - // exclude all childs from the clipping - for (ViewLayer* child = FirstChild(); child; child = NextChild()) { - fLocalClipping.Exclude(child->Frame()); - - if (deep) - child->RebuildClipping(deep); - } - - fScreenClippingValid = false; -} - -// ScreenClipping -BRegion& -ViewLayer::ScreenClipping() const -{ - if (!fScreenClippingValid) { - fScreenClipping = fLocalClipping; - ConvertToTop(&fScreenClipping); - fScreenClippingValid = true; - } - return fScreenClipping; -} - -// _InvalidateScreenClipping -void -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); - } - } - -} - + +#include + +#include +#include // for resize modes + +#include "Desktop.h" +#include "DrawingEngine.h" +#include "WindowLayer.h" + +#include "ViewLayer.h" + +extern BWindow* wind; + +// constructor +ViewLayer::ViewLayer(BRect frame, const char* name, + uint32 resizeMode, uint32 flags, + rgb_color viewColor) + : fName(name), + + fFrame(frame), + fScrollingOffset(0.0, 0.0), + + fViewColor(viewColor), + + fResizeMode(resizeMode), + fFlags(flags), + fShowLevel(1), + + fWindow(NULL), + fParent(NULL), + fIsTopLayer(false), + + fFirstChild(NULL), + fPreviousSibling(NULL), + fNextSibling(NULL), + fLastChild(NULL), + + fCurrentChild(NULL), + + fLocalClipping(Bounds()), + fScreenClipping(), + fScreenClippingValid(false) +{ + fFrame.left = float((int32)fFrame.left); + fFrame.top = float((int32)fFrame.top); + fFrame.right = float((int32)fFrame.right); + fFrame.bottom = float((int32)fFrame.bottom); +} + +// destructor +ViewLayer::~ViewLayer() +{ + // iterate over children and delete each one + ViewLayer* layer = fFirstChild; + while (layer) { + ViewLayer* toast = layer; + layer = layer->fNextSibling; + delete toast; + } +} + +// Bounds +BRect +ViewLayer::Bounds() const +{ + BRect bounds(fScrollingOffset.x, fScrollingOffset.y, + fScrollingOffset.x + fFrame.Width(), + fScrollingOffset.y + fFrame.Height()); + return bounds; +} + +// AttachedToWindow +void +ViewLayer::AttachedToWindow(WindowLayer* window, bool topLayer) +{ + fWindow = window; + fIsTopLayer = topLayer; + + for (ViewLayer* child = FirstChild(); child; child = NextChild()) + child->AttachedToWindow(window); +} + + +// DetachedFromWindow +void +ViewLayer::DetachedFromWindow() +{ + fWindow = NULL; + for (ViewLayer* child = FirstChild(); child; child = NextChild()) + child->DetachedFromWindow(); +} + +// AddChild +void +ViewLayer::AddChild(ViewLayer* layer) +{ + if (layer->fParent) { + printf("ViewLayer::AddChild() - ViewLayer already has a parent\n"); + return; + } + + layer->fParent = this; + + if (!fLastChild) { + // no children yet + fFirstChild = layer; + } else { + // append layer to formerly last child + fLastChild->fNextSibling = layer; + layer->fPreviousSibling = fLastChild; + } + fLastChild = layer; + + RebuildClipping(false); + + if (fWindow) { + layer->AttachedToWindow(fWindow); + fWindow->MarkDirty(&layer->ScreenClipping()); + } +} + +// RemoveChild +bool +ViewLayer::RemoveChild(ViewLayer* layer) +{ + if (layer->fParent != this) { + printf("ViewLayer::RemoveChild(%p - %s) - ViewLayer is not child of this (%p) layer!\n", layer, layer ? layer->Name() : NULL, this); + return false; + } + + layer->fParent = NULL; + + if (fLastChild == layer) + fLastChild = layer->fPreviousSibling; + // layer->fNextSibling would be NULL + + if (fFirstChild == layer ) + fFirstChild = layer->fNextSibling; + // layer->fPreviousSibling would be NULL + + // connect child before and after layer + if (layer->fPreviousSibling) + layer->fPreviousSibling->fNextSibling = layer->fNextSibling; + + if (layer->fNextSibling) + layer->fNextSibling->fPreviousSibling = layer->fPreviousSibling; + + // layer has no siblings anymore + layer->fPreviousSibling = NULL; + layer->fNextSibling = NULL; + + if (fParent) { + RebuildClipping(false); + } + if (fWindow) { + layer->DetachedFromWindow(); + } + + return true; +} + +// FirstChild +ViewLayer* +ViewLayer::FirstChild() const +{ + fCurrentChild = fFirstChild; + return fCurrentChild; +} + +// PreviousChild +ViewLayer* +ViewLayer::PreviousChild() const +{ + fCurrentChild = fCurrentChild->fPreviousSibling; + return fCurrentChild; +} + +// NextChild +ViewLayer* +ViewLayer::NextChild() const +{ + fCurrentChild = fCurrentChild->fNextSibling; + return fCurrentChild; +} + +// LastChild +ViewLayer* +ViewLayer::LastChild() const +{ + fCurrentChild = fLastChild; + return fCurrentChild; +} + +// TopLayer +ViewLayer* +ViewLayer::TopLayer() +{ + if (fParent) + return fParent->TopLayer(); + + return this; +} + +// CountChildren +uint32 +ViewLayer::CountChildren(bool deep) const +{ + uint32 count = 0; + for (ViewLayer* child = FirstChild(); child; child = NextChild()) { + count++; + if (deep) { + count += child->CountChildren(deep); + } + } + return count; +} + +// CollectTokensForChildren +void +ViewLayer::CollectTokensForChildren(BList* tokenMap) const +{ + for (ViewLayer* child = FirstChild(); child; child = NextChild()) { + tokenMap->AddItem((void*)child); + child->CollectTokensForChildren(tokenMap); + } +} + +// ConvertToParent +void +ViewLayer::ConvertToParent(BPoint* point) const +{ + // remove scrolling offset and convert to parent coordinate space + point->x += fFrame.left - fScrollingOffset.x; + point->y += fFrame.top - fScrollingOffset.y; +} + +// ConvertToParent +void +ViewLayer::ConvertToParent(BRect* rect) const +{ + // remove scrolling offset and convert to parent coordinate space + rect->OffsetBy(fFrame.left - fScrollingOffset.x, + fFrame.top - fScrollingOffset.y); +} + +// ConvertToParent +void +ViewLayer::ConvertToParent(BRegion* region) const +{ + // remove scrolling offset and convert to parent coordinate space + region->OffsetBy(fFrame.left - fScrollingOffset.x, + fFrame.top - fScrollingOffset.y); +} + +// ConvertToTop +void +ViewLayer::ConvertToTop(BPoint* point) const +{ + ConvertToParent(point); + + if (fParent) + fParent->ConvertToTop(point); +} + +// ConvertToTop +void +ViewLayer::ConvertToTop(BRect* rect) const +{ + ConvertToParent(rect); + + if (fParent) + fParent->ConvertToTop(rect); +} + +// ConvertToTop +void +ViewLayer::ConvertToTop(BRegion* region) const +{ + ConvertToParent(region); + + if (fParent) + fParent->ConvertToTop(region); +} + +// SetName +void +ViewLayer::SetName(const char* string) +{ + fName.SetTo(string); +} + +#define HW_MOVE 0 + +// MoveBy +void +ViewLayer::MoveBy(int32 x, int32 y) +{ + if (x == 0 && y == 0) + return; + +#if HW_MOVE + if (!fIsTopLayer && fWindow) { + // blit to new location (children as well) + BRect screenRect; +if (fParent) { + screenRect = fFrame & fParent->Bounds(); + fParent->ConvertToTop(&screenRect); +} else { + screenRect = Bounds(); + ConvertToTop(&screenRect); +} + + BRegion effectiveClippingRegion; + fWindow->GetContentRegion(&effectiveClippingRegion); + effectiveClippingRegion.IntersectWith(&fWindow->VisibleRegion()); + + BRegion copyRegion(screenRect); + copyRegion.IntersectWith(&effectiveClippingRegion); + + copyRegion.OffsetBy(x, y); + copyRegion.IntersectWith(&effectiveClippingRegion); + + BRegion alreadyDirty(screenRect); + { + BRegion windowDirty(fWindow->DirtyRegion()); + alreadyDirty.IntersectWith(&windowDirty); + } + + fFrame.OffsetBy(x, y); + _MoveScreenClipping(x, y, true); + +if (fParent) { + screenRect = fFrame & fParent->Bounds(); + fParent->ConvertToTop(&screenRect); +} else { + screenRect = Bounds(); + ConvertToTop(&screenRect); +} + BRegion dirtyRegion(screenRect); + dirtyRegion.Exclude(©Region); + + alreadyDirty.OffsetBy(x, y); + dirtyRegion.Include(&alreadyDirty); + + fWindow->MarkDirty(&dirtyRegion); + + copyRegion.OffsetBy(-x, -y); + + if (fWindow->GetDrawingEngine()->Lock()) { + fWindow->GetDrawingEngine()->CopyRegion(©Region, x, y); + fWindow->GetDrawingEngine()->Unlock(); + } + } else { + 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 +} + +// ResizeBy +void +ViewLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion) +{ + if (x == 0 && y == 0) + return; + + BRect oldBounds(Bounds()); + + fFrame.right += x; + fFrame.bottom += y; + + BRegion dirty(Bounds()); + dirty.Include(oldBounds); + if (!(fFlags & B_FULL_UPDATE_ON_RESIZE)) { + // the dirty region is just the difference of + // old and new bounds + dirty.Exclude(oldBounds & Bounds()); + } + + _InvalidateScreenClipping(true); + + if (dirty.CountRects() > 0) { + // exclude children, they are expected to + // have included their own dirty regions + for (ViewLayer* child = FirstChild(); child; child = NextChild()) { + BRect previousChildVisible(child->Frame() & oldBounds); + if (dirty.Frame().Intersects(previousChildVisible)) { + dirty.Exclude(previousChildVisible); + } + } + + ConvertToTop(&dirty); + dirtyRegion->Include(&dirty); + } + + // layout the children + for (ViewLayer* child = FirstChild(); child; child = NextChild()) + child->ParentResized(x, y, dirtyRegion); + + // at this point, children are at their new locations, + // so we can rebuild the clipping + RebuildClipping(false); +} + +// ScrollBy +void +ViewLayer::ScrollBy(int32 x, int32 y) +{ + fScrollingOffset.x += x; + fScrollingOffset.y += y; + // TODO: CopyRegion... + // TODO: ... + + _InvalidateScreenClipping(true); +} + +// ParentResized +void +ViewLayer::ParentResized(int32 x, int32 y, BRegion* dirtyRegion) +{ + uint16 rm = fResizeMode & 0x0000FFFF; + BRect newFrame = fFrame; + + // follow with left side + if ((rm & 0x0F00U) == _VIEW_RIGHT_ << 8) + newFrame.left += x; + else if ((rm & 0x0F00U) == _VIEW_CENTER_ << 8) + newFrame.left += x / 2; + + // follow with right side + if ((rm & 0x000FU) == _VIEW_RIGHT_) + newFrame.right += x; + else if ((rm & 0x000FU) == _VIEW_CENTER_) + newFrame.right += x / 2; + + // follow with top side + if ((rm & 0xF000U) == _VIEW_BOTTOM_ << 12) + newFrame.top += y; + else if ((rm & 0xF000U) == _VIEW_CENTER_ << 12) + newFrame.top += y / 2; + + // follow with bottom side + if ((rm & 0x00F0U) == _VIEW_BOTTOM_ << 4) + newFrame.bottom += y; + else if ((rm & 0x00F0U) == _VIEW_CENTER_ << 4) + newFrame.bottom += y / 2; + + if (newFrame != fFrame) { + // MoveBy will change fFrame, so cache it + BRect oldFrame = fFrame; + MoveBy(newFrame.left - oldFrame.left, + newFrame.top - oldFrame.top); + + ResizeBy(newFrame.Width() - oldFrame.Width(), + newFrame.Height() - oldFrame.Height(), dirtyRegion); + } +} + +// Draw +void +ViewLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, bool deep) +{ + // we can only draw within our own area + BRegion redraw(ScreenClipping()); + // add the current clipping + redraw.IntersectWith(effectiveClipping); + + if (drawingEngine->Lock()) { + // fill visible region with white + drawingEngine->SetHighColor(255, 255, 255); + BRect b(Bounds()); + ConvertToTop(&b); + drawingEngine->FillRegion(&redraw); + + drawingEngine->MarkDirty(&redraw); + drawingEngine->Unlock(); + } + + // let children draw + if (deep) { + // before passing the clipping on to children, exclude our + // own region from the available clipping + effectiveClipping->Exclude(&ScreenClipping()); + + for (ViewLayer* child = FirstChild(); child; child = NextChild()) { + child->Draw(drawingEngine, effectiveClipping, deep); + } + } +} + +// ClientDraw +void +ViewLayer::ClientDraw(DrawingEngine* drawingEngine, BRegion* effectiveClipping) +{ + if (drawingEngine->Lock()) { + drawingEngine->ConstrainClippingRegion(effectiveClipping); + + // draw a frame with the view color + BRect b(Bounds()); + b.OffsetTo(0.0, 0.0); + ConvertToTop(&b); + drawingEngine->SetHighColor(fViewColor); + drawingEngine->StrokeRect(b); + drawingEngine->StrokeLine(b.LeftTop(), b.RightBottom()); + + drawingEngine->ConstrainClippingRegion(NULL); + + drawingEngine->MarkDirty(effectiveClipping); + drawingEngine->Unlock(); + } +} + +// IsHidden +bool +ViewLayer::IsHidden() const +{ + // if we're explicitely hidden, then we're hidden... + if (fShowLevel < 1) + return true; + + // ...but if we're not hidden, we might still be hidden if our parent is + if (fParent) + return fParent->IsHidden(); + + // nope, definitely not hidden + return false; +} + +// Hide +void +ViewLayer::Hide() +{ + fShowLevel--; + + // TODO: track regions +} + +// Show +void +ViewLayer::Show() +{ + fShowLevel++; + + // TODO: track regions +} + +// PrintToStream +void +ViewLayer::PrintToStream() const +{ +} + +// RebuildClipping +void +ViewLayer::RebuildClipping(bool deep) +{ + // remember current local clipping in dirty region + BRegion oldLocalClipping(fLocalClipping); + + // the clipping spans over the bounds area + fLocalClipping.Set(Bounds()); + + // exclude all childs from the clipping + for (ViewLayer* child = FirstChild(); child; child = NextChild()) { + fLocalClipping.Exclude(child->Frame()); + + if (deep) + child->RebuildClipping(deep); + } + + fScreenClippingValid = false; +} + +// ScreenClipping +BRegion& +ViewLayer::ScreenClipping() const +{ + if (!fScreenClippingValid) { + fScreenClipping = fLocalClipping; + ConvertToTop(&fScreenClipping); + fScreenClippingValid = true; + } + return fScreenClipping; +} + +// _InvalidateScreenClipping +void +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); + } + } +} + +// _MoveScreenClipping +void +ViewLayer::_MoveScreenClipping(int32 x, int32 y, bool deep) +{ + if (fScreenClippingValid) + fScreenClipping.OffsetBy(x, y); + + if (deep) { + // invalidate the childrens screen clipping as well + for (ViewLayer* child = FirstChild(); child; child = NextChild()) { + child->_MoveScreenClipping(x, y, deep); + } + } +} + diff --git a/src/tests/servers/app/newerClipping/ViewLayer.h b/src/tests/servers/app/newerClipping/ViewLayer.h index e19eab1bf5..737fb832aa 100644 --- a/src/tests/servers/app/newerClipping/ViewLayer.h +++ b/src/tests/servers/app/newerClipping/ViewLayer.h @@ -2,10 +2,11 @@ #ifndef VIEW_LAYER_H #define VIEW_LAYER_H +#include #include #include - +class BList; class DrawingEngine; class WindowLayer; @@ -26,7 +27,8 @@ class ViewLayer { inline rgb_color ViewColor() const { return fViewColor; } - void AttachedToWindow(WindowLayer* window); + void AttachedToWindow(WindowLayer* window, + bool topLayer = false); void DetachedFromWindow(); // tree stuff @@ -43,7 +45,8 @@ class ViewLayer { ViewLayer* TopLayer(); - uint32 CountChildren() const; + uint32 CountChildren(bool deep = false) const; + void CollectTokensForChildren(BList* tokenMap) const; // coordinate conversion void ConvertToParent(BPoint* point) const; @@ -66,23 +69,30 @@ class ViewLayer { void ParentResized(int32 dx, int32 dy, BRegion* dirtyRegion); + // for background clearing void Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, bool deep = false); + // to simulate drawing done from client side + void ClientDraw(DrawingEngine* drawingEngine, + BRegion* effectiveClipping); + bool IsHidden() const; void Hide(); void Show(); // clipping - void RebuildClipping(bool deep = false); + void RebuildClipping(bool deep); BRegion& ScreenClipping() const; // debugging void PrintToStream() const; private: - void _InvalidateScreenClipping(bool deep = false); + void _InvalidateScreenClipping(bool deep); + void _MoveScreenClipping(int32 x, int32 y, + bool deep); BString fName; // area within parent coordinate space @@ -98,6 +108,7 @@ private: WindowLayer* fWindow; ViewLayer* fParent; + bool fIsTopLayer; ViewLayer* fFirstChild; ViewLayer* fPreviousSibling; diff --git a/src/tests/servers/app/newerClipping/WindowLayer.cpp b/src/tests/servers/app/newerClipping/WindowLayer.cpp index 1251dc46e5..569b1b9489 100644 --- a/src/tests/servers/app/newerClipping/WindowLayer.cpp +++ b/src/tests/servers/app/newerClipping/WindowLayer.cpp @@ -5,6 +5,7 @@ #include #include +#include "ClientLooper.h" #include "Desktop.h" #include "DrawingEngine.h" @@ -29,7 +30,15 @@ WindowLayer::WindowLayer(BRect frame, const char* name, fTopLayer(NULL), fDrawingEngine(drawingEngine), - fDesktop(desktop) + fDesktop(desktop), + + fTokenViewMap(64), + + fClient(new ClientLooper(name, this)), + fCurrentUpdateSession(NULL), + fPendingUpdateSession(NULL), + fUpdateRequested(false), + fInUpdate(false) { // the top layer is special, it has a coordinate system // as if it was attached directly to the desktop, therefor, @@ -38,6 +47,9 @@ WindowLayer::WindowLayer(BRect frame, const char* name, // fFrame as if it had fTopLayer = new(nothrow) ViewLayer(fFrame, "top view", B_FOLLOW_ALL, 0, (rgb_color){ 255, 255, 255, 255 }); + fTopLayer->AttachedToWindow(this, true); + + fClient->Run(); } // destructor @@ -53,7 +65,7 @@ WindowLayer::MessageReceived(BMessage* message) switch (message->what) { case MSG_REDRAW: { if (!MessageQueue()->FindMessage(MSG_REDRAW, 0)) { - while (!fDesktop->ReadLockClipping()) { + while (!fDesktop->ReadLockClippingWithTimeout()) { //printf("%s MSG_REDRAW -> timeout\n", Name()); if (MessageQueue()->FindMessage(MSG_REDRAW, 0)) { //printf("%s MSG_REDRAW -> timeout - leaving because there are pending redraws\n", Name()); @@ -62,12 +74,25 @@ WindowLayer::MessageReceived(BMessage* message) } _DrawContents(fTopLayer); _DrawBorder(); + fDesktop->ReadUnlockClipping(); } else { //printf("%s MSG_REDRAW -> pending redraws\n", Name()); } break; } + case MSG_BEGIN_UPDATE: + _BeginUpdate(); + break; + case MSG_END_UPDATE: + _EndUpdate(); + break; + case MSG_DRAWING_COMMAND: { + int32 token; + if (message->FindInt32("token", &token) >= B_OK) + _DrawClient(token); + break; + } default: BLooper::MessageReceived(message); break; @@ -174,6 +199,11 @@ WindowLayer::MoveBy(int32 x, int32 y) if (fContentRegionValid) fContentRegion.OffsetBy(x, y); + if (fCurrentUpdateSession) + fCurrentUpdateSession->MoveBy(x, y); + if (fPendingUpdateSession) + fPendingUpdateSession->MoveBy(x, y); + fTopLayer->MoveBy(x, y); // TODO: move a local dirty region! @@ -210,6 +240,14 @@ WindowLayer::AddChild(ViewLayer* layer) { fTopLayer->AddChild(layer); + // inform client about the view + // (just a part of the simulation) + fTokenViewMap.MakeEmpty(); + fTopLayer->CollectTokensForChildren(&fTokenViewMap); + BMessage message(MSG_VIEWS_ADDED); + message.AddInt32("count", fTokenViewMap.CountItems()); + fClient->PostMessage(&message); + // TODO: trigger redraw for dirty regions } @@ -221,6 +259,18 @@ WindowLayer::MarkDirty(BRegion* regionOnScreen) fDesktop->MarkDirty(regionOnScreen); } +// DirtyRegion +BRegion +WindowLayer::DirtyRegion() +{ + BRegion dirty; + if (fDesktop->ReadLockClipping()) { + dirty = *fDesktop->DirtyRegion(); + fDesktop->ReadUnlockClipping(); + } + return dirty; +} + # pragma mark - // _DrawContents @@ -244,15 +294,16 @@ WindowLayer::_DrawContents(ViewLayer* layer) // TODO: simplify // ideally, there would only be a local fDirtyRegion, // that we need to intersect with. fDirtyRegion would - // alread only include fVisibleRegion + // 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); - - // send UPDATE message to the client here } //else { //printf(" nothing to do\n"); @@ -260,6 +311,35 @@ WindowLayer::_DrawContents(ViewLayer* layer) } +// _DrawClient +void +WindowLayer::_DrawClient(int32 token) +{ + ViewLayer* layer = (ViewLayer*)fTokenViewMap.ItemAt(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 (effectiveClipping.CountRects() > 0 && fDesktop->ReadLockClipping()) { + effectiveClipping.IntersectWith(&fVisibleRegion); + // TODO: This step seems too much + BRegion contentRegion; + GetContentRegion(&contentRegion); + effectiveClipping.IntersectWith(&contentRegion); + + layer->ClientDraw(fDrawingEngine, &effectiveClipping); + + fDesktop->ReadUnlockClipping(); + } +} + // _DrawBorder void WindowLayer::_DrawBorder() @@ -298,3 +378,90 @@ WindowLayer::_DrawBorder() //} } +// _MarkContentDirty +void +WindowLayer::_MarkContentDirty(BRegion* localDirty) +{ + if (localDirty->CountRects() <= 0) + return; + if (!fPendingUpdateSession) { + // create new pending + fPendingUpdateSession = new UpdateSession(*localDirty); + } else { + // add to pending + fPendingUpdateSession->Include(localDirty); + } + + if (!fUpdateRequested) { + // send this to client + fClient->PostMessage(MSG_UPDATE); + fUpdateRequested = true; + } +} + +// _BeginUpdate +void +WindowLayer::_BeginUpdate() +{ + if (fUpdateRequested && !fCurrentUpdateSession) { + fCurrentUpdateSession = fPendingUpdateSession; + fPendingUpdateSession = NULL; + + if (fCurrentUpdateSession) { + // all drawing command from the client + // will have the dirty region from the update + // session enforced + fInUpdate = true; + } + } +} + +// _EndUpdate +void +WindowLayer::_EndUpdate() +{ + if (fInUpdate) { + delete fCurrentUpdateSession; + fCurrentUpdateSession = NULL; + + fInUpdate = false; + } + if (fPendingUpdateSession) { + // send this to client + fClient->PostMessage(MSG_UPDATE); + fUpdateRequested = true; + } else { + fUpdateRequested = false; + } +} + +#pragma mark - + +// constructor +UpdateSession::UpdateSession(const BRegion& dirtyRegion) + : fDirtyRegion(dirtyRegion) +{ +} + +// destructor +UpdateSession::~UpdateSession() +{ +} + +// Include +void +UpdateSession::Include(BRegion* additionalDirty) +{ + fDirtyRegion.Include(additionalDirty); +} + +// MoveBy +void +UpdateSession::MoveBy(int32 x, int32 y) +{ + fDirtyRegion.OffsetBy(x, y); +} + + + + diff --git a/src/tests/servers/app/newerClipping/WindowLayer.h b/src/tests/servers/app/newerClipping/WindowLayer.h index 28dbae24c2..0356cfc793 100644 --- a/src/tests/servers/app/newerClipping/WindowLayer.h +++ b/src/tests/servers/app/newerClipping/WindowLayer.h @@ -2,17 +2,39 @@ #ifndef WINDOW_LAYER_H #define WINDOW_LAYER_H +#include #include #include #include #include "ViewLayer.h" +class ClientLooper; class Desktop; class DrawingEngine; enum { - MSG_REDRAW = 'rdrw', + MSG_REDRAW = 'rdrw', + + MSG_BEGIN_UPDATE = 'bgud', + MSG_END_UPDATE = 'edud', + MSG_DRAWING_COMMAND = 'draw', +}; + +class UpdateSession { + public: + UpdateSession(const BRegion& dirtyRegion); + virtual ~UpdateSession(); + + void Include(BRegion* additionalDirty); + + inline BRegion& DirtyRegion() + { return fDirtyRegion; } + + void MoveBy(int32 x, int32 y); + + private: + BRegion fDirtyRegion; }; class WindowLayer : public BLooper { @@ -42,10 +64,20 @@ class WindowLayer : public BLooper { void MarkDirty(BRegion* regionOnScreen); + DrawingEngine* GetDrawingEngine() const + { return fDrawingEngine; } + + BRegion DirtyRegion(); + private: void _DrawContents(ViewLayer* layer = NULL); + void _DrawClient(int32 token); void _DrawBorder(); + void _MarkContentDirty(BRegion* localDirty); + void _BeginUpdate(); + void _EndUpdate(); + BRect fFrame; // the visible region is only recalculated from the @@ -65,6 +97,14 @@ class WindowLayer : public BLooper { DrawingEngine* fDrawingEngine; Desktop* fDesktop; + + BList fTokenViewMap; + + ClientLooper* fClient; + UpdateSession* fCurrentUpdateSession; + UpdateSession* fPendingUpdateSession; + bool fUpdateRequested; + bool fInUpdate; }; #endif // WINDOW_LAYER_H diff --git a/src/tests/servers/app/newerClipping/makefile b/src/tests/servers/app/newerClipping/makefile index ccfd41ca82..a8b13b4f8a 100644 --- a/src/tests/servers/app/newerClipping/makefile +++ b/src/tests/servers/app/newerClipping/makefile @@ -30,7 +30,8 @@ TYPE= APP # if two source files with the same name (source.c or source.cpp) # are included from different directories. Also note that spaces # in folder names do not work well with this makefile. -SRCS= Desktop.cpp \ +SRCS= ClientLooper.cpp \ + Desktop.cpp \ DrawingEngine.cpp \ main.cpp \ MultiLocker.cpp \