* implemented a BRegion pool per WindowLayer which is supposed

to cut down on BRegion related allocations, cannot really tell
  if it speeds things up
* used the new BRegion pool in WindowLayer and ViewLayer whereever
  a BRegion was used on the stack
* fixed the debugging stuff in MultiLocker - it will get you into
  the debugger if you
    - try to nest read locks
    - try to write lock when your are a reader already
    - don't match up nested locks when your a writer
    -> but only if you #define DEBUG 1 in the .cpp, is off by default now
* went over WindowLayer, ServerWindow, Desktop and a few other places
  and fixed the locking for use with the MultiLocker, the "a reader can
  not become a writer" is especially tricky, feel free to review the
  changes
* activated the MultiLocker, I tested this quite a bit, if there are
  problems simply turn on DEBUG and you should drop into the debugger
  right where the problem is... hope all is good


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17046 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2006-04-07 19:14:25 +00:00
parent 791b9c2141
commit 39c9925fcf
15 changed files with 471 additions and 259 deletions
-2
View File
@@ -199,8 +199,6 @@ enum {
AS_SCREENMODE_CHANGED, AS_SCREENMODE_CHANGED,
// Graphics calls // Graphics calls
AS_BEGIN_TRANSACTION,
AS_END_TRANSACTION,
AS_SET_HIGH_COLOR, AS_SET_HIGH_COLOR,
AS_SET_LOW_COLOR, AS_SET_LOW_COLOR,
AS_SET_VIEW_COLOR, AS_SET_VIEW_COLOR,
+7 -8
View File
@@ -50,6 +50,9 @@
# define STRACE(a) ; # define STRACE(a) ;
#endif #endif
#if !USE_MULTI_LOCKER
# define AutoWriteLocker BAutolock
#endif
class KeyboardFilter : public EventFilter { class KeyboardFilter : public EventFilter {
public: public:
@@ -1850,18 +1853,14 @@ Desktop::ViewUnderMouse(const WindowLayer* window)
WindowLayer * WindowLayer *
Desktop::FindWindowLayerByClientToken(int32 token, team_id teamID) Desktop::FindWindowLayerByClientToken(int32 token, team_id teamID)
{ {
LockSingleWindow();
for (WindowLayer *window = fAllWindows.FirstWindow(); window != NULL; for (WindowLayer *window = fAllWindows.FirstWindow(); window != NULL;
window = window->NextWindow(kAllWindowList)) { window = window->NextWindow(kAllWindowList)) {
if (window->ServerWindow()->ClientToken() == token if (window->ServerWindow()->ClientToken() == token
&& window->ServerWindow()->ClientTeam() == teamID) { && window->ServerWindow()->ClientTeam() == teamID) {
UnlockSingleWindow();
return window; return window;
} }
} }
UnlockSingleWindow();
return NULL; return NULL;
} }
@@ -1869,7 +1868,7 @@ Desktop::FindWindowLayerByClientToken(int32 token, team_id teamID)
void void
Desktop::MinimizeApplication(team_id team) Desktop::MinimizeApplication(team_id team)
{ {
BAutolock locker(fWindowLock); AutoWriteLocker locker(fWindowLock);
// Just minimize all windows of that application // Just minimize all windows of that application
@@ -1886,7 +1885,7 @@ Desktop::MinimizeApplication(team_id team)
void void
Desktop::BringApplicationToFront(team_id team) Desktop::BringApplicationToFront(team_id team)
{ {
BAutolock locker(fWindowLock); AutoWriteLocker locker(fWindowLock);
// TODO: for now, just maximize all windows of that application // TODO: for now, just maximize all windows of that application
@@ -1929,7 +1928,7 @@ Desktop::WindowAction(int32 windowToken, int32 action)
void void
Desktop::WriteWindowList(team_id team, BPrivate::LinkSender& sender) Desktop::WriteWindowList(team_id team, BPrivate::LinkSender& sender)
{ {
BAutolock locker(fWindowLock); AutoWriteLocker locker(fWindowLock);
// compute the number of windows // compute the number of windows
@@ -1961,7 +1960,7 @@ Desktop::WriteWindowList(team_id team, BPrivate::LinkSender& sender)
void void
Desktop::WriteWindowInfo(int32 serverToken, BPrivate::LinkSender& sender) Desktop::WriteWindowInfo(int32 serverToken, BPrivate::LinkSender& sender)
{ {
BAutolock locker(fWindowLock); AutoWriteLocker locker(fWindowLock);
BAutolock tokenLocker(BPrivate::gDefaultTokens); BAutolock tokenLocker(BPrivate::gDefaultTokens);
::ServerWindow* window; ::ServerWindow* window;
+1 -1
View File
@@ -31,7 +31,7 @@
#include <Region.h> #include <Region.h>
#include <Window.h> #include <Window.h>
#define USE_MULTI_LOCKER 0 #define USE_MULTI_LOCKER 1
#if USE_MULTI_LOCKER #if USE_MULTI_LOCKER
# include "MultiLocker.h" # include "MultiLocker.h"
+1
View File
@@ -38,6 +38,7 @@ Server app_server :
PNGDump.cpp PNGDump.cpp
RAMLinkMsgReader.cpp RAMLinkMsgReader.cpp
RGBColor.cpp RGBColor.cpp
RegionPool.cpp
ScreenManager.cpp ScreenManager.cpp
ServerApp.cpp ServerApp.cpp
ServerBitmap.cpp ServerBitmap.cpp
+36 -5
View File
@@ -11,7 +11,7 @@
#include <OS.h> #include <OS.h>
//#define TIMING 1 //#define TIMING 1
#define DEBUG 1 //#define DEBUG 1
MultiLocker::MultiLocker(const char* semaphoreBaseName) MultiLocker::MultiLocker(const char* semaphoreBaseName)
@@ -132,6 +132,11 @@ MultiLocker::ReadLock()
if (fInit == B_OK) { if (fInit == B_OK) {
if (IsWriteLocked()) { if (IsWriteLocked()) {
//the writer simply increments the nesting //the writer simply increments the nesting
#if DEBUG
if (fWriterNest < 0)
debugger("ReadLock() - negative writer nest count\n");
#endif
fWriterNest++; fWriterNest++;
locked = true; locked = true;
} else { } else {
@@ -174,10 +179,22 @@ MultiLocker::WriteLock()
if (IsWriteLocked(&stack_base, &thread)) { if (IsWriteLocked(&stack_base, &thread)) {
//already the writer - increment the nesting count //already the writer - increment the nesting count
#if DEBUG
if (fWriterNest < 0)
debugger("WriteLock() - negative nest count\n");
#endif
fWriterNest++; fWriterNest++;
locked = true; locked = true;
} else { } else {
//new writer acquiring the lock //new writer acquiring the lock
#if DEBUG
// NOTE: IsReadLocked() tells you
// if this thread really holds the
// "read lock" only in DEBUG mode!
if (IsReadLocked())
debugger("Reader wants to become writer!");
#endif
if (atomic_add(&fLockCount, 1) >= 1) { if (atomic_add(&fLockCount, 1) >= 1) {
//another writer in the lock - acquire the semaphore //another writer in the lock - acquire the semaphore
locked = (acquire_sem_etc(fWriterLock, 1, B_DO_NOT_RESCHEDULE, locked = (acquire_sem_etc(fWriterLock, 1, B_DO_NOT_RESCHEDULE,
@@ -227,6 +244,12 @@ MultiLocker::ReadUnlock()
if (IsWriteLocked()) { if (IsWriteLocked()) {
//writers simply decrement the nesting count //writers simply decrement the nesting count
fWriterNest--; fWriterNest--;
#if DEBUG
if (fWriterNest < 0)
debugger("ReadUnlock() - negative writer nest count\n");
#endif
unlocked = true; unlocked = true;
} else { } else {
//decrement and retrieve the read counter //decrement and retrieve the read counter
@@ -237,7 +260,7 @@ MultiLocker::ReadUnlock()
B_DO_NOT_RESCHEDULE) == B_OK); B_DO_NOT_RESCHEDULE) == B_OK);
} else unlocked = true; } else unlocked = true;
#ifdef DEBUG #if DEBUG
//unregister if we released the lock //unregister if we released the lock
if (unlocked) unregister_thread(); if (unlocked) unregister_thread();
#endif #endif
@@ -265,6 +288,12 @@ MultiLocker::WriteUnlock()
//if this is a nested lock simply decrement the nest count //if this is a nested lock simply decrement the nest count
if (fWriterNest > 0) { if (fWriterNest > 0) {
fWriterNest--; fWriterNest--;
#if DEBUG
if (fWriterNest < 0)
debugger("WriteUnlock(): nest count now negative\n");
#endif
unlocked = true; unlocked = true;
} else { } else {
//writer finally unlocking //writer finally unlocking
@@ -416,14 +445,16 @@ MultiLocker::IsReadLocked()
void void
MultiLocker::register_thread() MultiLocker::register_thread()
{ {
#ifdef DEBUG #if DEBUG
#if TIMING #if TIMING
bigtime_t start = system_time(); bigtime_t start = system_time();
#endif #endif
thread_id thread = find_thread(NULL); thread_id thread = find_thread(NULL);
ASSERT_WITH_MESSAGE(fDebugArray[thread%fMaxThreads] == 0,"Nested ReadLock!\n"); if (fDebugArray[thread%fMaxThreads] != 0)
debugger("Nested ReadLock!\n");
fDebugArray[thread%fMaxThreads]++; fDebugArray[thread%fMaxThreads]++;
#if TIMING #if TIMING
@@ -439,7 +470,7 @@ MultiLocker::register_thread()
void void
MultiLocker::unregister_thread() MultiLocker::unregister_thread()
{ {
#ifdef DEBUG #if DEBUG
#if TIMING #if TIMING
bigtime_t start = system_time(); bigtime_t start = system_time();
#endif #endif
+29 -8
View File
@@ -1,10 +1,20 @@
/* MultiLocker.h */ /* MultiLocker.h */
/* /*
Copyright 2005-2006, Haiku.
Distributed under the terms of the MIT license.
Copyright 1999, Be Incorporated. All Rights Reserved. Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License. This file may be used under the terms of the Be Sample Code License.
*/ */
/* multiple-reader single-writer locking class */ /** multiple-reader single-writer locking class */
// IMPORTANT:
// * nested read locks are not supported
// * a reader becomming the write is not supported
// * nested write locks are supported
// * a writer can do read locks, even nested ones
// * in case of problems, #define DEBUG 1 in the .cpp
#ifndef MULTI_LOCKER_H #ifndef MULTI_LOCKER_H
#define MULTI_LOCKER_H #define MULTI_LOCKER_H
@@ -31,7 +41,8 @@ class MultiLocker {
bool WriteUnlock(); bool WriteUnlock();
//does the current thread hold a write lock ? //does the current thread hold a write lock ?
bool IsWriteLocked(uint32 *stack_base = NULL, thread_id *thread = NULL); bool IsWriteLocked(uint32 *stack_base = NULL,
thread_id *thread = NULL);
//in DEBUG mode returns whether the lock is held //in DEBUG mode returns whether the lock is held
//in non-debug mode returns true //in non-debug mode returns true
bool IsReadLocked(); bool IsReadLocked();
@@ -82,31 +93,41 @@ class MultiLocker {
class AutoWriteLocker { class AutoWriteLocker {
public: public:
AutoWriteLocker(MultiLocker* lock) AutoWriteLocker(MultiLocker* lock)
: fLock(*lock)
{
fLock.WriteLock();
}
AutoWriteLocker(MultiLocker& lock)
: fLock(lock) : fLock(lock)
{ {
fLock->WriteLock(); fLock.WriteLock();
} }
~AutoWriteLocker() ~AutoWriteLocker()
{ {
fLock->WriteUnlock(); fLock.WriteUnlock();
} }
private: private:
MultiLocker* fLock; MultiLocker& fLock;
}; };
class AutoReadLocker { class AutoReadLocker {
public: public:
AutoReadLocker(MultiLocker* lock) AutoReadLocker(MultiLocker* lock)
: fLock(*lock)
{
fLock.ReadLock();
}
AutoReadLocker(MultiLocker& lock)
: fLock(lock) : fLock(lock)
{ {
fLock->ReadLock(); fLock.ReadLock();
} }
~AutoReadLocker() ~AutoReadLocker()
{ {
fLock->ReadUnlock(); fLock.ReadUnlock();
} }
private: private:
MultiLocker* fLock; MultiLocker& fLock;
}; };
+103
View File
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2006, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/
#include "RegionPool.h"
#include <new>
#include <stdio.h>
#if DEBUG_LEAK
#include <debugger.h>
#endif
#include <Region.h>
using std::nothrow;
RegionPool::RegionPool()
: fAvailable(4)
#if DEBUG_LEAK
,fUsed(4)
#endif
{
}
RegionPool::~RegionPool()
{
#if DEBUG_LEAK
if (fUsed.CountItems() > 0)
debugger("RegionPool::~RegionPool() - some regions still in use!");
#endif
int32 count = fAvailable.CountItems();
for (int32 i = 0; i < count; i++)
delete (BRegion*)fAvailable.ItemAtFast(i);
}
BRegion*
RegionPool::GetRegion()
{
BRegion* region = (BRegion*)fAvailable.RemoveItem(
fAvailable.CountItems() - 1);
if (!region) {
region = new (nothrow) BRegion();
if (!region) {
// whoa
fprintf(stderr, "RegionPool::GetRegion() - "
"no memory!\n");
}
}
#if DEBUG_LEAK
fUsed.AddItem(region);
#endif
return region;
}
BRegion*
RegionPool::GetRegion(const BRegion& other)
{
BRegion* region;
int32 count = fAvailable.CountItems();
if (count > 0) {
region = (BRegion*)fAvailable.RemoveItem(count - 1);
*region = other;
} else {
region = new (nothrow) BRegion(other);
if (!region) {
// whoa
fprintf(stderr, "RegionPool::GetRegion() - "
"no memory!\n");
}
}
#if DEBUG_LEAK
fUsed.AddItem(region);
#endif
return region;
}
void
RegionPool::Recycle(BRegion* region)
{
if (!fAvailable.AddItem(region)) {
// at least don't leak the region...
fprintf(stderr, "RegionPool::Recycle() - "
"no memory!\n");
delete region;
} else {
// prepare for next usage
region->MakeEmpty();
}
#if DEBUG_LEAK
fUsed.RemoveItem(region);
#endif
}
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2006, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/
#ifndef REGION_POOL_H
#define REGION_POOL_H
#include <List.h>
class BRegion;
#define DEBUG_LEAK 0
class RegionPool {
public:
RegionPool();
virtual ~RegionPool();
BRegion* GetRegion();
BRegion* GetRegion(const BRegion& other);
void Recycle(BRegion* region);
private:
BList fAvailable;
#if DEBUG_LEAK
BList fUsed;
#endif
};
#endif // REGION_POOL_H
+1
View File
@@ -194,6 +194,7 @@ ServerBitmap::_HandleSpace(color_space space, int32 bytesPerRow)
case B_YCbCr422: case B_YCbCr422:
case B_YUV422: case B_YUV422:
minBPR = (fWidth + 3) / 4 * 8; minBPR = (fWidth + 3) / 4 * 8;
// TODO: huh? why not simply fWidth * 2 ?!?
fBitsPerPixel = 16; fBitsPerPixel = 16;
break; break;
+30 -34
View File
@@ -51,7 +51,6 @@
#include "ServerPicture.h" #include "ServerPicture.h"
#include "ServerProtocol.h" #include "ServerProtocol.h"
#include "WindowLayer.h" #include "WindowLayer.h"
#include "Workspace.h"
#include "WorkspacesLayer.h" #include "WorkspacesLayer.h"
#include "ServerWindow.h" #include "ServerWindow.h"
@@ -386,8 +385,11 @@ ServerWindow::SetTitle(const char* newTitle)
rename_thread(Thread(), name); rename_thread(Thread(), name);
} }
if (fWindowLayer != NULL) if (fWindowLayer != NULL) {
fDesktop->UnlockSingleWindow();
fDesktop->SetWindowTitle(fWindowLayer, newTitle); fDesktop->SetWindowTitle(fWindowLayer, newTitle);
fDesktop->LockSingleWindow();
}
} }
@@ -584,10 +586,12 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
link.Read<bool>(&activate); link.Read<bool>(&activate);
fDesktop->UnlockSingleWindow();
if (activate) if (activate)
fDesktop->ActivateWindow(fWindowLayer); fDesktop->ActivateWindow(fWindowLayer);
else else
fDesktop->SendWindowBehind(fWindowLayer, NULL); fDesktop->SendWindowBehind(fWindowLayer, NULL);
fDesktop->LockSingleWindow();
break; break;
} }
case AS_SEND_BEHIND: case AS_SEND_BEHIND:
@@ -602,7 +606,9 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
WindowLayer *behindOf; WindowLayer *behindOf;
if ((behindOf = fDesktop->FindWindowLayerByClientToken(token, teamID)) != NULL) { if ((behindOf = fDesktop->FindWindowLayerByClientToken(token, teamID)) != NULL) {
fDesktop->UnlockSingleWindow();
fDesktop->SendWindowBehind(fWindowLayer, behindOf); fDesktop->SendWindowBehind(fWindowLayer, behindOf);
fDesktop->LockSingleWindow();
status = B_OK; status = B_OK;
} else } else
status = B_NAME_NOT_FOUND; status = B_NAME_NOT_FOUND;
@@ -617,23 +623,6 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
NotifyQuitRequested(); NotifyQuitRequested();
break; break;
case AS_BEGIN_TRANSACTION:
{
STRACE(("ServerWindow %s: Message AS_BEGIN_TRANSACTION unimplemented\n",
Title()));
// TODO: we could probably do a bit more here...
// TODO: AS_BEGIN_TRANSACTION
//fWindowLayer->DisableUpdateRequests();
break;
}
case AS_END_TRANSACTION:
{
STRACE(("ServerWindow %s: Message AS_END_TRANSACTION unimplemented\n",
Title()));
// TODO: AS_END_TRANSACTION
//fWindowLayer->EnableUpdateRequests();
break;
}
case AS_ENABLE_UPDATES: case AS_ENABLE_UPDATES:
{ {
STRACE(("ServerWindow %s: Message AS_ENABLE_UPDATES unimplemented\n", STRACE(("ServerWindow %s: Message AS_ENABLE_UPDATES unimplemented\n",
@@ -683,8 +672,10 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
|| windowLayer->Feel() != B_NORMAL_WINDOW_FEEL) { || windowLayer->Feel() != B_NORMAL_WINDOW_FEEL) {
status = B_BAD_VALUE; status = B_BAD_VALUE;
} else { } else {
fDesktop->UnlockSingleWindow();
status = fDesktop->AddWindowToSubset(fWindowLayer, windowLayer) status = fDesktop->AddWindowToSubset(fWindowLayer, windowLayer)
? B_OK : B_NO_MEMORY; ? B_OK : B_NO_MEMORY;
fDesktop->LockSingleWindow();
} }
} }
@@ -702,7 +693,9 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
WindowLayer* windowLayer = fDesktop->FindWindowLayerByClientToken( WindowLayer* windowLayer = fDesktop->FindWindowLayerByClientToken(
token, App()->ClientTeam()); token, App()->ClientTeam());
if (windowLayer != NULL) { if (windowLayer != NULL) {
fDesktop->UnlockSingleWindow();
fDesktop->RemoveWindowFromSubset(fWindowLayer, windowLayer); fDesktop->RemoveWindowFromSubset(fWindowLayer, windowLayer);
fDesktop->LockSingleWindow();
status = B_OK; status = B_OK;
} else } else
status = B_BAD_VALUE; status = B_BAD_VALUE;
@@ -725,8 +718,11 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
? B_OK : B_BAD_VALUE; ? B_OK : B_BAD_VALUE;
} }
if (status == B_OK && !fWindowLayer->IsOffscreenWindow()) if (status == B_OK && !fWindowLayer->IsOffscreenWindow()) {
fDesktop->UnlockSingleWindow();
fDesktop->SetWindowLook(fWindowLayer, (window_look)look); fDesktop->SetWindowLook(fWindowLayer, (window_look)look);
fDesktop->LockSingleWindow();
}
fLink.StartMessage(status); fLink.StartMessage(status);
fLink.Flush(); fLink.Flush();
@@ -744,8 +740,11 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
? B_OK : B_BAD_VALUE; ? B_OK : B_BAD_VALUE;
} }
if (status == B_OK && !fWindowLayer->IsOffscreenWindow()) if (status == B_OK && !fWindowLayer->IsOffscreenWindow()) {
fDesktop->UnlockSingleWindow();
fDesktop->SetWindowFeel(fWindowLayer, (window_feel)feel); fDesktop->SetWindowFeel(fWindowLayer, (window_feel)feel);
fDesktop->LockSingleWindow();
}
fLink.StartMessage(status); fLink.StartMessage(status);
fLink.Flush(); fLink.Flush();
@@ -763,8 +762,11 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
? B_OK : B_BAD_VALUE; ? B_OK : B_BAD_VALUE;
} }
if (status == B_OK && !fWindowLayer->IsOffscreenWindow()) if (status == B_OK && !fWindowLayer->IsOffscreenWindow()) {
fDesktop->UnlockSingleWindow();
fDesktop->SetWindowFlags(fWindowLayer, flags); fDesktop->SetWindowFlags(fWindowLayer, flags);
fDesktop->LockSingleWindow();
}
fLink.StartMessage(status); fLink.StartMessage(status);
fLink.Flush(); fLink.Flush();
@@ -801,7 +803,9 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
STRACE(("ServerWindow %s: Message AS_SET_WORKSPACES %lx\n", STRACE(("ServerWindow %s: Message AS_SET_WORKSPACES %lx\n",
Title(), newWorkspaces)); Title(), newWorkspaces));
fDesktop->UnlockSingleWindow();
fDesktop->SetWindowWorkspaces(fWindowLayer, newWorkspaces); fDesktop->SetWindowWorkspaces(fWindowLayer, newWorkspaces);
fDesktop->LockSingleWindow();
break; break;
} }
case AS_WINDOW_RESIZE: case AS_WINDOW_RESIZE:
@@ -820,7 +824,9 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
// pragmatically set window bounds // pragmatically set window bounds
fLink.StartMessage(B_BUSY); fLink.StartMessage(B_BUSY);
} else { } else {
fDesktop->UnlockSingleWindow();
fDesktop->ResizeWindowBy(fWindowLayer, xResizeBy, yResizeBy); fDesktop->ResizeWindowBy(fWindowLayer, xResizeBy, yResizeBy);
fDesktop->LockSingleWindow();
fLink.StartMessage(B_OK); fLink.StartMessage(B_OK);
} }
fLink.Flush(); fLink.Flush();
@@ -842,7 +848,9 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
// pragmatically set window positions // pragmatically set window positions
fLink.StartMessage(B_BUSY); fLink.StartMessage(B_BUSY);
} else { } else {
fDesktop->UnlockSingleWindow();
fDesktop->MoveWindowBy(fWindowLayer, xMoveBy, yMoveBy); fDesktop->MoveWindowBy(fWindowLayer, xMoveBy, yMoveBy);
fDesktop->LockSingleWindow();
fLink.StartMessage(B_OK); fLink.StartMessage(B_OK);
} }
fLink.Flush(); fLink.Flush();
@@ -901,22 +909,12 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
case AS_BEGIN_UPDATE: case AS_BEGIN_UPDATE:
DTRACE(("ServerWindowo %s: AS_BEGIN_UPDATE\n", Title())); DTRACE(("ServerWindowo %s: AS_BEGIN_UPDATE\n", Title()));
// NOTE: when line below is turned on, the behaviour starts to
// be very much like on R5, but if the client crashes in
// one of it's BView's Draw() functions, AS_END_UPDATE is
// never received and the app_server is toast! Maybe R5
// does something like this, but if the write lock cannot
// be optained within a certain amount of time, it crashes
// whoever holds the read lock on purpose.
//fDesktop->LockSingleWindow();
fWindowLayer->BeginUpdate(fLink); fWindowLayer->BeginUpdate(fLink);
break; break;
case AS_END_UPDATE: case AS_END_UPDATE:
DTRACE(("ServerWindowo %s: AS_END_UPDATE\n", Title())); DTRACE(("ServerWindowo %s: AS_END_UPDATE\n", Title()));
fWindowLayer->EndUpdate(); fWindowLayer->EndUpdate();
//fDesktop->UnlockSingleWindow();
break; break;
case AS_GET_MOUSE: case AS_GET_MOUSE:
@@ -2697,7 +2695,6 @@ ServerWindow::_SetCurrentLayer(ViewLayer* layer)
fCurrentDrawingRegionValid = false; fCurrentDrawingRegionValid = false;
#if 0 #if 0
#if DELAYED_BACKGROUND_CLEARING #if DELAYED_BACKGROUND_CLEARING
fWindowLayer->ReadLockWindows();
if (fCurrentLayer && fCurrentLayer->IsBackgroundDirty() && fWindowLayer->InUpdate()) { if (fCurrentLayer && fCurrentLayer->IsBackgroundDirty() && fWindowLayer->InUpdate()) {
DrawingEngine* drawingEngine = fWindowLayer->GetDrawingEngine(); DrawingEngine* drawingEngine = fWindowLayer->GetDrawingEngine();
if (drawingEngine->Lock()) { if (drawingEngine->Lock()) {
@@ -2714,7 +2711,6 @@ fWindowLayer->ReadLockWindows();
drawingEngine->Unlock(); drawingEngine->Unlock();
} }
} }
fWindowLayer->ReadUnlockWindows();
#endif #endif
#endif // 0 #endif // 0
} }
+62 -27
View File
@@ -198,8 +198,12 @@ ViewLayer::AddChild(ViewLayer* layer)
// trigger redraw // trigger redraw
BRect clippedFrame = layer->Frame(); BRect clippedFrame = layer->Frame();
ConvertToVisibleInTopView(&clippedFrame); ConvertToVisibleInTopView(&clippedFrame);
BRegion dirty(clippedFrame); BRegion* dirty = fWindow->GetRegion();
fWindow->MarkContentDirty(dirty); if (dirty) {
dirty->Set(clippedFrame);
fWindow->MarkContentDirty(*dirty);
fWindow->RecycleRegion(dirty);
}
} }
} }
} }
@@ -244,8 +248,12 @@ ViewLayer::RemoveChild(ViewLayer* layer)
// trigger redraw // trigger redraw
BRect clippedFrame = layer->Frame(); BRect clippedFrame = layer->Frame();
ConvertToVisibleInTopView(&clippedFrame); ConvertToVisibleInTopView(&clippedFrame);
BRegion dirty(clippedFrame); BRegion* dirty = fWindow->GetRegion();
fWindow->MarkContentDirty(dirty); if (dirty) {
dirty->Set(clippedFrame);
fWindow->MarkContentDirty(*dirty);
fWindow->RecycleRegion(dirty);
}
} }
} }
@@ -642,13 +650,19 @@ ViewLayer::MoveBy(int32 x, int32 y, BRegion* dirtyRegion)
// clipping oldVisibleBounds to newVisibleBounds // clipping oldVisibleBounds to newVisibleBounds
// makes sure we don't copy parts hidden under // makes sure we don't copy parts hidden under
// parent views // parent views
BRegion copyRegion(oldVisibleBounds & newVisibleBounds); BRegion* region = fWindow->GetRegion();
fWindow->CopyContents(&copyRegion, x, y); if (region) {
region->Set(oldVisibleBounds & newVisibleBounds);
fWindow->CopyContents(region, x, y);
region->Set(oldVisibleBounds);
newVisibleBounds.OffsetBy(x, y);
region->Exclude(newVisibleBounds);
dirtyRegion->Include(dirty);
fWindow->RecycleRegion(region);
}
BRegion dirty(oldVisibleBounds);
newVisibleBounds.OffsetBy(x, y);
dirty.Exclude(newVisibleBounds);
dirtyRegion->Include(&dirty);
#endif #endif
} }
@@ -681,32 +695,37 @@ ViewLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion)
oldBounds.right -= x; oldBounds.right -= x;
oldBounds.bottom -= y; oldBounds.bottom -= y;
BRegion dirty(Bounds()); BRegion* dirty = fWindow->GetRegion();
dirty.Include(oldBounds); if (!dirty)
return;
dirty->Set(Bounds());
dirty->Include(oldBounds);
if (!(fFlags & B_FULL_UPDATE_ON_RESIZE)) { if (!(fFlags & B_FULL_UPDATE_ON_RESIZE)) {
// the dirty region is just the difference of // the dirty region is just the difference of
// old and new bounds // old and new bounds
dirty.Exclude(oldBounds & Bounds()); dirty->Exclude(oldBounds & Bounds());
} }
InvalidateScreenClipping(true); InvalidateScreenClipping(true);
if (dirty.CountRects() > 0) { if (dirty->CountRects() > 0) {
// exclude children, they are expected to // exclude children, they are expected to
// include their own dirty regions in ParentResized() // include their own dirty regions in ParentResized()
for (ViewLayer* child = FirstChild(); child; child = child->NextSibling()) { for (ViewLayer* child = FirstChild(); child; child = child->NextSibling()) {
if (child->IsVisible()) { if (child->IsVisible()) {
BRect previousChildVisible(child->Frame() & oldBounds & Bounds()); BRect previousChildVisible(child->Frame() & oldBounds & Bounds());
if (dirty.Frame().Intersects(previousChildVisible)) { if (dirty->Frame().Intersects(previousChildVisible)) {
dirty.Exclude(previousChildVisible); dirty->Exclude(previousChildVisible);
} }
} }
} }
ConvertToScreen(&dirty); ConvertToScreen(dirty);
dirtyRegion->Include(&dirty); dirtyRegion->Include(dirty);
} }
fWindow->RecycleRegion(dirty);
} }
// layout the children // layout the children
@@ -795,10 +814,16 @@ ViewLayer::ScrollBy(int32 x, int32 y, BRegion* dirtyRegion)
// find the dirty region as far as we are // find the dirty region as far as we are
// concerned // concerned
BRegion dirty(oldBounds); BRegion* dirty = fWindow->GetRegion();
if (!dirty)
return;
dirty->Set(oldBounds);
stillVisibleBounds.OffsetBy(-x, -y); stillVisibleBounds.OffsetBy(-x, -y);
dirty.Exclude(stillVisibleBounds); dirty->Exclude(stillVisibleBounds);
dirtyRegion->Include(&dirty); dirtyRegion->Include(dirty);
fWindow->RecycleRegion(dirty);
// the screen clipping of this view and it's // the screen clipping of this view and it's
// childs is no longer valid // childs is no longer valid
@@ -843,12 +868,18 @@ ViewLayer::CopyBits(BRect src, BRect dst, BRegion& windowContentClipping)
BRect dirtyDst(dst); BRect dirtyDst(dst);
ConvertToVisibleInTopView(&dirtyDst); ConvertToVisibleInTopView(&dirtyDst);
BRegion dirty(dirtyDst); BRegion* dirty = fWindow->GetRegion();
if (!dirty)
return;
dirty->Set(dirtyDst);
// exclude the part that we could copy // exclude the part that we could copy
visibleSrc.OffsetBy(xOffset, yOffset); visibleSrc.OffsetBy(xOffset, yOffset);
dirty.Exclude(visibleSrc); dirty->Exclude(visibleSrc);
dirty.IntersectWith(&ScreenClipping(&windowContentClipping)); dirty->IntersectWith(&ScreenClipping(&windowContentClipping));
fWindow->MarkContentDirty(dirty); fWindow->MarkContentDirty(*dirty);
fWindow->RecycleRegion(dirty);
} }
@@ -1024,8 +1055,12 @@ ViewLayer::SetHidden(bool hidden)
// trigger a redraw // trigger a redraw
BRect clippedBounds = Bounds(); BRect clippedBounds = Bounds();
ConvertToVisibleInTopView(&clippedBounds); ConvertToVisibleInTopView(&clippedBounds);
BRegion dirty(clippedBounds); BRegion* dirty = fWindow->GetRegion();
fWindow->MarkContentDirty(dirty); if (!dirty)
return;
dirty->Set(clippedBounds);
fWindow->MarkContentDirty(*dirty);
fWindow->RecycleRegion(dirty);
} }
} }
} else { } else {
+145 -164
View File
@@ -88,6 +88,8 @@ WindowLayer::WindowLayer(const BRect& frame, const char *name,
fEffectiveDrawingRegion(), fEffectiveDrawingRegion(),
fEffectiveDrawingRegionValid(false), fEffectiveDrawingRegionValid(false),
fRegionPool(),
fIsClosing(false), fIsClosing(false),
fIsMinimizing(false), fIsMinimizing(false),
fIsZooming(false), fIsZooming(false),
@@ -122,9 +124,7 @@ WindowLayer::WindowLayer(const BRect& frame, const char *name,
fMinWidth(1), fMinWidth(1),
fMaxWidth(32768), fMaxWidth(32768),
fMinHeight(1), fMinHeight(1),
fMaxHeight(32768), fMaxHeight(32768)
fReadLocked(false)
{ {
// make sure our arguments are valid // make sure our arguments are valid
if (!IsValidLook(fLook)) if (!IsValidLook(fLook))
@@ -175,29 +175,6 @@ WindowLayer::~WindowLayer()
} }
bool
WindowLayer::ReadLockWindows()
{
if (fDesktop)
fReadLocked = fDesktop->LockSingleWindow();
else
fReadLocked = true;
return fReadLocked;
}
void
WindowLayer::ReadUnlockWindows()
{
if (fReadLocked) {
if (fDesktop)
fDesktop->UnlockSingleWindow();
fReadLocked = false;
}
}
void void
WindowLayer::SetClipping(BRegion* stillAvailableOnScreen) WindowLayer::SetClipping(BRegion* stillAvailableOnScreen)
{ {
@@ -413,29 +390,27 @@ WindowLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion)
void void
WindowLayer::ScrollViewBy(ViewLayer* view, int32 dx, int32 dy) WindowLayer::ScrollViewBy(ViewLayer* view, int32 dx, int32 dy)
{ {
// this can be executed from any thread, but if the // this is executed in ServerWindow with the Readlock
// desktop thread is executing this, it should have // held
// the write lock, otherwise it is not prevented
// from executing this at the same time as the window
// is doing something else here!
if (!view || view == fTopLayer || (dx == 0 && dy == 0)) if (!view || view == fTopLayer || (dx == 0 && dy == 0))
return; return;
if (fDesktop && fDesktop->LockSingleWindow()) { BRegion* dirty = fRegionPool.GetRegion();
BRegion dirty; if (!dirty)
view->ScrollBy(dx, dy, &dirty); return;
view->ScrollBy(dx, dy, dirty);
//fDrawingEngine->FillRegion(dirty, RGBColor(255, 0, 255, 255)); //fDrawingEngine->FillRegion(dirty, RGBColor(255, 0, 255, 255));
//snooze(2000); //snooze(2000);
if (IsVisible() && view->IsVisible()) { if (IsVisible() && view->IsVisible()) {
dirty.IntersectWith(&VisibleContentRegion()); dirty->IntersectWith(&VisibleContentRegion());
_TriggerContentRedraw(dirty); _TriggerContentRedraw(*dirty);
}
fDesktop->UnlockSingleWindow();
} }
fRegionPool.Recycle(dirty);
} }
@@ -443,64 +418,67 @@ WindowLayer::ScrollViewBy(ViewLayer* view, int32 dx, int32 dy)
void void
WindowLayer::CopyContents(BRegion* region, int32 xOffset, int32 yOffset) WindowLayer::CopyContents(BRegion* region, int32 xOffset, int32 yOffset)
{ {
if (IsVisible() && fDesktop && fDesktop->LockSingleWindow()) { // executed in ServerWindow thread with the read lock held
BRegion newDirty(*region); if (!IsVisible())
return;
// clip the region to the visible contents at the BRegion* newDirty = fRegionPool.GetRegion(*region);
// source and destination location (note that VisibleContentRegion()
// is used once to make sure it is valid, then fVisibleContentRegion // clip the region to the visible contents at the
// is used directly) // source and destination location (note that VisibleContentRegion()
region->IntersectWith(&VisibleContentRegion()); // is used once to make sure it is valid, then fVisibleContentRegion
// is used directly)
region->IntersectWith(&VisibleContentRegion());
if (region->CountRects() > 0) {
region->OffsetBy(xOffset, yOffset);
region->IntersectWith(&fVisibleContentRegion);
if (region->CountRects() > 0) { if (region->CountRects() > 0) {
region->OffsetBy(xOffset, yOffset); // if the region still contains any rects
region->IntersectWith(&fVisibleContentRegion); // offset to source location again
if (region->CountRects() > 0) { region->OffsetBy(-xOffset, -yOffset);
// if the region still contains any rects // the part which we can copy is not dirty
// offset to source location again newDirty->Exclude(region);
region->OffsetBy(-xOffset, -yOffset);
// the part which we can copy is not dirty fDrawingEngine->CopyRegion(region, xOffset, yOffset);
newDirty.Exclude(region);
fDrawingEngine->CopyRegion(region, xOffset, yOffset);
// move along the already dirty regions that are common // move along the already dirty regions that are common
// with the region that we could copy // with the region that we could copy
_ShiftPartOfRegion(&fDirtyRegion, region, xOffset, yOffset); _ShiftPartOfRegion(&fDirtyRegion, region, xOffset, yOffset);
if (fPendingUpdateSession.IsUsed()) if (fPendingUpdateSession.IsUsed())
_ShiftPartOfRegion(&fPendingUpdateSession.DirtyRegion(), region, xOffset, yOffset); _ShiftPartOfRegion(&fPendingUpdateSession.DirtyRegion(), region, xOffset, yOffset);
if (fCurrentUpdateSession.IsUsed()) { if (fCurrentUpdateSession.IsUsed()) {
// if there are parts in the current update session // if there are parts in the current update session
// that intersect with the copied region, we cannot // that intersect with the copied region, we cannot
// simply shift them as with the other dirty regions // simply shift them as with the other dirty regions
// - we cannot change the update rect already told to the // - we cannot change the update rect already told to the
// client, that's why we transfer those parts to the // client, that's why we transfer those parts to the
// new dirty region instead // new dirty region instead
BRegion common(*region); BRegion* common = fRegionPool.GetRegion(*region);
// see if there is a common part at all // see if there is a common part at all
common.IntersectWith(&fCurrentUpdateSession.DirtyRegion()); common->IntersectWith(&fCurrentUpdateSession.DirtyRegion());
if (common.CountRects() > 0) { if (common->CountRects() > 0) {
// cut the common part from the region // cut the common part from the region
fCurrentUpdateSession.DirtyRegion().Exclude(&common); fCurrentUpdateSession.DirtyRegion().Exclude(common);
newDirty.Include(&common); newDirty->Include(common);
}
} }
fRegionPool.Recycle(common);
} }
} }
// what is left visible from the original region
// at the destination after the region which could be
// copied has been excluded, is considered dirty
// NOTE: it may look like dirty regions are not moved
// if no region could be copied, but that's alright,
// since these parts will now be in newDirty anyways
// (with the right offset)
newDirty.OffsetBy(xOffset, yOffset);
newDirty.IntersectWith(&fVisibleContentRegion);
if (newDirty.CountRects() > 0)
ProcessDirtyRegion(newDirty);
fDesktop->UnlockSingleWindow();
} }
// what is left visible from the original region
// at the destination after the region which could be
// copied has been excluded, is considered dirty
// NOTE: it may look like dirty regions are not moved
// if no region could be copied, but that's alright,
// since these parts will now be in newDirty anyways
// (with the right offset)
newDirty->OffsetBy(xOffset, yOffset);
newDirty->IntersectWith(&fVisibleContentRegion);
if (newDirty->CountRects() > 0)
ProcessDirtyRegion(*newDirty);
fRegionPool.Recycle(newDirty);
} }
@@ -537,14 +515,11 @@ WindowLayer::ViewAt(const BPoint& where)
{ {
ViewLayer* view = NULL; ViewLayer* view = NULL;
if (ReadLockWindows()) { if (!fContentRegionValid)
if (!fContentRegionValid) _UpdateContentRegion();
_UpdateContentRegion();
view = fTopLayer->ViewAt(where, &fContentRegion); view = fTopLayer->ViewAt(where, &fContentRegion);
ReadUnlockWindows();
}
return view; return view;
} }
@@ -641,16 +616,18 @@ WindowLayer::ProcessDirtyRegion(BRegion& region)
void void
WindowLayer::RedrawDirtyRegion() WindowLayer::RedrawDirtyRegion()
{ {
if (!fDesktop || !fDesktop->LockSingleWindow()) // executed from ServerWindow with the read lock held
return;
if (IsVisible()) { if (IsVisible()) {
_DrawBorder(); _DrawBorder();
BRegion dirtyContentRegion(VisibleContentRegion()); BRegion* dirtyContentRegion =
dirtyContentRegion.IntersectWith(&fDirtyRegion); fRegionPool.GetRegion(VisibleContentRegion());
dirtyContentRegion->IntersectWith(&fDirtyRegion);
_TriggerContentRedraw(dirtyContentRegion); _TriggerContentRedraw(*dirtyContentRegion);
fRegionPool.Recycle(dirtyContentRegion);
} }
// reset the dirty region, since // reset the dirty region, since
@@ -658,11 +635,9 @@ WindowLayer::RedrawDirtyRegion()
// thread wanted to mark something // thread wanted to mark something
// dirty in the mean time, it was // dirty in the mean time, it was
// blocking on the global region lock to // blocking on the global region lock to
// get write access, since we held the // get write access, since we're holding
// read lock for the whole time. // the read lock for the whole time.
fDirtyRegion.MakeEmpty(); fDirtyRegion.MakeEmpty();
fDesktop->UnlockSingleWindow();
} }
@@ -685,23 +660,19 @@ WindowLayer::MarkContentDirty(BRegion& regionOnScreen)
// since this won't affect other windows, read locking // since this won't affect other windows, read locking
// is sufficient. If there was no dirty region before, // is sufficient. If there was no dirty region before,
// an update message is triggered // an update message is triggered
if (!fHidden && fDesktop && fDesktop->LockSingleWindow()) { if (fHidden)
regionOnScreen.IntersectWith(&VisibleContentRegion()); return;
_TriggerContentRedraw(regionOnScreen);
fDesktop->UnlockSingleWindow(); regionOnScreen.IntersectWith(&VisibleContentRegion());
} _TriggerContentRedraw(regionOnScreen);
} }
void void
WindowLayer::InvalidateView(ViewLayer* layer, BRegion& layerRegion) WindowLayer::InvalidateView(ViewLayer* layer, BRegion& layerRegion)
{ {
if (layer && IsVisible() && fDesktop && fDesktop->LockSingleWindow()) { if (layer && IsVisible() && layer->IsVisible()) {
if (!layer->IsVisible()) {
fDesktop->UnlockSingleWindow();
return;
}
if (!fContentRegionValid) if (!fContentRegionValid)
_UpdateContentRegion(); _UpdateContentRegion();
@@ -715,8 +686,6 @@ WindowLayer::InvalidateView(ViewLayer* layer, BRegion& layerRegion)
_TriggerContentRedraw(layerRegion); _TriggerContentRedraw(layerRegion);
} }
fDesktop->UnlockSingleWindow();
} }
} }
@@ -796,12 +765,12 @@ WindowLayer::MouseDown(BMessage* message, BPoint where, int32* _viewToken)
} }
// redraw decorator // redraw decorator
BRegion visibleBorder; BRegion* visibleBorder = fRegionPool.GetRegion();
GetBorderRegion(&visibleBorder); GetBorderRegion(visibleBorder);
visibleBorder.IntersectWith(&VisibleRegion()); visibleBorder->IntersectWith(&VisibleRegion());
fDrawingEngine->Lock(); fDrawingEngine->Lock();
fDrawingEngine->ConstrainClippingRegion(&visibleBorder); fDrawingEngine->ConstrainClippingRegion(visibleBorder);
if (fIsZooming) { if (fIsZooming) {
fDecorator->SetZoom(true); fDecorator->SetZoom(true);
@@ -813,6 +782,8 @@ WindowLayer::MouseDown(BMessage* message, BPoint where, int32* _viewToken)
fDrawingEngine->Unlock(); fDrawingEngine->Unlock();
fRegionPool.Recycle(visibleBorder);
// based on what the Decorator returned, properly place this window. // based on what the Decorator returned, properly place this window.
if (action == DEC_MOVETOBACK) { if (action == DEC_MOVETOBACK) {
fDesktop->SendWindowBehind(this); fDesktop->SendWindowBehind(this);
@@ -853,12 +824,12 @@ WindowLayer::MouseUp(BMessage* message, BPoint where, int32* _viewToken)
click_type action = _ActionFor(message); click_type action = _ActionFor(message);
// redraw decorator // redraw decorator
BRegion visibleBorder; BRegion* visibleBorder = fRegionPool.GetRegion();
GetBorderRegion(&visibleBorder); GetBorderRegion(visibleBorder);
visibleBorder.IntersectWith(&VisibleRegion()); visibleBorder->IntersectWith(&VisibleRegion());
fDrawingEngine->Lock(); fDrawingEngine->Lock();
fDrawingEngine->ConstrainClippingRegion(&visibleBorder); fDrawingEngine->ConstrainClippingRegion(visibleBorder);
if (fIsZooming) { if (fIsZooming) {
fIsZooming = false; fIsZooming = false;
@@ -886,6 +857,8 @@ WindowLayer::MouseUp(BMessage* message, BPoint where, int32* _viewToken)
} }
fDrawingEngine->Unlock(); fDrawingEngine->Unlock();
fRegionPool.Recycle(visibleBorder);
} }
fIsDragging = false; fIsDragging = false;
fIsResizing = false; fIsResizing = false;
@@ -923,12 +896,12 @@ WindowLayer::MouseMoved(BMessage *message, BPoint where, int32* _viewToken,
} }
if (fDecorator) { if (fDecorator) {
BRegion visibleBorder; BRegion* visibleBorder = fRegionPool.GetRegion();
GetBorderRegion(&visibleBorder); GetBorderRegion(visibleBorder);
visibleBorder.IntersectWith(&VisibleRegion()); visibleBorder->IntersectWith(&VisibleRegion());
fDrawingEngine->Lock(); fDrawingEngine->Lock();
fDrawingEngine->ConstrainClippingRegion(&visibleBorder); fDrawingEngine->ConstrainClippingRegion(visibleBorder);
if (fIsZooming) { if (fIsZooming) {
fDecorator->SetZoom(_ActionFor(message) == DEC_ZOOM); fDecorator->SetZoom(_ActionFor(message) == DEC_ZOOM);
@@ -939,6 +912,7 @@ WindowLayer::MouseMoved(BMessage *message, BPoint where, int32* _viewToken,
} }
fDrawingEngine->Unlock(); fDrawingEngine->Unlock();
fRegionPool.Recycle(visibleBorder);
} }
BPoint delta = where - fLastMousePosition; BPoint delta = where - fLastMousePosition;
@@ -1071,9 +1045,12 @@ WindowLayer::SetFocus(bool focus)
// so the window thread cannot be // so the window thread cannot be
// accessing fIsFocus // accessing fIsFocus
BRegion dirty(fBorderRegion); BRegion* dirty = fRegionPool.GetRegion(fBorderRegion);
dirty.IntersectWith(&fVisibleRegion); if (dirty) {
fDesktop->MarkDirty(dirty); dirty->IntersectWith(&fVisibleRegion);
fDesktop->MarkDirty(*dirty);
fRegionPool.Recycle(dirty);
}
fIsFocus = focus; fIsFocus = focus;
if (fDecorator) if (fDecorator)
@@ -1602,16 +1579,19 @@ void
WindowLayer::_ShiftPartOfRegion(BRegion* region, BRegion* regionToShift, WindowLayer::_ShiftPartOfRegion(BRegion* region, BRegion* regionToShift,
int32 xOffset, int32 yOffset) int32 xOffset, int32 yOffset)
{ {
BRegion common(*regionToShift); BRegion* common = fRegionPool.GetRegion(*regionToShift);
if (!common)
return;
// see if there is a common part at all // see if there is a common part at all
common.IntersectWith(region); common->IntersectWith(region);
if (common.CountRects() > 0) { if (common->CountRects() > 0) {
// cut the common part from the region, // cut the common part from the region,
// offset that to destination and include again // offset that to destination and include again
region->Exclude(&common); region->Exclude(common);
common.OffsetBy(xOffset, yOffset); common->OffsetBy(xOffset, yOffset);
region->Include(&common); region->Include(common);
} }
fRegionPool.Recycle(common);
} }
@@ -1655,19 +1635,22 @@ WindowLayer::_DrawBorder()
return; return;
// construct the region of the border that needs redrawing // construct the region of the border that needs redrawing
BRegion dirtyBorderRegion; BRegion* dirtyBorderRegion = fRegionPool.GetRegion();
GetBorderRegion(&dirtyBorderRegion); if (!dirtyBorderRegion)
return;
GetBorderRegion(dirtyBorderRegion);
// intersect with our visible region // intersect with our visible region
dirtyBorderRegion.IntersectWith(&fVisibleRegion); dirtyBorderRegion->IntersectWith(&fVisibleRegion);
// intersect with the dirty region // intersect with the dirty region
dirtyBorderRegion.IntersectWith(&fDirtyRegion); dirtyBorderRegion->IntersectWith(&fDirtyRegion);
if (dirtyBorderRegion.CountRects() > 0 && fDrawingEngine->Lock()) { if (dirtyBorderRegion->CountRects() > 0 && fDrawingEngine->Lock()) {
fDrawingEngine->ConstrainClippingRegion(&dirtyBorderRegion); fDrawingEngine->ConstrainClippingRegion(dirtyBorderRegion);
fDecorator->Draw(dirtyBorderRegion.Frame()); fDecorator->Draw(dirtyBorderRegion->Frame());
fDrawingEngine->Unlock(); fDrawingEngine->Unlock();
} }
fRegionPool.Recycle(dirtyBorderRegion);
} }
@@ -1730,15 +1713,10 @@ WindowLayer::BeginUpdate(BPrivate::PortLink& link)
// NOTE: since we might "shift" parts of the // NOTE: since we might "shift" parts of the
// internal dirty regions from the desktop thread // internal dirty regions from the desktop thread
// in response to WindowLayer::ResizeBy(), which // in response to WindowLayer::ResizeBy(), which
// might move arround views, this function needs to block // might move arround views, the user of this function
// on the global clipping lock so that the internal // needs to hold the global clipping lock so that the internal
// dirty regions are not messed with from the Desktop thread // dirty regions are not messed with from the Desktop thread
// and ServerWindow thread at the same time. // and ServerWindow thread at the same time.
if (!fDesktop->LockSingleWindow()) {
link.StartMessage(B_ERROR);
link.Flush();
return;
}
if (fUpdateRequested) { if (fUpdateRequested) {
// make the pending update session the current update session // make the pending update session the current update session
@@ -1760,8 +1738,15 @@ WindowLayer::BeginUpdate(BPrivate::PortLink& link)
if (!fContentRegionValid) if (!fContentRegionValid)
_UpdateContentRegion(); _UpdateContentRegion();
BRegion dirty(fCurrentUpdateSession.DirtyRegion()); BRegion* dirty = fRegionPool.GetRegion(
dirty.IntersectWith(&VisibleContentRegion()); fCurrentUpdateSession.DirtyRegion());
if (!dirty) {
link.StartMessage(B_ERROR);
link.Flush();
return;
}
dirty->IntersectWith(&VisibleContentRegion());
//fDrawingEngine->FillRegion(dirty, RGBColor(255, 0, 0, 255)); //fDrawingEngine->FillRegion(dirty, RGBColor(255, 0, 0, 255));
@@ -1772,10 +1757,10 @@ WindowLayer::BeginUpdate(BPrivate::PortLink& link)
link.Attach<float>(fFrame.Width()); link.Attach<float>(fFrame.Width());
link.Attach<float>(fFrame.Height()); link.Attach<float>(fFrame.Height());
// append he update rect in screen coords // append he update rect in screen coords
link.Attach<BRect>(dirty.Frame()); link.Attach<BRect>(dirty->Frame());
// find and attach all views that intersect with // find and attach all views that intersect with
// the dirty region // the dirty region
fTopLayer->AddTokensForLayersInRegion(link, dirty, &fContentRegion); fTopLayer->AddTokensForLayersInRegion(link, *dirty, &fContentRegion);
// mark the end of the token "list" // mark the end of the token "list"
link.Attach<int32>(B_NULL_TOKEN); link.Attach<int32>(B_NULL_TOKEN);
link.Flush(); link.Flush();
@@ -1783,17 +1768,17 @@ WindowLayer::BeginUpdate(BPrivate::PortLink& link)
#if DELAYED_BACKGROUND_CLEARING #if DELAYED_BACKGROUND_CLEARING
// NOTE: turning off DELAYED_BACKGROUND_CLEARING will // NOTE: turning off DELAYED_BACKGROUND_CLEARING will
// need investigation if it even still works... // need investigation if it even still works...
fTopLayer->Draw(fDrawingEngine, &dirty, fTopLayer->Draw(fDrawingEngine, dirty,
&fContentRegion, true); &fContentRegion, true);
#endif
fRegionPool.Recycle(dirty);
#endif
} else { } else {
printf("BeginUpdate() but no update requested!!\n"); printf("BeginUpdate() but no update requested!!\n");
link.StartMessage(B_ERROR); link.StartMessage(B_ERROR);
link.Flush(); link.Flush();
fprintf(stderr, "WindowLayer::BeginUpdate() - no update requested!\n"); fprintf(stderr, "WindowLayer::BeginUpdate() - no update requested!\n");
} }
fDesktop->UnlockSingleWindow();
} }
@@ -1801,8 +1786,6 @@ void
WindowLayer::EndUpdate() WindowLayer::EndUpdate()
{ {
// NOTE: see comment in _BeginUpdate() // NOTE: see comment in _BeginUpdate()
if (!fDesktop->LockSingleWindow())
return;
if (fInUpdate) { if (fInUpdate) {
fCurrentUpdateSession.SetUsed(false); fCurrentUpdateSession.SetUsed(false);
@@ -1816,8 +1799,6 @@ WindowLayer::EndUpdate()
} else { } else {
fUpdateRequested = false; fUpdateRequested = false;
} }
fDesktop->UnlockSingleWindow();
} }
+13 -6
View File
@@ -13,6 +13,7 @@
#include "Decorator.h" #include "Decorator.h"
#include "ViewLayer.h" #include "ViewLayer.h"
#include "RegionPool.h"
#include "ServerWindow.h" #include "ServerWindow.h"
#include "WindowList.h" #include "WindowList.h"
@@ -56,10 +57,6 @@ class WindowLayer {
::ServerWindow* ServerWindow() const { return fWindow; } ::ServerWindow* ServerWindow() const { return fWindow; }
::EventTarget& EventTarget() const { return fWindow->EventTarget(); } ::EventTarget& EventTarget() const { return fWindow->EventTarget(); }
// for convenience, handles window not attached to Desktop
bool ReadLockWindows();
void ReadUnlockWindows();
// setting and getting the "hard" clipping, you need to have // setting and getting the "hard" clipping, you need to have
// WriteLock()ed the clipping! // WriteLock()ed the clipping!
void SetClipping(BRegion* stillAvailableOnScreen); void SetClipping(BRegion* stillAvailableOnScreen);
@@ -116,6 +113,16 @@ class WindowLayer {
DrawingEngine* GetDrawingEngine() const DrawingEngine* GetDrawingEngine() const
{ return fDrawingEngine; } { return fDrawingEngine; }
// managing a region pool
::RegionPool* RegionPool()
{ return &fRegionPool; }
inline BRegion* GetRegion()
{ return fRegionPool.GetRegion(); }
inline BRegion* GetRegion(const BRegion& copy)
{ return fRegionPool.GetRegion(copy); }
inline void RecycleRegion(BRegion* region)
{ fRegionPool.Recycle(region); }
void CopyContents(BRegion* region, void CopyContents(BRegion* region,
int32 xOffset, int32 yOffset); int32 xOffset, int32 yOffset);
@@ -248,6 +255,8 @@ class WindowLayer {
BRegion fEffectiveDrawingRegion; BRegion fEffectiveDrawingRegion;
bool fEffectiveDrawingRegionValid; bool fEffectiveDrawingRegionValid;
::RegionPool fRegionPool;
BObjectList<WindowLayer> fSubsets; BObjectList<WindowLayer> fSubsets;
// TODO: remove those some day (let the decorator handle that stuff) // TODO: remove those some day (let the decorator handle that stuff)
@@ -322,8 +331,6 @@ class WindowLayer {
int32 fMaxWidth; int32 fMaxWidth;
int32 fMinHeight; int32 fMinHeight;
int32 fMaxHeight; int32 fMaxHeight;
mutable bool fReadLocked;
}; };
#endif // WINDOW_LAYER_H #endif // WINDOW_LAYER_H
+6 -2
View File
@@ -77,14 +77,18 @@ Workspace::Workspace(Desktop& desktop, int32 index)
fDesktop(desktop), fDesktop(desktop),
fCurrentWorkspace(index == desktop.CurrentWorkspace()) fCurrentWorkspace(index == desktop.CurrentWorkspace())
{ {
fDesktop.LockSingleWindow(); // fDesktop.LockSingleWindow();
// TODO: in which threads is this being used?
// from my investigations, it is used in the
// WorkspacesLayer::Draw(), which would have
// to hold the read lock already
RewindWindows(); RewindWindows();
} }
Workspace::~Workspace() Workspace::~Workspace()
{ {
fDesktop.UnlockSingleWindow(); // fDesktop.UnlockSingleWindow();
} }
+3 -2
View File
@@ -20,8 +20,8 @@ UseFreeTypeHeaders ;
local defines = [ FDefines TEST_MODE=1 ] ; local defines = [ FDefines TEST_MODE=1 ] ;
# USE_DIRECT_WINDOW_TEST_MODE=1 # USE_DIRECT_WINDOW_TEST_MODE=1
SubDirCcFlags $(defines) -fcheck-memory-usage -D_NO_INLINE_ASM ; SubDirCcFlags $(defines) ; #-fcheck-memory-usage -D_NO_INLINE_ASM ;
SubDirC++Flags $(defines) -fcheck-memory-usage -D_NO_INLINE_ASM ; SubDirC++Flags $(defines) ; #-fcheck-memory-usage -D_NO_INLINE_ASM ;
SEARCH_SOURCE += $(appServerDir) [ FDirName $(appServerDir) drawing ] ; SEARCH_SOURCE += $(appServerDir) [ FDirName $(appServerDir) drawing ] ;
@@ -112,6 +112,7 @@ Server haiku_app_server :
DefaultDecorator.cpp DefaultDecorator.cpp
OffscreenServerWindow.cpp OffscreenServerWindow.cpp
OffscreenWindowLayer.cpp OffscreenWindowLayer.cpp
RegionPool.cpp
ServerPicture.cpp ServerPicture.cpp
ServerScreen.cpp ServerScreen.cpp
ViewLayer.cpp ViewLayer.cpp