diff --git a/headers/os/app/Cursor.h b/headers/os/app/Cursor.h index 8daebe5ad0..c392305d2a 100644 --- a/headers/os/app/Cursor.h +++ b/headers/os/app/Cursor.h @@ -33,6 +33,7 @@ class BCursor : BArchivable { int32 fServerToken; bool fNeedToFree; + mutable bool fPendingViewCursor; uint32 _reserved[6]; }; diff --git a/headers/private/servers/app/CursorSet.h b/headers/private/servers/app/CursorSet.h index d3929efefa..d79a30354c 100644 --- a/headers/private/servers/app/CursorSet.h +++ b/headers/private/servers/app/CursorSet.h @@ -42,7 +42,7 @@ class CursorSet : public BMessage { status_t Save(const char *path,int32 saveflags=0); status_t Load(const char *path); status_t AddCursor(cursor_which which,const BBitmap *cursor, const BPoint &hotspot); - status_t AddCursor(cursor_which which, int8 *data); + status_t AddCursor(cursor_which which, uint8 *data); void RemoveCursor(cursor_which which); status_t FindCursor(cursor_which which, BBitmap **cursor, BPoint *hotspot); status_t FindCursor(cursor_which which, ServerCursor **cursor); @@ -51,7 +51,7 @@ class CursorSet : public BMessage { private: const char *_CursorWhichToString(cursor_which which); - BBitmap *_CursorDataToBitmap(int8 *data); + BBitmap *_CursorDataToBitmap(uint8 *data); }; #endif // CURSOR_SET_H diff --git a/headers/private/servers/app/ServerCursor.h b/headers/private/servers/app/ServerCursor.h index a775ed0e75..3977321a82 100644 --- a/headers/private/servers/app/ServerCursor.h +++ b/headers/private/servers/app/ServerCursor.h @@ -26,7 +26,7 @@ class ServerCursor : public ServerBitmap { int32 flags, BPoint hotspot, int32 bytesperrow = -1, screen_id screen = B_MAIN_SCREEN_ID); - ServerCursor(const int8* cursorDataFromR5); + ServerCursor(const uint8* cursorDataFromR5); ServerCursor(const uint8* alreadyPaddedData, uint32 width, uint32 height, color_space format); @@ -47,8 +47,16 @@ class ServerCursor : public ServerBitmap { int32 Token() const { return fToken; } - void Acquire() { atomic_add(&fReferenceCount, 1); } - bool Release() { return atomic_add(&fReferenceCount, -1) == 1; } + void Acquire() + { atomic_add(&fReferenceCount, 1); } + bool Release(); + + void SetPendingViewCursor(bool pending); + + void AttachedToManager(CursorManager* manager); + + const uint8* CursorData() const + { return fCursorData; } private: friend class CursorManager; @@ -56,6 +64,9 @@ class ServerCursor : public ServerBitmap { BPoint fHotSpot; team_id fOwningTeam; int32 fReferenceCount; + uint8* fCursorData; + CursorManager* fManager; + vint32 fPendingViewCursor; }; #endif // SERVER_CURSOR_H diff --git a/src/kits/app/Cursor.cpp b/src/kits/app/Cursor.cpp index da9b9baae4..4155e70162 100644 --- a/src/kits/app/Cursor.cpp +++ b/src/kits/app/Cursor.cpp @@ -31,7 +31,8 @@ const BCursor *B_CURSOR_I_BEAM; BCursor::BCursor(const void *cursorData) : fServerToken(-1), - fNeedToFree(false) + fNeedToFree(false), + fPendingViewCursor(false) { const uint8 *data = (const uint8 *)cursorData; @@ -68,6 +69,7 @@ BCursor::BCursor(BMessage *data) // undefined on BeOS fServerToken = -1; fNeedToFree = false; + fPendingViewCursor = false; } @@ -78,6 +80,7 @@ BCursor::~BCursor() BPrivate::AppServerLink link; link.StartMessage(AS_DELETE_CURSOR); link.Attach(fServerToken); + link.Attach(fPendingViewCursor); link.Flush(); } } diff --git a/src/kits/interface/View.cpp b/src/kits/interface/View.cpp index a0d5bfa95c..9af34aebcb 100644 --- a/src/kits/interface/View.cpp +++ b/src/kits/interface/View.cpp @@ -980,18 +980,20 @@ BView::ResizingMode() const void BView::SetViewCursor(const BCursor *cursor, bool sync) { - if (!cursor) + if (cursor == NULL || fOwner == NULL) return; - if (!fOwner) - debugger("View method requires owner and doesn't have one"); - check_lock(); fOwner->fLink->StartMessage(AS_LAYER_SET_CURSOR); fOwner->fLink->Attach(cursor->fServerToken); - if (sync) + if (!sync) { + cursor->fPendingViewCursor = true; + // this avoids a race condition in case the cursor is + // immediately deleted after this call, as the deletion + // is handled by the application, not the window + } else fOwner->fLink->Flush(); } diff --git a/src/servers/app/CursorData.cpp b/src/servers/app/CursorData.cpp index ad05ccf035..9ff4f0f8e3 100644 --- a/src/servers/app/CursorData.cpp +++ b/src/servers/app/CursorData.cpp @@ -51,7 +51,7 @@ transparent. Transparency only applies to white pixels—black pixels are always // Impressive ASCII art, eh? -int8 default_cursor_data[] = { +uint8 default_cursor_data[] = { 16,1,0,0, 255,224, // ***********----- 128,16, // *----------*---- @@ -91,56 +91,56 @@ int8 default_cursor_data[] = { 0,0 }; -int8 default_text_data[] = { +uint8 default_text_data[] = { 0x10, 0x01, 0x07, 0x07, 0x00, 0x00, 0x06, 0xC0, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x06, 0xC0, 0x0F, 0xE0, 0x07, 0xC0, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x07, 0xC0, 0x0F, 0xE0, 0x06, 0xC0 }; -int8 default_move_data[] = { +uint8 default_move_data[] = { 0x10, 0x01, 0x07, 0x07, 0x00, 0x00, 0x01, 0x00, 0x03, 0x80, 0x07, 0xC0, 0x00, 0x00, 0x10, 0x10, 0x30, 0x18, 0x71, 0x1C, 0x30, 0x18, 0x10, 0x10, 0x00, 0x00, 0x07, 0xC0, 0x03, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x80, 0x07, 0xC0, 0x0F, 0xE0, 0x1F, 0xF0, 0x38, 0x38, 0x7B, 0xBC, 0xFB, 0xBE, 0x7B, 0xBC, 0x38, 0x38, 0x1F, 0xF0, 0x0F, 0xE0, 0x07, 0xC0, 0x03, 0x80, 0x01, 0x00, 0x00, 0x00 }; -int8 default_drag_data[] = { +uint8 default_drag_data[] = { 0x10, 0x01, 0x00, 0x00, 0xFF, 0x00, 0x81, 0x00, 0x82, 0x00, 0x82, 0x00, 0x81, 0xFF, 0x80, 0x81, 0xB0, 0x41, 0xC8, 0x41, 0x04, 0x81, 0x03, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x03, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0x07, 0xFF, 0x03, 0xFF, 0x03, 0xFF, 0x03, 0xFF, 0x03, 0xFF, 0x03, 0xFF, 0x03, 0xFF, 0x03, 0xFF }; -int8 default_resize_data[] = { +uint8 default_resize_data[] = { 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x3E, 0x78, 0x1E, 0x70, 0x0E, 0x68, 0x16, 0x44, 0x22, 0x02, 0x40, 0x01, 0x80, 0x01, 0x80, 0x02, 0x40, 0x44, 0x22, 0x68, 0x16, 0x70, 0x0E, 0x78, 0x1E, 0x7C, 0x3E, 0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0xFC, 0x3F, 0xF8, 0x1F, 0xFC, 0x3F, 0xEE, 0x77, 0xC7, 0xE3, 0x03, 0xC0, 0x03, 0xC0, 0xC7, 0xE3, 0xEE, 0x77, 0xFC, 0x3F, 0xF8, 0x1F, 0xFC, 0x3F, 0xFE, 0x7F, 0xFE, 0x7F }; -int8 default_resize_ew_data[] = { +uint8 default_resize_ew_data[] = { 0x10, 0x01, 0x07, 0x07, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x11, 0x10, 0x31, 0x18, 0x71, 0x1C, 0x71, 0x1C, 0x31, 0x18, 0x11, 0x10, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x80, 0x03, 0x80, 0x0B, 0xA0, 0x1B, 0xB0, 0x3B, 0xB8, 0x7B, 0xBC, 0xFB, 0xBE, 0xFB, 0xBE, 0x7B, 0xBC, 0x3B, 0xB8, 0x1B, 0xB0, 0x0B, 0xA0, 0x03, 0x80, 0x03, 0x80, 0x01, 0x00 }; -int8 default_resize_ns_data[] = { +uint8 default_resize_ns_data[] = { 0x10, 0x01, 0x07, 0x07, 0x00, 0x00, 0x01, 0x80, 0x03, 0xC0, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0xC0, 0x07, 0xE0, 0x0F, 0xF0, 0x1F, 0xF8, 0x00, 0x00, 0x7F, 0xFE, 0xFF, 0xFF, 0x7F, 0xFE, 0x00, 0x00, 0x1F, 0xF8, 0x0F, 0xF0, 0x07, 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x00, 0x00 }; -int8 default_resize_nwse_data[] = { +uint8 default_resize_nwse_data[] = { 0x10, 0x01, 0x08, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x08, 0x1E, 0x10, 0x1C, 0x20, 0x18, 0x40, 0x10, 0x80, 0x01, 0x08, 0x02, 0x18, 0x04, 0x38, 0x08, 0x78, 0x10, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xCC, 0x3F, 0x9C, 0x3F, 0x38, 0x3E, 0x70, 0x3C, 0xE4, 0x39, 0xCC, 0x33, 0x9C, 0x27, 0x3C, 0x0E, 0x7C, 0x1C, 0xFC, 0x39, 0xFC, 0x33, 0xFC, 0x00, 0x00, 0x00, 0x00 }; -int8 default_resize_nesw_data[] = { +uint8 default_resize_nesw_data[] = { 0x10, 0x01, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xF8, 0x08, 0x78, 0x04, 0x38, 0x02, 0x18, 0x01, 0x08, 0x10, 0x80, 0x18, 0x40, 0x1C, 0x20, 0x1E, 0x10, 0x1F, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0xFC, 0x39, 0xFC, 0x1C, 0xFC, 0x0E, 0x7C, 0x27, 0x3C, 0x33, 0x9C, 0x39, 0xCC, 0x3C, 0xE4, 0x3E, 0x70, 0x3F, 0x38, 0x3F, 0x9C, 0x3F, 0xCC, 0x00, 0x00, @@ -149,7 +149,7 @@ int8 default_resize_nesw_data[] = { // known good cursor data for testing rest of system -int8 cross_cursor[] = {16,1,5,5, +uint8 cross_cursor[] = {16,1,5,5, 14,0,4,0,4,0,4,0,128,32,241,224,128,32,4,0, 4,0,4,0,14,0,0,0,0,0,0,0,0,0,0,0, 14,0,4,0,4,0,4,0,128,32,245,224,128,32,4,0, diff --git a/src/servers/app/CursorData.h b/src/servers/app/CursorData.h index dde23fcdd6..03d4e55eac 100644 --- a/src/servers/app/CursorData.h +++ b/src/servers/app/CursorData.h @@ -3,14 +3,14 @@ #include -extern int8 default_cursor_data[]; -extern int8 default_text_data[]; -extern int8 default_move_data[]; -extern int8 default_drag_data[]; -extern int8 default_resize_data[]; -extern int8 default_resize_ew_data[]; -extern int8 default_resize_ns_data[]; -extern int8 default_resize_nwse_data[]; -extern int8 default_resize_nesw_data[]; +extern uint8 default_cursor_data[]; +extern uint8 default_text_data[]; +extern uint8 default_move_data[]; +extern uint8 default_drag_data[]; +extern uint8 default_resize_data[]; +extern uint8 default_resize_ew_data[]; +extern uint8 default_resize_ns_data[]; +extern uint8 default_resize_nwse_data[]; +extern uint8 default_resize_nesw_data[]; #endif diff --git a/src/servers/app/CursorManager.cpp b/src/servers/app/CursorManager.cpp index 084648be30..e7da9bf92a 100644 --- a/src/servers/app/CursorManager.cpp +++ b/src/servers/app/CursorManager.cpp @@ -8,9 +8,11 @@ /** Handles the system's cursor infrastructure */ +#include "CursorManager.h" + +#include #include "CursorData.h" -#include "CursorManager.h" #include "HaikuSystemCursor.h" #include "ServerCursor.h" #include "ServerConfig.h" @@ -67,72 +69,80 @@ CursorManager::CursorManager() CursorManager::~CursorManager() { for (int32 i = 0; i < fCursorList.CountItems(); i++) { - delete (ServerCursor *)fCursorList.ItemAt(i); + delete (ServerCursor*)fCursorList.ItemAtFast(i); } } +ServerCursor* +CursorManager::CreateCursor(team_id clientTeam, const uint8* cursorData) +{ + if (!Lock()) + return NULL; + + ServerCursor* cursor = _FindCursor(clientTeam, cursorData); + + if (!cursor) { + cursor = new (nothrow) ServerCursor(cursorData); + if (cursor) { + cursor->SetOwningTeam(clientTeam); + if (AddCursor(cursor) < B_OK) { + delete cursor; + cursor = NULL; + } + } + } else { + cursor->Acquire(); + } + + Unlock(); + + return cursor; +} + /*! \brief Registers a cursor with the manager. - \param sc ServerCursor object to register - \return The token assigned to the cursor or B_ERROR if sc is NULL + \param cursor ServerCursor object to register + \return The token assigned to the cursor or B_ERROR if cursor is NULL */ int32 CursorManager::AddCursor(ServerCursor* cursor, int32 token) { - if (!cursor) + if (!cursor || !Lock()) return B_ERROR; - Lock(); - - fCursorList.AddItem(cursor); - if (token == -1) - cursor->fToken = fTokenSpace.NewToken(kCursorToken, cursor); - else { - fTokenSpace.SetToken(token, kCursorToken, cursor); - cursor->fToken = token; + if (!fCursorList.AddItem(cursor)) { + Unlock(); + return B_ERROR; } + if (token == -1) { + token = fTokenSpace.NewToken(kCursorToken, cursor); + } else { + fTokenSpace.SetToken(token, kCursorToken, cursor); + } + + cursor->fToken = token; + cursor->AttachedToManager(this); + Unlock(); + return token; } -void -CursorManager::_RemoveCursor(ServerCursor* cursor) -{ - fCursorList.RemoveItem(cursor); - fTokenSpace.RemoveToken(cursor->fToken); -} - - -ServerCursor* -CursorManager::_RemoveCursor(int32 index) -{ - ServerCursor* cursor = (ServerCursor *)fCursorList.RemoveItem(index); - if (cursor != NULL) - fTokenSpace.RemoveToken(cursor->fToken); - - return cursor; -} - - /*! \brief Releases a reference to a cursor If this was the last reference to this cursor, it will be deleted. */ void -CursorManager::ReleaseCursor(ServerCursor* cursor) +CursorManager::RemoveCursor(ServerCursor* cursor) { - Lock(); + if (!Lock()) + return; - if (cursor->Release()) { - // this was the last reference, remove the cursor - - _RemoveCursor(cursor); - delete cursor; - } + _RemoveCursor(cursor); Unlock(); } @@ -145,15 +155,13 @@ CursorManager::ReleaseCursor(ServerCursor* cursor) void CursorManager::DeleteCursors(team_id team) { - Lock(); + if (!Lock()) + return; for (int32 index = fCursorList.CountItems(); index-- > 0;) { - ServerCursor *cursor = (ServerCursor *)fCursorList.ItemAt(index); - if (cursor->OwningTeam() != team) - continue; - - _RemoveCursor(index); - delete cursor; + ServerCursor *cursor = (ServerCursor*)fCursorList.ItemAtFast(index); + if (cursor->OwningTeam() == team) + cursor->Release(); } Unlock(); @@ -372,22 +380,6 @@ CursorManager::ChangeCursor(cursor_which which, int32 token) } -/*! - \brief Internal function which finds the cursor with a particular ID - \param token ID of the cursor to find - \return The cursor or NULL if not found -*/ -ServerCursor * -CursorManager::FindCursor(int32 token) -{ - ServerCursor* cursor; - if (fTokenSpace.GetToken(token, kCursorToken, (void**)&cursor) == B_OK) - return cursor; - - return NULL; -} - - //! Sets the cursors to the defaults and saves them to CURSOR_SETTINGS_DIR/"d void CursorManager::SetDefaults() @@ -415,3 +407,56 @@ CursorManager::SetDefaults() SetCursorSet(string.String()); Unlock(); } + + +/*! + \brief Internal function which finds the cursor with a particular ID + \param token ID of the cursor to find + \return The cursor or NULL if not found +*/ +ServerCursor * +CursorManager::FindCursor(int32 token) +{ + ServerCursor* cursor; + if (fTokenSpace.GetToken(token, kCursorToken, (void**)&cursor) == B_OK) + return cursor; + + return NULL; +} + + +ServerCursor * +CursorManager::_FindCursor(team_id clientTeam, const uint8* cursorData) +{ + int32 count = fCursorList.CountItems(); + for (int32 i = 0; i < count; i++) { + ServerCursor* cursor = (ServerCursor*)fCursorList.ItemAtFast(i); + if (cursor->OwningTeam() == clientTeam + && cursor->CursorData() + && memcmp(cursor->CursorData(), cursorData, 68) == 0) { + return cursor; + } + } + return NULL; +} + + +void +CursorManager::_RemoveCursor(ServerCursor* cursor) +{ + fCursorList.RemoveItem(cursor); + fTokenSpace.RemoveToken(cursor->fToken); +} + + +//ServerCursor* +//CursorManager::_RemoveCursor(int32 index) +//{ +// ServerCursor* cursor = (ServerCursor*)fCursorList.RemoveItem(index); +// if (cursor != NULL) +// fTokenSpace.RemoveToken(cursor->fToken); +// +// return cursor; +//} + + diff --git a/src/servers/app/CursorManager.h b/src/servers/app/CursorManager.h index ce9411ace2..16d8a21b71 100644 --- a/src/servers/app/CursorManager.h +++ b/src/servers/app/CursorManager.h @@ -33,21 +33,27 @@ class CursorManager : public BLocker { CursorManager(); virtual ~CursorManager(); + ServerCursor* CreateCursor(team_id clientTeam, + const uint8* cursorData); + int32 AddCursor(ServerCursor* cursor, int32 token = -1); void DeleteCursors(team_id team); - void ReleaseCursor(ServerCursor* cursor); + void RemoveCursor(ServerCursor* cursor); void SetCursorSet(const char* path); ServerCursor* GetCursor(cursor_which which); cursor_which GetCursorWhich(); void ChangeCursor(cursor_which which, int32 token); void SetDefaults(); + ServerCursor* FindCursor(int32 token); private: + ServerCursor* _FindCursor(team_id cientTeam, + const uint8* cursorData); void _RemoveCursor(ServerCursor* cursor); - ServerCursor* _RemoveCursor(int32 index); +// ServerCursor* _RemoveCursor(int32 index); BList fCursorList; BTokenSpace fTokenSpace; diff --git a/src/servers/app/CursorSet.cpp b/src/servers/app/CursorSet.cpp index dc4b60bcdf..e5771f9a38 100644 --- a/src/servers/app/CursorSet.cpp +++ b/src/servers/app/CursorSet.cpp @@ -119,7 +119,7 @@ CursorSet::AddCursor(cursor_which which, const BBitmap *cursor, const BPoint &ho function must convert the R5 cursor data into a BBitmap */ status_t -CursorSet::AddCursor(cursor_which which, int8 *data) +CursorSet::AddCursor(cursor_which which, uint8 *data) { // Convert cursor data to a bitmap because all cursors are internally stored // as bitmaps @@ -316,7 +316,7 @@ CursorSet::_CursorWhichToString(cursor_which which) BBitmaps returned by this function are always in the RGBA32 color space */ BBitmap * -CursorSet::_CursorDataToBitmap(int8 *data) +CursorSet::_CursorDataToBitmap(uint8 *data) { // 68-byte array used in R5 for holding cursors. // This API has serious problems and should be deprecated(but supported) in R2 diff --git a/src/servers/app/Desktop.cpp b/src/servers/app/Desktop.cpp index de872fd26d..022c65bb30 100644 --- a/src/servers/app/Desktop.cpp +++ b/src/servers/app/Desktop.cpp @@ -601,7 +601,7 @@ Desktop::SetCursor(ServerCursor* newCursor) HWInterface()->SetCursor(newCursor); if (oldCursor != NULL) - fCursorManager.ReleaseCursor(oldCursor); + oldCursor->Release(); } diff --git a/src/servers/app/ServerApp.cpp b/src/servers/app/ServerApp.cpp index 5e537b079f..9e270dbec2 100644 --- a/src/servers/app/ServerApp.cpp +++ b/src/servers/app/ServerApp.cpp @@ -925,19 +925,33 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) // 2) port_id reply port status_t status = B_ERROR; - int8 cursorData[68]; + uint8 cursorData[68]; ServerCursor* cursor = NULL; +// if (link.Read(cursorData, sizeof(cursorData)) >= B_OK) { +// cursor = new (nothrow) ServerCursor(cursorData); +// if (cursor == NULL) +// status = B_NO_MEMORY; +// } +// +// if (cursor != NULL) { +// cursor->SetOwningTeam(fClientTeam); +// fDesktop->GetCursorManager().AddCursor(cursor); +// +// // Synchronous message - BApplication is waiting on the cursor's ID +// fLink.StartMessage(B_OK); +// fLink.Attach(cursor->Token()); +// } else +// fLink.StartMessage(status); + if (link.Read(cursorData, sizeof(cursorData)) >= B_OK) { - cursor = new (nothrow) ServerCursor(cursorData); + cursor = fDesktop->GetCursorManager().CreateCursor(fClientTeam, + cursorData); if (cursor == NULL) status = B_NO_MEMORY; } if (cursor != NULL) { - cursor->SetOwningTeam(fClientTeam); - fDesktop->GetCursorManager().AddCursor(cursor); - // Synchronous message - BApplication is waiting on the cursor's ID fLink.StartMessage(B_OK); fLink.Attach(cursor->Token()); @@ -952,14 +966,22 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) STRACE(("ServerApp %s: Delete BCursor\n", Signature())); // Attached data: // 1) int32 token ID of the cursor to delete - int32 token = B_NULL_TOKEN; + int32 token; + bool pendingViewCursor; link.Read(&token); + if (link.Read(&pendingViewCursor) != B_OK) + break; if (fAppCursor && fAppCursor->Token() == token) fAppCursor = NULL; - if (ServerCursor* cursor = fDesktop->GetCursorManager().FindCursor(token)) - fDesktop->GetCursorManager().ReleaseCursor(cursor); + ServerCursor* cursor = fDesktop->GetCursorManager().FindCursor(token); + if (cursor) { + if (pendingViewCursor) + cursor->SetPendingViewCursor(true); + + cursor->Release(); + } break; } diff --git a/src/servers/app/ServerCursor.cpp b/src/servers/app/ServerCursor.cpp index 505afa8d9a..3570cf2b72 100644 --- a/src/servers/app/ServerCursor.cpp +++ b/src/servers/app/ServerCursor.cpp @@ -17,8 +17,12 @@ #include "ServerCursor.h" +#include #include +#include "CursorManager.h" + +using std::nothrow; /*! \brief Constructor @@ -36,7 +40,10 @@ ServerCursor::ServerCursor(BRect r, color_space format, : ServerBitmap(r, format, flags, bytesPerRow, screen), fHotSpot(hotspot), fOwningTeam(-1), - fReferenceCount(1) + fReferenceCount(1), + fCursorData(NULL), + fManager(NULL), + fPendingViewCursor(0) { fHotSpot.ConstrainTo(Bounds()); _AllocateBuffer(); @@ -47,11 +54,14 @@ ServerCursor::ServerCursor(BRect r, color_space format, \brief Constructor \param data Pointer to 68-byte cursor data array. See BeBook entry for BCursor for details */ -ServerCursor::ServerCursor(const int8* data) +ServerCursor::ServerCursor(const uint8* data) : ServerBitmap(BRect(0, 0, 15, 15), B_RGBA32, 0), fHotSpot(0, 0), fOwningTeam(-1), - fReferenceCount(1) + fReferenceCount(1), + fCursorData(NULL), + fManager(NULL), + fPendingViewCursor(0) { // 68-byte array used in R5 for holding cursors. // This API has serious problems and should be deprecated(but supported) in R2 @@ -99,6 +109,10 @@ ServerCursor::ServerCursor(const int8* data) bmppos[i] = ((cursorval != 0) ? black : white) & ((maskval > 0) ? 0xFFFFFFFF : 0x00FFFFFF); } + + fCursorData = new (nothrow) uint8[68]; + if (fCursorData) + memcpy(fCursorData, data, 68); } } else { fWidth = 0; @@ -119,7 +133,10 @@ ServerCursor::ServerCursor(const uint8* alreadyPaddedData, : ServerBitmap(BRect(0, 0, width - 1, height - 1), format, 0), fHotSpot(0, 0), fOwningTeam(-1), - fReferenceCount(1) + fReferenceCount(1), + fCursorData(NULL), + fManager(NULL), + fPendingViewCursor(0) { _AllocateBuffer(); if (Bits()) @@ -135,7 +152,10 @@ ServerCursor::ServerCursor(const ServerCursor* cursor) : ServerBitmap(cursor), fHotSpot(0, 0), fOwningTeam(-1), - fReferenceCount(1) + fReferenceCount(1), + fCursorData(NULL), + fManager(NULL), + fPendingViewCursor(0) { // TODO: Hm. I don't move this into the if clause, // because it might break code elsewhere. @@ -146,6 +166,11 @@ ServerCursor::ServerCursor(const ServerCursor* cursor) if (Bits() && cursor->Bits()) memcpy(Bits(), cursor->Bits(), BitsLength()); fHotSpot = cursor->fHotSpot; + if (cursor->fCursorData) { + fCursorData = new (nothrow) uint8[68]; + if (fCursorData) + memcpy(fCursorData, cursor->fCursorData, 68); + } } } @@ -168,3 +193,37 @@ ServerCursor::SetHotSpot(BPoint hotSpot) fHotSpot.ConstrainTo(Bounds()); } + +bool +ServerCursor::Release() +{ + if (atomic_add(&fReferenceCount, -1) == 1) { + if (fPendingViewCursor > 0) { + // There is a SetViewCursor() waiting to be carried out + return false; + } + + if (fManager) { + fManager->RemoveCursor(this); + } + delete this; + + return true; + } + return false; +} + + +void +ServerCursor::SetPendingViewCursor(bool pending) +{ + atomic_add(&fPendingViewCursor, pending ? 1 : -1); +} + + +void +ServerCursor::AttachedToManager(CursorManager* manager) +{ + fManager = manager; +} + diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index 9e6116ea3c..0f2dd21628 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -162,8 +162,6 @@ ServerWindow::ServerWindow(const char *title, ServerApp *app, fClientReplyPort(clientPort), fClientLooperPort(looperPort), - fClientViewsWithInvalidCoords(B_VIEW_RESIZED), - fClientToken(clientToken), fCurrentLayer(NULL), @@ -1242,13 +1240,21 @@ ServerWindow::_DispatchViewMessage(int32 code, { DTRACE(("ServerWindow %s: Message AS_LAYER_CURSOR: ViewLayer: %s - NOT IMPLEMENTED\n", Title(), fCurrentLayer->Name())); int32 token; - if (link.Read(&token) == B_OK) { - // TODO: this badly needs reference counting - ServerCursor* cursor = fDesktop->GetCursorManager().FindCursor(token); - fCurrentLayer->SetCursor(cursor); - } + if (link.Read(&token) != B_OK) + break; - // TODO: if fCurrentLayer is the view under the cursor, the appearance should change immediately! + ServerCursor* cursor = fDesktop->GetCursorManager().FindCursor(token); + fCurrentLayer->SetCursor(cursor); + + if (fWindowLayer->IsFocus()) { + // The cursor might need to be updated now + fDesktop->UnlockSingleWindow(); + + if (fDesktop->EventDispatcher().ViewUnderMouse(fEventTarget) == fCurrentLayer->Token()) + fDesktop->SetCursor(cursor); + + fDesktop->LockSingleWindow(); + } break; } case AS_LAYER_SET_FLAGS: @@ -1263,14 +1269,12 @@ ServerWindow::_DispatchViewMessage(int32 code, case AS_LAYER_HIDE: { STRACE(("ServerWindow %s: Message AS_LAYER_HIDE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); -// TODO: test fCurrentLayer->SetHidden(true); break; } case AS_LAYER_SHOW: { STRACE(("ServerWindow %s: Message AS_LAYER_SHOW: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); -// TODO: test fCurrentLayer->SetHidden(false); break; } diff --git a/src/servers/app/ViewLayer.cpp b/src/servers/app/ViewLayer.cpp index f2dadf8f93..bc84828c1b 100644 --- a/src/servers/app/ViewLayer.cpp +++ b/src/servers/app/ViewLayer.cpp @@ -17,6 +17,7 @@ #include "DrawingEngine.h" #include "ServerApp.h" #include "ServerBitmap.h" +#include "ServerCursor.h" #include "ServerPicture.h" #include "ServerWindow.h" #include "WindowLayer.h" @@ -95,6 +96,9 @@ ViewLayer::~ViewLayer() // // TODO: Don't know yet if we should also delete fPicture + if (fCursor) + fCursor->Release(); + // iterate over children and delete each one ViewLayer* layer = fFirstChild; while (layer) { @@ -890,7 +894,17 @@ ViewLayer::SetEventMask(uint32 eventMask, uint32 options) void ViewLayer::SetCursor(ServerCursor *cursor) { - fCursor = cursor; + if (cursor != fCursor) { + if (fCursor) + fCursor->Release(); + + fCursor = cursor; + + if (fCursor) { + fCursor->Acquire(); + fCursor->SetPendingViewCursor(false); + } + } }