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