xref: /haiku/src/kits/app/Handler.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
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 	for (; iterator != handlers.end(); iterator++) {
686 		BMessenger target(*iterator);
687 		if (!target.IsValid())
688 			continue;
689 
690 		handlers.erase(iterator);
691 		iterator--;
692 		Add(target, what);
693 	}
694 }
695 
696 
697 void
698 ObserverList::_SendNotices(uint32 what, BMessage* message)
699 {
700 	// first iterate over the list of handlers and try to make valid messengers out of them
701 	_ValidateHandlers(what);
702 
703 	// now send it to all messengers we know
704 	vector<BMessenger>& messengers = fMessengerMap[what];
705 	vector<BMessenger>::iterator iterator = messengers.begin();
706 
707 	for (; iterator != messengers.end(); iterator++) {
708 		if (!(*iterator).IsValid()) {
709 			messengers.erase(iterator);
710 			continue;
711 		}
712 
713 		(*iterator).SendMessage(message);
714 	}
715 }
716 
717 
718 status_t
719 ObserverList::SendNotices(uint32 what, const BMessage* message)
720 {
721 	BMessage *copy = NULL;
722 	if (message) {
723 		copy = new BMessage(*message);
724 		copy->what = B_OBSERVER_NOTICE_CHANGE;
725 		copy->AddInt32(B_OBSERVE_ORIGINAL_WHAT, message->what);
726 	} else
727 		copy = new BMessage(B_OBSERVER_NOTICE_CHANGE);
728 
729 	copy->AddInt32(B_OBSERVE_WHAT_CHANGE, what);
730 
731 	_SendNotices(what, copy);
732 	_SendNotices(B_OBSERVER_OBSERVE_ALL, copy);
733 
734 	delete copy;
735 	return B_OK;
736 }
737 
738 
739 status_t
740 ObserverList::Add(const BHandler *handler, uint32 what)
741 {
742 	if (handler == NULL)
743 		return B_BAD_HANDLER;
744 
745 	// if this handler already represents a valid target, add its messenger
746 	BMessenger target(handler);
747 	if (target.IsValid())
748 		return Add(target, what);
749 
750 	vector<const BHandler*> &handlers = fHandlerMap[what];
751 
752 	vector<const BHandler*>::iterator iter;
753 	iter = find(handlers.begin(), handlers.end(), handler);
754 	if (iter != handlers.end()) {
755 		// TODO: do we want to have a reference count for this?
756 		return B_OK;
757 	}
758 
759 	handlers.push_back(handler);
760 	return B_OK;
761 }
762 
763 
764 status_t
765 ObserverList::Add(const BMessenger &messenger, uint32 what)
766 {
767 	vector<BMessenger> &messengers = fMessengerMap[what];
768 
769 	vector<BMessenger>::iterator iter;
770 	iter = find(messengers.begin(), messengers.end(), messenger);
771 	if (iter != messengers.end()) {
772 		// TODO: do we want to have a reference count for this?
773 		return B_OK;
774 	}
775 
776 	messengers.push_back(messenger);
777 	return B_OK;
778 }
779 
780 
781 status_t
782 ObserverList::Remove(const BHandler *handler, uint32 what)
783 {
784 	if (handler == NULL)
785 		return B_BAD_HANDLER;
786 
787 	// look into the list of messengers
788 	BMessenger target(handler);
789 	if (target.IsValid() && Remove(target, what) == B_OK)
790 		return B_OK;
791 
792 	vector<const BHandler*> &handlers = fHandlerMap[what];
793 
794 	vector<const BHandler*>::iterator iter;
795 	iter = find(handlers.begin(), handlers.end(), handler);
796 	if (iter != handlers.end()) {
797 		handlers.erase(iter);
798 		if (handlers.empty())
799 			fHandlerMap.erase(what);
800 
801 		return B_OK;
802 	}
803 
804 	return B_BAD_HANDLER;
805 }
806 
807 
808 status_t
809 ObserverList::Remove(const BMessenger &messenger, uint32 what)
810 {
811 	vector<BMessenger> &messengers = fMessengerMap[what];
812 
813 	vector<BMessenger>::iterator iter;
814 	iter = find(messengers.begin(), messengers.end(), messenger);
815 	if (iter != messengers.end()) {
816 		messengers.erase(iter);
817 		if (messengers.empty())
818 			fMessengerMap.erase(what);
819 
820 		return B_OK;
821 	}
822 
823 	return B_BAD_HANDLER;
824 }
825 
826 
827 bool
828 ObserverList::IsEmpty()
829 {
830 	return fHandlerMap.empty() && fMessengerMap.empty();
831 }
832 
833 
834 //	#pragma mark -
835 
836 
837 bool
838 FilterDeleter(void *_filter)
839 {
840 	delete static_cast<BMessageFilter *>(_filter);
841 	return false;
842 }
843 
844