* Copyright 2001-2014 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
* Erik Jaesler, erik@cgsoftware.com
*/
#include <TokenSpace.h>
#include <AppDefs.h>
#include <Handler.h>
#include <Looper.h>
#include <Message.h>
#include <MessageFilter.h>
#include <Messenger.h>
#include <PropertyInfo.h>
#include <algorithm>
#include <new>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <vector>
using std::map;
using std::vector;
using BPrivate::gDefaultTokens;
static const char* kArchiveNameField = "_name";
static const uint32 kMsgStartObserving = '_OBS';
static const uint32 kMsgStopObserving = '_OBP';
static const char* kObserveTarget = "be:observe_target";
static property_info sHandlerPropInfo[] = {
{
"Suites",
{ B_GET_PROPERTY },
{ B_DIRECT_SPECIFIER },
NULL,
0,
{ 0 },
{
{
{
{
"suites",
B_STRING_TYPE
}
}
},
{
{
{
"messages",
B_PROPERTY_INFO_TYPE
}
}
}
},
{}
},
{
"Messenger",
{ B_GET_PROPERTY },
{ B_DIRECT_SPECIFIER },
NULL, 0,
{ B_MESSENGER_TYPE },
{},
{}
},
{
"InternalName",
{ B_GET_PROPERTY },
{ B_DIRECT_SPECIFIER },
NULL, 0,
{ B_STRING_TYPE },
{},
{}
},
{ 0 }
};
bool FilterDeleter(void* filter);
namespace BPrivate {
class ObserverList {
public:
ObserverList();
~ObserverList();
status_t SendNotices(uint32 what, const BMessage* notice);
status_t Add(const BHandler* handler, uint32 what);
status_t Add(const BMessenger& messenger, uint32 what);
status_t Remove(const BHandler* handler, uint32 what);
status_t Remove(const BMessenger& messenger, uint32 what);
bool IsEmpty();
private:
typedef map<uint32, vector<const BHandler*> > HandlerObserverMap;
typedef map<uint32, vector<BMessenger> > MessengerObserverMap;
void _ValidateHandlers(uint32 what);
void _SendNotices(uint32 what, BMessage* notice);
HandlerObserverMap fHandlerMap;
MessengerObserverMap fMessengerMap;
};
}
using namespace BPrivate;
BHandler::BHandler(const char* name)
: BArchivable(),
fName(NULL)
{
_InitData(name);
}
BHandler::~BHandler()
{
if (LockLooper()) {
BLooper* looper = Looper();
looper->RemoveHandler(this);
looper->Unlock();
}
if (fFilters) {
int32 count = fFilters->CountItems();
for (int32 i = 0; i < count; i++)
delete (BMessageFilter*)fFilters->ItemAtFast(i);
delete fFilters;
}
delete fObserverList;
free(fName);
gDefaultTokens.RemoveToken(fToken);
}
BHandler::BHandler(BMessage* data)
: BArchivable(data),
fName(NULL)
{
const char* name = NULL;
if (data)
data->FindString(kArchiveNameField, &name);
_InitData(name);
}
BArchivable*
BHandler::Instantiate(BMessage* data)
{
if (!validate_instantiation(data, "BHandler"))
return NULL;
return new BHandler(data);
}
status_t
BHandler::Archive(BMessage* data, bool deep) const
{
status_t status = BArchivable::Archive(data, deep);
if (status < B_OK)
return status;
if (fName == NULL)
return B_OK;
return data->AddString(kArchiveNameField, fName);
}
void
BHandler::MessageReceived(BMessage* message)
{
BMessage reply(B_REPLY);
switch (message->what) {
case kMsgStartObserving:
case kMsgStopObserving:
{
BMessenger target;
uint32 what;
if (message->FindMessenger(kObserveTarget, &target) != B_OK
|| message->FindInt32(B_OBSERVE_WHAT_CHANGE, (int32*)&what)
!= B_OK) {
break;
}
ObserverList* list = _ObserverList();
if (list != NULL) {
if (message->what == kMsgStartObserving)
list->Add(target, what);
else
list->Remove(target, what);
}
break;
}
case B_GET_PROPERTY:
{
int32 cur;
BMessage specifier;
int32 form;
const char* prop;
status_t err = message->GetCurrentSpecifier(&cur, &specifier,
&form, &prop);
if (err != B_OK && err != B_BAD_SCRIPT_SYNTAX)
break;
bool known = false;
if (err == B_BAD_SCRIPT_SYNTAX || cur < 0
|| (strcmp(prop, "Messenger") == 0)) {
err = reply.AddMessenger("result", this);
known = true;
} else if (strcmp(prop, "Suites") == 0) {
err = GetSupportedSuites(&reply);
known = true;
} else if (strcmp(prop, "InternalName") == 0) {
err = reply.AddString("result", Name());
known = true;
}
if (known) {
reply.AddInt32("error", B_OK);
message->SendReply(&reply);
return;
}
break;
}
case B_GET_SUPPORTED_SUITES:
{
reply.AddInt32("error", GetSupportedSuites(&reply));
message->SendReply(&reply);
return;
}
}
if (fNextHandler) {
BHandler* target = Looper()->_HandlerFilter(message, fNextHandler);
if (target != NULL && target != this) {
target->MessageReceived(message);
}
} else if (message->what != B_MESSAGE_NOT_UNDERSTOOD
&& (message->WasDropped() || message->HasSpecifiers())) {
printf("BHandler %s: MessageReceived() couldn't understand the message:\n", Name());
message->PrintToStream();
message->SendReply(B_MESSAGE_NOT_UNDERSTOOD);
}
}
BLooper*
BHandler::Looper() const
{
return fLooper;
}
void
BHandler::SetName(const char* name)
{
if (fName != NULL) {
free(fName);
fName = NULL;
}
if (name != NULL)
fName = strdup(name);
}
const char*
BHandler::Name() const
{
return fName;
}
void
BHandler::SetNextHandler(BHandler* handler)
{
if (fLooper == NULL) {
debugger("handler must belong to looper before setting NextHandler");
return;
}
if (!fLooper->IsLocked()) {
debugger("The handler's looper must be locked before setting NextHandler");
return;
}
if (handler != NULL && fLooper != handler->Looper()) {
debugger("The handler and its NextHandler must have the same looper");
return;
}
fNextHandler = handler;
}
BHandler*
BHandler::NextHandler() const
{
return fNextHandler;
}
void
BHandler::AddFilter(BMessageFilter* filter)
{
BLooper* looper = fLooper;
if (looper != NULL && !looper->IsLocked()) {
debugger("Owning Looper must be locked before calling SetFilterList");
return;
}
if (looper != NULL)
filter->SetLooper(looper);
if (fFilters == NULL)
fFilters = new BList;
fFilters->AddItem(filter);
}
bool
BHandler::RemoveFilter(BMessageFilter* filter)
{
BLooper* looper = fLooper;
if (looper != NULL && !looper->IsLocked()) {
debugger("Owning Looper must be locked before calling SetFilterList");
return false;
}
if (fFilters != NULL && fFilters->RemoveItem((void*)filter)) {
filter->SetLooper(NULL);
return true;
}
return false;
}
void
BHandler::SetFilterList(BList* filters)
{
BLooper* looper = fLooper;
if (looper != NULL && !looper->IsLocked()) {
debugger("Owning Looper must be locked before calling SetFilterList");
return;
}
@note I would like to use BObjectList internally, but this function is
spec'd such that fFilters would get deleted and then assigned
'filters', which would obviously mess this up. Wondering if
anyone ever assigns a list of filters and then checks against
FilterList() to see if they are the same.
*/
if (fFilters != NULL) {
fFilters->DoForEach(FilterDeleter);
delete fFilters;
}
fFilters = filters;
if (fFilters) {
for (int32 i = 0; i < fFilters->CountItems(); ++i) {
BMessageFilter* filter =
static_cast<BMessageFilter*>(fFilters->ItemAt(i));
if (filter != NULL)
filter->SetLooper(looper);
}
}
}
BList*
BHandler::FilterList()
{
return fFilters;
}
bool
BHandler::LockLooper()
{
BLooper* looper = fLooper;
if (looper != NULL && looper->Lock()) {
if (fLooper == looper)
return true;
looper->Unlock();
}
return false;
}
status_t
BHandler::LockLooperWithTimeout(bigtime_t timeout)
{
BLooper* looper = fLooper;
if (looper == NULL)
return B_BAD_VALUE;
status_t status = looper->LockWithTimeout(timeout);
if (status != B_OK)
return status;
if (fLooper != looper) {
looper->Unlock();
return B_MISMATCHED_VALUES;
}
return B_OK;
}
void
BHandler::UnlockLooper()
{
fLooper->Unlock();
}
BHandler*
BHandler::ResolveSpecifier(BMessage* message, int32 index,
BMessage* specifier, int32 what, const char* property)
{
BPropertyInfo propertyInfo(sHandlerPropInfo);
if (propertyInfo.FindMatch(message, index, specifier, what, property) >= 0)
return this;
BMessage reply(B_MESSAGE_NOT_UNDERSTOOD);
reply.AddInt32("error", B_BAD_SCRIPT_SYNTAX);
reply.AddString("message", "Didn't understand the specifier(s)");
message->SendReply(&reply);
return NULL;
}
status_t
BHandler::GetSupportedSuites(BMessage* data)
{
@note This is the output from the original implementation (calling
PrintToStream() on both data and the contained BPropertyInfo):
BMessage: what = (0x0, or 0)
entry suites, type='CSTR', c=1, size=21, data[0]: "suite/vnd.Be-handler"
entry messages, type='SCTD', c=1, size= 0,
property commands types specifiers
--------------------------------------------------------------------------------
Suites PGET 1
(RTSC,suites)
(DTCS,messages)
Messenger PGET GNSM 1
InternalName PGET RTSC 1
With a good deal of trial and error, I determined that the
parenthetical clauses are entries in the 'ctypes' field of
property_info. 'ctypes' is an array of 'compound_type', which
contains an array of 'field_pair's. I haven't the foggiest what
either 'compound_type' or 'field_pair' is for, being as the
scripting docs are so bloody horrible. The corresponding
property_info array is declared in the globals section.
*/
if (data == NULL)
return B_BAD_VALUE;
status_t result = data->AddString("suites", "suite/vnd.Be-handler");
if (result == B_OK) {
BPropertyInfo propertyInfo(sHandlerPropInfo);
result = data->AddFlat("messages", &propertyInfo);
}
return result;
}
status_t
BHandler::StartWatching(BMessenger target, uint32 what)
{
BMessage message(kMsgStartObserving);
message.AddMessenger(kObserveTarget, this);
message.AddInt32(B_OBSERVE_WHAT_CHANGE, what);
return target.SendMessage(&message);
}
status_t
BHandler::StartWatchingAll(BMessenger target)
{
return StartWatching(target, B_OBSERVER_OBSERVE_ALL);
}
status_t
BHandler::StopWatching(BMessenger target, uint32 what)
{
BMessage message(kMsgStopObserving);
message.AddMessenger(kObserveTarget, this);
message.AddInt32(B_OBSERVE_WHAT_CHANGE, what);
return target.SendMessage(&message);
}
status_t
BHandler::StopWatchingAll(BMessenger target)
{
return StopWatching(target, B_OBSERVER_OBSERVE_ALL);
}
status_t
BHandler::StartWatching(BHandler* handler, uint32 what)
{
ObserverList* list = _ObserverList();
if (list == NULL)
return B_NO_MEMORY;
return list->Add(handler, what);
}
status_t
BHandler::StartWatchingAll(BHandler* handler)
{
return StartWatching(handler, B_OBSERVER_OBSERVE_ALL);
}
status_t
BHandler::StopWatching(BHandler* handler, uint32 what)
{
ObserverList* list = _ObserverList();
if (list == NULL)
return B_NO_MEMORY;
return list->Remove(handler, what);
}
status_t
BHandler::StopWatchingAll(BHandler* handler)
{
return StopWatching(handler, B_OBSERVER_OBSERVE_ALL);
}
status_t
BHandler::Perform(perform_code d, void* arg)
{
return BArchivable::Perform(d, arg);
}
void
BHandler::SendNotices(uint32 what, const BMessage* notice)
{
if (fObserverList != NULL)
fObserverList->SendNotices(what, notice);
}
bool
BHandler::IsWatched() const
{
return fObserverList && !fObserverList->IsEmpty();
}
void
BHandler::_InitData(const char* name)
{
SetName(name);
fLooper = NULL;
fNextHandler = NULL;
fFilters = NULL;
fObserverList = NULL;
fToken = gDefaultTokens.NewToken(B_HANDLER_TOKEN, this);
}
ObserverList*
BHandler::_ObserverList()
{
if (fObserverList == NULL)
fObserverList = new (std::nothrow) BPrivate::ObserverList();
return fObserverList;
}
void
BHandler::SetLooper(BLooper* looper)
{
fLooper = looper;
gDefaultTokens.SetHandlerTarget(fToken,
looper ? looper->fDirectTarget : NULL);
if (fFilters != NULL) {
for (int32 i = 0; i < fFilters->CountItems(); i++) {
static_cast<BMessageFilter*>(
fFilters->ItemAtFast(i))->SetLooper(looper);
}
}
}
#if __GNUC__ < 3
extern "C" void
_ReservedHandler1__8BHandler(BHandler* handler, uint32 what,
const BMessage* notice)
{
handler->BHandler::SendNotices(what, notice);
}
BHandler::BHandler(const BHandler &)
{
}
BHandler &
BHandler::operator=(const BHandler &)
{
return *this;
}
#endif
void BHandler::_ReservedHandler2() {}
void BHandler::_ReservedHandler3() {}
void BHandler::_ReservedHandler4() {}
ObserverList::ObserverList()
{
}
ObserverList::~ObserverList()
{
}
void
ObserverList::_ValidateHandlers(uint32 what)
{
vector<const BHandler*>& handlers = fHandlerMap[what];
vector<const BHandler*>::iterator iterator = handlers.begin();
while (iterator != handlers.end()) {
BMessenger target(*iterator);
if (!target.IsValid()) {
iterator++;
continue;
}
Add(target, what);
iterator = handlers.erase(iterator);
}
if (handlers.empty())
fHandlerMap.erase(what);
}
void
ObserverList::_SendNotices(uint32 what, BMessage* notice)
{
_ValidateHandlers(what);
vector<BMessenger>& messengers = fMessengerMap[what];
vector<BMessenger>::iterator iterator = messengers.begin();
while (iterator != messengers.end()) {
if (!(*iterator).IsValid()) {
iterator = messengers.erase(iterator);
continue;
}
(*iterator).SendMessage(notice);
iterator++;
}
if (messengers.empty())
fMessengerMap.erase(what);
}
status_t
ObserverList::SendNotices(uint32 what, const BMessage* notice)
{
BMessage* copy = NULL;
if (notice != NULL) {
copy = new BMessage(*notice);
copy->what = B_OBSERVER_NOTICE_CHANGE;
copy->AddInt32(B_OBSERVE_ORIGINAL_WHAT, notice->what);
} else
copy = new BMessage(B_OBSERVER_NOTICE_CHANGE);
copy->AddInt32(B_OBSERVE_WHAT_CHANGE, what);
_SendNotices(what, copy);
_SendNotices(B_OBSERVER_OBSERVE_ALL, copy);
delete copy;
return B_OK;
}
status_t
ObserverList::Add(const BHandler* handler, uint32 what)
{
if (handler == NULL)
return B_BAD_HANDLER;
BMessenger target(handler);
if (target.IsValid())
return Add(target, what);
vector<const BHandler*> &handlers = fHandlerMap[what];
vector<const BHandler*>::iterator iter;
iter = find(handlers.begin(), handlers.end(), handler);
if (iter != handlers.end()) {
return B_OK;
}
handlers.push_back(handler);
return B_OK;
}
status_t
ObserverList::Add(const BMessenger &messenger, uint32 what)
{
vector<BMessenger> &messengers = fMessengerMap[what];
vector<BMessenger>::iterator iter;
iter = find(messengers.begin(), messengers.end(), messenger);
if (iter != messengers.end()) {
return B_OK;
}
messengers.push_back(messenger);
return B_OK;
}
status_t
ObserverList::Remove(const BHandler* handler, uint32 what)
{
if (handler == NULL)
return B_BAD_HANDLER;
BMessenger target(handler);
if (target.IsValid() && Remove(target, what) == B_OK)
return B_OK;
status_t status = B_BAD_HANDLER;
vector<const BHandler*> &handlers = fHandlerMap[what];
vector<const BHandler*>::iterator iterator = find(handlers.begin(),
handlers.end(), handler);
if (iterator != handlers.end()) {
handlers.erase(iterator);
status = B_OK;
}
if (handlers.empty())
fHandlerMap.erase(what);
return status;
}
status_t
ObserverList::Remove(const BMessenger &messenger, uint32 what)
{
status_t status = B_BAD_HANDLER;
vector<BMessenger> &messengers = fMessengerMap[what];
vector<BMessenger>::iterator iterator = find(messengers.begin(),
messengers.end(), messenger);
if (iterator != messengers.end()) {
messengers.erase(iterator);
status = B_OK;
}
if (messengers.empty())
fMessengerMap.erase(what);
return status;
}
bool
ObserverList::IsEmpty()
{
return fHandlerMap.empty() && fMessengerMap.empty();
}
bool
FilterDeleter(void* _filter)
{
delete static_cast<BMessageFilter*>(_filter);
return false;
}