diff --git a/src/tests/servers/app/newerClipping/ClientLooper.h b/src/tests/servers/app/newerClipping/ClientLooper.h index 54d33f6d22..7e302830da 100644 --- a/src/tests/servers/app/newerClipping/ClientLooper.h +++ b/src/tests/servers/app/newerClipping/ClientLooper.h @@ -3,8 +3,8 @@ #define CLIENT_LOOPER_H #include -#include +class BMessageRunner; class WindowLayer; enum { diff --git a/src/tests/servers/app/newerClipping/Desktop.cpp b/src/tests/servers/app/newerClipping/Desktop.cpp index 3a99fc8de5..15418658a2 100644 --- a/src/tests/servers/app/newerClipping/Desktop.cpp +++ b/src/tests/servers/app/newerClipping/Desktop.cpp @@ -18,6 +18,7 @@ Desktop::Desktop(DrawView* drawView) fTracking(false), fLastMousePos(-1.0, -1.0), fClickedWindow(NULL), + fScrollingView(NULL), fResizing(false), fIs2ndButton(false), @@ -90,7 +91,9 @@ Desktop::MouseDown(BPoint where, uint32 buttons, int32 clicks) if (buttons == B_PRIMARY_MOUSE_BUTTON) { fTracking = true; if (fClickedWindow) { - if (clicks >= 2) { + if (modifiers() & B_SHIFT_KEY) { + fScrollingView = fClickedWindow->ViewAt(where); + } else if (clicks >= 2) { HideWindow(fClickedWindow); fClickedWindow = NULL; } else { @@ -132,6 +135,7 @@ Desktop::MouseUp(BPoint where) fTracking = false; fIs2ndButton = false; fClickedWindow = NULL; + fScrollingView = NULL; } // MouseMoved @@ -149,8 +153,13 @@ Desktop::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage) if (dx != 0 || dy != 0) { if (fClickedWindow) { + if (fScrollingView) { + if (LockClipping()) { + fClickedWindow->ScrollViewBy(fScrollingView, -dx, -dy); + UnlockClipping(); + } + } else if (fResizing) { //bigtime_t now = system_time(); - if (fResizing) { ResizeWindowBy(fClickedWindow, dx, dy); //printf("resizing: %lld\n", system_time() - now); } else { diff --git a/src/tests/servers/app/newerClipping/Desktop.h b/src/tests/servers/app/newerClipping/Desktop.h index 36218f89e1..68c6e25da4 100644 --- a/src/tests/servers/app/newerClipping/Desktop.h +++ b/src/tests/servers/app/newerClipping/Desktop.h @@ -21,6 +21,7 @@ #endif class WindowLayer; +class ViewLayer; enum { MSG_ADD_WINDOW = 'addw', @@ -100,14 +101,13 @@ private: bool fTracking; BPoint fLastMousePos; WindowLayer* fClickedWindow; + ViewLayer* fScrollingView; bool fResizing; bigtime_t fClickTime; bool fIs2ndButton; #if MULTI_LOCKER MultiLocker fClippingLock; -#elif RW_LOCKER - RWLocker fClippingLock; #else BLocker fClippingLock; #endif diff --git a/src/tests/servers/app/newerClipping/ViewLayer.cpp b/src/tests/servers/app/newerClipping/ViewLayer.cpp index d2a51bbf1d..e8ba10935e 100644 --- a/src/tests/servers/app/newerClipping/ViewLayer.cpp +++ b/src/tests/servers/app/newerClipping/ViewLayer.cpp @@ -258,6 +258,24 @@ ViewLayer::CollectTokensForChildren(BList* tokenMap) const } } +// ViewAt +ViewLayer* +ViewLayer::ViewAt(const BPoint& where, BRegion* windowContentClipping) +{ + if (!fVisible) + return NULL; + + if (ScreenClipping(windowContentClipping).Contains(where)) + return this; + + for (ViewLayer* child = FirstChild(); child; child = NextChild()) { + ViewLayer* layer = child->ViewAt(where, windowContentClipping); + if (layer) + return layer; + } + return NULL; +} + // ConvertToParent void ViewLayer::ConvertToParent(BPoint* point) const @@ -549,12 +567,43 @@ ViewLayer::ParentResized(int32 x, int32 y, BRegion* dirtyRegion) void ViewLayer::ScrollBy(int32 x, int32 y, BRegion* dirtyRegion) { + // blitting version, invalidates + // old contents + + // remember old bounds for tracking dirty region + BRect oldBounds(Bounds()); + // find the area of the view that can be scrolled, + // contents are shifted in the opposite direction from scrolling + BRect stillVisibleBounds(oldBounds); + stillVisibleBounds.OffsetBy(x, y); + + // NOTE: using ConvertToVisibleInTopView() + // instead of ConvertToTop(), this makes + // sure we don't try to move or invalidate an + // area hidden underneath the parent view + ConvertToVisibleInTopView(&oldBounds); + ConvertToVisibleInTopView(&stillVisibleBounds); + fScrollingOffset.x += x; fScrollingOffset.y += y; - // TODO: CopyRegion... - // TODO: ... + // do the blit, this will make sure + // that other more complex dirty regions + // are taken care of + BRegion copyRegion(stillVisibleBounds); + fWindow->CopyContents(©Region, -x, -y); + + // find the dirty region as far as we are + // concerned + BRegion dirty(oldBounds); + stillVisibleBounds.OffsetBy(-x, -y); + dirty.Exclude(stillVisibleBounds); + dirtyRegion->Include(&dirty); + + // the screen clipping of this view and it's + // childs is no longer valid InvalidateScreenClipping(true); + RebuildClipping(false); } // #pragma mark - @@ -572,8 +621,6 @@ ViewLayer::Draw(DrawingEngine* drawingEngine, BRegion* 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); diff --git a/src/tests/servers/app/newerClipping/ViewLayer.h b/src/tests/servers/app/newerClipping/ViewLayer.h index b0a2e2ace3..b241b0f5a5 100644 --- a/src/tests/servers/app/newerClipping/ViewLayer.h +++ b/src/tests/servers/app/newerClipping/ViewLayer.h @@ -50,6 +50,9 @@ class ViewLayer { uint32 CountChildren(bool deep = false) const; void CollectTokensForChildren(BList* tokenMap) const; + ViewLayer* ViewAt(const BPoint& where, + BRegion* windowContentClipping); + // coordinate conversion void ConvertToParent(BPoint* point) const; void ConvertToParent(BRect* rect) const; diff --git a/src/tests/servers/app/newerClipping/WindowLayer.cpp b/src/tests/servers/app/newerClipping/WindowLayer.cpp index 5c4ac7d414..039808a901 100644 --- a/src/tests/servers/app/newerClipping/WindowLayer.cpp +++ b/src/tests/servers/app/newerClipping/WindowLayer.cpp @@ -321,6 +321,30 @@ WindowLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion) fTopLayer->ResizeBy(x, y, dirtyRegion); } +// ScrollViewBy +void +WindowLayer::ScrollViewBy(ViewLayer* view, int32 dx, int32 dy) +{ + // this can be executed from any thread, but if the + // desktop thread is executing this, it should have + // the write lock, otherwise it is not prevented + // from executing this at the same time as the window + // is doing something else here! + + if (!view || (dx == 0 && dy == 0)) + return; + + if (fDesktop && fDesktop->ReadLockClipping()) { + + BRegion dirty; + view->ScrollBy(dx, dy, &dirty); + + _MarkContentDirty(&dirty); + + fDesktop->ReadUnlockClipping(); + } +} + // AddChild void WindowLayer::AddChild(ViewLayer* layer) @@ -338,11 +362,21 @@ WindowLayer::AddChild(ViewLayer* layer) // TODO: trigger redraw for dirty regions } +// ViewAt +ViewLayer* +WindowLayer::ViewAt(const BPoint& where) +{ + if (!fContentRegionValid) + _UpdateContentRegion(); + + return fTopLayer->ViewAt(where, &fContentRegion); +} + +// SetHidden void WindowLayer::SetHidden(bool hidden) { - // the desktop takes care of - // dirty regions + // the desktop takes care of dirty regions if (fHidden != hidden) { fHidden = hidden; @@ -618,7 +652,7 @@ WindowLayer::_DrawClientPolygon(int32 token, BPoint polygon[4]) // enforce the dirty region of the update session fEffectiveDrawingRegion.IntersectWith(&fCurrentUpdateSession.DirtyRegion()); } else { - printf("%s - _DrawClient(token: %ld) - not in update\n", Name(), token); + printf("%s - _DrawClientPolygon(token: %ld) - not in update\n", Name(), token); } fEffectiveDrawingRegionValid = true; } diff --git a/src/tests/servers/app/newerClipping/WindowLayer.h b/src/tests/servers/app/newerClipping/WindowLayer.h index 15e78af13d..2e607d765c 100644 --- a/src/tests/servers/app/newerClipping/WindowLayer.h +++ b/src/tests/servers/app/newerClipping/WindowLayer.h @@ -77,8 +77,12 @@ class WindowLayer : public BLooper { void MoveBy(int32 x, int32 y); void ResizeBy(int32 x, int32 y, BRegion* dirtyRegion); + void ScrollViewBy(ViewLayer* view, int32 dx, int32 dy); + void AddChild(ViewLayer* layer); + ViewLayer* ViewAt(const BPoint& where); + void SetHidden(bool hidden); inline bool IsHidden() const { return fHidden; }