From 8c8275c2ea950aae83caebb29d632a5fd9a9b286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Thu, 1 Dec 2005 17:24:47 +0000 Subject: [PATCH] showing and hiding windows and views works now, views are not so heavily tested, but any problems should be easy to fix. the recursive IsHidden() is now avoided, there is only one recursion now, which is when the hidden status changes. in the simulation, double clicking a window will temporarily hide it and show it asynchronously from the window thread. looks like the locking model works out fine. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15272 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../app/newerClipping/ClientLooper.cpp | 8 ++ .../servers/app/newerClipping/ClientLooper.h | 2 + .../servers/app/newerClipping/Desktop.cpp | 96 ++++++++++++-- src/tests/servers/app/newerClipping/Desktop.h | 7 +- .../servers/app/newerClipping/ViewLayer.cpp | 123 +++++++++--------- .../servers/app/newerClipping/ViewLayer.h | 14 +- .../servers/app/newerClipping/WindowLayer.cpp | 37 +++--- .../servers/app/newerClipping/WindowLayer.h | 6 +- 8 files changed, 195 insertions(+), 98 deletions(-) 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);