BPicture: Fix archive constructor.
[haiku.git] / src / kits / app / Handler.cpp
blobb158f0ee8af3d3bf08528e3dd67e49caa9d76eb9
1 /*
2 * Copyright 2001-2014 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Axel Dörfler, axeld@pinc-software.de
7 * Erik Jaesler, erik@cgsoftware.com
8 */
11 #include <TokenSpace.h>
13 #include <AppDefs.h>
14 #include <Handler.h>
15 #include <Looper.h>
16 #include <Message.h>
17 #include <MessageFilter.h>
18 #include <Messenger.h>
19 #include <PropertyInfo.h>
21 #include <algorithm>
22 #include <new>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <vector>
28 using std::map;
29 using std::vector;
30 using BPrivate::gDefaultTokens;
33 static const char* kArchiveNameField = "_name";
35 static const uint32 kMsgStartObserving = '_OBS';
36 static const uint32 kMsgStopObserving = '_OBP';
37 static const char* kObserveTarget = "be:observe_target";
40 static property_info sHandlerPropInfo[] = {
42 "Suites", // name
43 { B_GET_PROPERTY }, // commands
44 { B_DIRECT_SPECIFIER }, // specifiers
45 NULL, // usage
46 0, // extra data
47 { 0 }, // types
48 { // ctypes (compound_type)
49 { // ctypes[0]
50 { // pairs[0]
52 "suites", // name
53 B_STRING_TYPE // type
57 { // ctypes[1]
58 { // pairs[0]
60 "messages",
61 B_PROPERTY_INFO_TYPE
66 {} // reserved
69 "Messenger",
70 { B_GET_PROPERTY },
71 { B_DIRECT_SPECIFIER },
72 NULL, 0,
73 { B_MESSENGER_TYPE },
74 {},
78 "InternalName",
79 { B_GET_PROPERTY },
80 { B_DIRECT_SPECIFIER },
81 NULL, 0,
82 { B_STRING_TYPE },
83 {},
89 bool FilterDeleter(void* filter);
91 namespace BPrivate {
93 class ObserverList {
94 public:
95 ObserverList();
96 ~ObserverList();
98 status_t SendNotices(uint32 what, const BMessage* notice);
99 status_t Add(const BHandler* handler, uint32 what);
100 status_t Add(const BMessenger& messenger, uint32 what);
101 status_t Remove(const BHandler* handler, uint32 what);
102 status_t Remove(const BMessenger& messenger, uint32 what);
103 bool IsEmpty();
105 private:
106 typedef map<uint32, vector<const BHandler*> > HandlerObserverMap;
107 typedef map<uint32, vector<BMessenger> > MessengerObserverMap;
109 void _ValidateHandlers(uint32 what);
110 void _SendNotices(uint32 what, BMessage* notice);
112 HandlerObserverMap fHandlerMap;
113 MessengerObserverMap fMessengerMap;
116 } // namespace BPrivate
118 using namespace BPrivate;
121 // #pragma mark -
124 BHandler::BHandler(const char* name)
125 : BArchivable(),
126 fName(NULL)
128 _InitData(name);
132 BHandler::~BHandler()
134 if (LockLooper()) {
135 BLooper* looper = Looper();
136 looper->RemoveHandler(this);
137 looper->Unlock();
140 // remove all filters
141 if (fFilters) {
142 int32 count = fFilters->CountItems();
143 for (int32 i = 0; i < count; i++)
144 delete (BMessageFilter*)fFilters->ItemAtFast(i);
145 delete fFilters;
148 // remove all observers (the observer list manages itself)
149 delete fObserverList;
151 // free rest
152 free(fName);
153 gDefaultTokens.RemoveToken(fToken);
157 BHandler::BHandler(BMessage* data)
158 : BArchivable(data),
159 fName(NULL)
161 const char* name = NULL;
163 if (data)
164 data->FindString(kArchiveNameField, &name);
166 _InitData(name);
170 BArchivable*
171 BHandler::Instantiate(BMessage* data)
173 if (!validate_instantiation(data, "BHandler"))
174 return NULL;
176 return new BHandler(data);
180 status_t
181 BHandler::Archive(BMessage* data, bool deep) const
183 status_t status = BArchivable::Archive(data, deep);
184 if (status < B_OK)
185 return status;
187 if (fName == NULL)
188 return B_OK;
190 return data->AddString(kArchiveNameField, fName);
194 void
195 BHandler::MessageReceived(BMessage* message)
197 BMessage reply(B_REPLY);
199 switch (message->what) {
200 case kMsgStartObserving:
201 case kMsgStopObserving:
203 BMessenger target;
204 uint32 what;
205 if (message->FindMessenger(kObserveTarget, &target) != B_OK
206 || message->FindInt32(B_OBSERVE_WHAT_CHANGE, (int32*)&what)
207 != B_OK) {
208 break;
211 ObserverList* list = _ObserverList();
212 if (list != NULL) {
213 if (message->what == kMsgStartObserving)
214 list->Add(target, what);
215 else
216 list->Remove(target, what);
218 break;
221 case B_GET_PROPERTY:
223 int32 cur;
224 BMessage specifier;
225 int32 form;
226 const char* prop;
228 status_t err = message->GetCurrentSpecifier(&cur, &specifier,
229 &form, &prop);
230 if (err != B_OK && err != B_BAD_SCRIPT_SYNTAX)
231 break;
232 bool known = false;
233 // B_BAD_SCRIPT_SYNTAX defaults to the Messenger property
234 if (err == B_BAD_SCRIPT_SYNTAX || cur < 0
235 || (strcmp(prop, "Messenger") == 0)) {
236 err = reply.AddMessenger("result", this);
237 known = true;
238 } else if (strcmp(prop, "Suites") == 0) {
239 err = GetSupportedSuites(&reply);
240 known = true;
241 } else if (strcmp(prop, "InternalName") == 0) {
242 err = reply.AddString("result", Name());
243 known = true;
246 if (known) {
247 reply.AddInt32("error", B_OK);
248 message->SendReply(&reply);
249 return;
251 // let's try next handler
252 break;
255 case B_GET_SUPPORTED_SUITES:
257 reply.AddInt32("error", GetSupportedSuites(&reply));
258 message->SendReply(&reply);
259 return;
263 // ToDo: there is some more work needed here
264 // (someone in the know should fill in)!
266 if (fNextHandler) {
267 // we need to apply the next handler's filters here, too
268 BHandler* target = Looper()->_HandlerFilter(message, fNextHandler);
269 if (target != NULL && target != this) {
270 // TODO: we also need to make sure that "target" is not before
271 // us in the handler chain - at least in case it wasn't before
272 // the handler actually targeted with this message - this could
273 // get ugly, though.
274 target->MessageReceived(message);
276 } else if (message->what != B_MESSAGE_NOT_UNDERSTOOD
277 && (message->WasDropped() || message->HasSpecifiers())) {
278 printf("BHandler %s: MessageReceived() couldn't understand the message:\n", Name());
279 message->PrintToStream();
280 message->SendReply(B_MESSAGE_NOT_UNDERSTOOD);
285 BLooper*
286 BHandler::Looper() const
288 return fLooper;
292 void
293 BHandler::SetName(const char* name)
295 if (fName != NULL) {
296 free(fName);
297 fName = NULL;
300 if (name != NULL)
301 fName = strdup(name);
305 const char*
306 BHandler::Name() const
308 return fName;
312 void
313 BHandler::SetNextHandler(BHandler* handler)
315 if (fLooper == NULL) {
316 debugger("handler must belong to looper before setting NextHandler");
317 return;
320 if (!fLooper->IsLocked()) {
321 debugger("The handler's looper must be locked before setting NextHandler");
322 return;
325 if (handler != NULL && fLooper != handler->Looper()) {
326 debugger("The handler and its NextHandler must have the same looper");
327 return;
330 fNextHandler = handler;
334 BHandler*
335 BHandler::NextHandler() const
337 return fNextHandler;
341 void
342 BHandler::AddFilter(BMessageFilter* filter)
344 BLooper* looper = fLooper;
345 if (looper != NULL && !looper->IsLocked()) {
346 debugger("Owning Looper must be locked before calling SetFilterList");
347 return;
350 if (looper != NULL)
351 filter->SetLooper(looper);
353 if (fFilters == NULL)
354 fFilters = new BList;
356 fFilters->AddItem(filter);
360 bool
361 BHandler::RemoveFilter(BMessageFilter* filter)
363 BLooper* looper = fLooper;
364 if (looper != NULL && !looper->IsLocked()) {
365 debugger("Owning Looper must be locked before calling SetFilterList");
366 return false;
369 if (fFilters != NULL && fFilters->RemoveItem((void*)filter)) {
370 filter->SetLooper(NULL);
371 return true;
374 return false;
378 void
379 BHandler::SetFilterList(BList* filters)
381 BLooper* looper = fLooper;
382 if (looper != NULL && !looper->IsLocked()) {
383 debugger("Owning Looper must be locked before calling SetFilterList");
384 return;
388 @note I would like to use BObjectList internally, but this function is
389 spec'd such that fFilters would get deleted and then assigned
390 'filters', which would obviously mess this up. Wondering if
391 anyone ever assigns a list of filters and then checks against
392 FilterList() to see if they are the same.
395 // TODO: Explore issues with using BObjectList
396 if (fFilters != NULL) {
397 fFilters->DoForEach(FilterDeleter);
398 delete fFilters;
401 fFilters = filters;
402 if (fFilters) {
403 for (int32 i = 0; i < fFilters->CountItems(); ++i) {
404 BMessageFilter* filter =
405 static_cast<BMessageFilter*>(fFilters->ItemAt(i));
406 if (filter != NULL)
407 filter->SetLooper(looper);
413 BList*
414 BHandler::FilterList()
416 return fFilters;
420 bool
421 BHandler::LockLooper()
423 BLooper* looper = fLooper;
424 // Locking the looper also makes sure that the looper is valid
425 if (looper != NULL && looper->Lock()) {
426 // Have we locked the right looper? That's as far as the
427 // "pseudo-atomic" operation mentioned in the BeBook.
428 if (fLooper == looper)
429 return true;
431 // we locked the wrong looper, bail out
432 looper->Unlock();
435 return false;
439 status_t
440 BHandler::LockLooperWithTimeout(bigtime_t timeout)
442 BLooper* looper = fLooper;
443 if (looper == NULL)
444 return B_BAD_VALUE;
446 status_t status = looper->LockWithTimeout(timeout);
447 if (status != B_OK)
448 return status;
450 if (fLooper != looper) {
451 // we locked the wrong looper, bail out
452 looper->Unlock();
453 return B_MISMATCHED_VALUES;
456 return B_OK;
460 void
461 BHandler::UnlockLooper()
463 fLooper->Unlock();
467 BHandler*
468 BHandler::ResolveSpecifier(BMessage* message, int32 index,
469 BMessage* specifier, int32 what, const char* property)
471 // Straight from the BeBook
472 BPropertyInfo propertyInfo(sHandlerPropInfo);
473 if (propertyInfo.FindMatch(message, index, specifier, what, property) >= 0)
474 return this;
476 BMessage reply(B_MESSAGE_NOT_UNDERSTOOD);
477 reply.AddInt32("error", B_BAD_SCRIPT_SYNTAX);
478 reply.AddString("message", "Didn't understand the specifier(s)");
479 message->SendReply(&reply);
481 return NULL;
485 status_t
486 BHandler::GetSupportedSuites(BMessage* data)
489 @note This is the output from the original implementation (calling
490 PrintToStream() on both data and the contained BPropertyInfo):
492 BMessage: what = (0x0, or 0)
493 entry suites, type='CSTR', c=1, size=21, data[0]: "suite/vnd.Be-handler"
494 entry messages, type='SCTD', c=1, size= 0,
495 property commands types specifiers
496 --------------------------------------------------------------------------------
497 Suites PGET 1
498 (RTSC,suites)
499 (DTCS,messages)
501 Messenger PGET GNSM 1
502 InternalName PGET RTSC 1
504 With a good deal of trial and error, I determined that the
505 parenthetical clauses are entries in the 'ctypes' field of
506 property_info. 'ctypes' is an array of 'compound_type', which
507 contains an array of 'field_pair's. I haven't the foggiest what
508 either 'compound_type' or 'field_pair' is for, being as the
509 scripting docs are so bloody horrible. The corresponding
510 property_info array is declared in the globals section.
513 if (data == NULL)
514 return B_BAD_VALUE;
516 status_t result = data->AddString("suites", "suite/vnd.Be-handler");
517 if (result == B_OK) {
518 BPropertyInfo propertyInfo(sHandlerPropInfo);
519 result = data->AddFlat("messages", &propertyInfo);
522 return result;
526 status_t
527 BHandler::StartWatching(BMessenger target, uint32 what)
529 BMessage message(kMsgStartObserving);
530 message.AddMessenger(kObserveTarget, this);
531 message.AddInt32(B_OBSERVE_WHAT_CHANGE, what);
533 return target.SendMessage(&message);
537 status_t
538 BHandler::StartWatchingAll(BMessenger target)
540 return StartWatching(target, B_OBSERVER_OBSERVE_ALL);
544 status_t
545 BHandler::StopWatching(BMessenger target, uint32 what)
547 BMessage message(kMsgStopObserving);
548 message.AddMessenger(kObserveTarget, this);
549 message.AddInt32(B_OBSERVE_WHAT_CHANGE, what);
551 return target.SendMessage(&message);
555 status_t
556 BHandler::StopWatchingAll(BMessenger target)
558 return StopWatching(target, B_OBSERVER_OBSERVE_ALL);
562 status_t
563 BHandler::StartWatching(BHandler* handler, uint32 what)
565 ObserverList* list = _ObserverList();
566 if (list == NULL)
567 return B_NO_MEMORY;
569 return list->Add(handler, what);
573 status_t
574 BHandler::StartWatchingAll(BHandler* handler)
576 return StartWatching(handler, B_OBSERVER_OBSERVE_ALL);
580 status_t
581 BHandler::StopWatching(BHandler* handler, uint32 what)
583 ObserverList* list = _ObserverList();
584 if (list == NULL)
585 return B_NO_MEMORY;
587 return list->Remove(handler, what);
591 status_t
592 BHandler::StopWatchingAll(BHandler* handler)
594 return StopWatching(handler, B_OBSERVER_OBSERVE_ALL);
598 status_t
599 BHandler::Perform(perform_code d, void* arg)
601 return BArchivable::Perform(d, arg);
605 void
606 BHandler::SendNotices(uint32 what, const BMessage* notice)
608 if (fObserverList != NULL)
609 fObserverList->SendNotices(what, notice);
613 bool
614 BHandler::IsWatched() const
616 return fObserverList && !fObserverList->IsEmpty();
620 void
621 BHandler::_InitData(const char* name)
623 SetName(name);
625 fLooper = NULL;
626 fNextHandler = NULL;
627 fFilters = NULL;
628 fObserverList = NULL;
630 fToken = gDefaultTokens.NewToken(B_HANDLER_TOKEN, this);
634 ObserverList*
635 BHandler::_ObserverList()
637 if (fObserverList == NULL)
638 fObserverList = new (std::nothrow) BPrivate::ObserverList();
640 return fObserverList;
644 BHandler::BHandler(const BHandler &)
646 // No copy construction allowed.
650 BHandler &
651 BHandler::operator=(const BHandler &)
653 // No assignments allowed.
654 return *this;
658 void
659 BHandler::SetLooper(BLooper* looper)
661 fLooper = looper;
662 gDefaultTokens.SetHandlerTarget(fToken,
663 looper ? looper->fDirectTarget : NULL);
665 if (fFilters != NULL) {
666 for (int32 i = 0; i < fFilters->CountItems(); i++) {
667 static_cast<BMessageFilter*>(
668 fFilters->ItemAtFast(i))->SetLooper(looper);
674 #if __GNUC__ < 3
675 // binary compatibility with R4.5
677 extern "C" void
678 _ReservedHandler1__8BHandler(BHandler* handler, uint32 what,
679 const BMessage* notice)
681 handler->BHandler::SendNotices(what, notice);
684 #endif
686 void BHandler::_ReservedHandler2() {}
687 void BHandler::_ReservedHandler3() {}
688 void BHandler::_ReservedHandler4() {}
691 // #pragma mark -
694 ObserverList::ObserverList()
699 ObserverList::~ObserverList()
704 void
705 ObserverList::_ValidateHandlers(uint32 what)
707 vector<const BHandler*>& handlers = fHandlerMap[what];
708 vector<const BHandler*>::iterator iterator = handlers.begin();
710 while (iterator != handlers.end()) {
711 BMessenger target(*iterator);
712 if (!target.IsValid()) {
713 iterator++;
714 continue;
717 Add(target, what);
718 iterator = handlers.erase(iterator);
723 void
724 ObserverList::_SendNotices(uint32 what, BMessage* notice)
726 // first iterate over the list of handlers and try to make valid
727 // messengers out of them
728 _ValidateHandlers(what);
730 // now send it to all messengers we know
731 vector<BMessenger>& messengers = fMessengerMap[what];
732 vector<BMessenger>::iterator iterator = messengers.begin();
734 while (iterator != messengers.end()) {
735 if (!(*iterator).IsValid()) {
736 iterator = messengers.erase(iterator);
737 continue;
740 (*iterator).SendMessage(notice);
741 iterator++;
746 status_t
747 ObserverList::SendNotices(uint32 what, const BMessage* notice)
749 BMessage* copy = NULL;
750 if (notice != NULL) {
751 copy = new BMessage(*notice);
752 copy->what = B_OBSERVER_NOTICE_CHANGE;
753 copy->AddInt32(B_OBSERVE_ORIGINAL_WHAT, notice->what);
754 } else
755 copy = new BMessage(B_OBSERVER_NOTICE_CHANGE);
757 copy->AddInt32(B_OBSERVE_WHAT_CHANGE, what);
759 _SendNotices(what, copy);
760 _SendNotices(B_OBSERVER_OBSERVE_ALL, copy);
762 delete copy;
764 return B_OK;
768 status_t
769 ObserverList::Add(const BHandler* handler, uint32 what)
771 if (handler == NULL)
772 return B_BAD_HANDLER;
774 // if this handler already represents a valid target, add its messenger
775 BMessenger target(handler);
776 if (target.IsValid())
777 return Add(target, what);
779 vector<const BHandler*> &handlers = fHandlerMap[what];
781 vector<const BHandler*>::iterator iter;
782 iter = find(handlers.begin(), handlers.end(), handler);
783 if (iter != handlers.end()) {
784 // TODO: do we want to have a reference count for this?
785 return B_OK;
788 handlers.push_back(handler);
789 return B_OK;
793 status_t
794 ObserverList::Add(const BMessenger &messenger, uint32 what)
796 vector<BMessenger> &messengers = fMessengerMap[what];
798 vector<BMessenger>::iterator iter;
799 iter = find(messengers.begin(), messengers.end(), messenger);
800 if (iter != messengers.end()) {
801 // TODO: do we want to have a reference count for this?
802 return B_OK;
805 messengers.push_back(messenger);
806 return B_OK;
810 status_t
811 ObserverList::Remove(const BHandler* handler, uint32 what)
813 if (handler == NULL)
814 return B_BAD_HANDLER;
816 // look into the list of messengers
817 BMessenger target(handler);
818 if (target.IsValid() && Remove(target, what) == B_OK)
819 return B_OK;
821 vector<const BHandler*> &handlers = fHandlerMap[what];
823 vector<const BHandler*>::iterator iterator = find(handlers.begin(),
824 handlers.end(), handler);
825 if (iterator != handlers.end()) {
826 handlers.erase(iterator);
827 if (handlers.empty())
828 fHandlerMap.erase(what);
830 return B_OK;
833 return B_BAD_HANDLER;
837 status_t
838 ObserverList::Remove(const BMessenger &messenger, uint32 what)
840 vector<BMessenger> &messengers = fMessengerMap[what];
842 vector<BMessenger>::iterator iterator = find(messengers.begin(),
843 messengers.end(), messenger);
844 if (iterator != messengers.end()) {
845 messengers.erase(iterator);
846 if (messengers.empty())
847 fMessengerMap.erase(what);
849 return B_OK;
852 return B_BAD_HANDLER;
856 bool
857 ObserverList::IsEmpty()
859 return fHandlerMap.empty() && fMessengerMap.empty();
863 // #pragma mark -
866 bool
867 FilterDeleter(void* _filter)
869 delete static_cast<BMessageFilter*>(_filter);
870 return false;