xref: /haiku/src/kits/app/Handler.cpp (revision a4f6a81235ca2522c01f532de13cad9b729d4029)
1 /*
2  * Copyright 2001-2005, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Erik Jaesler (erik@cgsoftware.com)
7  */
8 
9 /**
10 	@note	Some musings on the member variable 'fToken'.  In searching a dump
11 			of libbe.so, I found a struct/class called 'TokenSpace', which has
12 			various member functions like 'new_token'.  More intriguing is a
13 			dump of Dano's version of libbe.so:  there is BPrivate::BTokenSpace,
14 			which also has functions like 'NewToken'.  There's more: one
15 			version of BTokenSpace::NewToken takes a pointer to another new
16 			class, BPrivate::BDirectMessageTarget.  Only a constructor,
17 			destructor and vtable are listed for it, so I'm guessing it's an
18 			abstract base class (or not very useful ;).  My guess is that
19 			BDirectMessageTarget facilitates sending messages straight to an
20 			associated BHandler.  Maybe from app_server?  Probably not, since
21 			you'd have to do IPC anyway.  But maybe within the same team, or
22 			even between teams?  It might save unnecessary trips to and from
23 			app_server for messages which otherwise are entirely client-side.
24 
25 			Back to tokens. There are also these functions in R5:
26 				_safe_get_server_token_(const BLooper*, int32*)
27 				BWindow::find_token_and_handler(BMessage*, int32*, BHandler**)
28 				BWindow::get_server_token
29 
30 			and Dano adds a few more provocative sounding functions:
31 				get_handler_token(short, void*) (listed 3 times, actually)
32 				new_handler_token(short, void*)
33 				remove_handler_token(short, void*)
34 
35 			Taken all together, I think there's a sound argument to be made that
36 			each BHandler has an int32 token associated with it in app_server.
37 
38 			Furthermore, there is, in R5, a function set_token_type(long, short)
39 			which leads me to think that although BHandler's have server tokens
40 			associated with them, the tokening facility is, in fact, generic.
41 			These functions would seem to support that theory:
42 				BBitmap::get_server_token
43 				BPicture::set_token
44 
45 			An important question is whether tokens are generated on the client
46 			side and registered with the server or generated on the server and
47 			given back to the client.  The exported functions of TokenSpace in
48 			libbe's dump are:
49 				~TokenSpace
50 				TokenSpace
51 				adjust_free(long, long)
52 				dump()
53 				find_free_entry(long*, long*)
54 				full_search_adjust()
55 				get_token(void**)
56 				get_token(short*, void**)
57 				new_token(long, short, void*)
58 				new_token_array(long)
59 				remove_token(long)
60 				set_token_type(long, short)
61 
62 			TokenSpace functions are also exported from app_server:
63 				~TokenSpace
64 				TokenSpace
65 				adjust_free(long, long)
66 				cleanup_dead(long)
67 				delete_atom(SAtom*)
68 				dump_tokens()
69 				find_free_entry(long*, long*)
70 				full_search_adjust()
71 				get_token(long, void**)
72 				get_token(long, short*, void**)
73 				get_token_by_type(int*, short, long, void**)
74 				grab_atom(long, SAtom**)
75 				iterate_tokens(long, short,
76 							   unsigned long(*)(long, long, short, void*, void*),
77 							   void*)
78 				new_token(long, short, void*)
79 				new_token_array(long)
80 				remove_token(long)
81 				set_token_type(long, short)
82 
83 			While there are common functions in both locations, the fact that
84 			app_server exports TokenSpace functions which libbe.so does not
85 			leads me to believe that libbe.so and app_server each have their own
86 			versions of TokenSpace.  While it's possible that the libbe version
87 			simply acts as a proxy for the app_server version, it seems not
88 			only inefficient but unnecessary as well:  client-side objects
89 			exists in a different "namespace" than server-side objects, so over-
90 			lap between the two token sets shouldn't be an issue.
91 
92 			Obviously, I can't be entirely sure this is how R5 does it, but it
93 			seems like a reasonable design to follow for our purposes.
94  */
95 
96 /**
97 	@note	Thought on "pseudo-atomic" operations in Lock(), LockWithTimeout(),
98 			and Unlock().  Seems like avoiding the possibility of a looper
99 			change during these functions would be the way to go, and having a
100 			semaphore that protects SetLooper() would do the job very nicely.
101 			Maybe that's too heavy-weight a solution, though.
102  */
103 
104 #include <TokenSpace.h>
105 
106 #include <AppDefs.h>
107 #include <Handler.h>
108 #include <Looper.h>
109 #include <Message.h>
110 #include <MessageFilter.h>
111 #include <Messenger.h>
112 #include <PropertyInfo.h>
113 
114 #include <algorithm>
115 #include <stdlib.h>
116 #include <string.h>
117 #include <vector>
118 
119 using std::map;
120 using std::vector;
121 using BPrivate::gDefaultTokens;
122 
123 
124 static const char *kArchiveNameField = "_name";
125 
126 static property_info sHandlerPropInfo[] = {
127 	{
128 		"Suites",					// name
129 		{ B_GET_PROPERTY },			// commands
130 		{ B_DIRECT_SPECIFIER },		// specifiers
131 		NULL,						// usage
132 		0,							// extra data
133 		{ 0 },						// types
134 		{							// ctypes (compound_type)
135 			{						// ctypes[0]
136 				{					// pairs[0]
137 					{
138 						"suites",		// name
139 						B_STRING_TYPE	// type
140 					}
141 				}
142 			},
143 			{						// ctypes[1]
144 				{					// pairs[0]
145 					{
146 						"messages",
147 						B_PROPERTY_INFO_TYPE
148 					}
149 				}
150 			}
151 		},
152 		{}		// reserved
153 	},
154 	{
155 		"Messenger",
156 			{ B_GET_PROPERTY },
157 			{ B_DIRECT_SPECIFIER },
158 			NULL, 0,
159 			{ B_MESSENGER_TYPE },
160 			{},
161 			{}
162 	},
163 	{
164 		"InternalName",
165 			{ B_GET_PROPERTY },
166 			{ B_DIRECT_SPECIFIER },
167 			NULL, 0,
168 			{ B_STRING_TYPE },
169 			{},
170 			{}
171 	},
172 	{}
173 };
174 
175 bool FilterDeleter(void *filter);
176 
177 typedef map<unsigned long, vector<BHandler *> >	THandlerObserverMap;
178 typedef map<unsigned long, vector<BMessenger> >	TMessengerObserverMap;
179 
180 //------------------------------------------------------------------------------
181 // TODO: Change to BPrivate::BObserverList if possible
182 class _ObserverList {
183 	public:
184 		_ObserverList(void);
185 		~_ObserverList(void);
186 		status_t SendNotices(unsigned long, BMessage const *);
187 		status_t StartObserving(BHandler *, unsigned long);
188 		status_t StartObserving(const BMessenger&, unsigned long);
189 		status_t StopObserving(BHandler *, unsigned long);
190 		status_t StopObserving(const BMessenger&, unsigned long);
191 		bool IsEmpty();
192 
193 	private:
194 		THandlerObserverMap		fHandlerMap;
195 		TMessengerObserverMap	fMessengerMap;
196 };
197 
198 
199 BHandler::BHandler(const char *name)
200 	: BArchivable(),
201 	fName(NULL)
202 {
203 	InitData(name);
204 }
205 
206 
207 BHandler::~BHandler()
208 {
209 	free(fName);
210 	gDefaultTokens.RemoveToken(fToken);
211 }
212 
213 
214 BHandler::BHandler(BMessage *data)
215 	: BArchivable(data),
216 	fName(NULL)
217 {
218 	const char *name = NULL;
219 
220 	if (data)
221 		data->FindString(kArchiveNameField, &name);
222 
223 	InitData(name);
224 }
225 
226 
227 BArchivable *
228 BHandler::Instantiate(BMessage *data)
229 {
230 	if (!validate_instantiation(data, "BHandler"))
231 		return NULL;
232 
233 	return new BHandler(data);
234 }
235 
236 
237 status_t
238 BHandler::Archive(BMessage *data, bool deep) const
239 {
240 	status_t status = BArchivable::Archive(data, deep);
241 	if (status < B_OK)
242 		return status;
243 
244 	return data->AddString(kArchiveNameField, fName);
245 }
246 
247 
248 void
249 BHandler::MessageReceived(BMessage *message)
250 {
251 	BMessage reply(B_REPLY);
252 
253 	switch (message->what) {
254 		// ToDo: am I missing something or is the "observed" stuff handshake completely missing?
255 
256 		case B_GET_PROPERTY:
257 		{
258 			int32 cur;
259 			BMessage specifier;
260 			int32 form;
261 			const char *prop;
262 
263 			status_t err = message->GetCurrentSpecifier(&cur, &specifier, &form, &prop);
264 			if (err == B_OK) {
265 				bool known = false;
266 				if (strcmp(prop, "Suites") == 0) {
267 					err = GetSupportedSuites(&reply);
268 					known = true;
269 				} else if (strcmp(prop, "Messenger") == 0) {
270 					err = reply.AddMessenger("result", this);
271 					known = true;
272 				} else if (strcmp(prop, "InternalName") == 0) {
273 					err = reply.AddString("result", Name());
274 					known = true;
275 				}
276 
277 				if (known) {
278 					reply.AddInt32("error", B_OK);
279 					message->SendReply(&reply);
280 					return;
281 				}
282 				// let's try next handler
283 			}
284 			break;
285 		}
286 
287 		case B_GET_SUPPORTED_SUITES:
288 		{
289 			reply.AddInt32("error", GetSupportedSuites(&reply));
290 			message->SendReply(&reply);
291 			return;
292 		}
293 	}
294 
295 	// ToDo: there is some more work needed here (someone in the know should fill in)!
296 
297 	if (fNextHandler) {
298 		// we need to apply the next handler's filters here, too
299 		BHandler* target = Looper()->_HandlerFilter(message, fNextHandler);
300 		if (target != NULL && target != this) {
301 			// TODO: we also need to make sure that "target" is not before
302 			//	us in the handler chain - at least in case it wasn't before
303 			//	the handler actually targeted with this message - this could
304 			//	get ugly, though.
305 			target->MessageReceived(message);
306 		}
307 	} else if (message->what != B_MESSAGE_NOT_UNDERSTOOD
308 		&& (message->WasDropped() || message->HasSpecifiers())) {
309 		printf("BHandler %s: MessageReceived() couldn't understand the message:\n", Name());
310 		message->PrintToStream();
311 		message->SendReply(B_MESSAGE_NOT_UNDERSTOOD);
312 	}
313 }
314 
315 
316 BLooper *
317 BHandler::Looper() const
318 {
319 	return fLooper;
320 }
321 
322 
323 void
324 BHandler::SetName(const char *name)
325 {
326 	if (fName != NULL) {
327 		free(fName);
328 		fName = NULL;
329 	}
330 
331 	if (name != NULL)
332 		fName = strdup(name);
333 }
334 
335 
336 const char *
337 BHandler::Name() const
338 {
339 	return fName;
340 }
341 
342 
343 void
344 BHandler::SetNextHandler(BHandler *handler)
345 {
346 	if (!fLooper) {
347 		debugger("handler must belong to looper before setting NextHandler");
348 		fNextHandler = NULL;
349 		return;
350 	}
351 
352 	if (!fLooper->IsLocked()) {
353 		debugger("The handler's looper must be locked before setting NextHandler");
354 		return;
355 	}
356 
357 	if (handler && fLooper != handler->Looper()) {
358 		debugger("The handler and its NextHandler must have the same looper");
359 		return;
360 	}
361 
362 	// NOTE: I'm sure some sort of threading protection should happen here,
363 	// hopefully the spec-mandated BLooper lock is sufficient.
364 	// TODO: implement correctly
365 	fNextHandler = handler;
366 }
367 
368 
369 BHandler *
370 BHandler::NextHandler() const
371 {
372 	return fNextHandler;
373 }
374 
375 
376 void
377 BHandler::AddFilter(BMessageFilter *filter)
378 {
379 	// NOTE:  Although the documentation states that the handler must belong to
380 	// a looper and the looper must be locked in order to use this method,
381 	// testing shows that this is not the case in the original implementation.
382 	// We may want to investigate enforcing these rules; it would be interesting
383 	// to see how many apps out there have violated the dictates of the docs.
384 	// For now, though, we'll play nicely.
385 #if 0
386 	if (!fLooper)
387 	{
388 		// TODO: error handling
389 		return false;
390 	}
391 
392 	if (!fLooper->IsLocked())
393 	{
394 		// TODO: error handling
395 		return false;
396 	}
397 #endif
398 
399 	if (fLooper != NULL)
400 		filter->SetLooper(fLooper);
401 
402 	if (!fFilters)
403 		fFilters = new BList;
404 
405 	fFilters->AddItem(filter);
406 }
407 
408 
409 bool
410 BHandler::RemoveFilter(BMessageFilter *filter)
411 {
412 	// NOTE:  Although the documentation states that the handler must belong to
413 	// a looper and the looper must be locked in order to use this method,
414 	// testing shows that this is not the case in the original implementation.
415 	// We may want to investigate enforcing these rules; it would be interesting
416 	// to see how many apps out there have violated the dictates of the docs.
417 	// For now, though, we'll play nicely.
418 #if 0
419 	if (!fLooper)
420 	{
421 		// TODO: error handling
422 		return false;
423 	}
424 
425 	if (!fLooper->IsLocked())
426 	{
427 		// TODO: error handling
428 		return false;
429 	}
430 #endif
431 
432 	if (fFilters != NULL && fFilters->RemoveItem((void *)filter)) {
433 		filter->SetLooper(NULL);
434 		return true;
435 	}
436 
437 	return false;
438 }
439 
440 
441 void
442 BHandler::SetFilterList(BList* filters)
443 {
444 	/**
445 		@note	Although the documentation states that the handler must belong to
446 				a looper and the looper must be locked in order to use this method,
447 				testing shows that this is not the case in the original implementation.
448 	 */
449 
450 #if 0
451 	if (!fLooper)
452 	{
453 		// TODO: error handling
454 		return;
455 	}
456 #endif
457 
458 	if (fLooper && !fLooper->IsLocked()) {
459 		debugger("Owning Looper must be locked before calling SetFilterList");
460 		return;
461 	}
462 
463 	/**
464 		@note	I would like to use BObjectList internally, but this function is
465 				spec'd such that fFilters would get deleted and then assigned
466 				'filters', which would obviously mess this up.  Wondering if
467 				anyone ever assigns a list of filters and then checks against
468 				FilterList() to see if they are the same.
469 	 */
470 
471 	// TODO: Explore issues with using BObjectList
472 	if (fFilters) {
473 		fFilters->DoForEach(FilterDeleter);
474 		delete fFilters;
475 	}
476 
477 	fFilters = filters;
478 	if (fFilters) {
479 		for (int32 i = 0; i < fFilters->CountItems(); ++i) {
480 			BMessageFilter *filter =
481 				static_cast<BMessageFilter *>(fFilters->ItemAt(i));
482 			if (filter != NULL)
483 				filter->SetLooper(fLooper);
484 		}
485 	}
486 }
487 
488 
489 BList *
490 BHandler::FilterList()
491 {
492 	return fFilters;
493 }
494 
495 
496 bool
497 BHandler::LockLooper()
498 {
499 	/**
500 		@note	BeBook says that this function "retrieves the handler's looper and
501 				unlocks it in a pseudo-atomic operation, thus avoiding a race
502 				condition."  How "pseudo-atomic" would look completely escapes me,
503 				so we'll go with the dumb version for now.  Maybe I should use a
504 				benaphore?
505 
506 				BeBook mentions handling the case where the handler's looper
507 				changes during this call.  I've attempted a "pseudo-atomic"
508 				operation to check that.
509 	 */
510 
511 	BLooper *looper = fLooper;
512 	if (looper) {
513 		bool result = looper->Lock();
514 
515 		// Are we still assigned to the same looper?
516 		if (fLooper == looper)
517 			return result;
518 
519 		if (result) {
520 			// Our looper is different, and the lock was successful on the old
521 			// one; undo the lock
522 			looper->Unlock();
523 		}
524 	}
525 
526 	return false;
527 }
528 
529 
530 status_t
531 BHandler::LockLooperWithTimeout(bigtime_t timeout)
532 {
533 	/**
534 		@note	BeBook says that this function "retrieves the handler's looper and
535 				unlocks it in a pseudo-atomic operation, thus avoiding a race
536 				condition."  How "pseudo-atomic" would look completely escapes me,
537 				so we'll go with the dumb version for now.  Maybe I should use a
538 				benaphore?
539 
540 				BeBook mentions handling the case where the handler's looper
541 				changes during this call.  I've attempted a "pseudo-atomic"
542 				operation to check for that.
543 	 */
544 
545 	BLooper *looper = fLooper;
546 	if (looper) {
547 		status_t result = looper->LockWithTimeout(timeout);
548 
549 		// Are we still assigned to the same looper?
550 		if (fLooper == looper)
551 			return result;
552 
553 		// Our looper changed during the lock attempt
554 		if (result == B_OK) {
555 			// The lock was successful on the old looper; undo the lock
556 			looper->Unlock();
557 		}
558 
559 		return B_MISMATCHED_VALUES;
560 	}
561 
562 	return B_BAD_VALUE;
563 }
564 
565 
566 void
567 BHandler::UnlockLooper()
568 {
569 	/**
570 		@note	BeBook says that this function "retrieves the handler's looper and
571 				unlocks it in a pseudo-atomic operation, thus avoiding a race
572 				condition."  How "pseudo-atomic" would look completely escapes me,
573 				so we'll go with the dumb version for now.  Maybe I should use a
574 				benaphore?
575 
576 				The solution I used for Lock() and LockWithTimeout() seems out of
577 				place here; if our looper does change while attempting to unlock it,
578 				re-Lock()ing the original looper just doesn't seem right.
579 	 */
580 
581 	// TODO: implement correctly
582 	BLooper *looper = fLooper;
583 	if (looper)
584 		looper->Unlock();
585 }
586 
587 
588 BHandler *
589 BHandler::ResolveSpecifier(BMessage *msg, int32 index,
590 	BMessage *specifier, int32 form, const char *property)
591 {
592 	// Straight from the BeBook
593 	BPropertyInfo propertyInfo(sHandlerPropInfo);
594 	if (propertyInfo.FindMatch(msg, index, specifier, form, property) >= 0)
595 		return this;
596 
597 	BMessage reply(B_MESSAGE_NOT_UNDERSTOOD);
598 	reply.AddInt32("error", B_BAD_SCRIPT_SYNTAX);
599 	reply.AddString("message", "Didn't understand the specifier(s)");
600 	msg->SendReply(&reply);
601 
602 	return NULL;
603 }
604 
605 
606 status_t
607 BHandler::GetSupportedSuites(BMessage *data)
608 {
609 /**
610 	@note	This is the output from the original implementation (calling
611 			PrintToStream() on both data and the contained BPropertyInfo):
612 
613 BMessage: what =  (0x0, or 0)
614     entry         suites, type='CSTR', c=1, size=21, data[0]: "suite/vnd.Be-handler"
615     entry       messages, type='SCTD', c=1, size= 0,
616       property   commands                       types                specifiers
617 --------------------------------------------------------------------------------
618         Suites   PGET                                               1
619                  (RTSC,suites)
620                  (DTCS,messages)
621 
622      Messenger   PGET                          GNSM                 1
623   InternalName   PGET                          RTSC                 1
624 
625 			With a good deal of trial and error, I determined that the
626 			parenthetical clauses are entries in the 'ctypes' field of
627 			property_info.  'ctypes' is an array of 'compound_type', which
628 			contains an array of 'field_pair's.  I haven't the foggiest what
629 			either 'compound_type' or 'field_pair' is for, being as the
630 			scripting docs are so bloody horrible.  The corresponding
631 			property_info array is declared in the globals section.
632  */
633 
634 	status_t err = B_OK;
635 	if (!data)
636 		err = B_BAD_VALUE;
637 
638 	if (!err) {
639 		err = data->AddString("suites", "suite/vnd.Be-handler");
640 		if (!err) {
641 			BPropertyInfo propertyInfo(sHandlerPropInfo);
642 			err = data->AddFlat("message", &propertyInfo);
643 		}
644 	}
645 
646 	return err;
647 }
648 
649 
650 status_t
651 BHandler::StartWatching(BMessenger messenger, uint32 what)
652 {
653 	if (fObserverList == NULL)
654 		fObserverList = new _ObserverList;
655 	return fObserverList->StartObserving(messenger, what);
656 }
657 
658 
659 status_t
660 BHandler::StartWatchingAll(BMessenger messenger)
661 {
662 	return StartWatching(messenger, B_OBSERVER_OBSERVE_ALL);
663 }
664 
665 
666 status_t
667 BHandler::StopWatching(BMessenger messenger, uint32 what)
668 {
669 	if (fObserverList == NULL)
670 		fObserverList = new _ObserverList;
671 	return fObserverList->StopObserving(messenger, what);
672 }
673 
674 
675 status_t
676 BHandler::StopWatchingAll(BMessenger messenger)
677 {
678 	return StopWatching(messenger, B_OBSERVER_OBSERVE_ALL);
679 }
680 
681 
682 status_t
683 BHandler::StartWatching(BHandler *handler, uint32 what)
684 {
685 	if (fObserverList == NULL)
686 		fObserverList = new _ObserverList;
687 	return fObserverList->StartObserving(handler, what);
688 }
689 
690 
691 status_t
692 BHandler::StartWatchingAll(BHandler *handler)
693 {
694 	return StartWatching(handler, B_OBSERVER_OBSERVE_ALL);
695 }
696 
697 
698 status_t
699 BHandler::StopWatching(BHandler *handler, uint32 what)
700 {
701 	if (fObserverList == NULL)
702 		fObserverList = new _ObserverList;
703 	return fObserverList->StopObserving(handler, what);
704 }
705 
706 
707 status_t
708 BHandler::StopWatchingAll(BHandler *handler)
709 {
710 	return StopWatching(handler, B_OBSERVER_OBSERVE_ALL);
711 }
712 
713 
714 status_t
715 BHandler::Perform(perform_code d, void *arg)
716 {
717 	return BArchivable::Perform(d, arg);
718 }
719 
720 
721 void
722 BHandler::SendNotices(uint32 what, const BMessage *msg)
723 {
724 	if (fObserverList != NULL)
725 		fObserverList->SendNotices(what, msg);
726 }
727 
728 
729 bool
730 BHandler::IsWatched() const
731 {
732 	return fObserverList && !fObserverList->IsEmpty();
733 }
734 
735 
736 void
737 BHandler::InitData(const char *name)
738 {
739 	SetName(name);
740 
741 	fLooper = NULL;
742 	fNextHandler = NULL;
743 	fFilters = NULL;
744 	fObserverList = NULL;
745 
746 	fToken = gDefaultTokens.NewToken(B_HANDLER_TOKEN, this);
747 }
748 
749 
750 BHandler::BHandler(const BHandler &)
751 {
752 	// No copy construction allowed.
753 }
754 
755 
756 BHandler &
757 BHandler::operator=(const BHandler &)
758 {
759 	// No assignments allowed.
760 	return *this;
761 }
762 
763 
764 void
765 BHandler::SetLooper(BLooper *looper)
766 {
767 	fLooper = looper;
768 
769 	if (fFilters) {
770 		for (int32 i = 0; i < fFilters->CountItems(); i++)
771 			static_cast<BMessageFilter *>(fFilters->ItemAtFast(i))->SetLooper(looper);
772 	}
773 }
774 
775 
776 #ifdef __INTEL__
777 // binary compatibility with R4.5
778 extern "C" void _ReservedHandler1__8BHandler(void) {}
779 #endif
780 
781 void BHandler::_ReservedHandler2() {}
782 void BHandler::_ReservedHandler3() {}
783 void BHandler::_ReservedHandler4() {}
784 
785 
786 //	#pragma mark -
787 
788 
789 _ObserverList::_ObserverList(void)
790 {
791 }
792 
793 
794 _ObserverList::~_ObserverList(void)
795 {
796 }
797 
798 
799 status_t
800 _ObserverList::SendNotices(unsigned long what, BMessage const *message)
801 {
802 	// Having to new a temporary is really irritating ...
803 	BMessage *copyMsg = NULL;
804 	if (message) {
805 		copyMsg = new BMessage(*message);
806 		copyMsg->what = B_OBSERVER_NOTICE_CHANGE;
807 		copyMsg->AddInt32(B_OBSERVE_ORIGINAL_WHAT, message->what);
808 	} else
809 		copyMsg = new BMessage(B_OBSERVER_NOTICE_CHANGE);
810 
811 	copyMsg->AddInt32(B_OBSERVE_WHAT_CHANGE, what);
812 
813 	vector<BHandler *> &handlers = fHandlerMap[what];
814 	for (uint32 i = 0; i < handlers.size(); ++i) {
815 		BMessenger msgr(handlers[i]);
816 		msgr.SendMessage(copyMsg);
817 	}
818 
819 	vector<BMessenger> &messengers = fMessengerMap[what];
820 	for (uint32 i = 0; i < messengers.size(); ++i)
821 		messengers[i].SendMessage(copyMsg);
822 
823 	// We have to send the message also to the handlers
824 	// and messengers which were subscribed to ALL events,
825 	// since they aren't caught by the above loops.
826 	// TODO: cleanup
827 	vector<BHandler *> &handlersAll = fHandlerMap[B_OBSERVER_OBSERVE_ALL];
828 	for (uint32 i = 0; i < handlersAll.size(); ++i) {
829 		BMessenger msgr(handlersAll[i]);
830 		msgr.SendMessage(copyMsg);
831 	}
832 
833 	vector<BMessenger> &messengersAll = fMessengerMap[B_OBSERVER_OBSERVE_ALL];
834 	for (uint32 i = 0; i < messengersAll.size(); ++i)
835 		messengers[i].SendMessage(copyMsg);
836 
837 	// Gotta make sure to clean up the annoying temporary ...
838 	delete copyMsg;
839 
840 	return B_OK;
841 }
842 
843 
844 status_t
845 _ObserverList::StartObserving(BHandler *handler, unsigned long what)
846 {
847 	if (handler == NULL)
848 		return B_BAD_HANDLER;
849 
850 	vector<BHandler*> &handlers = fHandlerMap[what];
851 
852 	vector<BHandler*>::iterator iter;
853 	iter = find(handlers.begin(), handlers.end(), handler);
854 	if (iter != handlers.end()) {
855 		// TODO: verify
856 		return B_OK;
857 	}
858 
859 	handlers.push_back(handler);
860 	return B_OK;
861 }
862 
863 
864 status_t
865 _ObserverList::StartObserving(const BMessenger &messenger,
866 	unsigned long what)
867 {
868 	vector<BMessenger> &messengers = fMessengerMap[what];
869 
870 	vector<BMessenger>::iterator iter;
871 	iter = find(messengers.begin(), messengers.end(), messenger);
872 	if (iter != messengers.end()) {
873 		// TODO: verify
874 		return B_OK;
875 	}
876 
877 	messengers.push_back(messenger);
878 	return B_OK;
879 }
880 
881 
882 status_t
883 _ObserverList::StopObserving(BHandler *handler, unsigned long what)
884 {
885 	if (handler == NULL)
886 		return B_BAD_HANDLER;
887 
888 	vector<BHandler*> &handlers = fHandlerMap[what];
889 
890 	vector<BHandler*>::iterator iter;
891 	iter = find(handlers.begin(), handlers.end(), handler);
892 	if (iter != handlers.end()) {
893 		handlers.erase(iter);
894 		if (handlers.empty())
895 			fHandlerMap.erase(what);
896 
897 		return B_OK;
898 	}
899 
900 	return B_BAD_HANDLER;
901 }
902 
903 
904 status_t
905 _ObserverList::StopObserving(const BMessenger &messenger,
906 	unsigned long what)
907 {
908 	// ???:	What if you call StartWatching(MyMsngr, aWhat) and then call
909 	//		StopWatchingAll(MyMsnger)?  Will MyMsnger be removed from the aWhat
910 	//		watcher list?  For now, we'll assume that they're discreet lists
911 	//		which do no cross checking; i.e., MyMsnger would *not* be removed in
912 	//		this scenario.
913 	vector<BMessenger> &messengers = fMessengerMap[what];
914 
915 	vector<BMessenger>::iterator iter;
916 	iter = find(messengers.begin(), messengers.end(), messenger);
917 	if (iter != messengers.end()) {
918 		messengers.erase(iter);
919 		if (messengers.empty())
920 			fMessengerMap.erase(what);
921 
922 		return B_OK;
923 	}
924 
925 	return B_BAD_HANDLER;
926 }
927 
928 
929 bool
930 _ObserverList::IsEmpty()
931 {
932 	return fHandlerMap.empty() && fMessengerMap.empty();
933 }
934 
935 
936 //	#pragma mark -
937 
938 
939 bool
940 FilterDeleter(void *_filter)
941 {
942 	delete static_cast<BMessageFilter *>(_filter);
943 	return false;
944 }
945 
946