diff --git a/src/servers/app/Desktop.cpp b/src/servers/app/Desktop.cpp index 593bb52e8d..261dd9b5d2 100644 --- a/src/servers/app/Desktop.cpp +++ b/src/servers/app/Desktop.cpp @@ -262,7 +262,7 @@ MouseFilter::Filter(BMessage* message, EventTarget** _target, int32* _viewToken, *_target = NULL; } - fDesktop->SetLastMouseState(where, buttons); + fDesktop->SetLastMouseState(where, buttons, window); fDesktop->UnlockAllWindows(); @@ -311,6 +311,7 @@ Desktop::Desktop(uid_t userID) fMouseEventWindow(NULL), fWindowUnderMouse(NULL), + fLockedFocusWindow(NULL), fViewUnderMouse(B_NULL_TOKEN), fLastMousePosition(B_ORIGIN), fLastMouseButtons(0), @@ -750,10 +751,17 @@ Desktop::Cursor() const void -Desktop::SetLastMouseState(const BPoint& position, int32 buttons) +Desktop::SetLastMouseState(const BPoint& position, int32 buttons, + Window* windowUnderMouse) { + // The all-window-lock is write-locked. fLastMousePosition = position; fLastMouseButtons = buttons; + + if (fLastMouseButtons == 0 && fLockedFocusWindow) { + fLockedFocusWindow = NULL; + SetFocusWindow(windowUnderMouse); + } } @@ -1375,9 +1383,13 @@ Desktop::SetFocusWindow(Window* focus) if (!LockAllWindows()) return; - bool hasModal = _WindowHasModal(focus); + // test for B_LOCK_WINDOW_FOCUS + if (fLockedFocusWindow && focus != fLockedFocusWindow) { + UnlockAllWindows(); + return; + } - // TODO: test for B_LOCK_WINDOW_FOCUS + bool hasModal = _WindowHasModal(focus); if (focus == fFocus && focus != NULL && !focus->IsHidden() && (focus->Flags() & B_AVOID_FOCUS) == 0 && !hasModal) { @@ -1461,6 +1473,23 @@ Desktop::SetFocusWindow(Window* focus) } +void +Desktop::SetFocusLocked(const Window* window) +{ + AutoWriteLocker _(fWindowLock); + + if (window != NULL) { + // Don't allow this to be set when no mouse buttons + // are pressed. (BView::SetMouseEventMask() should only be called + // from mouse hooks.) + if (fLastMouseButtons == 0) + return; + } + + fLockedFocusWindow = window; +} + + void Desktop::_BringWindowsToFront(WindowList& windows, int32 list, bool wereVisible) diff --git a/src/servers/app/Desktop.h b/src/servers/app/Desktop.h index 710bdda189..21f9a550e8 100644 --- a/src/servers/app/Desktop.h +++ b/src/servers/app/Desktop.h @@ -82,7 +82,7 @@ class Desktop : public MessageLooper, public ScreenOwner { void SetCursor(ServerCursor* cursor); ServerCursorReference Cursor() const; void SetLastMouseState(const BPoint& position, - int32 buttons); + int32 buttons, Window* windowUnderMouse); // for use by the mouse filter only // both mouse position calls require // the Desktop object to be locked @@ -164,6 +164,7 @@ class Desktop : public MessageLooper, public ScreenOwner { void SetFocusWindow(Window* window = NULL); EventTarget* KeyboardEventTarget(); + void SetFocusLocked(const Window* window); Window* FindWindowByClientToken(int32 token, team_id teamID); @@ -303,6 +304,7 @@ class Desktop : public MessageLooper, public ScreenOwner { Window* fMouseEventWindow; const Window* fWindowUnderMouse; + const Window* fLockedFocusWindow; int32 fViewUnderMouse; BPoint fLastMousePosition; int32 fLastMouseButtons; diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index 615247d926..c5f4f192a5 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -1343,6 +1343,8 @@ fDesktop->LockSingleWindow(); fDesktop->UnlockSingleWindow(); // TODO: possible deadlock if (eventMask != 0 || options != 0) { + if (options & B_LOCK_WINDOW_FOCUS) + fDesktop->SetFocusLocked(fWindow); fDesktop->EventDispatcher().AddTemporaryListener(EventTarget(), fCurrentView->Token(), eventMask, options); } else {