1 /* 2 * Copyright 2001-2006, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Erik Jaesler (erik@cgsoftware.com) 7 * Axel Dörfler, axeld@pinc-software.de 8 */ 9 10 11 #include <TokenSpace.h> 12 13 #include <AppDefs.h> 14 #include <Handler.h> 15 #include <Looper.h> 16 #include <Message.h> 17 #include <MessageFilter.h> 18 #include <Messenger.h> 19 #include <PropertyInfo.h> 20 21 #include <algorithm> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <vector> 25 26 using std::map; 27 using std::vector; 28 using BPrivate::gDefaultTokens; 29 30 31 static const char *kArchiveNameField = "_name"; 32 33 static property_info sHandlerPropInfo[] = { 34 { 35 "Suites", // name 36 { B_GET_PROPERTY }, // commands 37 { B_DIRECT_SPECIFIER }, // specifiers 38 NULL, // usage 39 0, // extra data 40 { 0 }, // types 41 { // ctypes (compound_type) 42 { // ctypes[0] 43 { // pairs[0] 44 { 45 "suites", // name 46 B_STRING_TYPE // type 47 } 48 } 49 }, 50 { // ctypes[1] 51 { // pairs[0] 52 { 53 "messages", 54 B_PROPERTY_INFO_TYPE 55 } 56 } 57 } 58 }, 59 {} // reserved 60 }, 61 { 62 "Messenger", 63 { B_GET_PROPERTY }, 64 { B_DIRECT_SPECIFIER }, 65 NULL, 0, 66 { B_MESSENGER_TYPE }, 67 {}, 68 {} 69 }, 70 { 71 "InternalName", 72 { B_GET_PROPERTY }, 73 { B_DIRECT_SPECIFIER }, 74 NULL, 0, 75 { B_STRING_TYPE }, 76 {}, 77 {} 78 }, 79 {} 80 }; 81 82 bool FilterDeleter(void *filter); 83 84 typedef map<unsigned long, vector<BHandler *> > THandlerObserverMap; 85 typedef map<unsigned long, vector<BMessenger> > TMessengerObserverMap; 86 87 //------------------------------------------------------------------------------ 88 // TODO: Change to BPrivate::BObserverList if possible 89 class _ObserverList { 90 public: 91 _ObserverList(void); 92 ~_ObserverList(void); 93 94 status_t SendNotices(unsigned long, BMessage const *); 95 status_t StartObserving(BHandler *, unsigned long); 96 status_t StartObserving(const BMessenger&, unsigned long); 97 status_t StopObserving(BHandler *, unsigned long); 98 status_t StopObserving(const BMessenger&, unsigned long); 99 bool IsEmpty(); 100 101 private: 102 THandlerObserverMap fHandlerMap; 103 TMessengerObserverMap fMessengerMap; 104 }; 105 106 107 // #pragma mark - 108 109 110 BHandler::BHandler(const char *name) 111 : BArchivable(), 112 fName(NULL) 113 { 114 InitData(name); 115 } 116 117 118 BHandler::~BHandler() 119 { 120 // remove all filters 121 if (fFilters) { 122 int32 count = fFilters->CountItems(); 123 for (int32 i = 0; i < count; i++) 124 delete (BMessageFilter*)fFilters->ItemAtFast(i); 125 delete fFilters; 126 } 127 128 // remove all observers (the observer list manages itself) 129 delete fObserverList; 130 131 // free rest 132 free(fName); 133 gDefaultTokens.RemoveToken(fToken); 134 } 135 136 137 BHandler::BHandler(BMessage *data) 138 : BArchivable(data), 139 fName(NULL) 140 { 141 const char *name = NULL; 142 143 if (data) 144 data->FindString(kArchiveNameField, &name); 145 146 InitData(name); 147 } 148 149 150 BArchivable * 151 BHandler::Instantiate(BMessage *data) 152 { 153 if (!validate_instantiation(data, "BHandler")) 154 return NULL; 155 156 return new BHandler(data); 157 } 158 159 160 status_t 161 BHandler::Archive(BMessage *data, bool deep) const 162 { 163 status_t status = BArchivable::Archive(data, deep); 164 if (status < B_OK) 165 return status; 166 167 return data->AddString(kArchiveNameField, fName); 168 } 169 170 171 void 172 BHandler::MessageReceived(BMessage *message) 173 { 174 BMessage reply(B_REPLY); 175 176 switch (message->what) { 177 // ToDo: am I missing something or is the "observed" stuff handshake completely missing? 178 179 case B_GET_PROPERTY: 180 { 181 int32 cur; 182 BMessage specifier; 183 int32 form; 184 const char *prop; 185 186 status_t err = message->GetCurrentSpecifier(&cur, &specifier, &form, &prop); 187 if (err == B_OK) { 188 bool known = false; 189 if (strcmp(prop, "Suites") == 0) { 190 err = GetSupportedSuites(&reply); 191 known = true; 192 } else if (strcmp(prop, "Messenger") == 0) { 193 err = reply.AddMessenger("result", this); 194 known = true; 195 } else if (strcmp(prop, "InternalName") == 0) { 196 err = reply.AddString("result", Name()); 197 known = true; 198 } 199 200 if (known) { 201 reply.AddInt32("error", B_OK); 202 message->SendReply(&reply); 203 return; 204 } 205 // let's try next handler 206 } 207 break; 208 } 209 210 case B_GET_SUPPORTED_SUITES: 211 { 212 reply.AddInt32("error", GetSupportedSuites(&reply)); 213 message->SendReply(&reply); 214 return; 215 } 216 } 217 218 // ToDo: there is some more work needed here (someone in the know should fill in)! 219 220 if (fNextHandler) { 221 // we need to apply the next handler's filters here, too 222 BHandler* target = Looper()->_HandlerFilter(message, fNextHandler); 223 if (target != NULL && target != this) { 224 // TODO: we also need to make sure that "target" is not before 225 // us in the handler chain - at least in case it wasn't before 226 // the handler actually targeted with this message - this could 227 // get ugly, though. 228 target->MessageReceived(message); 229 } 230 } else if (message->what != B_MESSAGE_NOT_UNDERSTOOD 231 && (message->WasDropped() || message->HasSpecifiers())) { 232 printf("BHandler %s: MessageReceived() couldn't understand the message:\n", Name()); 233 message->PrintToStream(); 234 message->SendReply(B_MESSAGE_NOT_UNDERSTOOD); 235 } 236 } 237 238 239 BLooper * 240 BHandler::Looper() const 241 { 242 return fLooper; 243 } 244 245 246 void 247 BHandler::SetName(const char *name) 248 { 249 if (fName != NULL) { 250 free(fName); 251 fName = NULL; 252 } 253 254 if (name != NULL) 255 fName = strdup(name); 256 } 257 258 259 const char * 260 BHandler::Name() const 261 { 262 return fName; 263 } 264 265 266 void 267 BHandler::SetNextHandler(BHandler *handler) 268 { 269 if (!fLooper) { 270 debugger("handler must belong to looper before setting NextHandler"); 271 return; 272 } 273 274 if (!fLooper->IsLocked()) { 275 debugger("The handler's looper must be locked before setting NextHandler"); 276 return; 277 } 278 279 if (handler && fLooper != handler->Looper()) { 280 debugger("The handler and its NextHandler must have the same looper"); 281 return; 282 } 283 284 fNextHandler = handler; 285 } 286 287 288 BHandler * 289 BHandler::NextHandler() const 290 { 291 return fNextHandler; 292 } 293 294 295 void 296 BHandler::AddFilter(BMessageFilter *filter) 297 { 298 if (fLooper && !fLooper->IsLocked()) { 299 debugger("Owning Looper must be locked before calling SetFilterList"); 300 return; 301 } 302 303 if (fLooper != NULL) 304 filter->SetLooper(fLooper); 305 306 if (!fFilters) 307 fFilters = new BList; 308 309 fFilters->AddItem(filter); 310 } 311 312 313 bool 314 BHandler::RemoveFilter(BMessageFilter *filter) 315 { 316 if (fLooper && !fLooper->IsLocked()) { 317 debugger("Owning Looper must be locked before calling SetFilterList"); 318 return false; 319 } 320 321 if (fFilters != NULL && fFilters->RemoveItem((void *)filter)) { 322 filter->SetLooper(NULL); 323 return true; 324 } 325 326 return false; 327 } 328 329 330 void 331 BHandler::SetFilterList(BList* filters) 332 { 333 if (fLooper && !fLooper->IsLocked()) { 334 debugger("Owning Looper must be locked before calling SetFilterList"); 335 return; 336 } 337 338 /** 339 @note I would like to use BObjectList internally, but this function is 340 spec'd such that fFilters would get deleted and then assigned 341 'filters', which would obviously mess this up. Wondering if 342 anyone ever assigns a list of filters and then checks against 343 FilterList() to see if they are the same. 344 */ 345 346 // TODO: Explore issues with using BObjectList 347 if (fFilters) { 348 fFilters->DoForEach(FilterDeleter); 349 delete fFilters; 350 } 351 352 fFilters = filters; 353 if (fFilters) { 354 for (int32 i = 0; i < fFilters->CountItems(); ++i) { 355 BMessageFilter *filter = 356 static_cast<BMessageFilter *>(fFilters->ItemAt(i)); 357 if (filter != NULL) 358 filter->SetLooper(fLooper); 359 } 360 } 361 } 362 363 364 BList * 365 BHandler::FilterList() 366 { 367 return fFilters; 368 } 369 370 371 bool 372 BHandler::LockLooper() 373 { 374 BLooper *looper = fLooper; 375 // Locking the looper also makes sure that the looper is valid 376 if (looper != NULL && looper->Lock()) { 377 // Have we locked the right looper? That's as far as the 378 // "pseudo-atomic" operation mentioned in the BeBook. 379 if (fLooper == looper) 380 return true; 381 382 // we locked the wrong looper, bail out 383 looper->Unlock(); 384 } 385 386 return false; 387 } 388 389 390 status_t 391 BHandler::LockLooperWithTimeout(bigtime_t timeout) 392 { 393 BLooper *looper = fLooper; 394 if (looper == NULL) 395 return B_BAD_VALUE; 396 397 status_t status = looper->LockWithTimeout(timeout); 398 if (status != B_OK) 399 return status; 400 401 if (fLooper != looper) { 402 // we locked the wrong looper, bail out 403 looper->Unlock(); 404 return B_MISMATCHED_VALUES; 405 } 406 407 return B_OK; 408 } 409 410 411 void 412 BHandler::UnlockLooper() 413 { 414 // The looper is locked at this point, and cannot change 415 if (fLooper != NULL) 416 fLooper->Unlock(); 417 } 418 419 420 BHandler * 421 BHandler::ResolveSpecifier(BMessage *msg, int32 index, 422 BMessage *specifier, int32 form, const char *property) 423 { 424 // Straight from the BeBook 425 BPropertyInfo propertyInfo(sHandlerPropInfo); 426 if (propertyInfo.FindMatch(msg, index, specifier, form, property) >= 0) 427 return this; 428 429 BMessage reply(B_MESSAGE_NOT_UNDERSTOOD); 430 reply.AddInt32("error", B_BAD_SCRIPT_SYNTAX); 431 reply.AddString("message", "Didn't understand the specifier(s)"); 432 msg->SendReply(&reply); 433 434 return NULL; 435 } 436 437 438 status_t 439 BHandler::GetSupportedSuites(BMessage *data) 440 { 441 /** 442 @note This is the output from the original implementation (calling 443 PrintToStream() on both data and the contained BPropertyInfo): 444 445 BMessage: what = (0x0, or 0) 446 entry suites, type='CSTR', c=1, size=21, data[0]: "suite/vnd.Be-handler" 447 entry messages, type='SCTD', c=1, size= 0, 448 property commands types specifiers 449 -------------------------------------------------------------------------------- 450 Suites PGET 1 451 (RTSC,suites) 452 (DTCS,messages) 453 454 Messenger PGET GNSM 1 455 InternalName PGET RTSC 1 456 457 With a good deal of trial and error, I determined that the 458 parenthetical clauses are entries in the 'ctypes' field of 459 property_info. 'ctypes' is an array of 'compound_type', which 460 contains an array of 'field_pair's. I haven't the foggiest what 461 either 'compound_type' or 'field_pair' is for, being as the 462 scripting docs are so bloody horrible. The corresponding 463 property_info array is declared in the globals section. 464 */ 465 466 status_t err = B_OK; 467 if (!data) 468 err = B_BAD_VALUE; 469 470 if (!err) { 471 err = data->AddString("suites", "suite/vnd.Be-handler"); 472 if (!err) { 473 BPropertyInfo propertyInfo(sHandlerPropInfo); 474 err = data->AddFlat("messages", &propertyInfo); 475 } 476 } 477 478 return err; 479 } 480 481 482 status_t 483 BHandler::StartWatching(BMessenger messenger, uint32 what) 484 { 485 if (fObserverList == NULL) 486 fObserverList = new _ObserverList; 487 return fObserverList->StartObserving(messenger, what); 488 } 489 490 491 status_t 492 BHandler::StartWatchingAll(BMessenger messenger) 493 { 494 return StartWatching(messenger, B_OBSERVER_OBSERVE_ALL); 495 } 496 497 498 status_t 499 BHandler::StopWatching(BMessenger messenger, uint32 what) 500 { 501 if (fObserverList == NULL) 502 fObserverList = new _ObserverList; 503 return fObserverList->StopObserving(messenger, what); 504 } 505 506 507 status_t 508 BHandler::StopWatchingAll(BMessenger messenger) 509 { 510 return StopWatching(messenger, B_OBSERVER_OBSERVE_ALL); 511 } 512 513 514 status_t 515 BHandler::StartWatching(BHandler *handler, uint32 what) 516 { 517 if (fObserverList == NULL) 518 fObserverList = new _ObserverList; 519 return fObserverList->StartObserving(handler, what); 520 } 521 522 523 status_t 524 BHandler::StartWatchingAll(BHandler *handler) 525 { 526 return StartWatching(handler, B_OBSERVER_OBSERVE_ALL); 527 } 528 529 530 status_t 531 BHandler::StopWatching(BHandler *handler, uint32 what) 532 { 533 if (fObserverList == NULL) 534 fObserverList = new _ObserverList; 535 return fObserverList->StopObserving(handler, what); 536 } 537 538 539 status_t 540 BHandler::StopWatchingAll(BHandler *handler) 541 { 542 return StopWatching(handler, B_OBSERVER_OBSERVE_ALL); 543 } 544 545 546 status_t 547 BHandler::Perform(perform_code d, void *arg) 548 { 549 return BArchivable::Perform(d, arg); 550 } 551 552 553 void 554 BHandler::SendNotices(uint32 what, const BMessage *msg) 555 { 556 if (fObserverList != NULL) 557 fObserverList->SendNotices(what, msg); 558 } 559 560 561 bool 562 BHandler::IsWatched() const 563 { 564 return fObserverList && !fObserverList->IsEmpty(); 565 } 566 567 568 void 569 BHandler::InitData(const char *name) 570 { 571 SetName(name); 572 573 fLooper = NULL; 574 fNextHandler = NULL; 575 fFilters = NULL; 576 fObserverList = NULL; 577 578 fToken = gDefaultTokens.NewToken(B_HANDLER_TOKEN, this); 579 } 580 581 582 BHandler::BHandler(const BHandler &) 583 { 584 // No copy construction allowed. 585 } 586 587 588 BHandler & 589 BHandler::operator=(const BHandler &) 590 { 591 // No assignments allowed. 592 return *this; 593 } 594 595 596 void 597 BHandler::SetLooper(BLooper *looper) 598 { 599 fLooper = looper; 600 601 if (fFilters) { 602 for (int32 i = 0; i < fFilters->CountItems(); i++) 603 static_cast<BMessageFilter *>(fFilters->ItemAtFast(i))->SetLooper(looper); 604 } 605 } 606 607 608 #ifdef __INTEL__ 609 // binary compatibility with R4.5 610 extern "C" void _ReservedHandler1__8BHandler(void) {} 611 #endif 612 613 void BHandler::_ReservedHandler2() {} 614 void BHandler::_ReservedHandler3() {} 615 void BHandler::_ReservedHandler4() {} 616 617 618 // #pragma mark - 619 620 621 _ObserverList::_ObserverList(void) 622 { 623 } 624 625 626 _ObserverList::~_ObserverList(void) 627 { 628 } 629 630 631 status_t 632 _ObserverList::SendNotices(unsigned long what, BMessage const *message) 633 { 634 // Having to new a temporary is really irritating ... 635 BMessage *copyMsg = NULL; 636 if (message) { 637 copyMsg = new BMessage(*message); 638 copyMsg->what = B_OBSERVER_NOTICE_CHANGE; 639 copyMsg->AddInt32(B_OBSERVE_ORIGINAL_WHAT, message->what); 640 } else 641 copyMsg = new BMessage(B_OBSERVER_NOTICE_CHANGE); 642 643 copyMsg->AddInt32(B_OBSERVE_WHAT_CHANGE, what); 644 645 vector<BHandler *> &handlers = fHandlerMap[what]; 646 for (uint32 i = 0; i < handlers.size(); ++i) { 647 BMessenger msgr(handlers[i]); 648 msgr.SendMessage(copyMsg); 649 } 650 651 vector<BMessenger> &messengers = fMessengerMap[what]; 652 for (uint32 i = 0; i < messengers.size(); ++i) 653 messengers[i].SendMessage(copyMsg); 654 655 // We have to send the message also to the handlers 656 // and messengers which were subscribed to ALL events, 657 // since they aren't caught by the above loops. 658 // TODO: cleanup 659 vector<BHandler *> &handlersAll = fHandlerMap[B_OBSERVER_OBSERVE_ALL]; 660 for (uint32 i = 0; i < handlersAll.size(); ++i) { 661 BMessenger msgr(handlersAll[i]); 662 msgr.SendMessage(copyMsg); 663 } 664 665 vector<BMessenger> &messengersAll = fMessengerMap[B_OBSERVER_OBSERVE_ALL]; 666 for (uint32 i = 0; i < messengersAll.size(); ++i) 667 messengers[i].SendMessage(copyMsg); 668 669 // Gotta make sure to clean up the annoying temporary ... 670 delete copyMsg; 671 672 return B_OK; 673 } 674 675 676 status_t 677 _ObserverList::StartObserving(BHandler *handler, unsigned long what) 678 { 679 if (handler == NULL) 680 return B_BAD_HANDLER; 681 682 vector<BHandler*> &handlers = fHandlerMap[what]; 683 684 vector<BHandler*>::iterator iter; 685 iter = find(handlers.begin(), handlers.end(), handler); 686 if (iter != handlers.end()) { 687 // TODO: verify 688 return B_OK; 689 } 690 691 handlers.push_back(handler); 692 return B_OK; 693 } 694 695 696 status_t 697 _ObserverList::StartObserving(const BMessenger &messenger, 698 unsigned long what) 699 { 700 vector<BMessenger> &messengers = fMessengerMap[what]; 701 702 vector<BMessenger>::iterator iter; 703 iter = find(messengers.begin(), messengers.end(), messenger); 704 if (iter != messengers.end()) { 705 // TODO: verify 706 return B_OK; 707 } 708 709 messengers.push_back(messenger); 710 return B_OK; 711 } 712 713 714 status_t 715 _ObserverList::StopObserving(BHandler *handler, unsigned long what) 716 { 717 if (handler == NULL) 718 return B_BAD_HANDLER; 719 720 vector<BHandler*> &handlers = fHandlerMap[what]; 721 722 vector<BHandler*>::iterator iter; 723 iter = find(handlers.begin(), handlers.end(), handler); 724 if (iter != handlers.end()) { 725 handlers.erase(iter); 726 if (handlers.empty()) 727 fHandlerMap.erase(what); 728 729 return B_OK; 730 } 731 732 return B_BAD_HANDLER; 733 } 734 735 736 status_t 737 _ObserverList::StopObserving(const BMessenger &messenger, 738 unsigned long what) 739 { 740 // ???: What if you call StartWatching(MyMsngr, aWhat) and then call 741 // StopWatchingAll(MyMsnger)? Will MyMsnger be removed from the aWhat 742 // watcher list? For now, we'll assume that they're discreet lists 743 // which do no cross checking; i.e., MyMsnger would *not* be removed in 744 // this scenario. 745 vector<BMessenger> &messengers = fMessengerMap[what]; 746 747 vector<BMessenger>::iterator iter; 748 iter = find(messengers.begin(), messengers.end(), messenger); 749 if (iter != messengers.end()) { 750 messengers.erase(iter); 751 if (messengers.empty()) 752 fMessengerMap.erase(what); 753 754 return B_OK; 755 } 756 757 return B_BAD_HANDLER; 758 } 759 760 761 bool 762 _ObserverList::IsEmpty() 763 { 764 return fHandlerMap.empty() && fMessengerMap.empty(); 765 } 766 767 768 // #pragma mark - 769 770 771 bool 772 FilterDeleter(void *_filter) 773 { 774 delete static_cast<BMessageFilter *>(_filter); 775 return false; 776 } 777 778