Have I said input event handling is done?

* didn't realize that mouse events always go to the view under the mouse, not
  only if its the focus window (FFM can really do harm, after all :-)).
* removed a TODO from the list: EventDispatcher::Target is now a public
  class EventTarget, and every ServerWindow has one.
* as a result, EventDispatcher no longer manages targets itself, it
  just maintains a list of them. You no longer set messengers, you
  only set targets.
* customization of the message filters, they no longer inherit from
  BMessageFilter (but EventFilter).
* a message target is no longer set explicetly anywhere, it's only
  changed in the message filters if needed.
* therefore, no more locking mess in the EventDispatcher needed.
* this also made the EventDispatcher::fLastFocus stuff superfluous.
* moved the RootLayer::MouseEventHandler() into the message filter.
* Replaced RootLayer::_ChildAt() with WindowAt().
* WindowLayer now has an idea if it has focus or not, it no longer needs
  to query the RootLayer for this - maybe we should rename "focus" to
  "active", though (as far as layers are concerned).
* the "_view_token" data is now added from the EventDispatcher, not
  the (Window)Layer class anymore.
* removed Layer::MouseWheelChanged() as we currently don't need it
  (if the need arises, we can add it back later again)
* there is still no mouse moved message sent when opening a window
  under the cursor, though...


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15228 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2005-11-29 16:01:41 +00:00
parent c7bba5ca04
commit f89b4c9a23
11 changed files with 342 additions and 399 deletions

View File

@ -49,26 +49,46 @@
#endif
class KeyboardFilter : public BMessageFilter {
class KeyboardFilter : public EventFilter {
public:
KeyboardFilter(Desktop* desktop);
virtual filter_result Filter(BMessage* message, BHandler** _target);
virtual filter_result Filter(BMessage* message, EventTarget** _target,
int32* _viewToken);
private:
Desktop* fDesktop;
Desktop* fDesktop;
EventTarget* fLastFocus;
bigtime_t fTimestamp;
};
class MouseFilter : public EventFilter {
public:
MouseFilter(Desktop* desktop);
virtual filter_result Filter(BMessage* message, EventTarget** _target,
int32* _viewToken);
private:
Desktop* fDesktop;
};
// #pragma mark -
KeyboardFilter::KeyboardFilter(Desktop* desktop)
: BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
fDesktop(desktop)
:
fDesktop(desktop),
fLastFocus(NULL),
fTimestamp(0)
{
}
filter_result
KeyboardFilter::Filter(BMessage* message, BHandler** /*_target*/)
KeyboardFilter::Filter(BMessage* message, EventTarget** _target,
int32* /*_viewToken*/)
{
int32 key;
int32 modifiers;
@ -123,6 +143,93 @@ KeyboardFilter::Filter(BMessage* message, BHandler** /*_target*/)
return B_SKIP_MESSAGE;
}
bigtime_t now = system_time();
::RootLayer* rootLayer = fDesktop->RootLayer();
rootLayer->Lock();
EventTarget* focus = NULL;
if (rootLayer->Focus() != NULL)
focus = &rootLayer->Focus()->Window()->EventTarget();
// TODO: this is a try to not steal focus from the current window
// in case you enter some text and a window pops up you haven't
// triggered yourself (like a pop-up window in your browser while
// you're typing a password in another window) - maybe this should
// be done differently, though (using something like B_LOCK_WINDOW_FOCUS)
if (focus != fLastFocus && now - fTimestamp > 100000) {
// if the time span between the key presses is very short
// we keep our previous focus alive - this is save even
// if the target doesn't exist anymore, as we don't reset
// it, and the event focus passed in is always valid (or NULL)
*_target = focus;
fLastFocus = focus;
}
rootLayer->Unlock();
// we always allow to switch focus after the enter key has pressed
if (key == B_ENTER)
fTimestamp = 0;
else
fTimestamp = now;
return B_DISPATCH_MESSAGE;
}
// #pragma mark -
MouseFilter::MouseFilter(Desktop* desktop)
:
fDesktop(desktop)
{
}
filter_result
MouseFilter::Filter(BMessage* message, EventTarget** _target, int32* _viewToken)
{
BPoint where;
if (message->FindPoint("where", &where) != B_OK)
return B_DISPATCH_MESSAGE;
::RootLayer* rootLayer = fDesktop->RootLayer();
rootLayer->Lock();
WindowLayer* window = rootLayer->MouseEventWindow();
if (window == NULL)
window = rootLayer->WindowAt(where);
if (window != NULL) {
// dispatch event in the window layers
switch (message->what) {
case B_MOUSE_DOWN:
window->MouseDown(message, where, _viewToken);
break;
case B_MOUSE_UP:
window->MouseUp(message, where, _viewToken);
rootLayer->SetMouseEventWindow(NULL);
break;
case B_MOUSE_MOVED:
window->MouseMoved(message, where, _viewToken);
break;
}
if (*_viewToken != B_NULL_TOKEN)
*_target = &window->Window()->EventTarget();
else
*_target = NULL;
} else
*_target = NULL;
rootLayer->Unlock();
return B_DISPATCH_MESSAGE;
}
@ -185,28 +292,7 @@ Desktop::Init()
fEventDispatcher.SetTo(gInputManager->GetStream());
fEventDispatcher.SetHWInterface(fVirtualScreen.HWInterface());
// temporary hack to get things started
class MouseFilter : public BMessageFilter {
public:
MouseFilter(::RootLayer* layer)
: BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
fRootLayer(layer)
{
}
virtual filter_result
Filter(BMessage* message, BHandler** /*_target*/)
{
fRootLayer->Lock();
fRootLayer->MouseEventHandler(message);
fRootLayer->Unlock();
return B_DISPATCH_MESSAGE;
}
private:
::RootLayer* fRootLayer;
};
fEventDispatcher.SetMouseFilter(new MouseFilter(fRootLayer));
fEventDispatcher.SetMouseFilter(new MouseFilter(this));
fEventDispatcher.SetKeyboardFilter(new KeyboardFilter(this));
// take care of setting the default cursor
@ -560,6 +646,9 @@ Desktop::RemoveWindowLayer(WindowLayer *windowLayer)
Unlock();
RootLayer()->RemoveWindowLayer(windowLayer);
if (windowLayer->Window() != NULL)
EventDispatcher().RemoveTarget(windowLayer->Window()->EventTarget());
}

View File

@ -12,6 +12,8 @@
#include "HWInterface.h"
#include "InputManager.h"
#include <TokenSpace.h>
#include <Autolock.h>
#include <MessageFilter.h>
#include <View.h>
@ -29,11 +31,6 @@
#endif
// TODO: the Target class could be made public, and ServerWindow could inherit
// from it - this would especially be nice if we didn't have to lock the root
// layer when messing with ServerWindow children (because then, RootLayer's
// mouse filter could almost be moved completely to the window).
/*!
The differentiation between messenger and token looks odd, but it
really has a reason as well:
@ -42,40 +39,7 @@
view(s).
*/
class EventDispatcher::Target {
public:
Target(const BMessenger& messenger);
~Target();
BMessenger& Messenger() { return fMessenger; }
event_listener* FindListener(int32 token, int32* _index = NULL);
bool AddListener(int32 token, uint32 eventMask, uint32 options,
bool temporary);
void RemoveListener(event_listener* listener, bool temporary);
bool RemoveListener(int32 token);
bool RemoveTemporaryListener(int32 token);
void RemoveTemporaryListeners();
bool IsNeeded() const { return fFocusOrLastFocus || !fListeners.IsEmpty(); }
void SetFocusOrLastFocus(bool focus) { fFocusOrLastFocus = focus; }
bool FocusOrLastFocus() const { return fFocusOrLastFocus; }
int32 CountListeners() const { return fListeners.CountItems(); }
event_listener* ListenerAt(int32 index) const { return fListeners.ItemAt(index); }
private:
bool _RemoveTemporaryListener(event_listener* listener, int32 index);
BObjectList<event_listener> fListeners;
BMessenger fMessenger;
bool fFocusOrLastFocus;
};
struct EventDispatcher::event_listener {
struct event_listener {
int32 token;
uint32 event_mask;
uint32 options;
@ -93,22 +57,27 @@ static const float kStandardImportance = 0.9f;
static const float kListenerImportance = 0.8f;
EventDispatcher::Target::Target(const BMessenger& messenger)
EventTarget::EventTarget()
:
fListeners(2, true),
fMessenger(messenger),
fFocusOrLastFocus(false)
fListeners(2, true)
{
}
EventDispatcher::Target::~Target()
EventTarget::~EventTarget()
{
}
EventDispatcher::event_listener*
EventDispatcher::Target::FindListener(int32 token, int32* _index)
void
EventTarget::SetTo(const BMessenger& messenger)
{
fMessenger = messenger;
}
event_listener*
EventTarget::FindListener(int32 token, int32* _index)
{
for (int32 i = fListeners.CountItems(); i-- > 0;) {
event_listener* listener = fListeners.ItemAt(i);
@ -125,7 +94,7 @@ EventDispatcher::Target::FindListener(int32 token, int32* _index)
bool
EventDispatcher::Target::_RemoveTemporaryListener(event_listener* listener, int32 index)
EventTarget::_RemoveTemporaryListener(event_listener* listener, int32 index)
{
if (listener->event_mask == 0) {
// this is only a temporary target
@ -150,7 +119,7 @@ EventDispatcher::Target::_RemoveTemporaryListener(event_listener* listener, int3
void
EventDispatcher::Target::RemoveTemporaryListeners()
EventTarget::RemoveTemporaryListeners()
{
for (int32 index = CountListeners(); index-- > 0;) {
event_listener* listener = ListenerAt(index);
@ -161,7 +130,7 @@ EventDispatcher::Target::RemoveTemporaryListeners()
bool
EventDispatcher::Target::RemoveTemporaryListener(int32 token)
EventTarget::RemoveTemporaryListener(int32 token)
{
int32 index;
event_listener* listener = FindListener(token, &index);
@ -173,7 +142,7 @@ EventDispatcher::Target::RemoveTemporaryListener(int32 token)
bool
EventDispatcher::Target::RemoveListener(int32 token)
EventTarget::RemoveListener(int32 token)
{
int32 index;
event_listener* listener = FindListener(token, &index);
@ -194,7 +163,7 @@ EventDispatcher::Target::RemoveListener(int32 token)
bool
EventDispatcher::Target::AddListener(int32 token, uint32 eventMask,
EventTarget::AddListener(int32 token, uint32 eventMask,
uint32 options, bool temporary)
{
event_listener* listener = new (std::nothrow) event_listener;
@ -231,15 +200,12 @@ EventDispatcher::EventDispatcher()
fStream(NULL),
fThread(-1),
fCursorThread(-1),
fPreviousMouseTarget(NULL),
fFocus(NULL),
fLastFocus(NULL),
fTransit(false),
fSuspendFocus(false),
fMouseFilter(NULL),
fKeyboardFilter(NULL),
fTargets(10, true),
// the list owns its items
fListenerLock("listener lock"),
fTargets(10),
fCursorLock("cursor loop lock"),
fHWInterface(NULL)
{
@ -321,101 +287,20 @@ EventDispatcher::_Run()
}
/*!
\brief Removes any reference to the target, but doesn't delete it.
*/
void
EventDispatcher::_UnsetLastFocus()
{
if (fLastFocus == NULL)
return;
fLastFocus->SetFocusOrLastFocus(false);
if (!fLastFocus->IsNeeded())
_RemoveTarget(fLastFocus);
fLastFocus = NULL;
}
void
EventDispatcher::SetFocus(const BMessenger* messenger)
EventDispatcher::RemoveTarget(EventTarget& target)
{
BAutolock _(this);
BAutolock _temp(fListenerLock);
ETRACE(("EventDispatcher::SetFocus(messenger = %p)\n", messenger));
if ((messenger == NULL && fFocus == NULL)
|| (messenger != NULL && fFocus != NULL && fFocus->Messenger() == *messenger))
return;
// update last focus
if (fLastFocus != NULL)
_UnsetLastFocus();
fLastFocus = fFocus;
// update focus
if (messenger != NULL) {
fFocus = _FindTarget(*messenger);
if (fFocus == NULL) {
// we need a new target for this focus
fFocus = _AddTarget(*messenger);
if (fFocus == NULL)
printf("EventDispatcher: could not set focus!\n");
}
if (fFocus != NULL)
fFocus->SetFocusOrLastFocus(true);
} else
if (fFocus == &target)
fFocus = NULL;
if (fPreviousMouseTarget == &target)
fPreviousMouseTarget = NULL;
fFocusGotExitTransit = true;
fTransit = true;
}
EventDispatcher::Target*
EventDispatcher::_FindTarget(const BMessenger& messenger, int32* _index)
{
for (int32 i = fTargets.CountItems(); i-- > 0;) {
Target* target = fTargets.ItemAt(i);
if (target->Messenger() == messenger) {
if (_index)
*_index = i;
return target;
}
}
return NULL;
}
EventDispatcher::Target*
EventDispatcher::_AddTarget(const BMessenger& messenger)
{
Target* target = new (std::nothrow) Target(messenger);
if (target == NULL) {
printf("EventDispatcher: could not create new target!\n");
return NULL;
}
bool success = fTargets.AddItem(target);
if (!success) {
printf("EventDispatcher: could not add new target!\n");
delete target;
return NULL;
}
return target;
}
void
EventDispatcher::_RemoveTarget(Target* target)
{
// the list owns its items and will delete the target itself
fTargets.RemoveItem(target);
fTargets.RemoveItem(&target);
}
@ -427,19 +312,15 @@ EventDispatcher::_RemoveTarget(Target* target)
leaves the event mask untouched and just updates the options.
*/
bool
EventDispatcher::_AddListener(const BMessenger& messenger, int32 token,
EventDispatcher::_AddListener(EventTarget& target, int32 token,
uint32 eventMask, uint32 options, bool temporary)
{
BAutolock _(fListenerLock);
Target* target = _FindTarget(messenger);
if (target == NULL) {
// we need a new target for this messenger
target = _AddTarget(messenger);
if (target == NULL)
return false;
}
BAutolock _(this);
event_listener* listener = target->FindListener(token);
if (!fTargets.HasItem(&target))
fTargets.AddItem(&target);
event_listener* listener = target.FindListener(token);
if (listener != NULL) {
// we already have this target, update its event mask
if (temporary) {
@ -463,10 +344,10 @@ EventDispatcher::_AddListener(const BMessenger& messenger, int32 token,
// we need a new target
bool success = target->AddListener(token, eventMask, options, temporary);
bool success = target.AddListener(token, eventMask, options, temporary);
if (!success) {
if (!target->IsNeeded())
_RemoveTarget(target);
if (target.IsEmpty())
fTargets.RemoveItem(&target);
} else {
if (options & B_SUSPEND_VIEW_FOCUS)
fSuspendFocus = true;
@ -480,7 +361,7 @@ void
EventDispatcher::_RemoveTemporaryListeners()
{
for (int32 i = fTargets.CountItems(); i-- > 0;) {
Target* target = fTargets.ItemAt(i);
EventTarget* target = fTargets.ItemAt(i);
target->RemoveTemporaryListeners();
}
@ -488,61 +369,48 @@ EventDispatcher::_RemoveTemporaryListeners()
bool
EventDispatcher::AddListener(const BMessenger& messenger, int32 token,
EventDispatcher::AddListener(EventTarget& target, int32 token,
uint32 eventMask, uint32 options)
{
options &= B_NO_POINTER_HISTORY;
// that's currently the only allowed option
return _AddListener(messenger, token, eventMask, options, false);
return _AddListener(target, token, eventMask, options, false);
}
bool
EventDispatcher::AddTemporaryListener(const BMessenger& messenger,
EventDispatcher::AddTemporaryListener(EventTarget& target,
int32 token, uint32 eventMask, uint32 options)
{
return _AddListener(messenger, token, eventMask, options, true);
return _AddListener(target, token, eventMask, options, true);
}
void
EventDispatcher::RemoveListener(const BMessenger& messenger, int32 token)
EventDispatcher::RemoveListener(EventTarget& target, int32 token)
{
BAutolock _(fListenerLock);
BAutolock _(this);
ETRACE(("events: remove listener token %ld\n", token));
int32 index;
Target* target = _FindTarget(messenger, &index);
if (target == NULL)
return;
if (target->RemoveListener(token) && !target->IsNeeded()) {
fTargets.RemoveItemAt(index);
delete target;
}
if (target.RemoveListener(token) && target.IsEmpty())
fTargets.RemoveItem(&target);
}
void
EventDispatcher::RemoveTemporaryListener(const BMessenger& messenger, int32 token)
EventDispatcher::RemoveTemporaryListener(EventTarget& target, int32 token)
{
BAutolock _(fListenerLock);
BAutolock _(this);
ETRACE(("events: remove temporary listener token %ld\n", token));
int32 index;
Target* target = _FindTarget(messenger, &index);
if (target == NULL)
return;
if (target->RemoveTemporaryListener(token) && !target->IsNeeded()) {
fTargets.RemoveItemAt(index);
delete target;
}
if (target.RemoveTemporaryListener(token) && target.IsEmpty())
fTargets.RemoveItem(&target);
}
void
EventDispatcher::SetMouseFilter(BMessageFilter* filter)
EventDispatcher::SetMouseFilter(EventFilter* filter)
{
BAutolock _(this);
@ -555,7 +423,7 @@ EventDispatcher::SetMouseFilter(BMessageFilter* filter)
void
EventDispatcher::SetKeyboardFilter(BMessageFilter* filter)
EventDispatcher::SetKeyboardFilter(EventFilter* filter)
{
BAutolock _(this);
@ -633,13 +501,10 @@ EventDispatcher::_SendMessage(BMessenger& messenger, BMessage* message,
bool
EventDispatcher::_AddTokens(BMessage* message, Target* target, uint32 eventMask)
EventDispatcher::_AddTokens(BMessage* message, EventTarget* target, uint32 eventMask)
{
_RemoveTokens(message);
BAutolock _(fListenerLock);
// temporary lock
int32 count = target->CountListeners();
for (int32 i = count; i-- > 0;) {
event_listener* listener = target->ListenerAt(i);
@ -696,7 +561,8 @@ EventDispatcher::_EventLoop()
BAutolock _(this);
bool sendToLastFocus = false;
EventTarget* current = NULL;
EventTarget* previous = NULL;
bool pointerEvent = false;
bool keyboardEvent = false;
bool addedTokens = false;
@ -704,45 +570,37 @@ EventDispatcher::_EventLoop()
switch (event->what) {
case B_MOUSE_MOVED:
{
BPoint where;
if (event->FindPoint("where", &where) == B_OK)
fLastCursorPosition = where;
if (!HasCursorThread()) {
// there is no cursor thread, we need to move the cursor ourselves
BAutolock _(fCursorLock);
BPoint where;
if (fHWInterface != NULL && event->FindPoint("where", &where) == B_OK)
fHWInterface->MoveCursorTo(where.x, where.y);
}
if (fTransit) {
// target has changed, we need to add the be:transit field
// to the message
if (fLastFocus != NULL) {
addedTokens = _AddTokens(event, fLastFocus, B_POINTER_EVENTS);
_SendMessage(fLastFocus->Messenger(), event,
kMouseTransitImportance);
sendToLastFocus = true;
// we no longer need the last focus messenger
_UnsetLastFocus();
if (fHWInterface != NULL) {
fHWInterface->MoveCursorTo(fLastCursorPosition.x,
fLastCursorPosition.y);
}
fTransit = false;
}
BPoint where;
if (event->FindPoint("where", &where) == B_OK)
fLastCursorPosition = where;
// supposed to fall through
}
case B_MOUSE_DOWN:
case B_MOUSE_UP:
{
#ifdef TRACE_EVENTS
if (event->what != B_MOUSE_MOVED)
printf("mouse up/down event, focus = %p\n", fFocus);
printf("mouse up/down event, previous target = %p\n", fPreviousMouseTarget);
#endif
if (fMouseFilter != NULL
&& fMouseFilter->Filter(event, NULL) == B_SKIP_MESSAGE) {
pointerEvent = true;
if (fMouseFilter == NULL)
break;
EventTarget* mouseTarget = fPreviousMouseTarget;
int32 viewToken = B_NULL_TOKEN;
if (fMouseFilter->Filter(event, &mouseTarget, &viewToken) == B_SKIP_MESSAGE) {
// this is a work-around if the wrong B_MOUSE_UP
// event is filtered out
if (event->what == B_MOUSE_UP) {
@ -763,31 +621,30 @@ EventDispatcher::_EventLoop()
event->RemoveName("where");
event->AddPoint("screen_where", fLastCursorPosition);
pointerEvent = true;
if (event->what == B_MOUSE_MOVED
&& fPreviousMouseTarget != NULL
&& mouseTarget != fPreviousMouseTarget) {
// target has changed, we need to notify the previous target
// that the mouse has exited its views
addedTokens = _AddTokens(event, fPreviousMouseTarget,
B_POINTER_EVENTS);
_SendMessage(fPreviousMouseTarget->Messenger(), event,
kMouseTransitImportance);
previous = fPreviousMouseTarget;
}
if (fFocus != NULL) {
int32 viewToken;
current = fPreviousMouseTarget = mouseTarget;
addedTokens |= _AddTokens(event, fFocus, B_POINTER_EVENTS);
if (addedTokens)
_SetFeedFocus(event);
else if (fFocusGotExitTransit) {
// TODO: this is a temporary hack to not continue to
// send mouse messages to the client when the mouse
// pointer is not over it
if (event->FindInt32("_view_token", &viewToken) != B_OK)
break;
if (current != NULL) {
addedTokens |= _AddTokens(event, current, B_POINTER_EVENTS);
if (viewToken != B_NULL_TOKEN)
event->AddInt32("_view_token", viewToken);
fFocusGotExitTransit = false;
} else if (event->what == B_MOUSE_MOVED) {
if (event->FindInt32("_view_token", &viewToken) != B_OK)
fFocusGotExitTransit = true;
}
_SendMessage(fFocus->Messenger(), event, event->what == B_MOUSE_MOVED
_SendMessage(current->Messenger(), event, event->what == B_MOUSE_MOVED
? kMouseMovedImportance : kStandardImportance);
}
break;
}
case B_KEY_DOWN:
case B_KEY_UP:
@ -797,12 +654,12 @@ EventDispatcher::_EventLoop()
ETRACE(("key event, focus = %p\n", fFocus));
if (fKeyboardFilter != NULL
&& fKeyboardFilter->Filter(event, NULL) == B_SKIP_MESSAGE)
&& fKeyboardFilter->Filter(event, &fFocus) == B_SKIP_MESSAGE)
break;
keyboardEvent = true;
if (fFocus != NULL && _AddTokens(event, fFocus, B_KEYBOARD_EVENTS)) {
if (current != NULL && _AddTokens(event, fFocus, B_KEYBOARD_EVENTS)) {
// if tokens were added, we need to explicetly suspend
// focus in the event - if not, the event is simply not
// forwarded to the target
@ -815,8 +672,10 @@ EventDispatcher::_EventLoop()
// supposed to fall through
default:
if (fFocus != NULL && (!fSuspendFocus || addedTokens))
_SendMessage(fFocus->Messenger(), event, kStandardImportance);
current = fFocus;
if (current != NULL && (!fSuspendFocus || addedTokens))
_SendMessage(current->Messenger(), event, kStandardImportance);
break;
}
@ -833,13 +692,11 @@ EventDispatcher::_EventLoop()
event->RemoveName("_view_token");
}
BAutolock _temp(fListenerLock);
for (int32 i = fTargets.CountItems(); i-- > 0;) {
Target* target = fTargets.ItemAt(i);
EventTarget* target = fTargets.ItemAt(i);
// we already sent the event to the all focus and last focus tokens
if (fFocus == target || (sendToLastFocus && fLastFocus == target))
if (current == target || previous == target)
continue;
// don't send the message if there are no tokens for this event
@ -851,7 +708,6 @@ EventDispatcher::_EventLoop()
? kMouseMovedImportance : kListenerImportance)) {
// the target doesn't seem to exist anymore, let's remove it
fTargets.RemoveItemAt(i);
delete target;
}
}

View File

@ -10,14 +10,52 @@
#include <Locker.h>
#include <MessageFilter.h>
#include <Messenger.h>
#include <ObjectList.h>
class BMessageFilter;
class EventStream;
class HWInterface;
struct event_listener;
class EventTarget {
public:
EventTarget();
~EventTarget();
void SetTo(const BMessenger& messenger);
BMessenger& Messenger() { return fMessenger; }
event_listener* FindListener(int32 token, int32* _index = NULL);
bool AddListener(int32 token, uint32 eventMask, uint32 options,
bool temporary);
void RemoveListener(event_listener* listener, bool temporary);
bool RemoveListener(int32 token);
bool RemoveTemporaryListener(int32 token);
void RemoveTemporaryListeners();
bool IsEmpty() const { return fListeners.IsEmpty(); }
int32 CountListeners() const { return fListeners.CountItems(); }
event_listener* ListenerAt(int32 index) const
{ return fListeners.ItemAt(index); }
private:
bool _RemoveTemporaryListener(event_listener* listener, int32 index);
BObjectList<event_listener> fListeners;
BMessenger fMessenger;
};
class EventFilter {
public:
virtual filter_result Filter(BMessage* event, EventTarget** _target,
int32* _viewToken = NULL) = 0;
};
class EventDispatcher : public BLocker {
public:
@ -27,17 +65,17 @@ class EventDispatcher : public BLocker {
status_t SetTo(EventStream* stream);
status_t InitCheck();
void SetFocus(const BMessenger* messenger);
void RemoveTarget(EventTarget& target);
bool AddListener(const BMessenger& messenger, int32 token,
bool AddListener(EventTarget& target, int32 token,
uint32 eventMask, uint32 options);
bool AddTemporaryListener(const BMessenger& messenger,
bool AddTemporaryListener(EventTarget& target,
int32 token, uint32 eventMask, uint32 options);
void RemoveListener(const BMessenger& messenger, int32 token);
void RemoveTemporaryListener(const BMessenger& messenger, int32 token);
void RemoveListener(EventTarget& target, int32 token);
void RemoveTemporaryListener(EventTarget& target, int32 token);
void SetMouseFilter(BMessageFilter* filter);
void SetKeyboardFilter(BMessageFilter* filter);
void SetMouseFilter(EventFilter* filter);
void SetKeyboardFilter(EventFilter* filter);
void GetMouse(BPoint& where, int32& buttons);
@ -45,26 +83,20 @@ class EventDispatcher : public BLocker {
void SetHWInterface(HWInterface* interface);
private:
struct event_listener;
class Target;
status_t _Run();
void _Unset();
bool _SendMessage(BMessenger& messenger, BMessage* message, float importance);
bool _AddTokens(BMessage* message, Target* target, uint32 eventMask);
bool _AddTokens(BMessage* message, EventTarget* target, uint32 eventMask);
void _RemoveTokens(BMessage* message);
void _SetFeedFocus(BMessage* message);
void _UnsetFeedFocus(BMessage* message);
void _UnsetLastFocus();
void _SetMouseTarget(const BMessenger* messenger);
void _UnsetLastMouseTarget();
Target* _FindTarget(const BMessenger& messenger, int32* _index = NULL);
Target* _AddTarget(const BMessenger& messenger);
void _RemoveTarget(Target* target);
bool _AddListener(const BMessenger& messenger, int32 token,
bool _AddListener(EventTarget& target, int32 token,
uint32 eventMask, uint32 options, bool temporary);
void _RemoveTemporaryListeners();
@ -79,22 +111,18 @@ class EventDispatcher : public BLocker {
thread_id fThread;
thread_id fCursorThread;
Target* fFocus;
Target* fLastFocus;
bool fTransit;
bool fFocusGotExitTransit;
EventTarget* fPreviousMouseTarget;
EventTarget* fFocus;
bool fSuspendFocus;
BMessageFilter* fMouseFilter;
BMessageFilter* fKeyboardFilter;
EventFilter* fMouseFilter;
EventFilter* fKeyboardFilter;
BObjectList<Target> fTargets;
BObjectList<EventTarget> fTargets;
BPoint fLastCursorPosition;
int32 fLastButtons;
BLocker fListenerLock;
// temporary locker until we have an actual locking model
BLocker fCursorLock;
HWInterface* fHWInterface;
};

View File

@ -834,26 +834,23 @@ Layer::CopyBits(BRect& src, BRect& dst, int32 xOffset, int32 yOffset)
void
Layer::MouseDown(BMessage *msg, BPoint where)
Layer::MouseDown(BMessage *msg, BPoint where, int32* _viewToken)
{
*_viewToken = ViewToken();
}
void
Layer::MouseUp(BMessage *msg, BPoint where)
Layer::MouseUp(BMessage *msg, BPoint where, int32* _viewToken)
{
*_viewToken = ViewToken();
}
void
Layer::MouseMoved(BMessage *msg, BPoint where)
{
}
void
Layer::MouseWheelChanged(BMessage *msg, BPoint where)
Layer::MouseMoved(BMessage *msg, BPoint where, int32* _viewToken)
{
*_viewToken = ViewToken();
}

View File

@ -151,10 +151,9 @@ class Layer {
int32 xOffset, int32 yOffset);
// input handling
virtual void MouseDown(BMessage *msg, BPoint where);
virtual void MouseUp(BMessage *msg, BPoint where);
virtual void MouseMoved(BMessage *msg, BPoint where);
virtual void MouseWheelChanged(BMessage *msg, BPoint where);
virtual void MouseDown(BMessage *msg, BPoint where, int32* _viewToken);
virtual void MouseUp(BMessage *msg, BPoint where, int32* _viewToken);
virtual void MouseMoved(BMessage *msg, BPoint where, int32* _viewToken);
virtual void WorkspaceActivated(int32 index, bool active);
virtual void WorkspacesChanged(uint32 oldWorkspaces, uint32 newWorkspaces);

View File

@ -55,7 +55,7 @@ RootLayer::RootLayer(const char *name, Desktop *desktop, DrawingEngine *driver)
: Layer(BRect(0, 0, 0, 0), name, 0, B_FOLLOW_ALL, B_WILL_DRAW, driver),
fDesktop(desktop),
fDragMessage(NULL),
fMouseEventLayer(NULL),
fMouseEventWindow(NULL),
fAllRegionsLock("root layer region lock"),
fDirtyForRedraw(),
@ -172,20 +172,15 @@ RootLayer::_SetFocus(WindowLayer* focus, BRegion& update)
if (fFocus != NULL) {
update.Include(&fFocus->VisibleRegion());
//fFocus->SetFocus(false);
fFocus->SetFocus(false);
}
fFocus = focus;
if (focus != NULL) {
// TODO: the unlocking is evil, but there is currently no cleaner way to do this, ugh...
// (this is also responsible for an occasional crash on quit)
Unlock();
fDesktop->EventDispatcher().SetFocus(&focus->Window()->FocusMessenger());
Lock();
update.Include(&focus->VisibleRegion());
} else
fDesktop->EventDispatcher().SetFocus(NULL);
focus->SetFocus(true);
}
return true;
}
@ -194,6 +189,8 @@ RootLayer::_SetFocus(WindowLayer* focus, BRegion& update)
bool
RootLayer::SetFocus(WindowLayer* focus)
{
BAutolock _(fAllRegionsLock);
BRegion update;
bool success = _SetFocus(focus, update);
if (!success)
@ -524,15 +521,15 @@ RootLayer::_WindowsChanged(BRegion& region)
}
Layer*
RootLayer::_ChildAt(BPoint where)
WindowLayer*
RootLayer::WindowAt(BPoint where)
{
if (VisibleRegion().Contains(where))
return NULL;
for (Layer* child = LastChild(); child; child = child->PreviousLayer()) {
if (child->FullVisible().Contains(where))
return child;
return dynamic_cast<WindowLayer*>(child);
}
return NULL;
@ -543,48 +540,17 @@ RootLayer::_ChildAt(BPoint where)
void
RootLayer::MouseEventHandler(BMessage *event)
RootLayer::SetMouseEventWindow(WindowLayer* window)
{
BPoint where;
if (event->FindPoint("where", &where) != B_OK)
return;
Layer* layer = fMouseEventLayer;
if (layer == NULL) {
layer = _ChildAt(where);
if (layer == NULL)
return;
}
switch (event->what) {
case B_MOUSE_DOWN:
layer->MouseDown(event, where);
break;
case B_MOUSE_UP:
layer->MouseUp(event, where);
SetMouseEventLayer(NULL);
break;
case B_MOUSE_MOVED:
layer->MouseMoved(event, where);
break;
}
}
void
RootLayer::SetMouseEventLayer(Layer* layer)
{
fMouseEventLayer = layer;
fMouseEventWindow = window;
}
void
RootLayer::LayerRemoved(Layer* layer)
{
if (fMouseEventLayer == layer)
fMouseEventLayer = NULL;
if (fMouseEventWindow == layer)
fMouseEventWindow = NULL;
}

View File

@ -57,7 +57,6 @@ class RootLayer : public Layer {
void HideWindowLayer(WindowLayer* windowLayer);
void ShowWindowLayer(WindowLayer* windowLayer, bool toFront = true);
// void RevealNewWMState(Workspace::State &oldWMState);
bool SetFocus(WindowLayer* focus);
WindowLayer* Focus() const { return fFocus; }
WindowLayer* Front() const { return fFront; }
@ -67,15 +66,13 @@ class RootLayer : public Layer {
void SetWorkspacesLayer(Layer* layer) { fWorkspacesLayer = layer; }
Layer* WorkspacesLayer() const { return fWorkspacesLayer; }
#if 0
void SetBGColor(const RGBColor &col);
RGBColor BGColor(void) const;
#endif
void SetDragMessage(BMessage *msg);
BMessage* DragMessage() const;
void SetMouseEventLayer(Layer* layer);
WindowLayer* WindowAt(BPoint where);
WindowLayer* MouseEventWindow() const { return fMouseEventWindow; }
void SetMouseEventWindow(WindowLayer* layer);
void LayerRemoved(Layer* layer);
@ -100,8 +97,6 @@ class RootLayer : public Layer {
void AddWindowLayer(WindowLayer* windowLayer);
void RemoveWindowLayer(WindowLayer* windowLayer);
void MouseEventHandler(BMessage *msg);
private:
bool _SetFocus(WindowLayer* focus, BRegion& update);
void _SetFront(WindowLayer* front, BRegion& update);
@ -112,11 +107,9 @@ class RootLayer : public Layer {
void _WindowsChanged(BRegion& region);
void _UpdateWorkspace(Workspace& workspace);
Layer* _ChildAt(BPoint where);
Desktop* fDesktop;
BMessage* fDragMessage;
Layer* fMouseEventLayer;
WindowLayer* fMouseEventWindow;
BLocker fAllRegionsLock;

View File

@ -159,6 +159,8 @@ ServerWindow::ServerWindow(const char *title, ServerApp *app,
BMessenger::Private(fHandlerMessenger).SetTo(fClientTeam,
looperPort, clientToken);
fEventTarget.SetTo(fFocusMessenger);
fDeathSemaphore = create_sem(0, "window death");
}
@ -680,7 +682,7 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
}
if (fCurrentLayer->EventMask() != 0) {
fDesktop->EventDispatcher().RemoveListener(FocusMessenger(),
fDesktop->EventDispatcher().RemoveListener(EventTarget(),
fCurrentLayer->ViewToken());
}
@ -721,6 +723,8 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
case AS_LAYER_SET_EVENT_MASK:
{
STRACE(("ServerWindow %s: Message AS_LAYER_SET_MOUSE_EVENT_MASK: Layer name: %s\n", fTitle, fCurrentLayer->Name()));
rootLayer->Unlock();
// we don't want RootLayer to be locked while we play with the events
uint32 eventMask, options;
@ -729,33 +733,38 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
fCurrentLayer->SetEventMask(eventMask, options);
if (eventMask != 0 || options != 0) {
fDesktop->EventDispatcher().AddListener(FocusMessenger(),
fDesktop->EventDispatcher().AddListener(EventTarget(),
fCurrentLayer->ViewToken(), eventMask, options);
} else {
fDesktop->EventDispatcher().RemoveListener(FocusMessenger(),
fDesktop->EventDispatcher().RemoveListener(EventTarget(),
fCurrentLayer->ViewToken());
}
}
rootLayer->Lock();
break;
}
case AS_LAYER_SET_MOUSE_EVENT_MASK:
{
STRACE(("ServerWindow %s: Message AS_LAYER_SET_MOUSE_EVENT_MASK: Layer name: %s\n", fTitle, fCurrentLayer->Name()));
rootLayer->Unlock();
// we don't want RootLayer to be locked while we play with the events
uint32 eventMask, options;
link.Read<uint32>(&eventMask);
if (link.Read<uint32>(&options) == B_OK) {
if (eventMask != 0 || options != 0) {
fDesktop->EventDispatcher().AddTemporaryListener(FocusMessenger(),
fDesktop->EventDispatcher().AddTemporaryListener(EventTarget(),
fCurrentLayer->ViewToken(), eventMask, options);
} else {
fDesktop->EventDispatcher().RemoveTemporaryListener(FocusMessenger(),
fDesktop->EventDispatcher().RemoveTemporaryListener(EventTarget(),
fCurrentLayer->ViewToken());
}
}
// TODO: support B_LOCK_WINDOW_FOCUS option in RootLayer
rootLayer->Lock();
break;
}
case AS_LAYER_MOVE_TO:

View File

@ -13,6 +13,7 @@
#define SERVER_WINDOW_H
#include "EventDispatcher.h"
#include "MessageLooper.h"
#include <PortLink.h>
@ -59,6 +60,8 @@ public:
virtual bool Run();
virtual port_id MessagePort() const { return fMessagePort; }
::EventTarget& EventTarget() { return fEventTarget; }
void ReplaceDecorator();
void Show();
void Hide();
@ -135,6 +138,7 @@ private:
port_id fClientLooperPort;
BMessenger fFocusMessenger;
BMessenger fHandlerMessenger;
::EventTarget fEventTarget;
BMessage fClientViewsWithInvalidCoords;

View File

@ -70,6 +70,8 @@ WindowLayer::WindowLayer(const BRect &frame,
fMouseButtons(0),
fLastMousePosition(-1.0, -1.0),
fIsFocus(false),
fIsClosing(false),
fIsMinimizing(false),
fIsZooming(false),
@ -148,7 +150,7 @@ WindowLayer::Draw(const BRect& updateRect)
// if we have a visible region, it is decorator's one.
if (fDecorator) {
fDecorator->SetFocus(GetRootLayer()->Focus() == this);
fDecorator->SetFocus(IsFocus());
fDecorator->Draw(updateRect);
}
}
@ -389,7 +391,7 @@ WindowLayer::GetSizeLimits(float* minWidth, float* maxWidth,
void
WindowLayer::MouseDown(BMessage *msg, BPoint where)
WindowLayer::MouseDown(BMessage *msg, BPoint where, int32* _viewToken)
{
Desktop* desktop = Window()->App()->GetDesktop();
@ -403,8 +405,8 @@ WindowLayer::MouseDown(BMessage *msg, BPoint where)
if (fDecorator)
action = _ActionFor(msg);
// deactivate border buttons on first click(select)
if (GetRootLayer()->Focus() != this && action != DEC_MOVETOBACK
// deactivate border buttons on first click (select)
if (!IsFocus() && action != DEC_MOVETOBACK
&& action != DEC_RESIZE && action != DEC_SLIDETAB)
action = DEC_DRAG;
@ -454,12 +456,12 @@ WindowLayer::MouseDown(BMessage *msg, BPoint where)
if (action == DEC_MOVETOBACK) {
desktop->SendBehindWindow(this, NULL);
} else {
GetRootLayer()->SetMouseEventLayer(this);
GetRootLayer()->SetMouseEventWindow(this);
desktop->ActivateWindow(this);
}
} else if (target != NULL) {
// clicking a simple Layer.
if (GetRootLayer()->Focus() != this) {
if (!IsFocus()) {
DesktopSettings desktopSettings(desktop);
// not in FFM mode?
@ -470,14 +472,13 @@ WindowLayer::MouseDown(BMessage *msg, BPoint where)
return;
}
msg->AddInt32("_view_token", target->ViewToken());
target->MouseDown(msg, where);
target->MouseDown(msg, where, _viewToken);
}
}
void
WindowLayer::MouseUp(BMessage *msg, BPoint where)
WindowLayer::MouseUp(BMessage *msg, BPoint where, int32* _viewToken)
{
bool invalidate = false;
if (fDecorator) {
@ -517,15 +518,13 @@ WindowLayer::MouseUp(BMessage *msg, BPoint where)
fIsSlidingTab = false;
Layer* target = LayerAt(where);
if (target != NULL && target != this) {
msg->AddInt32("_view_token", target->ViewToken());
target->MouseUp(msg, where);
}
if (target != NULL && target != this)
target->MouseUp(msg, where, _viewToken);
}
void
WindowLayer::MouseMoved(BMessage *msg, BPoint where)
WindowLayer::MouseMoved(BMessage *msg, BPoint where, int32* _viewToken)
{
if (fDecorator) {
// TODO: present behavior is not fine!
@ -560,14 +559,12 @@ WindowLayer::MouseMoved(BMessage *msg, BPoint where)
Desktop* desktop = Window()->App()->GetDesktop();
DesktopSettings desktopSettings(desktop);
if (desktopSettings.MouseMode() != B_NORMAL_MOUSE && GetRootLayer()->Focus() != this)
if (desktopSettings.MouseMode() != B_NORMAL_MOUSE && !IsFocus())
GetRootLayer()->SetFocus(this);
Layer* target = LayerAt(where);
if (target != NULL && target != this) {
msg->AddInt32("_view_token", target->ViewToken());
target->MouseMoved(msg, where);
}
if (target != NULL && target != this)
target->MouseMoved(msg, where, _viewToken);
}

View File

@ -84,9 +84,9 @@ class WindowLayer : public Layer {
float* minHeight,
float* maxHeight) const;
virtual void MouseDown(BMessage *msg, BPoint where);
virtual void MouseUp(BMessage *msg, BPoint where);
virtual void MouseMoved(BMessage *msg, BPoint where);
virtual void MouseDown(BMessage *msg, BPoint where, int32* _viewToken);
virtual void MouseUp(BMessage *msg, BPoint where, int32* _viewToken);
virtual void MouseMoved(BMessage *msg, BPoint where, int32* _viewToken);
// click_type ActionFor(const BMessage *msg)
// { return _ActionFor(evt); }
@ -100,6 +100,9 @@ class WindowLayer : public Layer {
void UpdateFont();
void UpdateScreen();
bool IsFocus() const { return fIsFocus; }
void SetFocus(bool focus) { fIsFocus = focus; }
inline Decorator* GetDecorator() const { return fDecorator; }
inline int32 Look() const { return fLook; }
@ -151,6 +154,8 @@ class WindowLayer : public Layer {
BPoint fLastMousePosition;
BPoint fResizingClickOffset;
bool fIsFocus;
bool fIsClosing;
bool fIsMinimizing;
bool fIsZooming;