#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;
}
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)
{
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;
}