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