* Adding a remote desktop interface that operates on app_server drawing

primitives by providing a RemoteDrawingEngine and a RemoteHWInterface.
  Not really optimized yet, still a bit WIP.
* Adding corresponding infrastructure like a blocking ring buffer and network
  sender/receiver that are attached to the buffers to feed/drain them as well
  as a RemoteMessage helper that provides a message based interface.  
* Adding target screen concept to request an app to be run on a specific screen.
  It's controlled by the TARGET_SCREEN environment variable which is added on
  the app side and sent to the app_server.
* Right now only remote target screens are supported, in which case a new
  RemoteHWInterface is created that tries to connect to the given host:port.
* Fix shape bounds when drawing, they need to be translated by the pen position
  and converted to screen like the points as well. Wasn't visible though as the
  bounds weren't used in the normal DrawingEngine.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33417 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz
2009-10-04 14:15:17 +00:00
parent e40d2817aa
commit 68667bf48a
33 changed files with 3669 additions and 120 deletions
+1
View File
@@ -1272,6 +1272,7 @@ BApplication::_ConnectToServer()
fServerLink->StartMessage(AS_GET_DESKTOP);
fServerLink->Attach<port_id>(clientPort);
fServerLink->Attach<int32>(getuid());
fServerLink->AttachString(getenv("TARGET_SCREEN"));
int32 code;
if (fServerLink->FlushWithReply(code) != B_OK || code != B_OK) {
+19 -7
View File
@@ -176,12 +176,12 @@ AppServer::RunLooper()
/*! \brief Creates a desktop object for an authorized user
*/
Desktop*
AppServer::_CreateDesktop(uid_t userID)
AppServer::_CreateDesktop(uid_t userID, const char* targetScreen)
{
BAutolock locker(fDesktopLock);
Desktop* desktop = NULL;
try {
desktop = new Desktop(userID);
desktop = new Desktop(userID, targetScreen);
status_t status = desktop->Init();
if (status == B_OK) {
@@ -208,16 +208,20 @@ AppServer::_CreateDesktop(uid_t userID)
/*! \brief Finds the desktop object that belongs to a certain user
*/
Desktop *
AppServer::_FindDesktop(uid_t userID)
Desktop*
AppServer::_FindDesktop(uid_t userID, const char* targetScreen)
{
BAutolock locker(fDesktopLock);
for (int32 i = 0; i < fDesktops.CountItems(); i++) {
Desktop* desktop = fDesktops.ItemAt(i);
if (desktop->UserID() == userID)
if (desktop->UserID() == userID
&& ((desktop->TargetScreen() == NULL && targetScreen == NULL)
|| (desktop->TargetScreen() != NULL && targetScreen != NULL
&& strcmp(desktop->TargetScreen(), targetScreen) == 0))) {
return desktop;
}
}
return NULL;
@@ -242,15 +246,23 @@ AppServer::_DispatchMessage(int32 code, BPrivate::LinkReceiver& msg)
int32 userID;
msg.Read<int32>(&userID);
Desktop* desktop = _FindDesktop(userID);
char* targetScreen = NULL;
msg.ReadString(&targetScreen);
if (targetScreen != NULL && strlen(targetScreen) == 0) {
free(targetScreen);
targetScreen = NULL;
}
Desktop* desktop = _FindDesktop(userID, targetScreen);
if (desktop == NULL) {
// we need to create a new desktop object for this user
// TODO: test if the user exists on the system
// TODO: maybe have a separate AS_START_DESKTOP_SESSION for
// authorizing the user
desktop = _CreateDesktop(userID);
desktop = _CreateDesktop(userID, targetScreen);
}
free(targetScreen);
BPrivate::LinkSender reply(replyPort);
if (desktop != NULL) {
reply.StartMessage(B_OK);
+2 -2
View File
@@ -42,8 +42,8 @@ class AppServer : public MessageLooper {
private:
virtual void _DispatchMessage(int32 code, BPrivate::LinkReceiver& link);
Desktop* _CreateDesktop(uid_t userID);
Desktop* _FindDesktop(uid_t userID);
Desktop* _CreateDesktop(uid_t userID, const char* targetScreen);
Desktop* _FindDesktop(uid_t userID, const char* targetScreen);
void _LaunchInputServer();
+10 -4
View File
@@ -289,11 +289,12 @@ workspace_in_workspaces(int32 index, uint32 workspaces)
// #pragma mark -
Desktop::Desktop(uid_t userID)
Desktop::Desktop(uid_t userID, const char* targetScreen)
:
MessageLooper("desktop"),
fUserID(userID),
fTargetScreen(strdup(targetScreen)),
fSettings(NULL),
fSharedReadOnlyArea(-1),
fApplicationsLock("application list"),
@@ -355,7 +356,7 @@ Desktop::Init()
const size_t areaSize = B_PAGE_SIZE;
char name[B_OS_NAME_LENGTH];
snprintf(name, sizeof(name), "d:%d:shared read only", /*id*/0);
snprintf(name, sizeof(name), "d:%d:shared read only", fUserID);
fSharedReadOnlyArea = create_area(name, (void **)&fServerReadOnlyMemory,
B_ANY_ADDRESS, areaSize, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
if (fSharedReadOnlyArea < B_OK)
@@ -385,8 +386,12 @@ Desktop::Init()
gInputManager->AddStream(new InputServerStream);
#endif
EventStream* stream = fVirtualScreen.HWInterface()->CreateEventStream();
if (stream == NULL)
stream = gInputManager->GetStream();
fEventDispatcher.SetDesktop(this);
fEventDispatcher.SetTo(gInputManager->GetStream());
fEventDispatcher.SetTo(stream);
if (fEventDispatcher.InitCheck() != B_OK)
_LaunchInputServer();
@@ -2079,7 +2084,8 @@ Desktop::_LaunchInputServer()
void
Desktop::_GetLooperName(char* name, size_t length)
{
snprintf(name, length, "d:%d:%s", /*id*/0, /*name*/"baron");
snprintf(name, length, "d:%d:%s", fUserID,
fTargetScreen == NULL ? "baron" : fTargetScreen);
}
+3 -1
View File
@@ -59,12 +59,13 @@ namespace BPrivate {
class Desktop : public MessageLooper, public ScreenOwner {
public:
Desktop(uid_t userID);
Desktop(uid_t userID, const char* targetScreen);
virtual ~Desktop();
status_t Init();
uid_t UserID() const { return fUserID; }
const char* TargetScreen() { return fTargetScreen; }
virtual port_id MessagePort() const { return fMessagePort; }
area_id SharedReadOnlyArea() const
{ return fSharedReadOnlyArea; }
@@ -296,6 +297,7 @@ private:
friend class LockedDesktopSettings;
uid_t fUserID;
const char* fTargetScreen;
::VirtualScreen fVirtualScreen;
DesktopSettingsPrivate* fSettings;
port_id fMessagePort;
+2 -2
View File
@@ -63,8 +63,8 @@ Server app_server :
# libraries
:
libtranslation.so libbe.so
libasdrawing.a libpainter.a libagg.a libfreetype.so
libtranslation.so libbe.so libbnetapi.so
libasdrawing.a libasremote.a libpainter.a libagg.a libfreetype.so
libtextencoding.so libshared.a $(TARGET_LIBSTDC++)
: app_server.rdef
+1 -1
View File
@@ -42,7 +42,7 @@ get_mode_frequency(const display_mode& mode)
Screen::Screen(::HWInterface *interface, int32 id)
:
fID(id),
fDriver(interface ? new DrawingEngine(interface) : NULL),
fDriver(interface ? interface->CreateDrawingEngine() : NULL),
fHWInterface(interface)
{
}
+21 -4
View File
@@ -14,6 +14,8 @@
#include "Screen.h"
#include "ServerConfig.h"
#include "remote/RemoteHWInterface.h"
#include <Autolock.h>
#include <Entry.h>
#include <NodeMonitor.h>
@@ -86,7 +88,7 @@ ScreenManager::CountScreens() const
status_t
ScreenManager::AcquireScreens(ScreenOwner* owner, int32* wishList,
int32 wishCount, bool force, ScreenList& list)
int32 wishCount, const char* target, bool force, ScreenList& list)
{
BAutolock locker(this);
int32 added = 0;
@@ -102,6 +104,20 @@ ScreenManager::AcquireScreens(ScreenOwner* owner, int32* wishList,
}
}
if (added == 0 && target != NULL) {
// there's a specific target screen we want to initialize
// TODO: right now we only support remote screens, but we could
// also target specific accelerants to support other graphics cards
RemoteHWInterface* interface = new(nothrow) RemoteHWInterface(target);
if (interface != NULL) {
screen_item* item = _AddHWInterface(interface);
if (item != NULL && list.AddItem(item->screen)) {
item->owner = owner;
added++;
}
}
}
return added > 0 ? B_OK : B_ENTRY_NOT_FOUND;
}
@@ -153,13 +169,13 @@ ScreenManager::_ScanDrivers()
}
void
ScreenManager::screen_item*
ScreenManager::_AddHWInterface(HWInterface* interface)
{
Screen* screen = new(nothrow) Screen(interface, fScreenList.CountItems());
if (screen == NULL) {
delete interface;
return;
return NULL;
}
// The interface is now owned by the screen
@@ -170,13 +186,14 @@ ScreenManager::_AddHWInterface(HWInterface* interface)
item->screen = screen;
item->owner = NULL;
if (fScreenList.AddItem(item))
return;
return item;
delete item;
}
}
delete screen;
return NULL;
}
+5 -4
View File
@@ -41,20 +41,21 @@ class ScreenManager : public BLooper {
int32 CountScreens() const;
status_t AcquireScreens(ScreenOwner* owner, int32* wishList,
int32 wishCount, bool force, ScreenList& list);
int32 wishCount, const char* target, bool force,
ScreenList& list);
void ReleaseScreens(ScreenList& list);
virtual void MessageReceived(BMessage* message);
private:
void _ScanDrivers();
void _AddHWInterface(HWInterface* interface);
struct screen_item {
Screen* screen;
ScreenOwner* owner;
};
void _ScanDrivers();
screen_item* _AddHWInterface(HWInterface* interface);
BObjectList<screen_item> fScreenList;
};
+17
View File
@@ -191,6 +191,23 @@ ServerFont::operator=(const ServerFont& font)
}
bool
ServerFont::operator==(const ServerFont& other) const
{
if (fStyle == NULL && other.fStyle == NULL)
return true;
if (GetFamilyAndStyle() != other.GetFamilyAndStyle())
return false;
return fSize == other.fSize && fRotation == other.fRotation
&& fShear == other.fShear && fFalseBoldWidth == other.fFalseBoldWidth
&& fFlags == other.fFlags && fSpacing == other.fSpacing
&& fEncoding == other.fEncoding && fBounds == other.fBounds
&& fDirection == other.fDirection && fFace == other.fFace;
}
/*!
\brief Returns the number of strikes in the font
\return The number of strikes in the font
+1
View File
@@ -37,6 +37,7 @@ class ServerFont {
virtual ~ServerFont();
ServerFont &operator=(const ServerFont& font);
bool operator==(const ServerFont& other) const;
font_direction Direction() const
{ return fDirection; }
+9 -1
View File
@@ -2541,6 +2541,9 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code,
fCurrentView->ConvertToScreenForDrawing(&ptList[i]);
}
shapeFrame.OffsetBy(penLocation);
fCurrentView->ConvertToScreenForDrawing(&shapeFrame);
drawingEngine->DrawShape(shapeFrame, opCount, opList, ptCount,
ptList, code == AS_FILL_SHAPE);
}
@@ -3430,7 +3433,7 @@ ServerWindow::MakeWindow(BRect frame, const char* name,
// The non-offscreen ServerWindow uses the DrawingEngine instance from
// the desktop.
return new(std::nothrow) ::Window(frame, name, look, feel, flags,
workspace, this, new (nothrow) DrawingEngine(fDesktop->HWInterface()));
workspace, this, fDesktop->HWInterface()->CreateDrawingEngine());
}
@@ -3591,6 +3594,11 @@ ServerWindow::_EnableDirectWindowMode()
return B_ERROR;
}
if (fDesktop->HWInterface()->FrontBuffer() == NULL) {
// direct window mode not supported
return B_UNSUPPORTED;
}
fDirectWindowInfo = new(std::nothrow) DirectWindowInfo;
if (fDirectWindowInfo == NULL)
return B_NO_MEMORY;
+3 -3
View File
@@ -80,8 +80,8 @@ VirtualScreen::SetConfiguration(Desktop& desktop,
_Reset();
ScreenList list;
status_t status = gScreenManager->AcquireScreens(&desktop, NULL, 0, false,
list);
status_t status = gScreenManager->AcquireScreens(&desktop, NULL, 0,
desktop.TargetScreen(), false, list);
if (status != B_OK) {
// TODO: we would try again here with force == true
return status;
@@ -200,7 +200,7 @@ VirtualScreen::ScreenByID(int32 id) const
for (int32 i = fScreenList.CountItems(); i-- > 0;) {
screen_item* item = fScreenList.ItemAt(i);
if (item->screen->ID() == id)
if (item->screen->ID() == id || id == B_MAIN_SCREEN_ID.id)
return item->screen;
}
+3 -5
View File
@@ -194,9 +194,7 @@ DrawingEngine::SetCopyToFrontEnabled(bool enable)
void
DrawingEngine::CopyToFront(/*const*/ BRegion& region)
{
int32 count = region.CountRects();
for (int32 i = 0; i < count; i++)
fGraphicsCard->Invalidate(region.RectAt(i));
fGraphicsCard->InvalidateRegion(region);
}
@@ -521,7 +519,7 @@ DrawingEngine::CopyRegion(/*const*/ BRegion* region,
sortedRectList[nextSortedIndex].bottom = (int32)n->rect.bottom;
nextSortedIndex++;
} else {
BRect touched = _CopyRect(n->rect, xOffset, yOffset);
BRect touched = CopyRect(n->rect, xOffset, yOffset);
fGraphicsCard->Invalidate(touched);
}
@@ -1399,7 +1397,7 @@ DrawingEngine::ReadBitmap(ServerBitmap *bitmap, bool drawCursor, BRect bounds)
// #pragma mark -
BRect
DrawingEngine::_CopyRect(BRect src, int32 xOffset, int32 yOffset) const
DrawingEngine::CopyRect(BRect src, int32 xOffset, int32 yOffset) const
{
// TODO: assumes drawing buffer is 32 bits (which it currently always is)
BRect dst;
+87 -84
View File
@@ -34,160 +34,163 @@ class ServerFont;
class DrawingEngine : public HWInterfaceListener {
public:
DrawingEngine(HWInterface* interface = NULL);
virtual ~DrawingEngine();
virtual ~DrawingEngine();
// HWInterfaceListener interface
virtual void FrameBufferChanged();
virtual void FrameBufferChanged();
// for "changing" hardware
void SetHWInterface(HWInterface* interface);
// for "changing" hardware
void SetHWInterface(HWInterface* interface);
void SetCopyToFrontEnabled(bool enable);
bool CopyToFrontEnabled() const
virtual void SetCopyToFrontEnabled(bool enable);
bool CopyToFrontEnabled() const
{ return fCopyToFront; }
void CopyToFront(/*const*/ BRegion& region);
virtual void CopyToFront(/*const*/ BRegion& region);
// locking
bool LockParallelAccess();
bool IsParallelAccessLocked();
void UnlockParallelAccess();
// locking
bool LockParallelAccess();
bool IsParallelAccessLocked();
void UnlockParallelAccess();
bool LockExclusiveAccess();
bool IsExclusiveAccessLocked();
void UnlockExclusiveAccess();
bool LockExclusiveAccess();
bool IsExclusiveAccessLocked();
void UnlockExclusiveAccess();
// for screen shots
ServerBitmap* DumpToBitmap();
status_t ReadBitmap(ServerBitmap *bitmap, bool drawCursor,
// for screen shots
ServerBitmap* DumpToBitmap();
virtual status_t ReadBitmap(ServerBitmap *bitmap, bool drawCursor,
BRect bounds);
// clipping for all drawing functions, passing a NULL region
// will remove any clipping (drawing allowed everywhere)
void ConstrainClippingRegion(const BRegion* region);
// clipping for all drawing functions, passing a NULL region
// will remove any clipping (drawing allowed everywhere)
virtual void ConstrainClippingRegion(const BRegion* region);
void SetDrawState(const DrawState* state,
virtual void SetDrawState(const DrawState* state,
int32 xOffset = 0, int32 yOffset = 0);
void SetHighColor(const rgb_color& color);
void SetLowColor(const rgb_color& color);
void SetPenSize(float size);
void SetStrokeMode(cap_mode lineCap, join_mode joinMode,
virtual void SetHighColor(const rgb_color& color);
virtual void SetLowColor(const rgb_color& color);
virtual void SetPenSize(float size);
virtual void SetStrokeMode(cap_mode lineCap, join_mode joinMode,
float miterLimit);
void SetPattern(const struct pattern& pattern);
void SetDrawingMode(drawing_mode mode);
void SetDrawingMode(drawing_mode mode,
virtual void SetPattern(const struct pattern& pattern);
virtual void SetDrawingMode(drawing_mode mode);
virtual void SetDrawingMode(drawing_mode mode,
drawing_mode& oldMode);
void SetBlendingMode(source_alpha srcAlpha,
virtual void SetBlendingMode(source_alpha srcAlpha,
alpha_function alphaFunc);
void SetFont(const ServerFont& font);
void SetFont(const DrawState* state);
virtual void SetFont(const ServerFont& font);
virtual void SetFont(const DrawState* state);
void SuspendAutoSync();
void Sync();
void SuspendAutoSync();
void Sync();
// drawing functions
void CopyRegion(/*const*/ BRegion* region,
// drawing functions
virtual void CopyRegion(/*const*/ BRegion* region,
int32 xOffset, int32 yOffset);
void InvertRect(BRect r);
virtual void InvertRect(BRect r);
void DrawBitmap(ServerBitmap* bitmap,
virtual void DrawBitmap(ServerBitmap* bitmap,
const BRect& bitmapRect, const BRect& viewRect,
uint32 options = 0);
// drawing primitives
// drawing primitives
void DrawArc(BRect r, const float& angle,
virtual void DrawArc(BRect r, const float& angle,
const float& span, bool filled);
void FillArc(BRect r, const float& angle,
virtual void FillArc(BRect r, const float& angle,
const float& span, const BGradient& gradient);
void DrawBezier(BPoint* pts, bool filled);
void FillBezier(BPoint* pts, const BGradient& gradient);
virtual void DrawBezier(BPoint* pts, bool filled);
virtual void FillBezier(BPoint* pts, const BGradient& gradient);
void DrawEllipse(BRect r, bool filled);
void FillEllipse(BRect r, const BGradient& gradient);
virtual void DrawEllipse(BRect r, bool filled);
virtual void FillEllipse(BRect r, const BGradient& gradient);
void DrawPolygon(BPoint* ptlist, int32 numpts,
virtual void DrawPolygon(BPoint* ptlist, int32 numpts,
BRect bounds, bool filled, bool closed);
void FillPolygon(BPoint* ptlist, int32 numpts,
virtual void FillPolygon(BPoint* ptlist, int32 numpts,
BRect bounds, const BGradient& gradient,
bool closed);
// these rgb_color versions are used internally by the server
void StrokePoint(const BPoint& pt,
// these rgb_color versions are used internally by the server
virtual void StrokePoint(const BPoint& point,
const rgb_color& color);
void StrokeRect(BRect r, const rgb_color &color);
void FillRect(BRect r, const rgb_color &color);
void FillRegion(BRegion& r, const rgb_color& color);
virtual void StrokeRect(BRect rect, const rgb_color &color);
virtual void FillRect(BRect rect, const rgb_color &color);
virtual void FillRegion(BRegion& region, const rgb_color& color);
void StrokeRect(BRect r);
void FillRect(BRect r);
void FillRect(BRect r, const BGradient& gradient);
virtual void StrokeRect(BRect rect);
virtual void FillRect(BRect rect);
virtual void FillRect(BRect rect, const BGradient& gradient);
void FillRegion(BRegion& r);
void FillRegion(BRegion& r, const BGradient& gradient);
virtual void FillRegion(BRegion& region);
virtual void FillRegion(BRegion& region,
const BGradient& gradient);
void DrawRoundRect(BRect r, float xrad,
virtual void DrawRoundRect(BRect rect, float xrad,
float yrad, bool filled);
void FillRoundRect(BRect r, float xrad,
virtual void FillRoundRect(BRect rect, float xrad,
float yrad, const BGradient& gradient);
void DrawShape(const BRect& bounds,
virtual void DrawShape(const BRect& bounds,
int32 opcount, const uint32* oplist,
int32 ptcount, const BPoint* ptlist,
bool filled);
void FillShape(const BRect& bounds,
virtual void FillShape(const BRect& bounds,
int32 opcount, const uint32* oplist,
int32 ptcount, const BPoint* ptlist,
const BGradient& gradient);
void DrawTriangle(BPoint* pts, const BRect& bounds,
virtual void DrawTriangle(BPoint* points, const BRect& bounds,
bool filled);
void FillTriangle(BPoint* pts,
const BRect& bounds, const BGradient& gradient);
virtual void FillTriangle(BPoint* points, const BRect& bounds,
const BGradient& gradient);
// this version used by Decorator
void StrokeLine(const BPoint& start,
// these versions are used by the Decorator
virtual void StrokeLine(const BPoint& start,
const BPoint& end, const rgb_color& color);
void StrokeLine(const BPoint& start,
virtual void StrokeLine(const BPoint& start,
const BPoint& end);
void StrokeLineArray(int32 numlines,
virtual void StrokeLineArray(int32 numlines,
const ViewLineArrayInfo* data);
// -------- text related calls
// -------- text related calls
// returns the pen position behind the (virtually) drawn
// string
BPoint DrawString(const char* string, int32 length,
// returns the pen position behind the (virtually) drawn
// string
virtual BPoint DrawString(const char* string, int32 length,
const BPoint& pt,
escapement_delta* delta = NULL);
float StringWidth(const char* string, int32 length,
float StringWidth(const char* string, int32 length,
escapement_delta* delta = NULL);
// convenience function which is independent of graphics
// state (to be used by Decorator or ServerApp etc)
float StringWidth(const char* string,
// convenience function which is independent of graphics
// state (to be used by Decorator or ServerApp etc)
float StringWidth(const char* string,
int32 length, const ServerFont& font,
escapement_delta* delta = NULL);
private:
BRect _CopyRect(BRect r, int32 xOffset,
// software rendering backend invoked by CopyRegion() for the sorted
// individual rects
virtual BRect CopyRect(BRect rect, int32 xOffset,
int32 yOffset) const;
void _CopyRect(uint8* bits, uint32 width,
private:
void _CopyRect(uint8* bits, uint32 width,
uint32 height, uint32 bytesPerRow,
int32 xOffset, int32 yOffset) const;
inline void _CopyToFront(const BRect& frame);
inline void _CopyToFront(const BRect& frame);
Painter* fPainter;
HWInterface* fGraphicsCard;
uint32 fAvailableHWAccleration;
int32 fSuspendSyncLevel;
bool fCopyToFront;
Painter* fPainter;
HWInterface* fGraphicsCard;
uint32 fAvailableHWAccleration;
int32 fSuspendSyncLevel;
bool fCopyToFront;
};
#endif // DRAWING_ENGINE_H_
+43
View File
@@ -18,6 +18,7 @@
#include "drawing_support.h"
#include "DrawingEngine.h"
#include "RenderingBuffer.h"
#include "SystemPalette.h"
#include "UpdateQueue.h"
@@ -79,6 +80,20 @@ HWInterface::Initialize()
}
DrawingEngine*
HWInterface::CreateDrawingEngine()
{
return new(std::nothrow) DrawingEngine(this);
}
EventStream*
HWInterface::CreateEventStream()
{
return NULL;
}
status_t
HWInterface::GetAccelerantPath(BString &path)
{
@@ -165,6 +180,18 @@ HWInterface::Cursor() const
}
ServerCursorReference
HWInterface::CursorAndDragBitmap() const
{
if (!fFloatingOverlaysLock.Lock())
return ServerCursorReference(NULL);
ServerCursorReference reference(fCursorAndDragBitmap);
fFloatingOverlaysLock.Unlock();
return reference;
}
void
HWInterface::SetCursorVisible(bool visible)
{
@@ -317,6 +344,22 @@ HWInterface::IsDoubleBuffered() const
}
/*! The object needs to be already locked!
*/
status_t
HWInterface::InvalidateRegion(BRegion& region)
{
int32 count = region.CountRects();
for (int32 i = 0; i < count; i++) {
status_t result = Invalidate(region.RectAt(i));
if (result != B_OK)
return result;
}
return B_OK;
}
/*! The object needs to be already locked!
*/
status_t
+13 -2
View File
@@ -23,11 +23,13 @@
#include "ServerCursor.h"
class BString;
class DrawingEngine;
class EventStream;
class Overlay;
class RenderingBuffer;
class ServerBitmap;
class UpdateQueue;
class BString;
enum {
@@ -69,6 +71,13 @@ public:
virtual status_t Initialize();
virtual status_t Shutdown() = 0;
// allocating a DrawingEngine attached to this HWInterface
virtual DrawingEngine* CreateDrawingEngine();
// creating an event stream specific for this HWInterface
// returns NULL when there is no specific event stream necessary
virtual EventStream* CreateEventStream();
// screen mode stuff
virtual status_t SetMode(const display_mode& mode) = 0;
virtual void GetMode(display_mode* mode) = 0;
@@ -115,6 +124,7 @@ public:
// cursor handling (these do their own Read/Write locking)
ServerCursorReference Cursor() const;
ServerCursorReference CursorAndDragBitmap() const;
virtual void SetCursor(ServerCursor* cursor);
virtual void SetCursorVisible(bool visible);
bool IsCursorVisible();
@@ -122,7 +132,7 @@ public:
virtual void MoveCursorTo(float x, float y);
BPoint CursorPosition();
void SetDragBitmap(const ServerBitmap* bitmap,
virtual void SetDragBitmap(const ServerBitmap* bitmap,
const BPoint& offsetFromCursor);
// overlay support
@@ -148,6 +158,7 @@ public:
virtual bool IsDoubleBuffered() const;
// Invalidate is used for scheduling an area for updating
virtual status_t InvalidateRegion(BRegion& region);
virtual status_t Invalidate(const BRect& frame);
// while as CopyBackToFront() actually performs the operation
// either directly or asynchronously by the UpdateQueue thread
+1
View File
@@ -28,3 +28,4 @@ StaticLibrary libasdrawing.a :
;
SubInclude HAIKU_TOP src servers app drawing Painter ;
SubInclude HAIKU_TOP src servers app drawing remote ;
+25
View File
@@ -0,0 +1,25 @@
SubDir HAIKU_TOP src servers app drawing remote ;
UseLibraryHeaders agg ;
UsePrivateHeaders app graphics interface kernel shared ;
UsePrivateHeaders [ FDirName graphics common ] ;
UsePrivateSystemHeaders ;
UseHeaders [ FDirName $(HAIKU_TOP) src servers app ] ;
UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing ] ;
UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter ] ;
UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter drawing_modes ] ;
UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter font_support ] ;
UseFreeTypeHeaders ;
StaticLibrary libasremote.a :
NetReceiver.cpp
NetSender.cpp
RemoteDrawingEngine.cpp
RemoteEventStream.cpp
RemoteHWInterface.cpp
RemoteMessage.cpp
StreamingRingBuffer.cpp
;
@@ -0,0 +1,110 @@
/*
* Copyright 2009, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#include "NetReceiver.h"
#include "StreamingRingBuffer.h"
#include <NetEndpoint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRACE(x...) /*debug_printf("NetReceiver: "x)*/
#define TRACE_ERROR(x...) debug_printf("NetReceiver: "x)
NetReceiver::NetReceiver(BNetEndpoint *listener, StreamingRingBuffer *target)
:
fListener(listener),
fTarget(target),
fReceiverThread(-1),
fStopThread(false),
fEndpoint(NULL)
{
fReceiverThread = spawn_thread(_NetworkReceiverEntry, "network receiver",
B_NORMAL_PRIORITY, this);
resume_thread(fReceiverThread);
}
NetReceiver::~NetReceiver()
{
fStopThread = true;
if (fEndpoint != NULL)
fEndpoint->Close();
//int32 result;
//wait_for_thread(fReceiverThread, &result);
// TODO: find out why closing the endpoint doesn't notify the waiter
kill_thread(fReceiverThread);
}
int32
NetReceiver::_NetworkReceiverEntry(void *data)
{
return ((NetReceiver *)data)->_NetworkReceiver();
}
status_t
NetReceiver::_NetworkReceiver()
{
status_t result = fListener->Listen();
if (result != B_OK) {
TRACE_ERROR("failed to listen on port: %s\n", strerror(result));
return result;
}
while (!fStopThread) {
fEndpoint = fListener->Accept(1000);
if (fEndpoint == NULL)
continue;
int32 errorCount = 0;
TRACE("new endpoint connection: %p\n", fEndpoint);
while (!fStopThread) {
uint8 buffer[4096];
int32 readSize = fEndpoint->Receive(buffer, sizeof(buffer));
if (readSize < 0) {
TRACE_ERROR("read failed, closing connection: %s\n",
strerror(readSize));
BNetEndpoint *endpoint = fEndpoint;
fEndpoint = NULL;
delete endpoint;
return readSize;
}
if (readSize == 0) {
TRACE("read 0 bytes, retrying\n");
snooze(100 * 1000);
errorCount++;
if (errorCount == 5) {
TRACE_ERROR("failed to read, assuming disconnect\n");
break;
}
continue;
}
errorCount = 0;
status_t result = fTarget->Write(buffer, readSize);
if (result != B_OK) {
TRACE_ERROR("writing to ring buffer failed: %s\n",
strerror(result));
return result;
}
}
}
return B_OK;
}
@@ -0,0 +1,38 @@
/*
* Copyright 2009, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#ifndef NET_RECEIVER_H
#define NET_RECEIVER_H
#include <OS.h>
#include <SupportDefs.h>
class BNetEndpoint;
class StreamingRingBuffer;
class NetReceiver {
public:
NetReceiver(BNetEndpoint *listener,
StreamingRingBuffer *target);
~NetReceiver();
BNetEndpoint * Endpoint() { return fEndpoint; }
private:
static int32 _NetworkReceiverEntry(void *data);
status_t _NetworkReceiver();
BNetEndpoint * fListener;
StreamingRingBuffer * fTarget;
thread_id fReceiverThread;
bool fStopThread;
BNetEndpoint * fEndpoint;
};
#endif // NET_RECEIVER_H
@@ -0,0 +1,75 @@
/*
* Copyright 2009, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#include "NetSender.h"
#include "StreamingRingBuffer.h"
#include <NetEndpoint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRACE(x...) /*debug_printf("NetSender: "x)*/
#define TRACE_ERROR(x...) debug_printf("NetSender: "x)
NetSender::NetSender(BNetEndpoint *endpoint, StreamingRingBuffer *source)
:
fEndpoint(endpoint),
fSource(source),
fSenderThread(-1),
fStopThread(false)
{
fSenderThread = spawn_thread(_NetworkSenderEntry, "network sender",
B_NORMAL_PRIORITY, this);
resume_thread(fSenderThread);
}
NetSender::~NetSender()
{
fStopThread = true;
int32 result;
wait_for_thread(fSenderThread, &result);
}
int32
NetSender::_NetworkSenderEntry(void *data)
{
return ((NetSender *)data)->_NetworkSender();
}
status_t
NetSender::_NetworkSender()
{
while (!fStopThread) {
uint8 buffer[4096];
int32 readSize = fSource->Read(buffer, sizeof(buffer), true);
if (readSize < 0) {
TRACE_ERROR("read failed, stopping sender thread: %s\n",
strerror(readSize));
return readSize;
}
while (readSize > 0) {
int32 sendSize = fEndpoint->Send(buffer, readSize);
if (sendSize < 0) {
TRACE_ERROR("sending data failed: %s\n", strerror(sendSize));
return sendSize;
}
readSize -= sendSize;
}
}
return B_OK;
}
@@ -0,0 +1,34 @@
/*
* Copyright 2009, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#ifndef NET_SENDER_H
#define NET_SENDER_H
#include <OS.h>
#include <SupportDefs.h>
class BNetEndpoint;
class StreamingRingBuffer;
class NetSender {
public:
NetSender(BNetEndpoint *endpoint,
StreamingRingBuffer *source);
~NetSender();
private:
static int32 _NetworkSenderEntry(void *data);
status_t _NetworkSender();
BNetEndpoint * fEndpoint;
StreamingRingBuffer * fSource;
thread_id fSenderThread;
bool fStopThread;
};
#endif // NET_SENDER_H
@@ -0,0 +1,939 @@
/*
* Copyright 2009, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#include "RemoteDrawingEngine.h"
#include "RemoteMessage.h"
#include "DrawState.h"
#include <Bitmap.h>
#include <new>
RemoteDrawingEngine::RemoteDrawingEngine(RemoteHWInterface* interface)
:
DrawingEngine(interface),
fHWInterface(interface),
fToken((uint32)this), // TODO: need to redo that for 64 bit
fExtendWidth(0),
fCallbackAdded(false),
fResultNotify(-1)
{
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_CREATE_STATE);
message.Add(fToken);
}
RemoteDrawingEngine::~RemoteDrawingEngine()
{
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_DELETE_STATE);
message.Add(fToken);
message.Flush();
if (fCallbackAdded)
fHWInterface->RemoveCallback(fToken);
if (fResultNotify >= 0)
delete_sem(fResultNotify);
}
// #pragma mark -
void
RemoteDrawingEngine::FrameBufferChanged()
{
// Not allowed
}
// #pragma mark -
void
RemoteDrawingEngine::SetCopyToFrontEnabled(bool enabled)
{
DrawingEngine::SetCopyToFrontEnabled(enabled);
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(enabled ? RP_ENABLE_SYNC_DRAWING : RP_DISABLE_SYNC_DRAWING);
message.Add(fToken);
}
// #pragma mark -
//! the RemoteDrawingEngine needs to be locked!
void
RemoteDrawingEngine::ConstrainClippingRegion(const BRegion* region)
{
if (fClippingRegion == *region)
return;
fClippingRegion = *region;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_CONSTRAIN_CLIPPING_REGION);
message.Add(fToken);
message.AddRegion(*region);
}
void
RemoteDrawingEngine::SetDrawState(const DrawState* state, int32 xOffset,
int32 yOffset)
{
SetPenSize(state->PenSize());
SetDrawingMode(state->GetDrawingMode());
SetBlendingMode(state->AlphaSrcMode(), state->AlphaFncMode());
SetPattern(state->GetPattern().GetPattern());
SetStrokeMode(state->LineCapMode(), state->LineJoinMode(),
state->MiterLimit());
SetHighColor(state->HighColor());
SetLowColor(state->LowColor());
SetFont(state->Font());
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_SET_OFFSETS);
message.Add(fToken);
message.Add(xOffset);
message.Add(yOffset);
}
void
RemoteDrawingEngine::SetHighColor(const rgb_color& color)
{
if (fState.HighColor() == color)
return;
fState.SetHighColor(color);
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_SET_HIGH_COLOR);
message.Add(fToken);
message.Add(color);
}
void
RemoteDrawingEngine::SetLowColor(const rgb_color& color)
{
if (fState.LowColor() == color)
return;
fState.SetLowColor(color);
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_SET_LOW_COLOR);
message.Add(fToken);
message.Add(color);
}
void
RemoteDrawingEngine::SetPenSize(float size)
{
if (fState.PenSize() == size)
return;
fState.SetPenSize(size);
fExtendWidth = -(size / 2);
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_SET_PEN_SIZE);
message.Add(fToken);
message.Add(size);
}
void
RemoteDrawingEngine::SetStrokeMode(cap_mode lineCap, join_mode joinMode,
float miterLimit)
{
if (fState.LineCapMode() == lineCap && fState.LineJoinMode() == joinMode
&& fState.MiterLimit() == miterLimit)
return;
fState.SetLineCapMode(lineCap);
fState.SetLineJoinMode(joinMode);
fState.SetMiterLimit(miterLimit);
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_SET_STROKE_MODE);
message.Add(fToken);
message.Add(lineCap);
message.Add(joinMode);
message.Add(miterLimit);
}
void
RemoteDrawingEngine::SetBlendingMode(source_alpha sourceAlpha,
alpha_function alphaFunc)
{
if (fState.AlphaSrcMode() == sourceAlpha
&& fState.AlphaFncMode() == alphaFunc)
return;
fState.SetBlendingMode(sourceAlpha, alphaFunc);
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_SET_BLENDING_MODE);
message.Add(fToken);
message.Add(sourceAlpha);
message.Add(alphaFunc);
}
void
RemoteDrawingEngine::SetPattern(const struct pattern& pattern)
{
if (fState.GetPattern() == pattern)
return;
fState.SetPattern(pattern);
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_SET_PATTERN);
message.Add(fToken);
message.Add(pattern);
}
void
RemoteDrawingEngine::SetDrawingMode(drawing_mode mode)
{
if (fState.GetDrawingMode() == mode)
return;
fState.SetDrawingMode(mode);
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_SET_DRAWING_MODE);
message.Add(fToken);
message.Add(mode);
}
void
RemoteDrawingEngine::SetDrawingMode(drawing_mode mode, drawing_mode& oldMode)
{
oldMode = fState.GetDrawingMode();
SetDrawingMode(mode);
}
void
RemoteDrawingEngine::SetFont(const ServerFont& font)
{
if (fState.Font() == font)
return;
fState.SetFont(font);
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_SET_FONT);
message.Add(fToken);
message.AddFont(font);
}
void
RemoteDrawingEngine::SetFont(const DrawState* state)
{
SetFont(state->Font());
}
// #pragma mark -
BRect
RemoteDrawingEngine::CopyRect(BRect rect, int32 xOffset, int32 yOffset) const
{
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_COPY_RECT_NO_CLIPPING);
message.Add(xOffset);
message.Add(yOffset);
message.Add(rect);
return rect.OffsetBySelf(xOffset, yOffset);
}
void
RemoteDrawingEngine::InvertRect(BRect rect)
{
if (!fClippingRegion.Intersects(rect))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_INVERT_RECT);
message.Add(fToken);
message.Add(rect);
}
void
RemoteDrawingEngine::DrawBitmap(ServerBitmap* bitmap, const BRect& _bitmapRect,
const BRect& _viewRect, uint32 options)
{
if (!fClippingRegion.Intersects(_viewRect))
return;
BRect viewRect = _viewRect;
BRect bitmapRect = _bitmapRect;
if (bitmapRect.IntegerWidth() == viewRect.IntegerWidth()
&& bitmapRect.IntegerHeight() == viewRect.IntegerHeight()) {
// unscaled bitmap we can chop off stuff we don't need
BRegion target(viewRect);
target.IntersectWith(&fClippingRegion);
BRect frame = target.Frame();
if (frame != viewRect) {
BPoint offset = frame.LeftTop() - viewRect.LeftTop();
viewRect = frame;
bitmapRect = viewRect.OffsetToCopy(bitmapRect.LeftTop() + offset);
}
}
UtilityBitmap* other = NULL;
BRect bounds = bitmap->Bounds();
BRect newBounds;
newBounds.right
= min_c(bounds.IntegerWidth(), bitmapRect.IntegerWidth());
newBounds.bottom
= min_c(bounds.IntegerHeight(), bitmapRect.IntegerHeight());
if (newBounds.IntegerWidth() < bounds.IntegerWidth()
|| newBounds.IntegerHeight() < bounds.IntegerHeight()) {
other = new(std::nothrow) UtilityBitmap(newBounds, bitmap->ColorSpace(),
bitmap->Flags());
if (other != NULL && other->ImportBits(bitmap->Bits(),
bitmap->BitsLength(), bitmap->BytesPerRow(),
bitmap->ColorSpace(), bitmapRect.LeftTop(), BPoint(0, 0),
newBounds.IntegerWidth() + 1,
newBounds.IntegerHeight() + 1) == B_OK) {
bitmapRect.OffsetTo(0, 0);
bitmap = other;
}
}
// TODO: we may want to cache/checksum bitmaps
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_DRAW_BITMAP);
message.Add(fToken);
message.Add(bitmapRect);
message.Add(viewRect);
message.Add(options);
message.AddBitmap(*bitmap);
if (other != NULL)
delete other;
}
void
RemoteDrawingEngine::DrawArc(BRect rect, const float& angle, const float& span,
bool filled)
{
BRect bounds = rect;
if (!filled)
bounds.InsetBy(fExtendWidth, fExtendWidth);
if (!fClippingRegion.Intersects(bounds))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(filled ? RP_FILL_ARC : RP_STROKE_ARC);
message.Add(fToken);
message.Add(rect);
message.Add(angle);
message.Add(span);
}
void
RemoteDrawingEngine::FillArc(BRect rect, const float& angle, const float& span,
const BGradient& gradient)
{
if (!fClippingRegion.Intersects(rect))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_FILL_ARC_GRADIENT);
message.Add(fToken);
message.Add(rect);
message.Add(angle);
message.Add(span);
message.AddGradient(gradient);
}
void
RemoteDrawingEngine::DrawBezier(BPoint* points, bool filled)
{
BRect bounds = _BuildBounds(points, 4);
if (!filled)
bounds.InsetBy(fExtendWidth, fExtendWidth);
if (!fClippingRegion.Intersects(bounds))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(filled ? RP_FILL_BEZIER : RP_STROKE_BEZIER);
message.Add(fToken);
message.AddList(points, 4);
}
void
RemoteDrawingEngine::FillBezier(BPoint* points, const BGradient& gradient)
{
BRect bounds = _BuildBounds(points, 4);
if (!fClippingRegion.Intersects(bounds))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_FILL_BEZIER_GRADIENT);
message.Add(fToken);
message.AddList(points, 4);
message.AddGradient(gradient);
}
void
RemoteDrawingEngine::DrawEllipse(BRect rect, bool filled)
{
BRect bounds = rect;
if (!filled)
bounds.InsetBy(fExtendWidth, fExtendWidth);
if (!fClippingRegion.Intersects(bounds))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(filled ? RP_FILL_ELLIPSE : RP_STROKE_ELLIPSE);
message.Add(fToken);
message.Add(rect);
}
void
RemoteDrawingEngine::FillEllipse(BRect rect, const BGradient& gradient)
{
if (!fClippingRegion.Intersects(rect))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_FILL_ELLIPSE_GRADIENT);
message.Add(fToken);
message.Add(rect);
message.AddGradient(gradient);
}
void
RemoteDrawingEngine::DrawPolygon(BPoint* pointList, int32 numPoints,
BRect bounds, bool filled, bool closed)
{
BRect clipBounds = bounds;
if (!filled)
clipBounds.InsetBy(fExtendWidth, fExtendWidth);
if (!fClippingRegion.Intersects(clipBounds))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(filled ? RP_FILL_POLYGON : RP_STROKE_POLYGON);
message.Add(fToken);
message.Add(bounds);
message.Add(closed);
message.Add(numPoints);
for (int32 i = 0; i < numPoints; i++)
message.Add(pointList[i]);
}
void
RemoteDrawingEngine::FillPolygon(BPoint* pointList, int32 numPoints,
BRect bounds, const BGradient& gradient, bool closed)
{
if (!fClippingRegion.Intersects(bounds))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_FILL_POLYGON_GRADIENT);
message.Add(fToken);
message.Add(bounds);
message.Add(closed);
message.Add(numPoints);
for (int32 i = 0; i < numPoints; i++)
message.Add(pointList[i]);
message.AddGradient(gradient);
}
// #pragma mark - rgb_color versions
void
RemoteDrawingEngine::StrokePoint(const BPoint& point, const rgb_color& color)
{
BRect bounds(point, point);
bounds.InsetBy(fExtendWidth, fExtendWidth);
if (!fClippingRegion.Intersects(bounds))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_STROKE_POINT_COLOR);
message.Add(fToken);
message.Add(point);
message.Add(color);
}
void
RemoteDrawingEngine::StrokeLine(const BPoint& start, const BPoint& end,
const rgb_color& color)
{
BPoint points[2] = { start, end };
BRect bounds = _BuildBounds(points, 2);
if (!fClippingRegion.Intersects(bounds))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_STROKE_LINE_1PX_COLOR);
message.Add(fToken);
message.AddList(points, 2);
message.Add(color);
}
void
RemoteDrawingEngine::StrokeRect(BRect rect, const rgb_color &color)
{
BRect bounds = rect;
bounds.InsetBy(fExtendWidth, fExtendWidth);
if (!fClippingRegion.Intersects(bounds))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_STROKE_RECT_1PX_COLOR);
message.Add(fToken);
message.Add(rect);
message.Add(color);
}
void
RemoteDrawingEngine::FillRect(BRect rect, const rgb_color& color)
{
if (!fClippingRegion.Intersects(rect))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_FILL_RECT_COLOR);
message.Add(fToken);
message.Add(rect);
message.Add(color);
}
void
RemoteDrawingEngine::FillRegion(BRegion& region, const rgb_color& color)
{
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_FILL_REGION_COLOR_NO_CLIPPING);
message.AddRegion(region);
message.Add(color);
}
// #pragma mark - DrawState versions
void
RemoteDrawingEngine::StrokeRect(BRect rect)
{
BRect bounds = rect;
bounds.InsetBy(fExtendWidth, fExtendWidth);
if (!fClippingRegion.Intersects(bounds))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_STROKE_RECT);
message.Add(fToken);
message.Add(rect);
}
void
RemoteDrawingEngine::FillRect(BRect rect)
{
if (!fClippingRegion.Intersects(rect))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_FILL_RECT);
message.Add(fToken);
message.Add(rect);
}
void
RemoteDrawingEngine::FillRect(BRect rect, const BGradient& gradient)
{
if (!fClippingRegion.Intersects(rect))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_FILL_RECT_GRADIENT);
message.Add(fToken);
message.Add(rect);
message.AddGradient(gradient);
}
void
RemoteDrawingEngine::FillRegion(BRegion& region)
{
BRegion clippedRegion = region;
clippedRegion.IntersectWith(&fClippingRegion);
if (clippedRegion.CountRects() == 0)
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_FILL_REGION);
message.Add(fToken);
message.AddRegion(clippedRegion.CountRects() < region.CountRects()
? clippedRegion : region);
}
void
RemoteDrawingEngine::FillRegion(BRegion& region, const BGradient& gradient)
{
BRegion clippedRegion = region;
clippedRegion.IntersectWith(&fClippingRegion);
if (clippedRegion.CountRects() == 0)
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_FILL_REGION_GRADIENT);
message.Add(fToken);
message.AddRegion(clippedRegion.CountRects() < region.CountRects()
? clippedRegion : region);
message.AddGradient(gradient);
}
void
RemoteDrawingEngine::DrawRoundRect(BRect rect, float xRadius, float yRadius,
bool filled)
{
BRect bounds = rect;
if (!filled)
bounds.InsetBy(fExtendWidth, fExtendWidth);
if (!fClippingRegion.Intersects(bounds))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(filled ? RP_FILL_ROUND_RECT : RP_STROKE_ROUND_RECT);
message.Add(fToken);
message.Add(rect);
message.Add(xRadius);
message.Add(yRadius);
}
void
RemoteDrawingEngine::FillRoundRect(BRect rect, float xRadius, float yRadius,
const BGradient& gradient)
{
if (!fClippingRegion.Intersects(rect))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_FILL_ROUND_RECT_GRADIENT);
message.Add(fToken);
message.Add(rect);
message.Add(xRadius);
message.Add(yRadius);
message.AddGradient(gradient);
}
void
RemoteDrawingEngine::DrawShape(const BRect& bounds, int32 opCount,
const uint32* opList, int32 pointCount, const BPoint* pointList,
bool filled)
{
BRect clipBounds = bounds;
if (!filled)
clipBounds.InsetBy(fExtendWidth, fExtendWidth);
if (!fClippingRegion.Intersects(clipBounds))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(filled ? RP_FILL_SHAPE : RP_STROKE_SHAPE);
message.Add(fToken);
message.Add(bounds);
message.Add(opCount);
message.AddList(opList, opCount);
message.Add(pointCount);
message.AddList(pointList, pointCount);
}
void
RemoteDrawingEngine::FillShape(const BRect& bounds, int32 opCount,
const uint32* opList, int32 pointCount, const BPoint* pointList,
const BGradient& gradient)
{
if (!fClippingRegion.Intersects(bounds))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_FILL_SHAPE_GRADIENT);
message.Add(fToken);
message.Add(bounds);
message.Add(opCount);
message.AddList(opList, opCount);
message.Add(pointCount);
message.AddList(pointList, pointCount);
message.AddGradient(gradient);
}
void
RemoteDrawingEngine::DrawTriangle(BPoint* points, const BRect& bounds,
bool filled)
{
BRect clipBounds = bounds;
if (!filled)
clipBounds.InsetBy(fExtendWidth, fExtendWidth);
if (!fClippingRegion.Intersects(clipBounds))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(filled ? RP_FILL_TRIANGLE : RP_STROKE_TRIANGLE);
message.Add(fToken);
message.AddList(points, 3);
message.Add(bounds);
}
void
RemoteDrawingEngine::FillTriangle(BPoint* points, const BRect& bounds,
const BGradient& gradient)
{
if (!fClippingRegion.Intersects(bounds))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_FILL_TRIANGLE_GRADIENT);
message.Add(fToken);
message.Add(points[0]);
message.Add(points[1]);
message.Add(points[2]);
message.Add(bounds);
message.AddGradient(gradient);
}
void
RemoteDrawingEngine::StrokeLine(const BPoint &start, const BPoint &end)
{
BPoint points[2] = { start, end };
BRect bounds = _BuildBounds(points, 2);
if (!fClippingRegion.Intersects(bounds))
return;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_STROKE_LINE);
message.Add(fToken);
message.AddList(points, 2);
}
void
RemoteDrawingEngine::StrokeLineArray(int32 numLines,
const ViewLineArrayInfo *lineData)
{
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_STROKE_LINE_ARRAY);
message.Add(fToken);
message.Add(numLines);
for (int32 i = 0; i < numLines; i++)
message.AddArrayLine(lineData[i]);
}
// #pragma mark - string functions
BPoint
RemoteDrawingEngine::DrawString(const char* string, int32 length,
const BPoint& point, escapement_delta* delta)
{
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_DRAW_STRING);
message.Add(fToken);
message.Add(point);
message.AddString(string, length);
message.Add(delta != NULL);
if (delta != NULL)
message.AddList(delta, length);
status_t result = _AddCallback();
if (message.Flush() != B_OK)
return point;
if (result != B_OK)
return point;
do {
result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
1 * 1000 * 1000);
} while (result == B_INTERRUPTED);
if (result != B_OK)
return point;
return fDrawStringResult;
}
float
RemoteDrawingEngine::StringWidth(const char* string, int32 length,
escapement_delta* delta)
{
// TODO: decide if really needed and use callback if so
return fState.Font().StringWidth(string, length, delta);
}
// #pragma mark -
status_t
RemoteDrawingEngine::ReadBitmap(ServerBitmap* bitmap, bool drawCursor,
BRect bounds)
{
if (_AddCallback() != B_OK)
return B_UNSUPPORTED;
RemoteMessage message(NULL, fHWInterface->SendBuffer());
message.Start(RP_READ_BITMAP);
message.Add(fToken);
message.Add(bounds);
message.Add(drawCursor);
if (message.Flush() != B_OK)
return B_UNSUPPORTED;
status_t result;
do {
result = acquire_sem_etc(fResultNotify, 1, B_RELATIVE_TIMEOUT,
100 * 1000 * 1000);
} while (result == B_INTERRUPTED);
if (result != B_OK)
return result;
BBitmap* read = fReadBitmapResult;
if (read == NULL)
return B_UNSUPPORTED;
result = bitmap->ImportBits(read->Bits(), read->BitsLength(),
read->BytesPerRow(), read->ColorSpace());
delete read;
return result;
}
// #pragma mark -
status_t
RemoteDrawingEngine::_AddCallback()
{
if (fCallbackAdded)
return B_OK;
if (fResultNotify < 0)
fResultNotify = create_sem(0, "drawing engine result");
if (fResultNotify < 0)
return fResultNotify;
status_t result = fHWInterface->AddCallback(fToken, &_DrawingEngineResult,
this);
fCallbackAdded = result == B_OK;
return result;
}
bool
RemoteDrawingEngine::_DrawingEngineResult(void* cookie, RemoteMessage& message)
{
RemoteDrawingEngine* engine = (RemoteDrawingEngine*)cookie;
switch (message.Code()) {
case RP_DRAW_STRING_RESULT:
if (message.Read(engine->fDrawStringResult) != B_OK)
return false;
break;
case RP_STRING_WIDTH_RESULT:
if (message.Read(engine->fStringWidthResult) != B_OK)
return false;
break;
case RP_READ_BITMAP_RESULT:
if (message.ReadBitmap(&engine->fReadBitmapResult) != B_OK)
return false;
break;
default:
return false;
}
release_sem(engine->fResultNotify);
return true;
}
BRect
RemoteDrawingEngine::_BuildBounds(BPoint* points, int32 pointCount)
{
BRect bounds(1000000, 1000000, 0, 0);
for (int32 i = 0; i < pointCount; i++) {
bounds.left = min_c(bounds.left, points[i].x);
bounds.top = min_c(bounds.top, points[i].y);
bounds.right = max_c(bounds.right, points[i].x);
bounds.bottom = max_c(bounds.bottom, points[i].y);
}
return bounds;
}
@@ -0,0 +1,165 @@
/*
* Copyright 2009, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#ifndef REMOTE_DRAWING_ENGINE_H
#define REMOTE_DRAWING_ENGINE_H
#include "DrawingEngine.h"
#include "DrawState.h"
#include "RemoteHWInterface.h"
#include "ServerFont.h"
class BPoint;
class BRect;
class BRegion;
class ServerBitmap;
class RemoteDrawingEngine : public DrawingEngine {
public:
RemoteDrawingEngine(
RemoteHWInterface* interface);
virtual ~RemoteDrawingEngine();
// HWInterfaceListener interface
virtual void FrameBufferChanged();
virtual void SetCopyToFrontEnabled(bool enabled);
// for screen shots
virtual status_t ReadBitmap(ServerBitmap* bitmap,
bool drawCursor, BRect bounds);
// clipping for all drawing functions, passing a NULL region
// will remove any clipping (drawing allowed everywhere)
virtual void ConstrainClippingRegion(const BRegion* region);
virtual void SetDrawState(const DrawState* state,
int32 xOffset = 0, int32 yOffset = 0);
virtual void SetHighColor(const rgb_color& color);
virtual void SetLowColor(const rgb_color& color);
virtual void SetPenSize(float size);
virtual void SetStrokeMode(cap_mode lineCap,
join_mode joinMode, float miterLimit);
virtual void SetPattern(const struct pattern& pattern);
virtual void SetDrawingMode(drawing_mode mode);
virtual void SetDrawingMode(drawing_mode mode,
drawing_mode& oldMode);
virtual void SetBlendingMode(source_alpha srcAlpha,
alpha_function alphaFunc);
virtual void SetFont(const ServerFont& font);
virtual void SetFont(const DrawState* state);
// drawing functions
virtual void InvertRect(BRect rect);
virtual void DrawBitmap(ServerBitmap* bitmap,
const BRect& bitmapRect,
const BRect& viewRect, uint32 options = 0);
// drawing primitives
virtual void DrawArc(BRect rect, const float& angle,
const float& span, bool filled);
virtual void FillArc(BRect rect, const float& angle,
const float& span,
const BGradient& gradient);
virtual void DrawBezier(BPoint* points, bool filled);
virtual void FillBezier(BPoint* points,
const BGradient& gradient);
virtual void DrawEllipse(BRect rect, bool filled);
virtual void FillEllipse(BRect rect,
const BGradient& gradient);
virtual void DrawPolygon(BPoint* pointList, int32 numPoints,
BRect bounds, bool filled, bool closed);
virtual void FillPolygon(BPoint* pointList, int32 numPoints,
BRect bounds, const BGradient& gradient,
bool closed);
// these rgb_color versions are used internally by the server
virtual void StrokePoint(const BPoint& point,
const rgb_color& color);
virtual void StrokeRect(BRect rect, const rgb_color &color);
virtual void FillRect(BRect rect, const rgb_color &color);
virtual void FillRegion(BRegion& region,
const rgb_color& color);
virtual void StrokeRect(BRect rect);
virtual void FillRect(BRect rect);
virtual void FillRect(BRect rect, const BGradient& gradient);
virtual void FillRegion(BRegion& region);
virtual void FillRegion(BRegion& region,
const BGradient& gradient);
virtual void DrawRoundRect(BRect rect, float xRadius,
float yRadius, bool filled);
virtual void FillRoundRect(BRect rect, float xRadius,
float yRadius, const BGradient& gradient);
virtual void DrawShape(const BRect& bounds,
int32 opCount, const uint32* opList,
int32 pointCount, const BPoint* pointList,
bool filled);
virtual void FillShape(const BRect& bounds,
int32 opCount, const uint32* opList,
int32 pointCount, const BPoint* pointList,
const BGradient& gradient);
virtual void DrawTriangle(BPoint* points,
const BRect& bounds, bool filled);
virtual void FillTriangle(BPoint* points,
const BRect& bounds,
const BGradient& gradient);
// these versions are used by the Decorator
virtual void StrokeLine(const BPoint& start,
const BPoint& end, const rgb_color& color);
virtual void StrokeLine(const BPoint& start,
const BPoint& end);
virtual void StrokeLineArray(int32 numlines,
const ViewLineArrayInfo* data);
// returns the pen position behind the (virtually) drawn string
virtual BPoint DrawString(const char* string, int32 length,
const BPoint& point,
escapement_delta* delta = NULL);
virtual float StringWidth(const char* string, int32 length,
escapement_delta* delta = NULL);
// software rendering backend invoked by CopyRegion() for the sorted
// individual rects
virtual BRect CopyRect(BRect rect, int32 xOffset,
int32 yOffset) const;
private:
status_t _AddCallback();
static bool _DrawingEngineResult(void* cookie,
RemoteMessage& message);
BRect _BuildBounds(BPoint* points, int32 pointCount);
RemoteHWInterface* fHWInterface;
uint32 fToken;
DrawState fState;
BRegion fClippingRegion;
float fExtendWidth;
bool fCallbackAdded;
sem_id fResultNotify;
BPoint fDrawStringResult;
float fStringWidthResult;
BBitmap* fReadBitmapResult;
};
#endif // REMOTE_DRAWING_ENGINE_H
@@ -0,0 +1,215 @@
/*
* Copyright 2009, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#include "RemoteEventStream.h"
#include "RemoteMessage.h"
#include "StreamingRingBuffer.h"
#include <Autolock.h>
#include <new>
RemoteEventStream::RemoteEventStream()
:
fEventList(10, true),
fEventListLocker("remote event list"),
fEventNotification(-1),
fWaitingOnEvent(false),
fLatestMouseMovedEvent(NULL),
fMousePosition(0, 0),
fMouseButtons(0),
fModifiers(0)
{
fEventNotification = create_sem(0, "remote event notification");
}
RemoteEventStream::~RemoteEventStream()
{
delete_sem(fEventNotification);
}
void
RemoteEventStream::UpdateScreenBounds(BRect bounds)
{
}
bool
RemoteEventStream::GetNextEvent(BMessage** _event)
{
BAutolock lock(fEventListLocker);
while (fEventList.CountItems() == 0) {
fWaitingOnEvent = true;
lock.Unlock();
status_t result;
do {
result = acquire_sem(fEventNotification);
} while (result == B_INTERRUPTED);
lock.Lock();
if (!lock.IsLocked())
return false;
}
*_event = fEventList.RemoveItemAt(0);
return true;
}
status_t
RemoteEventStream::InsertEvent(BMessage* event)
{
BAutolock lock(fEventListLocker);
if (!lock.IsLocked())
return B_ERROR;
if (!fEventList.AddItem(event))
return B_ERROR;
if (event->what == B_MOUSE_MOVED)
fLatestMouseMovedEvent = event;
return B_OK;
}
BMessage*
RemoteEventStream::PeekLatestMouseMoved()
{
return fLatestMouseMovedEvent;
}
bool
RemoteEventStream::EventReceived(RemoteMessage& message)
{
uint16 code = message.Code();
uint32 what = 0;
switch (code) {
case RP_MOUSE_MOVED:
what = B_MOUSE_MOVED;
break;
case RP_MOUSE_DOWN:
what = B_MOUSE_DOWN;
break;
case RP_MOUSE_UP:
what = B_MOUSE_UP;
break;
case RP_MOUSE_WHEEL_CHANGED:
what = B_MOUSE_WHEEL_CHANGED;
break;
case RP_KEY_DOWN:
what = B_KEY_DOWN;
break;
case RP_KEY_UP:
what = B_KEY_UP;
break;
case RP_MODIFIERS_CHANGED:
what = B_MODIFIERS_CHANGED;
break;
}
if (what == 0)
return false;
BMessage* event = new BMessage(what);
if (event == NULL)
return false;
event->AddInt64("when", system_time());
switch (code) {
case RP_MOUSE_MOVED:
case RP_MOUSE_DOWN:
case RP_MOUSE_UP:
{
message.Read(fMousePosition);
if (code != RP_MOUSE_MOVED)
message.Read(fMouseButtons);
event->AddPoint("where", fMousePosition);
event->AddInt32("buttons", fMouseButtons);
event->AddInt32("modifiers", fModifiers);
if (code == RP_MOUSE_DOWN) {
int32 clicks;
if (message.Read(clicks) == B_OK)
event->AddInt32("clicks", clicks);
}
if (code == RP_MOUSE_MOVED)
fLatestMouseMovedEvent = event;
break;
}
case RP_MOUSE_WHEEL_CHANGED:
{
float xDelta, yDelta;
message.Read(xDelta);
message.Read(yDelta);
event->AddFloat("be:wheel_delta_x", xDelta);
event->AddFloat("be:wheel_delta_y", yDelta);
break;
}
case RP_KEY_DOWN:
case RP_KEY_UP:
{
int32 numBytes;
if (message.Read(numBytes) != B_OK)
break;
char* bytes = (char*)malloc(numBytes + 1);
if (bytes == NULL)
break;
if (message.ReadList(bytes, numBytes) != B_OK)
break;
for (int32 i = 0; i < numBytes; i++)
event->AddInt8("byte", (int8)bytes[i]);
bytes[numBytes] = 0;
event->AddData("bytes", B_STRING_TYPE, bytes, numBytes + 1, false);
event->AddInt32("modifiers", fModifiers);
int32 rawChar;
if (message.Read(rawChar) == B_OK)
event->AddInt32("raw_char", rawChar);
int32 key;
if (message.Read(key) == B_OK)
event->AddInt32("key", key);
break;
}
case RP_MODIFIERS_CHANGED:
{
event->AddInt32("be:old_modifiers", fModifiers);
message.Read(fModifiers);
event->AddInt32("modifiers", fModifiers);
break;
}
}
BAutolock lock(fEventListLocker);
fEventList.AddItem(event);
if (fWaitingOnEvent) {
fWaitingOnEvent = false;
lock.Unlock();
release_sem(fEventNotification);
}
return true;
}
@@ -0,0 +1,45 @@
/*
* Copyright 2009, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#ifndef REMOTE_EVENT_STREAM_H
#define REMOTE_EVENT_STREAM_H
#include "EventStream.h"
#include <Locker.h>
#include <ObjectList.h>
class RemoteMessage;
class RemoteEventStream : public EventStream {
public:
RemoteEventStream();
virtual ~RemoteEventStream();
virtual bool IsValid() { return true; }
virtual void SendQuit() {}
virtual void UpdateScreenBounds(BRect bounds);
virtual bool GetNextEvent(BMessage** _event);
virtual status_t InsertEvent(BMessage* event);
virtual BMessage* PeekLatestMouseMoved();
bool EventReceived(RemoteMessage& message);
private:
BObjectList<BMessage> fEventList;
BLocker fEventListLocker;
sem_id fEventNotification;
bool fWaitingOnEvent;
BMessage* fLatestMouseMovedEvent;
BPoint fMousePosition;
uint32 fMouseButtons;
uint32 fModifiers;
};
#endif // REMOTE_EVENT_STREAM_H
@@ -0,0 +1,572 @@
/*
* Copyright 2009, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#include "RemoteHWInterface.h"
#include "RemoteDrawingEngine.h"
#include "RemoteEventStream.h"
#include "RemoteMessage.h"
#include "NetReceiver.h"
#include "NetSender.h"
#include "StreamingRingBuffer.h"
#include <Autolock.h>
#include <NetEndpoint.h>
#include <new>
#include <string.h>
#define TRACE(x...) /*debug_printf("RemoteHWInterface: "x)*/
#define TRACE_ALWAYS(x...) debug_printf("RemoteHWInterface: "x)
#define TRACE_ERROR(x...) debug_printf("RemoteHWInterface: "x)
struct callback_info {
uint32 token;
CallbackFunction callback;
void* cookie;
};
RemoteHWInterface::RemoteHWInterface(const char* target)
:
HWInterface(),
fTarget(target),
fRemoteHost(NULL),
fRemotePort(10900),
fIsConnected(false),
fProtocolVersion(100),
fConnectionSpeed(0),
fListenPort(10901),
fSendEndpoint(NULL),
fReceiveEndpoint(NULL),
fSendBuffer(NULL),
fReceiveBuffer(NULL),
fSender(NULL),
fReceiver(NULL),
fEventThread(-1),
fEventStream(NULL),
fCallbackLocker("callback locker")
{
fDisplayMode.virtual_width = 640;
fDisplayMode.virtual_height = 480;
fDisplayMode.space = B_RGB32;
fRemoteHost = strdup(fTarget);
char *portStart = strchr(fRemoteHost, ':');
if (portStart != NULL) {
portStart[0] = 0;
portStart++;
if (sscanf(portStart, "%lu", &fRemotePort) != 1) {
fInitStatus = B_BAD_VALUE;
return;
}
fListenPort = fRemotePort + 1;
}
fSendEndpoint = new(std::nothrow) BNetEndpoint();
if (fSendEndpoint == NULL) {
fInitStatus = B_NO_MEMORY;
return;
}
fReceiveEndpoint = new(std::nothrow) BNetEndpoint();
if (fReceiveEndpoint == NULL) {
fInitStatus = B_NO_MEMORY;
return;
}
fInitStatus = fReceiveEndpoint->Bind(fListenPort);
if (fInitStatus != B_OK)
return;
fSendBuffer = new(std::nothrow) StreamingRingBuffer(16 * 1024);
if (fSendBuffer == NULL) {
fInitStatus = B_NO_MEMORY;
return;
}
fInitStatus = fSendBuffer->InitCheck();
if (fInitStatus != B_OK)
return;
fReceiveBuffer = new(std::nothrow) StreamingRingBuffer(16 * 1024);
if (fReceiveBuffer == NULL) {
fInitStatus = B_NO_MEMORY;
return;
}
fInitStatus = fReceiveBuffer->InitCheck();
if (fInitStatus != B_OK)
return;
fSender = new(std::nothrow) NetSender(fSendEndpoint, fSendBuffer);
if (fSender == NULL) {
fInitStatus = B_NO_MEMORY;
return;
}
fReceiver = new(std::nothrow) NetReceiver(fReceiveEndpoint, fReceiveBuffer);
if (fReceiver == NULL) {
fInitStatus = B_NO_MEMORY;
return;
}
fEventStream = new(std::nothrow) RemoteEventStream();
if (fEventStream == NULL) {
fInitStatus = B_NO_MEMORY;
return;
}
fSendEndpoint->SetTimeout(3 * 1000 * 1000);
fInitStatus = _Connect();
if (fInitStatus != B_OK)
return;
fEventThread = spawn_thread(_EventThreadEntry, "remote event thread",
B_NORMAL_PRIORITY, this);
if (fEventThread < 0) {
fInitStatus = fEventThread;
return;
}
resume_thread(fEventThread);
}
RemoteHWInterface::~RemoteHWInterface()
{
delete fReceiver;
delete fReceiveBuffer;
delete fSendBuffer;
delete fSender;
delete fReceiveEndpoint;
delete fSendEndpoint;
delete fEventStream;
free(fRemoteHost);
}
status_t
RemoteHWInterface::Initialize()
{
return fInitStatus;
}
status_t
RemoteHWInterface::Shutdown()
{
_Disconnect();
return B_OK;
}
DrawingEngine*
RemoteHWInterface::CreateDrawingEngine()
{
return new(std::nothrow) RemoteDrawingEngine(this);
}
EventStream*
RemoteHWInterface::CreateEventStream()
{
return fEventStream;
}
status_t
RemoteHWInterface::AddCallback(uint32 token, CallbackFunction callback,
void* cookie)
{
BAutolock lock(fCallbackLocker);
int32 index = fCallbacks.BinarySearchIndexByKey(token, &_CallbackCompare);
if (index >= 0)
return B_NAME_IN_USE;
callback_info* info = new(std::nothrow) callback_info;
if (info == NULL)
return B_NO_MEMORY;
info->token = token;
info->callback = callback;
info->cookie = cookie;
fCallbacks.AddItem(info, -index - 1);
return B_OK;
}
bool
RemoteHWInterface::RemoveCallback(uint32 token)
{
BAutolock lock(fCallbackLocker);
int32 index = fCallbacks.BinarySearchIndexByKey(token, &_CallbackCompare);
if (index < 0)
return false;
delete fCallbacks.RemoveItemAt(index);
return true;
}
callback_info*
RemoteHWInterface::_FindCallback(uint32 token)
{
BAutolock lock(fCallbackLocker);
return fCallbacks.BinarySearchByKey(token, &_CallbackCompare);
}
int
RemoteHWInterface::_CallbackCompare(const uint32* key,
const callback_info* info)
{
if (info->token == *key)
return 0;
if (info->token < *key)
return -1;
return 1;
}
int32
RemoteHWInterface::_EventThreadEntry(void* data)
{
return ((RemoteHWInterface*)data)->_EventThread();
}
status_t
RemoteHWInterface::_EventThread()
{
RemoteMessage message(fReceiveBuffer, fSendBuffer);
while (true) {
uint16 code;
status_t result = message.NextMessage(code);
if (result != B_OK) {
TRACE_ERROR("failed to read message from receiver: %s\n",
strerror(result));
return result;
}
TRACE("got message code %u with %lu bytes\n", code, message.DataLeft());
if (code >= RP_MOUSE_MOVED && code <= RP_MODIFIERS_CHANGED) {
// an input event, dispatch to the event stream
if (fEventStream->EventReceived(message))
continue;
}
switch (code) {
case RP_UPDATE_DISPLAY_MODE:
{
// TODO: implement, we only handle it in the context of the
// initial mode setup on connect
break;
}
default:
{
uint32 token;
if (message.Read(token) == B_OK) {
callback_info* info = _FindCallback(token);
if (info != NULL && info->callback(info->cookie, message))
break;
}
TRACE_ERROR("unhandled remote event code %u\n", code);
break;
}
}
}
}
status_t
RemoteHWInterface::_Connect()
{
TRACE("connecting to host \"%s\" port %lu\n", fRemoteHost, fRemotePort);
status_t result = fSendEndpoint->Connect(fRemoteHost, (uint16)fRemotePort);
if (result != B_OK) {
TRACE_ERROR("failed to connect to host \"%s\" port %lu\n", fRemoteHost,
fRemotePort);
return result;
}
RemoteMessage message(fReceiveBuffer, fSendBuffer);
message.Start(RP_INIT_CONNECTION);
message.Add(fListenPort);
result = message.Flush();
if (result != B_OK) {
TRACE_ERROR("failed to send init connection message\n");
return result;
}
uint16 code;
result = message.NextMessage(code);
if (result != B_OK) {
TRACE_ERROR("failed to read message from receiver: %s\n",
strerror(result));
return result;
}
TRACE("code %u with %lu bytes of data\n", code, message.DataLeft());
if (code != RP_UPDATE_DISPLAY_MODE) {
TRACE_ERROR("invalid connection init code %u\n", code);
return B_ERROR;
}
int32 width, height;
message.Read(width);
result = message.Read(height);
if (result != B_OK) {
TRACE_ERROR("failed to get initial display mode\n");
return result;
}
fDisplayMode.virtual_width = width;
fDisplayMode.virtual_height = height;
return B_OK;
}
void
RemoteHWInterface::_Disconnect()
{
if (fIsConnected) {
RemoteMessage message(NULL, fSendBuffer);
message.Start(RP_CLOSE_CONNECTION);
message.Flush();
fIsConnected = false;
}
if (fSendEndpoint != NULL)
fSendEndpoint->Close();
if (fReceiveEndpoint != NULL)
fReceiveEndpoint->Close();
}
status_t
RemoteHWInterface::SetMode(const display_mode& mode)
{
// The display mode depends on the screen resolution of the client, we
// don't allow to change it.
return B_UNSUPPORTED;
}
void
RemoteHWInterface::GetMode(display_mode* mode)
{
if (mode == NULL || !ReadLock())
return;
*mode = fDisplayMode;
ReadUnlock();
}
status_t
RemoteHWInterface::GetDeviceInfo(accelerant_device_info* info)
{
if (!ReadLock())
return B_ERROR;
info->version = fProtocolVersion;
info->dac_speed = fConnectionSpeed;
info->memory = 33554432; // 32MB
sprintf(info->name, "Haiku, Inc. RemoteHWInterface");
sprintf(info->chipset, "Haiku, Inc. Chipset");
sprintf(info->serial_no, fTarget);
ReadUnlock();
return B_OK;
}
status_t
RemoteHWInterface::GetFrameBufferConfig(frame_buffer_config& config)
{
// We don't actually have a frame buffer.
return B_UNSUPPORTED;
}
status_t
RemoteHWInterface::GetModeList(display_mode** _modes, uint32* _count)
{
AutoReadLocker _(this);
display_mode* modes = new(std::nothrow) display_mode[1];
if (modes == NULL)
return B_NO_MEMORY;
modes[0] = fDisplayMode;
*_modes = modes;
*_count = 1;
return B_OK;
}
status_t
RemoteHWInterface::GetPixelClockLimits(display_mode* mode, uint32* low,
uint32* high)
{
return B_UNSUPPORTED;
}
status_t
RemoteHWInterface::GetTimingConstraints(display_timing_constraints* constraints)
{
return B_UNSUPPORTED;
}
status_t
RemoteHWInterface::ProposeMode(display_mode* candidate, const display_mode* low,
const display_mode* high)
{
return B_UNSUPPORTED;
}
status_t
RemoteHWInterface::SetDPMSMode(uint32 state)
{
return B_UNSUPPORTED;
}
uint32
RemoteHWInterface::DPMSMode()
{
return B_UNSUPPORTED;
}
uint32
RemoteHWInterface::DPMSCapabilities()
{
return 0;
}
sem_id
RemoteHWInterface::RetraceSemaphore()
{
return -1;
}
status_t
RemoteHWInterface::WaitForRetrace(bigtime_t timeout)
{
return B_UNSUPPORTED;
}
void
RemoteHWInterface::SetCursor(ServerCursor* cursor)
{
HWInterface::SetCursor(cursor);
RemoteMessage message(NULL, fSendBuffer);
message.Start(RP_SET_CURSOR);
message.AddCursor(Cursor().Cursor());
}
void
RemoteHWInterface::SetCursorVisible(bool visible)
{
HWInterface::SetCursorVisible(visible);
RemoteMessage message(NULL, fSendBuffer);
message.Start(RP_SET_CURSOR_VISIBLE);
message.Add(visible);
}
void
RemoteHWInterface::MoveCursorTo(float x, float y)
{
HWInterface::MoveCursorTo(x, y);
RemoteMessage message(NULL, fSendBuffer);
message.Start(RP_MOVE_CURSOR_TO);
message.Add(x);
message.Add(y);
}
void
RemoteHWInterface::SetDragBitmap(const ServerBitmap* bitmap,
const BPoint& offsetFromCursor)
{
HWInterface::SetDragBitmap(bitmap, offsetFromCursor);
RemoteMessage message(NULL, fSendBuffer);
message.Start(RP_SET_CURSOR);
message.AddCursor(CursorAndDragBitmap().Cursor());
}
RenderingBuffer*
RemoteHWInterface::FrontBuffer() const
{
return NULL;
}
RenderingBuffer*
RemoteHWInterface::BackBuffer() const
{
return NULL;
}
bool
RemoteHWInterface::IsDoubleBuffered() const
{
return false;
}
status_t
RemoteHWInterface::InvalidateRegion(BRegion& region)
{
RemoteMessage message(NULL, fSendBuffer);
message.Start(RP_INVALIDATE_REGION);
message.AddRegion(region);
return B_OK;
}
status_t
RemoteHWInterface::Invalidate(const BRect& frame)
{
RemoteMessage message(NULL, fSendBuffer);
message.Start(RP_INVALIDATE_RECT);
message.Add(frame);
return B_OK;
}
status_t
RemoteHWInterface::CopyBackToFront(const BRect& frame)
{
return B_OK;
}
@@ -0,0 +1,127 @@
/*
* Copyright 2009, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#ifndef REMOTE_HW_INTERFACE_H
#define REMOTE_HW_INTERFACE_H
#include "HWInterface.h"
#include <Locker.h>
#include <ObjectList.h>
class BNetEndpoint;
class StreamingRingBuffer;
class NetSender;
class NetReceiver;
class RemoteEventStream;
class RemoteMessage;
struct callback_info;
typedef bool (*CallbackFunction)(void* cookie, RemoteMessage& message);
class RemoteHWInterface : public HWInterface {
public:
RemoteHWInterface(const char* target);
virtual ~RemoteHWInterface();
virtual status_t Initialize();
virtual status_t Shutdown();
virtual DrawingEngine* CreateDrawingEngine();
virtual EventStream* CreateEventStream();
virtual status_t SetMode(const display_mode& mode);
virtual void GetMode(display_mode* mode);
virtual status_t GetDeviceInfo(accelerant_device_info* info);
virtual status_t GetFrameBufferConfig(
frame_buffer_config& config);
virtual status_t GetModeList(display_mode** _modeList,
uint32* _count);
virtual status_t GetPixelClockLimits(display_mode* mode,
uint32* _low, uint32* _high);
virtual status_t GetTimingConstraints(
display_timing_constraints* constraints);
virtual status_t ProposeMode(display_mode* candidate,
const display_mode* low,
const display_mode* high);
virtual sem_id RetraceSemaphore();
virtual status_t WaitForRetrace(
bigtime_t timeout = B_INFINITE_TIMEOUT);
virtual status_t SetDPMSMode(uint32 state);
virtual uint32 DPMSMode();
virtual uint32 DPMSCapabilities();
// cursor handling
virtual void SetCursor(ServerCursor* cursor);
virtual void SetCursorVisible(bool visible);
virtual void MoveCursorTo(float x, float y);
virtual void SetDragBitmap(const ServerBitmap* bitmap,
const BPoint& offsetFormCursor);
// frame buffer access
virtual RenderingBuffer* FrontBuffer() const;
virtual RenderingBuffer* BackBuffer() const;
virtual bool IsDoubleBuffered() const;
virtual status_t InvalidateRegion(BRegion& region);
virtual status_t Invalidate(const BRect& frame);
virtual status_t CopyBackToFront(const BRect& frame);
// drawing engine interface
StreamingRingBuffer* ReceiveBuffer() { return fReceiveBuffer; }
StreamingRingBuffer* SendBuffer() { return fSendBuffer; }
status_t AddCallback(uint32 token,
CallbackFunction callback,
void* cookie);
bool RemoveCallback(uint32 token);
private:
callback_info* _FindCallback(uint32 token);
static int _CallbackCompare(const uint32* key,
const callback_info* info);
static int32 _EventThreadEntry(void* data);
status_t _EventThread();
status_t _Connect();
void _Disconnect();
const char* fTarget;
char* fRemoteHost;
uint32 fRemotePort;
status_t fInitStatus;
bool fIsConnected;
uint32 fProtocolVersion;
uint32 fConnectionSpeed;
display_mode fDisplayMode;
uint16 fListenPort;
BNetEndpoint* fSendEndpoint;
BNetEndpoint* fReceiveEndpoint;
StreamingRingBuffer* fSendBuffer;
StreamingRingBuffer* fReceiveBuffer;
NetSender* fSender;
NetReceiver* fReceiver;
thread_id fEventThread;
RemoteEventStream* fEventStream;
BLocker fCallbackLocker;
BObjectList<callback_info> fCallbacks;
};
#endif // REMOTE_HW_INTERFACE_H
@@ -0,0 +1,501 @@
/*
* Copyright 2009, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#include "RemoteMessage.h"
#ifndef CLIENT_COMPILE
#include "DrawState.h"
#include "ServerBitmap.h"
#include "ServerCursor.h"
#endif
#include <Bitmap.h>
#include <Font.h>
#include <View.h>
#include <Gradient.h>
#include <GradientLinear.h>
#include <GradientRadial.h>
#include <GradientRadialFocus.h>
#include <GradientDiamond.h>
#include <GradientConic.h>
#include <new>
status_t
RemoteMessage::NextMessage(uint16& code)
{
if (fDataLeft > 0) {
// discard remainder of message
int32 readSize = fSource->Read(NULL, fDataLeft);
if (readSize < 0)
return readSize;
}
static const uint32 kHeaderSize = sizeof(uint16) + sizeof(uint32);
fDataLeft = kHeaderSize;
Read(code);
uint32 dataLeft;
status_t result = Read(dataLeft);
if (result != B_OK)
return result;
if (dataLeft < kHeaderSize)
return B_ERROR;
fDataLeft = dataLeft - kHeaderSize;
fCode = code;
return B_OK;
}
#ifndef CLIENT_COMPILE
void
RemoteMessage::AddBitmap(const ServerBitmap& bitmap)
{
Add(bitmap.Width());
Add(bitmap.Height());
Add(bitmap.BytesPerRow());
Add(bitmap.ColorSpace());
Add(bitmap.Flags());
uint32 bitsLength = bitmap.BitsLength();
Add(bitsLength);
if (!_MakeSpace(bitsLength))
return;
memcpy(fBuffer + fWriteIndex, bitmap.Bits(), bitsLength);
fWriteIndex += bitsLength;
fAvailable -= bitsLength;
}
void
RemoteMessage::AddFont(const ServerFont& font)
{
Add(font.Direction());
Add((uint8)font.Encoding());
Add(font.Flags());
Add((uint8)font.Spacing());
Add(font.Shear());
Add(font.Rotation());
Add(font.FalseBoldWidth());
Add(font.Size());
Add(font.Face());
Add(font.GetFamilyAndStyle());
}
void
RemoteMessage::AddDrawState(const DrawState& drawState)
{
Add(drawState.PenSize());
Add(drawState.SubPixelPrecise());
Add(drawState.GetDrawingMode());
Add(drawState.AlphaSrcMode());
Add(drawState.AlphaFncMode());
AddPattern(drawState.GetPattern());
Add(drawState.LineCapMode());
Add(drawState.LineJoinMode());
Add(drawState.MiterLimit());
Add(drawState.HighColor());
Add(drawState.LowColor());
}
void
RemoteMessage::AddArrayLine(const ViewLineArrayInfo& line)
{
Add(line.startPoint);
Add(line.endPoint);
Add(line.color);
}
void
RemoteMessage::AddCursor(const ServerCursor& cursor)
{
Add(cursor.GetHotSpot());
AddBitmap(cursor);
}
void
RemoteMessage::AddPattern(const Pattern& pattern)
{
Add(pattern.GetPattern());
}
#else // !CLIENT_COMPILE
void
RemoteMessage::AddBitmap(const BBitmap& bitmap)
{
BRect bounds = bitmap.Bounds();
Add(bounds.IntegerWidth() + 1);
Add(bounds.IntegerHeight() + 1);
Add(bitmap.BytesPerRow());
Add(bitmap.ColorSpace());
Add(bitmap.Flags());
uint32 bitsLength = bitmap.BitsLength();
Add(bitsLength);
if (!_MakeSpace(bitsLength))
return;
memcpy(fBuffer + fWriteIndex, bitmap.Bits(), bitsLength);
fWriteIndex += bitsLength;
fAvailable -= bitsLength;
}
#endif // !CLIENT_COMPILE
void
RemoteMessage::AddGradient(const BGradient& gradient)
{
Add(gradient.GetType());
switch (gradient.GetType()) {
case BGradient::TYPE_NONE:
break;
case BGradient::TYPE_LINEAR:
{
const BGradientLinear* linear
= dynamic_cast<const BGradientLinear *>(&gradient);
if (linear == NULL)
return;
Add(linear->Start());
Add(linear->End());
break;
}
case BGradient::TYPE_RADIAL:
{
const BGradientRadial* radial
= dynamic_cast<const BGradientRadial *>(&gradient);
if (radial == NULL)
return;
Add(radial->Center());
Add(radial->Radius());
break;
}
case BGradient::TYPE_RADIAL_FOCUS:
{
const BGradientRadialFocus* radialFocus
= dynamic_cast<const BGradientRadialFocus *>(&gradient);
if (radialFocus == NULL)
return;
Add(radialFocus->Center());
Add(radialFocus->Focal());
Add(radialFocus->Radius());
break;
}
case BGradient::TYPE_DIAMOND:
{
const BGradientDiamond* diamond
= dynamic_cast<const BGradientDiamond *>(&gradient);
if (diamond == NULL)
return;
Add(diamond->Center());
break;
}
case BGradient::TYPE_CONIC:
{
const BGradientConic* conic
= dynamic_cast<const BGradientConic *>(&gradient);
if (conic == NULL)
return;
Add(conic->Center());
Add(conic->Angle());
break;
}
}
int32 stopCount = gradient.CountColorStops();
Add(stopCount);
for (int32 i = 0; i < stopCount; i++) {
BGradient::ColorStop* stop = gradient.ColorStopAt(i);
if (stop == NULL)
return;
Add(stop->color);
Add(stop->offset);
}
}
status_t
RemoteMessage::ReadString(char** _string, size_t& _length)
{
uint32 length;
status_t result = Read(length);
if (result != B_OK)
return result;
if (length > fDataLeft)
return B_ERROR;
char *string = (char *)malloc(length + 1);
if (string == NULL)
return B_NO_MEMORY;
int32 readSize = fSource->Read(string, length);
if (readSize < 0)
return readSize;
if ((uint32)readSize != length)
return B_ERROR;
fDataLeft -= readSize;
string[length] = 0;
*_string = string;
_length = length;
return B_OK;
}
status_t
RemoteMessage::ReadBitmap(BBitmap** _bitmap)
{
color_space colorSpace;
uint32 bitsLength, flags;
int32 width, height, bytesPerRow;
Read(width);
Read(height);
Read(bytesPerRow);
Read(colorSpace);
Read(flags);
Read(bitsLength);
if (bitsLength > fDataLeft)
return B_ERROR;
#ifndef CLIENT_COMPILE
flags = B_BITMAP_NO_SERVER_LINK;
#endif
BBitmap *bitmap = new(std::nothrow) BBitmap(
BRect(0, 0, width - 1, height - 1), flags, colorSpace, bytesPerRow);
if (bitmap == NULL)
return B_NO_MEMORY;
status_t result = bitmap->InitCheck();
if (result != B_OK) {
delete bitmap;
return result;
}
if (bitmap->BitsLength() < (int32)bitsLength) {
delete bitmap;
return B_ERROR;
}
int32 readSize = fSource->Read(bitmap->Bits(), bitsLength);
if ((uint32)readSize != bitsLength) {
delete bitmap;
return readSize < 0 ? readSize : B_ERROR;
}
fDataLeft -= readSize;
*_bitmap = bitmap;
return B_OK;
}
status_t
RemoteMessage::ReadFontState(BFont& font)
{
uint8 encoding, spacing;
uint16 face;
uint32 flags, familyAndStyle;
font_direction direction;
float falseBoldWidth, rotation, shear, size;
Read(direction);
Read(encoding);
Read(flags);
Read(spacing);
Read(shear);
Read(rotation);
Read(falseBoldWidth);
Read(size);
Read(face);
status_t result = Read(familyAndStyle);
if (result != B_OK)
return result;
font.SetFamilyAndStyle(familyAndStyle);
font.SetEncoding(encoding);
font.SetFlags(flags);
font.SetSpacing(spacing);
font.SetShear(shear);
font.SetRotation(rotation);
font.SetFalseBoldWidth(falseBoldWidth);
font.SetSize(size);
font.SetFace(face);
return B_OK;
}
status_t
RemoteMessage::ReadViewState(BView& view, ::pattern& pattern)
{
bool subPixelPrecise;
float penSize, miterLimit;
drawing_mode drawingMode;
source_alpha sourceAlpha;
alpha_function alphaFunction;
cap_mode capMode;
join_mode joinMode;
rgb_color highColor, lowColor;
Read(penSize);
Read(subPixelPrecise);
Read(drawingMode);
Read(sourceAlpha);
Read(alphaFunction);
Read(pattern);
Read(capMode);
Read(joinMode);
Read(miterLimit);
Read(highColor);
status_t result = Read(lowColor);
if (result != B_OK)
return result;
uint32 flags = view.Flags() & ~B_SUBPIXEL_PRECISE;
view.SetFlags(flags | (subPixelPrecise ? B_SUBPIXEL_PRECISE : 0));
view.SetPenSize(penSize);
view.SetDrawingMode(drawingMode);
view.SetBlendingMode(sourceAlpha, alphaFunction);
view.SetLineMode(capMode, joinMode, miterLimit);
view.SetHighColor(highColor);
view.SetLowColor(lowColor);
return B_OK;
}
status_t
RemoteMessage::ReadGradient(BGradient** _gradient)
{
BGradient::Type type;
Read(type);
BGradient *gradient = NULL;
switch (type) {
case BGradient::TYPE_NONE:
break;
case BGradient::TYPE_LINEAR:
{
BPoint start, end;
Read(start);
Read(end);
gradient = new(std::nothrow) BGradientLinear(start, end);
break;
}
case BGradient::TYPE_RADIAL:
{
BPoint center;
float radius;
Read(center);
Read(radius);
gradient = new(std::nothrow) BGradientRadial(center, radius);
break;
}
case BGradient::TYPE_RADIAL_FOCUS:
{
BPoint center, focal;
float radius;
Read(center);
Read(focal);
Read(radius);
gradient = new(std::nothrow) BGradientRadialFocus(center, radius,
focal);
break;
}
case BGradient::TYPE_DIAMOND:
{
BPoint center;
Read(center);
gradient = new(std::nothrow) BGradientDiamond(center);
break;
}
case BGradient::TYPE_CONIC:
{
BPoint center;
float angle;
Read(center);
Read(angle);
gradient = new(std::nothrow) BGradientConic(center, angle);
break;
}
}
if (gradient == NULL)
return B_NO_MEMORY;
int32 stopCount;
status_t result = Read(stopCount);
if (result != B_OK)
return result;
for (int32 i = 0; i < stopCount; i++) {
rgb_color color;
float offset;
Read(color);
result = Read(offset);
if (result != B_OK)
return result;
gradient->AddColor(color, offset);
}
*_gradient = gradient;
return B_OK;
}
status_t
RemoteMessage::ReadArrayLine(BPoint& startPoint, BPoint& endPoint,
rgb_color& color)
{
Read(startPoint);
Read(endPoint);
return Read(color);
}
@@ -0,0 +1,359 @@
/*
* Copyright 2009, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#ifndef REMOTE_MESSAGE_H
#define REMOTE_MESSAGE_H
#ifndef CLIENT_COMPILE
# include "PatternHandler.h"
# include <ViewPrivate.h>
#endif
#include "StreamingRingBuffer.h"
#include <GraphicsDefs.h>
#include <Region.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
class BBitmap;
class BFont;
class BGradient;
class BView;
class DrawState;
class Pattern;
class RemotePainter;
class ServerBitmap;
class ServerCursor;
class ServerFont;
class ViewLineArrayInfo;
enum {
RP_INIT_CONNECTION = 1,
RP_UPDATE_DISPLAY_MODE,
RP_CLOSE_CONNECTION,
RP_CREATE_STATE = 20,
RP_DELETE_STATE,
RP_ENABLE_SYNC_DRAWING,
RP_DISABLE_SYNC_DRAWING,
RP_INVALIDATE_RECT,
RP_INVALIDATE_REGION,
RP_SET_OFFSETS = 40,
RP_SET_HIGH_COLOR,
RP_SET_LOW_COLOR,
RP_SET_PEN_SIZE,
RP_SET_STROKE_MODE,
RP_SET_BLENDING_MODE,
RP_SET_PATTERN,
RP_SET_DRAWING_MODE,
RP_SET_FONT,
RP_CONSTRAIN_CLIPPING_REGION = 60,
RP_COPY_RECT_NO_CLIPPING,
RP_INVERT_RECT,
RP_DRAW_BITMAP,
RP_STROKE_ARC = 80,
RP_STROKE_BEZIER,
RP_STROKE_ELLIPSE,
RP_STROKE_POLYGON,
RP_STROKE_RECT,
RP_STROKE_ROUND_RECT,
RP_STROKE_SHAPE,
RP_STROKE_TRIANGLE,
RP_STROKE_LINE,
RP_STROKE_LINE_ARRAY,
RP_FILL_ARC = 100,
RP_FILL_BEZIER,
RP_FILL_ELLIPSE,
RP_FILL_POLYGON,
RP_FILL_RECT,
RP_FILL_ROUND_RECT,
RP_FILL_SHAPE,
RP_FILL_TRIANGLE,
RP_FILL_REGION,
RP_FILL_ARC_GRADIENT = 120,
RP_FILL_BEZIER_GRADIENT,
RP_FILL_ELLIPSE_GRADIENT,
RP_FILL_POLYGON_GRADIENT,
RP_FILL_RECT_GRADIENT,
RP_FILL_ROUND_RECT_GRADIENT,
RP_FILL_SHAPE_GRADIENT,
RP_FILL_TRIANGLE_GRADIENT,
RP_FILL_REGION_GRADIENT,
RP_STROKE_POINT_COLOR = 140,
RP_STROKE_LINE_1PX_COLOR,
RP_STROKE_RECT_1PX_COLOR,
RP_FILL_RECT_COLOR = 160,
RP_FILL_REGION_COLOR_NO_CLIPPING,
RP_DRAW_STRING = 180,
RP_DRAW_STRING_RESULT,
RP_STRING_WIDTH,
RP_STRING_WIDTH_RESULT,
RP_READ_BITMAP,
RP_READ_BITMAP_RESULT,
RP_SET_CURSOR = 200,
RP_SET_CURSOR_VISIBLE,
RP_MOVE_CURSOR_TO,
RP_MOUSE_MOVED = 220,
RP_MOUSE_DOWN,
RP_MOUSE_UP,
RP_MOUSE_WHEEL_CHANGED,
RP_KEY_DOWN = 240,
RP_KEY_UP,
RP_UNMAPPED_KEY_DOWN,
RP_UNMAPPED_KEY_UP,
RP_MODIFIERS_CHANGED
};
class RemoteMessage {
public:
RemoteMessage(StreamingRingBuffer* source,
StreamingRingBuffer *target);
~RemoteMessage();
void Start(uint16 code);
status_t Flush();
status_t NextMessage(uint16& code);
uint16 Code() { return fCode; }
uint32 DataLeft() { return fDataLeft; }
template<typename T>
void Add(const T& value);
void AddString(const char* string, size_t length);
void AddRegion(const BRegion& region);
void AddGradient(const BGradient& gradient);
#ifndef CLIENT_COMPILE
void AddBitmap(const ServerBitmap& bitmap);
void AddFont(const ServerFont& font);
void AddPattern(const Pattern& pattern);
void AddDrawState(const DrawState& drawState);
void AddArrayLine(const ViewLineArrayInfo& line);
void AddCursor(const ServerCursor& cursor);
#else
void AddBitmap(const BBitmap& bitmap);
#endif
template<typename T>
void AddList(const T* array, int32 count);
template<typename T>
status_t Read(T& value);
status_t ReadRegion(BRegion& region);
status_t ReadFontState(BFont& font);
// sets font state
status_t ReadViewState(BView& view, ::pattern& pattern);
// sets viewstate and returns pattern
status_t ReadString(char** _string, size_t& length);
status_t ReadBitmap(BBitmap** _bitmap);
status_t ReadGradient(BGradient** _gradient);
status_t ReadArrayLine(BPoint& startPoint,
BPoint& endPoint, rgb_color& color);
template<typename T>
status_t ReadList(T* array, int32 count);
private:
bool _MakeSpace(size_t size);
StreamingRingBuffer* fSource;
StreamingRingBuffer* fTarget;
uint8* fBuffer;
size_t fAvailable;
size_t fWriteIndex;
uint32 fDataLeft;
uint16 fCode;
};
inline
RemoteMessage::RemoteMessage(StreamingRingBuffer* source,
StreamingRingBuffer* target)
:
fSource(source),
fTarget(target),
fBuffer(NULL),
fAvailable(0),
fWriteIndex(0),
fDataLeft(0)
{
}
inline
RemoteMessage::~RemoteMessage()
{
if (fWriteIndex > 0)
Flush();
free(fBuffer);
}
inline void
RemoteMessage::Start(uint16 code)
{
if (fWriteIndex > 0)
Flush();
Add(code);
uint32 sizeDummy;
Add(sizeDummy);
}
inline status_t
RemoteMessage::Flush()
{
if (fWriteIndex == 0)
return B_NO_INIT;
uint32 length = fWriteIndex;
fAvailable += fWriteIndex;
fWriteIndex = 0;
memcpy(fBuffer + sizeof(uint16), &length, sizeof(uint32));
return fTarget->Write(fBuffer, length);
}
template<typename T>
inline void
RemoteMessage::Add(const T& value)
{
if (!_MakeSpace(sizeof(T)))
return;
memcpy(fBuffer + fWriteIndex, &value, sizeof(T));
fWriteIndex += sizeof(T);
fAvailable -= sizeof(T);
}
inline void
RemoteMessage::AddString(const char* string, size_t length)
{
Add(length);
if (length > fAvailable && !_MakeSpace(length))
return;
memcpy(fBuffer + fWriteIndex, string, length);
fWriteIndex += length;
fAvailable -= length;
}
inline void
RemoteMessage::AddRegion(const BRegion& region)
{
int32 rectCount = region.CountRects();
Add(rectCount);
for (int32 i = 0; i < rectCount; i++)
Add(region.RectAt(i));
}
template<typename T>
inline void
RemoteMessage::AddList(const T* array, int32 count)
{
for (int32 i = 0; i < count; i++)
Add(array[i]);
}
template<typename T>
inline status_t
RemoteMessage::Read(T& value)
{
if (fDataLeft < sizeof(T))
return B_ERROR;
int32 readSize = fSource->Read(&value, sizeof(T));
if (readSize < 0)
return readSize;
if (readSize != sizeof(T))
return B_ERROR;
fDataLeft -= sizeof(T);
return B_OK;
}
inline status_t
RemoteMessage::ReadRegion(BRegion& region)
{
region.MakeEmpty();
int32 rectCount;
Read(rectCount);
for (int32 i = 0; i < rectCount; i++) {
BRect rect;
status_t result = Read(rect);
if (result != B_OK)
return result;
region.Include(rect);
}
return B_OK;
}
template<typename T>
inline status_t
RemoteMessage::ReadList(T* array, int32 count)
{
for (int32 i = 0; i < count; i++) {
status_t result = Read(array[i]);
if (result != B_OK)
return result;
}
return B_OK;
}
inline bool
RemoteMessage::_MakeSpace(size_t size)
{
if (fAvailable >= size)
return true;
size_t extraSize = size + 20;
uint8 *newBuffer = (uint8*)realloc(fBuffer, fWriteIndex + extraSize);
if (newBuffer == NULL)
return false;
fAvailable = extraSize;
fBuffer = newBuffer;
return true;
}
#endif // REMOTE_MESSAGE_H
@@ -0,0 +1,176 @@
/*
* Copyright 2009, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#include "StreamingRingBuffer.h"
#include <Autolock.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRACE(x...) /*debug_printf("StreamingRingBuffer: "x)*/
#define TRACE_ERROR(x...) debug_printf("StreamingRingBuffer: "x)
StreamingRingBuffer::StreamingRingBuffer(size_t bufferSize)
:
fReaderWaiting(false),
fWriterWaiting(false),
fReaderNotifier(-1),
fWriterNotifier(-1),
fReaderLocker("StreamingRingBuffer reader"),
fWriterLocker("StreamingRingBuffer writer"),
fDataLocker("StreamingRingBuffer data"),
fBuffer(NULL),
fBufferSize(bufferSize),
fReadable(0),
fReadPosition(0),
fWritePosition(0)
{
fReaderNotifier = create_sem(0, "StreamingRingBuffer read notify");
fWriterNotifier = create_sem(0, "StreamingRingBuffer write notify");
fBuffer = (uint8 *)malloc(fBufferSize);
if (fBuffer == NULL)
fBufferSize = 0;
}
StreamingRingBuffer::~StreamingRingBuffer()
{
delete_sem(fReaderNotifier);
delete_sem(fWriterNotifier);
free(fBuffer);
}
status_t
StreamingRingBuffer::InitCheck()
{
if (fReaderNotifier < 0)
return fReaderNotifier;
if (fWriterNotifier < 0)
return fWriterNotifier;
if (fBuffer == NULL)
return B_NO_MEMORY;
return B_OK;
}
int32
StreamingRingBuffer::Read(void *buffer, size_t length, bool onlyBlockOnNoData)
{
BAutolock readerLock(fReaderLocker);
if (!readerLock.IsLocked())
return B_ERROR;
BAutolock dataLock(fDataLocker);
if (!dataLock.IsLocked())
return B_ERROR;
int32 readSize = 0;
while (length > 0) {
size_t copyLength = min_c(length, fBufferSize - fReadPosition);
copyLength = min_c(copyLength, fReadable);
if (copyLength == 0) {
if (onlyBlockOnNoData && readSize > 0)
return readSize;
fReaderWaiting = true;
dataLock.Unlock();
status_t result;
do {
TRACE("waiting in reader\n");
result = acquire_sem(fReaderNotifier);
TRACE("done waiting in reader with status: 0x%08lx\n", result);
} while (result == B_INTERRUPTED);
if (result != B_OK)
return result;
if (!dataLock.Lock())
return B_ERROR;
continue;
}
// support discarding input
if (buffer != NULL) {
memcpy(buffer, fBuffer + fReadPosition, copyLength);
buffer = (uint8 *)buffer + copyLength;
}
fReadPosition = (fReadPosition + copyLength) % fBufferSize;
fReadable -= copyLength;
readSize += copyLength;
length -= copyLength;
if (fWriterWaiting) {
release_sem_etc(fWriterNotifier, 1, B_DO_NOT_RESCHEDULE);
fWriterWaiting = false;
}
}
return readSize;
}
status_t
StreamingRingBuffer::Write(const void *buffer, size_t length)
{
BAutolock writerLock(fWriterLocker);
if (!writerLock.IsLocked())
return B_ERROR;
BAutolock dataLock(fDataLocker);
if (!dataLock.IsLocked())
return B_ERROR;
while (length > 0) {
size_t copyLength = min_c(length, fBufferSize - fWritePosition);
copyLength = min_c(copyLength, fBufferSize - fReadable);
if (copyLength == 0) {
fWriterWaiting = true;
dataLock.Unlock();
status_t result;
do {
TRACE("waiting in writer\n");
result = acquire_sem(fWriterNotifier);
TRACE("done waiting in writer with status: 0x%08lx\n", result);
} while (result == B_INTERRUPTED);
if (result != B_OK)
return result;
if (!dataLock.Lock())
return B_ERROR;
continue;
}
memcpy(fBuffer + fWritePosition, buffer, copyLength);
fWritePosition = (fWritePosition + copyLength) % fBufferSize;
fReadable += copyLength;
buffer = (uint8 *)buffer + copyLength;
length -= copyLength;
if (fReaderWaiting) {
release_sem_etc(fReaderNotifier, 1, B_DO_NOT_RESCHEDULE);
fReaderWaiting = false;
}
}
return B_OK;
}
@@ -0,0 +1,47 @@
/*
* Copyright 2009, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
*/
#ifndef STREAMING_RING_BUFFER_H
#define STREAMING_RING_BUFFER_H
#include <OS.h>
#include <SupportDefs.h>
#include <Locker.h>
class StreamingRingBuffer {
public:
StreamingRingBuffer(size_t bufferSize);
~StreamingRingBuffer();
status_t InitCheck();
// blocking read and write
int32 Read(void *buffer, size_t length,
bool onlyBlockOnNoData = false);
status_t Write(const void *buffer, size_t length);
private:
bool _Lock();
void _Unlock();
bool fReaderWaiting;
bool fWriterWaiting;
sem_id fReaderNotifier;
sem_id fWriterNotifier;
BLocker fReaderLocker;
BLocker fWriterLocker;
BLocker fDataLocker;
uint8 * fBuffer;
size_t fBufferSize;
size_t fReadable;
int32 fReadPosition;
int32 fWritePosition;
};
#endif // STREAMING_RING_BUFFER_H