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:
parent
2057d3c0aa
commit
8c8275c2ea
@ -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;
|
||||
|
@ -10,6 +10,8 @@ enum {
|
||||
MSG_UPDATE = 'updt',
|
||||
MSG_VIEWS_ADDED = 'vwad',
|
||||
MSG_VIEWS_REMOVED = 'vwrm',
|
||||
|
||||
MSG_WINDOW_HIDDEN = 'whdn',
|
||||
};
|
||||
|
||||
class ClientLooper : public BLooper {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user