xref: /haiku/src/kits/app/Handler.cpp (revision 37fedaf8494b34aad811abcc49e79aa32943f880)
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 };
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 == NULL)
188 		return B_OK;
189 
190 	return data->AddString(kArchiveNameField, fName);
191 }
192 
193 
194 void
195 BHandler::MessageReceived(BMessage* message)
196 {
197 	BMessage reply(B_REPLY);
198 
199 	switch (message->what) {
200 		case kMsgStartObserving:
201 		case kMsgStopObserving:
202 		{
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;
209 			}
210 
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);
217 			}
218 			break;
219 		}
220 
221 		case B_GET_PROPERTY:
222 		{
223 			int32 cur;
224 			BMessage specifier;
225 			int32 form;
226 			const char* prop;
227 
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;
244 			}
245 
246 			if (known) {
247 				reply.AddInt32("error", B_OK);
248 				message->SendReply(&reply);
249 				return;
250 			}
251 			// let's try next handler
252 			break;
253 		}
254 
255 		case B_GET_SUPPORTED_SUITES:
256 		{
257 			reply.AddInt32("error", GetSupportedSuites(&reply));
258 			message->SendReply(&reply);
259 			return;
260 		}
261 	}
262 
263 	// ToDo: there is some more work needed here
264 	// (someone in the know should fill in)!
265 
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);
275 		}
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);
281 	}
282 }
283 
284 
285 BLooper*
286 BHandler::Looper() const
287 {
288 	return fLooper;
289 }
290 
291 
292 void
293 BHandler::SetName(const char* name)
294 {
295 	if (fName != NULL) {
296 		free(fName);
297 		fName = NULL;
298 	}
299 
300 	if (name != NULL)
301 		fName = strdup(name);
302 }
303 
304 
305 const char*
306 BHandler::Name() const
307 {
308 	return fName;
309 }
310 
311 
312 void
313 BHandler::SetNextHandler(BHandler* handler)
314 {
315 	if (fLooper == NULL) {
316 		debugger("handler must belong to looper before setting NextHandler");
317 		return;
318 	}
319 
320 	if (!fLooper->IsLocked()) {
321 		debugger("The handler's looper must be locked before setting NextHandler");
322 		return;
323 	}
324 
325 	if (handler != NULL && fLooper != handler->Looper()) {
326 		debugger("The handler and its NextHandler must have the same looper");
327 		return;
328 	}
329 
330 	fNextHandler = handler;
331 }
332 
333 
334 BHandler*
335 BHandler::NextHandler() const
336 {
337 	return fNextHandler;
338 }
339 
340 
341 void
342 BHandler::AddFilter(BMessageFilter* filter)
343 {
344 	BLooper* looper = fLooper;
345 	if (looper != NULL && !looper->IsLocked()) {
346 		debugger("Owning Looper must be locked before calling SetFilterList");
347 		return;
348 	}
349 
350 	if (looper != NULL)
351 		filter->SetLooper(looper);
352 
353 	if (fFilters == NULL)
354 		fFilters = new BList;
355 
356 	fFilters->AddItem(filter);
357 }
358 
359 
360 bool
361 BHandler::RemoveFilter(BMessageFilter* filter)
362 {
363 	BLooper* looper = fLooper;
364 	if (looper != NULL && !looper->IsLocked()) {
365 		debugger("Owning Looper must be locked before calling SetFilterList");
366 		return false;
367 	}
368 
369 	if (fFilters != NULL && fFilters->RemoveItem((void*)filter)) {
370 		filter->SetLooper(NULL);
371 		return true;
372 	}
373 
374 	return false;
375 }
376 
377 
378 void
379 BHandler::SetFilterList(BList* filters)
380 {
381 	BLooper* looper = fLooper;
382 	if (looper != NULL && !looper->IsLocked()) {
383 		debugger("Owning Looper must be locked before calling SetFilterList");
384 		return;
385 	}
386 
387 	/**
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.
393 	 */
394 
395 	// TODO: Explore issues with using BObjectList
396 	if (fFilters != NULL) {
397 		fFilters->DoForEach(FilterDeleter);
398 		delete fFilters;
399 	}
400 
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);
408 		}
409 	}
410 }
411 
412 
413 BList*
414 BHandler::FilterList()
415 {
416 	return fFilters;
417 }
418 
419 
420 bool
421 BHandler::LockLooper()
422 {
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;
430 
431 		// we locked the wrong looper, bail out
432 		looper->Unlock();
433 	}
434 
435 	return false;
436 }
437 
438 
439 status_t
440 BHandler::LockLooperWithTimeout(bigtime_t timeout)
441 {
442 	BLooper* looper = fLooper;
443 	if (looper == NULL)
444 		return B_BAD_VALUE;
445 
446 	status_t status = looper->LockWithTimeout(timeout);
447 	if (status != B_OK)
448 		return status;
449 
450 	if (fLooper != looper) {
451 		// we locked the wrong looper, bail out
452 		looper->Unlock();
453 		return B_MISMATCHED_VALUES;
454 	}
455 
456 	return B_OK;
457 }
458 
459 
460 void
461 BHandler::UnlockLooper()
462 {
463 	fLooper->Unlock();
464 }
465 
466 
467 BHandler*
468 BHandler::ResolveSpecifier(BMessage* message, int32 index,
469 	BMessage* specifier, int32 what, const char* property)
470 {
471 	// Straight from the BeBook
472 	BPropertyInfo propertyInfo(sHandlerPropInfo);
473 	if (propertyInfo.FindMatch(message, index, specifier, what, property) >= 0)
474 		return this;
475 
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);
480 
481 	return NULL;
482 }
483 
484 
485 status_t
486 BHandler::GetSupportedSuites(BMessage* data)
487 {
488 /**
489 	@note	This is the output from the original implementation (calling
490 			PrintToStream() on both data and the contained BPropertyInfo):
491 
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)
500 
501 	 Messenger   PGET                          GNSM                 1
502   InternalName   PGET                          RTSC                 1
503 
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.
511  */
512 
513 	status_t err = B_OK;
514 	if (data == NULL)
515 		err = B_BAD_VALUE;
516 
517 	if (err != B_OK) {
518 		err = data->AddString("suites", "suite/vnd.Be-handler");
519 		if (err != B_OK) {
520 			BPropertyInfo propertyInfo(sHandlerPropInfo);
521 			err = data->AddFlat("messages", &propertyInfo);
522 		}
523 	}
524 
525 	return err;
526 }
527 
528 
529 status_t
530 BHandler::StartWatching(BMessenger target, uint32 what)
531 {
532 	BMessage message(kMsgStartObserving);
533 	message.AddMessenger(kObserveTarget, this);
534 	message.AddInt32(B_OBSERVE_WHAT_CHANGE, what);
535 
536 	return target.SendMessage(&message);
537 }
538 
539 
540 status_t
541 BHandler::StartWatchingAll(BMessenger target)
542 {
543 	return StartWatching(target, B_OBSERVER_OBSERVE_ALL);
544 }
545 
546 
547 status_t
548 BHandler::StopWatching(BMessenger target, uint32 what)
549 {
550 	BMessage message(kMsgStopObserving);
551 	message.AddMessenger(kObserveTarget, this);
552 	message.AddInt32(B_OBSERVE_WHAT_CHANGE, what);
553 
554 	return target.SendMessage(&message);
555 }
556 
557 
558 status_t
559 BHandler::StopWatchingAll(BMessenger target)
560 {
561 	return StopWatching(target, B_OBSERVER_OBSERVE_ALL);
562 }
563 
564 
565 status_t
566 BHandler::StartWatching(BHandler* handler, uint32 what)
567 {
568 	ObserverList* list = _ObserverList();
569 	if (list == NULL)
570 		return B_NO_MEMORY;
571 
572 	return list->Add(handler, what);
573 }
574 
575 
576 status_t
577 BHandler::StartWatchingAll(BHandler* handler)
578 {
579 	return StartWatching(handler, B_OBSERVER_OBSERVE_ALL);
580 }
581 
582 
583 status_t
584 BHandler::StopWatching(BHandler* handler, uint32 what)
585 {
586 	ObserverList* list = _ObserverList();
587 	if (list == NULL)
588 		return B_NO_MEMORY;
589 
590 	return list->Remove(handler, what);
591 }
592 
593 
594 status_t
595 BHandler::StopWatchingAll(BHandler* handler)
596 {
597 	return StopWatching(handler, B_OBSERVER_OBSERVE_ALL);
598 }
599 
600 
601 status_t
602 BHandler::Perform(perform_code d, void* arg)
603 {
604 	return BArchivable::Perform(d, arg);
605 }
606 
607 
608 void
609 BHandler::SendNotices(uint32 what, const BMessage* notice)
610 {
611 	if (fObserverList != NULL)
612 		fObserverList->SendNotices(what, notice);
613 }
614 
615 
616 bool
617 BHandler::IsWatched() const
618 {
619 	return fObserverList && !fObserverList->IsEmpty();
620 }
621 
622 
623 void
624 BHandler::_InitData(const char* name)
625 {
626 	SetName(name);
627 
628 	fLooper = NULL;
629 	fNextHandler = NULL;
630 	fFilters = NULL;
631 	fObserverList = NULL;
632 
633 	fToken = gDefaultTokens.NewToken(B_HANDLER_TOKEN, this);
634 }
635 
636 
637 ObserverList*
638 BHandler::_ObserverList()
639 {
640 	if (fObserverList == NULL)
641 		fObserverList = new (std::nothrow) BPrivate::ObserverList();
642 
643 	return fObserverList;
644 }
645 
646 
647 BHandler::BHandler(const BHandler &)
648 {
649 	// No copy construction allowed.
650 }
651 
652 
653 BHandler &
654 BHandler::operator=(const BHandler &)
655 {
656 	// No assignments allowed.
657 	return *this;
658 }
659 
660 
661 void
662 BHandler::SetLooper(BLooper* looper)
663 {
664 	fLooper = looper;
665 	gDefaultTokens.SetHandlerTarget(fToken,
666 		looper ? looper->fDirectTarget : NULL);
667 
668 	if (fFilters != NULL) {
669 		for (int32 i = 0; i < fFilters->CountItems(); i++) {
670 			static_cast<BMessageFilter*>(
671 				fFilters->ItemAtFast(i))->SetLooper(looper);
672 		}
673 	}
674 }
675 
676 
677 #if __GNUC__ < 3
678 // binary compatibility with R4.5
679 
680 extern "C" void
681 _ReservedHandler1__8BHandler(BHandler* handler, uint32 what,
682 	const BMessage* notice)
683 {
684 	handler->BHandler::SendNotices(what, notice);
685 }
686 
687 #endif
688 
689 void BHandler::_ReservedHandler2() {}
690 void BHandler::_ReservedHandler3() {}
691 void BHandler::_ReservedHandler4() {}
692 
693 
694 //	#pragma mark -
695 
696 
697 ObserverList::ObserverList()
698 {
699 }
700 
701 
702 ObserverList::~ObserverList()
703 {
704 }
705 
706 
707 void
708 ObserverList::_ValidateHandlers(uint32 what)
709 {
710 	vector<const BHandler*>& handlers = fHandlerMap[what];
711 	vector<const BHandler*>::iterator iterator = handlers.begin();
712 
713 	while (iterator != handlers.end()) {
714 		BMessenger target(*iterator);
715 		if (!target.IsValid()) {
716 			iterator++;
717 			continue;
718 		}
719 
720 		Add(target, what);
721 		iterator = handlers.erase(iterator);
722 	}
723 }
724 
725 
726 void
727 ObserverList::_SendNotices(uint32 what, BMessage* notice)
728 {
729 	// first iterate over the list of handlers and try to make valid
730 	// messengers out of them
731 	_ValidateHandlers(what);
732 
733 	// now send it to all messengers we know
734 	vector<BMessenger>& messengers = fMessengerMap[what];
735 	vector<BMessenger>::iterator iterator = messengers.begin();
736 
737 	while (iterator != messengers.end()) {
738 		if (!(*iterator).IsValid()) {
739 			iterator = messengers.erase(iterator);
740 			continue;
741 		}
742 
743 		(*iterator).SendMessage(notice);
744 		iterator++;
745 	}
746 }
747 
748 
749 status_t
750 ObserverList::SendNotices(uint32 what, const BMessage* notice)
751 {
752 	BMessage* copy = NULL;
753 	if (notice != NULL) {
754 		copy = new BMessage(*notice);
755 		copy->what = B_OBSERVER_NOTICE_CHANGE;
756 		copy->AddInt32(B_OBSERVE_ORIGINAL_WHAT, notice->what);
757 	} else
758 		copy = new BMessage(B_OBSERVER_NOTICE_CHANGE);
759 
760 	copy->AddInt32(B_OBSERVE_WHAT_CHANGE, what);
761 
762 	_SendNotices(what, copy);
763 	_SendNotices(B_OBSERVER_OBSERVE_ALL, copy);
764 
765 	delete copy;
766 
767 	return B_OK;
768 }
769 
770 
771 status_t
772 ObserverList::Add(const BHandler* handler, uint32 what)
773 {
774 	if (handler == NULL)
775 		return B_BAD_HANDLER;
776 
777 	// if this handler already represents a valid target, add its messenger
778 	BMessenger target(handler);
779 	if (target.IsValid())
780 		return Add(target, what);
781 
782 	vector<const BHandler*> &handlers = fHandlerMap[what];
783 
784 	vector<const BHandler*>::iterator iter;
785 	iter = find(handlers.begin(), handlers.end(), handler);
786 	if (iter != handlers.end()) {
787 		// TODO: do we want to have a reference count for this?
788 		return B_OK;
789 	}
790 
791 	handlers.push_back(handler);
792 	return B_OK;
793 }
794 
795 
796 status_t
797 ObserverList::Add(const BMessenger &messenger, uint32 what)
798 {
799 	vector<BMessenger> &messengers = fMessengerMap[what];
800 
801 	vector<BMessenger>::iterator iter;
802 	iter = find(messengers.begin(), messengers.end(), messenger);
803 	if (iter != messengers.end()) {
804 		// TODO: do we want to have a reference count for this?
805 		return B_OK;
806 	}
807 
808 	messengers.push_back(messenger);
809 	return B_OK;
810 }
811 
812 
813 status_t
814 ObserverList::Remove(const BHandler* handler, uint32 what)
815 {
816 	if (handler == NULL)
817 		return B_BAD_HANDLER;
818 
819 	// look into the list of messengers
820 	BMessenger target(handler);
821 	if (target.IsValid() && Remove(target, what) == B_OK)
822 		return B_OK;
823 
824 	vector<const BHandler*> &handlers = fHandlerMap[what];
825 
826 	vector<const BHandler*>::iterator iterator = find(handlers.begin(),
827 		handlers.end(), handler);
828 	if (iterator != handlers.end()) {
829 		handlers.erase(iterator);
830 		if (handlers.empty())
831 			fHandlerMap.erase(what);
832 
833 		return B_OK;
834 	}
835 
836 	return B_BAD_HANDLER;
837 }
838 
839 
840 status_t
841 ObserverList::Remove(const BMessenger &messenger, uint32 what)
842 {
843 	vector<BMessenger> &messengers = fMessengerMap[what];
844 
845 	vector<BMessenger>::iterator iterator = find(messengers.begin(),
846 		messengers.end(), messenger);
847 	if (iterator != messengers.end()) {
848 		messengers.erase(iterator);
849 		if (messengers.empty())
850 			fMessengerMap.erase(what);
851 
852 		return B_OK;
853 	}
854 
855 	return B_BAD_HANDLER;
856 }
857 
858 
859 bool
860 ObserverList::IsEmpty()
861 {
862 	return fHandlerMap.empty() && fMessengerMap.empty();
863 }
864 
865 
866 //	#pragma mark -
867 
868 
869 bool
870 FilterDeleter(void* _filter)
871 {
872 	delete static_cast<BMessageFilter*>(_filter);
873 	return false;
874 }
875