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