* 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:
parent
a40e885b9d
commit
ff89d51e02
68
src/tests/servers/app/newerClipping/ClientLooper.cpp
Normal file
68
src/tests/servers/app/newerClipping/ClientLooper.cpp
Normal file
@ -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;
|
||||
}
|
||||
}
|
28
src/tests/servers/app/newerClipping/ClientLooper.h
Normal file
28
src/tests/servers/app/newerClipping/ClientLooper.h
Normal file
@ -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
|
||||
#if RUN_WITH_FRAME_BUFFER
|
||||
if (fDrawingEngine->Lock()) {
|
||||
fDirtyRegion.MakeEmpty();
|
||||
|
||||
BRegion region(fDrawingEngine->Bounds());
|
||||
fDrawingEngine->Unlock();
|
||||
|
||||
@ -123,6 +125,7 @@ Desktop::MouseDown(BPoint where, uint32 buttons)
|
||||
_SetBackground(®ion);
|
||||
}
|
||||
#else
|
||||
fDirtyRegion.MakeEmpty();
|
||||
fDrawingEngine->MarkDirty();
|
||||
#endif
|
||||
}
|
||||
@ -156,10 +159,13 @@ Desktop::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
|
||||
|
||||
if (dx != 0 || dy != 0) {
|
||||
if (fClickedWindow) {
|
||||
//bigtime_t now = system_time();
|
||||
if (fResizing) {
|
||||
ResizeWindowBy(fClickedWindow, dx, dy);
|
||||
//printf("resizing: %lld\n", system_time() - now);
|
||||
} else {
|
||||
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()) {
|
||||
// the dirty region starts with the visible area of the window being moved
|
||||
BRegion newDirtyRegion(window->VisibleRegion());
|
||||
BRegion alreadyDirtyRegion(fDirtyRegion);
|
||||
// we have to move along the part of the current dirty region
|
||||
// that intersects with the window being moved
|
||||
BRegion alreadyDirtyRegion(fDirtyRegion);
|
||||
alreadyDirtyRegion.IntersectWith(&window->VisibleRegion());
|
||||
|
||||
window->MoveBy(x, y);
|
||||
|
@ -65,7 +65,8 @@ class Desktop : public BLooper {
|
||||
void ReadUnlockClipping() { fClippingLock.WriteUnlock(); }
|
||||
# endif
|
||||
#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(); }
|
||||
#endif
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,10 +2,11 @@
|
||||
#ifndef VIEW_LAYER_H
|
||||
#define VIEW_LAYER_H
|
||||
|
||||
#include <GraphicsDefs.h>
|
||||
#include <Region.h>
|
||||
#include <String.h>
|
||||
|
||||
|
||||
class BList;
|
||||
class DrawingEngine;
|
||||
class WindowLayer;
|
||||
|
||||
@ -26,7 +27,8 @@ class ViewLayer {
|
||||
inline rgb_color ViewColor() const
|
||||
{ return fViewColor; }
|
||||
|
||||
void AttachedToWindow(WindowLayer* window);
|
||||
void AttachedToWindow(WindowLayer* window,
|
||||
bool topLayer = false);
|
||||
void DetachedFromWindow();
|
||||
|
||||
// tree stuff
|
||||
@ -43,7 +45,8 @@ class ViewLayer {
|
||||
|
||||
ViewLayer* TopLayer();
|
||||
|
||||
uint32 CountChildren() const;
|
||||
uint32 CountChildren(bool deep = false) const;
|
||||
void CollectTokensForChildren(BList* tokenMap) const;
|
||||
|
||||
// coordinate conversion
|
||||
void ConvertToParent(BPoint* point) const;
|
||||
@ -66,23 +69,30 @@ class ViewLayer {
|
||||
void ParentResized(int32 dx, int32 dy,
|
||||
BRegion* dirtyRegion);
|
||||
|
||||
// for background clearing
|
||||
void Draw(DrawingEngine* drawingEngine,
|
||||
BRegion* effectiveClipping,
|
||||
bool deep = false);
|
||||
|
||||
// to simulate drawing done from client side
|
||||
void ClientDraw(DrawingEngine* drawingEngine,
|
||||
BRegion* effectiveClipping);
|
||||
|
||||
bool IsHidden() const;
|
||||
void Hide();
|
||||
void Show();
|
||||
|
||||
// clipping
|
||||
void RebuildClipping(bool deep = false);
|
||||
void RebuildClipping(bool deep);
|
||||
BRegion& ScreenClipping() const;
|
||||
|
||||
// debugging
|
||||
void PrintToStream() const;
|
||||
|
||||
private:
|
||||
void _InvalidateScreenClipping(bool deep = false);
|
||||
void _InvalidateScreenClipping(bool deep);
|
||||
void _MoveScreenClipping(int32 x, int32 y,
|
||||
bool deep);
|
||||
|
||||
BString fName;
|
||||
// area within parent coordinate space
|
||||
@ -98,6 +108,7 @@ private:
|
||||
|
||||
WindowLayer* fWindow;
|
||||
ViewLayer* fParent;
|
||||
bool fIsTopLayer;
|
||||
|
||||
ViewLayer* fFirstChild;
|
||||
ViewLayer* fPreviousSibling;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <Message.h>
|
||||
#include <MessageQueue.h>
|
||||
|
||||
#include "ClientLooper.h"
|
||||
#include "Desktop.h"
|
||||
#include "DrawingEngine.h"
|
||||
|
||||
@ -29,7 +30,15 @@ WindowLayer::WindowLayer(BRect frame, const char* name,
|
||||
fTopLayer(NULL),
|
||||
|
||||
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
|
||||
// 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
|
||||
fTopLayer = new(nothrow) ViewLayer(fFrame, "top view", B_FOLLOW_ALL, 0,
|
||||
(rgb_color){ 255, 255, 255, 255 });
|
||||
fTopLayer->AttachedToWindow(this, true);
|
||||
|
||||
fClient->Run();
|
||||
}
|
||||
|
||||
// destructor
|
||||
@ -53,7 +65,7 @@ WindowLayer::MessageReceived(BMessage* message)
|
||||
switch (message->what) {
|
||||
case MSG_REDRAW: {
|
||||
if (!MessageQueue()->FindMessage(MSG_REDRAW, 0)) {
|
||||
while (!fDesktop->ReadLockClipping()) {
|
||||
while (!fDesktop->ReadLockClippingWithTimeout()) {
|
||||
//printf("%s MSG_REDRAW -> timeout\n", Name());
|
||||
if (MessageQueue()->FindMessage(MSG_REDRAW, 0)) {
|
||||
//printf("%s MSG_REDRAW -> timeout - leaving because there are pending redraws\n", Name());
|
||||
@ -62,12 +74,25 @@ WindowLayer::MessageReceived(BMessage* message)
|
||||
}
|
||||
_DrawContents(fTopLayer);
|
||||
_DrawBorder();
|
||||
|
||||
fDesktop->ReadUnlockClipping();
|
||||
} else {
|
||||
//printf("%s MSG_REDRAW -> pending redraws\n", Name());
|
||||
}
|
||||
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:
|
||||
BLooper::MessageReceived(message);
|
||||
break;
|
||||
@ -174,6 +199,11 @@ WindowLayer::MoveBy(int32 x, int32 y)
|
||||
if (fContentRegionValid)
|
||||
fContentRegion.OffsetBy(x, y);
|
||||
|
||||
if (fCurrentUpdateSession)
|
||||
fCurrentUpdateSession->MoveBy(x, y);
|
||||
if (fPendingUpdateSession)
|
||||
fPendingUpdateSession->MoveBy(x, y);
|
||||
|
||||
fTopLayer->MoveBy(x, y);
|
||||
|
||||
// TODO: move a local dirty region!
|
||||
@ -210,6 +240,14 @@ WindowLayer::AddChild(ViewLayer* 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
|
||||
}
|
||||
|
||||
@ -221,6 +259,18 @@ WindowLayer::MarkDirty(BRegion* regionOnScreen)
|
||||
fDesktop->MarkDirty(regionOnScreen);
|
||||
}
|
||||
|
||||
// DirtyRegion
|
||||
BRegion
|
||||
WindowLayer::DirtyRegion()
|
||||
{
|
||||
BRegion dirty;
|
||||
if (fDesktop->ReadLockClipping()) {
|
||||
dirty = *fDesktop->DirtyRegion();
|
||||
fDesktop->ReadUnlockClipping();
|
||||
}
|
||||
return dirty;
|
||||
}
|
||||
|
||||
# pragma mark -
|
||||
|
||||
// _DrawContents
|
||||
@ -244,15 +294,16 @@ WindowLayer::_DrawContents(ViewLayer* layer)
|
||||
// TODO: simplify
|
||||
// ideally, there would only be a local fDirtyRegion,
|
||||
// that we need to intersect with. fDirtyRegion would
|
||||
// alread only include fVisibleRegion
|
||||
// already only include fVisibleRegion
|
||||
effectiveWindowClipping.IntersectWith(&fVisibleRegion);
|
||||
effectiveWindowClipping.IntersectWith(fDesktop->DirtyRegion());
|
||||
if (effectiveWindowClipping.Frame().IsValid()) {
|
||||
// send UPDATE message to the client here
|
||||
_MarkContentDirty(&effectiveWindowClipping);
|
||||
|
||||
layer->Draw(fDrawingEngine, &effectiveWindowClipping, true);
|
||||
|
||||
fDesktop->MarkClean(&fContentRegion);
|
||||
|
||||
// send UPDATE message to the client here
|
||||
}
|
||||
//else {
|
||||
//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
|
||||
void
|
||||
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
|
||||
#define WINDOW_LAYER_H
|
||||
|
||||
#include <List.h>
|
||||
#include <Looper.h>
|
||||
#include <Region.h>
|
||||
#include <String.h>
|
||||
|
||||
#include "ViewLayer.h"
|
||||
|
||||
class ClientLooper;
|
||||
class Desktop;
|
||||
class DrawingEngine;
|
||||
|
||||
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 {
|
||||
@ -42,10 +64,20 @@ class WindowLayer : public BLooper {
|
||||
|
||||
void MarkDirty(BRegion* regionOnScreen);
|
||||
|
||||
DrawingEngine* GetDrawingEngine() const
|
||||
{ return fDrawingEngine; }
|
||||
|
||||
BRegion DirtyRegion();
|
||||
|
||||
private:
|
||||
void _DrawContents(ViewLayer* layer = NULL);
|
||||
void _DrawClient(int32 token);
|
||||
void _DrawBorder();
|
||||
|
||||
void _MarkContentDirty(BRegion* localDirty);
|
||||
void _BeginUpdate();
|
||||
void _EndUpdate();
|
||||
|
||||
|
||||
BRect fFrame;
|
||||
// the visible region is only recalculated from the
|
||||
@ -65,6 +97,14 @@ class WindowLayer : public BLooper {
|
||||
|
||||
DrawingEngine* fDrawingEngine;
|
||||
Desktop* fDesktop;
|
||||
|
||||
BList fTokenViewMap;
|
||||
|
||||
ClientLooper* fClient;
|
||||
UpdateSession* fCurrentUpdateSession;
|
||||
UpdateSession* fPendingUpdateSession;
|
||||
bool fUpdateRequested;
|
||||
bool fInUpdate;
|
||||
};
|
||||
|
||||
#endif // WINDOW_LAYER_H
|
||||
|
@ -30,7 +30,8 @@ TYPE= APP
|
||||
# if two source files with the same name (source.c or source.cpp)
|
||||
# are included from different directories. Also note that spaces
|
||||
# in folder names do not work well with this makefile.
|
||||
SRCS= Desktop.cpp \
|
||||
SRCS= ClientLooper.cpp \
|
||||
Desktop.cpp \
|
||||
DrawingEngine.cpp \
|
||||
main.cpp \
|
||||
MultiLocker.cpp \
|
||||
|
Loading…
x
Reference in New Issue
Block a user