diff --git a/src/servers/app/BitmapManager.cpp b/src/servers/app/BitmapManager.cpp index 98e8aebd1d..27702fe688 100644 --- a/src/servers/app/BitmapManager.cpp +++ b/src/servers/app/BitmapManager.cpp @@ -220,6 +220,9 @@ BitmapManager::DeleteBitmap(ServerBitmap* bitmap) if (bitmap->Overlay() != NULL) fOverlays.RemoveItem(bitmap); + if (bitmap->Owner() != NULL) + bitmap->Owner()->BitmapRemoved(bitmap); + if (fBitmapList.RemoveItem(bitmap)) delete bitmap; } diff --git a/src/servers/app/OffscreenServerWindow.cpp b/src/servers/app/OffscreenServerWindow.cpp index 96c39090b4..d6121610a9 100644 --- a/src/servers/app/OffscreenServerWindow.cpp +++ b/src/servers/app/OffscreenServerWindow.cpp @@ -24,6 +24,7 @@ OffscreenServerWindow::OffscreenServerWindow(const char *title, ServerApp *app, OffscreenServerWindow::~OffscreenServerWindow() { + fBitmap->Release(); } diff --git a/src/servers/app/ServerApp.cpp b/src/servers/app/ServerApp.cpp index ac71d461f2..df41219dd2 100644 --- a/src/servers/app/ServerApp.cpp +++ b/src/servers/app/ServerApp.cpp @@ -97,6 +97,7 @@ ServerApp::ServerApp(Desktop* desktop, port_id clientReplyPort, fClientTeam(clientTeam), fWindowListLock("window list"), fTemporaryDisplayModeChange(0), + fMapLocker("server app maps"), fAppCursor(NULL), fViewCursor(NULL), fCursorHideLevel(0), @@ -188,12 +189,20 @@ ServerApp::~ServerApp() fWindowListLock.Lock(); } - for (int32 i = fBitmapList.CountItems(); i-- > 0;) { - gBitmapManager->DeleteBitmap((ServerBitmap*)fBitmapList.ItemAt(i)); + fMapLocker.Lock(); + + while (!fBitmapMap.empty()) { + ServerBitmap* bitmap = fBitmapMap.begin()->second; + + fBitmapMap.erase(fBitmapMap.begin()); + bitmap->Release(); } - for (int32 i = fPictureList.CountItems(); i-- > 0;) { - delete fPictureList.ItemAt(i); + while (!fPictureMap.empty()) { + ServerPicture* picture = fPictureMap.begin()->second; + + fPictureMap.erase(fPictureMap.begin()); + picture->ReleaseReference(); } fDesktop->GetCursorManager().DeleteCursors(fClientTeam); @@ -243,37 +252,6 @@ ServerApp::Quit(sem_id shutdownSemaphore) } -/*! \brief Send a message to the ServerApp's BApplication - \param message The message to send -*/ -void -ServerApp::SendMessageToClient(BMessage* message) const -{ - status_t status = fHandlerMessenger.SendMessage(message, (BHandler*)NULL, - 100000); - if (status != B_OK) { - syslog(LOG_ERR, "app %s send to client failed: %s\n", Signature(), - strerror(status)); - } -} - - -bool -ServerApp::_HasWindowUnderMouse() -{ - BAutolock locker(fWindowListLock); - - for (int32 i = fWindowList.CountItems(); i-- > 0;) { - ServerWindow* serverWindow = fWindowList.ItemAt(i); - - if (fDesktop->ViewUnderMouse(serverWindow->Window()) != B_NULL_TOKEN) - return true; - } - - return false; -} - - /*! \brief Sets the ServerApp's active status \param value The new status of the ServerApp. @@ -302,6 +280,21 @@ ServerApp::Activate(bool value) } +/*! \brief Send a message to the ServerApp's BApplication + \param message The message to send +*/ +void +ServerApp::SendMessageToClient(BMessage* message) const +{ + status_t status = fHandlerMessenger.SendMessage(message, (BHandler*)NULL, + 100000); + if (status != B_OK) { + syslog(LOG_ERR, "app %s send to client failed: %s\n", Signature(), + strerror(status)); + } +} + + void ServerApp::SetCurrentCursor(ServerCursor* cursor) { @@ -330,6 +323,185 @@ ServerApp::CurrentCursor() const } +bool +ServerApp::AddWindow(ServerWindow* window) +{ + BAutolock locker(fWindowListLock); + + return fWindowList.AddItem(window); +} + + +void +ServerApp::RemoveWindow(ServerWindow* window) +{ + BAutolock locker(fWindowListLock); + + fWindowList.RemoveItem(window); +} + + +bool +ServerApp::InWorkspace(int32 index) const +{ + BAutolock locker(fWindowListLock); + + // we could cache this, but then we'd have to recompute the cached + // value everytime a window has closed or changed workspaces + + // TODO: support initial application workspace! + + for (int32 i = fWindowList.CountItems(); i-- > 0;) { + ServerWindow* serverWindow = fWindowList.ItemAt(i); + + const Window* window = serverWindow->Window(); + if (window == NULL || window->IsOffscreenWindow()) + continue; + + // only normal and unhidden windows count + + if (window->IsNormal() && !window->IsHidden() + && window->InWorkspace(index)) + return true; + } + + return false; +} + + +uint32 +ServerApp::Workspaces() const +{ + uint32 workspaces = 0; + + BAutolock locker(fWindowListLock); + + // we could cache this, but then we'd have to recompute the cached + // value everytime a window has closed or changed workspaces + + for (int32 i = fWindowList.CountItems(); i-- > 0;) { + ServerWindow* serverWindow = fWindowList.ItemAt(i); + + const Window* window = serverWindow->Window(); + if (window == NULL || window->IsOffscreenWindow()) + continue; + + // only normal and unhidden windows count + + if (window->IsNormal() && !window->IsHidden()) + workspaces |= window->Workspaces(); + } + + // TODO: add initial application workspace! + return workspaces; +} + + +/*! \brief Acquires a reference of the desired bitmap, if available. + \param token ID token of the bitmap to find + \return The bitmap having that ID or NULL if not found +*/ +ServerBitmap* +ServerApp::GetBitmap(int32 token) const +{ + if (token < 1) + return NULL; + + BAutolock _(fMapLocker); + + ServerBitmap* bitmap = _FindBitmap(token); + if (bitmap == NULL) + return NULL; + + bitmap->Acquire(); + + return bitmap; +} + + +bool +ServerApp::BitmapAdded(ServerBitmap* bitmap) +{ + BAutolock _(fMapLocker); + + try { + fBitmapMap.insert(std::make_pair(bitmap->Token(), bitmap)); + } catch (std::bad_alloc& exception) { + return false; + } + + return true; +} + + +void +ServerApp::BitmapRemoved(ServerBitmap* bitmap) +{ + BAutolock _(fMapLocker); + fBitmapMap.erase(bitmap->Token()); +} + + +ServerPicture* +ServerApp::CreatePicture(const ServerPicture* original) +{ + ServerPicture* picture; + if (original != NULL) + picture = new(std::nothrow) ServerPicture(*original); + else + picture = new(std::nothrow) ServerPicture(); + + if (picture != NULL && !picture->SetOwner(this)) + picture->ReleaseReference(); + + return picture; +} + + +ServerPicture* +ServerApp::GetPicture(int32 token) const +{ + if (token < 1) + return NULL; + + BAutolock _(fMapLocker); + + ServerPicture* picture = _FindPicture(token); + if (picture == NULL) + return NULL; + + picture->AcquireReference(); + + return picture; +} + + +bool +ServerApp::PictureAdded(ServerPicture* picture) +{ + BAutolock _(fMapLocker); + + try { + fPictureMap.insert(std::make_pair(picture->Token(), picture)); + } catch (std::bad_alloc& exception) { + return false; + } + + return true; +} + + +void +ServerApp::PictureRemoved(ServerPicture* picture) +{ + BAutolock _(fMapLocker); + fPictureMap.erase(picture->Token()); +} + + +// #pragma mark - private methods + + void ServerApp::_GetLooperName(char* name, size_t length) { @@ -337,88 +509,6 @@ ServerApp::_GetLooperName(char* name, size_t length) } -/*! \brief The thread function ServerApps use to monitor messages -*/ -void -ServerApp::_MessageLooper() -{ - // Message-dispatching loop for the ServerApp - - // First let's tell the client how to talk with us. - fLink.StartMessage(B_OK); - fLink.Attach(fMessagePort); - fLink.Attach(fDesktop->SharedReadOnlyArea()); - fLink.Flush(); - - BPrivate::LinkReceiver &receiver = fLink.Receiver(); - - int32 code; - status_t err = B_OK; - - while (!fQuitting) { - STRACE(("info: ServerApp::_MessageLooper() listening on port %ld.\n", - fMessagePort)); - - err = receiver.GetNextMessage(code, B_INFINITE_TIMEOUT); - if (err != B_OK || code == B_QUIT_REQUESTED) { - STRACE(("ServerApp: application seems to be gone...\n")); - - // Tell desktop to quit us - BPrivate::LinkSender link(fDesktop->MessagePort()); - link.StartMessage(AS_DELETE_APP); - link.Attach(Thread()); - link.Flush(); - break; - } - - switch (code) { - case kMsgAppQuit: - // we receive this from our destructor on quit - fQuitting = true; - break; - - case AS_QUIT_APP: - { - // This message is received only when the app_server is asked - // to shut down in test/debug mode. Of course, if we are testing - // while using AccelerantDriver, we do NOT want to shut down - // client applications. The server can be quit in this fashion - // through the driver's interface, such as closing the - // ViewDriver's window. - - STRACE(("ServerApp %s:Server shutdown notification received\n", - Signature())); - - // If we are using the real, accelerated version of the - // DrawingEngine, we do NOT want the user to be able shut down - // the server. The results would NOT be pretty -#if TEST_MODE - BMessage pleaseQuit(B_QUIT_REQUESTED); - SendMessageToClient(&pleaseQuit); -#endif - break; - } - - default: - STRACE(("ServerApp %s: Got a Message to dispatch\n", - Signature())); - _DispatchMessage(code, receiver); - break; - } - } - - // Quit() will send us a message; we're handling the exiting procedure - thread_id sender; - sem_id shutdownSemaphore; - receive_data(&sender, &shutdownSemaphore, sizeof(sem_id)); - - delete this; - - if (shutdownSemaphore >= B_OK) - release_sem(shutdownSemaphore); -} - - /*! \brief Handler function for BApplication API messages \param code Identifier code for the message. Equivalent to BMessage::what \param buffer Any attachments @@ -653,9 +743,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) STRACE(("ServerApp %s: Create Bitmap (%.1fx%.1f)\n", Signature(), frame.Width() + 1, frame.Height() + 1)); - if (bitmap != NULL && fBitmapList.AddItem(bitmap)) { - bitmap->SetOwner(this); - + if (bitmap != NULL && bitmap->SetOwner(this)) { fLink.StartMessage(B_OK); fLink.Attach(bitmap->Token()); fLink.Attach(allocationFlags); @@ -665,11 +753,11 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) fLink.Attach( fMemoryAllocator.AreaOffset(bitmap->AllocationCookie())); - if (allocationFlags & kFramebuffer) + if ((allocationFlags & kFramebuffer) != 0) fLink.Attach(bitmap->BytesPerRow()); } else { if (bitmap != NULL) - gBitmapManager->DeleteBitmap(bitmap); + bitmap->Release(); fLink.StartMessage(B_NO_MEMORY); } @@ -689,13 +777,17 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) int32 token; link.Read(&token); - ServerBitmap *bitmap = FindBitmap(token); - if (bitmap && fBitmapList.RemoveItem(bitmap)) { + fMapLocker.Lock(); + + ServerBitmap* bitmap = _FindBitmap(token); + if (bitmap != NULL) { STRACE(("ServerApp %s: Deleting Bitmap %ld\n", Signature(), token)); - gBitmapManager->DeleteBitmap(bitmap); + bitmap->Release(); } + + fMapLocker.Unlock(); break; } case AS_GET_BITMAP_OVERLAY_RESTRICTIONS: @@ -707,13 +799,15 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) if (link.Read(&token) != B_OK) break; - ServerBitmap *bitmap = FindBitmap(token); + ServerBitmap* bitmap = GetBitmap(token); if (bitmap != NULL) { STRACE(("ServerApp %s: Get overlay restrictions for bitmap " "%ld\n", Signature(), token)); status = fDesktop->HWInterface()->GetOverlayRestrictions( bitmap->Overlay(), &restrictions); + + bitmap->Release(); } fLink.StartMessage(status); @@ -752,7 +846,9 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) for (int32 i = 0; i < subPicturesCount; i++) { int32 token = -1; link.Read(&token); - if (ServerPicture* subPicture = FindPicture(token)) + + // TODO: do we actually need another reference here? + if (ServerPicture* subPicture = GetPicture(token)) picture->NestPicture(subPicture); } status = picture->ImportData(link); @@ -771,8 +867,13 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) { STRACE(("ServerApp %s: Delete Picture\n", Signature())); int32 token; - if (link.Read(&token) == B_OK) - DeletePicture(token); + if (link.Read(&token) == B_OK) { + BAutolock _(fMapLocker); + + ServerPicture* picture = _FindPicture(token); + if (picture != NULL) + picture->ReleaseReference(); + } break; } @@ -782,7 +883,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) int32 token; ServerPicture* original = NULL; if (link.Read(&token) == B_OK) - original = FindPicture(token); + original = GetPicture(token); if (original != NULL) { ServerPicture* cloned = CreatePicture(original); @@ -791,6 +892,8 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) fLink.Attach(cloned->Token()); } else fLink.StartMessage(B_NO_MEMORY); + + original->ReleaseReference(); } else fLink.StartMessage(B_BAD_VALUE); @@ -803,10 +906,11 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) STRACE(("ServerApp %s: Download Picture\n", Signature())); int32 token; link.Read(&token); - ServerPicture* picture = FindPicture(token); + ServerPicture* picture = GetPicture(token); if (picture != NULL) { picture->ExportData(fLink); // ExportData() calls StartMessage() already + picture->ReleaseReference(); } else fLink.StartMessage(B_ERROR); @@ -2740,8 +2844,8 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) case AS_READ_BITMAP: { STRACE(("ServerApp %s: AS_READ_BITMAP\n", Signature())); - int32 bitmapToken; - link.Read(&bitmapToken); + int32 token; + link.Read(&token); bool drawCursor = true; link.Read(&drawCursor); @@ -2749,13 +2853,15 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) BRect bounds; link.Read(&bounds); - ServerBitmap *bitmap = FindBitmap(bitmapToken); + ServerBitmap* bitmap = GetBitmap(token); if (bitmap != NULL) { if (fDesktop->GetDrawingEngine()->ReadBitmap(bitmap, - drawCursor, bounds) == B_OK) { + drawCursor, bounds) == B_OK) { fLink.StartMessage(B_OK); } else fLink.StartMessage(B_BAD_VALUE); + + gBitmapManager->DeleteBitmap(bitmap); } else fLink.StartMessage(B_BAD_VALUE); @@ -2910,6 +3016,88 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) } +/*! \brief The thread function ServerApps use to monitor messages +*/ +void +ServerApp::_MessageLooper() +{ + // Message-dispatching loop for the ServerApp + + // First let's tell the client how to talk with us. + fLink.StartMessage(B_OK); + fLink.Attach(fMessagePort); + fLink.Attach(fDesktop->SharedReadOnlyArea()); + fLink.Flush(); + + BPrivate::LinkReceiver &receiver = fLink.Receiver(); + + int32 code; + status_t err = B_OK; + + while (!fQuitting) { + STRACE(("info: ServerApp::_MessageLooper() listening on port %ld.\n", + fMessagePort)); + + err = receiver.GetNextMessage(code, B_INFINITE_TIMEOUT); + if (err != B_OK || code == B_QUIT_REQUESTED) { + STRACE(("ServerApp: application seems to be gone...\n")); + + // Tell desktop to quit us + BPrivate::LinkSender link(fDesktop->MessagePort()); + link.StartMessage(AS_DELETE_APP); + link.Attach(Thread()); + link.Flush(); + break; + } + + switch (code) { + case kMsgAppQuit: + // we receive this from our destructor on quit + fQuitting = true; + break; + + case AS_QUIT_APP: + { + // This message is received only when the app_server is asked + // to shut down in test/debug mode. Of course, if we are testing + // while using AccelerantDriver, we do NOT want to shut down + // client applications. The server can be quit in this fashion + // through the driver's interface, such as closing the + // ViewDriver's window. + + STRACE(("ServerApp %s:Server shutdown notification received\n", + Signature())); + + // If we are using the real, accelerated version of the + // DrawingEngine, we do NOT want the user to be able shut down + // the server. The results would NOT be pretty +#if TEST_MODE + BMessage pleaseQuit(B_QUIT_REQUESTED); + SendMessageToClient(&pleaseQuit); +#endif + break; + } + + default: + STRACE(("ServerApp %s: Got a Message to dispatch\n", + Signature())); + _DispatchMessage(code, receiver); + break; + } + } + + // Quit() will send us a message; we're handling the exiting procedure + thread_id sender; + sem_id shutdownSemaphore; + receive_data(&sender, &shutdownSemaphore, sizeof(sem_id)); + + delete this; + + if (shutdownSemaphore >= B_OK) + release_sem(shutdownSemaphore); +} + + status_t ServerApp::_CreateWindow(int32 code, BPrivate::LinkReceiver& link, port_id& clientReplyPort) @@ -2960,7 +3148,7 @@ ServerApp::_CreateWindow(int32 code, BPrivate::LinkReceiver& link, ServerWindow *window = NULL; if (code == AS_CREATE_OFFSCREEN_WINDOW) { - ServerBitmap* bitmap = FindBitmap(bitmapToken); + ServerBitmap* bitmap = GetBitmap(bitmapToken); if (bitmap != NULL) { window = new (nothrow) OffscreenServerWindow(title, this, @@ -2996,44 +3184,14 @@ ServerApp::_CreateWindow(int32 code, BPrivate::LinkReceiver& link, bool -ServerApp::AddWindow(ServerWindow* window) +ServerApp::_HasWindowUnderMouse() { BAutolock locker(fWindowListLock); - return fWindowList.AddItem(window); -} - - -void -ServerApp::RemoveWindow(ServerWindow* window) -{ - BAutolock locker(fWindowListLock); - - fWindowList.RemoveItem(window); -} - - -bool -ServerApp::InWorkspace(int32 index) const -{ - BAutolock locker(fWindowListLock); - - // we could cache this, but then we'd have to recompute the cached - // value everytime a window has closed or changed workspaces - - // TODO: support initial application workspace! - for (int32 i = fWindowList.CountItems(); i-- > 0;) { ServerWindow* serverWindow = fWindowList.ItemAt(i); - const Window* window = serverWindow->Window(); - if (window == NULL || window->IsOffscreenWindow()) - continue; - - // only normal and unhidden windows count - - if (window->IsNormal() && !window->IsHidden() - && window->InWorkspace(index)) + if (fDesktop->ViewUnderMouse(serverWindow->Window()) != B_NULL_TOKEN) return true; } @@ -3041,110 +3199,27 @@ ServerApp::InWorkspace(int32 index) const } -uint32 -ServerApp::Workspaces() const -{ - uint32 workspaces = 0; - - BAutolock locker(fWindowListLock); - - // we could cache this, but then we'd have to recompute the cached - // value everytime a window has closed or changed workspaces - - for (int32 i = fWindowList.CountItems(); i-- > 0;) { - ServerWindow* serverWindow = fWindowList.ItemAt(i); - - const Window* window = serverWindow->Window(); - if (window == NULL || window->IsOffscreenWindow()) - continue; - - // only normal and unhidden windows count - - if (window->IsNormal() && !window->IsHidden()) - workspaces |= window->Workspaces(); - } - - // TODO: add initial application workspace! - return workspaces; -} - - -int32 -ServerApp::CountBitmaps() const -{ - return fBitmapList.CountItems(); -} - - -/*! \brief Looks up a ServerApp's ServerBitmap in its list - \param token ID token of the bitmap to find - \return The bitmap having that ID or NULL if not found -*/ ServerBitmap* -ServerApp::FindBitmap(int32 token) const +ServerApp::_FindBitmap(int32 token) const { - // TODO: we need to make sure the bitmap is ours?! - ServerBitmap* bitmap; - if (gTokenSpace.GetToken(token, kBitmapToken, (void**)&bitmap) == B_OK) - return bitmap; + ASSERT(fMapLock.IsLocked()); - return NULL; -} + BitmapMap::const_iterator iterator = fBitmapMap.find(token); + if (iterator == fBitmapMap.end()) + return NULL; - -int32 -ServerApp::CountPictures() const -{ - return fPictureList.CountItems(); + return iterator->second; } ServerPicture* -ServerApp::CreatePicture(const ServerPicture* original) +ServerApp::_FindPicture(int32 token) const { - ServerPicture* picture; - if (original != NULL) - picture = new(std::nothrow) ServerPicture(*original); - else - picture = new(std::nothrow) ServerPicture(); + ASSERT(fMapLock.IsLocked()); - if (picture != NULL) - fPictureList.AddItem(picture); + PictureMap::const_iterator iterator = fPictureMap.find(token); + if (iterator == fPictureMap.end()) + return NULL; - return picture; -} - - -ServerPicture* -ServerApp::FindPicture(int32 token) const -{ - // TODO: we need to make sure the picture is ours?! - ServerPicture* picture; - if (gTokenSpace.GetToken(token, kPictureToken, (void**)&picture) == B_OK) - return picture; - - return NULL; -} - - -bool -ServerApp::DeletePicture(int32 token) -{ - ServerPicture* picture = FindPicture(token); - if (picture == NULL) - return false; - - if (!fPictureList.RemoveItem(picture)) - return false; - - delete picture; - - return true; -} - - -team_id -ServerApp::ClientTeam() const -{ - return fClientTeam; + return iterator->second; } diff --git a/src/servers/app/ServerApp.h b/src/servers/app/ServerApp.h index 76936f9342..df762d84ee 100644 --- a/src/servers/app/ServerApp.h +++ b/src/servers/app/ServerApp.h @@ -64,7 +64,7 @@ public: void SetCurrentCursor(ServerCursor* cursor); ServerCursor* CurrentCursor() const; - team_id ClientTeam() const; + team_id ClientTeam() const { return fClientTeam; } const char* Signature() const { return fSignature.String(); } @@ -78,14 +78,15 @@ public: int32 InitialWorkspace() const { return fInitialWorkspace; } - int32 CountBitmaps() const; - ServerBitmap* FindBitmap(int32 token) const; + ServerBitmap* GetBitmap(int32 token) const; + bool BitmapAdded(ServerBitmap* bitmap); + void BitmapRemoved(ServerBitmap* bitmap); - int32 CountPictures() const; ServerPicture* CreatePicture( const ServerPicture* original = NULL); - ServerPicture* FindPicture(int32 token) const; - bool DeletePicture(int32 token); + ServerPicture* GetPicture(int32 token) const; + bool PictureAdded(ServerPicture* picture); + void PictureRemoved(ServerPicture* picture); Desktop* GetDesktop() const { return fDesktop; } @@ -94,17 +95,23 @@ public: BPrivate::BTokenSpace& ViewTokens() { return fViewTokens; } private: + virtual void _GetLooperName(char* name, size_t size); virtual void _DispatchMessage(int32 code, BPrivate::LinkReceiver& link); virtual void _MessageLooper(); - virtual void _GetLooperName(char* name, size_t size); status_t _CreateWindow(int32 code, BPrivate::LinkReceiver& link, port_id& clientReplyPort); bool _HasWindowUnderMouse(); + ServerBitmap* _FindBitmap(int32 token) const; + ServerPicture* _FindPicture(int32 token) const; + private: + typedef std::map BitmapMap; + typedef std::map PictureMap; + port_id fMessagePort; port_id fClientReplyPort; // our BApplication's event port @@ -133,8 +140,9 @@ private: // NOTE: Bitmaps and Pictures are stored globally, but ServerApps // remember which ones they own so that they can destroy them when // they quit. - BList fBitmapList; - BObjectList fPictureList; + mutable BLocker fMapLocker; + BitmapMap fBitmapMap; + PictureMap fPictureMap; ServerCursor* fAppCursor; ServerCursor* fViewCursor; diff --git a/src/servers/app/ServerBitmap.cpp b/src/servers/app/ServerBitmap.cpp index e1868b985f..5e32379046 100644 --- a/src/servers/app/ServerBitmap.cpp +++ b/src/servers/app/ServerBitmap.cpp @@ -15,11 +15,14 @@ #include #include +#include "BitmapManager.h" #include "ClientMemoryAllocator.h" #include "ColorConversion.h" #include "HWInterface.h" #include "InterfacePrivate.h" #include "Overlay.h" +#include "ServerApp.h" + using std::nothrow; using namespace BPrivate; @@ -127,6 +130,13 @@ ServerBitmap::Acquire() } +void +ServerBitmap::Release() +{ + gBitmapManager->DeleteBitmap(this); +} + + bool ServerBitmap::_Release() { @@ -212,10 +222,18 @@ ServerBitmap::Overlay() const } -void +bool ServerBitmap::SetOwner(ServerApp* owner) { - fOwner = owner; + if (fOwner != NULL) + fOwner->BitmapRemoved(this); + + if (owner != NULL && owner->BitmapAdded(this)) { + fOwner = owner; + return true; + } + + return false; } diff --git a/src/servers/app/ServerBitmap.h b/src/servers/app/ServerBitmap.h index 63159bbca0..638ce909e8 100644 --- a/src/servers/app/ServerBitmap.h +++ b/src/servers/app/ServerBitmap.h @@ -29,11 +29,12 @@ class ServerApp; all cursors. Every BBitmap has a shadow ServerBitmap object. */ class ServerBitmap { - public: +public: inline bool IsValid() const { return fBuffer != NULL; } void Acquire(); + void Release(); inline uint8* Bits() const { return fBuffer; } @@ -68,7 +69,7 @@ class ServerBitmap { void SetOverlay(::Overlay* overlay); ::Overlay* Overlay() const; - void SetOwner(ServerApp* owner); + bool SetOwner(ServerApp* owner); ServerApp* Owner() const; //! Does a shallow copy of the bitmap passed to it @@ -113,7 +114,7 @@ protected: }; class UtilityBitmap : public ServerBitmap { - public: +public: UtilityBitmap(BRect rect, color_space space, uint32 flags, int32 bytesperline = -1, screen_id screen = B_MAIN_SCREEN_ID); diff --git a/src/servers/app/ServerPicture.cpp b/src/servers/app/ServerPicture.cpp index 9f2ff0c7d6..2d23b5e9d5 100644 --- a/src/servers/app/ServerPicture.cpp +++ b/src/servers/app/ServerPicture.cpp @@ -460,12 +460,14 @@ static void draw_picture(View* view, BPoint where, int32 token) { ServerPicture* picture - = view->Window()->ServerWindow()->App()->FindPicture(token); + = view->Window()->ServerWindow()->App()->GetPicture(token); if (picture != NULL) { view->SetDrawingOrigin(where); view->PushState(); picture->Play(view); view->PopState(); + + picture->ReleaseReference(); } } @@ -781,7 +783,8 @@ ServerPicture::ServerPicture() : fFile(NULL), fPictures(NULL), - fUsurped(NULL) + fUsurped(NULL), + fOwner(NULL) { fToken = gTokenSpace.NewToken(kPictureToken, this); fData = new(std::nothrow) BMallocIO(); @@ -795,7 +798,8 @@ ServerPicture::ServerPicture(const ServerPicture& picture) fFile(NULL), fData(NULL), fPictures(NULL), - fUsurped(NULL) + fUsurped(NULL), + fOwner(NULL) { fToken = gTokenSpace.NewToken(kPictureToken, this); @@ -821,7 +825,8 @@ ServerPicture::ServerPicture(const char* fileName, int32 offset) fFile(NULL), fData(NULL), fPictures(NULL), - fUsurped(NULL) + fUsurped(NULL), + fOwner(NULL) { fToken = gTokenSpace.NewToken(kPictureToken, this); @@ -848,10 +853,27 @@ ServerPicture::~ServerPicture() delete fFile; gTokenSpace.RemoveToken(fToken); - // We only delete the subpictures list, not the subpictures - // themselves, since the ServerApp keeps them in a list and - // will delete them on quit. - delete fPictures; + if (fPictures != NULL) { + for (int32 i = fPictures->CountItems(); i-- > 0;) + fPictures->ItemAt(i)->ReleaseReference(); + + delete fPictures; + } +} + + +bool +ServerPicture::SetOwner(ServerApp* owner) +{ + if (fOwner != NULL) + fOwner->PictureRemoved(this); + + if (owner != NULL && owner->PictureAdded(this)) { + fOwner = owner; + return true; + } + + return false; } @@ -1082,3 +1104,13 @@ ServerPicture::ExportData(BPrivate::PortLink& link) fData->Seek(oldPosition, SEEK_SET); return status; } + + +void +ServerPicture::LastReferenceReleased() +{ + if (fOwner != NULL) + fOwner->PictureRemoved(this); + + delete this; +} diff --git a/src/servers/app/ServerPicture.h b/src/servers/app/ServerPicture.h index 3543f8db83..ca2ec12723 100644 --- a/src/servers/app/ServerPicture.h +++ b/src/servers/app/ServerPicture.h @@ -14,6 +14,7 @@ #include #include +#include class ServerApp; @@ -27,7 +28,7 @@ namespace BPrivate { class BList; -class ServerPicture : public PictureDataWriter { +class ServerPicture : public Referenceable, public PictureDataWriter { public: ServerPicture(); ServerPicture(const ServerPicture& other); @@ -36,6 +37,7 @@ public: ~ServerPicture(); int32 Token() { return fToken; } + bool SetOwner(ServerApp* owner); void EnterStateChange(); void ExitStateChange(); @@ -55,6 +57,9 @@ public: status_t ImportData(BPrivate::LinkReceiver& link); status_t ExportData(BPrivate::PortLink& link); +protected: + virtual void LastReferenceReleased(); + private: typedef BObjectList PictureList; @@ -63,6 +68,7 @@ private: BPositionIO* fData; PictureList* fPictures; ServerPicture* fUsurped; + ServerApp* fOwner; }; #endif // SERVER_PICTURE_H diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index 53b745f2fd..8f43eda2ca 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -1797,13 +1797,11 @@ fDesktop->LockSingleWindow(); rgb_color colorKey = {0}; if (status == B_OK) { - ServerBitmap* bitmap = fServerApp->FindBitmap(bitmapToken); + ServerBitmap* bitmap = fServerApp->GetBitmap(bitmapToken); if (bitmapToken == -1 || bitmap != NULL) { bool wasOverlay = fCurrentView->ViewBitmap() != NULL && fCurrentView->ViewBitmap()->Overlay() != NULL; - // TODO: this is a race condition: the bitmap could have been - // deleted in the mean time!! fCurrentView->SetViewBitmap(bitmap, srcRect, dstRect, resizingMode, options); @@ -1821,6 +1819,8 @@ fDesktop->LockSingleWindow(); bitmap->Overlay()->SetFlags(options); colorKey = bitmap->Overlay()->Color(); } + + bitmap->Release(); } else status = B_BAD_VALUE; } @@ -1862,20 +1862,17 @@ fDesktop->LockSingleWindow(); if (link.Read(&inverse) != B_OK) break; - // search for a picture with the specified token. - ServerPicture *picture = fServerApp->FindPicture(pictureToken); - // TODO: Increase that picture's reference count. - // (~ allocate a picture) + ServerPicture* picture = fServerApp->GetPicture(pictureToken); if (picture == NULL) break; BRegion region; // TODO: I think we also need the BView's token // I think PictureToRegion would fit better into the View class (?) - if (PictureToRegion(picture, region, inverse, where) < B_OK) - break; + if (PictureToRegion(picture, region, inverse, where) == B_OK) + fCurrentView->SetUserClipping(®ion); - fCurrentView->SetUserClipping(®ion); + picture->ReleaseReference(); break; } @@ -1996,12 +1993,13 @@ fDesktop->LockSingleWindow(); if (link.Read(buffer, bufferSize) == B_OK && dragMessage.Unflatten(buffer) == B_OK) { ServerBitmap* bitmap - = fServerApp->FindBitmap(bitmapToken); + = fServerApp->GetBitmap(bitmapToken); // TODO: possible deadlock fDesktop->UnlockSingleWindow(); fDesktop->EventDispatcher().SetDragMessage(dragMessage, bitmap, offset); fDesktop->LockSingleWindow(); + bitmap->Release(); } delete[] buffer; } @@ -2067,7 +2065,7 @@ fDesktop->LockSingleWindow(); { DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_PICTURE\n", Title())); - ServerPicture *picture = App()->CreatePicture(); + ServerPicture* picture = App()->CreatePicture(); picture->SyncState(fCurrentView); fCurrentView->SetPicture(picture); break; @@ -2078,13 +2076,17 @@ fDesktop->LockSingleWindow(); DTRACE(("ServerWindow %s: Message AS_VIEW_APPEND_TO_PICTURE\n", Title())); - int32 pictureToken; - link.Read(&pictureToken); - ServerPicture *picture = App()->FindPicture(pictureToken); - if (picture) + int32 token; + link.Read(&token); + + ServerPicture* picture = App()->GetPicture(token); + if (picture != NULL) picture->SyncState(fCurrentView); + fCurrentView->SetPicture(picture); - // we don't care if it's NULL + + if (picture != NULL) + picture->ReleaseReference(); break; } @@ -2093,7 +2095,7 @@ fDesktop->LockSingleWindow(); DTRACE(("ServerWindow %s: Message AS_VIEW_END_PICTURE\n", Title())); - ServerPicture *picture = fCurrentView->Picture(); + ServerPicture* picture = fCurrentView->Picture(); if (picture != NULL) { fCurrentView->SetPicture(NULL); fLink.StartMessage(B_OK); @@ -2263,9 +2265,8 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, options |= B_FILTER_BITMAP_BILINEAR; #endif - ServerBitmap* bitmap = fServerApp->FindBitmap(info.bitmapToken); - if (bitmap) { - + ServerBitmap* bitmap = fServerApp->GetBitmap(info.bitmapToken); + if (bitmap != NULL) { DTRACE(("ServerWindow %s: Message AS_VIEW_DRAW_BITMAP: " "View: %s, bitmap: %ld (size %ld x %ld), " "BRect(%.1f, %.1f, %.1f, %.1f) -> " @@ -2281,8 +2282,9 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, drawingEngine->DrawBitmap(bitmap, info.bitmapRect, info.viewRect, info.options); - } + bitmap->Release(); + } break; } case AS_STROKE_ARC: @@ -2716,18 +2718,20 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code, case AS_VIEW_DRAW_PICTURE: { int32 token; - if (link.Read(&token) == B_OK) { - BPoint where; - link.Read(&where); + link.Read(&token); - ServerPicture *picture = App()->FindPicture(token); + BPoint where; + if (link.Read(&where) == B_OK) { + ServerPicture* picture = App()->GetPicture(token); if (picture != NULL) { fCurrentView->PushState(); + fCurrentView->SetDrawingOrigin(where); - fCurrentView->PushState(); picture->Play(fCurrentView); + fCurrentView->PopState(); - fCurrentView->PopState(); + + picture->ReleaseReference(); } } break; @@ -3115,7 +3119,7 @@ ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver &link) ViewDrawBitmapInfo info; link.Read(&info); - ServerBitmap *bitmap = App()->FindBitmap(info.bitmapToken); + ServerBitmap* bitmap = App()->GetBitmap(info.bitmapToken); if (bitmap == NULL) break; @@ -3124,23 +3128,26 @@ ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver &link) bitmap->ColorSpace(), info.options, bitmap->Bits(), bitmap->BitsLength()); + bitmap->Release(); break; } case AS_VIEW_DRAW_PICTURE: { int32 token; - if (link.Read(&token) == B_OK) { - BPoint where; - link.Read(&where); + link.Read(&token); - ServerPicture *pictureToDraw = App()->FindPicture(token); - if (picture != NULL) { + BPoint where; + if (link.Read(&where) == B_OK) { + ServerPicture* pictureToDraw = App()->GetPicture(token); + if (pictureToDraw != NULL) { // We need to make a copy of the picture, since it can // change after it has been drawn - ServerPicture *copy = App()->CreatePicture(pictureToDraw); + ServerPicture* copy = App()->CreatePicture(pictureToDraw); picture->NestPicture(copy); picture->WriteDrawPicture(where, copy->Token()); + + pictureToDraw->ReleaseReference(); } } break; @@ -3183,21 +3190,26 @@ ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver &link) case AS_VIEW_APPEND_TO_PICTURE: { - int32 pictureToken; - link.Read(&pictureToken); - ServerPicture *appendPicture = App()->FindPicture(pictureToken); - if (appendPicture) { + int32 token; + link.Read(&token); + + ServerPicture* appendPicture = App()->GetPicture(token); + if (appendPicture != NULL) { //picture->SyncState(fCurrentView); appendPicture->Usurp(picture); } + fCurrentView->SetPicture(appendPicture); - // we don't care if it's NULL + + if (appendPicture != NULL) + appendPicture->ReleaseReference(); break; } case AS_VIEW_END_PICTURE: { - ServerPicture *steppedDown = picture->StepDown(); + ServerPicture* steppedDown = picture->StepDown(); + fCurrentView->SetPicture(steppedDown); fLink.StartMessage(B_OK); fLink.Attach(picture->Token()); diff --git a/src/servers/app/View.cpp b/src/servers/app/View.cpp index b496683d16..84c88887c8 100644 --- a/src/servers/app/View.cpp +++ b/src/servers/app/View.cpp @@ -154,7 +154,7 @@ View::InitCheck() const { if (fDrawState == NULL) return B_NO_MEMORY; - + return B_OK; } @@ -1291,7 +1291,7 @@ View::SetEventMask(uint32 eventMask, uint32 options) void -View::SetCursor(ServerCursor *cursor) +View::SetCursor(ServerCursor* cursor) { if (cursor == fCursor) return; @@ -1307,9 +1307,18 @@ View::SetCursor(ServerCursor *cursor) void -View::SetPicture(ServerPicture *picture) +View::SetPicture(ServerPicture* picture) { + if (picture == fPicture) + return; + + if (fPicture != NULL) + fPicture->ReleaseReference(); + fPicture = picture; + + if (fPicture != NULL) + fPicture->AcquireReference(); }