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