Fixed a big race condition in the server code:

* ServerApp was accessing ServerWindow::Window() (while having the app window
  lock held), but in fact, there was no guarantee it already existed, or was
  added to the Desktop.
* Therefore, the Window() semantics have changed to only return a window in
  case the window exists *and* has been added to the desktop (the latter
  constraint might be lifted again, though). Therefore, it doesn't work
  for offscreen windows, and should not be used within ServerWindow code
  anymore.
* This fixes bug #686 and maybe others as well.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17878 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-06-19 23:42:22 +00:00
parent 4810cdcdbc
commit 3a44e6e37d
4 changed files with 45 additions and 19 deletions

View File

@ -2021,7 +2021,7 @@ Desktop::SetViewUnderMouse(const WindowLayer* window, int32 viewToken)
int32
Desktop::ViewUnderMouse(const WindowLayer* window)
{
if (fWindowUnderMouse == window)
if (window != NULL && fWindowUnderMouse == window)
return fViewUnderMouse;
return B_NULL_TOKEN;
@ -2086,16 +2086,18 @@ Desktop::WindowAction(int32 windowToken, int32 action)
LockAllWindows();
::ServerWindow* serverWindow;
WindowLayer* window;
if (BPrivate::gDefaultTokens.GetToken(windowToken,
B_SERVER_TOKEN, (void**)&serverWindow) != B_OK) {
B_SERVER_TOKEN, (void**)&serverWindow) != B_OK
|| (window = serverWindow->Window()) == NULL) {
UnlockAllWindows();
return;
}
if (action == B_BRING_TO_FRONT
&& !serverWindow->Window()->IsMinimized()) {
&& !window->IsMinimized()) {
// the window is visible, we just need to make it the front window
ActivateWindow(serverWindow->Window());
ActivateWindow(window);
} else
serverWindow->NotifyMinimize(action == B_MINIMIZE_WINDOW);

View File

@ -271,9 +271,9 @@ ServerApp::_HasWindowUnderMouse()
BAutolock locker(fWindowListLock);
for (int32 i = fWindowList.CountItems(); i-- > 0;) {
ServerWindow* window = fWindowList.ItemAt(i);
ServerWindow* serverWindow = fWindowList.ItemAt(i);
if (fDesktop->ViewUnderMouse(window->Window()) != B_NULL_TOKEN)
if (fDesktop->ViewUnderMouse(serverWindow->Window()) != B_NULL_TOKEN)
return true;
}
@ -439,7 +439,10 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
if (fWindowListLock.Lock()) {
for (int32 i = fWindowList.CountItems(); i-- > 0;) {
ServerWindow* serverWindow = fWindowList.ItemAt(i);
WindowLayer* window = serverWindow->Window();
if (window == NULL || window->IsOffscreenWindow())
continue;
if (window->Feel() == kWindowScreenFeel)
fDesktop->SetWindowFeel(window, B_NORMAL_WINDOW_FEEL);
@ -2479,12 +2482,15 @@ ServerApp::InWorkspace(int32 index) const
// TODO: support initial application workspace!
for (int32 i = fWindowList.CountItems(); i-- > 0;) {
ServerWindow* window = fWindowList.ItemAt(i);
const WindowLayer* layer = window->Window();
ServerWindow* serverWindow = fWindowList.ItemAt(i);
const WindowLayer* window = serverWindow->Window();
if (window == NULL || window->IsOffscreenWindow())
continue;
// only normal and unhidden windows count
if (layer->IsNormal() && !layer->IsHidden() && layer->InWorkspace(index))
if (window->IsNormal() && !window->IsHidden() && window->InWorkspace(index))
return true;
}
@ -2503,13 +2509,16 @@ ServerApp::Workspaces() const
// value everytime a window has closed or changed workspaces
for (int32 i = fWindowList.CountItems(); i-- > 0;) {
ServerWindow* window = fWindowList.ItemAt(i);
const WindowLayer* layer = window->Window();
ServerWindow* serverWindow = fWindowList.ItemAt(i);
const WindowLayer* window = serverWindow->Window();
if (window == NULL || window->IsOffscreenWindow())
continue;
// only normal and unhidden windows count
if (layer->IsNormal() && !layer->IsHidden())
workspaces |= layer->Workspaces();
if (window->IsNormal() && !window->IsHidden())
workspaces |= window->Workspaces();
}
// TODO: add initial application workspace!

View File

@ -151,6 +151,7 @@ ServerWindow::ServerWindow(const char *title, ServerApp *app,
fDesktop(app->GetDesktop()),
fServerApp(app),
fWindowLayer(NULL),
fWindowAddedToDesktop(false),
fClientTeam(app->ClientTeam()),
@ -187,14 +188,16 @@ ServerWindow::~ServerWindow()
{
STRACE(("ServerWindow(%s@%p):~ServerWindow()\n", fTitle, this));
if (!fWindowLayer->IsOffscreenWindow())
if (!fWindowLayer->IsOffscreenWindow()) {
fWindowAddedToDesktop = false;
fDesktop->RemoveWindow(fWindowLayer);
delete fWindowLayer;
}
if (App() != NULL)
App()->RemoveWindow(this);
delete fWindowLayer;
free(fTitle);
delete_port(fMessagePort);
@ -243,8 +246,10 @@ ServerWindow::Init(BRect frame, window_look look, window_feel feel,
if (!fWindowLayer)
return B_NO_MEMORY;
if (!fWindowLayer->IsOffscreenWindow())
if (!fWindowLayer->IsOffscreenWindow()) {
fDesktop->AddWindow(fWindowLayer);
fWindowAddedToDesktop = true;
}
return B_OK;
}
@ -459,10 +464,19 @@ ServerWindow::GetInfo(window_info& info)
}
/*!
Returns the ServerWindow's WindowLayer, if it exists and has been
added to the Desktop already.
In other words, you cannot assume this method will always give you
a valid pointer.
*/
WindowLayer*
ServerWindow::Window() const
{
// TODO: ensure desktop is locked!
if (!fWindowAddedToDesktop)
return NULL;
return fWindowLayer;
}
@ -833,7 +847,7 @@ fDesktop->LockSingleWindow();
STRACE(("ServerWindow %s: Message AS_WINDOW_RESIZE %.1f, %.1f\n",
Title(), xResizeBy, yResizeBy));
if (Window()->IsResizing()) {
if (fWindowLayer->IsResizing()) {
// While the user resizes the window, we ignore
// pragmatically set window bounds
fLink.StartMessage(B_BUSY);
@ -857,7 +871,7 @@ fDesktop->LockSingleWindow();
STRACE(("ServerWindow %s: Message AS_WINDOW_MOVE: %.1f, %.1f\n",
Title(), xMoveBy, yMoveBy));
if (Window()->IsDragging()) {
if (fWindowLayer->IsDragging()) {
// While the user moves the window, we ignore
// pragmatically set window positions
fLink.StartMessage(B_BUSY);

View File

@ -136,6 +136,7 @@ private:
::Desktop* fDesktop;
ServerApp* fServerApp;
WindowLayer* fWindowLayer;
bool fWindowAddedToDesktop;
team_id fClientTeam;