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:
Stephan Aßmus
2006-02-06 10:28:30 +00:00
parent 585c5a0042
commit bb160ab5f6
6 changed files with 88 additions and 34 deletions
+28 -6
View File
@@ -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);
+1 -1
View File
@@ -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:
+15
View File
@@ -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
+8
View File
@@ -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,
+32 -26
View File
@@ -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
+4 -1
View File
@@ -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; }