This enables BDirectWindow support again.

It also fixed a bug in the old code - the handshake semaphores were created
acquirable, causing the BDirectWindow::DirectDaemonFunc() to call DirectConnected()
with an uninitialized buffer and way too early - this probably didn't show up
before since it called it before the BDirectWindow constructor ran through,
so that DirectConnected() would still point to the BDirectWindow version, and
not to the implemented one of its subclass...


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15505 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2005-12-11 21:46:35 +00:00
parent bd09e99dbd
commit bff84e78b7
4 changed files with 147 additions and 104 deletions

View File

@ -430,18 +430,36 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
}
case AS_GET_WINDOW_LIST:
{
team_id team;
link.Read<team_id>(&team);
fDesktop->WriteWindowList(team, fLink.Sender());
break;
}
case AS_GET_WINDOW_INFO:
{
int32 serverToken;
link.Read<int32>(&serverToken);
fDesktop->WriteWindowInfo(serverToken, fLink.Sender());
break;
}
case AS_DIRECT_WINDOW_SUPPORTS_WINDOW_MODE:
{
// TODO: How to determine this?
screen_id id;
if (link.Read<screen_id>(&id) == B_OK) {
fLink.StartMessage(B_OK);
fLink.Attach<bool>(true);
} else
fLink.StartMessage(B_BAD_VALUE);
fLink.Flush();
break;
}
case AS_UPDATE_COLORS:
{

View File

@ -83,43 +83,66 @@ using std::nothrow;
static struct profile { int32 count; bigtime_t time; } sMessageProfile[AS_LAST_CODE];
#endif
struct dw_data {
sem_id direct_sem;
sem_id direct_sem_ack;
area_id direct_area;
direct_buffer_info *direct_info;
dw_data() :
direct_sem(-1),
direct_sem_ack(-1),
direct_area(-1),
direct_info(NULL)
{
direct_area = create_area("direct area", (void **)&direct_info,
B_ANY_ADDRESS, B_PAGE_SIZE, B_NO_LOCK, B_READ_WRITE);
direct_sem = create_sem(1, "direct sem");
direct_sem_ack = create_sem(1, "direct sem ack");
}
~dw_data()
{
if (direct_area >= 0)
delete_area(direct_area);
if (direct_sem >= 0)
delete_sem(direct_sem);
if (direct_sem_ack >= 0)
delete_sem(direct_sem_ack);
}
bool IsValid() const
{
return (direct_area >= 0) && (direct_sem >= 0)
&& (direct_sem_ack >= 0) && (direct_info != NULL);
}
struct direct_window_data {
direct_window_data();
~direct_window_data();
status_t InitCheck() const;
sem_id sem;
sem_id sem_ack;
area_id area;
bool started;
direct_buffer_info *buffer_info;
};
direct_window_data::direct_window_data()
:
sem(-1),
sem_ack(-1),
area(-1),
started(false),
buffer_info(NULL)
{
area = create_area("direct area", (void **)&buffer_info,
B_ANY_ADDRESS, B_PAGE_SIZE, B_NO_LOCK, B_READ_WRITE);
sem = create_sem(0, "direct sem");
sem_ack = create_sem(0, "direct sem ack");
}
direct_window_data::~direct_window_data()
{
// this should make the client die in case it's still running
buffer_info->bits = NULL;
buffer_info->bytes_per_row = 0;
delete_area(area);
delete_sem(sem);
delete_sem(sem_ack);
}
status_t
direct_window_data::InitCheck() const
{
if (area < B_OK)
return area;
if (sem < B_OK)
return sem;
if (sem_ack < B_OK)
return sem_ack;
return B_OK;
}
// #pragma mark -
/*!
Sets up the basic BWindow counterpart - you have to call Init() before
you can actually use it, though.
@ -884,6 +907,29 @@ fDesktop->ReadLockWindows();
break;
}
// BDirectWindow communication
case AS_DIRECT_WINDOW_GET_SYNC_DATA:
{
status_t status = _EnableDirectWindowMode();
if (status == B_OK) {
fLink.StartMessage(B_OK);
struct direct_window_sync_data syncData = {
fDirectWindowData->area,
fDirectWindowData->sem,
fDirectWindowData->sem_ack
};
fLink.Attach(&syncData, sizeof(syncData));
} else
fLink.StartMessage(status);
fLink.Flush();
break;
}
// View creation and destruction (don't need a valid fCurrentLayer)
case AS_SET_CURRENT_LAYER:
{
int32 token;
@ -1676,33 +1722,6 @@ ServerWindow::_DispatchViewMessage(int32 code,
break;
}
// BDirectWindow communication
case AS_DIRECT_WINDOW_SUPPORTS_WINDOW_MODE:
// TODO: How to determine this?
fLink.StartMessage(B_OK);
fLink.Attach<bool>(true);
fLink.Flush();
break;
case AS_DIRECT_WINDOW_GET_SYNC_DATA:
{
if (_EnableDirectWindowMode() == B_OK) {
fLink.StartMessage(B_OK);
struct direct_window_sync_data syncData = {
fDirectWindowData->direct_area,
fDirectWindowData->direct_sem,
fDirectWindowData->direct_sem_ack
};
fLink.Attach(&syncData, sizeof(syncData));
} else
fLink.StartMessage(B_ERROR);
fLink.Flush();
break;
}
default:
if (fDesktop->ReadLockWindows()) {
_DispatchViewDrawingMessage(code, link);
@ -2227,14 +2246,16 @@ ServerWindow::_EnableDirectWindowMode()
return B_ERROR;
}
fDirectWindowData = new (nothrow) dw_data;
fDirectWindowData = new (nothrow) direct_window_data;
if (fDirectWindowData == NULL)
return B_NO_MEMORY;
if (!fDirectWindowData->IsValid()) {
status_t status = fDirectWindowData->InitCheck();
if (status < B_OK) {
delete fDirectWindowData;
fDirectWindowData = NULL;
return B_ERROR;
return status;
}
return B_OK;
@ -2242,62 +2263,65 @@ ServerWindow::_EnableDirectWindowMode()
void
ServerWindow::HandleDirectConnection(int bufferState, int driverState)
ServerWindow::HandleDirectConnection(int32 bufferState, int32 driverState)
{
if (fDirectWindowData == NULL)
STRACE(("HandleDirectConnection(bufferState = %ld, driverState = %ld)\n",
bufferState, driverState));
if (fDirectWindowData == NULL
|| (!fDirectWindowData->started
&& (bufferState & B_DIRECT_MODE_MASK) != B_DIRECT_START))
return;
printf("bufferState = %ld\n", bufferState);
fDirectWindowData->started = true;
if (bufferState != -1)
fDirectWindowData->direct_info->buffer_state = (direct_buffer_state)bufferState;
fDirectWindowData->buffer_info->buffer_state = (direct_buffer_state)bufferState;
if (driverState != -1)
fDirectWindowData->direct_info->driver_state = (direct_driver_state)driverState;
fDirectWindowData->buffer_info->driver_state = (direct_driver_state)driverState;
if ((bufferState & B_DIRECT_MODE_MASK) != B_DIRECT_STOP) {
// TODO: Locking ?
RenderingBuffer *buffer = fDesktop->HWInterface()->FrontBuffer();
fDirectWindowData->direct_info->bits = buffer->Bits();
fDirectWindowData->direct_info->pci_bits = NULL; // TODO
fDirectWindowData->direct_info->bytes_per_row = buffer->BytesPerRow();
fDirectWindowData->direct_info->bits_per_pixel = buffer->BytesPerRow() / buffer->Width() * 8;
fDirectWindowData->direct_info->pixel_format = buffer->ColorSpace();
fDirectWindowData->direct_info->layout = B_BUFFER_NONINTERLEAVED;
fDirectWindowData->direct_info->orientation = B_BUFFER_TOP_TO_BOTTOM; // TODO
fDirectWindowData->buffer_info->bits = buffer->Bits();
fDirectWindowData->buffer_info->pci_bits = NULL; // TODO
fDirectWindowData->buffer_info->bytes_per_row = buffer->BytesPerRow();
fDirectWindowData->buffer_info->bits_per_pixel = buffer->BytesPerRow() / buffer->Width() * 8;
fDirectWindowData->buffer_info->pixel_format = buffer->ColorSpace();
fDirectWindowData->buffer_info->layout = B_BUFFER_NONINTERLEAVED;
fDirectWindowData->buffer_info->orientation = B_BUFFER_TOP_TO_BOTTOM; // TODO
WindowLayer *layer = const_cast<WindowLayer *>(GetWindowLayer());
fDirectWindowData->direct_info->window_bounds = to_clipping_rect(layer->Frame());
fDirectWindowData->buffer_info->window_bounds = to_clipping_rect(layer->Frame());
// TODO: Review this
const int32 kMaxClipRectsCount = (B_PAGE_SIZE - sizeof(direct_buffer_info))
/ sizeof(clipping_rect);
// TODO: Is there a simpler way to obtain this result ?
// We just want the region INSIDE the window, border excluded.
BRegion clipRegion;
// TODO: fix HandleDirectConnection()
/* = const_cast<BRegion &>(layer->FullVisible());
BRegion exclude = const_cast<BRegion &>(layer->VisibleRegion());
clipRegion.Exclude(&exclude);
*/
fDirectWindowData->direct_info->clip_list_count = min_c(clipRegion.CountRects(),
kMaxClipRectsCount);
fDirectWindowData->direct_info->clip_bounds = clipRegion.FrameInt();
// We just want the region inside the window, border excluded.
BRegion clipRegion = fWindowLayer->VisibleContentRegion();
clipRegion.PrintToStream();
for (uint32 i = 0; i < fDirectWindowData->direct_info->clip_list_count; i++)
fDirectWindowData->direct_info->clip_list[i] = clipRegion.RectAtInt(i);
fDirectWindowData->buffer_info->clip_list_count = min_c(clipRegion.CountRects(),
kMaxClipRectsCount);
fDirectWindowData->buffer_info->clip_bounds = clipRegion.FrameInt();
for (uint32 i = 0; i < fDirectWindowData->buffer_info->clip_list_count; i++)
fDirectWindowData->buffer_info->clip_list[i] = clipRegion.RectAtInt(i);
}
// Releasing this sem causes the client to call BDirectWindow::DirectConnected()
release_sem(fDirectWindowData->direct_sem);
release_sem(fDirectWindowData->sem);
// TODO: Waiting half a second in this thread is not a problem,
// but since we are called from the RootLayer's thread too, very bad things could happen.
// TODO: Waiting half a second in the ServerWindow thread is not a problem,
// but since we are called from the Desktop's thread too, very bad things could happen.
// Find some way to call this method only within ServerWindow's thread (messaging ?)
status_t status;
do {
// TODO: The timeout is 3000000 usecs (3 seconds) on beos.
// Test, but I think half a second is enough.
status = acquire_sem_etc(fDirectWindowData->direct_sem_ack, 1, B_TIMEOUT, 500000);
status = acquire_sem_etc(fDirectWindowData->sem_ack, 1, B_TIMEOUT, 500000);
} while (status == B_INTERRUPTED);
if (status < B_OK) {

View File

@ -39,7 +39,7 @@ class WindowLayer;
class Workspace;
class ViewLayer;
class ServerPicture;
struct dw_data;
struct direct_window_data;
struct window_info;
#define AS_UPDATE_DECORATOR 'asud'
@ -96,8 +96,8 @@ public:
// related thread/team_id(s).
inline team_id ClientTeam() const { return fClientTeam; }
void HandleDirectConnection(int bufferState = -1,
int driverState = -1);
void HandleDirectConnection(int32 bufferState = -1,
int32 driverState = -1);
inline int32 ClientToken() const { return fClientToken; }
inline int32 ServerToken() const { return fServerToken; }
@ -158,7 +158,7 @@ private:
BRegion fCurrentDrawingRegion;
bool fCurrentDrawingRegionValid;
dw_data* fDirectWindowData;
direct_window_data* fDirectWindowData;
};
#endif // SERVER_WINDOW_H

View File

@ -187,7 +187,7 @@ WindowLayer::ReadUnlockWindows()
}
}
// SetClipping
void
WindowLayer::SetClipping(BRegion* stillAvailableOnScreen)
{
@ -201,10 +201,11 @@ WindowLayer::SetClipping(BRegion* stillAvailableOnScreen)
fVisibleContentRegionValid = false;
fEffectiveDrawingRegionValid = false;
// TODO: Window()->HandleDirectConnection(B_DIRECT_MODIFY | B_CLIPPING_MODIFIED);
// TODO: review this!
fWindow->HandleDirectConnection(B_DIRECT_MODIFY | B_CLIPPING_MODIFIED);
}
// GetFullRegion
void
WindowLayer::GetFullRegion(BRegion* region)
{