* Reworked EventDispatcher::SendFakeMouseMoved() after an idea by Stephan
that solves most app_server locking headaches: it now works asynchronously, and therefore doesn't need to lock the EventDispatcher anymore. * EventStreams now allow to inject messages into the stream to allow the above functionality. * InputServerStream::GetNextEvent() no longer returns when there is no event. * Desktop::ActivateWindow() now locks all windows before checking the workspaces of the windows, fixing a race condition that could lead to Window::Foremost() being called for a window that isn't on the current workspace, leading to a crash. * I currently cannot access Trac, but I recall there should be an open bug report about this. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28224 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+20
-12
@@ -1326,8 +1326,6 @@ Desktop::RemoveWorkspacesView(WorkspacesView* view)
|
|||||||
|
|
||||||
This has only to be done in case the view changed without user interaction,
|
This has only to be done in case the view changed without user interaction,
|
||||||
ie. because of a workspace change or a closing window.
|
ie. because of a workspace change or a closing window.
|
||||||
|
|
||||||
Windows must not be locked when calling this method.
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
Desktop::_SendFakeMouseMoved(Window* window)
|
Desktop::_SendFakeMouseMoved(Window* window)
|
||||||
@@ -1520,6 +1518,9 @@ Desktop::ActivateWindow(Window* window)
|
|||||||
|
|
||||||
// TODO: take care about floating windows
|
// TODO: take care about floating windows
|
||||||
|
|
||||||
|
if (!LockAllWindows())
|
||||||
|
return;
|
||||||
|
|
||||||
bool windowOnOtherWorkspace = !window->InWorkspace(fCurrentWorkspace);
|
bool windowOnOtherWorkspace = !window->InWorkspace(fCurrentWorkspace);
|
||||||
if (windowOnOtherWorkspace) {
|
if (windowOnOtherWorkspace) {
|
||||||
if ((window->Flags() & B_NO_WORKSPACE_ACTIVATION) == 0
|
if ((window->Flags() & B_NO_WORKSPACE_ACTIVATION) == 0
|
||||||
@@ -1535,13 +1536,12 @@ Desktop::ActivateWindow(Window* window)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ((window->Flags() & B_NOT_ANCHORED_ON_ACTIVATE) == 0)
|
} else if ((window->Flags() & B_NOT_ANCHORED_ON_ACTIVATE) == 0) {
|
||||||
|
UnlockAllWindows();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!LockAllWindows())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (windowOnOtherWorkspace
|
if (windowOnOtherWorkspace
|
||||||
&& (window->Flags() & B_NOT_ANCHORED_ON_ACTIVATE) != 0) {
|
&& (window->Flags() & B_NOT_ANCHORED_ON_ACTIVATE) != 0) {
|
||||||
// bring the window to the current workspace
|
// bring the window to the current workspace
|
||||||
@@ -1554,12 +1554,7 @@ Desktop::ActivateWindow(Window* window)
|
|||||||
// Unlike WindowAction(), this is called from the application itself,
|
// Unlike WindowAction(), this is called from the application itself,
|
||||||
// so we will just unminimize the window here.
|
// so we will just unminimize the window here.
|
||||||
window->SetMinimized(false);
|
window->SetMinimized(false);
|
||||||
UnlockAllWindows();
|
|
||||||
|
|
||||||
ShowWindow(window);
|
ShowWindow(window);
|
||||||
|
|
||||||
if (!LockAllWindows())
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window == FrontWindow()) {
|
if (window == FrontWindow()) {
|
||||||
@@ -2368,7 +2363,7 @@ Desktop::ViewUnderMouse(const Window* window)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Window *
|
Window*
|
||||||
Desktop::FindWindowByClientToken(int32 token, team_id teamID)
|
Desktop::FindWindowByClientToken(int32 token, team_id teamID)
|
||||||
{
|
{
|
||||||
for (Window *window = fAllWindows.FirstWindow(); window != NULL;
|
for (Window *window = fAllWindows.FirstWindow(); window != NULL;
|
||||||
@@ -2383,6 +2378,19 @@ Desktop::FindWindowByClientToken(int32 token, team_id teamID)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
::EventTarget*
|
||||||
|
Desktop::FindTarget(BMessenger& messenger)
|
||||||
|
{
|
||||||
|
for (Window *window = fAllWindows.FirstWindow(); window != NULL;
|
||||||
|
window = window->NextWindow(kAllWindowList)) {
|
||||||
|
if (window->EventTarget().Messenger() == messenger)
|
||||||
|
return &window->EventTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Desktop::MinimizeApplication(team_id team)
|
Desktop::MinimizeApplication(team_id team)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -167,6 +167,7 @@ class Desktop : public MessageLooper, public ScreenOwner {
|
|||||||
|
|
||||||
Window* FindWindowByClientToken(int32 token,
|
Window* FindWindowByClientToken(int32 token,
|
||||||
team_id teamID);
|
team_id teamID);
|
||||||
|
EventTarget* FindTarget(BMessenger& messenger);
|
||||||
|
|
||||||
#if USE_MULTI_LOCKER
|
#if USE_MULTI_LOCKER
|
||||||
bool LockSingleWindow()
|
bool LockSingleWindow()
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "ServerBitmap.h"
|
#include "ServerBitmap.h"
|
||||||
|
|
||||||
#include <MessagePrivate.h>
|
#include <MessagePrivate.h>
|
||||||
|
#include <MessengerPrivate.h>
|
||||||
#include <ServerProtocol.h>
|
#include <ServerProtocol.h>
|
||||||
#include <TokenSpace.h>
|
#include <TokenSpace.h>
|
||||||
|
|
||||||
@@ -72,6 +73,8 @@ struct event_listener {
|
|||||||
|
|
||||||
static const char* kTokenName = "_token";
|
static const char* kTokenName = "_token";
|
||||||
|
|
||||||
|
static const uint32 kFakeMouseMoved = 'fake';
|
||||||
|
|
||||||
static const float kMouseMovedImportance = 0.1f;
|
static const float kMouseMovedImportance = 0.1f;
|
||||||
static const float kMouseTransitImportance = 1.0f;
|
static const float kMouseTransitImportance = 1.0f;
|
||||||
static const float kStandardImportance = 0.9f;
|
static const float kStandardImportance = 0.9f;
|
||||||
@@ -494,7 +497,44 @@ EventDispatcher::GetMouse(BPoint& where, int32& buttons)
|
|||||||
void
|
void
|
||||||
EventDispatcher::SendFakeMouseMoved(EventTarget& target, int32 viewToken)
|
EventDispatcher::SendFakeMouseMoved(EventTarget& target, int32 viewToken)
|
||||||
{
|
{
|
||||||
BAutolock _(this);
|
if (fStream == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BMessage* fakeMove = new BMessage(kFakeMouseMoved);
|
||||||
|
if (fakeMove == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fakeMove->AddMessenger("target", target.Messenger());
|
||||||
|
fakeMove->AddInt32("view_token", viewToken);
|
||||||
|
|
||||||
|
fStream->InsertEvent(fakeMove);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
EventDispatcher::_SendFakeMouseMoved(BMessage* message)
|
||||||
|
{
|
||||||
|
BMessenger target;
|
||||||
|
int32 viewToken;
|
||||||
|
if (message->FindInt32("view_token", &viewToken) != B_OK
|
||||||
|
|| message->FindMessenger("target", &target) != B_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (fDesktop == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Check if the target is still valid
|
||||||
|
::EventTarget* eventTarget = NULL;
|
||||||
|
|
||||||
|
fDesktop->LockSingleWindow();
|
||||||
|
|
||||||
|
if (target.IsValid())
|
||||||
|
eventTarget = fDesktop->FindTarget(target);
|
||||||
|
|
||||||
|
fDesktop->UnlockSingleWindow();
|
||||||
|
|
||||||
|
if (eventTarget == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
BMessage moved(B_MOUSE_MOVED);
|
BMessage moved(B_MOUSE_MOVED);
|
||||||
moved.AddPoint("screen_where", fLastCursorPosition);
|
moved.AddPoint("screen_where", fLastCursorPosition);
|
||||||
@@ -504,7 +544,7 @@ EventDispatcher::SendFakeMouseMoved(EventTarget& target, int32 viewToken)
|
|||||||
moved.AddMessage("be:drag_message", &fDragMessage);
|
moved.AddMessage("be:drag_message", &fDragMessage);
|
||||||
|
|
||||||
if (fPreviousMouseTarget != NULL
|
if (fPreviousMouseTarget != NULL
|
||||||
&& fPreviousMouseTarget != &target) {
|
&& fPreviousMouseTarget->Messenger() != target) {
|
||||||
_AddTokens(&moved, fPreviousMouseTarget, B_POINTER_EVENTS);
|
_AddTokens(&moved, fPreviousMouseTarget, B_POINTER_EVENTS);
|
||||||
_SendMessage(fPreviousMouseTarget->Messenger(), &moved,
|
_SendMessage(fPreviousMouseTarget->Messenger(), &moved,
|
||||||
kMouseTransitImportance);
|
kMouseTransitImportance);
|
||||||
@@ -515,8 +555,9 @@ EventDispatcher::SendFakeMouseMoved(EventTarget& target, int32 viewToken)
|
|||||||
moved.AddInt32("_view_token", viewToken);
|
moved.AddInt32("_view_token", viewToken);
|
||||||
// this only belongs to the new target
|
// this only belongs to the new target
|
||||||
|
|
||||||
_SendMessage(target.Messenger(), &moved, kMouseTransitImportance);
|
_SendMessage(target, &moved, kMouseTransitImportance);
|
||||||
fPreviousMouseTarget = ⌖
|
|
||||||
|
fPreviousMouseTarget = eventTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -718,12 +759,6 @@ EventDispatcher::_EventLoop()
|
|||||||
{
|
{
|
||||||
BMessage* event;
|
BMessage* event;
|
||||||
while (fStream->GetNextEvent(&event)) {
|
while (fStream->GetNextEvent(&event)) {
|
||||||
if (event == NULL) {
|
|
||||||
// may happen in out of memory situations or junk at the port
|
|
||||||
// we can't do anything about those yet
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
BAutolock _(this);
|
BAutolock _(this);
|
||||||
fLastUpdate = system_time();
|
fLastUpdate = system_time();
|
||||||
|
|
||||||
@@ -734,6 +769,9 @@ EventDispatcher::_EventLoop()
|
|||||||
bool addedTokens = false;
|
bool addedTokens = false;
|
||||||
|
|
||||||
switch (event->what) {
|
switch (event->what) {
|
||||||
|
case kFakeMouseMoved:
|
||||||
|
_SendFakeMouseMoved(event);
|
||||||
|
break;
|
||||||
case B_MOUSE_MOVED:
|
case B_MOUSE_MOVED:
|
||||||
{
|
{
|
||||||
BPoint where;
|
BPoint where;
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ class EventDispatcher : public BLocker {
|
|||||||
status_t _Run();
|
status_t _Run();
|
||||||
void _Unset();
|
void _Unset();
|
||||||
|
|
||||||
|
void _SendFakeMouseMoved(BMessage* message);
|
||||||
bool _SendMessage(BMessenger& messenger, BMessage* message,
|
bool _SendMessage(BMessenger& messenger, BMessage* message,
|
||||||
float importance);
|
float importance);
|
||||||
|
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ InputServerStream::UpdateScreenBounds(BRect bounds)
|
|||||||
bool
|
bool
|
||||||
InputServerStream::GetNextEvent(BMessage** _event)
|
InputServerStream::GetNextEvent(BMessage** _event)
|
||||||
{
|
{
|
||||||
if (fEvents.IsEmpty()) {
|
while (fEvents.IsEmpty()) {
|
||||||
// wait for new events
|
// wait for new events
|
||||||
BMessage* event;
|
BMessage* event;
|
||||||
status_t status = _MessageFromPort(&event);
|
status_t status = _MessageFromPort(&event);
|
||||||
@@ -191,6 +191,21 @@ InputServerStream::GetNextCursorPosition(BPoint &where)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
InputServerStream::InsertEvent(BMessage* event)
|
||||||
|
{
|
||||||
|
fEvents.AddMessage(event);
|
||||||
|
status_t status = write_port_etc(fPort, 'insm', NULL, 0, B_RELATIVE_TIMEOUT,
|
||||||
|
0);
|
||||||
|
if (status == B_BAD_PORT_ID)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
// If the port is full, we obviously don't care to report this, as we
|
||||||
|
// already placed our message.
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
BMessage*
|
BMessage*
|
||||||
InputServerStream::PeekLatestMouseMoved()
|
InputServerStream::PeekLatestMouseMoved()
|
||||||
{
|
{
|
||||||
@@ -231,6 +246,10 @@ InputServerStream::_MessageFromPort(BMessage** _message, bigtime_t timeout)
|
|||||||
// this will cause GetNextEvent() to return false
|
// this will cause GetNextEvent() to return false
|
||||||
return B_BAD_PORT_ID;
|
return B_BAD_PORT_ID;
|
||||||
}
|
}
|
||||||
|
if (code == 'insm') {
|
||||||
|
// a message has been inserted into our queue
|
||||||
|
return B_INTERRUPTED;
|
||||||
|
}
|
||||||
|
|
||||||
// we have the message, now let's unflatten it
|
// we have the message, now let's unflatten it
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ class EventStream {
|
|||||||
virtual bool GetNextEvent(BMessage** _event) = 0;
|
virtual bool GetNextEvent(BMessage** _event) = 0;
|
||||||
virtual bool GetNextCursorPosition(BPoint& where);
|
virtual bool GetNextCursorPosition(BPoint& where);
|
||||||
|
|
||||||
|
virtual status_t InsertEvent(BMessage* event) = 0;
|
||||||
|
|
||||||
virtual BMessage* PeekLatestMouseMoved() = 0;
|
virtual BMessage* PeekLatestMouseMoved() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -55,6 +57,8 @@ class InputServerStream : public EventStream {
|
|||||||
virtual bool GetNextEvent(BMessage** _event);
|
virtual bool GetNextEvent(BMessage** _event);
|
||||||
virtual bool GetNextCursorPosition(BPoint& where);
|
virtual bool GetNextCursorPosition(BPoint& where);
|
||||||
|
|
||||||
|
virtual status_t InsertEvent(BMessage* event);
|
||||||
|
|
||||||
virtual BMessage* PeekLatestMouseMoved();
|
virtual BMessage* PeekLatestMouseMoved();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
Reference in New Issue
Block a user