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 bool known = false; 188 if (cur < 0 || (strcmp(prop, "Messenger") == 0)) { 189 err = reply.AddMessenger("result", this); 190 known = true; 191 } else if (strcmp(prop, "Suites") == 0) { 192 err = GetSupportedSuites(&reply); 193 known = true; 194 } else if (strcmp(prop, "InternalName") == 0) { 195 err = reply.AddString("result", Name()); 196 known = true; 197 } 198 199 if (known) { 200 reply.AddInt32("error", B_OK); 201 message->SendReply(&reply); 202 return; 203 } 204 // let's try next handler 205 break; 206 } 207 208 case B_GET_SUPPORTED_SUITES: 209 { 210 reply.AddInt32("error", GetSupportedSuites(&reply)); 211 message->SendReply(&reply); 212 return; 213 } 214 } 215 216 // ToDo: there is some more work needed here (someone in the know should fill in)! 217 218 if (fNextHandler) { 219 // we need to apply the next handler's filters here, too 220 BHandler* target = Looper()->_HandlerFilter(message, fNextHandler); 221 if (target != NULL && target != this) { 222 // TODO: we also need to make sure that "target" is not before 223 // us in the handler chain - at least in case it wasn't before 224 // the handler actually targeted with this message - this could 225 // get ugly, though. 226 target->MessageReceived(message); 227 } 228 } else if (message->what != B_MESSAGE_NOT_UNDERSTOOD 229 && (message->WasDropped() || message->HasSpecifiers())) { 230 printf("BHandler %s: MessageReceived() couldn't understand the message:\n", Name()); 231 message->PrintToStream(); 232 message->SendReply(B_MESSAGE_NOT_UNDERSTOOD); 233 } 234 } 235 236 237 BLooper * 238 BHandler::Looper() const 239 { 240 return fLooper; 241 } 242 243 244 void 245 BHandler::SetName(const char *name) 246 { 247 if (fName != NULL) { 248 free(fName); 249 fName = NULL; 250 } 251 252 if (name != NULL) 253 fName = strdup(name); 254 } 255 256 257 const char * 258 BHandler::Name() const 259 { 260 return fName; 261 } 262 263 264 void 265 BHandler::SetNextHandler(BHandler *handler) 266 { 267 if (!fLooper) { 268 debugger("handler must belong to looper before setting NextHandler"); 269 return; 270 } 271 272 if (!fLooper->IsLocked()) { 273 debugger("The handler's looper must be locked before setting NextHandler"); 274 return; 275 } 276 277 if (handler && fLooper != handler->Looper()) { 278 debugger("The handler and its NextHandler must have the same looper"); 279 return; 280 } 281 282 fNextHandler = handler; 283 } 284 285 286 BHandler * 287 BHandler::NextHandler() const 288 { 289 return fNextHandler; 290 } 291 292 293 void 294 BHandler::AddFilter(BMessageFilter *filter) 295 { 296 if (fLooper && !fLooper->IsLocked()) { 297 debugger("Owning Looper must be locked before calling SetFilterList"); 298 return; 299 } 300 301 if (fLooper != NULL) 302 filter->SetLooper(fLooper); 303 304 if (!fFilters) 305 fFilters = new BList; 306 307 fFilters->AddItem(filter); 308 } 309 310 311 bool 312 BHandler::RemoveFilter(BMessageFilter *filter) 313 { 314 if (fLooper && !fLooper->IsLocked()) { 315 debugger("Owning Looper must be locked before calling SetFilterList"); 316 return false; 317 } 318 319 if (fFilters != NULL && fFilters->RemoveItem((void *)filter)) { 320 filter->SetLooper(NULL); 321 return true; 322 } 323 324 return false; 325 } 326 327 328 void 329 BHandler::SetFilterList(BList* filters) 330 { 331 if (fLooper && !fLooper->IsLocked()) { 332 debugger("Owning Looper must be locked before calling SetFilterList"); 333 return; 334 } 335 336 /** 337 @note I would like to use BObjectList internally, but this function is 338 spec'd such that fFilters would get deleted and then assigned 339 'filters', which would obviously mess this up. Wondering if 340 anyone ever assigns a list of filters and then checks against 341 FilterList() to see if they are the same. 342 */ 343 344 // TODO: Explore issues with using BObjectList 345 if (fFilters) { 346 fFilters->DoForEach(FilterDeleter); 347 delete fFilters; 348 } 349 350 fFilters = filters; 351 if (fFilters) { 352 for (int32 i = 0; i < fFilters->CountItems(); ++i) { 353 BMessageFilter *filter = 354 static_cast<BMessageFilter *>(fFilters->ItemAt(i)); 355 if (filter != NULL) 356 filter->SetLooper(fLooper); 357 } 358 } 359 } 360 361 362 BList * 363 BHandler::FilterList() 364 { 365 return fFilters; 366 } 367 368 369 bool 370 BHandler::LockLooper() 371 { 372 BLooper *looper = fLooper; 373 // Locking the looper also makes sure that the looper is valid 374 if (looper != NULL && looper->Lock()) { 375 // Have we locked the right looper? That's as far as the 376 // "pseudo-atomic" operation mentioned in the BeBook. 377 if (fLooper == looper) 378 return true; 379 380 // we locked the wrong looper, bail out 381 looper->Unlock(); 382 } 383 384 return false; 385 } 386 387 388 status_t 389 BHandler::LockLooperWithTimeout(bigtime_t timeout) 390 { 391 BLooper *looper = fLooper; 392 if (looper == NULL) 393 return B_BAD_VALUE; 394 395 status_t status = looper->LockWithTimeout(timeout); 396 if (status != B_OK) 397 return status; 398 399 if (fLooper != looper) { 400 // we locked the wrong looper, bail out 401 looper->Unlock(); 402 return B_MISMATCHED_VALUES; 403 } 404 405 return B_OK; 406 } 407 408 409 void 410 BHandler::UnlockLooper() 411 { 412 // The looper is locked at this point, and cannot change 413 if (fLooper != NULL) 414 fLooper->Unlock(); 415 } 416 417 418 BHandler * 419 BHandler::ResolveSpecifier(BMessage *msg, int32 index, 420 BMessage *specifier, int32 form, const char *property) 421 { 422 // Straight from the BeBook 423 BPropertyInfo propertyInfo(sHandlerPropInfo); 424 if (propertyInfo.FindMatch(msg, index, specifier, form, property) >= 0) 425 return this; 426 427 BMessage reply(B_MESSAGE_NOT_UNDERSTOOD); 428 reply.AddInt32("error", B_BAD_SCRIPT_SYNTAX); 429 reply.AddString("message", "Didn't understand the specifier(s)"); 430 msg->SendReply(&reply); 431 432 return NULL; 433 } 434 435 436 status_t 437 BHandler::GetSupportedSuites(BMessage *data) 438 { 439 /** 440 @note This is the output from the original implementation (calling 441 PrintToStream() on both data and the contained BPropertyInfo): 442 443 BMessage: what = (0x0, or 0) 444 entry suites, type='CSTR', c=1, size=21, data[0]: "suite/vnd.Be-handler" 445 entry messages, type='SCTD', c=1, size= 0, 446 property commands types specifiers 447 -------------------------------------------------------------------------------- 448 Suites PGET 1 449 (RTSC,suites) 450 (DTCS,messages) 451 452 Messenger PGET GNSM 1 453 InternalName PGET RTSC 1 454 455 With a good deal of trial and error, I determined that the 456 parenthetical clauses are entries in the 'ctypes' field of 457 property_info. 'ctypes' is an array of 'compound_type', which 458 contains an array of 'field_pair's. I haven't the foggiest what 459 either 'compound_type' or 'field_pair' is for, being as the 460 scripting docs are so bloody horrible. The corresponding 461 property_info array is declared in the globals section. 462 */ 463 464 status_t err = B_OK; 465 if (!data) 466 err = B_BAD_VALUE; 467 468 if (!err) { 469 err = data->AddString("suites", "suite/vnd.Be-handler"); 470 if (!err) { 471 BPropertyInfo propertyInfo(sHandlerPropInfo); 472 err = data->AddFlat("messages", &propertyInfo); 473 } 474 } 475 476 return err; 477 } 478 479 480 status_t 481 BHandler::StartWatching(BMessenger messenger, uint32 what) 482 { 483 if (fObserverList == NULL) 484 fObserverList = new _ObserverList; 485 return fObserverList->StartObserving(messenger, what); 486 } 487 488 489 status_t 490 BHandler::StartWatchingAll(BMessenger messenger) 491 { 492 return StartWatching(messenger, B_OBSERVER_OBSERVE_ALL); 493 } 494 495 496 status_t 497 BHandler::StopWatching(BMessenger messenger, uint32 what) 498 { 499 if (fObserverList == NULL) 500 fObserverList = new _ObserverList; 501 return fObserverList->StopObserving(messenger, what); 502 } 503 504 505 status_t 506 BHandler::StopWatchingAll(BMessenger messenger) 507 { 508 return StopWatching(messenger, B_OBSERVER_OBSERVE_ALL); 509 } 510 511 512 status_t 513 BHandler::StartWatching(BHandler *handler, uint32 what) 514 { 515 if (fObserverList == NULL) 516 fObserverList = new _ObserverList; 517 return fObserverList->StartObserving(handler, what); 518 } 519 520 521 status_t 522 BHandler::StartWatchingAll(BHandler *handler) 523 { 524 return StartWatching(handler, B_OBSERVER_OBSERVE_ALL); 525 } 526 527 528 status_t 529 BHandler::StopWatching(BHandler *handler, uint32 what) 530 { 531 if (fObserverList == NULL) 532 fObserverList = new _ObserverList; 533 return fObserverList->StopObserving(handler, what); 534 } 535 536 537 status_t 538 BHandler::StopWatchingAll(BHandler *handler) 539 { 540 return StopWatching(handler, B_OBSERVER_OBSERVE_ALL); 541 } 542 543 544 status_t 545 BHandler::Perform(perform_code d, void *arg) 546 { 547 return BArchivable::Perform(d, arg); 548 } 549 550 551 void 552 BHandler::SendNotices(uint32 what, const BMessage *msg) 553 { 554 if (fObserverList != NULL) 555 fObserverList->SendNotices(what, msg); 556 } 557 558 559 bool 560 BHandler::IsWatched() const 561 { 562 return fObserverList && !fObserverList->IsEmpty(); 563 } 564 565 566 void 567 BHandler::InitData(const char *name) 568 { 569 SetName(name); 570 571 fLooper = NULL; 572 fNextHandler = NULL; 573 fFilters = NULL; 574 fObserverList = NULL; 575 576 fToken = gDefaultTokens.NewToken(B_HANDLER_TOKEN, this); 577 } 578 579 580 BHandler::BHandler(const BHandler &) 581 { 582 // No copy construction allowed. 583 } 584 585 586 BHandler & 587 BHandler::operator=(const BHandler &) 588 { 589 // No assignments allowed. 590 return *this; 591 } 592 593 594 void 595 BHandler::SetLooper(BLooper *looper) 596 { 597 fLooper = looper; 598 599 if (fFilters) { 600 for (int32 i = 0; i < fFilters->CountItems(); i++) 601 static_cast<BMessageFilter *>(fFilters->ItemAtFast(i))->SetLooper(looper); 602 } 603 } 604 605 606 #ifdef __INTEL__ 607 // binary compatibility with R4.5 608 extern "C" void _ReservedHandler1__8BHandler(void) {} 609 #endif 610 611 void BHandler::_ReservedHandler2() {} 612 void BHandler::_ReservedHandler3() {} 613 void BHandler::_ReservedHandler4() {} 614 615 616 // #pragma mark - 617 618 619 _ObserverList::_ObserverList(void) 620 { 621 } 622 623 624 _ObserverList::~_ObserverList(void) 625 { 626 } 627 628 629 status_t 630 _ObserverList::SendNotices(unsigned long what, BMessage const *message) 631 { 632 // Having to new a temporary is really irritating ... 633 BMessage *copyMsg = NULL; 634 if (message) { 635 copyMsg = new BMessage(*message); 636 copyMsg->what = B_OBSERVER_NOTICE_CHANGE; 637 copyMsg->AddInt32(B_OBSERVE_ORIGINAL_WHAT, message->what); 638 } else 639 copyMsg = new BMessage(B_OBSERVER_NOTICE_CHANGE); 640 641 copyMsg->AddInt32(B_OBSERVE_WHAT_CHANGE, what); 642 643 vector<BHandler *> &handlers = fHandlerMap[what]; 644 for (uint32 i = 0; i < handlers.size(); ++i) { 645 BMessenger msgr(handlers[i]); 646 msgr.SendMessage(copyMsg); 647 } 648 649 vector<BMessenger> &messengers = fMessengerMap[what]; 650 for (uint32 i = 0; i < messengers.size(); ++i) 651 messengers[i].SendMessage(copyMsg); 652 653 // We have to send the message also to the handlers 654 // and messengers which were subscribed to ALL events, 655 // since they aren't caught by the above loops. 656 // TODO: cleanup 657 vector<BHandler *> &handlersAll = fHandlerMap[B_OBSERVER_OBSERVE_ALL]; 658 for (uint32 i = 0; i < handlersAll.size(); ++i) { 659 BMessenger msgr(handlersAll[i]); 660 msgr.SendMessage(copyMsg); 661 } 662 663 vector<BMessenger> &messengersAll = fMessengerMap[B_OBSERVER_OBSERVE_ALL]; 664 for (uint32 i = 0; i < messengersAll.size(); ++i) 665 messengers[i].SendMessage(copyMsg); 666 667 // Gotta make sure to clean up the annoying temporary ... 668 delete copyMsg; 669 670 return B_OK; 671 } 672 673 674 status_t 675 _ObserverList::StartObserving(BHandler *handler, unsigned long what) 676 { 677 if (handler == NULL) 678 return B_BAD_HANDLER; 679 680 vector<BHandler*> &handlers = fHandlerMap[what]; 681 682 vector<BHandler*>::iterator iter; 683 iter = find(handlers.begin(), handlers.end(), handler); 684 if (iter != handlers.end()) { 685 // TODO: verify 686 return B_OK; 687 } 688 689 handlers.push_back(handler); 690 return B_OK; 691 } 692 693 694 status_t 695 _ObserverList::StartObserving(const BMessenger &messenger, 696 unsigned long what) 697 { 698 vector<BMessenger> &messengers = fMessengerMap[what]; 699 700 vector<BMessenger>::iterator iter; 701 iter = find(messengers.begin(), messengers.end(), messenger); 702 if (iter != messengers.end()) { 703 // TODO: verify 704 return B_OK; 705 } 706 707 messengers.push_back(messenger); 708 return B_OK; 709 } 710 711 712 status_t 713 _ObserverList::StopObserving(BHandler *handler, unsigned long what) 714 { 715 if (handler == NULL) 716 return B_BAD_HANDLER; 717 718 vector<BHandler*> &handlers = fHandlerMap[what]; 719 720 vector<BHandler*>::iterator iter; 721 iter = find(handlers.begin(), handlers.end(), handler); 722 if (iter != handlers.end()) { 723 handlers.erase(iter); 724 if (handlers.empty()) 725 fHandlerMap.erase(what); 726 727 return B_OK; 728 } 729 730 return B_BAD_HANDLER; 731 } 732 733 734 status_t 735 _ObserverList::StopObserving(const BMessenger &messenger, 736 unsigned long what) 737 { 738 // ???: What if you call StartWatching(MyMsngr, aWhat) and then call 739 // StopWatchingAll(MyMsnger)? Will MyMsnger be removed from the aWhat 740 // watcher list? For now, we'll assume that they're discreet lists 741 // which do no cross checking; i.e., MyMsnger would *not* be removed in 742 // this scenario. 743 vector<BMessenger> &messengers = fMessengerMap[what]; 744 745 vector<BMessenger>::iterator iter; 746 iter = find(messengers.begin(), messengers.end(), messenger); 747 if (iter != messengers.end()) { 748 messengers.erase(iter); 749 if (messengers.empty()) 750 fMessengerMap.erase(what); 751 752 return B_OK; 753 } 754 755 return B_BAD_HANDLER; 756 } 757 758 759 bool 760 _ObserverList::IsEmpty() 761 { 762 return fHandlerMap.empty() && fMessengerMap.empty(); 763 } 764 765 766 // #pragma mark - 767 768 769 bool 770 FilterDeleter(void *_filter) 771 { 772 delete static_cast<BMessageFilter *>(_filter); 773 return false; 774 } 775 776