xref: /haiku/src/kits/app/Handler.cpp (revision fef6144999c2fa611f59ee6ffe6dd7999501385c)
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 		// ToDo: take the handler's message filter into account!
322 		fNextHandler->MessageReceived(message);
323 	} else if (message->what != B_MESSAGE_NOT_UNDERSTOOD
324 		&& (message->WasDropped() || message->HasSpecifiers())) {
325 		printf("BHandler::MessageReceived(): B_MESSAGE_NOT_UNDERSTOOD");
326 		message->PrintToStream();
327 		message->SendReply(B_MESSAGE_NOT_UNDERSTOOD);
328 	}
329 }
330 
331 
332 BLooper *
333 BHandler::Looper() const
334 {
335 	return fLooper;
336 }
337 
338 
339 void
340 BHandler::SetName(const char *name)
341 {
342 	if (fName != NULL) {
343 		free(fName);
344 		fName = NULL;
345 	}
346 
347 	if (name != NULL)
348 		fName = strdup(name);
349 }
350 
351 
352 const char *
353 BHandler::Name() const
354 {
355 	return fName;
356 }
357 
358 
359 void
360 BHandler::SetNextHandler(BHandler *handler)
361 {
362 	if (!fLooper) {
363 		debugger("handler must belong to looper before setting NextHandler");
364 		fNextHandler = NULL;
365 		return;
366 	}
367 
368 	if (!fLooper->IsLocked()) {
369 		debugger("The handler's looper must be locked before setting NextHandler");
370 		return;
371 	}
372 
373 	if (handler && fLooper != handler->Looper()) {
374 		debugger("The handler and its NextHandler must have the same looper");
375 		return;
376 	}
377 
378 	// NOTE: I'm sure some sort of threading protection should happen here,
379 	// hopefully the spec-mandated BLooper lock is sufficient.
380 	// TODO: implement correctly
381 	fNextHandler = handler;
382 }
383 
384 
385 BHandler *
386 BHandler::NextHandler() const
387 {
388 	return fNextHandler;
389 }
390 
391 
392 void
393 BHandler::AddFilter(BMessageFilter *filter)
394 {
395 	// NOTE:  Although the documentation states that the handler must belong to
396 	// a looper and the looper must be locked in order to use this method,
397 	// testing shows that this is not the case in the original implementation.
398 	// We may want to investigate enforcing these rules; it would be interesting
399 	// to see how many apps out there have violated the dictates of the docs.
400 	// For now, though, we'll play nicely.
401 #if 0
402 	if (!fLooper)
403 	{
404 		// TODO: error handling
405 		return false;
406 	}
407 
408 	if (!fLooper->IsLocked())
409 	{
410 		// TODO: error handling
411 		return false;
412 	}
413 #endif
414 
415 	if (fLooper != NULL)
416 		filter->SetLooper(fLooper);
417 
418 	if (!fFilters)
419 		fFilters = new BList;
420 
421 	fFilters->AddItem(filter);
422 }
423 
424 
425 bool
426 BHandler::RemoveFilter(BMessageFilter *filter)
427 {
428 	// NOTE:  Although the documentation states that the handler must belong to
429 	// a looper and the looper must be locked in order to use this method,
430 	// testing shows that this is not the case in the original implementation.
431 	// We may want to investigate enforcing these rules; it would be interesting
432 	// to see how many apps out there have violated the dictates of the docs.
433 	// For now, though, we'll play nicely.
434 #if 0
435 	if (!fLooper)
436 	{
437 		// TODO: error handling
438 		return false;
439 	}
440 
441 	if (!fLooper->IsLocked())
442 	{
443 		// TODO: error handling
444 		return false;
445 	}
446 #endif
447 
448 	if (fFilters != NULL && fFilters->RemoveItem((void *)filter)) {
449 		filter->SetLooper(NULL);
450 		return true;
451 	}
452 
453 	return false;
454 }
455 
456 
457 void
458 BHandler::SetFilterList(BList* filters)
459 {
460 	/**
461 		@note	Although the documentation states that the handler must belong to
462 				a looper and the looper must be locked in order to use this method,
463 				testing shows that this is not the case in the original implementation.
464 	 */
465 
466 #if 0
467 	if (!fLooper)
468 	{
469 		// TODO: error handling
470 		return;
471 	}
472 #endif
473 
474 	if (fLooper && !fLooper->IsLocked()) {
475 		debugger("Owning Looper must be locked before calling SetFilterList");
476 		return;
477 	}
478 
479 	/**
480 		@note	I would like to use BObjectList internally, but this function is
481 				spec'd such that fFilters would get deleted and then assigned
482 				'filters', which would obviously mess this up.  Wondering if
483 				anyone ever assigns a list of filters and then checks against
484 				FilterList() to see if they are the same.
485 	 */
486 
487 	// TODO: Explore issues with using BObjectList
488 	if (fFilters) {
489 		fFilters->DoForEach(FilterDeleter);
490 		delete fFilters;
491 	}
492 
493 	fFilters = filters;
494 	if (fFilters) {
495 		for (int32 i = 0; i < fFilters->CountItems(); ++i) {
496 			BMessageFilter *filter =
497 				static_cast<BMessageFilter *>(fFilters->ItemAt(i));
498 			if (filter != NULL)
499 				filter->SetLooper(fLooper);
500 		}
501 	}
502 }
503 
504 
505 BList *
506 BHandler::FilterList()
507 {
508 	return fFilters;
509 }
510 
511 
512 bool
513 BHandler::LockLooper()
514 {
515 	/**
516 		@note	BeBook says that this function "retrieves the handler's looper and
517 				unlocks it in a pseudo-atomic operation, thus avoiding a race
518 				condition."  How "pseudo-atomic" would look completely escapes me,
519 				so we'll go with the dumb version for now.  Maybe I should use a
520 				benaphore?
521 
522 				BeBook mentions handling the case where the handler's looper
523 				changes during this call.  I've attempted a "pseudo-atomic"
524 				operation to check that.
525 	 */
526 
527 	BLooper *looper = fLooper;
528 	if (looper) {
529 		bool result = looper->Lock();
530 
531 		// Are we still assigned to the same looper?
532 		if (fLooper == looper)
533 			return result;
534 
535 		if (result) {
536 			// Our looper is different, and the lock was successful on the old
537 			// one; undo the lock
538 			looper->Unlock();
539 		}
540 	}
541 
542 	return false;
543 }
544 
545 
546 status_t
547 BHandler::LockLooperWithTimeout(bigtime_t timeout)
548 {
549 	/**
550 		@note	BeBook says that this function "retrieves the handler's looper and
551 				unlocks it in a pseudo-atomic operation, thus avoiding a race
552 				condition."  How "pseudo-atomic" would look completely escapes me,
553 				so we'll go with the dumb version for now.  Maybe I should use a
554 				benaphore?
555 
556 				BeBook mentions handling the case where the handler's looper
557 				changes during this call.  I've attempted a "pseudo-atomic"
558 				operation to check for that.
559 	 */
560 
561 	BLooper *looper = fLooper;
562 	if (looper) {
563 		status_t result = looper->LockWithTimeout(timeout);
564 
565 		// Are we still assigned to the same looper?
566 		if (fLooper == looper)
567 			return result;
568 
569 		// Our looper changed during the lock attempt
570 		if (result == B_OK) {
571 			// The lock was successful on the old looper; undo the lock
572 			looper->Unlock();
573 		}
574 
575 		return B_MISMATCHED_VALUES;
576 	}
577 
578 	return B_BAD_VALUE;
579 }
580 
581 
582 void
583 BHandler::UnlockLooper()
584 {
585 	/**
586 		@note	BeBook says that this function "retrieves the handler's looper and
587 				unlocks it in a pseudo-atomic operation, thus avoiding a race
588 				condition."  How "pseudo-atomic" would look completely escapes me,
589 				so we'll go with the dumb version for now.  Maybe I should use a
590 				benaphore?
591 
592 				The solution I used for Lock() and LockWithTimeout() seems out of
593 				place here; if our looper does change while attempting to unlock it,
594 				re-Lock()ing the original looper just doesn't seem right.
595 	 */
596 
597 	// TODO: implement correctly
598 	BLooper *looper = fLooper;
599 	if (looper)
600 		looper->Unlock();
601 }
602 
603 
604 BHandler *
605 BHandler::ResolveSpecifier(BMessage *msg, int32 index,
606 	BMessage *specifier, int32 form, const char *property)
607 {
608 	// Straight from the BeBook
609 	BPropertyInfo propertyInfo(sHandlerPropInfo);
610 	if (propertyInfo.FindMatch(msg, index, specifier, form, property) >= 0)
611 		return this;
612 
613 	BMessage reply(B_MESSAGE_NOT_UNDERSTOOD);
614 	reply.AddInt32("error", B_BAD_SCRIPT_SYNTAX);
615 	reply.AddString("message", "Didn't understand the specifier(s)");
616 	msg->SendReply(&reply);
617 
618 	return NULL;
619 }
620 
621 
622 status_t
623 BHandler::GetSupportedSuites(BMessage *data)
624 {
625 /**
626 	@note	This is the output from the original implementation (calling
627 			PrintToStream() on both data and the contained BPropertyInfo):
628 
629 BMessage: what =  (0x0, or 0)
630     entry         suites, type='CSTR', c=1, size=21, data[0]: "suite/vnd.Be-handler"
631     entry       messages, type='SCTD', c=1, size= 0,
632       property   commands                       types                specifiers
633 --------------------------------------------------------------------------------
634         Suites   PGET                                               1
635                  (RTSC,suites)
636                  (DTCS,messages)
637 
638      Messenger   PGET                          GNSM                 1
639   InternalName   PGET                          RTSC                 1
640 
641 			With a good deal of trial and error, I determined that the
642 			parenthetical clauses are entries in the 'ctypes' field of
643 			property_info.  'ctypes' is an array of 'compound_type', which
644 			contains an array of 'field_pair's.  I haven't the foggiest what
645 			either 'compound_type' or 'field_pair' is for, being as the
646 			scripting docs are so bloody horrible.  The corresponding
647 			property_info array is declared in the globals section.
648  */
649 
650 	status_t err = B_OK;
651 	if (!data)
652 		err = B_BAD_VALUE;
653 
654 	if (!err) {
655 		err = data->AddString("suites", "suite/vnd.Be-handler");
656 		if (!err) {
657 			BPropertyInfo propertyInfo(sHandlerPropInfo);
658 			err = data->AddFlat("message", &propertyInfo);
659 		}
660 	}
661 
662 	return err;
663 }
664 
665 
666 status_t
667 BHandler::StartWatching(BMessenger messenger, uint32 what)
668 {
669 	fObserverList ? fObserverList : fObserverList = new _ObserverList;
670 	return fObserverList->StartObserving(messenger, what);
671 }
672 
673 
674 status_t
675 BHandler::StartWatchingAll(BMessenger messenger)
676 {
677 	fObserverList ? fObserverList : fObserverList = new _ObserverList;
678 	return fObserverList->StartObserving(messenger, B_OBSERVER_OBSERVE_ALL);
679 }
680 
681 
682 status_t
683 BHandler::StopWatching(BMessenger messenger, uint32 what)
684 {
685 	fObserverList ? fObserverList : fObserverList = new _ObserverList;
686 	return fObserverList->StopObserving(messenger, what);
687 }
688 
689 
690 status_t
691 BHandler::StopWatchingAll(BMessenger messenger)
692 {
693 	fObserverList ? fObserverList : fObserverList = new _ObserverList;
694 	return fObserverList->StopObserving(messenger, B_OBSERVER_OBSERVE_ALL);
695 }
696 
697 
698 status_t
699 BHandler::StartWatching(BHandler *handler, uint32 what)
700 {
701 	if (fObserverList == NULL)
702 		fObserverList = new _ObserverList;
703 	return fObserverList->StartObserving(handler, what);
704 }
705 
706 
707 status_t
708 BHandler::StartWatchingAll(BHandler *handler)
709 {
710 	return StartWatching(handler, B_OBSERVER_OBSERVE_ALL);
711 }
712 
713 
714 status_t
715 BHandler::StopWatching(BHandler *handler, uint32 what)
716 {
717 	fObserverList ? fObserverList : fObserverList = new _ObserverList;
718 	return fObserverList->StopObserving(handler, what);
719 }
720 
721 
722 status_t
723 BHandler::StopWatchingAll(BHandler *handler)
724 {
725 	fObserverList ? fObserverList : fObserverList = new _ObserverList;
726 	return fObserverList->StopObserving(handler, B_OBSERVER_OBSERVE_ALL);
727 }
728 
729 
730 status_t
731 BHandler::Perform(perform_code d, void *arg)
732 {
733 	return BArchivable::Perform(d, arg);
734 }
735 
736 
737 void
738 BHandler::SendNotices(uint32 what, const BMessage *msg)
739 {
740 	if (fObserverList != NULL)
741 		fObserverList->SendNotices(what, msg);
742 }
743 
744 
745 bool
746 BHandler::IsWatched() const
747 {
748 	return fObserverList && !fObserverList->IsEmpty();
749 }
750 
751 
752 void
753 BHandler::InitData(const char *name)
754 {
755 	SetName(name);
756 
757 	fLooper = NULL;
758 	fNextHandler = NULL;
759 	fFilters = NULL;
760 	fObserverList = NULL;
761 
762 	fToken = gDefaultTokens.NewToken(B_HANDLER_TOKEN, this);
763 }
764 
765 
766 BHandler::BHandler(const BHandler &)
767 {
768 	// No copy construction allowed.
769 }
770 
771 
772 BHandler &
773 BHandler::operator=(const BHandler &)
774 {
775 	// No assignments allowed.
776 	return *this;
777 }
778 
779 
780 void
781 BHandler::SetLooper(BLooper *looper)
782 {
783 	fLooper = looper;
784 
785 	if (fFilters) {
786 		for (int32 i = 0; i < fFilters->CountItems(); i++)
787 			static_cast<BMessageFilter *>(fFilters->ItemAtFast(i))->SetLooper(looper);
788 	}
789 }
790 
791 
792 #ifdef __INTEL__
793 // binary compatibility with R4.5
794 extern "C" void _ReservedHandler1__8BHandler(void) {}
795 #endif
796 
797 void BHandler::_ReservedHandler2() {}
798 void BHandler::_ReservedHandler3() {}
799 void BHandler::_ReservedHandler4() {}
800 
801 
802 //	#pragma mark -
803 
804 
805 _ObserverList::_ObserverList(void)
806 {
807 }
808 
809 
810 _ObserverList::~_ObserverList(void)
811 {
812 }
813 
814 
815 status_t
816 _ObserverList::SendNotices(unsigned long what, BMessage const *message)
817 {
818 	// Having to new a temporary is really irritating ...
819 	BMessage *copyMsg = NULL;
820 	if (message) {
821 		copyMsg = new BMessage(*message);
822 		copyMsg->what = B_OBSERVER_NOTICE_CHANGE;
823 		copyMsg->AddInt32(B_OBSERVE_ORIGINAL_WHAT, message->what);
824 	} else
825 		copyMsg = new BMessage(B_OBSERVER_NOTICE_CHANGE);
826 
827 	copyMsg->AddInt32(B_OBSERVE_WHAT_CHANGE, what);
828 
829 	vector<BHandler *> &handlers = fHandlerMap[what];
830 	for (uint32 i = 0; i < handlers.size(); ++i) {
831 		BMessenger msgr(handlers[i]);
832 		msgr.SendMessage(copyMsg);
833 	}
834 
835 	vector<BMessenger> &messengers = fMessengerMap[what];
836 	for (uint32 i = 0; i < messengers.size(); ++i)
837 		messengers[i].SendMessage(copyMsg);
838 
839 	// We have to send the message also to the handlers
840 	// and messengers which were subscribed to ALL events,
841 	// since they aren't caught by the above loops.
842 	// TODO: cleanup
843 	vector<BHandler *> &handlersAll = fHandlerMap[B_OBSERVER_OBSERVE_ALL];
844 	for (uint32 i = 0; i < handlersAll.size(); ++i) {
845 		BMessenger msgr(handlersAll[i]);
846 		msgr.SendMessage(copyMsg);
847 	}
848 
849 	vector<BMessenger> &messengersAll = fMessengerMap[B_OBSERVER_OBSERVE_ALL];
850 	for (uint32 i = 0; i < messengersAll.size(); ++i)
851 		messengers[i].SendMessage(copyMsg);
852 
853 	// Gotta make sure to clean up the annoying temporary ...
854 	delete copyMsg;
855 
856 	return B_OK;
857 }
858 
859 
860 status_t
861 _ObserverList::StartObserving(BHandler *handler, unsigned long what)
862 {
863 	if (handler == NULL)
864 		return B_BAD_HANDLER;
865 
866 	vector<BHandler*> &handlers = fHandlerMap[what];
867 
868 	vector<BHandler*>::iterator iter;
869 	iter = find(handlers.begin(), handlers.end(), handler);
870 	if (iter != handlers.end()) {
871 		// TODO: verify
872 		return B_OK;
873 	}
874 
875 	handlers.push_back(handler);
876 	return B_OK;
877 }
878 
879 
880 status_t
881 _ObserverList::StartObserving(const BMessenger &messenger,
882 	unsigned long what)
883 {
884 	vector<BMessenger> &messengers = fMessengerMap[what];
885 
886 	vector<BMessenger>::iterator iter;
887 	iter = find(messengers.begin(), messengers.end(), messenger);
888 	if (iter != messengers.end()) {
889 		// TODO: verify
890 		return B_OK;
891 	}
892 
893 	messengers.push_back(messenger);
894 	return B_OK;
895 }
896 
897 
898 status_t
899 _ObserverList::StopObserving(BHandler *handler, unsigned long what)
900 {
901 	if (handler == NULL)
902 		return B_BAD_HANDLER;
903 
904 	vector<BHandler*> &handlers = fHandlerMap[what];
905 
906 	vector<BHandler*>::iterator iter;
907 	iter = find(handlers.begin(), handlers.end(), handler);
908 	if (iter != handlers.end()) {
909 		handlers.erase(iter);
910 		if (handlers.empty())
911 			fHandlerMap.erase(what);
912 
913 		return B_OK;
914 	}
915 
916 	return B_BAD_HANDLER;
917 }
918 
919 
920 status_t
921 _ObserverList::StopObserving(const BMessenger &messenger,
922 	unsigned long what)
923 {
924 	// ???:	What if you call StartWatching(MyMsngr, aWhat) and then call
925 	//		StopWatchingAll(MyMsnger)?  Will MyMsnger be removed from the aWhat
926 	//		watcher list?  For now, we'll assume that they're discreet lists
927 	//		which do no cross checking; i.e., MyMsnger would *not* be removed in
928 	//		this scenario.
929 	vector<BMessenger> &messengers = fMessengerMap[what];
930 
931 	vector<BMessenger>::iterator iter;
932 	iter = find(messengers.begin(), messengers.end(), messenger);
933 	if (iter != messengers.end()) {
934 		messengers.erase(iter);
935 		if (messengers.empty())
936 			fMessengerMap.erase(what);
937 
938 		return B_OK;
939 	}
940 
941 	return B_BAD_HANDLER;
942 }
943 
944 
945 bool
946 _ObserverList::IsEmpty()
947 {
948 	return fHandlerMap.empty() && fMessengerMap.empty();
949 }
950 
951 
952 //	#pragma mark -
953 
954 
955 bool
956 FilterDeleter(void *_filter)
957 {
958 	delete static_cast<BMessageFilter *>(_filter);
959 	return false;
960 }
961 
962