diff --git a/src/tests/servers/app/newerClipping/ClientLooper.cpp b/src/tests/servers/app/newerClipping/ClientLooper.cpp index 9ada6a0473..eb6e2356e0 100644 --- a/src/tests/servers/app/newerClipping/ClientLooper.cpp +++ b/src/tests/servers/app/newerClipping/ClientLooper.cpp @@ -61,6 +61,14 @@ ClientLooper::MessageReceived(BMessage* message) fViewCount -= count; break; } + + case MSG_WINDOW_HIDDEN: + // there is no way we're going to accept this + // discrimination for longer than 2 seconds! + snooze(2000000); + fServerWindow->PostMessage(MSG_SHOW); + break; + default: BLooper::MessageReceived(message); break; diff --git a/src/tests/servers/app/newerClipping/ClientLooper.h b/src/tests/servers/app/newerClipping/ClientLooper.h index 43c4cf9f00..425ee851c4 100644 --- a/src/tests/servers/app/newerClipping/ClientLooper.h +++ b/src/tests/servers/app/newerClipping/ClientLooper.h @@ -10,6 +10,8 @@ enum { MSG_UPDATE = 'updt', MSG_VIEWS_ADDED = 'vwad', MSG_VIEWS_REMOVED = 'vwrm', + + MSG_WINDOW_HIDDEN = 'whdn', }; class ClientLooper : public BLooper { diff --git a/src/tests/servers/app/newerClipping/Desktop.cpp b/src/tests/servers/app/newerClipping/Desktop.cpp index 611f82a100..3a99fc8de5 100644 --- a/src/tests/servers/app/newerClipping/Desktop.cpp +++ b/src/tests/servers/app/newerClipping/Desktop.cpp @@ -82,7 +82,7 @@ Desktop::Draw(BRect updateRect) // MouseDown void -Desktop::MouseDown(BPoint where, uint32 buttons) +Desktop::MouseDown(BPoint where, uint32 buttons, int32 clicks) { fLastMousePos = where; fClickedWindow = WindowAt(where); @@ -90,10 +90,15 @@ Desktop::MouseDown(BPoint where, uint32 buttons) if (buttons == B_PRIMARY_MOUSE_BUTTON) { fTracking = true; if (fClickedWindow) { - BRect frame(fClickedWindow->Frame()); - BRect resizeRect(frame.right - 10, frame.bottom - 10, - frame.right + 4, frame.bottom + 4); - fResizing = resizeRect.Contains(where); + if (clicks >= 2) { + HideWindow(fClickedWindow); + fClickedWindow = NULL; + } else { + BRect frame(fClickedWindow->Frame()); + BRect resizeRect(frame.right - 10, frame.bottom - 10, + frame.right + 4, frame.bottom + 4); + fResizing = resizeRect.Contains(where); + } } } else if (buttons == B_SECONDARY_MOUSE_BUTTON) { if (fClickedWindow) @@ -184,10 +189,12 @@ Desktop::MessageReceived(BMessage* message) case B_MOUSE_DOWN: { BPoint where; uint32 buttons; + int32 clicks; if (message->FindPoint("where", &where) >= B_OK && - message->FindInt32("buttons", (int32*)&buttons) >= B_OK) { + message->FindInt32("buttons", (int32*)&buttons) >= B_OK && + message->FindInt32("clicks", &clicks) >= B_OK) { - MouseDown(where, buttons); + MouseDown(where, buttons, clicks); } break; } @@ -320,7 +327,7 @@ Desktop::WindowAt(const BPoint& where) const int32 count = CountWindows(); for (int32 i = count - 1; i >= 0; i--) { WindowLayer* window = WindowAtFast(i); - if (window->VisibleRegion().Contains(where)) + if (!window->IsHidden() && window->VisibleRegion().Contains(where)) return window; } return NULL; @@ -419,6 +426,66 @@ Desktop::ResizeWindowBy(WindowLayer* window, int32 x, int32 y) Unlock(); } +// ShowWindow +void +Desktop::ShowWindow(WindowLayer* window) +{ + SetWindowHidden(window, false); +} + +// HideWindow +void +Desktop::HideWindow(WindowLayer* window) +{ + SetWindowHidden(window, true); +} + +// SetWindowHidden +void +Desktop::SetWindowHidden(WindowLayer* window, bool hidden) +{ + if (LockClipping()) { + + if (window->IsHidden() != hidden) { + + window->SetHidden(hidden); + + BRegion dirty; + + if (hidden) { + // after rebuilding the clipping, + // this window will not have a visible + // region anymore, so we need to remember + // it now + // (actually that's not true, since + // hidden windows are excluded from the + // clipping calculation, but anyways) + dirty = window->VisibleRegion(); + } + + BRegion background; + _RebuildClippingForAllWindows(&background); + _SetBackground(&background); + + if (!hidden) { + // everything that is now visible in the + // window needs a redraw, but other windows + // are not affected, we can call ProcessDirtyRegion() + // of the window, and don't have to use MarkDirty() + dirty = window->VisibleRegion(); + window->ProcessDirtyRegion(&dirty); + } else { + // when the window was hidden, the dirty region + // affects other windows + MarkDirty(&dirty); + } + } + + UnlockClipping(); + } +} + + // BringToFront void Desktop::BringToFront(WindowLayer* window) @@ -550,9 +617,11 @@ Desktop::_RebuildClippingForAllWindows(BRegion* stillAvailableOnScreen) int32 count = CountWindows(); for (int32 i = count - 1; i >= 0; i--) { WindowLayer* window = WindowAtFast(i); - window->SetClipping(stillAvailableOnScreen); - // that windows region is not available on screen anymore - stillAvailableOnScreen->Exclude(&window->VisibleRegion()); + if (!window->IsHidden()) { + window->SetClipping(stillAvailableOnScreen); + // that windows region is not available on screen anymore + stillAvailableOnScreen->Exclude(&window->VisibleRegion()); + } } } @@ -564,9 +633,8 @@ Desktop::_TriggerWindowRedrawing(BRegion* newDirtyRegion) int32 count = CountWindows(); for (int32 i = count - 1; i >= 0; i--) { WindowLayer* window = WindowAtFast(i); - if (newDirtyRegion->Intersects(window->VisibleRegion().Frame())) -// window->PostMessage(MSG_REDRAW); -window->ProcessDirtyRegion(newDirtyRegion); + if (!window->IsHidden() && newDirtyRegion->Intersects(window->VisibleRegion().Frame())) + window->ProcessDirtyRegion(newDirtyRegion); } } diff --git a/src/tests/servers/app/newerClipping/Desktop.h b/src/tests/servers/app/newerClipping/Desktop.h index 661be8ac36..36218f89e1 100644 --- a/src/tests/servers/app/newerClipping/Desktop.h +++ b/src/tests/servers/app/newerClipping/Desktop.h @@ -37,7 +37,8 @@ class Desktop : public BLooper { // functions for the DrawView void Draw(BRect updateRect); - void MouseDown(BPoint where, uint32 buttons); + void MouseDown(BPoint where, uint32 buttons, + int32 clicks); void MouseUp(BPoint where); void MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage); @@ -60,6 +61,10 @@ class Desktop : public BLooper { void MoveWindowBy(WindowLayer* window, int32 x, int32 y); void ResizeWindowBy(WindowLayer* window, int32 x, int32 y); + void ShowWindow(WindowLayer* window); + void HideWindow(WindowLayer* window); + void SetWindowHidden(WindowLayer* window, bool hidden); + void BringToFront(WindowLayer* window); void SendToBack(WindowLayer* window); diff --git a/src/tests/servers/app/newerClipping/ViewLayer.cpp b/src/tests/servers/app/newerClipping/ViewLayer.cpp index 95ef42af2c..d2a51bbf1d 100644 --- a/src/tests/servers/app/newerClipping/ViewLayer.cpp +++ b/src/tests/servers/app/newerClipping/ViewLayer.cpp @@ -28,6 +28,7 @@ ViewLayer::ViewLayer(BRect frame, const char* name, // ViewLayers start visible by default fHidden(false), + fVisible(true), fWindow(NULL), fParent(NULL), @@ -124,23 +125,19 @@ ViewLayer::AddChild(ViewLayer* layer) } fLastChild = layer; - RebuildClipping(false); + if (layer->IsVisible()) + RebuildClipping(false); if (fWindow) { layer->AttachedToWindow(fWindow); - // 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); + if (fVisible && layer->IsVisible()) { + // trigger redraw + BRect clippedFrame = layer->Frame(); + ConvertToVisibleInTopView(&clippedFrame); + BRegion dirty(clippedFrame); + fWindow->MarkContentDirty(&dirty); + } } } @@ -174,12 +171,19 @@ ViewLayer::RemoveChild(ViewLayer* layer) layer->fPreviousSibling = NULL; layer->fNextSibling = NULL; - if (fParent) { + if (layer->IsVisible()) RebuildClipping(false); - } + if (fWindow) { layer->DetachedFromWindow(); - // TODO: handle exposed area + + if (fVisible && layer->IsVisible()) { + // trigger redraw + BRect clippedFrame = layer->Frame(); + ConvertToVisibleInTopView(&clippedFrame); + BRegion dirty(clippedFrame); + fWindow->MarkContentDirty(&dirty); + } } return true; @@ -387,7 +391,7 @@ ViewLayer::MoveBy(int32 x, int32 y, BRegion* dirtyRegion) fFrame.OffsetBy(x, y); // to move on screen, we must not be hidden and we must have a parent - if (!IsHidden() && fParent && dirtyRegion) { + if (fVisible && fParent && dirtyRegion) { #if 0 // based on redraw on new location // the place were we are now visible @@ -454,7 +458,7 @@ ViewLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion) fFrame.right += x; fFrame.bottom += y; - if (!IsHidden() && dirtyRegion) { + if (fVisible && dirtyRegion) { BRect oldBounds(Bounds()); oldBounds.right -= x; oldBounds.bottom -= y; @@ -474,9 +478,11 @@ ViewLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion) // exclude children, they are expected to // include their own dirty regions in ParentResized() for (ViewLayer* child = FirstChild(); child; child = NextChild()) { - BRect previousChildVisible(child->Frame() & oldBounds & Bounds()); - if (dirty.Frame().Intersects(previousChildVisible)) { - dirty.Exclude(previousChildVisible); + if (child->IsVisible()) { + BRect previousChildVisible(child->Frame() & oldBounds & Bounds()); + if (dirty.Frame().Intersects(previousChildVisible)) { + dirty.Exclude(previousChildVisible); + } } } @@ -619,50 +625,50 @@ ViewLayer::ClientDraw(DrawingEngine* drawingEngine, BRegion* effectiveClipping) // #pragma mark - +// SetHidden +void +ViewLayer::SetHidden(bool hidden) +{ + // TODO: test... + + if (fHidden != hidden) { + fHidden = hidden; + + // recurse into children and update their visible flag + if (fParent) { + bool olfVisible = fVisible; + UpdateVisibleDeep(fParent->IsVisible()); + if (olfVisible != fVisible) { + // include or exclude us from the parent area + fParent->RebuildClipping(false); + if (fWindow) { + // trigger a redraw + BRect clippedBounds = Bounds(); + ConvertToVisibleInTopView(&clippedBounds); + BRegion dirty(clippedBounds); + fWindow->MarkContentDirty(&dirty); + } + } + } else { + UpdateVisibleDeep(true); + } + } +} + // IsHidden bool ViewLayer::IsHidden() const { - // if we're explicitely hidden, then we're hidden... - if (fHidden) - 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; + return fHidden; } -// Hide +// UpdateVisibleDeep void -ViewLayer::Hide() +ViewLayer::UpdateVisibleDeep(bool parentVisible) { - if (!fHidden) { - fHidden = true; - - if (fParent && !fParent->IsHidden()) { - // TODO: track regions - // RebuildClipping() - // ... - } - } -} - -// Show -void -ViewLayer::Show() -{ - if (fHidden) { - fHidden = false; - - if (fParent && !fParent->IsHidden()) { - // TODO: track regions - // RebuildClipping() - // ... - } - } + fVisible = parentVisible && !fHidden; + for (ViewLayer* child = FirstChild(); child; child = NextChild()) + child->UpdateVisibleDeep(fVisible); } // PrintToStream @@ -680,7 +686,8 @@ ViewLayer::RebuildClipping(bool deep) // exclude all childs from the clipping for (ViewLayer* child = FirstChild(); child; child = NextChild()) { - fLocalClipping.Exclude(child->Frame()); + if (child->IsVisible()) + fLocalClipping.Exclude(child->Frame()); if (deep) child->RebuildClipping(deep); diff --git a/src/tests/servers/app/newerClipping/ViewLayer.h b/src/tests/servers/app/newerClipping/ViewLayer.h index ccebad45b6..b0a2e2ace3 100644 --- a/src/tests/servers/app/newerClipping/ViewLayer.h +++ b/src/tests/servers/app/newerClipping/ViewLayer.h @@ -94,20 +94,25 @@ class ViewLayer { void ClientDraw( DrawingEngine* drawingEngine, BRegion* effectiveClipping); + void SetHidden(bool hidden); bool IsHidden() const; - void Hide(); - void Show(); + + // takes into account parent views hidden status + bool IsVisible() const + { return fVisible; } + // update visible status for this view and all children + // according to the parents visibility + void UpdateVisibleDeep(bool parentVisible); // clipping void RebuildClipping(bool deep); BRegion& ScreenClipping(BRegion* windowContentClipping, bool force = false) const; + void InvalidateScreenClipping(bool deep); // debugging void PrintToStream() const; - void InvalidateScreenClipping(bool deep); - private: void _MoveScreenClipping(int32 x, int32 y, bool deep); @@ -123,6 +128,7 @@ private: uint32 fResizeMode; uint32 fFlags; bool fHidden; + bool fVisible; WindowLayer* fWindow; ViewLayer* fParent; diff --git a/src/tests/servers/app/newerClipping/WindowLayer.cpp b/src/tests/servers/app/newerClipping/WindowLayer.cpp index 5e732a1893..8c03dd2b4c 100644 --- a/src/tests/servers/app/newerClipping/WindowLayer.cpp +++ b/src/tests/servers/app/newerClipping/WindowLayer.cpp @@ -117,6 +117,12 @@ WindowLayer::MessageReceived(BMessage* message) _DrawClient(token); break; } + + case MSG_SHOW: + if (IsHidden()) { + fDesktop->ShowWindow(this); + } + break; default: BLooper::MessageReceived(message); break; @@ -306,28 +312,21 @@ WindowLayer::AddChild(ViewLayer* layer) } void -WindowLayer::Hide() +WindowLayer::SetHidden(bool hidden) { - if (fHidden) - return; + // the desktop takes care of + // dirty regions + if (fHidden != hidden) { + fHidden = hidden; - fHidden = true; + fTopLayer->SetHidden(hidden); - // TODO: notify window manager - // TODO: call RevealNewWMState -} - -void -WindowLayer::Show() -{ - if (!fHidden) - return; - - fHidden = false; - - // TODO: notify window manager - // TODO: call RevealNewWMState + // this is only for simulation purposes: + if (fHidden) + fClient->PostMessage(MSG_WINDOW_HIDDEN); + // TODO: anything else? + } } // ProcessDirtyRegion @@ -509,7 +508,7 @@ WindowLayer::_DrawClient(int32 token) // If true readlocking would work correctly, this would // not be an issue ViewLayer* layer = (ViewLayer*)fTokenViewMap.ItemAt(token); - if (!layer) + if (!layer || !layer->IsVisible()) return; if (fDesktop->ReadLockClipping()) { diff --git a/src/tests/servers/app/newerClipping/WindowLayer.h b/src/tests/servers/app/newerClipping/WindowLayer.h index 3a3ddf76c0..8943a033f0 100644 --- a/src/tests/servers/app/newerClipping/WindowLayer.h +++ b/src/tests/servers/app/newerClipping/WindowLayer.h @@ -16,9 +16,12 @@ class DrawingEngine; enum { MSG_REDRAW = 'rdrw', + // client messages MSG_BEGIN_UPDATE = 'bgud', MSG_END_UPDATE = 'edud', MSG_DRAWING_COMMAND = 'draw', + + MSG_SHOW = 'show', }; class UpdateSession { @@ -73,10 +76,9 @@ class WindowLayer : public BLooper { void AddChild(ViewLayer* layer); + void SetHidden(bool hidden); inline bool IsHidden() const { return fHidden; } - void Hide(); - void Show(); void MarkDirty(BRegion* regionOnScreen); void MarkContentDirty(BRegion* regionOnScreen);