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