Implemented support for Set[Mouse]EventMask() functionality - still untested, though.
Also supports the B_SUSPEND_VIEW_FOCUS options, B_NO_POINTER_HISTORY is not yet there, and B_LOCK_WINDOW_FOCUS has to be implemented somewhere else (its outside of the scope of this class). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15007 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
6482dd587f
commit
0307fbb17d
@ -15,12 +15,31 @@
|
||||
#include <MessageFilter.h>
|
||||
#include <View.h>
|
||||
|
||||
#include <new>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
/*!
|
||||
The differentiation between messenger and token looks odd, but it
|
||||
really has a reason as well:
|
||||
All events are sent to the window only - it may then use the token or
|
||||
token list to identify the specific target view(s).
|
||||
*/
|
||||
struct EventDispatcher::event_target {
|
||||
BMessenger messenger;
|
||||
int32 token;
|
||||
uint32 events;
|
||||
uint32 options;
|
||||
uint32 temporary_events;
|
||||
uint32 temporary_options;
|
||||
};
|
||||
|
||||
static const char* kTokenName = "_token_";
|
||||
|
||||
static const float kMouseMovedImportance = 0.1f;
|
||||
static const float kMouseTransitImportance = 1.0f;
|
||||
static const float kStandardImportance = 0.9f;
|
||||
static const float kListenerImportance = 0.8f;
|
||||
|
||||
|
||||
EventDispatcher::EventDispatcher()
|
||||
@ -31,8 +50,11 @@ EventDispatcher::EventDispatcher()
|
||||
fHasFocus(false),
|
||||
fHasLastFocus(false),
|
||||
fTransit(false),
|
||||
fSuspendFocus(false),
|
||||
fMouseFilter(NULL),
|
||||
fKeyFilter(NULL),
|
||||
fListeners(10, true),
|
||||
// the list owns its items
|
||||
fCursorLock("cursor loop lock"),
|
||||
fHWInterface(NULL)
|
||||
{
|
||||
@ -110,17 +132,159 @@ EventDispatcher::SetFocus(BMessenger* messenger)
|
||||
return;
|
||||
|
||||
fHasLastFocus = fHasFocus;
|
||||
if (fHasFocus)
|
||||
fLastFocusTokens.MakeEmpty();
|
||||
|
||||
if (fHasFocus) {
|
||||
fLastFocus = fFocus;
|
||||
fLastFocusTokens.AddList(&fFocusTokens);
|
||||
}
|
||||
|
||||
fHasFocus = messenger != NULL;
|
||||
if (fHasFocus)
|
||||
fFocusTokens.MakeEmpty();
|
||||
|
||||
if (fHasFocus) {
|
||||
fFocus = *messenger;
|
||||
|
||||
// add all B_POINTER_EVENTS tokens that target this messenger
|
||||
for (int32 i = fListeners.CountItems(); i-- > 0;) {
|
||||
event_target* target = fListeners.ItemAt(i);
|
||||
|
||||
if (((target->events | target->temporary_events) & B_POINTER_EVENTS) != 0
|
||||
&& target->messenger == fFocus)
|
||||
fFocusTokens.AddItem((void *)target->token);
|
||||
}
|
||||
}
|
||||
|
||||
fTransit = true;
|
||||
}
|
||||
|
||||
|
||||
EventDispatcher::event_target*
|
||||
EventDispatcher::_FindListener(BMessenger& messenger, int32 token, int32* _index)
|
||||
{
|
||||
for (int32 i = fListeners.CountItems(); i-- > 0;) {
|
||||
event_target* target = fListeners.ItemAt(i);
|
||||
|
||||
if (target->token == token && target->messenger == messenger) {
|
||||
if (_index)
|
||||
*_index = i;
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
EventDispatcher::_AddListener(BMessenger& messenger, int32 token,
|
||||
uint32 events, uint32 options, bool temporary)
|
||||
{
|
||||
BAutolock _(this);
|
||||
event_target* target = _FindListener(messenger, token);
|
||||
if (target != NULL) {
|
||||
// we already have this target, update its event mask
|
||||
if (temporary) {
|
||||
target->temporary_events = events;
|
||||
target->temporary_options = options;
|
||||
} else {
|
||||
target->events = events;
|
||||
target->options = options;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// we need a new target
|
||||
|
||||
target = new (std::nothrow) event_target;
|
||||
if (target == NULL)
|
||||
return false;
|
||||
|
||||
target->messenger = messenger;
|
||||
target->token = token;
|
||||
|
||||
if (temporary) {
|
||||
target->events = 0;
|
||||
target->options = 0;
|
||||
target->temporary_events = events;
|
||||
target->temporary_options = options;
|
||||
if (options & B_SUSPEND_VIEW_FOCUS)
|
||||
fSuspendFocus = true;
|
||||
} else {
|
||||
target->events = events;
|
||||
target->options = options;
|
||||
target->temporary_events = 0;
|
||||
target->temporary_options = 0;
|
||||
}
|
||||
|
||||
bool success = fListeners.AddItem(target);
|
||||
if (success) {
|
||||
if ((events & B_POINTER_EVENTS) != 0
|
||||
&& fHasFocus && fFocus == messenger) {
|
||||
// add this token to the current token list
|
||||
fFocusTokens.AddItem((void *)token);
|
||||
}
|
||||
} else
|
||||
delete target;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EventDispatcher::_RemoveTemporaryListeners()
|
||||
{
|
||||
for (int32 i = fListeners.CountItems(); i-- > 0;) {
|
||||
event_target* target = fListeners.ItemAt(i);
|
||||
|
||||
if (target->events == 0) {
|
||||
// this is only a temporary target
|
||||
fListeners.RemoveItemAt(i);
|
||||
|
||||
if ((target->temporary_events & B_POINTER_EVENTS) != 0
|
||||
&& fHasFocus && fFocus == target->messenger) {
|
||||
// remove this token from the current token list
|
||||
fFocusTokens.RemoveItem((void *)target->token);
|
||||
}
|
||||
|
||||
delete target;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
EventDispatcher::AddListener(BMessenger& messenger, int32 token,
|
||||
uint32 events, uint32 options)
|
||||
{
|
||||
return _AddListener(messenger, token, events, options, false);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
EventDispatcher::AddTemporaryListener(BMessenger& messenger, int32 token,
|
||||
uint32 events, uint32 options)
|
||||
{
|
||||
return _AddListener(messenger, token, events, options, true);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EventDispatcher::RemoveListener(BMessenger& messenger, int32 token)
|
||||
{
|
||||
BAutolock _(this);
|
||||
|
||||
int32 index;
|
||||
event_target* target = _FindListener(messenger, token, &index);
|
||||
if (target == NULL)
|
||||
return;
|
||||
|
||||
fListeners.RemoveItemAt(index);
|
||||
delete target;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EventDispatcher::SetMouseFilter(BMessageFilter* filter)
|
||||
{
|
||||
@ -167,7 +331,18 @@ EventDispatcher::SetHWInterface(HWInterface* interface)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
/*!
|
||||
\brief Sends \a message to the provided \a messenger.
|
||||
|
||||
TODO: the following feature is not yet implemented:
|
||||
If the message could not be delivered immediately, it is included
|
||||
in a waiting message queue with a fixed length - the least important
|
||||
messages are removed first when that gets full.
|
||||
|
||||
Returns "false" if the target port does not exist anymore, "true"
|
||||
if it doesn't.
|
||||
*/
|
||||
bool
|
||||
EventDispatcher::_SendMessage(BMessenger& messenger, BMessage* message,
|
||||
float importance)
|
||||
{
|
||||
@ -176,6 +351,13 @@ EventDispatcher::_SendMessage(BMessenger& messenger, BMessage* message,
|
||||
status_t status = messenger.SendMessage(message, (BHandler*)NULL, 100000);
|
||||
if (status != B_OK)
|
||||
printf("failed to send message to target: %lx\n", message->what);
|
||||
|
||||
if (status == B_BAD_PORT_ID) {
|
||||
// the target port is gone
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -187,6 +369,45 @@ EventDispatcher::_SetTransit(BMessage* message, int32 transit)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EventDispatcher::_UnsetTransit(BMessage* message)
|
||||
{
|
||||
message->RemoveName("be:transit");
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
EventDispatcher::_AddTokens(BMessage* message, BList& tokens)
|
||||
{
|
||||
_RemoveTokens(message);
|
||||
|
||||
int32 count = tokens.CountItems();
|
||||
for (int32 i = count; i-- > 0;) {
|
||||
int32 token = (int32)tokens.ItemAt(i);
|
||||
|
||||
if (message->AddInt32(kTokenName, token) != B_OK)
|
||||
count--;
|
||||
}
|
||||
|
||||
return count != 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EventDispatcher::_RemoveTokens(BMessage* message)
|
||||
{
|
||||
message->RemoveName(kTokenName);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EventDispatcher::_SetToken(BMessage* message, int32 token)
|
||||
{
|
||||
if (message->ReplaceInt32(kTokenName, token) != B_OK)
|
||||
message->AddInt32(kTokenName, token);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EventDispatcher::_EventLoop()
|
||||
{
|
||||
@ -199,7 +420,12 @@ EventDispatcher::_EventLoop()
|
||||
}
|
||||
|
||||
BAutolock _(this);
|
||||
|
||||
bool sendToLastFocus = false;
|
||||
bool pointerEvent = false;
|
||||
bool keyboardEvent = false;
|
||||
bool addedTransit = false;
|
||||
bool addedTokens = false;
|
||||
|
||||
switch (event->what) {
|
||||
case B_MOUSE_MOVED:
|
||||
@ -217,14 +443,19 @@ EventDispatcher::_EventLoop()
|
||||
// to the message
|
||||
if (fHasLastFocus) {
|
||||
_SetTransit(event, B_EXITED_VIEW);
|
||||
addedTokens = _AddTokens(event, fLastFocusTokens);
|
||||
_SendMessage(fLastFocus, event, kMouseTransitImportance);
|
||||
sendToLastFocus = true;
|
||||
|
||||
// we no longer need the last focus messenger
|
||||
fHasLastFocus = false;
|
||||
fLastFocusTokens.MakeEmpty();
|
||||
}
|
||||
if (fHasFocus)
|
||||
_SetTransit(event, B_ENTERED_VIEW);
|
||||
|
||||
fTransit = false;
|
||||
addedTransit = true;
|
||||
}
|
||||
// supposed to fall through
|
||||
case B_MOUSE_DOWN:
|
||||
@ -233,7 +464,10 @@ EventDispatcher::_EventLoop()
|
||||
&& fMouseFilter->Filter(event, NULL) == B_SKIP_MESSAGE)
|
||||
break;
|
||||
|
||||
pointerEvent = true;
|
||||
|
||||
if (fHasFocus) {
|
||||
addedTokens |= _AddTokens(event, fFocusTokens);
|
||||
_SendMessage(fFocus, event, event->what == B_MOUSE_MOVED
|
||||
? kMouseMovedImportance : kStandardImportance);
|
||||
}
|
||||
@ -248,12 +482,54 @@ EventDispatcher::_EventLoop()
|
||||
&& fKeyFilter->Filter(event, NULL) == B_SKIP_MESSAGE)
|
||||
break;
|
||||
|
||||
keyboardEvent = true;
|
||||
|
||||
// supposed to fall through
|
||||
|
||||
default:
|
||||
if (fHasFocus)
|
||||
if (fHasFocus && !fSuspendFocus)
|
||||
_SendMessage(fFocus, event, kStandardImportance);
|
||||
break;
|
||||
}
|
||||
|
||||
if (keyboardEvent || pointerEvent) {
|
||||
// send the event to the additional listeners
|
||||
|
||||
if (addedTransit)
|
||||
_UnsetTransit(event);
|
||||
if (addedTokens)
|
||||
_RemoveTokens(event);
|
||||
|
||||
for (int32 i = fListeners.CountItems(); i-- > 0;) {
|
||||
event_target* target = fListeners.ItemAt(i);
|
||||
|
||||
// we already sent the event to the all focus and last focus tokens
|
||||
if ((fHasFocus && target->messenger == fFocus)
|
||||
|| (sendToLastFocus && target->messenger == fLastFocus))
|
||||
continue;
|
||||
|
||||
uint32 effectiveEvents = target->events | target->temporary_events;
|
||||
|
||||
// make sure only those interested listeners get the message
|
||||
if ((keyboardEvent && (effectiveEvents & B_KEYBOARD_EVENTS) == 0)
|
||||
|| (pointerEvent && (effectiveEvents & B_POINTER_EVENTS) == 0))
|
||||
continue;
|
||||
|
||||
_SetToken(event, target->token);
|
||||
if (!_SendMessage(target->messenger, event, event->what == B_MOUSE_MOVED
|
||||
? kMouseMovedImportance : kListenerImportance)) {
|
||||
// the target doesn't seem to exist anymore, let's remove this target
|
||||
fListeners.RemoveItemAt(i);
|
||||
delete target;
|
||||
}
|
||||
}
|
||||
|
||||
if (event->what == B_MOUSE_UP) {
|
||||
fSuspendFocus = false;
|
||||
_RemoveTemporaryListeners();
|
||||
}
|
||||
}
|
||||
|
||||
delete event;
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include <Locker.h>
|
||||
#include <Messenger.h>
|
||||
#include <ObjectList.h>
|
||||
|
||||
class BMessageFilter;
|
||||
|
||||
@ -28,6 +29,12 @@ class EventDispatcher : public BLocker {
|
||||
|
||||
void SetFocus(BMessenger* messenger);
|
||||
|
||||
bool AddListener(BMessenger& messenger, int32 token,
|
||||
uint32 events, uint32 options);
|
||||
bool AddTemporaryListener(BMessenger& messenger, int32 token,
|
||||
uint32 events, uint32 options);
|
||||
void RemoveListener(BMessenger& messenger, int32 token);
|
||||
|
||||
void SetMouseFilter(BMessageFilter* filter);
|
||||
void SetKeyFilter(BMessageFilter* filter);
|
||||
|
||||
@ -37,11 +44,23 @@ class EventDispatcher : public BLocker {
|
||||
EventStream* Stream();
|
||||
|
||||
private:
|
||||
struct event_target;
|
||||
|
||||
status_t _Run();
|
||||
void _Unset();
|
||||
|
||||
void _SendMessage(BMessenger& messenger, BMessage* message, float importance);
|
||||
bool _SendMessage(BMessenger& messenger, BMessage* message, float importance);
|
||||
void _SetTransit(BMessage* message, int32 transit);
|
||||
void _UnsetTransit(BMessage* message);
|
||||
bool _AddTokens(BMessage* message, BList& tokens);
|
||||
void _RemoveTokens(BMessage* message);
|
||||
void _SetToken(BMessage* message, int32 token);
|
||||
|
||||
event_target* _FindListener(BMessenger& messenger, int32 token,
|
||||
int32* _index = NULL);
|
||||
bool _AddListener(BMessenger& messenger, int32 token, uint32 events,
|
||||
uint32 options, bool temporary);
|
||||
void _RemoveTemporaryListeners();
|
||||
|
||||
void _EventLoop();
|
||||
void _CursorLoop();
|
||||
@ -59,9 +78,15 @@ class EventDispatcher : public BLocker {
|
||||
bool fHasFocus;
|
||||
bool fHasLastFocus;
|
||||
bool fTransit;
|
||||
BList fLastFocusTokens;
|
||||
BList fFocusTokens;
|
||||
bool fSuspendFocus;
|
||||
|
||||
BMessageFilter* fMouseFilter;
|
||||
BMessageFilter* fKeyFilter;
|
||||
|
||||
BObjectList<event_target> fListeners;
|
||||
|
||||
BLocker fCursorLock;
|
||||
HWInterface* fHWInterface;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user