diff --git a/src/kits/interface/Window.cpp b/src/kits/interface/Window.cpp index 852a228e70..80678a5328 100644 --- a/src/kits/interface/Window.cpp +++ b/src/kits/interface/Window.cpp @@ -946,16 +946,38 @@ BWindow::DispatchMessage(BMessage *msg, BHandler *target) { STRACE(("info:BWindow handling _UPDATE_.\n")); BRect updateRect; - msg->FindRect("_rect", &updateRect); - updateRect.OffsetBy(fFrame.LeftTop()); fLink->StartMessage(AS_BEGIN_UPDATE); fInTransaction = true; - int32 token; - for (int32 i = 0; msg->FindInt32("_token", i, &token) == B_OK; i++) { - if (BView* view = _FindView(token)) - view->_Draw(updateRect); + int32 code; + if (fLink->FlushWithReply(code) == B_OK + && code == B_OK) { + // read culmulated update rect + fLink->Read(&updateRect); + + // read tokens for views that need to be drawn + // NOTE: we need to read the tokens completely + // first, or other calls would likely mess up the + // data in the link. + BList tokens(20); + int32 token; + status_t error = fLink->Read(&token); + while (error >= B_OK && token != B_NULL_TOKEN) { + tokens.AddItem((void*)token); + error = fLink->Read(&token); + } + // draw + int32 count = tokens.CountItems(); + for (int32 i = 0; i < count; i++) { + if (BView* view = _FindView((int32)tokens.ItemAtFast(i))) + view->_Draw(updateRect); + } + // TODO: the tokens are actually hirachically sorted, + // so traversing the list in revers and calling + // child->DrawAfterChildren would actually work correctly, + // only that drawing outside a view is not yet supported + // in the app_server. } fLink->StartMessage(AS_END_UPDATE); diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index 2cb0081fb0..1183e073f9 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -892,7 +892,7 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link) // whoever holds the read lock on purpose. //fDesktop->LockSingleWindow(); - fWindowLayer->BeginUpdate(); + fWindowLayer->BeginUpdate(fLink); break; case AS_END_UPDATE: diff --git a/src/servers/app/ViewLayer.cpp b/src/servers/app/ViewLayer.cpp index e060dbfab2..223c1e13af 100644 --- a/src/servers/app/ViewLayer.cpp +++ b/src/servers/app/ViewLayer.cpp @@ -23,6 +23,7 @@ #include #include +#include #include // for resize modes #include @@ -1027,6 +1028,20 @@ ViewLayer::AddTokensForLayersInRegion(BMessage* message, windowContentClipping); } +// AddTokensForLayersInRegion +void +ViewLayer::AddTokensForLayersInRegion(BPrivate::PortLink& link, + BRegion& region, + BRegion* windowContentClipping) +{ + if (region.Intersects(ScreenClipping(windowContentClipping).Frame())) + link.Attach(fToken); + + for (ViewLayer* child = FirstChild(); child; child = child->NextSibling()) + child->AddTokensForLayersInRegion(link, region, + windowContentClipping); +} + // PrintToStream void ViewLayer::PrintToStream() const diff --git a/src/servers/app/ViewLayer.h b/src/servers/app/ViewLayer.h index d9c81ece99..c5e685fce7 100644 --- a/src/servers/app/ViewLayer.h +++ b/src/servers/app/ViewLayer.h @@ -20,6 +20,10 @@ class BList; +namespace BPrivate { + class PortLink; +}; + class DrawState; class DrawingEngine; class WindowLayer; @@ -179,6 +183,10 @@ class ViewLayer { BRegion& region, BRegion* windowContentClipping); + void AddTokensForLayersInRegion(BPrivate::PortLink& link, + BRegion& region, + BRegion* windowContentClipping); + // clipping void RebuildClipping(bool deep); BRegion& ScreenClipping(BRegion* windowContentClipping, diff --git a/src/servers/app/WindowLayer.cpp b/src/servers/app/WindowLayer.cpp index dae8e3d479..8fe7fd1eec 100644 --- a/src/servers/app/WindowLayer.cpp +++ b/src/servers/app/WindowLayer.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -442,7 +443,7 @@ WindowLayer::CopyContents(BRegion* region, int32 xOffset, int32 yOffset) BRegion newDirty(*region); // clip the region to the visible contents at the - // source and destination location (not that VisibleContentRegion() + // source and destination location (note that VisibleContentRegion() // is used once to make sure it is valid, then fVisibleContentRegion // is used directly) region->IntersectWith(&VisibleContentRegion()); @@ -1595,7 +1596,7 @@ WindowLayer::_ShiftPartOfRegion(BRegion* region, BRegion* regionToShift, if (common.CountRects() > 0) { // cut the common part from the region, // offset that to destination and include again - region->Exclude(&common); +// region->Exclude(&common); common.OffsetBy(xOffset, yOffset); region->Include(&common); } @@ -1615,6 +1616,8 @@ WindowLayer::_TriggerContentRedraw(BRegion& dirtyContentRegion) // if (!fTopLayer->IsBackgroundDirty()) // fTopLayer->MarkBackgroundDirty(); #else +// NOTE: turning off DELAYED_BACKGROUND_CLEARING will +// need investigation if it even still works... if (!fContentRegionValid) _UpdateContentRegion(); @@ -1682,6 +1685,8 @@ WindowLayer::_TransferToUpdateSession(BRegion* contentDirtyRegion) // that have not yet been redrawn in the current update // session) #if !DELAYED_BACKGROUND_CLEARING +// NOTE: turning off DELAYED_BACKGROUND_CLEARING will +// need investigation if it even still works... if (fCurrentUpdateSession.IsUsed()) { fCurrentUpdateSession.Exclude(contentDirtyRegion); fEffectiveDrawingRegionValid = false; @@ -1702,31 +1707,13 @@ void WindowLayer::_SendUpdateMessage() { BMessage message(_UPDATE_); - BRect updateRect = fPendingUpdateSession.DirtyRegion().Frame(); - updateRect.OffsetBy(-fFrame.left, -fFrame.top); - message.AddRect("_rect", updateRect); - - // find all views that need an update - if (!fContentRegionValid) - _UpdateContentRegion(); - - fTopLayer->AddTokensForLayersInRegion(&message, - fPendingUpdateSession.DirtyRegion(), - &fContentRegion); - ServerWindow()->SendMessageToClient(&message); fUpdateRequested = true; - - // TODO: the toggling between the update sessions is too - // expensive, optimize with some pointer tricks - fCurrentUpdateSession = fPendingUpdateSession; - fPendingUpdateSession.SetUsed(false); } - void -WindowLayer::BeginUpdate() +WindowLayer::BeginUpdate(BPrivate::PortLink& link) { // NOTE: since we might "shift" parts of the // internal dirty regions from the desktop thread @@ -1735,17 +1722,24 @@ WindowLayer::BeginUpdate() // on the global clipping lock so that the internal // dirty regions are not messed with from the Desktop thread // and ServerWindow thread at the same time. - if (!fDesktop->LockSingleWindow()) + if (!fDesktop->LockSingleWindow()) { + link.StartMessage(B_ERROR); + link.Flush(); return; + } - if (fUpdateRequested && fCurrentUpdateSession.IsUsed()) { + if (fUpdateRequested) { + // make the pending update session the current update session + // TODO: the toggling between the update sessions is too + // expensive, optimize with some pointer tricks + fCurrentUpdateSession = fPendingUpdateSession; + fPendingUpdateSession.SetUsed(false); // all drawing command from the client // will have the dirty region from the update // session enforced fInUpdate = true; fEffectiveDrawingRegionValid = false; -#if DELAYED_BACKGROUND_CLEARING // TODO: each view could be drawn individually // right before carrying out the first drawing // command from the client during an update @@ -1757,10 +1751,24 @@ WindowLayer::BeginUpdate() BRegion dirty(fCurrentUpdateSession.DirtyRegion()); dirty.IntersectWith(&VisibleContentRegion()); + // find and attach all views that intersect with + // the dirty region + link.StartMessage(B_OK); + link.Attach(dirty.Frame()); + fTopLayer->AddTokensForLayersInRegion(link, dirty, &fContentRegion); + // mark the end of the token "list" + link.Attach(B_NULL_TOKEN); + link.Flush(); + +#if DELAYED_BACKGROUND_CLEARING +// NOTE: turning off DELAYED_BACKGROUND_CLEARING will +// need investigation if it even still works... fTopLayer->Draw(fDrawingEngine, &dirty, &fContentRegion, true); #endif } else { + link.StartMessage(B_ERROR); + link.Flush(); fprintf(stderr, "WindowLayer::BeginUpdate() - no update requested!\n"); } @@ -1795,8 +1803,6 @@ WindowLayer::EndUpdate() void WindowLayer::_UpdateContentRegion() { - // TODO: speed up by avoiding "Exclude()" - // start from the frame, extend to include decorator border fContentRegion.Set(fFrame); // resize handle diff --git a/src/servers/app/WindowLayer.h b/src/servers/app/WindowLayer.h index b8ecde570d..36ff98e537 100644 --- a/src/servers/app/WindowLayer.h +++ b/src/servers/app/WindowLayer.h @@ -20,6 +20,9 @@ #include #include +namespace BPrivate { + class PortLink; +}; class ClientLooper; class Decorator; @@ -102,7 +105,7 @@ class WindowLayer { void EnableUpdateRequests(); void DisableUpdateRequests(); - void BeginUpdate(); + void BeginUpdate(BPrivate::PortLink& link); void EndUpdate(); bool InUpdate() const { return fInUpdate; }