* 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:
parent
7ab39de989
commit
955307393f
@ -1326,8 +1326,6 @@ Desktop::RemoveWorkspacesView(WorkspacesView* view)
|
||||
|
||||
This has only to be done in case the view changed without user interaction,
|
||||
ie. because of a workspace change or a closing window.
|
||||
|
||||
Windows must not be locked when calling this method.
|
||||
*/
|
||||
void
|
||||
Desktop::_SendFakeMouseMoved(Window* window)
|
||||
@ -1520,6 +1518,9 @@ Desktop::ActivateWindow(Window* window)
|
||||
|
||||
// TODO: take care about floating windows
|
||||
|
||||
if (!LockAllWindows())
|
||||
return;
|
||||
|
||||
bool windowOnOtherWorkspace = !window->InWorkspace(fCurrentWorkspace);
|
||||
if (windowOnOtherWorkspace) {
|
||||
if ((window->Flags() & B_NO_WORKSPACE_ACTIVATION) == 0
|
||||
@ -1535,12 +1536,11 @@ Desktop::ActivateWindow(Window* window)
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if ((window->Flags() & B_NOT_ANCHORED_ON_ACTIVATE) == 0)
|
||||
} else if ((window->Flags() & B_NOT_ANCHORED_ON_ACTIVATE) == 0) {
|
||||
UnlockAllWindows();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!LockAllWindows())
|
||||
return;
|
||||
}
|
||||
|
||||
if (windowOnOtherWorkspace
|
||||
&& (window->Flags() & B_NOT_ANCHORED_ON_ACTIVATE) != 0) {
|
||||
@ -1554,12 +1554,7 @@ Desktop::ActivateWindow(Window* window)
|
||||
// Unlike WindowAction(), this is called from the application itself,
|
||||
// so we will just unminimize the window here.
|
||||
window->SetMinimized(false);
|
||||
UnlockAllWindows();
|
||||
|
||||
ShowWindow(window);
|
||||
|
||||
if (!LockAllWindows())
|
||||
return;
|
||||
}
|
||||
|
||||
if (window == FrontWindow()) {
|
||||
@ -2368,7 +2363,7 @@ Desktop::ViewUnderMouse(const Window* window)
|
||||
}
|
||||
|
||||
|
||||
Window *
|
||||
Window*
|
||||
Desktop::FindWindowByClientToken(int32 token, team_id teamID)
|
||||
{
|
||||
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
|
||||
Desktop::MinimizeApplication(team_id team)
|
||||
{
|
||||
|
@ -167,6 +167,7 @@ class Desktop : public MessageLooper, public ScreenOwner {
|
||||
|
||||
Window* FindWindowByClientToken(int32 token,
|
||||
team_id teamID);
|
||||
EventTarget* FindTarget(BMessenger& messenger);
|
||||
|
||||
#if USE_MULTI_LOCKER
|
||||
bool LockSingleWindow()
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "ServerBitmap.h"
|
||||
|
||||
#include <MessagePrivate.h>
|
||||
#include <MessengerPrivate.h>
|
||||
#include <ServerProtocol.h>
|
||||
#include <TokenSpace.h>
|
||||
|
||||
@ -72,6 +73,8 @@ struct event_listener {
|
||||
|
||||
static const char* kTokenName = "_token";
|
||||
|
||||
static const uint32 kFakeMouseMoved = 'fake';
|
||||
|
||||
static const float kMouseMovedImportance = 0.1f;
|
||||
static const float kMouseTransitImportance = 1.0f;
|
||||
static const float kStandardImportance = 0.9f;
|
||||
@ -494,7 +497,44 @@ EventDispatcher::GetMouse(BPoint& where, int32& buttons)
|
||||
void
|
||||
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);
|
||||
moved.AddPoint("screen_where", fLastCursorPosition);
|
||||
@ -504,7 +544,7 @@ EventDispatcher::SendFakeMouseMoved(EventTarget& target, int32 viewToken)
|
||||
moved.AddMessage("be:drag_message", &fDragMessage);
|
||||
|
||||
if (fPreviousMouseTarget != NULL
|
||||
&& fPreviousMouseTarget != &target) {
|
||||
&& fPreviousMouseTarget->Messenger() != target) {
|
||||
_AddTokens(&moved, fPreviousMouseTarget, B_POINTER_EVENTS);
|
||||
_SendMessage(fPreviousMouseTarget->Messenger(), &moved,
|
||||
kMouseTransitImportance);
|
||||
@ -515,8 +555,9 @@ EventDispatcher::SendFakeMouseMoved(EventTarget& target, int32 viewToken)
|
||||
moved.AddInt32("_view_token", viewToken);
|
||||
// this only belongs to the new target
|
||||
|
||||
_SendMessage(target.Messenger(), &moved, kMouseTransitImportance);
|
||||
fPreviousMouseTarget = ⌖
|
||||
_SendMessage(target, &moved, kMouseTransitImportance);
|
||||
|
||||
fPreviousMouseTarget = eventTarget;
|
||||
}
|
||||
|
||||
|
||||
@ -718,12 +759,6 @@ EventDispatcher::_EventLoop()
|
||||
{
|
||||
BMessage* 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);
|
||||
fLastUpdate = system_time();
|
||||
|
||||
@ -734,6 +769,9 @@ EventDispatcher::_EventLoop()
|
||||
bool addedTokens = false;
|
||||
|
||||
switch (event->what) {
|
||||
case kFakeMouseMoved:
|
||||
_SendFakeMouseMoved(event);
|
||||
break;
|
||||
case B_MOUSE_MOVED:
|
||||
{
|
||||
BPoint where;
|
||||
|
@ -102,6 +102,7 @@ class EventDispatcher : public BLocker {
|
||||
status_t _Run();
|
||||
void _Unset();
|
||||
|
||||
void _SendFakeMouseMoved(BMessage* message);
|
||||
bool _SendMessage(BMessenger& messenger, BMessage* message,
|
||||
float importance);
|
||||
|
||||
|
@ -120,7 +120,7 @@ InputServerStream::UpdateScreenBounds(BRect bounds)
|
||||
bool
|
||||
InputServerStream::GetNextEvent(BMessage** _event)
|
||||
{
|
||||
if (fEvents.IsEmpty()) {
|
||||
while (fEvents.IsEmpty()) {
|
||||
// wait for new events
|
||||
BMessage* 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*
|
||||
InputServerStream::PeekLatestMouseMoved()
|
||||
{
|
||||
@ -231,6 +246,10 @@ InputServerStream::_MessageFromPort(BMessage** _message, bigtime_t timeout)
|
||||
// this will cause GetNextEvent() to return false
|
||||
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
|
||||
|
||||
|
@ -32,6 +32,8 @@ class EventStream {
|
||||
virtual bool GetNextEvent(BMessage** _event) = 0;
|
||||
virtual bool GetNextCursorPosition(BPoint& where);
|
||||
|
||||
virtual status_t InsertEvent(BMessage* event) = 0;
|
||||
|
||||
virtual BMessage* PeekLatestMouseMoved() = 0;
|
||||
};
|
||||
|
||||
@ -55,6 +57,8 @@ class InputServerStream : public EventStream {
|
||||
virtual bool GetNextEvent(BMessage** _event);
|
||||
virtual bool GetNextCursorPosition(BPoint& where);
|
||||
|
||||
virtual status_t InsertEvent(BMessage* event);
|
||||
|
||||
virtual BMessage* PeekLatestMouseMoved();
|
||||
|
||||
private:
|
||||
|
Loading…
Reference in New Issue
Block a user