* ServerApp's bitmap and picture handling was completely broken, as it ignored

concurrency as well as reference counting, causing occasional crashes and
  memory corruption.
* ServerPicture now subclasses Referenceable, and will notify its owner when
  it's going to be deleted. This might bring some regressions, although I
  couldn't spot anything wrong yet.
* ServerBitmap will now also notify its owner when it's going to be deleted as
  well.
* Switched from the former picture/bitmap lists to a std::map. This also solves
  the issue of not checking whether or not the bitmap/picture actually belongs
  to the ServerApp (before, all apps could access and delete all
  pictures/bitmaps)
* Introduced a new fMapLocker that guards the new maps.
* ServerWindow now uses GetBitmap()/GetPicture(), and gives up its reference
  after use.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33876 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2009-11-04 13:28:32 +00:00
parent 1ff7e27441
commit 85a7877f80
10 changed files with 495 additions and 330 deletions
+3
View File
@@ -220,6 +220,9 @@ BitmapManager::DeleteBitmap(ServerBitmap* bitmap)
if (bitmap->Overlay() != NULL) if (bitmap->Overlay() != NULL)
fOverlays.RemoveItem(bitmap); fOverlays.RemoveItem(bitmap);
if (bitmap->Owner() != NULL)
bitmap->Owner()->BitmapRemoved(bitmap);
if (fBitmapList.RemoveItem(bitmap)) if (fBitmapList.RemoveItem(bitmap))
delete bitmap; delete bitmap;
} }
@@ -24,6 +24,7 @@ OffscreenServerWindow::OffscreenServerWindow(const char *title, ServerApp *app,
OffscreenServerWindow::~OffscreenServerWindow() OffscreenServerWindow::~OffscreenServerWindow()
{ {
fBitmap->Release();
} }
+338 -263
View File
@@ -97,6 +97,7 @@ ServerApp::ServerApp(Desktop* desktop, port_id clientReplyPort,
fClientTeam(clientTeam), fClientTeam(clientTeam),
fWindowListLock("window list"), fWindowListLock("window list"),
fTemporaryDisplayModeChange(0), fTemporaryDisplayModeChange(0),
fMapLocker("server app maps"),
fAppCursor(NULL), fAppCursor(NULL),
fViewCursor(NULL), fViewCursor(NULL),
fCursorHideLevel(0), fCursorHideLevel(0),
@@ -188,12 +189,20 @@ ServerApp::~ServerApp()
fWindowListLock.Lock(); fWindowListLock.Lock();
} }
for (int32 i = fBitmapList.CountItems(); i-- > 0;) { fMapLocker.Lock();
gBitmapManager->DeleteBitmap((ServerBitmap*)fBitmapList.ItemAt(i));
while (!fBitmapMap.empty()) {
ServerBitmap* bitmap = fBitmapMap.begin()->second;
fBitmapMap.erase(fBitmapMap.begin());
bitmap->Release();
} }
for (int32 i = fPictureList.CountItems(); i-- > 0;) { while (!fPictureMap.empty()) {
delete fPictureList.ItemAt(i); ServerPicture* picture = fPictureMap.begin()->second;
fPictureMap.erase(fPictureMap.begin());
picture->ReleaseReference();
} }
fDesktop->GetCursorManager().DeleteCursors(fClientTeam); 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 /*! \brief Sets the ServerApp's active status
\param value The new status of the ServerApp. \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 void
ServerApp::SetCurrentCursor(ServerCursor* cursor) 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 void
ServerApp::_GetLooperName(char* name, size_t length) 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<port_id>(fMessagePort);
fLink.Attach<area_id>(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_id>(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 /*! \brief Handler function for BApplication API messages
\param code Identifier code for the message. Equivalent to BMessage::what \param code Identifier code for the message. Equivalent to BMessage::what
\param buffer Any attachments \param buffer Any attachments
@@ -653,9 +743,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
STRACE(("ServerApp %s: Create Bitmap (%.1fx%.1f)\n", STRACE(("ServerApp %s: Create Bitmap (%.1fx%.1f)\n",
Signature(), frame.Width() + 1, frame.Height() + 1)); Signature(), frame.Width() + 1, frame.Height() + 1));
if (bitmap != NULL && fBitmapList.AddItem(bitmap)) { if (bitmap != NULL && bitmap->SetOwner(this)) {
bitmap->SetOwner(this);
fLink.StartMessage(B_OK); fLink.StartMessage(B_OK);
fLink.Attach<int32>(bitmap->Token()); fLink.Attach<int32>(bitmap->Token());
fLink.Attach<uint8>(allocationFlags); fLink.Attach<uint8>(allocationFlags);
@@ -665,11 +753,11 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
fLink.Attach<int32>( fLink.Attach<int32>(
fMemoryAllocator.AreaOffset(bitmap->AllocationCookie())); fMemoryAllocator.AreaOffset(bitmap->AllocationCookie()));
if (allocationFlags & kFramebuffer) if ((allocationFlags & kFramebuffer) != 0)
fLink.Attach<int32>(bitmap->BytesPerRow()); fLink.Attach<int32>(bitmap->BytesPerRow());
} else { } else {
if (bitmap != NULL) if (bitmap != NULL)
gBitmapManager->DeleteBitmap(bitmap); bitmap->Release();
fLink.StartMessage(B_NO_MEMORY); fLink.StartMessage(B_NO_MEMORY);
} }
@@ -689,13 +777,17 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
int32 token; int32 token;
link.Read<int32>(&token); link.Read<int32>(&token);
ServerBitmap *bitmap = FindBitmap(token); fMapLocker.Lock();
if (bitmap && fBitmapList.RemoveItem(bitmap)) {
ServerBitmap* bitmap = _FindBitmap(token);
if (bitmap != NULL) {
STRACE(("ServerApp %s: Deleting Bitmap %ld\n", Signature(), STRACE(("ServerApp %s: Deleting Bitmap %ld\n", Signature(),
token)); token));
gBitmapManager->DeleteBitmap(bitmap); bitmap->Release();
} }
fMapLocker.Unlock();
break; break;
} }
case AS_GET_BITMAP_OVERLAY_RESTRICTIONS: case AS_GET_BITMAP_OVERLAY_RESTRICTIONS:
@@ -707,13 +799,15 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
if (link.Read<int32>(&token) != B_OK) if (link.Read<int32>(&token) != B_OK)
break; break;
ServerBitmap *bitmap = FindBitmap(token); ServerBitmap* bitmap = GetBitmap(token);
if (bitmap != NULL) { if (bitmap != NULL) {
STRACE(("ServerApp %s: Get overlay restrictions for bitmap " STRACE(("ServerApp %s: Get overlay restrictions for bitmap "
"%ld\n", Signature(), token)); "%ld\n", Signature(), token));
status = fDesktop->HWInterface()->GetOverlayRestrictions( status = fDesktop->HWInterface()->GetOverlayRestrictions(
bitmap->Overlay(), &restrictions); bitmap->Overlay(), &restrictions);
bitmap->Release();
} }
fLink.StartMessage(status); fLink.StartMessage(status);
@@ -752,7 +846,9 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
for (int32 i = 0; i < subPicturesCount; i++) { for (int32 i = 0; i < subPicturesCount; i++) {
int32 token = -1; int32 token = -1;
link.Read<int32>(&token); link.Read<int32>(&token);
if (ServerPicture* subPicture = FindPicture(token))
// TODO: do we actually need another reference here?
if (ServerPicture* subPicture = GetPicture(token))
picture->NestPicture(subPicture); picture->NestPicture(subPicture);
} }
status = picture->ImportData(link); status = picture->ImportData(link);
@@ -771,8 +867,13 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
{ {
STRACE(("ServerApp %s: Delete Picture\n", Signature())); STRACE(("ServerApp %s: Delete Picture\n", Signature()));
int32 token; int32 token;
if (link.Read<int32>(&token) == B_OK) if (link.Read<int32>(&token) == B_OK) {
DeletePicture(token); BAutolock _(fMapLocker);
ServerPicture* picture = _FindPicture(token);
if (picture != NULL)
picture->ReleaseReference();
}
break; break;
} }
@@ -782,7 +883,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
int32 token; int32 token;
ServerPicture* original = NULL; ServerPicture* original = NULL;
if (link.Read<int32>(&token) == B_OK) if (link.Read<int32>(&token) == B_OK)
original = FindPicture(token); original = GetPicture(token);
if (original != NULL) { if (original != NULL) {
ServerPicture* cloned = CreatePicture(original); ServerPicture* cloned = CreatePicture(original);
@@ -791,6 +892,8 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
fLink.Attach<int32>(cloned->Token()); fLink.Attach<int32>(cloned->Token());
} else } else
fLink.StartMessage(B_NO_MEMORY); fLink.StartMessage(B_NO_MEMORY);
original->ReleaseReference();
} else } else
fLink.StartMessage(B_BAD_VALUE); fLink.StartMessage(B_BAD_VALUE);
@@ -803,10 +906,11 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
STRACE(("ServerApp %s: Download Picture\n", Signature())); STRACE(("ServerApp %s: Download Picture\n", Signature()));
int32 token; int32 token;
link.Read<int32>(&token); link.Read<int32>(&token);
ServerPicture* picture = FindPicture(token); ServerPicture* picture = GetPicture(token);
if (picture != NULL) { if (picture != NULL) {
picture->ExportData(fLink); picture->ExportData(fLink);
// ExportData() calls StartMessage() already // ExportData() calls StartMessage() already
picture->ReleaseReference();
} else } else
fLink.StartMessage(B_ERROR); fLink.StartMessage(B_ERROR);
@@ -2740,8 +2844,8 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
case AS_READ_BITMAP: case AS_READ_BITMAP:
{ {
STRACE(("ServerApp %s: AS_READ_BITMAP\n", Signature())); STRACE(("ServerApp %s: AS_READ_BITMAP\n", Signature()));
int32 bitmapToken; int32 token;
link.Read<int32>(&bitmapToken); link.Read<int32>(&token);
bool drawCursor = true; bool drawCursor = true;
link.Read<bool>(&drawCursor); link.Read<bool>(&drawCursor);
@@ -2749,13 +2853,15 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
BRect bounds; BRect bounds;
link.Read<BRect>(&bounds); link.Read<BRect>(&bounds);
ServerBitmap *bitmap = FindBitmap(bitmapToken); ServerBitmap* bitmap = GetBitmap(token);
if (bitmap != NULL) { if (bitmap != NULL) {
if (fDesktop->GetDrawingEngine()->ReadBitmap(bitmap, if (fDesktop->GetDrawingEngine()->ReadBitmap(bitmap,
drawCursor, bounds) == B_OK) { drawCursor, bounds) == B_OK) {
fLink.StartMessage(B_OK); fLink.StartMessage(B_OK);
} else } else
fLink.StartMessage(B_BAD_VALUE); fLink.StartMessage(B_BAD_VALUE);
gBitmapManager->DeleteBitmap(bitmap);
} else } else
fLink.StartMessage(B_BAD_VALUE); 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<port_id>(fMessagePort);
fLink.Attach<area_id>(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_id>(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 status_t
ServerApp::_CreateWindow(int32 code, BPrivate::LinkReceiver& link, ServerApp::_CreateWindow(int32 code, BPrivate::LinkReceiver& link,
port_id& clientReplyPort) port_id& clientReplyPort)
@@ -2960,7 +3148,7 @@ ServerApp::_CreateWindow(int32 code, BPrivate::LinkReceiver& link,
ServerWindow *window = NULL; ServerWindow *window = NULL;
if (code == AS_CREATE_OFFSCREEN_WINDOW) { if (code == AS_CREATE_OFFSCREEN_WINDOW) {
ServerBitmap* bitmap = FindBitmap(bitmapToken); ServerBitmap* bitmap = GetBitmap(bitmapToken);
if (bitmap != NULL) { if (bitmap != NULL) {
window = new (nothrow) OffscreenServerWindow(title, this, window = new (nothrow) OffscreenServerWindow(title, this,
@@ -2996,44 +3184,14 @@ ServerApp::_CreateWindow(int32 code, BPrivate::LinkReceiver& link,
bool bool
ServerApp::AddWindow(ServerWindow* window) ServerApp::_HasWindowUnderMouse()
{ {
BAutolock locker(fWindowListLock); 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;) { for (int32 i = fWindowList.CountItems(); i-- > 0;) {
ServerWindow* serverWindow = fWindowList.ItemAt(i); ServerWindow* serverWindow = fWindowList.ItemAt(i);
const Window* window = serverWindow->Window(); if (fDesktop->ViewUnderMouse(serverWindow->Window()) != B_NULL_TOKEN)
if (window == NULL || window->IsOffscreenWindow())
continue;
// only normal and unhidden windows count
if (window->IsNormal() && !window->IsHidden()
&& window->InWorkspace(index))
return true; 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* ServerBitmap*
ServerApp::FindBitmap(int32 token) const ServerApp::_FindBitmap(int32 token) const
{ {
// TODO: we need to make sure the bitmap is ours?! ASSERT(fMapLock.IsLocked());
ServerBitmap* bitmap;
if (gTokenSpace.GetToken(token, kBitmapToken, (void**)&bitmap) == B_OK)
return bitmap;
return NULL; BitmapMap::const_iterator iterator = fBitmapMap.find(token);
} if (iterator == fBitmapMap.end())
return NULL;
return iterator->second;
int32
ServerApp::CountPictures() const
{
return fPictureList.CountItems();
} }
ServerPicture* ServerPicture*
ServerApp::CreatePicture(const ServerPicture* original) ServerApp::_FindPicture(int32 token) const
{ {
ServerPicture* picture; ASSERT(fMapLock.IsLocked());
if (original != NULL)
picture = new(std::nothrow) ServerPicture(*original);
else
picture = new(std::nothrow) ServerPicture();
if (picture != NULL) PictureMap::const_iterator iterator = fPictureMap.find(token);
fPictureList.AddItem(picture); if (iterator == fPictureMap.end())
return NULL;
return picture; return iterator->second;
}
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;
} }
+17 -9
View File
@@ -64,7 +64,7 @@ public:
void SetCurrentCursor(ServerCursor* cursor); void SetCurrentCursor(ServerCursor* cursor);
ServerCursor* CurrentCursor() const; ServerCursor* CurrentCursor() const;
team_id ClientTeam() const; team_id ClientTeam() const { return fClientTeam; }
const char* Signature() const const char* Signature() const
{ return fSignature.String(); } { return fSignature.String(); }
@@ -78,14 +78,15 @@ public:
int32 InitialWorkspace() const int32 InitialWorkspace() const
{ return fInitialWorkspace; } { return fInitialWorkspace; }
int32 CountBitmaps() const; ServerBitmap* GetBitmap(int32 token) const;
ServerBitmap* FindBitmap(int32 token) const; bool BitmapAdded(ServerBitmap* bitmap);
void BitmapRemoved(ServerBitmap* bitmap);
int32 CountPictures() const;
ServerPicture* CreatePicture( ServerPicture* CreatePicture(
const ServerPicture* original = NULL); const ServerPicture* original = NULL);
ServerPicture* FindPicture(int32 token) const; ServerPicture* GetPicture(int32 token) const;
bool DeletePicture(int32 token); bool PictureAdded(ServerPicture* picture);
void PictureRemoved(ServerPicture* picture);
Desktop* GetDesktop() const { return fDesktop; } Desktop* GetDesktop() const { return fDesktop; }
@@ -94,17 +95,23 @@ public:
BPrivate::BTokenSpace& ViewTokens() { return fViewTokens; } BPrivate::BTokenSpace& ViewTokens() { return fViewTokens; }
private: private:
virtual void _GetLooperName(char* name, size_t size);
virtual void _DispatchMessage(int32 code, virtual void _DispatchMessage(int32 code,
BPrivate::LinkReceiver& link); BPrivate::LinkReceiver& link);
virtual void _MessageLooper(); virtual void _MessageLooper();
virtual void _GetLooperName(char* name, size_t size);
status_t _CreateWindow(int32 code, status_t _CreateWindow(int32 code,
BPrivate::LinkReceiver& link, BPrivate::LinkReceiver& link,
port_id& clientReplyPort); port_id& clientReplyPort);
bool _HasWindowUnderMouse(); bool _HasWindowUnderMouse();
ServerBitmap* _FindBitmap(int32 token) const;
ServerPicture* _FindPicture(int32 token) const;
private: private:
typedef std::map<int32, ServerBitmap*> BitmapMap;
typedef std::map<int32, ServerPicture*> PictureMap;
port_id fMessagePort; port_id fMessagePort;
port_id fClientReplyPort; port_id fClientReplyPort;
// our BApplication's event port // our BApplication's event port
@@ -133,8 +140,9 @@ private:
// NOTE: Bitmaps and Pictures are stored globally, but ServerApps // NOTE: Bitmaps and Pictures are stored globally, but ServerApps
// remember which ones they own so that they can destroy them when // remember which ones they own so that they can destroy them when
// they quit. // they quit.
BList fBitmapList; mutable BLocker fMapLocker;
BObjectList<ServerPicture> fPictureList; BitmapMap fBitmapMap;
PictureMap fPictureMap;
ServerCursor* fAppCursor; ServerCursor* fAppCursor;
ServerCursor* fViewCursor; ServerCursor* fViewCursor;
+20 -2
View File
@@ -15,11 +15,14 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "BitmapManager.h"
#include "ClientMemoryAllocator.h" #include "ClientMemoryAllocator.h"
#include "ColorConversion.h" #include "ColorConversion.h"
#include "HWInterface.h" #include "HWInterface.h"
#include "InterfacePrivate.h" #include "InterfacePrivate.h"
#include "Overlay.h" #include "Overlay.h"
#include "ServerApp.h"
using std::nothrow; using std::nothrow;
using namespace BPrivate; using namespace BPrivate;
@@ -127,6 +130,13 @@ ServerBitmap::Acquire()
} }
void
ServerBitmap::Release()
{
gBitmapManager->DeleteBitmap(this);
}
bool bool
ServerBitmap::_Release() ServerBitmap::_Release()
{ {
@@ -212,10 +222,18 @@ ServerBitmap::Overlay() const
} }
void bool
ServerBitmap::SetOwner(ServerApp* owner) ServerBitmap::SetOwner(ServerApp* owner)
{ {
fOwner = owner; if (fOwner != NULL)
fOwner->BitmapRemoved(this);
if (owner != NULL && owner->BitmapAdded(this)) {
fOwner = owner;
return true;
}
return false;
} }
+4 -3
View File
@@ -29,11 +29,12 @@ class ServerApp;
all cursors. Every BBitmap has a shadow ServerBitmap object. all cursors. Every BBitmap has a shadow ServerBitmap object.
*/ */
class ServerBitmap { class ServerBitmap {
public: public:
inline bool IsValid() const inline bool IsValid() const
{ return fBuffer != NULL; } { return fBuffer != NULL; }
void Acquire(); void Acquire();
void Release();
inline uint8* Bits() const inline uint8* Bits() const
{ return fBuffer; } { return fBuffer; }
@@ -68,7 +69,7 @@ class ServerBitmap {
void SetOverlay(::Overlay* overlay); void SetOverlay(::Overlay* overlay);
::Overlay* Overlay() const; ::Overlay* Overlay() const;
void SetOwner(ServerApp* owner); bool SetOwner(ServerApp* owner);
ServerApp* Owner() const; ServerApp* Owner() const;
//! Does a shallow copy of the bitmap passed to it //! Does a shallow copy of the bitmap passed to it
@@ -113,7 +114,7 @@ protected:
}; };
class UtilityBitmap : public ServerBitmap { class UtilityBitmap : public ServerBitmap {
public: public:
UtilityBitmap(BRect rect, color_space space, UtilityBitmap(BRect rect, color_space space,
uint32 flags, int32 bytesperline = -1, uint32 flags, int32 bytesperline = -1,
screen_id screen = B_MAIN_SCREEN_ID); screen_id screen = B_MAIN_SCREEN_ID);
+40 -8
View File
@@ -460,12 +460,14 @@ static void
draw_picture(View* view, BPoint where, int32 token) draw_picture(View* view, BPoint where, int32 token)
{ {
ServerPicture* picture ServerPicture* picture
= view->Window()->ServerWindow()->App()->FindPicture(token); = view->Window()->ServerWindow()->App()->GetPicture(token);
if (picture != NULL) { if (picture != NULL) {
view->SetDrawingOrigin(where); view->SetDrawingOrigin(where);
view->PushState(); view->PushState();
picture->Play(view); picture->Play(view);
view->PopState(); view->PopState();
picture->ReleaseReference();
} }
} }
@@ -781,7 +783,8 @@ ServerPicture::ServerPicture()
: :
fFile(NULL), fFile(NULL),
fPictures(NULL), fPictures(NULL),
fUsurped(NULL) fUsurped(NULL),
fOwner(NULL)
{ {
fToken = gTokenSpace.NewToken(kPictureToken, this); fToken = gTokenSpace.NewToken(kPictureToken, this);
fData = new(std::nothrow) BMallocIO(); fData = new(std::nothrow) BMallocIO();
@@ -795,7 +798,8 @@ ServerPicture::ServerPicture(const ServerPicture& picture)
fFile(NULL), fFile(NULL),
fData(NULL), fData(NULL),
fPictures(NULL), fPictures(NULL),
fUsurped(NULL) fUsurped(NULL),
fOwner(NULL)
{ {
fToken = gTokenSpace.NewToken(kPictureToken, this); fToken = gTokenSpace.NewToken(kPictureToken, this);
@@ -821,7 +825,8 @@ ServerPicture::ServerPicture(const char* fileName, int32 offset)
fFile(NULL), fFile(NULL),
fData(NULL), fData(NULL),
fPictures(NULL), fPictures(NULL),
fUsurped(NULL) fUsurped(NULL),
fOwner(NULL)
{ {
fToken = gTokenSpace.NewToken(kPictureToken, this); fToken = gTokenSpace.NewToken(kPictureToken, this);
@@ -848,10 +853,27 @@ ServerPicture::~ServerPicture()
delete fFile; delete fFile;
gTokenSpace.RemoveToken(fToken); gTokenSpace.RemoveToken(fToken);
// We only delete the subpictures list, not the subpictures if (fPictures != NULL) {
// themselves, since the ServerApp keeps them in a list and for (int32 i = fPictures->CountItems(); i-- > 0;)
// will delete them on quit. fPictures->ItemAt(i)->ReleaseReference();
delete fPictures;
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); fData->Seek(oldPosition, SEEK_SET);
return status; return status;
} }
void
ServerPicture::LastReferenceReleased()
{
if (fOwner != NULL)
fOwner->PictureRemoved(this);
delete this;
}
+7 -1
View File
@@ -14,6 +14,7 @@
#include <ObjectList.h> #include <ObjectList.h>
#include <PictureDataWriter.h> #include <PictureDataWriter.h>
#include <Referenceable.h>
class ServerApp; class ServerApp;
@@ -27,7 +28,7 @@ namespace BPrivate {
class BList; class BList;
class ServerPicture : public PictureDataWriter { class ServerPicture : public Referenceable, public PictureDataWriter {
public: public:
ServerPicture(); ServerPicture();
ServerPicture(const ServerPicture& other); ServerPicture(const ServerPicture& other);
@@ -36,6 +37,7 @@ public:
~ServerPicture(); ~ServerPicture();
int32 Token() { return fToken; } int32 Token() { return fToken; }
bool SetOwner(ServerApp* owner);
void EnterStateChange(); void EnterStateChange();
void ExitStateChange(); void ExitStateChange();
@@ -55,6 +57,9 @@ public:
status_t ImportData(BPrivate::LinkReceiver& link); status_t ImportData(BPrivate::LinkReceiver& link);
status_t ExportData(BPrivate::PortLink& link); status_t ExportData(BPrivate::PortLink& link);
protected:
virtual void LastReferenceReleased();
private: private:
typedef BObjectList<ServerPicture> PictureList; typedef BObjectList<ServerPicture> PictureList;
@@ -63,6 +68,7 @@ private:
BPositionIO* fData; BPositionIO* fData;
PictureList* fPictures; PictureList* fPictures;
ServerPicture* fUsurped; ServerPicture* fUsurped;
ServerApp* fOwner;
}; };
#endif // SERVER_PICTURE_H #endif // SERVER_PICTURE_H
+53 -41
View File
@@ -1797,13 +1797,11 @@ fDesktop->LockSingleWindow();
rgb_color colorKey = {0}; rgb_color colorKey = {0};
if (status == B_OK) { if (status == B_OK) {
ServerBitmap* bitmap = fServerApp->FindBitmap(bitmapToken); ServerBitmap* bitmap = fServerApp->GetBitmap(bitmapToken);
if (bitmapToken == -1 || bitmap != NULL) { if (bitmapToken == -1 || bitmap != NULL) {
bool wasOverlay = fCurrentView->ViewBitmap() != NULL bool wasOverlay = fCurrentView->ViewBitmap() != NULL
&& fCurrentView->ViewBitmap()->Overlay() != 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, fCurrentView->SetViewBitmap(bitmap, srcRect, dstRect,
resizingMode, options); resizingMode, options);
@@ -1821,6 +1819,8 @@ fDesktop->LockSingleWindow();
bitmap->Overlay()->SetFlags(options); bitmap->Overlay()->SetFlags(options);
colorKey = bitmap->Overlay()->Color(); colorKey = bitmap->Overlay()->Color();
} }
bitmap->Release();
} else } else
status = B_BAD_VALUE; status = B_BAD_VALUE;
} }
@@ -1862,20 +1862,17 @@ fDesktop->LockSingleWindow();
if (link.Read<bool>(&inverse) != B_OK) if (link.Read<bool>(&inverse) != B_OK)
break; break;
// search for a picture with the specified token. ServerPicture* picture = fServerApp->GetPicture(pictureToken);
ServerPicture *picture = fServerApp->FindPicture(pictureToken);
// TODO: Increase that picture's reference count.
// (~ allocate a picture)
if (picture == NULL) if (picture == NULL)
break; break;
BRegion region; BRegion region;
// TODO: I think we also need the BView's token // TODO: I think we also need the BView's token
// I think PictureToRegion would fit better into the View class (?) // I think PictureToRegion would fit better into the View class (?)
if (PictureToRegion(picture, region, inverse, where) < B_OK) if (PictureToRegion(picture, region, inverse, where) == B_OK)
break; fCurrentView->SetUserClipping(&region);
fCurrentView->SetUserClipping(&region); picture->ReleaseReference();
break; break;
} }
@@ -1996,12 +1993,13 @@ fDesktop->LockSingleWindow();
if (link.Read(buffer, bufferSize) == B_OK if (link.Read(buffer, bufferSize) == B_OK
&& dragMessage.Unflatten(buffer) == B_OK) { && dragMessage.Unflatten(buffer) == B_OK) {
ServerBitmap* bitmap ServerBitmap* bitmap
= fServerApp->FindBitmap(bitmapToken); = fServerApp->GetBitmap(bitmapToken);
// TODO: possible deadlock // TODO: possible deadlock
fDesktop->UnlockSingleWindow(); fDesktop->UnlockSingleWindow();
fDesktop->EventDispatcher().SetDragMessage(dragMessage, fDesktop->EventDispatcher().SetDragMessage(dragMessage,
bitmap, offset); bitmap, offset);
fDesktop->LockSingleWindow(); fDesktop->LockSingleWindow();
bitmap->Release();
} }
delete[] buffer; delete[] buffer;
} }
@@ -2067,7 +2065,7 @@ fDesktop->LockSingleWindow();
{ {
DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_PICTURE\n", DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_PICTURE\n",
Title())); Title()));
ServerPicture *picture = App()->CreatePicture(); ServerPicture* picture = App()->CreatePicture();
picture->SyncState(fCurrentView); picture->SyncState(fCurrentView);
fCurrentView->SetPicture(picture); fCurrentView->SetPicture(picture);
break; break;
@@ -2078,13 +2076,17 @@ fDesktop->LockSingleWindow();
DTRACE(("ServerWindow %s: Message AS_VIEW_APPEND_TO_PICTURE\n", DTRACE(("ServerWindow %s: Message AS_VIEW_APPEND_TO_PICTURE\n",
Title())); Title()));
int32 pictureToken; int32 token;
link.Read<int32>(&pictureToken); link.Read<int32>(&token);
ServerPicture *picture = App()->FindPicture(pictureToken);
if (picture) ServerPicture* picture = App()->GetPicture(token);
if (picture != NULL)
picture->SyncState(fCurrentView); picture->SyncState(fCurrentView);
fCurrentView->SetPicture(picture); fCurrentView->SetPicture(picture);
// we don't care if it's NULL
if (picture != NULL)
picture->ReleaseReference();
break; break;
} }
@@ -2093,7 +2095,7 @@ fDesktop->LockSingleWindow();
DTRACE(("ServerWindow %s: Message AS_VIEW_END_PICTURE\n", DTRACE(("ServerWindow %s: Message AS_VIEW_END_PICTURE\n",
Title())); Title()));
ServerPicture *picture = fCurrentView->Picture(); ServerPicture* picture = fCurrentView->Picture();
if (picture != NULL) { if (picture != NULL) {
fCurrentView->SetPicture(NULL); fCurrentView->SetPicture(NULL);
fLink.StartMessage(B_OK); fLink.StartMessage(B_OK);
@@ -2263,9 +2265,8 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code,
options |= B_FILTER_BITMAP_BILINEAR; options |= B_FILTER_BITMAP_BILINEAR;
#endif #endif
ServerBitmap* bitmap = fServerApp->FindBitmap(info.bitmapToken); ServerBitmap* bitmap = fServerApp->GetBitmap(info.bitmapToken);
if (bitmap) { if (bitmap != NULL) {
DTRACE(("ServerWindow %s: Message AS_VIEW_DRAW_BITMAP: " DTRACE(("ServerWindow %s: Message AS_VIEW_DRAW_BITMAP: "
"View: %s, bitmap: %ld (size %ld x %ld), " "View: %s, bitmap: %ld (size %ld x %ld), "
"BRect(%.1f, %.1f, %.1f, %.1f) -> " "BRect(%.1f, %.1f, %.1f, %.1f) -> "
@@ -2281,8 +2282,9 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code,
drawingEngine->DrawBitmap(bitmap, info.bitmapRect, drawingEngine->DrawBitmap(bitmap, info.bitmapRect,
info.viewRect, info.options); info.viewRect, info.options);
}
bitmap->Release();
}
break; break;
} }
case AS_STROKE_ARC: case AS_STROKE_ARC:
@@ -2716,18 +2718,20 @@ ServerWindow::_DispatchViewDrawingMessage(int32 code,
case AS_VIEW_DRAW_PICTURE: case AS_VIEW_DRAW_PICTURE:
{ {
int32 token; int32 token;
if (link.Read<int32>(&token) == B_OK) { link.Read<int32>(&token);
BPoint where;
link.Read<BPoint>(&where);
ServerPicture *picture = App()->FindPicture(token); BPoint where;
if (link.Read<BPoint>(&where) == B_OK) {
ServerPicture* picture = App()->GetPicture(token);
if (picture != NULL) { if (picture != NULL) {
fCurrentView->PushState(); fCurrentView->PushState();
fCurrentView->SetDrawingOrigin(where); fCurrentView->SetDrawingOrigin(where);
fCurrentView->PushState();
picture->Play(fCurrentView); picture->Play(fCurrentView);
fCurrentView->PopState(); fCurrentView->PopState();
fCurrentView->PopState();
picture->ReleaseReference();
} }
} }
break; break;
@@ -3115,7 +3119,7 @@ ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver &link)
ViewDrawBitmapInfo info; ViewDrawBitmapInfo info;
link.Read<ViewDrawBitmapInfo>(&info); link.Read<ViewDrawBitmapInfo>(&info);
ServerBitmap *bitmap = App()->FindBitmap(info.bitmapToken); ServerBitmap* bitmap = App()->GetBitmap(info.bitmapToken);
if (bitmap == NULL) if (bitmap == NULL)
break; break;
@@ -3124,23 +3128,26 @@ ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver &link)
bitmap->ColorSpace(), info.options, bitmap->Bits(), bitmap->ColorSpace(), info.options, bitmap->Bits(),
bitmap->BitsLength()); bitmap->BitsLength());
bitmap->Release();
break; break;
} }
case AS_VIEW_DRAW_PICTURE: case AS_VIEW_DRAW_PICTURE:
{ {
int32 token; int32 token;
if (link.Read<int32>(&token) == B_OK) { link.Read<int32>(&token);
BPoint where;
link.Read<BPoint>(&where);
ServerPicture *pictureToDraw = App()->FindPicture(token); BPoint where;
if (picture != NULL) { if (link.Read<BPoint>(&where) == B_OK) {
ServerPicture* pictureToDraw = App()->GetPicture(token);
if (pictureToDraw != NULL) {
// We need to make a copy of the picture, since it can // We need to make a copy of the picture, since it can
// change after it has been drawn // change after it has been drawn
ServerPicture *copy = App()->CreatePicture(pictureToDraw); ServerPicture* copy = App()->CreatePicture(pictureToDraw);
picture->NestPicture(copy); picture->NestPicture(copy);
picture->WriteDrawPicture(where, copy->Token()); picture->WriteDrawPicture(where, copy->Token());
pictureToDraw->ReleaseReference();
} }
} }
break; break;
@@ -3183,21 +3190,26 @@ ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver &link)
case AS_VIEW_APPEND_TO_PICTURE: case AS_VIEW_APPEND_TO_PICTURE:
{ {
int32 pictureToken; int32 token;
link.Read<int32>(&pictureToken); link.Read<int32>(&token);
ServerPicture *appendPicture = App()->FindPicture(pictureToken);
if (appendPicture) { ServerPicture* appendPicture = App()->GetPicture(token);
if (appendPicture != NULL) {
//picture->SyncState(fCurrentView); //picture->SyncState(fCurrentView);
appendPicture->Usurp(picture); appendPicture->Usurp(picture);
} }
fCurrentView->SetPicture(appendPicture); fCurrentView->SetPicture(appendPicture);
// we don't care if it's NULL
if (appendPicture != NULL)
appendPicture->ReleaseReference();
break; break;
} }
case AS_VIEW_END_PICTURE: case AS_VIEW_END_PICTURE:
{ {
ServerPicture *steppedDown = picture->StepDown(); ServerPicture* steppedDown = picture->StepDown();
fCurrentView->SetPicture(steppedDown); fCurrentView->SetPicture(steppedDown);
fLink.StartMessage(B_OK); fLink.StartMessage(B_OK);
fLink.Attach<int32>(picture->Token()); fLink.Attach<int32>(picture->Token());
+12 -3
View File
@@ -154,7 +154,7 @@ View::InitCheck() const
{ {
if (fDrawState == NULL) if (fDrawState == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
return B_OK; return B_OK;
} }
@@ -1291,7 +1291,7 @@ View::SetEventMask(uint32 eventMask, uint32 options)
void void
View::SetCursor(ServerCursor *cursor) View::SetCursor(ServerCursor* cursor)
{ {
if (cursor == fCursor) if (cursor == fCursor)
return; return;
@@ -1307,9 +1307,18 @@ View::SetCursor(ServerCursor *cursor)
void void
View::SetPicture(ServerPicture *picture) View::SetPicture(ServerPicture* picture)
{ {
if (picture == fPicture)
return;
if (fPicture != NULL)
fPicture->ReleaseReference();
fPicture = picture; fPicture = picture;
if (fPicture != NULL)
fPicture->AcquireReference();
} }