diff --git a/src/tests/servers/app/newerClipping/Desktop.cpp b/src/tests/servers/app/newerClipping/Desktop.cpp index 08fd756b40..e10278adff 100644 --- a/src/tests/servers/app/newerClipping/Desktop.cpp +++ b/src/tests/servers/app/newerClipping/Desktop.cpp @@ -159,13 +159,13 @@ Desktop::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage) if (dx != 0 || dy != 0) { if (fClickedWindow) { -bigtime_t now = system_time(); +//bigtime_t now = system_time(); if (fResizing) { ResizeWindowBy(fClickedWindow, dx, dy); -printf("resizing: %lld\n", system_time() - now); +//printf("resizing: %lld\n", system_time() - now); } else { MoveWindowBy(fClickedWindow, dx, dy); -printf("moving: %lld\n", system_time() - now); +//printf("moving: %lld\n", system_time() - now); } } } @@ -358,6 +358,9 @@ Desktop::BottomWindow() const void Desktop::MoveWindowBy(WindowLayer* window, int32 x, int32 y) { + if (!Lock()) + return; + if (LockClipping()) { // the dirty region starts with the visible area of the window being moved BRegion newDirtyRegion(window->VisibleRegion()); @@ -403,12 +406,17 @@ Desktop::MoveWindowBy(WindowLayer* window, int32 x, int32 y) UnlockClipping(); } + + Unlock(); } // ResizeWindowBy void Desktop::ResizeWindowBy(WindowLayer* window, int32 x, int32 y) { + if (!Lock()) + return; + if (LockClipping()) { BRegion newDirtyRegion; BRegion previouslyOccupiedRegion(window->VisibleRegion()); @@ -428,6 +436,8 @@ Desktop::ResizeWindowBy(WindowLayer* window, int32 x, int32 y) UnlockClipping(); } + + Unlock(); } // BringToFront diff --git a/src/tests/servers/app/newerClipping/ViewLayer.cpp b/src/tests/servers/app/newerClipping/ViewLayer.cpp index 61490957c6..83180bd588 100644 --- a/src/tests/servers/app/newerClipping/ViewLayer.cpp +++ b/src/tests/servers/app/newerClipping/ViewLayer.cpp @@ -31,7 +31,6 @@ ViewLayer::ViewLayer(BRect frame, const char* name, fWindow(NULL), fParent(NULL), - fIsTopLayer(false), fFirstChild(NULL), fPreviousSibling(NULL), @@ -72,12 +71,23 @@ ViewLayer::Bounds() const return bounds; } +// ConvertToVisibleInTopView +void +ViewLayer::ConvertToVisibleInTopView(BRect* bounds) const +{ + *bounds = *bounds & Bounds(); + // NOTE: this step is necessary even if we don't have a parent! + ConvertToParent(bounds); + + if (fParent) + fParent->ConvertToVisibleInTopView(bounds); +} + // AttachedToWindow void -ViewLayer::AttachedToWindow(WindowLayer* window, bool topLayer) +ViewLayer::AttachedToWindow(WindowLayer* window) { fWindow = window; - fIsTopLayer = topLayer; for (ViewLayer* child = FirstChild(); child; child = NextChild()) child->AttachedToWindow(window); @@ -211,13 +221,13 @@ ViewLayer::LastChild() const ViewLayer* ViewLayer::TopLayer() { - if (fIsTopLayer) - return this; + // returns the top level view of the hirarchy, + // it doesn't have to be the top level of a window if (fParent) return fParent->TopLayer(); - else - return NULL; + + return this; } // CountChildren @@ -328,6 +338,36 @@ ViewLayer::ConvertToTop(BRegion* region) const fParent->ConvertToTop(region); } +// ConvertFromTop +void +ViewLayer::ConvertFromTop(BPoint* point) const +{ + ConvertFromParent(point); + + if (fParent) + fParent->ConvertFromTop(point); +} + +// ConvertFromTop +void +ViewLayer::ConvertFromTop(BRect* rect) const +{ + ConvertFromParent(rect); + + if (fParent) + fParent->ConvertFromTop(rect); +} + +// ConvertFromTop +void +ViewLayer::ConvertFromTop(BRegion* region) const +{ + ConvertFromParent(region); + + if (fParent) + fParent->ConvertFromTop(region); +} + // SetName void ViewLayer::SetName(const char* string) @@ -335,72 +375,7 @@ ViewLayer::SetName(const char* string) fName.SetTo(string); } -#if 0 -// MoveBy -void -ViewLayer::MoveBy(int32 x, int32 y, BRegion* dirtyRegion) -{ - if (x == 0 && y == 0) - return; - - 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); - } - fFrame.OffsetBy(x, y); -} -#else // 0 +#pragma mark - // MoveBy void @@ -410,28 +385,64 @@ ViewLayer::MoveBy(int32 x, int32 y, BRegion* dirtyRegion) return; fFrame.OffsetBy(x, y); - InvalidateScreenClipping(true); // to move on screen, we must not be hidden and we must have a parent - if (!IsHidden() && fParent && !fIsTopLayer && dirtyRegion) { - // clip to parent - BRect oldScreenRect(Bounds()); - oldScreenRect.OffsetByCopy(-x, -y); - ConvertToParent(&oldScreenRect); + if (!IsHidden() && fParent && dirtyRegion) { +#if 0 +// based on redraw on new location + // the place were we are now visible + BRect newVisibleBounds = Bounds(); + // we can use the frame of the old + // local clipping to see which parts need invalidation + BRect oldVisibleBounds(Bounds()); + oldVisibleBounds.OffsetBy(-x, -y); + ConvertToTop(&oldVisibleBounds); - BRect screenRect(Bounds()); - ConvertToParent(&screenRect); + ConvertToVisibleInTopView(&newVisibleBounds); - // TODO: see AddChild - // TODO: shouldn't we use regions? - BRect dirty = oldScreenRect | screenRect; - dirty = dirty & fParent->Bounds(); - fParent->ConvertToTop(&dirty); - - dirtyRegion->Include(dirty); + dirtyRegion->Include(oldVisibleBounds); + // newVisibleBounds already is in screen coords + dirtyRegion->Include(newVisibleBounds); +#else +// blitting version, invalidates +// old contents + BRect oldVisibleBounds(Bounds()); + oldVisibleBounds.OffsetBy(-x, -y); + ConvertToTop(&oldVisibleBounds); + + BRect newVisibleBounds(Bounds()); + // NOTE: using ConvertToVisibleInTopView() + // instead of ConvertToTop()! see below + ConvertToVisibleInTopView(&newVisibleBounds); + + newVisibleBounds.OffsetBy(-x, -y); + + // clipping oldVisibleBounds to newVisibleBounds + // makes sure we don't copy parts hidden under + // parent views + BRegion copyRegion(oldVisibleBounds & newVisibleBounds); + fWindow->CopyContents(©Region, x, y); + + BRegion dirty(oldVisibleBounds); + newVisibleBounds.OffsetBy(x, y); + dirty.Exclude(newVisibleBounds); + dirtyRegion->Include(&dirty); +#endif + } + + if (!fParent) { + // the top view's screen clipping does not change, + // because no parts are clipped away from parent + // views + _MoveScreenClipping(x, y, true); + } else { + // parts might have been revealed from underneath + // the parent, or might now be hidden underneath + // the parent, this is taken care of when building + // the screen clipping + InvalidateScreenClipping(true); } } -#endif // 0 // ResizeBy void @@ -472,19 +483,17 @@ ViewLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion) 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); - } else { - // just layout the children - for (ViewLayer* child = FirstChild(); child; child = NextChild()) - child->ParentResized(x, y, NULL); } + + // 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 + // TODO: when the implementation of Hide() and Show() is + // complete, see if this should be avoided + RebuildClipping(false); } // ParentResized @@ -542,6 +551,8 @@ ViewLayer::ScrollBy(int32 x, int32 y, BRegion* dirtyRegion) InvalidateScreenClipping(true); } +#pragma mark - + // Draw void ViewLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, @@ -606,20 +617,17 @@ ViewLayer::ClientDraw(DrawingEngine* drawingEngine, BRegion* effectiveClipping) } } +#pragma mark - + // IsHidden bool ViewLayer::IsHidden() const { - // if we're explicitely hidden... + // if we're explicitely hidden, then we're hidden... if (fHidden) return true; - // if we don't have a window, or our window is hidden, - // then yes, we're hidden too - if (fWindow == NULL || (fWindow && fWindow->IsHidden())) - return true; - - // if we're not hidden yet, we might still be hidden if our parent is + // ...but if we're not hidden, we might still be hidden if our parent is if (fParent) return fParent->IsHidden(); @@ -631,18 +639,30 @@ ViewLayer::IsHidden() const void ViewLayer::Hide() { - fHidden = true; + if (!fHidden) { + fHidden = true; - // TODO: track regions + if (fParent && !fParent->IsHidden()) { + // TODO: track regions + // RebuildClipping() + // ... + } + } } // Show void ViewLayer::Show() { - fHidden = false; + if (fHidden) { + fHidden = false; - // TODO: track regions + if (fParent && !fParent->IsHidden()) { + // TODO: track regions + // RebuildClipping() + // ... + } + } } // PrintToStream @@ -655,9 +675,6 @@ ViewLayer::PrintToStream() const 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()); @@ -678,13 +695,18 @@ ViewLayer::ScreenClipping(BRegion* windowContentClipping, bool force) const { if (!fScreenClippingValid || force) { fScreenClipping = fLocalClipping; - if (fParent) { - BRect parentWindow = fParent->Bounds(); - ConvertFromParent(&parentWindow); - BRegion visibleInParent(parentWindow); - fScreenClipping.IntersectWith(&visibleInParent); - } ConvertToTop(&fScreenClipping); + + // see if we parts of our bounds are hidden underneath + // the parent, the local clipping does not account for this + BRect clippedBounds = Bounds(); + ConvertToVisibleInTopView(&clippedBounds); + if (clippedBounds.Width() < fScreenClipping.Frame().Width() || + clippedBounds.Height() < fScreenClipping.Frame().Height()) { + BRegion temp(clippedBounds); + fScreenClipping.IntersectWith(&temp); + } + fScreenClipping.IntersectWith(windowContentClipping); fScreenClippingValid = true; } diff --git a/src/tests/servers/app/newerClipping/ViewLayer.h b/src/tests/servers/app/newerClipping/ViewLayer.h index cc4bcbc6b3..ccebad45b6 100644 --- a/src/tests/servers/app/newerClipping/ViewLayer.h +++ b/src/tests/servers/app/newerClipping/ViewLayer.h @@ -23,12 +23,14 @@ class ViewLayer { inline BRect Frame() const { return fFrame; } BRect Bounds() const; + // converts the given frame up the view hirarchy and + // clips to each views bounds + void ConvertToVisibleInTopView(BRect* bounds) const; inline rgb_color ViewColor() const { return fViewColor; } - void AttachedToWindow(WindowLayer* window, - bool topLayer = false); + void AttachedToWindow(WindowLayer* window); void DetachedFromWindow(); // tree stuff @@ -61,6 +63,10 @@ class ViewLayer { void ConvertToTop(BRect* rect) const; void ConvertToTop(BRegion* region) const; + void ConvertFromTop(BPoint* point) const; + void ConvertFromTop(BRect* rect) const; + void ConvertFromTop(BRegion* region) const; + // settings void SetName(const char* string); inline const char* Name() const @@ -120,7 +126,6 @@ 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 4eeaafbd02..7c8bda7015 100644 --- a/src/tests/servers/app/newerClipping/WindowLayer.cpp +++ b/src/tests/servers/app/newerClipping/WindowLayer.cpp @@ -56,7 +56,7 @@ 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); + fTopLayer->AttachedToWindow(this); fClient->Run(); } @@ -82,7 +82,7 @@ WindowLayer::MessageReceived(BMessage* message) } } _DrawBorder(); - _DrawContents(fTopLayer); + _TriggerContentRedraw(); fDesktop->ReadUnlockClipping(); } else { @@ -307,6 +307,7 @@ WindowLayer::Show() void WindowLayer::MarkDirty(BRegion* regionOnScreen) { + // for triggering MSG_REDRAW if (fDesktop) fDesktop->MarkDirty(regionOnScreen); } @@ -315,6 +316,7 @@ WindowLayer::MarkDirty(BRegion* regionOnScreen) void WindowLayer::MarkContentDirty(BRegion* regionOnScreen) { + // for triggering MSG_REDRAW if (fDesktop && fDesktop->LockClipping()) { regionOnScreen->IntersectWith(&fVisibleContentRegion); @@ -323,29 +325,65 @@ WindowLayer::MarkContentDirty(BRegion* regionOnScreen) fDesktop->UnlockClipping(); } } -/* -// DirtyRegion -BRegion -WindowLayer::DirtyRegion() -{ - BRegion dirty; - if (fDesktop->ReadLockClipping()) { - dirty = *fDesktop->DirtyRegion(); - fDesktop->ReadUnlockClipping(); - } - return dirty; -} -*/ + # pragma mark - -// _DrawContents +// CopyContents void -WindowLayer::_DrawContents(ViewLayer* layer) +WindowLayer::CopyContents(BRegion* region, int32 xOffset, int32 yOffset) +{ + // this function takes care of invalidating parts that could not be copied + + if (fDesktop->LockClipping()) { + + BRegion newDirty(*region); + + region->IntersectWith(&fVisibleContentRegion); + region->OffsetBy(xOffset, yOffset); + region->IntersectWith(&fVisibleContentRegion); + + region->OffsetBy(-xOffset, -yOffset); + + newDirty.Exclude(region); + + _ShiftPartOfRegion(fDesktop->DirtyRegion(), region, xOffset, yOffset); + if (fDrawingEngine->Lock()) { + fDrawingEngine->CopyRegion(region, xOffset, yOffset); + fDrawingEngine->Unlock(); + } + + if (fCurrentUpdateSession) + _ShiftPartOfRegion(&fCurrentUpdateSession->DirtyRegion(), region, xOffset, yOffset); + if (fPendingUpdateSession) + _ShiftPartOfRegion(&fPendingUpdateSession->DirtyRegion(), region, xOffset, yOffset); + + newDirty.OffsetBy(xOffset, yOffset); + newDirty.IntersectWith(&fVisibleContentRegion); + fDesktop->MarkDirty(&newDirty); + + fDesktop->UnlockClipping(); + } +} + +# pragma mark - + +// _ShiftPartOfRegion +void +WindowLayer::_ShiftPartOfRegion(BRegion* region, BRegion* regionToShift, + int32 xOffset, int32 yOffset) +{ + BRegion common(*region); + common.IntersectWith(regionToShift); + region->Exclude(&common); + common.OffsetBy(xOffset, yOffset); + region->Include(&common); +} + +// _TriggerContentRedraw +void +WindowLayer::_TriggerContentRedraw() { //printf("%s - DrawContents()\n", Name()); - if (!layer) - layer = fTopLayer; - if (fDesktop->ReadLockClipping()) { BRegion dirtyContentRegion(fVisibleContentRegion); @@ -367,8 +405,8 @@ if (fDrawingEngine->Lock()) { fDesktop->MarkClean(&dirtyContentRegion); - layer->Draw(fDrawingEngine, &dirtyContentRegion, - &fVisibleContentRegion, true); + fTopLayer->Draw(fDrawingEngine, &dirtyContentRegion, + &fVisibleContentRegion, false); } fDesktop->ReadUnlockClipping(); @@ -398,8 +436,14 @@ WindowLayer::_DrawClient(int32 token) BRegion effectiveClipping(fEffectiveDrawingRegion); effectiveClipping.IntersectWith(&layer->ScreenClipping(&fVisibleContentRegion)); - + if (effectiveClipping.CountRects() > 0) { + // clear the back ground + // TODO: only if this is the first drawing command for + // this layer of course! + layer->Draw(fDrawingEngine, &effectiveClipping, + &fVisibleContentRegion, false); + layer->ClientDraw(fDrawingEngine, &effectiveClipping); } @@ -456,6 +500,8 @@ WindowLayer::_DrawBorder() void WindowLayer::_MarkContentDirty(BRegion* contentDirtyRegion) { +if (fDesktop->ReadLockClipping()) { + if (contentDirtyRegion->CountRects() <= 0) return; @@ -480,12 +526,17 @@ WindowLayer::_MarkContentDirty(BRegion* contentDirtyRegion) fClient->PostMessage(MSG_UPDATE); fUpdateRequested = true; } + +fDesktop->ReadUnlockClipping(); +} } // _BeginUpdate void WindowLayer::_BeginUpdate() { +if (fDesktop->ReadLockClipping()) { + if (fUpdateRequested && !fCurrentUpdateSession) { fCurrentUpdateSession = fPendingUpdateSession; fPendingUpdateSession = NULL; @@ -498,12 +549,17 @@ WindowLayer::_BeginUpdate() } fEffectiveDrawingRegionValid = false; } + +fDesktop->ReadUnlockClipping(); +} } // _EndUpdate void WindowLayer::_EndUpdate() { +if (fDesktop->ReadLockClipping()) { + if (fInUpdate) { delete fCurrentUpdateSession; fCurrentUpdateSession = NULL; @@ -518,6 +574,9 @@ WindowLayer::_EndUpdate() } else { fUpdateRequested = false; } + +fDesktop->ReadUnlockClipping(); +} } #pragma mark - diff --git a/src/tests/servers/app/newerClipping/WindowLayer.h b/src/tests/servers/app/newerClipping/WindowLayer.h index 8b4682c917..9785016821 100644 --- a/src/tests/servers/app/newerClipping/WindowLayer.h +++ b/src/tests/servers/app/newerClipping/WindowLayer.h @@ -74,13 +74,19 @@ class WindowLayer : public BLooper { DrawingEngine* GetDrawingEngine() const { return fDrawingEngine; } -// BRegion DirtyRegion(); + void CopyContents(BRegion* region, + int32 xOffset, int32 yOffset); private: - void _DrawContents(ViewLayer* layer = NULL); + void _ShiftPartOfRegion(BRegion* region, BRegion* regionToShift, + int32 xOffset, int32 yOffset); + + // different types of drawing + void _TriggerContentRedraw(); void _DrawClient(int32 token); void _DrawBorder(); + // handling update sessions void _MarkContentDirty(BRegion* contentDirtyRegion); void _BeginUpdate(); void _EndUpdate(); @@ -110,11 +116,26 @@ class WindowLayer : public BLooper { DrawingEngine* fDrawingEngine; Desktop* fDesktop; + // for mapping drawing requests from the client + // to the local view pointers BList fTokenViewMap; + // the client looper, which will do asynchronous + // drawing (the window will clear the content + // and the client is supposed to draw onto + // the cleared regions) ClientLooper* fClient; + // The synchronization, which client drawing commands + // belong to the redraw of which region is handled + // through an UpdateSession. When the client has + // been informed that it should redraw stuff, then + // this is the current update session. All new + // redraw requests from the root layer will go + // into the pending update session. UpdateSession* fCurrentUpdateSession; UpdateSession* fPendingUpdateSession; + // these two flags are supposed to ensure a sane + // and consistent update session bool fUpdateRequested; bool fInUpdate; }; diff --git a/src/tests/servers/app/newerClipping/main.cpp b/src/tests/servers/app/newerClipping/main.cpp index ca1a9e266e..be19c388c6 100644 --- a/src/tests/servers/app/newerClipping/main.cpp +++ b/src/tests/servers/app/newerClipping/main.cpp @@ -144,13 +144,15 @@ Window::AddWindow(BRect frame, const char* name) f.OffsetBy(f.Width() + 6, 0); - layer = new ViewLayer(f, "View", B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM, +// layer = new ViewLayer(f, "View", B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM, + layer = new ViewLayer(f, "View", B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, B_FULL_UPDATE_ON_RESIZE, (rgb_color){ 120, 120, 120, 255 }); layer1->AddChild(layer); f.OffsetBy(f.Width() + 6, 0); - layer = new ViewLayer(f, "View", B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM, +// layer = new ViewLayer(f, "View", B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM, + layer = new ViewLayer(f, "View", B_FOLLOW_LEFT | B_FOLLOW_BOTTOM, B_FULL_UPDATE_ON_RESIZE, (rgb_color){ 120, 120, 120, 255 }); layer1->AddChild(layer); }