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
This commit is contained in:
Stephan Aßmus
2005-12-01 17:24:47 +00:00
parent 2057d3c0aa
commit 8c8275c2ea
8 changed files with 195 additions and 98 deletions
@@ -61,6 +61,14 @@ ClientLooper::MessageReceived(BMessage* message)
fViewCount -= count; fViewCount -= count;
break; 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: default:
BLooper::MessageReceived(message); BLooper::MessageReceived(message);
break; break;
@@ -10,6 +10,8 @@ enum {
MSG_UPDATE = 'updt', MSG_UPDATE = 'updt',
MSG_VIEWS_ADDED = 'vwad', MSG_VIEWS_ADDED = 'vwad',
MSG_VIEWS_REMOVED = 'vwrm', MSG_VIEWS_REMOVED = 'vwrm',
MSG_WINDOW_HIDDEN = 'whdn',
}; };
class ClientLooper : public BLooper { class ClientLooper : public BLooper {
@@ -82,7 +82,7 @@ Desktop::Draw(BRect updateRect)
// MouseDown // MouseDown
void void
Desktop::MouseDown(BPoint where, uint32 buttons) Desktop::MouseDown(BPoint where, uint32 buttons, int32 clicks)
{ {
fLastMousePos = where; fLastMousePos = where;
fClickedWindow = WindowAt(where); fClickedWindow = WindowAt(where);
@@ -90,11 +90,16 @@ Desktop::MouseDown(BPoint where, uint32 buttons)
if (buttons == B_PRIMARY_MOUSE_BUTTON) { if (buttons == B_PRIMARY_MOUSE_BUTTON) {
fTracking = true; fTracking = true;
if (fClickedWindow) { if (fClickedWindow) {
if (clicks >= 2) {
HideWindow(fClickedWindow);
fClickedWindow = NULL;
} else {
BRect frame(fClickedWindow->Frame()); BRect frame(fClickedWindow->Frame());
BRect resizeRect(frame.right - 10, frame.bottom - 10, BRect resizeRect(frame.right - 10, frame.bottom - 10,
frame.right + 4, frame.bottom + 4); frame.right + 4, frame.bottom + 4);
fResizing = resizeRect.Contains(where); fResizing = resizeRect.Contains(where);
} }
}
} else if (buttons == B_SECONDARY_MOUSE_BUTTON) { } else if (buttons == B_SECONDARY_MOUSE_BUTTON) {
if (fClickedWindow) if (fClickedWindow)
SendToBack(fClickedWindow); SendToBack(fClickedWindow);
@@ -184,10 +189,12 @@ Desktop::MessageReceived(BMessage* message)
case B_MOUSE_DOWN: { case B_MOUSE_DOWN: {
BPoint where; BPoint where;
uint32 buttons; uint32 buttons;
int32 clicks;
if (message->FindPoint("where", &where) >= B_OK && 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; break;
} }
@@ -320,7 +327,7 @@ Desktop::WindowAt(const BPoint& where) const
int32 count = CountWindows(); int32 count = CountWindows();
for (int32 i = count - 1; i >= 0; i--) { for (int32 i = count - 1; i >= 0; i--) {
WindowLayer* window = WindowAtFast(i); WindowLayer* window = WindowAtFast(i);
if (window->VisibleRegion().Contains(where)) if (!window->IsHidden() && window->VisibleRegion().Contains(where))
return window; return window;
} }
return NULL; return NULL;
@@ -419,6 +426,66 @@ Desktop::ResizeWindowBy(WindowLayer* window, int32 x, int32 y)
Unlock(); 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 // BringToFront
void void
Desktop::BringToFront(WindowLayer* window) Desktop::BringToFront(WindowLayer* window)
@@ -550,11 +617,13 @@ Desktop::_RebuildClippingForAllWindows(BRegion* stillAvailableOnScreen)
int32 count = CountWindows(); int32 count = CountWindows();
for (int32 i = count - 1; i >= 0; i--) { for (int32 i = count - 1; i >= 0; i--) {
WindowLayer* window = WindowAtFast(i); WindowLayer* window = WindowAtFast(i);
if (!window->IsHidden()) {
window->SetClipping(stillAvailableOnScreen); window->SetClipping(stillAvailableOnScreen);
// that windows region is not available on screen anymore // that windows region is not available on screen anymore
stillAvailableOnScreen->Exclude(&window->VisibleRegion()); stillAvailableOnScreen->Exclude(&window->VisibleRegion());
} }
} }
}
// _TriggerWindowRedrawing // _TriggerWindowRedrawing
void void
@@ -564,8 +633,7 @@ Desktop::_TriggerWindowRedrawing(BRegion* newDirtyRegion)
int32 count = CountWindows(); int32 count = CountWindows();
for (int32 i = count - 1; i >= 0; i--) { for (int32 i = count - 1; i >= 0; i--) {
WindowLayer* window = WindowAtFast(i); WindowLayer* window = WindowAtFast(i);
if (newDirtyRegion->Intersects(window->VisibleRegion().Frame())) if (!window->IsHidden() && newDirtyRegion->Intersects(window->VisibleRegion().Frame()))
// window->PostMessage(MSG_REDRAW);
window->ProcessDirtyRegion(newDirtyRegion); window->ProcessDirtyRegion(newDirtyRegion);
} }
} }
@@ -37,7 +37,8 @@ class Desktop : public BLooper {
// functions for the DrawView // functions for the DrawView
void Draw(BRect updateRect); void Draw(BRect updateRect);
void MouseDown(BPoint where, uint32 buttons); void MouseDown(BPoint where, uint32 buttons,
int32 clicks);
void MouseUp(BPoint where); void MouseUp(BPoint where);
void MouseMoved(BPoint where, uint32 code, void MouseMoved(BPoint where, uint32 code,
const BMessage* dragMessage); const BMessage* dragMessage);
@@ -60,6 +61,10 @@ class Desktop : public BLooper {
void MoveWindowBy(WindowLayer* window, int32 x, int32 y); void MoveWindowBy(WindowLayer* window, int32 x, int32 y);
void ResizeWindowBy(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 BringToFront(WindowLayer* window);
void SendToBack(WindowLayer* window); void SendToBack(WindowLayer* window);
@@ -28,6 +28,7 @@ ViewLayer::ViewLayer(BRect frame, const char* name,
// ViewLayers start visible by default // ViewLayers start visible by default
fHidden(false), fHidden(false),
fVisible(true),
fWindow(NULL), fWindow(NULL),
fParent(NULL), fParent(NULL),
@@ -124,23 +125,19 @@ ViewLayer::AddChild(ViewLayer* layer)
} }
fLastChild = layer; fLastChild = layer;
if (layer->IsVisible())
RebuildClipping(false); RebuildClipping(false);
if (fWindow) { if (fWindow) {
layer->AttachedToWindow(fWindow); layer->AttachedToWindow(fWindow);
// TODO: not correct... need something like if (fVisible && layer->IsVisible()) {
// ViewLayer::ClipToParent(BRect frame) // trigger redraw
// { BRect clippedFrame = layer->Frame();
// frame = frame & Bounds(); ConvertToVisibleInTopView(&clippedFrame);
// ConvertToParent(&frame); BRegion dirty(clippedFrame);
// fParent->ClipToParent(&frame); fWindow->MarkContentDirty(&dirty);
// } }
BRect dirty(layer->Frame());
dirty = dirty & Bounds();
ConvertToTop(&dirty);
BRegion dirtyRegion(dirty);
fWindow->MarkContentDirty(&dirtyRegion);
} }
} }
@@ -174,12 +171,19 @@ ViewLayer::RemoveChild(ViewLayer* layer)
layer->fPreviousSibling = NULL; layer->fPreviousSibling = NULL;
layer->fNextSibling = NULL; layer->fNextSibling = NULL;
if (fParent) { if (layer->IsVisible())
RebuildClipping(false); RebuildClipping(false);
}
if (fWindow) { if (fWindow) {
layer->DetachedFromWindow(); 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; return true;
@@ -387,7 +391,7 @@ ViewLayer::MoveBy(int32 x, int32 y, BRegion* dirtyRegion)
fFrame.OffsetBy(x, y); fFrame.OffsetBy(x, y);
// to move on screen, we must not be hidden and we must have a parent // 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 #if 0
// based on redraw on new location // based on redraw on new location
// the place were we are now visible // the place were we are now visible
@@ -454,7 +458,7 @@ ViewLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion)
fFrame.right += x; fFrame.right += x;
fFrame.bottom += y; fFrame.bottom += y;
if (!IsHidden() && dirtyRegion) { if (fVisible && dirtyRegion) {
BRect oldBounds(Bounds()); BRect oldBounds(Bounds());
oldBounds.right -= x; oldBounds.right -= x;
oldBounds.bottom -= y; oldBounds.bottom -= y;
@@ -474,11 +478,13 @@ ViewLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion)
// exclude children, they are expected to // exclude children, they are expected to
// include their own dirty regions in ParentResized() // include their own dirty regions in ParentResized()
for (ViewLayer* child = FirstChild(); child; child = NextChild()) { for (ViewLayer* child = FirstChild(); child; child = NextChild()) {
if (child->IsVisible()) {
BRect previousChildVisible(child->Frame() & oldBounds & Bounds()); BRect previousChildVisible(child->Frame() & oldBounds & Bounds());
if (dirty.Frame().Intersects(previousChildVisible)) { if (dirty.Frame().Intersects(previousChildVisible)) {
dirty.Exclude(previousChildVisible); dirty.Exclude(previousChildVisible);
} }
} }
}
ConvertToTop(&dirty); ConvertToTop(&dirty);
dirtyRegion->Include(&dirty); dirtyRegion->Include(&dirty);
@@ -619,50 +625,50 @@ ViewLayer::ClientDraw(DrawingEngine* drawingEngine, BRegion* effectiveClipping)
// #pragma mark - // #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 // IsHidden
bool bool
ViewLayer::IsHidden() const ViewLayer::IsHidden() const
{ {
// if we're explicitely hidden, then we're hidden... return fHidden;
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;
} }
// Hide // UpdateVisibleDeep
void void
ViewLayer::Hide() ViewLayer::UpdateVisibleDeep(bool parentVisible)
{ {
if (!fHidden) { fVisible = parentVisible && !fHidden;
fHidden = true; for (ViewLayer* child = FirstChild(); child; child = NextChild())
child->UpdateVisibleDeep(fVisible);
if (fParent && !fParent->IsHidden()) {
// TODO: track regions
// RebuildClipping()
// ...
}
}
}
// Show
void
ViewLayer::Show()
{
if (fHidden) {
fHidden = false;
if (fParent && !fParent->IsHidden()) {
// TODO: track regions
// RebuildClipping()
// ...
}
}
} }
// PrintToStream // PrintToStream
@@ -680,6 +686,7 @@ ViewLayer::RebuildClipping(bool deep)
// exclude all childs from the clipping // exclude all childs from the clipping
for (ViewLayer* child = FirstChild(); child; child = NextChild()) { for (ViewLayer* child = FirstChild(); child; child = NextChild()) {
if (child->IsVisible())
fLocalClipping.Exclude(child->Frame()); fLocalClipping.Exclude(child->Frame());
if (deep) if (deep)
@@ -94,20 +94,25 @@ class ViewLayer {
void ClientDraw( DrawingEngine* drawingEngine, void ClientDraw( DrawingEngine* drawingEngine,
BRegion* effectiveClipping); BRegion* effectiveClipping);
void SetHidden(bool hidden);
bool IsHidden() const; 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 // clipping
void RebuildClipping(bool deep); void RebuildClipping(bool deep);
BRegion& ScreenClipping(BRegion* windowContentClipping, BRegion& ScreenClipping(BRegion* windowContentClipping,
bool force = false) const; bool force = false) const;
void InvalidateScreenClipping(bool deep);
// debugging // debugging
void PrintToStream() const; void PrintToStream() const;
void InvalidateScreenClipping(bool deep);
private: private:
void _MoveScreenClipping(int32 x, int32 y, void _MoveScreenClipping(int32 x, int32 y,
bool deep); bool deep);
@@ -123,6 +128,7 @@ private:
uint32 fResizeMode; uint32 fResizeMode;
uint32 fFlags; uint32 fFlags;
bool fHidden; bool fHidden;
bool fVisible;
WindowLayer* fWindow; WindowLayer* fWindow;
ViewLayer* fParent; ViewLayer* fParent;
@@ -117,6 +117,12 @@ WindowLayer::MessageReceived(BMessage* message)
_DrawClient(token); _DrawClient(token);
break; break;
} }
case MSG_SHOW:
if (IsHidden()) {
fDesktop->ShowWindow(this);
}
break;
default: default:
BLooper::MessageReceived(message); BLooper::MessageReceived(message);
break; break;
@@ -306,28 +312,21 @@ WindowLayer::AddChild(ViewLayer* layer)
} }
void void
WindowLayer::Hide() WindowLayer::SetHidden(bool hidden)
{ {
// the desktop takes care of
// dirty regions
if (fHidden != hidden) {
fHidden = hidden;
fTopLayer->SetHidden(hidden);
// this is only for simulation purposes:
if (fHidden) if (fHidden)
return; fClient->PostMessage(MSG_WINDOW_HIDDEN);
fHidden = true; // TODO: anything else?
// TODO: notify window manager
// TODO: call RevealNewWMState
} }
void
WindowLayer::Show()
{
if (!fHidden)
return;
fHidden = false;
// TODO: notify window manager
// TODO: call RevealNewWMState
} }
// ProcessDirtyRegion // ProcessDirtyRegion
@@ -509,7 +508,7 @@ WindowLayer::_DrawClient(int32 token)
// If true readlocking would work correctly, this would // If true readlocking would work correctly, this would
// not be an issue // not be an issue
ViewLayer* layer = (ViewLayer*)fTokenViewMap.ItemAt(token); ViewLayer* layer = (ViewLayer*)fTokenViewMap.ItemAt(token);
if (!layer) if (!layer || !layer->IsVisible())
return; return;
if (fDesktop->ReadLockClipping()) { if (fDesktop->ReadLockClipping()) {
@@ -16,9 +16,12 @@ class DrawingEngine;
enum { enum {
MSG_REDRAW = 'rdrw', MSG_REDRAW = 'rdrw',
// client messages
MSG_BEGIN_UPDATE = 'bgud', MSG_BEGIN_UPDATE = 'bgud',
MSG_END_UPDATE = 'edud', MSG_END_UPDATE = 'edud',
MSG_DRAWING_COMMAND = 'draw', MSG_DRAWING_COMMAND = 'draw',
MSG_SHOW = 'show',
}; };
class UpdateSession { class UpdateSession {
@@ -73,10 +76,9 @@ class WindowLayer : public BLooper {
void AddChild(ViewLayer* layer); void AddChild(ViewLayer* layer);
void SetHidden(bool hidden);
inline bool IsHidden() const inline bool IsHidden() const
{ return fHidden; } { return fHidden; }
void Hide();
void Show();
void MarkDirty(BRegion* regionOnScreen); void MarkDirty(BRegion* regionOnScreen);
void MarkContentDirty(BRegion* regionOnScreen); void MarkContentDirty(BRegion* regionOnScreen);