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