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

View File

@ -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;

View File

@ -10,6 +10,8 @@ enum {
MSG_UPDATE = 'updt',
MSG_VIEWS_ADDED = 'vwad',
MSG_VIEWS_REMOVED = 'vwrm',
MSG_WINDOW_HIDDEN = 'whdn',
};
class ClientLooper : public BLooper {

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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()) {

View File

@ -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);