xref: /haiku/src/kits/app/Handler.cpp (revision b671e9bbdbd10268a042b4f4cc4317ccd03d105e)
1 /*
2  * Copyright 2001-2007, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Erik Jaesler (erik@cgsoftware.com)
7  *		Axel Dörfler, axeld@pinc-software.de
8  */
9 
10 
11 #include <TokenSpace.h>
12 
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>
20 
21 #include <algorithm>
22 #include <new>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <vector>
27 
28 using std::map;
29 using std::vector;
30 using BPrivate::gDefaultTokens;
31 
32 
33 static const char* kArchiveNameField = "_name";
34 
35 static const uint32 kMsgStartObserving = '_OBS';
36 static const uint32 kMsgStopObserving = '_OBP';
37 static const char* kObserveTarget = "be:observe_target";
38 
39 
40 static property_info sHandlerPropInfo[] = {
41 	{
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]
51 					{
52 						"suites",		// name
53 						B_STRING_TYPE	// type
54 					}
55 				}
56 			},
57 			{						// ctypes[1]
58 				{					// pairs[0]
59 					{
60 						"messages",
61 						B_PROPERTY_INFO_TYPE
62 					}
63 				}
64 			}
65 		},
66 		{}		// reserved
67 	},
68 	{
69 		"Messenger",
70 			{ B_GET_PROPERTY },
71 			{ B_DIRECT_SPECIFIER },
72 			NULL, 0,
73 			{ B_MESSENGER_TYPE },
74 			{},
75 			{}
76 	},
77 	{
78 		"InternalName",
79 			{ B_GET_PROPERTY },
80 			{ B_DIRECT_SPECIFIER },
81 			NULL, 0,
82 			{ B_STRING_TYPE },
83 			{},
84 			{}
85 	},
86 	{}
87 };
88 
89 bool FilterDeleter(void *filter);
90 
91 namespace BPrivate {
92 
93 class ObserverList {
94 	public:
95 		ObserverList();
96 		~ObserverList();
97 
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();
104 
105 	private:
106 		typedef map<uint32, vector<const BHandler *> > HandlerObserverMap;
107 		typedef map<uint32, vector<BMessenger> > MessengerObserverMap;
108 
109 		void _ValidateHandlers(uint32 what);
110 		void _SendNotices(uint32 what, BMessage* notice);
111 
112 		HandlerObserverMap		fHandlerMap;
113 		MessengerObserverMap	fMessengerMap;
114 };
115 
116 }	// namespace BPrivate
117 
118 using namespace BPrivate;
119 
120 
121 //	#pragma mark -
122 
123 
124 BHandler::BHandler(const char *name)
125 	: BArchivable(),
126 	fName(NULL)
127 {
128 	_InitData(name);
129 }
130 
131 
132 BHandler::~BHandler()
133 {
134 	if (LockLooper()) {
135 		BLooper* looper = Looper();
136 		looper->RemoveHandler(this);
137 		looper->Unlock();
138 	}
139 
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;
146 	}
147 
148 	// remove all observers (the observer list manages itself)
149 	delete fObserverList;
150 
151 	// free rest
152 	free(fName);
153 	gDefaultTokens.RemoveToken(fToken);
154 }
155 
156 
157 BHandler::BHandler(BMessage *data)
158 	: BArchivable(data),
159 	fName(NULL)
160 {
161 	const char *name = NULL;
162 
163 	if (data)
164 		data->FindString(kArchiveNameField, &name);
165 
166 	_InitData(name);
167 }
168 
169 
170 BArchivable *
171 BHandler::Instantiate(BMessage *data)
172 {
173 	if (!validate_instantiation(data, "BHandler"))
174 		return NULL;
175 
176 	return new BHandler(data);
177 }
178 
179 
180 status_t
181 BHandler::Archive(BMessage *data, bool deep) const
182 {
183 	status_t status = BArchivable::Archive(data, deep);
184 	if (status < B_OK)
185 		return status;
186 
187 	if (!fName)
188 		return B_OK;
189 	return data->AddString(kArchiveNameField, fName);
190 }
191 
192 
193 void
194 BHandler::MessageReceived(BMessage *message)
195 {
196 	BMessage reply(B_REPLY);
197 
198 	switch (message->what) {
199 		case kMsgStartObserving:
200 		case kMsgStopObserving:
201 		{
202 			BMessenger target;
203 			uint32 what;
204 			if (message->FindMessenger(kObserveTarget, &target) != B_OK
205 				|| message->FindInt32(B_OBSERVE_WHAT_CHANGE, (int32*)&what) != B_OK)
206 				break;
207 
208 			ObserverList* list = _ObserverList();
209 			if (list != NULL) {
210 				if (message->what == kMsgStartObserving)
211 					list->Add(target, what);
212 				else
213 					list->Remove(target, what);
214 			}
215 			break;
216 		}
217 
218 		case B_GET_PROPERTY:
219 		{
220 			int32 cur;
221 			BMessage specifier;
222 			int32 form;
223 			const char *prop;
224 
225 			status_t err = message->GetCurrentSpecifier(&cur, &specifier, &form, &prop);
226 			bool known = false;
227 			if (cur < 0 || (strcmp(prop, "Messenger") == 0)) {
228 				err = reply.AddMessenger("result", this);
229 				known = true;
230 			} else if (strcmp(prop, "Suites") == 0) {
231 				err = GetSupportedSuites(&reply);
232 				known = true;
233 			} else if (strcmp(prop, "InternalName") == 0) {
234 				err = reply.AddString("result", Name());
235 				known = true;
236 			}
237 
238 			if (known) {
239 				reply.AddInt32("error", B_OK);
240 				message->SendReply(&reply);
241 				return;
242 			}
243 			// let's try next handler
244 			break;
245 		}
246 
247 		case B_GET_SUPPORTED_SUITES:
248 		{
249 			reply.AddInt32("error", GetSupportedSuites(&reply));
250 			message->SendReply(&reply);
251 			return;
252 		}
253 	}
254 
255 	// ToDo: there is some more work needed here (someone in the know should fill in)!
256 
257 	if (fNextHandler) {
258 		// we need to apply the next handler's filters here, too
259 		BHandler* target = Looper()->_HandlerFilter(message, fNextHandler);
260 		if (target != NULL && target != this) {
261 			// TODO: we also need to make sure that "target" is not before
262 			//	us in the handler chain - at least in case it wasn't before
263 			//	the handler actually targeted with this message - this could
264 			//	get ugly, though.
265 			target->MessageReceived(message);
266 		}
267 	} else if (message->what != B_MESSAGE_NOT_UNDERSTOOD
268 		&& (message->WasDropped() || message->HasSpecifiers())) {
269 		printf("BHandler %s: MessageReceived() couldn't understand the message:\n", Name());
270 		message->PrintToStream();
271 		message->SendReply(B_MESSAGE_NOT_UNDERSTOOD);
272 	}
273 }
274 
275 
276 BLooper *
277 BHandler::Looper() const
278 {
279 	return fLooper;
280 }
281 
282 
283 void
284 BHandler::SetName(const char *name)
285 {
286 	if (fName != NULL) {
287 		free(fName);
288 		fName = NULL;
289 	}
290 
291 	if (name != NULL)
292 		fName = strdup(name);
293 }
294 
295 
296 const char *
297 BHandler::Name() const
298 {
299 	return fName;
300 }
301 
302 
303 void
304 BHandler::SetNextHandler(BHandler *handler)
305 {
306 	if (!fLooper) {
307 		debugger("handler must belong to looper before setting NextHandler");
308 		return;
309 	}
310 
311 	if (!fLooper->IsLocked()) {
312 		debugger("The handler's looper must be locked before setting NextHandler");
313 		return;
314 	}
315 
316 	if (handler && fLooper != handler->Looper()) {
317 		debugger("The handler and its NextHandler must have the same looper");
318 		return;
319 	}
320 
321 	fNextHandler = handler;
322 }
323 
324 
325 BHandler *
326 BHandler::NextHandler() const
327 {
328 	return fNextHandler;
329 }
330 
331 
332 void
333 BHandler::AddFilter(BMessageFilter *filter)
334 {
335 	BLooper* looper = fLooper;
336 	if (looper && !looper->IsLocked()) {
337 		debugger("Owning Looper must be locked before calling SetFilterList");
338 		return;
339 	}
340 
341 	if (looper != NULL)
342 		filter->SetLooper(looper);
343 
344 	if (!fFilters)
345 		fFilters = new BList;
346 
347 	fFilters->AddItem(filter);
348 }
349 
350 
351 bool
352 BHandler::RemoveFilter(BMessageFilter *filter)
353 {
354 	BLooper* looper = fLooper;
355 	if (looper && !looper->IsLocked()) {
356 		debugger("Owning Looper must be locked before calling SetFilterList");
357 		return false;
358 	}
359 
360 	if (fFilters != NULL && fFilters->RemoveItem((void *)filter)) {
361 		filter->SetLooper(NULL);
362 		return true;
363 	}
364 
365 	return false;
366 }
367 
368 
369 void
370 BHandler::SetFilterList(BList* filters)
371 {
372 	BLooper* looper = fLooper;
373 	if (looper && !looper->IsLocked()) {
374 		debugger("Owning Looper must be locked before calling SetFilterList");
375 		return;
376 	}
377 
378 	/**
379 		@note	I would like to use BObjectList internally, but this function is
380 				spec'd such that fFilters would get deleted and then assigned
381 				'filters', which would obviously mess this up.  Wondering if
382 				anyone ever assigns a list of filters and then checks against
383 				FilterList() to see if they are the same.
384 	 */
385 
386 	// TODO: Explore issues with using BObjectList
387 	if (fFilters) {
388 		fFilters->DoForEach(FilterDeleter);
389 		delete fFilters;
390 	}
391 
392 	fFilters = filters;
393 	if (fFilters) {
394 		for (int32 i = 0; i < fFilters->CountItems(); ++i) {
395 			BMessageFilter *filter =
396 				static_cast<BMessageFilter *>(fFilters->ItemAt(i));
397 			if (filter != NULL)
398 				filter->SetLooper(looper);
399 		}
400 	}
401 }
402 
403 
404 BList *
405 BHandler::FilterList()
406 {
407 	return fFilters;
408 }
409 
410 
411 bool
412 BHandler::LockLooper()
413 {
414 	BLooper *looper = fLooper;
415 	// Locking the looper also makes sure that the looper is valid
416 	if (looper != NULL && looper->Lock()) {
417 		// Have we locked the right looper? That's as far as the
418 		// "pseudo-atomic" operation mentioned in the BeBook.
419 		if (fLooper == looper)
420 			return true;
421 
422 		// we locked the wrong looper, bail out
423 		looper->Unlock();
424 	}
425 
426 	return false;
427 }
428 
429 
430 status_t
431 BHandler::LockLooperWithTimeout(bigtime_t timeout)
432 {
433 	BLooper *looper = fLooper;
434 	if (looper == NULL)
435 		return B_BAD_VALUE;
436 
437 	status_t status = looper->LockWithTimeout(timeout);
438 	if (status != B_OK)
439 		return status;
440 
441 	if (fLooper != looper) {
442 		// we locked the wrong looper, bail out
443 		looper->Unlock();
444 		return B_MISMATCHED_VALUES;
445 	}
446 
447 	return B_OK;
448 }
449 
450 
451 void
452 BHandler::UnlockLooper()
453 {
454 	fLooper->Unlock();
455 }
456 
457 
458 BHandler *
459 BHandler::ResolveSpecifier(BMessage *msg, int32 index,
460 	BMessage *specifier, int32 form, const char *property)
461 {
462 	// Straight from the BeBook
463 	BPropertyInfo propertyInfo(sHandlerPropInfo);
464 	if (propertyInfo.FindMatch(msg, index, specifier, form, property) >= 0)
465 		return this;
466 
467 	BMessage reply(B_MESSAGE_NOT_UNDERSTOOD);
468 	reply.AddInt32("error", B_BAD_SCRIPT_SYNTAX);
469 	reply.AddString("message", "Didn't understand the specifier(s)");
470 	msg->SendReply(&reply);
471 
472 	return NULL;
473 }
474 
475 
476 status_t
477 BHandler::GetSupportedSuites(BMessage *data)
478 {
479 /**
480 	@note	This is the output from the original implementation (calling
481 			PrintToStream() on both data and the contained BPropertyInfo):
482 
483 BMessage: what =  (0x0, or 0)
484 	entry         suites, type='CSTR', c=1, size=21, data[0]: "suite/vnd.Be-handler"
485 	entry       messages, type='SCTD', c=1, size= 0,
486 	  property   commands                       types                specifiers
487 --------------------------------------------------------------------------------
488 		Suites   PGET                                               1
489 				 (RTSC,suites)
490 				 (DTCS,messages)
491 
492 	 Messenger   PGET                          GNSM                 1
493   InternalName   PGET                          RTSC                 1
494 
495 			With a good deal of trial and error, I determined that the
496 			parenthetical clauses are entries in the 'ctypes' field of
497 			property_info.  'ctypes' is an array of 'compound_type', which
498 			contains an array of 'field_pair's.  I haven't the foggiest what
499 			either 'compound_type' or 'field_pair' is for, being as the
500 			scripting docs are so bloody horrible.  The corresponding
501 			property_info array is declared in the globals section.
502  */
503 
504 	status_t err = B_OK;
505 	if (!data)
506 		err = B_BAD_VALUE;
507 
508 	if (!err) {
509 		err = data->AddString("suites", "suite/vnd.Be-handler");
510 		if (!err) {
511 			BPropertyInfo propertyInfo(sHandlerPropInfo);
512 			err = data->AddFlat("messages", &propertyInfo);
513 		}
514 	}
515 
516 	return err;
517 }
518 
519 
520 status_t
521 BHandler::StartWatching(BMessenger target, uint32 what)
522 {
523 	BMessage message(kMsgStartObserving);
524 	message.AddMessenger(kObserveTarget, this);
525 	message.AddInt32(B_OBSERVE_WHAT_CHANGE, what);
526 
527 	return target.SendMessage(&message);
528 }
529 
530 
531 status_t
532 BHandler::StartWatchingAll(BMessenger target)
533 {
534 	return StartWatching(target, B_OBSERVER_OBSERVE_ALL);
535 }
536 
537 
538 status_t
539 BHandler::StopWatching(BMessenger target, uint32 what)
540 {
541 	BMessage message(kMsgStopObserving);
542 	message.AddMessenger(kObserveTarget, this);
543 	message.AddInt32(B_OBSERVE_WHAT_CHANGE, what);
544 
545 	return target.SendMessage(&message);
546 }
547 
548 
549 status_t
550 BHandler::StopWatchingAll(BMessenger target)
551 {
552 	return StopWatching(target, B_OBSERVER_OBSERVE_ALL);
553 }
554 
555 
556 status_t
557 BHandler::StartWatching(BHandler* handler, uint32 what)
558 {
559 	ObserverList* list = _ObserverList();
560 	if (list == NULL)
561 		return B_NO_MEMORY;
562 
563 	return list->Add(handler, what);
564 }
565 
566 
567 status_t
568 BHandler::StartWatchingAll(BHandler* handler)
569 {
570 	return StartWatching(handler, B_OBSERVER_OBSERVE_ALL);
571 }
572 
573 
574 status_t
575 BHandler::StopWatching(BHandler* handler, uint32 what)
576 {
577 	ObserverList* list = _ObserverList();
578 	if (list == NULL)
579 		return B_NO_MEMORY;
580 
581 	return list->Remove(handler, what);
582 }
583 
584 
585 status_t
586 BHandler::StopWatchingAll(BHandler *handler)
587 {
588 	return StopWatching(handler, B_OBSERVER_OBSERVE_ALL);
589 }
590 
591 
592 status_t
593 BHandler::Perform(perform_code d, void *arg)
594 {
595 	return BArchivable::Perform(d, arg);
596 }
597 
598 
599 void
600 BHandler::SendNotices(uint32 what, const BMessage *msg)
601 {
602 	if (fObserverList != NULL)
603 		fObserverList->SendNotices(what, msg);
604 }
605 
606 
607 bool
608 BHandler::IsWatched() const
609 {
610 	return fObserverList && !fObserverList->IsEmpty();
611 }
612 
613 
614 void
615 BHandler::_InitData(const char *name)
616 {
617 	SetName(name);
618 
619 	fLooper = NULL;
620 	fNextHandler = NULL;
621 	fFilters = NULL;
622 	fObserverList = NULL;
623 
624 	fToken = gDefaultTokens.NewToken(B_HANDLER_TOKEN, this);
625 }
626 
627 
628 ObserverList*
629 BHandler::_ObserverList()
630 {
631 	if (fObserverList == NULL)
632 		fObserverList = new (std::nothrow) BPrivate::ObserverList();
633 
634 	return fObserverList;
635 }
636 
637 
638 BHandler::BHandler(const BHandler &)
639 {
640 	// No copy construction allowed.
641 }
642 
643 
644 BHandler &
645 BHandler::operator=(const BHandler &)
646 {
647 	// No assignments allowed.
648 	return *this;
649 }
650 
651 
652 void
653 BHandler::SetLooper(BLooper *looper)
654 {
655 	fLooper = looper;
656 	gDefaultTokens.SetHandlerTarget(fToken, looper ? looper->fDirectTarget : NULL);
657 
658 	if (fFilters) {
659 		for (int32 i = 0; i < fFilters->CountItems(); i++)
660 			static_cast<BMessageFilter *>(fFilters->ItemAtFast(i))->SetLooper(looper);
661 	}
662 }
663 
664 
665 #if __GNUC__ < 3
666 // binary compatibility with R4.5
667 
668 extern "C" void
669 _ReservedHandler1__8BHandler(BHandler* handler, uint32 what,
670 	const BMessage* notice)
671 {
672 	handler->BHandler::SendNotices(what, notice);
673 }
674 
675 #endif
676 
677 void BHandler::_ReservedHandler2() {}
678 void BHandler::_ReservedHandler3() {}
679 void BHandler::_ReservedHandler4() {}
680 
681 
682 //	#pragma mark -
683 
684 
685 ObserverList::ObserverList()
686 {
687 }
688 
689 
690 ObserverList::~ObserverList()
691 {
692 }
693 
694 
695 void
696 ObserverList::_ValidateHandlers(uint32 what)
697 {
698 	vector<const BHandler *>& handlers = fHandlerMap[what];
699 	vector<const BHandler *>::iterator iterator = handlers.begin();
700 
701 	while (iterator != handlers.end()) {
702 		BMessenger target(*iterator);
703 		if (!target.IsValid()) {
704 			iterator++;
705 			continue;
706 		}
707 
708 		Add(target, what);
709 		iterator = handlers.erase(iterator);
710 	}
711 }
712 
713 
714 void
715 ObserverList::_SendNotices(uint32 what, BMessage* message)
716 {
717 	// first iterate over the list of handlers and try to make valid messengers out of them
718 	_ValidateHandlers(what);
719 
720 	// now send it to all messengers we know
721 	vector<BMessenger>& messengers = fMessengerMap[what];
722 	vector<BMessenger>::iterator iterator = messengers.begin();
723 
724 	while (iterator != messengers.end()) {
725 		if (!(*iterator).IsValid()) {
726 			iterator = messengers.erase(iterator);
727 			continue;
728 		}
729 
730 		(*iterator).SendMessage(message);
731 		iterator++;
732 	}
733 }
734 
735 
736 status_t
737 ObserverList::SendNotices(uint32 what, const BMessage* message)
738 {
739 	BMessage *copy = NULL;
740 	if (message) {
741 		copy = new BMessage(*message);
742 		copy->what = B_OBSERVER_NOTICE_CHANGE;
743 		copy->AddInt32(B_OBSERVE_ORIGINAL_WHAT, message->what);
744 	} else
745 		copy = new BMessage(B_OBSERVER_NOTICE_CHANGE);
746 
747 	copy->AddInt32(B_OBSERVE_WHAT_CHANGE, what);
748 
749 	_SendNotices(what, copy);
750 	_SendNotices(B_OBSERVER_OBSERVE_ALL, copy);
751 
752 	delete copy;
753 	return B_OK;
754 }
755 
756 
757 status_t
758 ObserverList::Add(const BHandler *handler, uint32 what)
759 {
760 	if (handler == NULL)
761 		return B_BAD_HANDLER;
762 
763 	// if this handler already represents a valid target, add its messenger
764 	BMessenger target(handler);
765 	if (target.IsValid())
766 		return Add(target, what);
767 
768 	vector<const BHandler*> &handlers = fHandlerMap[what];
769 
770 	vector<const BHandler*>::iterator iter;
771 	iter = find(handlers.begin(), handlers.end(), handler);
772 	if (iter != handlers.end()) {
773 		// TODO: do we want to have a reference count for this?
774 		return B_OK;
775 	}
776 
777 	handlers.push_back(handler);
778 	return B_OK;
779 }
780 
781 
782 status_t
783 ObserverList::Add(const BMessenger &messenger, uint32 what)
784 {
785 	vector<BMessenger> &messengers = fMessengerMap[what];
786 
787 	vector<BMessenger>::iterator iter;
788 	iter = find(messengers.begin(), messengers.end(), messenger);
789 	if (iter != messengers.end()) {
790 		// TODO: do we want to have a reference count for this?
791 		return B_OK;
792 	}
793 
794 	messengers.push_back(messenger);
795 	return B_OK;
796 }
797 
798 
799 status_t
800 ObserverList::Remove(const BHandler *handler, uint32 what)
801 {
802 	if (handler == NULL)
803 		return B_BAD_HANDLER;
804 
805 	// look into the list of messengers
806 	BMessenger target(handler);
807 	if (target.IsValid() && Remove(target, what) == B_OK)
808 		return B_OK;
809 
810 	vector<const BHandler*> &handlers = fHandlerMap[what];
811 
812 	vector<const BHandler*>::iterator iterator = find(handlers.begin(),
813 		handlers.end(), handler);
814 	if (iterator != handlers.end()) {
815 		handlers.erase(iterator);
816 		if (handlers.empty())
817 			fHandlerMap.erase(what);
818 
819 		return B_OK;
820 	}
821 
822 	return B_BAD_HANDLER;
823 }
824 
825 
826 status_t
827 ObserverList::Remove(const BMessenger &messenger, uint32 what)
828 {
829 	vector<BMessenger> &messengers = fMessengerMap[what];
830 
831 	vector<BMessenger>::iterator iterator = find(messengers.begin(),
832 		messengers.end(), messenger);
833 	if (iterator != messengers.end()) {
834 		messengers.erase(iterator);
835 		if (messengers.empty())
836 			fMessengerMap.erase(what);
837 
838 		return B_OK;
839 	}
840 
841 	return B_BAD_HANDLER;
842 }
843 
844 
845 bool
846 ObserverList::IsEmpty()
847 {
848 	return fHandlerMap.empty() && fMessengerMap.empty();
849 }
850 
851 
852 //	#pragma mark -
853 
854 
855 bool
856 FilterDeleter(void *_filter)
857 {
858 	delete static_cast<BMessageFilter *>(_filter);
859 	return false;
860 }
861 
862