change the way the _UPDATE_ message is used: it is now a mere notification that some views need updating. The BWindow will then pull data from the server which views exactly and the update rect. Therefor, the server can append regions to the current update session even if an _UPDATE_ message has already been sent to the client. If multiple views are invalidated in the client, only one update session will be triggered instead of two with the old implementation. Some drawing defects can be observed, but I know how to reproduce them so I hope to fix them soon.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16245 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -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<BRect>(&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<int32>(&token);
|
||||
while (error >= B_OK && token != B_NULL_TOKEN) {
|
||||
tokens.AddItem((void*)token);
|
||||
error = fLink->Read<int32>(&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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <List.h>
|
||||
#include <Message.h>
|
||||
#include <PortLink.h>
|
||||
#include <View.h> // for resize modes
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -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<int32>(fToken);
|
||||
|
||||
for (ViewLayer* child = FirstChild(); child; child = child->NextSibling())
|
||||
child->AddTokensForLayersInRegion(link, region,
|
||||
windowContentClipping);
|
||||
}
|
||||
|
||||
// PrintToStream
|
||||
void
|
||||
ViewLayer::PrintToStream() const
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <Debug.h>
|
||||
#include <DirectWindow.h>
|
||||
#include <PortLink.h>
|
||||
#include <View.h>
|
||||
|
||||
#include <new>
|
||||
@@ -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<BRect>(dirty.Frame());
|
||||
fTopLayer->AddTokensForLayersInRegion(link, dirty, &fContentRegion);
|
||||
// mark the end of the token "list"
|
||||
link.Attach<int32>(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
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
#include <Region.h>
|
||||
#include <String.h>
|
||||
|
||||
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; }
|
||||
|
||||
Reference in New Issue
Block a user