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