diff --git a/src/kits/app/Application.cpp b/src/kits/app/Application.cpp index 3ef471b054..341645cfc6 100644 --- a/src/kits/app/Application.cpp +++ b/src/kits/app/Application.cpp @@ -1272,6 +1272,7 @@ BApplication::_ConnectToServer() fServerLink->StartMessage(AS_GET_DESKTOP); fServerLink->Attach(clientPort); fServerLink->Attach(getuid()); + fServerLink->AttachString(getenv("TARGET_SCREEN")); int32 code; if (fServerLink->FlushWithReply(code) != B_OK || code != B_OK) { diff --git a/src/servers/app/AppServer.cpp b/src/servers/app/AppServer.cpp index bce30f4be9..612d6450a5 100644 --- a/src/servers/app/AppServer.cpp +++ b/src/servers/app/AppServer.cpp @@ -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(&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); diff --git a/src/servers/app/AppServer.h b/src/servers/app/AppServer.h index 8f33e2b1d7..cffa5b3fd4 100644 --- a/src/servers/app/AppServer.h +++ b/src/servers/app/AppServer.h @@ -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(); diff --git a/src/servers/app/Desktop.cpp b/src/servers/app/Desktop.cpp index f533c93781..c1e8a158b8 100644 --- a/src/servers/app/Desktop.cpp +++ b/src/servers/app/Desktop.cpp @@ -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); } diff --git a/src/servers/app/Desktop.h b/src/servers/app/Desktop.h index eea2414696..d98fbd7bac 100644 --- a/src/servers/app/Desktop.h +++ b/src/servers/app/Desktop.h @@ -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; diff --git a/src/servers/app/Jamfile b/src/servers/app/Jamfile index 8393b0f402..00e0d60224 100644 --- a/src/servers/app/Jamfile +++ b/src/servers/app/Jamfile @@ -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 diff --git a/src/servers/app/Screen.cpp b/src/servers/app/Screen.cpp index f1ab5b54de..6b3b081129 100644 --- a/src/servers/app/Screen.cpp +++ b/src/servers/app/Screen.cpp @@ -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) { } diff --git a/src/servers/app/ScreenManager.cpp b/src/servers/app/ScreenManager.cpp index c117358562..844a4e5fd0 100644 --- a/src/servers/app/ScreenManager.cpp +++ b/src/servers/app/ScreenManager.cpp @@ -14,6 +14,8 @@ #include "Screen.h" #include "ServerConfig.h" +#include "remote/RemoteHWInterface.h" + #include #include #include @@ -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; } diff --git a/src/servers/app/ScreenManager.h b/src/servers/app/ScreenManager.h index 7951f03216..2c81dd1e1f 100644 --- a/src/servers/app/ScreenManager.h +++ b/src/servers/app/ScreenManager.h @@ -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 fScreenList; }; diff --git a/src/servers/app/ServerFont.cpp b/src/servers/app/ServerFont.cpp index 0a1500f562..5eecba71ee 100644 --- a/src/servers/app/ServerFont.cpp +++ b/src/servers/app/ServerFont.cpp @@ -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 diff --git a/src/servers/app/ServerFont.h b/src/servers/app/ServerFont.h index 68691f7297..f162304c6e 100644 --- a/src/servers/app/ServerFont.h +++ b/src/servers/app/ServerFont.h @@ -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; } diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index dc8a2f5500..d10790b1ee 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -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; diff --git a/src/servers/app/VirtualScreen.cpp b/src/servers/app/VirtualScreen.cpp index 91a9c103cf..eb12a1abf0 100644 --- a/src/servers/app/VirtualScreen.cpp +++ b/src/servers/app/VirtualScreen.cpp @@ -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; } diff --git a/src/servers/app/drawing/DrawingEngine.cpp b/src/servers/app/drawing/DrawingEngine.cpp index 624b1ceae3..92fc01ae0c 100644 --- a/src/servers/app/drawing/DrawingEngine.cpp +++ b/src/servers/app/drawing/DrawingEngine.cpp @@ -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; diff --git a/src/servers/app/drawing/DrawingEngine.h b/src/servers/app/drawing/DrawingEngine.h index e97c4c8794..8ab968693e 100644 --- a/src/servers/app/drawing/DrawingEngine.h +++ b/src/servers/app/drawing/DrawingEngine.h @@ -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_ diff --git a/src/servers/app/drawing/HWInterface.cpp b/src/servers/app/drawing/HWInterface.cpp index 4e40cbe815..fe23d4f466 100644 --- a/src/servers/app/drawing/HWInterface.cpp +++ b/src/servers/app/drawing/HWInterface.cpp @@ -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 diff --git a/src/servers/app/drawing/HWInterface.h b/src/servers/app/drawing/HWInterface.h index 9e13b921f5..cef1207483 100644 --- a/src/servers/app/drawing/HWInterface.h +++ b/src/servers/app/drawing/HWInterface.h @@ -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 diff --git a/src/servers/app/drawing/Jamfile b/src/servers/app/drawing/Jamfile index c34276d202..52fe15dc34 100644 --- a/src/servers/app/drawing/Jamfile +++ b/src/servers/app/drawing/Jamfile @@ -28,3 +28,4 @@ StaticLibrary libasdrawing.a : ; SubInclude HAIKU_TOP src servers app drawing Painter ; +SubInclude HAIKU_TOP src servers app drawing remote ; diff --git a/src/servers/app/drawing/remote/Jamfile b/src/servers/app/drawing/remote/Jamfile new file mode 100644 index 0000000000..d55a61f523 --- /dev/null +++ b/src/servers/app/drawing/remote/Jamfile @@ -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 +; diff --git a/src/servers/app/drawing/remote/NetReceiver.cpp b/src/servers/app/drawing/remote/NetReceiver.cpp new file mode 100644 index 0000000000..e342066bc9 --- /dev/null +++ b/src/servers/app/drawing/remote/NetReceiver.cpp @@ -0,0 +1,110 @@ +/* + * Copyright 2009, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ + +#include "NetReceiver.h" + +#include "StreamingRingBuffer.h" + +#include + +#include +#include +#include + +#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; +} diff --git a/src/servers/app/drawing/remote/NetReceiver.h b/src/servers/app/drawing/remote/NetReceiver.h new file mode 100644 index 0000000000..21799a0791 --- /dev/null +++ b/src/servers/app/drawing/remote/NetReceiver.h @@ -0,0 +1,38 @@ +/* + * Copyright 2009, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ +#ifndef NET_RECEIVER_H +#define NET_RECEIVER_H + +#include +#include + +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 diff --git a/src/servers/app/drawing/remote/NetSender.cpp b/src/servers/app/drawing/remote/NetSender.cpp new file mode 100644 index 0000000000..0d7cca0d53 --- /dev/null +++ b/src/servers/app/drawing/remote/NetSender.cpp @@ -0,0 +1,75 @@ +/* + * Copyright 2009, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ + +#include "NetSender.h" + +#include "StreamingRingBuffer.h" + +#include + +#include +#include +#include + +#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; +} diff --git a/src/servers/app/drawing/remote/NetSender.h b/src/servers/app/drawing/remote/NetSender.h new file mode 100644 index 0000000000..dbc415ee3e --- /dev/null +++ b/src/servers/app/drawing/remote/NetSender.h @@ -0,0 +1,34 @@ +/* + * Copyright 2009, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ +#ifndef NET_SENDER_H +#define NET_SENDER_H + +#include +#include + +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 diff --git a/src/servers/app/drawing/remote/RemoteDrawingEngine.cpp b/src/servers/app/drawing/remote/RemoteDrawingEngine.cpp new file mode 100644 index 0000000000..75028029b0 --- /dev/null +++ b/src/servers/app/drawing/remote/RemoteDrawingEngine.cpp @@ -0,0 +1,939 @@ +/* + * Copyright 2009, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ + +#include "RemoteDrawingEngine.h" +#include "RemoteMessage.h" + +#include "DrawState.h" + +#include + +#include + + +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; +} diff --git a/src/servers/app/drawing/remote/RemoteDrawingEngine.h b/src/servers/app/drawing/remote/RemoteDrawingEngine.h new file mode 100644 index 0000000000..1d25bf9d5e --- /dev/null +++ b/src/servers/app/drawing/remote/RemoteDrawingEngine.h @@ -0,0 +1,165 @@ +/* + * Copyright 2009, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ +#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 diff --git a/src/servers/app/drawing/remote/RemoteEventStream.cpp b/src/servers/app/drawing/remote/RemoteEventStream.cpp new file mode 100644 index 0000000000..eb681044af --- /dev/null +++ b/src/servers/app/drawing/remote/RemoteEventStream.cpp @@ -0,0 +1,215 @@ +/* + * Copyright 2009, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ + +#include "RemoteEventStream.h" + +#include "RemoteMessage.h" +#include "StreamingRingBuffer.h" + +#include + +#include + + +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; +} diff --git a/src/servers/app/drawing/remote/RemoteEventStream.h b/src/servers/app/drawing/remote/RemoteEventStream.h new file mode 100644 index 0000000000..95366b89d7 --- /dev/null +++ b/src/servers/app/drawing/remote/RemoteEventStream.h @@ -0,0 +1,45 @@ +/* + * Copyright 2009, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ +#ifndef REMOTE_EVENT_STREAM_H +#define REMOTE_EVENT_STREAM_H + +#include "EventStream.h" + +#include +#include + +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 fEventList; + BLocker fEventListLocker; + sem_id fEventNotification; + bool fWaitingOnEvent; + BMessage* fLatestMouseMovedEvent; + + BPoint fMousePosition; + uint32 fMouseButtons; + uint32 fModifiers; +}; + +#endif // REMOTE_EVENT_STREAM_H diff --git a/src/servers/app/drawing/remote/RemoteHWInterface.cpp b/src/servers/app/drawing/remote/RemoteHWInterface.cpp new file mode 100644 index 0000000000..18fe8327f0 --- /dev/null +++ b/src/servers/app/drawing/remote/RemoteHWInterface.cpp @@ -0,0 +1,572 @@ +/* + * Copyright 2009, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ + +#include "RemoteHWInterface.h" +#include "RemoteDrawingEngine.h" +#include "RemoteEventStream.h" +#include "RemoteMessage.h" + +#include "NetReceiver.h" +#include "NetSender.h" +#include "StreamingRingBuffer.h" + +#include +#include + +#include +#include + + +#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; +} diff --git a/src/servers/app/drawing/remote/RemoteHWInterface.h b/src/servers/app/drawing/remote/RemoteHWInterface.h new file mode 100644 index 0000000000..c196ecbc1f --- /dev/null +++ b/src/servers/app/drawing/remote/RemoteHWInterface.h @@ -0,0 +1,127 @@ +/* + * Copyright 2009, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ +#ifndef REMOTE_HW_INTERFACE_H +#define REMOTE_HW_INTERFACE_H + +#include "HWInterface.h" + +#include +#include + +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 fCallbacks; +}; + +#endif // REMOTE_HW_INTERFACE_H diff --git a/src/servers/app/drawing/remote/RemoteMessage.cpp b/src/servers/app/drawing/remote/RemoteMessage.cpp new file mode 100644 index 0000000000..1c8db0cedc --- /dev/null +++ b/src/servers/app/drawing/remote/RemoteMessage.cpp @@ -0,0 +1,501 @@ +/* + * Copyright 2009, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ + +#include "RemoteMessage.h" + +#ifndef CLIENT_COMPILE +#include "DrawState.h" +#include "ServerBitmap.h" +#include "ServerCursor.h" +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + + +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(&gradient); + if (linear == NULL) + return; + + Add(linear->Start()); + Add(linear->End()); + break; + } + + case BGradient::TYPE_RADIAL: + { + const BGradientRadial* radial + = dynamic_cast(&gradient); + if (radial == NULL) + return; + + Add(radial->Center()); + Add(radial->Radius()); + break; + } + + case BGradient::TYPE_RADIAL_FOCUS: + { + const BGradientRadialFocus* radialFocus + = dynamic_cast(&gradient); + if (radialFocus == NULL) + return; + + Add(radialFocus->Center()); + Add(radialFocus->Focal()); + Add(radialFocus->Radius()); + break; + } + + case BGradient::TYPE_DIAMOND: + { + const BGradientDiamond* diamond + = dynamic_cast(&gradient); + if (diamond == NULL) + return; + + Add(diamond->Center()); + break; + } + + case BGradient::TYPE_CONIC: + { + const BGradientConic* conic + = dynamic_cast(&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); +} diff --git a/src/servers/app/drawing/remote/RemoteMessage.h b/src/servers/app/drawing/remote/RemoteMessage.h new file mode 100644 index 0000000000..8cd97fbe35 --- /dev/null +++ b/src/servers/app/drawing/remote/RemoteMessage.h @@ -0,0 +1,359 @@ +/* + * Copyright 2009, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ +#ifndef REMOTE_MESSAGE_H +#define REMOTE_MESSAGE_H + +#ifndef CLIENT_COMPILE +# include "PatternHandler.h" +# include +#endif + +#include "StreamingRingBuffer.h" + +#include +#include + +#include +#include +#include + +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 + 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 + void AddList(const T* array, int32 count); + + template + 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 + 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 +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 +inline void +RemoteMessage::AddList(const T* array, int32 count) +{ + for (int32 i = 0; i < count; i++) + Add(array[i]); +} + + +template +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 +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 diff --git a/src/servers/app/drawing/remote/StreamingRingBuffer.cpp b/src/servers/app/drawing/remote/StreamingRingBuffer.cpp new file mode 100644 index 0000000000..601bc2293e --- /dev/null +++ b/src/servers/app/drawing/remote/StreamingRingBuffer.cpp @@ -0,0 +1,176 @@ +/* + * Copyright 2009, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ + +#include "StreamingRingBuffer.h" + +#include + +#include +#include +#include + +#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; +} diff --git a/src/servers/app/drawing/remote/StreamingRingBuffer.h b/src/servers/app/drawing/remote/StreamingRingBuffer.h new file mode 100644 index 0000000000..a38744b085 --- /dev/null +++ b/src/servers/app/drawing/remote/StreamingRingBuffer.h @@ -0,0 +1,47 @@ +/* + * Copyright 2009, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + */ +#ifndef STREAMING_RING_BUFFER_H +#define STREAMING_RING_BUFFER_H + +#include +#include +#include + +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