* adds drawing commands from clients

* adds concept of a current and a pending update session
* marks dirty views being resized or moved

Some aspects of the design are buggy, others are slow, but I'm
approaching a good overview of what's needed and what problems
lurk in the details. In the end I hope to make things work fast
and correctly at all times. Adi or anybody else, feel free to
join the efforts.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15158 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2005-11-26 00:13:34 +00:00
parent a40e885b9d
commit ff89d51e02
9 changed files with 963 additions and 514 deletions
@@ -0,0 +1,68 @@
#include <stdio.h>
#include <Message.h>
#include <MessageQueue.h>
#include <String.h>
#include "WindowLayer.h"
#include "ClientLooper.h"
#define SLOW_DRAWING 0
// constructor
ClientLooper::ClientLooper(const char* name, WindowLayer* serverWindow)
: BLooper(""),
fServerWindow(serverWindow),
fViewCount(0)
{
BString clientName(name);
clientName << " client";
SetName(clientName.String());
}
// destructor
ClientLooper::~ClientLooper()
{
}
// MessageReceived
void
ClientLooper::MessageReceived(BMessage* message)
{
switch (message->what) {
case MSG_UPDATE:
fServerWindow->PostMessage(MSG_BEGIN_UPDATE);
for (int32 i = 0; i < fViewCount; i++) {
// the client is slow
snooze(1000L);
// send the command to redraw a view
BMessage command(MSG_DRAWING_COMMAND);
command.AddInt32("token", i);
fServerWindow->PostMessage(&command);
}
fServerWindow->PostMessage(MSG_END_UPDATE);
break;
case MSG_VIEWS_ADDED: {
int32 count;
if (message->FindInt32("count", &count) >= B_OK) {
fViewCount += count;
}
break;
}
case MSG_VIEWS_REMOVED: {
int32 count;
if (message->FindInt32("count", &count) >= B_OK)
fViewCount -= count;
break;
}
default:
BLooper::MessageReceived(message);
break;
}
}
@@ -0,0 +1,28 @@
#ifndef CLIENT_LOOPER_H
#define CLIENT_LOOPER_H
#include <Looper.h>
class WindowLayer;
enum {
MSG_UPDATE = 'updt',
MSG_VIEWS_ADDED = 'vwad',
MSG_VIEWS_REMOVED = 'vwrm',
};
class ClientLooper : public BLooper {
public:
ClientLooper(const char* name,
WindowLayer* serverWindow);
virtual ~ClientLooper();
virtual void MessageReceived(BMessage* message);
private:
WindowLayer* fServerWindow;
int32 fViewCount;
};
#endif // CLIENT_LOOPER_H
@@ -114,6 +114,8 @@ Desktop::MouseDown(BPoint where, uint32 buttons)
// complete redraw // complete redraw
#if RUN_WITH_FRAME_BUFFER #if RUN_WITH_FRAME_BUFFER
if (fDrawingEngine->Lock()) { if (fDrawingEngine->Lock()) {
fDirtyRegion.MakeEmpty();
BRegion region(fDrawingEngine->Bounds()); BRegion region(fDrawingEngine->Bounds());
fDrawingEngine->Unlock(); fDrawingEngine->Unlock();
@@ -123,6 +125,7 @@ Desktop::MouseDown(BPoint where, uint32 buttons)
_SetBackground(&region); _SetBackground(&region);
} }
#else #else
fDirtyRegion.MakeEmpty();
fDrawingEngine->MarkDirty(); fDrawingEngine->MarkDirty();
#endif #endif
} }
@@ -156,10 +159,13 @@ Desktop::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
if (dx != 0 || dy != 0) { if (dx != 0 || dy != 0) {
if (fClickedWindow) { if (fClickedWindow) {
//bigtime_t now = system_time();
if (fResizing) { if (fResizing) {
ResizeWindowBy(fClickedWindow, dx, dy); ResizeWindowBy(fClickedWindow, dx, dy);
//printf("resizing: %lld\n", system_time() - now);
} else { } else {
MoveWindowBy(fClickedWindow, dx, dy); MoveWindowBy(fClickedWindow, dx, dy);
//printf("moving: %lld\n", system_time() - now);
} }
} }
} }
@@ -355,9 +361,9 @@ Desktop::MoveWindowBy(WindowLayer* window, int32 x, int32 y)
if (LockClipping()) { if (LockClipping()) {
// the dirty region starts with the visible area of the window being moved // the dirty region starts with the visible area of the window being moved
BRegion newDirtyRegion(window->VisibleRegion()); BRegion newDirtyRegion(window->VisibleRegion());
BRegion alreadyDirtyRegion(fDirtyRegion);
// we have to move along the part of the current dirty region // we have to move along the part of the current dirty region
// that intersects with the window being moved // that intersects with the window being moved
BRegion alreadyDirtyRegion(fDirtyRegion);
alreadyDirtyRegion.IntersectWith(&window->VisibleRegion()); alreadyDirtyRegion.IntersectWith(&window->VisibleRegion());
window->MoveBy(x, y); window->MoveBy(x, y);
@@ -65,7 +65,8 @@ class Desktop : public BLooper {
void ReadUnlockClipping() { fClippingLock.WriteUnlock(); } void ReadUnlockClipping() { fClippingLock.WriteUnlock(); }
# endif # endif
#else #else
bool ReadLockClipping() { return fClippingLock.LockWithTimeout(10000) >= B_OK; } bool ReadLockClipping() { return fClippingLock.Lock(); }
bool ReadLockClippingWithTimeout() { return fClippingLock.LockWithTimeout(10000) >= B_OK; }
void ReadUnlockClipping() { fClippingLock.Unlock(); } void ReadUnlockClipping() { fClippingLock.Unlock(); }
#endif #endif
File diff suppressed because it is too large Load Diff
@@ -2,10 +2,11 @@
#ifndef VIEW_LAYER_H #ifndef VIEW_LAYER_H
#define VIEW_LAYER_H #define VIEW_LAYER_H
#include <GraphicsDefs.h>
#include <Region.h> #include <Region.h>
#include <String.h> #include <String.h>
class BList;
class DrawingEngine; class DrawingEngine;
class WindowLayer; class WindowLayer;
@@ -26,7 +27,8 @@ class ViewLayer {
inline rgb_color ViewColor() const inline rgb_color ViewColor() const
{ return fViewColor; } { return fViewColor; }
void AttachedToWindow(WindowLayer* window); void AttachedToWindow(WindowLayer* window,
bool topLayer = false);
void DetachedFromWindow(); void DetachedFromWindow();
// tree stuff // tree stuff
@@ -43,7 +45,8 @@ class ViewLayer {
ViewLayer* TopLayer(); ViewLayer* TopLayer();
uint32 CountChildren() const; uint32 CountChildren(bool deep = false) const;
void CollectTokensForChildren(BList* tokenMap) const;
// coordinate conversion // coordinate conversion
void ConvertToParent(BPoint* point) const; void ConvertToParent(BPoint* point) const;
@@ -66,23 +69,30 @@ class ViewLayer {
void ParentResized(int32 dx, int32 dy, void ParentResized(int32 dx, int32 dy,
BRegion* dirtyRegion); BRegion* dirtyRegion);
// for background clearing
void Draw(DrawingEngine* drawingEngine, void Draw(DrawingEngine* drawingEngine,
BRegion* effectiveClipping, BRegion* effectiveClipping,
bool deep = false); bool deep = false);
// to simulate drawing done from client side
void ClientDraw(DrawingEngine* drawingEngine,
BRegion* effectiveClipping);
bool IsHidden() const; bool IsHidden() const;
void Hide(); void Hide();
void Show(); void Show();
// clipping // clipping
void RebuildClipping(bool deep = false); void RebuildClipping(bool deep);
BRegion& ScreenClipping() const; BRegion& ScreenClipping() const;
// debugging // debugging
void PrintToStream() const; void PrintToStream() const;
private: private:
void _InvalidateScreenClipping(bool deep = false); void _InvalidateScreenClipping(bool deep);
void _MoveScreenClipping(int32 x, int32 y,
bool deep);
BString fName; BString fName;
// area within parent coordinate space // area within parent coordinate space
@@ -98,6 +108,7 @@ private:
WindowLayer* fWindow; WindowLayer* fWindow;
ViewLayer* fParent; ViewLayer* fParent;
bool fIsTopLayer;
ViewLayer* fFirstChild; ViewLayer* fFirstChild;
ViewLayer* fPreviousSibling; ViewLayer* fPreviousSibling;
@@ -5,6 +5,7 @@
#include <Message.h> #include <Message.h>
#include <MessageQueue.h> #include <MessageQueue.h>
#include "ClientLooper.h"
#include "Desktop.h" #include "Desktop.h"
#include "DrawingEngine.h" #include "DrawingEngine.h"
@@ -29,7 +30,15 @@ WindowLayer::WindowLayer(BRect frame, const char* name,
fTopLayer(NULL), fTopLayer(NULL),
fDrawingEngine(drawingEngine), fDrawingEngine(drawingEngine),
fDesktop(desktop) fDesktop(desktop),
fTokenViewMap(64),
fClient(new ClientLooper(name, this)),
fCurrentUpdateSession(NULL),
fPendingUpdateSession(NULL),
fUpdateRequested(false),
fInUpdate(false)
{ {
// the top layer is special, it has a coordinate system // the top layer is special, it has a coordinate system
// as if it was attached directly to the desktop, therefor, // as if it was attached directly to the desktop, therefor,
@@ -38,6 +47,9 @@ WindowLayer::WindowLayer(BRect frame, const char* name,
// fFrame as if it had // fFrame as if it had
fTopLayer = new(nothrow) ViewLayer(fFrame, "top view", B_FOLLOW_ALL, 0, fTopLayer = new(nothrow) ViewLayer(fFrame, "top view", B_FOLLOW_ALL, 0,
(rgb_color){ 255, 255, 255, 255 }); (rgb_color){ 255, 255, 255, 255 });
fTopLayer->AttachedToWindow(this, true);
fClient->Run();
} }
// destructor // destructor
@@ -53,7 +65,7 @@ WindowLayer::MessageReceived(BMessage* message)
switch (message->what) { switch (message->what) {
case MSG_REDRAW: { case MSG_REDRAW: {
if (!MessageQueue()->FindMessage(MSG_REDRAW, 0)) { if (!MessageQueue()->FindMessage(MSG_REDRAW, 0)) {
while (!fDesktop->ReadLockClipping()) { while (!fDesktop->ReadLockClippingWithTimeout()) {
//printf("%s MSG_REDRAW -> timeout\n", Name()); //printf("%s MSG_REDRAW -> timeout\n", Name());
if (MessageQueue()->FindMessage(MSG_REDRAW, 0)) { if (MessageQueue()->FindMessage(MSG_REDRAW, 0)) {
//printf("%s MSG_REDRAW -> timeout - leaving because there are pending redraws\n", Name()); //printf("%s MSG_REDRAW -> timeout - leaving because there are pending redraws\n", Name());
@@ -62,12 +74,25 @@ WindowLayer::MessageReceived(BMessage* message)
} }
_DrawContents(fTopLayer); _DrawContents(fTopLayer);
_DrawBorder(); _DrawBorder();
fDesktop->ReadUnlockClipping(); fDesktop->ReadUnlockClipping();
} else { } else {
//printf("%s MSG_REDRAW -> pending redraws\n", Name()); //printf("%s MSG_REDRAW -> pending redraws\n", Name());
} }
break; break;
} }
case MSG_BEGIN_UPDATE:
_BeginUpdate();
break;
case MSG_END_UPDATE:
_EndUpdate();
break;
case MSG_DRAWING_COMMAND: {
int32 token;
if (message->FindInt32("token", &token) >= B_OK)
_DrawClient(token);
break;
}
default: default:
BLooper::MessageReceived(message); BLooper::MessageReceived(message);
break; break;
@@ -174,6 +199,11 @@ WindowLayer::MoveBy(int32 x, int32 y)
if (fContentRegionValid) if (fContentRegionValid)
fContentRegion.OffsetBy(x, y); fContentRegion.OffsetBy(x, y);
if (fCurrentUpdateSession)
fCurrentUpdateSession->MoveBy(x, y);
if (fPendingUpdateSession)
fPendingUpdateSession->MoveBy(x, y);
fTopLayer->MoveBy(x, y); fTopLayer->MoveBy(x, y);
// TODO: move a local dirty region! // TODO: move a local dirty region!
@@ -210,6 +240,14 @@ WindowLayer::AddChild(ViewLayer* layer)
{ {
fTopLayer->AddChild(layer); fTopLayer->AddChild(layer);
// inform client about the view
// (just a part of the simulation)
fTokenViewMap.MakeEmpty();
fTopLayer->CollectTokensForChildren(&fTokenViewMap);
BMessage message(MSG_VIEWS_ADDED);
message.AddInt32("count", fTokenViewMap.CountItems());
fClient->PostMessage(&message);
// TODO: trigger redraw for dirty regions // TODO: trigger redraw for dirty regions
} }
@@ -221,6 +259,18 @@ WindowLayer::MarkDirty(BRegion* regionOnScreen)
fDesktop->MarkDirty(regionOnScreen); fDesktop->MarkDirty(regionOnScreen);
} }
// DirtyRegion
BRegion
WindowLayer::DirtyRegion()
{
BRegion dirty;
if (fDesktop->ReadLockClipping()) {
dirty = *fDesktop->DirtyRegion();
fDesktop->ReadUnlockClipping();
}
return dirty;
}
# pragma mark - # pragma mark -
// _DrawContents // _DrawContents
@@ -244,15 +294,16 @@ WindowLayer::_DrawContents(ViewLayer* layer)
// TODO: simplify // TODO: simplify
// ideally, there would only be a local fDirtyRegion, // ideally, there would only be a local fDirtyRegion,
// that we need to intersect with. fDirtyRegion would // that we need to intersect with. fDirtyRegion would
// alread only include fVisibleRegion // already only include fVisibleRegion
effectiveWindowClipping.IntersectWith(&fVisibleRegion); effectiveWindowClipping.IntersectWith(&fVisibleRegion);
effectiveWindowClipping.IntersectWith(fDesktop->DirtyRegion()); effectiveWindowClipping.IntersectWith(fDesktop->DirtyRegion());
if (effectiveWindowClipping.Frame().IsValid()) { if (effectiveWindowClipping.Frame().IsValid()) {
// send UPDATE message to the client here
_MarkContentDirty(&effectiveWindowClipping);
layer->Draw(fDrawingEngine, &effectiveWindowClipping, true); layer->Draw(fDrawingEngine, &effectiveWindowClipping, true);
fDesktop->MarkClean(&fContentRegion); fDesktop->MarkClean(&fContentRegion);
// send UPDATE message to the client here
} }
//else { //else {
//printf(" nothing to do\n"); //printf(" nothing to do\n");
@@ -260,6 +311,35 @@ WindowLayer::_DrawContents(ViewLayer* layer)
} }
// _DrawClient
void
WindowLayer::_DrawClient(int32 token)
{
ViewLayer* layer = (ViewLayer*)fTokenViewMap.ItemAt(token);
if (!layer)
return;
BRegion effectiveClipping(layer->ScreenClipping());
if (fInUpdate) {
// enforce the dirty region of the update session
effectiveClipping.IntersectWith(&fCurrentUpdateSession->DirtyRegion());
} else {
printf("%s - _DrawClient(token: %ld) - not in update\n", Name(), token);
}
if (effectiveClipping.CountRects() > 0 && fDesktop->ReadLockClipping()) {
effectiveClipping.IntersectWith(&fVisibleRegion);
// TODO: This step seems too much
BRegion contentRegion;
GetContentRegion(&contentRegion);
effectiveClipping.IntersectWith(&contentRegion);
layer->ClientDraw(fDrawingEngine, &effectiveClipping);
fDesktop->ReadUnlockClipping();
}
}
// _DrawBorder // _DrawBorder
void void
WindowLayer::_DrawBorder() WindowLayer::_DrawBorder()
@@ -298,3 +378,90 @@ WindowLayer::_DrawBorder()
//} //}
} }
// _MarkContentDirty
void
WindowLayer::_MarkContentDirty(BRegion* localDirty)
{
if (localDirty->CountRects() <= 0)
return;
if (!fPendingUpdateSession) {
// create new pending
fPendingUpdateSession = new UpdateSession(*localDirty);
} else {
// add to pending
fPendingUpdateSession->Include(localDirty);
}
if (!fUpdateRequested) {
// send this to client
fClient->PostMessage(MSG_UPDATE);
fUpdateRequested = true;
}
}
// _BeginUpdate
void
WindowLayer::_BeginUpdate()
{
if (fUpdateRequested && !fCurrentUpdateSession) {
fCurrentUpdateSession = fPendingUpdateSession;
fPendingUpdateSession = NULL;
if (fCurrentUpdateSession) {
// all drawing command from the client
// will have the dirty region from the update
// session enforced
fInUpdate = true;
}
}
}
// _EndUpdate
void
WindowLayer::_EndUpdate()
{
if (fInUpdate) {
delete fCurrentUpdateSession;
fCurrentUpdateSession = NULL;
fInUpdate = false;
}
if (fPendingUpdateSession) {
// send this to client
fClient->PostMessage(MSG_UPDATE);
fUpdateRequested = true;
} else {
fUpdateRequested = false;
}
}
#pragma mark -
// constructor
UpdateSession::UpdateSession(const BRegion& dirtyRegion)
: fDirtyRegion(dirtyRegion)
{
}
// destructor
UpdateSession::~UpdateSession()
{
}
// Include
void
UpdateSession::Include(BRegion* additionalDirty)
{
fDirtyRegion.Include(additionalDirty);
}
// MoveBy
void
UpdateSession::MoveBy(int32 x, int32 y)
{
fDirtyRegion.OffsetBy(x, y);
}
@@ -2,17 +2,39 @@
#ifndef WINDOW_LAYER_H #ifndef WINDOW_LAYER_H
#define WINDOW_LAYER_H #define WINDOW_LAYER_H
#include <List.h>
#include <Looper.h> #include <Looper.h>
#include <Region.h> #include <Region.h>
#include <String.h> #include <String.h>
#include "ViewLayer.h" #include "ViewLayer.h"
class ClientLooper;
class Desktop; class Desktop;
class DrawingEngine; class DrawingEngine;
enum { enum {
MSG_REDRAW = 'rdrw', MSG_REDRAW = 'rdrw',
MSG_BEGIN_UPDATE = 'bgud',
MSG_END_UPDATE = 'edud',
MSG_DRAWING_COMMAND = 'draw',
};
class UpdateSession {
public:
UpdateSession(const BRegion& dirtyRegion);
virtual ~UpdateSession();
void Include(BRegion* additionalDirty);
inline BRegion& DirtyRegion()
{ return fDirtyRegion; }
void MoveBy(int32 x, int32 y);
private:
BRegion fDirtyRegion;
}; };
class WindowLayer : public BLooper { class WindowLayer : public BLooper {
@@ -42,10 +64,20 @@ class WindowLayer : public BLooper {
void MarkDirty(BRegion* regionOnScreen); void MarkDirty(BRegion* regionOnScreen);
DrawingEngine* GetDrawingEngine() const
{ return fDrawingEngine; }
BRegion DirtyRegion();
private: private:
void _DrawContents(ViewLayer* layer = NULL); void _DrawContents(ViewLayer* layer = NULL);
void _DrawClient(int32 token);
void _DrawBorder(); void _DrawBorder();
void _MarkContentDirty(BRegion* localDirty);
void _BeginUpdate();
void _EndUpdate();
BRect fFrame; BRect fFrame;
// the visible region is only recalculated from the // the visible region is only recalculated from the
@@ -65,6 +97,14 @@ class WindowLayer : public BLooper {
DrawingEngine* fDrawingEngine; DrawingEngine* fDrawingEngine;
Desktop* fDesktop; Desktop* fDesktop;
BList fTokenViewMap;
ClientLooper* fClient;
UpdateSession* fCurrentUpdateSession;
UpdateSession* fPendingUpdateSession;
bool fUpdateRequested;
bool fInUpdate;
}; };
#endif // WINDOW_LAYER_H #endif // WINDOW_LAYER_H
+2 -1
View File
@@ -30,7 +30,8 @@ TYPE= APP
# if two source files with the same name (source.c or source.cpp) # if two source files with the same name (source.c or source.cpp)
# are included from different directories. Also note that spaces # are included from different directories. Also note that spaces
# in folder names do not work well with this makefile. # in folder names do not work well with this makefile.
SRCS= Desktop.cpp \ SRCS= ClientLooper.cpp \
Desktop.cpp \
DrawingEngine.cpp \ DrawingEngine.cpp \
main.cpp \ main.cpp \
MultiLocker.cpp \ MultiLocker.cpp \