* 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:
@@ -199,8 +199,6 @@ enum {
|
||||
AS_SCREENMODE_CHANGED,
|
||||
|
||||
// Graphics calls
|
||||
AS_BEGIN_TRANSACTION,
|
||||
AS_END_TRANSACTION,
|
||||
AS_SET_HIGH_COLOR,
|
||||
AS_SET_LOW_COLOR,
|
||||
AS_SET_VIEW_COLOR,
|
||||
|
||||
@@ -50,6 +50,9 @@
|
||||
# define STRACE(a) ;
|
||||
#endif
|
||||
|
||||
#if !USE_MULTI_LOCKER
|
||||
# define AutoWriteLocker BAutolock
|
||||
#endif
|
||||
|
||||
class KeyboardFilter : public EventFilter {
|
||||
public:
|
||||
@@ -1850,18 +1853,14 @@ Desktop::ViewUnderMouse(const WindowLayer* window)
|
||||
WindowLayer *
|
||||
Desktop::FindWindowLayerByClientToken(int32 token, team_id teamID)
|
||||
{
|
||||
LockSingleWindow();
|
||||
|
||||
for (WindowLayer *window = fAllWindows.FirstWindow(); window != NULL;
|
||||
window = window->NextWindow(kAllWindowList)) {
|
||||
if (window->ServerWindow()->ClientToken() == token
|
||||
&& window->ServerWindow()->ClientTeam() == teamID) {
|
||||
UnlockSingleWindow();
|
||||
return window;
|
||||
}
|
||||
}
|
||||
|
||||
UnlockSingleWindow();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1869,7 +1868,7 @@ Desktop::FindWindowLayerByClientToken(int32 token, team_id teamID)
|
||||
void
|
||||
Desktop::MinimizeApplication(team_id team)
|
||||
{
|
||||
BAutolock locker(fWindowLock);
|
||||
AutoWriteLocker locker(fWindowLock);
|
||||
|
||||
// Just minimize all windows of that application
|
||||
|
||||
@@ -1886,7 +1885,7 @@ Desktop::MinimizeApplication(team_id team)
|
||||
void
|
||||
Desktop::BringApplicationToFront(team_id team)
|
||||
{
|
||||
BAutolock locker(fWindowLock);
|
||||
AutoWriteLocker locker(fWindowLock);
|
||||
|
||||
// TODO: for now, just maximize all windows of that application
|
||||
|
||||
@@ -1929,7 +1928,7 @@ Desktop::WindowAction(int32 windowToken, int32 action)
|
||||
void
|
||||
Desktop::WriteWindowList(team_id team, BPrivate::LinkSender& sender)
|
||||
{
|
||||
BAutolock locker(fWindowLock);
|
||||
AutoWriteLocker locker(fWindowLock);
|
||||
|
||||
// compute the number of windows
|
||||
|
||||
@@ -1961,7 +1960,7 @@ Desktop::WriteWindowList(team_id team, BPrivate::LinkSender& sender)
|
||||
void
|
||||
Desktop::WriteWindowInfo(int32 serverToken, BPrivate::LinkSender& sender)
|
||||
{
|
||||
BAutolock locker(fWindowLock);
|
||||
AutoWriteLocker locker(fWindowLock);
|
||||
BAutolock tokenLocker(BPrivate::gDefaultTokens);
|
||||
|
||||
::ServerWindow* window;
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include <Region.h>
|
||||
#include <Window.h>
|
||||
|
||||
#define USE_MULTI_LOCKER 0
|
||||
#define USE_MULTI_LOCKER 1
|
||||
|
||||
#if USE_MULTI_LOCKER
|
||||
# include "MultiLocker.h"
|
||||
|
||||
@@ -38,6 +38,7 @@ Server app_server :
|
||||
PNGDump.cpp
|
||||
RAMLinkMsgReader.cpp
|
||||
RGBColor.cpp
|
||||
RegionPool.cpp
|
||||
ScreenManager.cpp
|
||||
ServerApp.cpp
|
||||
ServerBitmap.cpp
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <OS.h>
|
||||
|
||||
//#define TIMING 1
|
||||
#define DEBUG 1
|
||||
//#define DEBUG 1
|
||||
|
||||
|
||||
MultiLocker::MultiLocker(const char* semaphoreBaseName)
|
||||
@@ -132,6 +132,11 @@ MultiLocker::ReadLock()
|
||||
if (fInit == B_OK) {
|
||||
if (IsWriteLocked()) {
|
||||
//the writer simply increments the nesting
|
||||
#if DEBUG
|
||||
if (fWriterNest < 0)
|
||||
debugger("ReadLock() - negative writer nest count\n");
|
||||
#endif
|
||||
|
||||
fWriterNest++;
|
||||
locked = true;
|
||||
} else {
|
||||
@@ -174,10 +179,22 @@ MultiLocker::WriteLock()
|
||||
|
||||
if (IsWriteLocked(&stack_base, &thread)) {
|
||||
//already the writer - increment the nesting count
|
||||
#if DEBUG
|
||||
if (fWriterNest < 0)
|
||||
debugger("WriteLock() - negative nest count\n");
|
||||
#endif
|
||||
|
||||
fWriterNest++;
|
||||
locked = true;
|
||||
} else {
|
||||
//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) {
|
||||
//another writer in the lock - acquire the semaphore
|
||||
locked = (acquire_sem_etc(fWriterLock, 1, B_DO_NOT_RESCHEDULE,
|
||||
@@ -227,6 +244,12 @@ MultiLocker::ReadUnlock()
|
||||
if (IsWriteLocked()) {
|
||||
//writers simply decrement the nesting count
|
||||
fWriterNest--;
|
||||
|
||||
#if DEBUG
|
||||
if (fWriterNest < 0)
|
||||
debugger("ReadUnlock() - negative writer nest count\n");
|
||||
#endif
|
||||
|
||||
unlocked = true;
|
||||
} else {
|
||||
//decrement and retrieve the read counter
|
||||
@@ -237,7 +260,7 @@ MultiLocker::ReadUnlock()
|
||||
B_DO_NOT_RESCHEDULE) == B_OK);
|
||||
} else unlocked = true;
|
||||
|
||||
#ifdef DEBUG
|
||||
#if DEBUG
|
||||
//unregister if we released the lock
|
||||
if (unlocked) unregister_thread();
|
||||
#endif
|
||||
@@ -265,6 +288,12 @@ MultiLocker::WriteUnlock()
|
||||
//if this is a nested lock simply decrement the nest count
|
||||
if (fWriterNest > 0) {
|
||||
fWriterNest--;
|
||||
|
||||
#if DEBUG
|
||||
if (fWriterNest < 0)
|
||||
debugger("WriteUnlock(): nest count now negative\n");
|
||||
#endif
|
||||
|
||||
unlocked = true;
|
||||
} else {
|
||||
//writer finally unlocking
|
||||
@@ -416,14 +445,16 @@ MultiLocker::IsReadLocked()
|
||||
void
|
||||
MultiLocker::register_thread()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
#if DEBUG
|
||||
#if TIMING
|
||||
bigtime_t start = system_time();
|
||||
#endif
|
||||
|
||||
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]++;
|
||||
|
||||
#if TIMING
|
||||
@@ -439,7 +470,7 @@ MultiLocker::register_thread()
|
||||
void
|
||||
MultiLocker::unregister_thread()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
#if DEBUG
|
||||
#if TIMING
|
||||
bigtime_t start = system_time();
|
||||
#endif
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
/* MultiLocker.h */
|
||||
/*
|
||||
Copyright 2005-2006, Haiku.
|
||||
Distributed under the terms of the MIT license.
|
||||
|
||||
Copyright 1999, Be Incorporated. All Rights Reserved.
|
||||
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
|
||||
#define MULTI_LOCKER_H
|
||||
@@ -31,7 +41,8 @@ class MultiLocker {
|
||||
bool WriteUnlock();
|
||||
|
||||
//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 non-debug mode returns true
|
||||
bool IsReadLocked();
|
||||
@@ -82,31 +93,41 @@ class MultiLocker {
|
||||
class AutoWriteLocker {
|
||||
public:
|
||||
AutoWriteLocker(MultiLocker* lock)
|
||||
: fLock(*lock)
|
||||
{
|
||||
fLock.WriteLock();
|
||||
}
|
||||
AutoWriteLocker(MultiLocker& lock)
|
||||
: fLock(lock)
|
||||
{
|
||||
fLock->WriteLock();
|
||||
fLock.WriteLock();
|
||||
}
|
||||
~AutoWriteLocker()
|
||||
{
|
||||
fLock->WriteUnlock();
|
||||
fLock.WriteUnlock();
|
||||
}
|
||||
private:
|
||||
MultiLocker* fLock;
|
||||
MultiLocker& fLock;
|
||||
};
|
||||
|
||||
class AutoReadLocker {
|
||||
public:
|
||||
AutoReadLocker(MultiLocker* lock)
|
||||
: fLock(*lock)
|
||||
{
|
||||
fLock.ReadLock();
|
||||
}
|
||||
AutoReadLocker(MultiLocker& lock)
|
||||
: fLock(lock)
|
||||
{
|
||||
fLock->ReadLock();
|
||||
fLock.ReadLock();
|
||||
}
|
||||
~AutoReadLocker()
|
||||
{
|
||||
fLock->ReadUnlock();
|
||||
fLock.ReadUnlock();
|
||||
}
|
||||
private:
|
||||
MultiLocker* fLock;
|
||||
MultiLocker& fLock;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -194,6 +194,7 @@ ServerBitmap::_HandleSpace(color_space space, int32 bytesPerRow)
|
||||
case B_YCbCr422:
|
||||
case B_YUV422:
|
||||
minBPR = (fWidth + 3) / 4 * 8;
|
||||
// TODO: huh? why not simply fWidth * 2 ?!?
|
||||
fBitsPerPixel = 16;
|
||||
break;
|
||||
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
#include "ServerPicture.h"
|
||||
#include "ServerProtocol.h"
|
||||
#include "WindowLayer.h"
|
||||
#include "Workspace.h"
|
||||
#include "WorkspacesLayer.h"
|
||||
|
||||
#include "ServerWindow.h"
|
||||
@@ -386,8 +385,11 @@ ServerWindow::SetTitle(const char* newTitle)
|
||||
rename_thread(Thread(), name);
|
||||
}
|
||||
|
||||
if (fWindowLayer != NULL)
|
||||
if (fWindowLayer != NULL) {
|
||||
fDesktop->UnlockSingleWindow();
|
||||
fDesktop->SetWindowTitle(fWindowLayer, newTitle);
|
||||
fDesktop->LockSingleWindow();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -584,10 +586,12 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
|
||||
|
||||
link.Read<bool>(&activate);
|
||||
|
||||
fDesktop->UnlockSingleWindow();
|
||||
if (activate)
|
||||
fDesktop->ActivateWindow(fWindowLayer);
|
||||
else
|
||||
fDesktop->SendWindowBehind(fWindowLayer, NULL);
|
||||
fDesktop->LockSingleWindow();
|
||||
break;
|
||||
}
|
||||
case AS_SEND_BEHIND:
|
||||
@@ -602,7 +606,9 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
|
||||
|
||||
WindowLayer *behindOf;
|
||||
if ((behindOf = fDesktop->FindWindowLayerByClientToken(token, teamID)) != NULL) {
|
||||
fDesktop->UnlockSingleWindow();
|
||||
fDesktop->SendWindowBehind(fWindowLayer, behindOf);
|
||||
fDesktop->LockSingleWindow();
|
||||
status = B_OK;
|
||||
} else
|
||||
status = B_NAME_NOT_FOUND;
|
||||
@@ -617,23 +623,6 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
|
||||
NotifyQuitRequested();
|
||||
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:
|
||||
{
|
||||
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) {
|
||||
status = B_BAD_VALUE;
|
||||
} else {
|
||||
fDesktop->UnlockSingleWindow();
|
||||
status = fDesktop->AddWindowToSubset(fWindowLayer, windowLayer)
|
||||
? B_OK : B_NO_MEMORY;
|
||||
fDesktop->LockSingleWindow();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -702,7 +693,9 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
|
||||
WindowLayer* windowLayer = fDesktop->FindWindowLayerByClientToken(
|
||||
token, App()->ClientTeam());
|
||||
if (windowLayer != NULL) {
|
||||
fDesktop->UnlockSingleWindow();
|
||||
fDesktop->RemoveWindowFromSubset(fWindowLayer, windowLayer);
|
||||
fDesktop->LockSingleWindow();
|
||||
status = B_OK;
|
||||
} else
|
||||
status = B_BAD_VALUE;
|
||||
@@ -725,8 +718,11 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
|
||||
? 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->LockSingleWindow();
|
||||
}
|
||||
|
||||
fLink.StartMessage(status);
|
||||
fLink.Flush();
|
||||
@@ -744,8 +740,11 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
|
||||
? 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->LockSingleWindow();
|
||||
}
|
||||
|
||||
fLink.StartMessage(status);
|
||||
fLink.Flush();
|
||||
@@ -763,8 +762,11 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
|
||||
? B_OK : B_BAD_VALUE;
|
||||
}
|
||||
|
||||
if (status == B_OK && !fWindowLayer->IsOffscreenWindow())
|
||||
if (status == B_OK && !fWindowLayer->IsOffscreenWindow()) {
|
||||
fDesktop->UnlockSingleWindow();
|
||||
fDesktop->SetWindowFlags(fWindowLayer, flags);
|
||||
fDesktop->LockSingleWindow();
|
||||
}
|
||||
|
||||
fLink.StartMessage(status);
|
||||
fLink.Flush();
|
||||
@@ -801,7 +803,9 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
|
||||
STRACE(("ServerWindow %s: Message AS_SET_WORKSPACES %lx\n",
|
||||
Title(), newWorkspaces));
|
||||
|
||||
fDesktop->UnlockSingleWindow();
|
||||
fDesktop->SetWindowWorkspaces(fWindowLayer, newWorkspaces);
|
||||
fDesktop->LockSingleWindow();
|
||||
break;
|
||||
}
|
||||
case AS_WINDOW_RESIZE:
|
||||
@@ -820,7 +824,9 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
|
||||
// pragmatically set window bounds
|
||||
fLink.StartMessage(B_BUSY);
|
||||
} else {
|
||||
fDesktop->UnlockSingleWindow();
|
||||
fDesktop->ResizeWindowBy(fWindowLayer, xResizeBy, yResizeBy);
|
||||
fDesktop->LockSingleWindow();
|
||||
fLink.StartMessage(B_OK);
|
||||
}
|
||||
fLink.Flush();
|
||||
@@ -842,7 +848,9 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
|
||||
// pragmatically set window positions
|
||||
fLink.StartMessage(B_BUSY);
|
||||
} else {
|
||||
fDesktop->UnlockSingleWindow();
|
||||
fDesktop->MoveWindowBy(fWindowLayer, xMoveBy, yMoveBy);
|
||||
fDesktop->LockSingleWindow();
|
||||
fLink.StartMessage(B_OK);
|
||||
}
|
||||
fLink.Flush();
|
||||
@@ -901,22 +909,12 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
|
||||
|
||||
case AS_BEGIN_UPDATE:
|
||||
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);
|
||||
break;
|
||||
|
||||
case AS_END_UPDATE:
|
||||
DTRACE(("ServerWindowo %s: AS_END_UPDATE\n", Title()));
|
||||
fWindowLayer->EndUpdate();
|
||||
//fDesktop->UnlockSingleWindow();
|
||||
break;
|
||||
|
||||
case AS_GET_MOUSE:
|
||||
@@ -2697,7 +2695,6 @@ ServerWindow::_SetCurrentLayer(ViewLayer* layer)
|
||||
fCurrentDrawingRegionValid = false;
|
||||
#if 0
|
||||
#if DELAYED_BACKGROUND_CLEARING
|
||||
fWindowLayer->ReadLockWindows();
|
||||
if (fCurrentLayer && fCurrentLayer->IsBackgroundDirty() && fWindowLayer->InUpdate()) {
|
||||
DrawingEngine* drawingEngine = fWindowLayer->GetDrawingEngine();
|
||||
if (drawingEngine->Lock()) {
|
||||
@@ -2714,7 +2711,6 @@ fWindowLayer->ReadLockWindows();
|
||||
drawingEngine->Unlock();
|
||||
}
|
||||
}
|
||||
fWindowLayer->ReadUnlockWindows();
|
||||
#endif
|
||||
#endif // 0
|
||||
}
|
||||
|
||||
@@ -198,8 +198,12 @@ ViewLayer::AddChild(ViewLayer* layer)
|
||||
// trigger redraw
|
||||
BRect clippedFrame = layer->Frame();
|
||||
ConvertToVisibleInTopView(&clippedFrame);
|
||||
BRegion dirty(clippedFrame);
|
||||
fWindow->MarkContentDirty(dirty);
|
||||
BRegion* dirty = fWindow->GetRegion();
|
||||
if (dirty) {
|
||||
dirty->Set(clippedFrame);
|
||||
fWindow->MarkContentDirty(*dirty);
|
||||
fWindow->RecycleRegion(dirty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -244,8 +248,12 @@ ViewLayer::RemoveChild(ViewLayer* layer)
|
||||
// trigger redraw
|
||||
BRect clippedFrame = layer->Frame();
|
||||
ConvertToVisibleInTopView(&clippedFrame);
|
||||
BRegion dirty(clippedFrame);
|
||||
fWindow->MarkContentDirty(dirty);
|
||||
BRegion* dirty = fWindow->GetRegion();
|
||||
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
|
||||
// makes sure we don't copy parts hidden under
|
||||
// parent views
|
||||
BRegion copyRegion(oldVisibleBounds & newVisibleBounds);
|
||||
fWindow->CopyContents(©Region, x, y);
|
||||
BRegion* region = fWindow->GetRegion();
|
||||
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
|
||||
}
|
||||
|
||||
@@ -681,32 +695,37 @@ ViewLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion)
|
||||
oldBounds.right -= x;
|
||||
oldBounds.bottom -= y;
|
||||
|
||||
BRegion dirty(Bounds());
|
||||
dirty.Include(oldBounds);
|
||||
BRegion* dirty = fWindow->GetRegion();
|
||||
if (!dirty)
|
||||
return;
|
||||
|
||||
dirty->Set(Bounds());
|
||||
dirty->Include(oldBounds);
|
||||
|
||||
if (!(fFlags & B_FULL_UPDATE_ON_RESIZE)) {
|
||||
// the dirty region is just the difference of
|
||||
// old and new bounds
|
||||
dirty.Exclude(oldBounds & Bounds());
|
||||
dirty->Exclude(oldBounds & Bounds());
|
||||
}
|
||||
|
||||
InvalidateScreenClipping(true);
|
||||
|
||||
if (dirty.CountRects() > 0) {
|
||||
if (dirty->CountRects() > 0) {
|
||||
// exclude children, they are expected to
|
||||
// include their own dirty regions in ParentResized()
|
||||
for (ViewLayer* child = FirstChild(); child; child = child->NextSibling()) {
|
||||
if (child->IsVisible()) {
|
||||
BRect previousChildVisible(child->Frame() & oldBounds & Bounds());
|
||||
if (dirty.Frame().Intersects(previousChildVisible)) {
|
||||
dirty.Exclude(previousChildVisible);
|
||||
if (dirty->Frame().Intersects(previousChildVisible)) {
|
||||
dirty->Exclude(previousChildVisible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConvertToScreen(&dirty);
|
||||
dirtyRegion->Include(&dirty);
|
||||
ConvertToScreen(dirty);
|
||||
dirtyRegion->Include(dirty);
|
||||
}
|
||||
fWindow->RecycleRegion(dirty);
|
||||
}
|
||||
|
||||
// layout the children
|
||||
@@ -795,10 +814,16 @@ ViewLayer::ScrollBy(int32 x, int32 y, BRegion* dirtyRegion)
|
||||
|
||||
// find the dirty region as far as we are
|
||||
// concerned
|
||||
BRegion dirty(oldBounds);
|
||||
BRegion* dirty = fWindow->GetRegion();
|
||||
if (!dirty)
|
||||
return;
|
||||
|
||||
dirty->Set(oldBounds);
|
||||
stillVisibleBounds.OffsetBy(-x, -y);
|
||||
dirty.Exclude(stillVisibleBounds);
|
||||
dirtyRegion->Include(&dirty);
|
||||
dirty->Exclude(stillVisibleBounds);
|
||||
dirtyRegion->Include(dirty);
|
||||
|
||||
fWindow->RecycleRegion(dirty);
|
||||
|
||||
// the screen clipping of this view and it's
|
||||
// childs is no longer valid
|
||||
@@ -843,12 +868,18 @@ ViewLayer::CopyBits(BRect src, BRect dst, BRegion& windowContentClipping)
|
||||
BRect dirtyDst(dst);
|
||||
ConvertToVisibleInTopView(&dirtyDst);
|
||||
|
||||
BRegion dirty(dirtyDst);
|
||||
BRegion* dirty = fWindow->GetRegion();
|
||||
if (!dirty)
|
||||
return;
|
||||
|
||||
dirty->Set(dirtyDst);
|
||||
// exclude the part that we could copy
|
||||
visibleSrc.OffsetBy(xOffset, yOffset);
|
||||
dirty.Exclude(visibleSrc);
|
||||
dirty.IntersectWith(&ScreenClipping(&windowContentClipping));
|
||||
fWindow->MarkContentDirty(dirty);
|
||||
dirty->Exclude(visibleSrc);
|
||||
dirty->IntersectWith(&ScreenClipping(&windowContentClipping));
|
||||
fWindow->MarkContentDirty(*dirty);
|
||||
|
||||
fWindow->RecycleRegion(dirty);
|
||||
}
|
||||
|
||||
|
||||
@@ -1024,8 +1055,12 @@ ViewLayer::SetHidden(bool hidden)
|
||||
// trigger a redraw
|
||||
BRect clippedBounds = Bounds();
|
||||
ConvertToVisibleInTopView(&clippedBounds);
|
||||
BRegion dirty(clippedBounds);
|
||||
fWindow->MarkContentDirty(dirty);
|
||||
BRegion* dirty = fWindow->GetRegion();
|
||||
if (!dirty)
|
||||
return;
|
||||
dirty->Set(clippedBounds);
|
||||
fWindow->MarkContentDirty(*dirty);
|
||||
fWindow->RecycleRegion(dirty);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
+145
-164
@@ -88,6 +88,8 @@ WindowLayer::WindowLayer(const BRect& frame, const char *name,
|
||||
fEffectiveDrawingRegion(),
|
||||
fEffectiveDrawingRegionValid(false),
|
||||
|
||||
fRegionPool(),
|
||||
|
||||
fIsClosing(false),
|
||||
fIsMinimizing(false),
|
||||
fIsZooming(false),
|
||||
@@ -122,9 +124,7 @@ WindowLayer::WindowLayer(const BRect& frame, const char *name,
|
||||
fMinWidth(1),
|
||||
fMaxWidth(32768),
|
||||
fMinHeight(1),
|
||||
fMaxHeight(32768),
|
||||
|
||||
fReadLocked(false)
|
||||
fMaxHeight(32768)
|
||||
{
|
||||
// make sure our arguments are valid
|
||||
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
|
||||
WindowLayer::SetClipping(BRegion* stillAvailableOnScreen)
|
||||
{
|
||||
@@ -413,29 +390,27 @@ WindowLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion)
|
||||
void
|
||||
WindowLayer::ScrollViewBy(ViewLayer* view, int32 dx, int32 dy)
|
||||
{
|
||||
// this can be executed from any thread, but if the
|
||||
// desktop thread is executing this, it should have
|
||||
// the write lock, otherwise it is not prevented
|
||||
// from executing this at the same time as the window
|
||||
// is doing something else here!
|
||||
// this is executed in ServerWindow with the Readlock
|
||||
// held
|
||||
|
||||
if (!view || view == fTopLayer || (dx == 0 && dy == 0))
|
||||
return;
|
||||
|
||||
if (fDesktop && fDesktop->LockSingleWindow()) {
|
||||
BRegion dirty;
|
||||
view->ScrollBy(dx, dy, &dirty);
|
||||
BRegion* dirty = fRegionPool.GetRegion();
|
||||
if (!dirty)
|
||||
return;
|
||||
|
||||
view->ScrollBy(dx, dy, dirty);
|
||||
|
||||
//fDrawingEngine->FillRegion(dirty, RGBColor(255, 0, 255, 255));
|
||||
//snooze(2000);
|
||||
|
||||
if (IsVisible() && view->IsVisible()) {
|
||||
dirty.IntersectWith(&VisibleContentRegion());
|
||||
_TriggerContentRedraw(dirty);
|
||||
}
|
||||
|
||||
fDesktop->UnlockSingleWindow();
|
||||
if (IsVisible() && view->IsVisible()) {
|
||||
dirty->IntersectWith(&VisibleContentRegion());
|
||||
_TriggerContentRedraw(*dirty);
|
||||
}
|
||||
|
||||
fRegionPool.Recycle(dirty);
|
||||
}
|
||||
|
||||
|
||||
@@ -443,64 +418,67 @@ WindowLayer::ScrollViewBy(ViewLayer* view, int32 dx, int32 dy)
|
||||
void
|
||||
WindowLayer::CopyContents(BRegion* region, int32 xOffset, int32 yOffset)
|
||||
{
|
||||
if (IsVisible() && fDesktop && fDesktop->LockSingleWindow()) {
|
||||
BRegion newDirty(*region);
|
||||
// executed in ServerWindow thread with the read lock held
|
||||
if (!IsVisible())
|
||||
return;
|
||||
|
||||
// clip the region to the visible contents at the
|
||||
// source and destination location (note that VisibleContentRegion()
|
||||
// is used once to make sure it is valid, then fVisibleContentRegion
|
||||
// is used directly)
|
||||
region->IntersectWith(&VisibleContentRegion());
|
||||
BRegion* newDirty = fRegionPool.GetRegion(*region);
|
||||
|
||||
// clip the region to the visible contents at the
|
||||
// source and destination location (note that 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) {
|
||||
region->OffsetBy(xOffset, yOffset);
|
||||
region->IntersectWith(&fVisibleContentRegion);
|
||||
if (region->CountRects() > 0) {
|
||||
// if the region still contains any rects
|
||||
// offset to source location again
|
||||
region->OffsetBy(-xOffset, -yOffset);
|
||||
// the part which we can copy is not dirty
|
||||
newDirty.Exclude(region);
|
||||
|
||||
fDrawingEngine->CopyRegion(region, xOffset, yOffset);
|
||||
// if the region still contains any rects
|
||||
// offset to source location again
|
||||
region->OffsetBy(-xOffset, -yOffset);
|
||||
// the part which we can copy is not dirty
|
||||
newDirty->Exclude(region);
|
||||
|
||||
fDrawingEngine->CopyRegion(region, xOffset, yOffset);
|
||||
|
||||
// move along the already dirty regions that are common
|
||||
// with the region that we could copy
|
||||
_ShiftPartOfRegion(&fDirtyRegion, region, xOffset, yOffset);
|
||||
if (fPendingUpdateSession.IsUsed())
|
||||
_ShiftPartOfRegion(&fPendingUpdateSession.DirtyRegion(), region, xOffset, yOffset);
|
||||
// move along the already dirty regions that are common
|
||||
// with the region that we could copy
|
||||
_ShiftPartOfRegion(&fDirtyRegion, region, xOffset, yOffset);
|
||||
if (fPendingUpdateSession.IsUsed())
|
||||
_ShiftPartOfRegion(&fPendingUpdateSession.DirtyRegion(), region, xOffset, yOffset);
|
||||
|
||||
if (fCurrentUpdateSession.IsUsed()) {
|
||||
// if there are parts in the current update session
|
||||
// that intersect with the copied region, we cannot
|
||||
// simply shift them as with the other dirty regions
|
||||
// - we cannot change the update rect already told to the
|
||||
// client, that's why we transfer those parts to the
|
||||
// new dirty region instead
|
||||
BRegion common(*region);
|
||||
// see if there is a common part at all
|
||||
common.IntersectWith(&fCurrentUpdateSession.DirtyRegion());
|
||||
if (common.CountRects() > 0) {
|
||||
// cut the common part from the region
|
||||
fCurrentUpdateSession.DirtyRegion().Exclude(&common);
|
||||
newDirty.Include(&common);
|
||||
}
|
||||
if (fCurrentUpdateSession.IsUsed()) {
|
||||
// if there are parts in the current update session
|
||||
// that intersect with the copied region, we cannot
|
||||
// simply shift them as with the other dirty regions
|
||||
// - we cannot change the update rect already told to the
|
||||
// client, that's why we transfer those parts to the
|
||||
// new dirty region instead
|
||||
BRegion* common = fRegionPool.GetRegion(*region);
|
||||
// see if there is a common part at all
|
||||
common->IntersectWith(&fCurrentUpdateSession.DirtyRegion());
|
||||
if (common->CountRects() > 0) {
|
||||
// cut the common part from the region
|
||||
fCurrentUpdateSession.DirtyRegion().Exclude(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;
|
||||
|
||||
if (ReadLockWindows()) {
|
||||
if (!fContentRegionValid)
|
||||
_UpdateContentRegion();
|
||||
if (!fContentRegionValid)
|
||||
_UpdateContentRegion();
|
||||
|
||||
view = fTopLayer->ViewAt(where, &fContentRegion);
|
||||
view = fTopLayer->ViewAt(where, &fContentRegion);
|
||||
|
||||
ReadUnlockWindows();
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -641,16 +616,18 @@ WindowLayer::ProcessDirtyRegion(BRegion& region)
|
||||
void
|
||||
WindowLayer::RedrawDirtyRegion()
|
||||
{
|
||||
if (!fDesktop || !fDesktop->LockSingleWindow())
|
||||
return;
|
||||
// executed from ServerWindow with the read lock held
|
||||
|
||||
if (IsVisible()) {
|
||||
_DrawBorder();
|
||||
|
||||
BRegion dirtyContentRegion(VisibleContentRegion());
|
||||
dirtyContentRegion.IntersectWith(&fDirtyRegion);
|
||||
BRegion* dirtyContentRegion =
|
||||
fRegionPool.GetRegion(VisibleContentRegion());
|
||||
dirtyContentRegion->IntersectWith(&fDirtyRegion);
|
||||
|
||||
_TriggerContentRedraw(dirtyContentRegion);
|
||||
_TriggerContentRedraw(*dirtyContentRegion);
|
||||
|
||||
fRegionPool.Recycle(dirtyContentRegion);
|
||||
}
|
||||
|
||||
// reset the dirty region, since
|
||||
@@ -658,11 +635,9 @@ WindowLayer::RedrawDirtyRegion()
|
||||
// thread wanted to mark something
|
||||
// dirty in the mean time, it was
|
||||
// blocking on the global region lock to
|
||||
// get write access, since we held the
|
||||
// read lock for the whole time.
|
||||
// get write access, since we're holding
|
||||
// the read lock for the whole time.
|
||||
fDirtyRegion.MakeEmpty();
|
||||
|
||||
fDesktop->UnlockSingleWindow();
|
||||
}
|
||||
|
||||
|
||||
@@ -685,23 +660,19 @@ WindowLayer::MarkContentDirty(BRegion& regionOnScreen)
|
||||
// since this won't affect other windows, read locking
|
||||
// is sufficient. If there was no dirty region before,
|
||||
// an update message is triggered
|
||||
if (!fHidden && fDesktop && fDesktop->LockSingleWindow()) {
|
||||
regionOnScreen.IntersectWith(&VisibleContentRegion());
|
||||
_TriggerContentRedraw(regionOnScreen);
|
||||
if (fHidden)
|
||||
return;
|
||||
|
||||
fDesktop->UnlockSingleWindow();
|
||||
}
|
||||
regionOnScreen.IntersectWith(&VisibleContentRegion());
|
||||
_TriggerContentRedraw(regionOnScreen);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WindowLayer::InvalidateView(ViewLayer* layer, BRegion& layerRegion)
|
||||
{
|
||||
if (layer && IsVisible() && fDesktop && fDesktop->LockSingleWindow()) {
|
||||
if (!layer->IsVisible()) {
|
||||
fDesktop->UnlockSingleWindow();
|
||||
return;
|
||||
}
|
||||
if (layer && IsVisible() && layer->IsVisible()) {
|
||||
|
||||
if (!fContentRegionValid)
|
||||
_UpdateContentRegion();
|
||||
|
||||
@@ -715,8 +686,6 @@ WindowLayer::InvalidateView(ViewLayer* layer, BRegion& layerRegion)
|
||||
|
||||
_TriggerContentRedraw(layerRegion);
|
||||
}
|
||||
|
||||
fDesktop->UnlockSingleWindow();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -796,12 +765,12 @@ WindowLayer::MouseDown(BMessage* message, BPoint where, int32* _viewToken)
|
||||
}
|
||||
|
||||
// redraw decorator
|
||||
BRegion visibleBorder;
|
||||
GetBorderRegion(&visibleBorder);
|
||||
visibleBorder.IntersectWith(&VisibleRegion());
|
||||
BRegion* visibleBorder = fRegionPool.GetRegion();
|
||||
GetBorderRegion(visibleBorder);
|
||||
visibleBorder->IntersectWith(&VisibleRegion());
|
||||
|
||||
fDrawingEngine->Lock();
|
||||
fDrawingEngine->ConstrainClippingRegion(&visibleBorder);
|
||||
fDrawingEngine->ConstrainClippingRegion(visibleBorder);
|
||||
|
||||
if (fIsZooming) {
|
||||
fDecorator->SetZoom(true);
|
||||
@@ -813,6 +782,8 @@ WindowLayer::MouseDown(BMessage* message, BPoint where, int32* _viewToken)
|
||||
|
||||
fDrawingEngine->Unlock();
|
||||
|
||||
fRegionPool.Recycle(visibleBorder);
|
||||
|
||||
// based on what the Decorator returned, properly place this window.
|
||||
if (action == DEC_MOVETOBACK) {
|
||||
fDesktop->SendWindowBehind(this);
|
||||
@@ -853,12 +824,12 @@ WindowLayer::MouseUp(BMessage* message, BPoint where, int32* _viewToken)
|
||||
click_type action = _ActionFor(message);
|
||||
|
||||
// redraw decorator
|
||||
BRegion visibleBorder;
|
||||
GetBorderRegion(&visibleBorder);
|
||||
visibleBorder.IntersectWith(&VisibleRegion());
|
||||
BRegion* visibleBorder = fRegionPool.GetRegion();
|
||||
GetBorderRegion(visibleBorder);
|
||||
visibleBorder->IntersectWith(&VisibleRegion());
|
||||
|
||||
fDrawingEngine->Lock();
|
||||
fDrawingEngine->ConstrainClippingRegion(&visibleBorder);
|
||||
fDrawingEngine->ConstrainClippingRegion(visibleBorder);
|
||||
|
||||
if (fIsZooming) {
|
||||
fIsZooming = false;
|
||||
@@ -886,6 +857,8 @@ WindowLayer::MouseUp(BMessage* message, BPoint where, int32* _viewToken)
|
||||
}
|
||||
|
||||
fDrawingEngine->Unlock();
|
||||
|
||||
fRegionPool.Recycle(visibleBorder);
|
||||
}
|
||||
fIsDragging = false;
|
||||
fIsResizing = false;
|
||||
@@ -923,12 +896,12 @@ WindowLayer::MouseMoved(BMessage *message, BPoint where, int32* _viewToken,
|
||||
}
|
||||
|
||||
if (fDecorator) {
|
||||
BRegion visibleBorder;
|
||||
GetBorderRegion(&visibleBorder);
|
||||
visibleBorder.IntersectWith(&VisibleRegion());
|
||||
BRegion* visibleBorder = fRegionPool.GetRegion();
|
||||
GetBorderRegion(visibleBorder);
|
||||
visibleBorder->IntersectWith(&VisibleRegion());
|
||||
|
||||
fDrawingEngine->Lock();
|
||||
fDrawingEngine->ConstrainClippingRegion(&visibleBorder);
|
||||
fDrawingEngine->ConstrainClippingRegion(visibleBorder);
|
||||
|
||||
if (fIsZooming) {
|
||||
fDecorator->SetZoom(_ActionFor(message) == DEC_ZOOM);
|
||||
@@ -939,6 +912,7 @@ WindowLayer::MouseMoved(BMessage *message, BPoint where, int32* _viewToken,
|
||||
}
|
||||
|
||||
fDrawingEngine->Unlock();
|
||||
fRegionPool.Recycle(visibleBorder);
|
||||
}
|
||||
|
||||
BPoint delta = where - fLastMousePosition;
|
||||
@@ -1071,9 +1045,12 @@ WindowLayer::SetFocus(bool focus)
|
||||
// so the window thread cannot be
|
||||
// accessing fIsFocus
|
||||
|
||||
BRegion dirty(fBorderRegion);
|
||||
dirty.IntersectWith(&fVisibleRegion);
|
||||
fDesktop->MarkDirty(dirty);
|
||||
BRegion* dirty = fRegionPool.GetRegion(fBorderRegion);
|
||||
if (dirty) {
|
||||
dirty->IntersectWith(&fVisibleRegion);
|
||||
fDesktop->MarkDirty(*dirty);
|
||||
fRegionPool.Recycle(dirty);
|
||||
}
|
||||
|
||||
fIsFocus = focus;
|
||||
if (fDecorator)
|
||||
@@ -1602,16 +1579,19 @@ void
|
||||
WindowLayer::_ShiftPartOfRegion(BRegion* region, BRegion* regionToShift,
|
||||
int32 xOffset, int32 yOffset)
|
||||
{
|
||||
BRegion common(*regionToShift);
|
||||
BRegion* common = fRegionPool.GetRegion(*regionToShift);
|
||||
if (!common)
|
||||
return;
|
||||
// see if there is a common part at all
|
||||
common.IntersectWith(region);
|
||||
if (common.CountRects() > 0) {
|
||||
common->IntersectWith(region);
|
||||
if (common->CountRects() > 0) {
|
||||
// cut the common part from the region,
|
||||
// offset that to destination and include again
|
||||
region->Exclude(&common);
|
||||
common.OffsetBy(xOffset, yOffset);
|
||||
region->Include(&common);
|
||||
region->Exclude(common);
|
||||
common->OffsetBy(xOffset, yOffset);
|
||||
region->Include(common);
|
||||
}
|
||||
fRegionPool.Recycle(common);
|
||||
}
|
||||
|
||||
|
||||
@@ -1655,19 +1635,22 @@ WindowLayer::_DrawBorder()
|
||||
return;
|
||||
|
||||
// construct the region of the border that needs redrawing
|
||||
BRegion dirtyBorderRegion;
|
||||
GetBorderRegion(&dirtyBorderRegion);
|
||||
BRegion* dirtyBorderRegion = fRegionPool.GetRegion();
|
||||
if (!dirtyBorderRegion)
|
||||
return;
|
||||
GetBorderRegion(dirtyBorderRegion);
|
||||
// intersect with our visible region
|
||||
dirtyBorderRegion.IntersectWith(&fVisibleRegion);
|
||||
dirtyBorderRegion->IntersectWith(&fVisibleRegion);
|
||||
// intersect with the dirty region
|
||||
dirtyBorderRegion.IntersectWith(&fDirtyRegion);
|
||||
dirtyBorderRegion->IntersectWith(&fDirtyRegion);
|
||||
|
||||
if (dirtyBorderRegion.CountRects() > 0 && fDrawingEngine->Lock()) {
|
||||
fDrawingEngine->ConstrainClippingRegion(&dirtyBorderRegion);
|
||||
fDecorator->Draw(dirtyBorderRegion.Frame());
|
||||
if (dirtyBorderRegion->CountRects() > 0 && fDrawingEngine->Lock()) {
|
||||
fDrawingEngine->ConstrainClippingRegion(dirtyBorderRegion);
|
||||
fDecorator->Draw(dirtyBorderRegion->Frame());
|
||||
|
||||
fDrawingEngine->Unlock();
|
||||
}
|
||||
fRegionPool.Recycle(dirtyBorderRegion);
|
||||
}
|
||||
|
||||
|
||||
@@ -1730,15 +1713,10 @@ WindowLayer::BeginUpdate(BPrivate::PortLink& link)
|
||||
// NOTE: since we might "shift" parts of the
|
||||
// internal dirty regions from the desktop thread
|
||||
// in response to WindowLayer::ResizeBy(), which
|
||||
// might move arround views, this function needs to block
|
||||
// on the global clipping lock so that the internal
|
||||
// might move arround views, the user of this function
|
||||
// needs to hold the global clipping lock so that the internal
|
||||
// dirty regions are not messed with from the Desktop thread
|
||||
// and ServerWindow thread at the same time.
|
||||
if (!fDesktop->LockSingleWindow()) {
|
||||
link.StartMessage(B_ERROR);
|
||||
link.Flush();
|
||||
return;
|
||||
}
|
||||
|
||||
if (fUpdateRequested) {
|
||||
// make the pending update session the current update session
|
||||
@@ -1760,8 +1738,15 @@ WindowLayer::BeginUpdate(BPrivate::PortLink& link)
|
||||
if (!fContentRegionValid)
|
||||
_UpdateContentRegion();
|
||||
|
||||
BRegion dirty(fCurrentUpdateSession.DirtyRegion());
|
||||
dirty.IntersectWith(&VisibleContentRegion());
|
||||
BRegion* dirty = fRegionPool.GetRegion(
|
||||
fCurrentUpdateSession.DirtyRegion());
|
||||
if (!dirty) {
|
||||
link.StartMessage(B_ERROR);
|
||||
link.Flush();
|
||||
return;
|
||||
}
|
||||
|
||||
dirty->IntersectWith(&VisibleContentRegion());
|
||||
|
||||
//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.Height());
|
||||
// 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
|
||||
// the dirty region
|
||||
fTopLayer->AddTokensForLayersInRegion(link, dirty, &fContentRegion);
|
||||
fTopLayer->AddTokensForLayersInRegion(link, *dirty, &fContentRegion);
|
||||
// mark the end of the token "list"
|
||||
link.Attach<int32>(B_NULL_TOKEN);
|
||||
link.Flush();
|
||||
@@ -1783,17 +1768,17 @@ WindowLayer::BeginUpdate(BPrivate::PortLink& link)
|
||||
#if DELAYED_BACKGROUND_CLEARING
|
||||
// NOTE: turning off DELAYED_BACKGROUND_CLEARING will
|
||||
// need investigation if it even still works...
|
||||
fTopLayer->Draw(fDrawingEngine, &dirty,
|
||||
fTopLayer->Draw(fDrawingEngine, dirty,
|
||||
&fContentRegion, true);
|
||||
#endif
|
||||
|
||||
fRegionPool.Recycle(dirty);
|
||||
#endif
|
||||
} else {
|
||||
printf("BeginUpdate() but no update requested!!\n");
|
||||
link.StartMessage(B_ERROR);
|
||||
link.Flush();
|
||||
fprintf(stderr, "WindowLayer::BeginUpdate() - no update requested!\n");
|
||||
}
|
||||
|
||||
fDesktop->UnlockSingleWindow();
|
||||
}
|
||||
|
||||
|
||||
@@ -1801,8 +1786,6 @@ void
|
||||
WindowLayer::EndUpdate()
|
||||
{
|
||||
// NOTE: see comment in _BeginUpdate()
|
||||
if (!fDesktop->LockSingleWindow())
|
||||
return;
|
||||
|
||||
if (fInUpdate) {
|
||||
fCurrentUpdateSession.SetUsed(false);
|
||||
@@ -1816,8 +1799,6 @@ WindowLayer::EndUpdate()
|
||||
} else {
|
||||
fUpdateRequested = false;
|
||||
}
|
||||
|
||||
fDesktop->UnlockSingleWindow();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "Decorator.h"
|
||||
#include "ViewLayer.h"
|
||||
#include "RegionPool.h"
|
||||
#include "ServerWindow.h"
|
||||
#include "WindowList.h"
|
||||
|
||||
@@ -56,10 +57,6 @@ class WindowLayer {
|
||||
::ServerWindow* ServerWindow() const { return fWindow; }
|
||||
::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
|
||||
// WriteLock()ed the clipping!
|
||||
void SetClipping(BRegion* stillAvailableOnScreen);
|
||||
@@ -116,6 +113,16 @@ class WindowLayer {
|
||||
DrawingEngine* GetDrawingEngine() const
|
||||
{ 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,
|
||||
int32 xOffset, int32 yOffset);
|
||||
|
||||
@@ -248,6 +255,8 @@ class WindowLayer {
|
||||
BRegion fEffectiveDrawingRegion;
|
||||
bool fEffectiveDrawingRegionValid;
|
||||
|
||||
::RegionPool fRegionPool;
|
||||
|
||||
BObjectList<WindowLayer> fSubsets;
|
||||
|
||||
// TODO: remove those some day (let the decorator handle that stuff)
|
||||
@@ -322,8 +331,6 @@ class WindowLayer {
|
||||
int32 fMaxWidth;
|
||||
int32 fMinHeight;
|
||||
int32 fMaxHeight;
|
||||
|
||||
mutable bool fReadLocked;
|
||||
};
|
||||
|
||||
#endif // WINDOW_LAYER_H
|
||||
|
||||
@@ -77,14 +77,18 @@ Workspace::Workspace(Desktop& desktop, int32 index)
|
||||
fDesktop(desktop),
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
Workspace::~Workspace()
|
||||
{
|
||||
fDesktop.UnlockSingleWindow();
|
||||
// fDesktop.UnlockSingleWindow();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ UseFreeTypeHeaders ;
|
||||
local defines = [ FDefines TEST_MODE=1 ] ;
|
||||
# USE_DIRECT_WINDOW_TEST_MODE=1
|
||||
|
||||
SubDirCcFlags $(defines) -fcheck-memory-usage -D_NO_INLINE_ASM ;
|
||||
SubDirC++Flags $(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 ;
|
||||
|
||||
SEARCH_SOURCE += $(appServerDir) [ FDirName $(appServerDir) drawing ] ;
|
||||
|
||||
@@ -112,6 +112,7 @@ Server haiku_app_server :
|
||||
DefaultDecorator.cpp
|
||||
OffscreenServerWindow.cpp
|
||||
OffscreenWindowLayer.cpp
|
||||
RegionPool.cpp
|
||||
ServerPicture.cpp
|
||||
ServerScreen.cpp
|
||||
ViewLayer.cpp
|
||||
|
||||
Reference in New Issue
Block a user