2005-11-17 17:58:19 +03:00
|
|
|
/*
|
|
|
|
* Copyright 2005, Haiku, Inc. All Rights Reserved.
|
|
|
|
* Distributed under the terms of the MIT License.
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Axel Dörfler, axeld@pinc-software.de
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "EventDispatcher.h"
|
|
|
|
#include "EventStream.h"
|
|
|
|
#include "HWInterface.h"
|
|
|
|
|
|
|
|
#include <Autolock.h>
|
|
|
|
#include <MessageFilter.h>
|
|
|
|
#include <View.h>
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
|
|
static const float kMouseMovedImportance = 0.1f;
|
|
|
|
static const float kMouseTransitImportance = 1.0f;
|
|
|
|
static const float kStandardImportance = 0.9f;
|
|
|
|
|
|
|
|
|
|
|
|
EventDispatcher::EventDispatcher()
|
|
|
|
: BLocker("event dispatcher"),
|
|
|
|
fStream(NULL),
|
|
|
|
fThread(-1),
|
|
|
|
fCursorThread(-1),
|
2005-11-17 19:08:04 +03:00
|
|
|
fHasFocus(false),
|
|
|
|
fHasLastFocus(false),
|
2005-11-17 17:58:19 +03:00
|
|
|
fTransit(false),
|
|
|
|
fMouseFilter(NULL),
|
|
|
|
fKeyFilter(NULL),
|
|
|
|
fCursorLock("cursor loop lock"),
|
|
|
|
fHWInterface(NULL)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EventDispatcher::~EventDispatcher()
|
|
|
|
{
|
|
|
|
_Unset();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
EventDispatcher::SetTo(EventStream& stream)
|
|
|
|
{
|
|
|
|
_Unset();
|
|
|
|
|
|
|
|
fStream = &stream;
|
|
|
|
return _Run();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
EventDispatcher::InitCheck()
|
|
|
|
{
|
|
|
|
if (fStream != NULL) {
|
|
|
|
if (fThread < B_OK)
|
|
|
|
return fThread;
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
return B_NO_INIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
EventDispatcher::_Unset()
|
|
|
|
{
|
|
|
|
fStream->SendQuit();
|
|
|
|
|
|
|
|
wait_for_thread(fThread, NULL);
|
|
|
|
wait_for_thread(fCursorThread, NULL);
|
|
|
|
|
|
|
|
fThread = fCursorThread = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
EventDispatcher::_Run()
|
|
|
|
{
|
|
|
|
fThread = spawn_thread(_event_looper, "event loop",
|
|
|
|
B_REAL_TIME_DISPLAY_PRIORITY - 10, this);
|
|
|
|
if (fThread < B_OK)
|
|
|
|
return fThread;
|
|
|
|
|
|
|
|
if (fStream->SupportsCursorThread()) {
|
|
|
|
fCursorThread = spawn_thread(_cursor_looper, "cursor loop",
|
|
|
|
B_REAL_TIME_DISPLAY_PRIORITY - 5, this);
|
|
|
|
if (resume_thread(fCursorThread) != B_OK) {
|
|
|
|
kill_thread(fCursorThread);
|
|
|
|
fCursorThread = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return resume_thread(fThread);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
EventDispatcher::SetFocus(BMessenger* messenger)
|
|
|
|
{
|
|
|
|
BAutolock _(this);
|
|
|
|
|
2005-11-17 19:08:04 +03:00
|
|
|
if (fFocus == *messenger)
|
2005-11-17 17:58:19 +03:00
|
|
|
return;
|
|
|
|
|
2005-11-17 19:08:04 +03:00
|
|
|
fHasLastFocus = fHasFocus;
|
|
|
|
if (fHasFocus)
|
|
|
|
fLastFocus = fFocus;
|
|
|
|
|
|
|
|
fHasFocus = messenger != NULL;
|
|
|
|
if (fHasFocus)
|
|
|
|
fFocus = *messenger;
|
|
|
|
|
2005-11-17 17:58:19 +03:00
|
|
|
fTransit = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
EventDispatcher::SetMouseFilter(BMessageFilter* filter)
|
|
|
|
{
|
|
|
|
BAutolock _(this);
|
|
|
|
|
|
|
|
if (fMouseFilter == filter)
|
|
|
|
return;
|
|
|
|
|
|
|
|
delete fMouseFilter;
|
|
|
|
fMouseFilter = filter;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
EventDispatcher::SetKeyFilter(BMessageFilter* filter)
|
|
|
|
{
|
|
|
|
BAutolock _(this);
|
|
|
|
|
|
|
|
if (fKeyFilter == filter)
|
|
|
|
return;
|
|
|
|
|
|
|
|
delete fKeyFilter;
|
|
|
|
fKeyFilter = filter;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
EventDispatcher::HasCursorThread()
|
|
|
|
{
|
|
|
|
return fCursorThread >= B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
\brief Sets the HWInterface to use when moving the mouse cursor.
|
|
|
|
\a interface is allowed to be NULL.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
EventDispatcher::SetHWInterface(HWInterface* interface)
|
|
|
|
{
|
|
|
|
BAutolock _(fCursorLock);
|
|
|
|
|
|
|
|
fHWInterface = interface;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2005-11-17 19:08:04 +03:00
|
|
|
EventDispatcher::_SendMessage(BMessenger& messenger, BMessage* message,
|
2005-11-17 17:58:19 +03:00
|
|
|
float importance)
|
|
|
|
{
|
|
|
|
// TODO: add failed messages to a queue, and start dropping them by importance
|
|
|
|
|
2005-11-17 19:08:04 +03:00
|
|
|
status_t status = messenger.SendMessage(message, (BHandler*)NULL, 100000);
|
2005-11-17 17:58:19 +03:00
|
|
|
if (status != B_OK)
|
|
|
|
printf("failed to send message to target: %lx\n", message->what);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
EventDispatcher::_SetTransit(BMessage* message, int32 transit)
|
|
|
|
{
|
|
|
|
if (message->ReplaceInt32("be:transit", transit) != B_OK)
|
|
|
|
message->AddInt32("be:transit", transit);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
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);
|
2005-11-17 19:08:04 +03:00
|
|
|
bool sendToLastFocus = false;
|
2005-11-17 17:58:19 +03:00
|
|
|
|
|
|
|
switch (event->what) {
|
|
|
|
case B_MOUSE_MOVED:
|
|
|
|
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
|
2005-11-17 19:08:04 +03:00
|
|
|
if (fHasLastFocus) {
|
2005-11-17 17:58:19 +03:00
|
|
|
_SetTransit(event, B_EXITED_VIEW);
|
|
|
|
_SendMessage(fLastFocus, event, kMouseTransitImportance);
|
2005-11-17 19:08:04 +03:00
|
|
|
sendToLastFocus = true;
|
2005-11-17 17:58:19 +03:00
|
|
|
|
|
|
|
// we no longer need the last focus messenger
|
2005-11-17 19:08:04 +03:00
|
|
|
fHasLastFocus = false;
|
2005-11-17 17:58:19 +03:00
|
|
|
}
|
2005-11-17 19:08:04 +03:00
|
|
|
if (fHasFocus)
|
2005-11-17 17:58:19 +03:00
|
|
|
_SetTransit(event, B_ENTERED_VIEW);
|
|
|
|
}
|
|
|
|
// supposed to fall through
|
|
|
|
case B_MOUSE_DOWN:
|
|
|
|
case B_MOUSE_UP:
|
|
|
|
if (fMouseFilter != NULL
|
|
|
|
&& fMouseFilter->Filter(event, NULL) == B_SKIP_MESSAGE)
|
|
|
|
break;
|
|
|
|
|
2005-11-17 19:08:04 +03:00
|
|
|
if (fHasFocus) {
|
|
|
|
_SendMessage(fFocus, event, event->what == B_MOUSE_MOVED
|
|
|
|
? kMouseMovedImportance : kStandardImportance);
|
|
|
|
}
|
2005-11-17 17:58:19 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case B_KEY_DOWN:
|
|
|
|
case B_KEY_UP:
|
|
|
|
case B_UNMAPPED_KEY_DOWN:
|
|
|
|
case B_UNMAPPED_KEY_UP:
|
|
|
|
case B_MODIFIERS_CHANGED:
|
|
|
|
if (fKeyFilter != NULL
|
|
|
|
&& fKeyFilter->Filter(event, NULL) == B_SKIP_MESSAGE)
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2005-11-17 19:08:04 +03:00
|
|
|
if (fHasFocus)
|
|
|
|
_SendMessage(fFocus, event, kStandardImportance);
|
2005-11-17 17:58:19 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete event;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
EventDispatcher::_CursorLoop()
|
|
|
|
{
|
|
|
|
BPoint where;
|
|
|
|
while (fStream->GetNextCursorPosition(where)) {
|
|
|
|
BAutolock _(fCursorLock);
|
|
|
|
|
|
|
|
if (fHWInterface != NULL)
|
|
|
|
fHWInterface->MoveCursorTo(where.x, where.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
fCursorThread = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*static*/
|
|
|
|
status_t
|
|
|
|
EventDispatcher::_event_looper(void* _dispatcher)
|
|
|
|
{
|
|
|
|
EventDispatcher* dispatcher = (EventDispatcher*)_dispatcher;
|
|
|
|
|
|
|
|
dispatcher->_EventLoop();
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*static*/
|
|
|
|
status_t
|
|
|
|
EventDispatcher::_cursor_looper(void* _dispatcher)
|
|
|
|
{
|
|
|
|
EventDispatcher* dispatcher = (EventDispatcher*)_dispatcher;
|
|
|
|
|
|
|
|
dispatcher->_CursorLoop();
|
|
|
|
return B_OK;
|
|
|
|
}
|