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:
@@ -15,12 +15,31 @@
|
|||||||
#include <MessageFilter.h>
|
#include <MessageFilter.h>
|
||||||
#include <View.h>
|
#include <View.h>
|
||||||
|
|
||||||
|
#include <new>
|
||||||
#include <stdio.h>
|
#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 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;
|
||||||
|
static const float kListenerImportance = 0.8f;
|
||||||
|
|
||||||
|
|
||||||
EventDispatcher::EventDispatcher()
|
EventDispatcher::EventDispatcher()
|
||||||
@@ -31,8 +50,11 @@ EventDispatcher::EventDispatcher()
|
|||||||
fHasFocus(false),
|
fHasFocus(false),
|
||||||
fHasLastFocus(false),
|
fHasLastFocus(false),
|
||||||
fTransit(false),
|
fTransit(false),
|
||||||
|
fSuspendFocus(false),
|
||||||
fMouseFilter(NULL),
|
fMouseFilter(NULL),
|
||||||
fKeyFilter(NULL),
|
fKeyFilter(NULL),
|
||||||
|
fListeners(10, true),
|
||||||
|
// the list owns its items
|
||||||
fCursorLock("cursor loop lock"),
|
fCursorLock("cursor loop lock"),
|
||||||
fHWInterface(NULL)
|
fHWInterface(NULL)
|
||||||
{
|
{
|
||||||
@@ -110,17 +132,159 @@ EventDispatcher::SetFocus(BMessenger* messenger)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
fHasLastFocus = fHasFocus;
|
fHasLastFocus = fHasFocus;
|
||||||
if (fHasFocus)
|
fLastFocusTokens.MakeEmpty();
|
||||||
|
|
||||||
|
if (fHasFocus) {
|
||||||
fLastFocus = fFocus;
|
fLastFocus = fFocus;
|
||||||
|
fLastFocusTokens.AddList(&fFocusTokens);
|
||||||
|
}
|
||||||
|
|
||||||
fHasFocus = messenger != NULL;
|
fHasFocus = messenger != NULL;
|
||||||
if (fHasFocus)
|
fFocusTokens.MakeEmpty();
|
||||||
|
|
||||||
|
if (fHasFocus) {
|
||||||
fFocus = *messenger;
|
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;
|
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
|
void
|
||||||
EventDispatcher::SetMouseFilter(BMessageFilter* filter)
|
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,
|
EventDispatcher::_SendMessage(BMessenger& messenger, BMessage* message,
|
||||||
float importance)
|
float importance)
|
||||||
{
|
{
|
||||||
@@ -176,6 +351,13 @@ EventDispatcher::_SendMessage(BMessenger& messenger, BMessage* message,
|
|||||||
status_t status = messenger.SendMessage(message, (BHandler*)NULL, 100000);
|
status_t status = messenger.SendMessage(message, (BHandler*)NULL, 100000);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
printf("failed to send message to target: %lx\n", message->what);
|
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
|
void
|
||||||
EventDispatcher::_EventLoop()
|
EventDispatcher::_EventLoop()
|
||||||
{
|
{
|
||||||
@@ -199,7 +420,12 @@ EventDispatcher::_EventLoop()
|
|||||||
}
|
}
|
||||||
|
|
||||||
BAutolock _(this);
|
BAutolock _(this);
|
||||||
|
|
||||||
bool sendToLastFocus = false;
|
bool sendToLastFocus = false;
|
||||||
|
bool pointerEvent = false;
|
||||||
|
bool keyboardEvent = false;
|
||||||
|
bool addedTransit = false;
|
||||||
|
bool addedTokens = false;
|
||||||
|
|
||||||
switch (event->what) {
|
switch (event->what) {
|
||||||
case B_MOUSE_MOVED:
|
case B_MOUSE_MOVED:
|
||||||
@@ -217,14 +443,19 @@ EventDispatcher::_EventLoop()
|
|||||||
// to the message
|
// to the message
|
||||||
if (fHasLastFocus) {
|
if (fHasLastFocus) {
|
||||||
_SetTransit(event, B_EXITED_VIEW);
|
_SetTransit(event, B_EXITED_VIEW);
|
||||||
|
addedTokens = _AddTokens(event, fLastFocusTokens);
|
||||||
_SendMessage(fLastFocus, event, kMouseTransitImportance);
|
_SendMessage(fLastFocus, event, kMouseTransitImportance);
|
||||||
sendToLastFocus = true;
|
sendToLastFocus = true;
|
||||||
|
|
||||||
// we no longer need the last focus messenger
|
// we no longer need the last focus messenger
|
||||||
fHasLastFocus = false;
|
fHasLastFocus = false;
|
||||||
|
fLastFocusTokens.MakeEmpty();
|
||||||
}
|
}
|
||||||
if (fHasFocus)
|
if (fHasFocus)
|
||||||
_SetTransit(event, B_ENTERED_VIEW);
|
_SetTransit(event, B_ENTERED_VIEW);
|
||||||
|
|
||||||
|
fTransit = false;
|
||||||
|
addedTransit = true;
|
||||||
}
|
}
|
||||||
// supposed to fall through
|
// supposed to fall through
|
||||||
case B_MOUSE_DOWN:
|
case B_MOUSE_DOWN:
|
||||||
@@ -233,7 +464,10 @@ EventDispatcher::_EventLoop()
|
|||||||
&& fMouseFilter->Filter(event, NULL) == B_SKIP_MESSAGE)
|
&& fMouseFilter->Filter(event, NULL) == B_SKIP_MESSAGE)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
pointerEvent = true;
|
||||||
|
|
||||||
if (fHasFocus) {
|
if (fHasFocus) {
|
||||||
|
addedTokens |= _AddTokens(event, fFocusTokens);
|
||||||
_SendMessage(fFocus, event, event->what == B_MOUSE_MOVED
|
_SendMessage(fFocus, event, event->what == B_MOUSE_MOVED
|
||||||
? kMouseMovedImportance : kStandardImportance);
|
? kMouseMovedImportance : kStandardImportance);
|
||||||
}
|
}
|
||||||
@@ -248,12 +482,54 @@ EventDispatcher::_EventLoop()
|
|||||||
&& fKeyFilter->Filter(event, NULL) == B_SKIP_MESSAGE)
|
&& fKeyFilter->Filter(event, NULL) == B_SKIP_MESSAGE)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
keyboardEvent = true;
|
||||||
|
|
||||||
|
// supposed to fall through
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (fHasFocus)
|
if (fHasFocus && !fSuspendFocus)
|
||||||
_SendMessage(fFocus, event, kStandardImportance);
|
_SendMessage(fFocus, event, kStandardImportance);
|
||||||
break;
|
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;
|
delete event;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <Locker.h>
|
#include <Locker.h>
|
||||||
#include <Messenger.h>
|
#include <Messenger.h>
|
||||||
|
#include <ObjectList.h>
|
||||||
|
|
||||||
class BMessageFilter;
|
class BMessageFilter;
|
||||||
|
|
||||||
@@ -28,6 +29,12 @@ class EventDispatcher : public BLocker {
|
|||||||
|
|
||||||
void SetFocus(BMessenger* messenger);
|
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 SetMouseFilter(BMessageFilter* filter);
|
||||||
void SetKeyFilter(BMessageFilter* filter);
|
void SetKeyFilter(BMessageFilter* filter);
|
||||||
|
|
||||||
@@ -37,11 +44,23 @@ class EventDispatcher : public BLocker {
|
|||||||
EventStream* Stream();
|
EventStream* Stream();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct event_target;
|
||||||
|
|
||||||
status_t _Run();
|
status_t _Run();
|
||||||
void _Unset();
|
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 _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 _EventLoop();
|
||||||
void _CursorLoop();
|
void _CursorLoop();
|
||||||
@@ -59,9 +78,15 @@ class EventDispatcher : public BLocker {
|
|||||||
bool fHasFocus;
|
bool fHasFocus;
|
||||||
bool fHasLastFocus;
|
bool fHasLastFocus;
|
||||||
bool fTransit;
|
bool fTransit;
|
||||||
|
BList fLastFocusTokens;
|
||||||
|
BList fFocusTokens;
|
||||||
|
bool fSuspendFocus;
|
||||||
|
|
||||||
BMessageFilter* fMouseFilter;
|
BMessageFilter* fMouseFilter;
|
||||||
BMessageFilter* fKeyFilter;
|
BMessageFilter* fKeyFilter;
|
||||||
|
|
||||||
|
BObjectList<event_target> fListeners;
|
||||||
|
|
||||||
BLocker fCursorLock;
|
BLocker fCursorLock;
|
||||||
HWInterface* fHWInterface;
|
HWInterface* fHWInterface;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user