1 /* 2 * Copyright 2004-2013 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 * Jérôme Duval 8 * Marcus Overhagen 9 * John Scipione, jscipione@gmail.com 10 */ 11 12 13 //! Manager for input_server add-ons (devices, filters, methods) 14 15 16 #include "AddOnManager.h" 17 18 #include <stdio.h> 19 #include <string.h> 20 21 #include <Autolock.h> 22 #include <Deskbar.h> 23 #include <Directory.h> 24 #include <Entry.h> 25 #include <image.h> 26 #include <Path.h> 27 #include <Roster.h> 28 #include <String.h> 29 30 #include <PathMonitor.h> 31 32 #include "InputServer.h" 33 #include "InputServerTypes.h" 34 #include "MethodReplicant.h" 35 36 37 #undef TRACE 38 //#define TRACE_ADD_ON_MONITOR 39 #ifdef TRACE_ADD_ON_MONITOR 40 # define TRACE(x...) debug_printf(x) 41 # define ERROR(x...) debug_printf(x) 42 #else 43 # define TRACE(x...) ; 44 // TODO: probably better to the syslog 45 # define ERROR(x...) debug_printf(x) 46 #endif 47 48 49 50 class AddOnManager::MonitorHandler : public AddOnMonitorHandler { 51 public: 52 MonitorHandler(AddOnManager* manager) 53 { 54 fManager = manager; 55 } 56 57 virtual void AddOnEnabled(const add_on_entry_info* entryInfo) 58 { 59 CALLED(); 60 entry_ref ref; 61 make_entry_ref(entryInfo->dir_nref.device, entryInfo->dir_nref.node, 62 entryInfo->name, &ref); 63 BEntry entry(&ref, false); 64 65 fManager->_RegisterAddOn(entry); 66 } 67 68 virtual void AddOnDisabled(const add_on_entry_info* entryInfo) 69 { 70 CALLED(); 71 entry_ref ref; 72 make_entry_ref(entryInfo->dir_nref.device, entryInfo->dir_nref.node, 73 entryInfo->name, &ref); 74 BEntry entry(&ref, false); 75 76 fManager->_UnregisterAddOn(entry); 77 } 78 79 private: 80 AddOnManager* fManager; 81 }; 82 83 84 // #pragma mark - 85 86 87 template<class T> T* 88 instantiate_add_on(image_id image, const char* path, const char* type) 89 { 90 T* (*instantiateFunction)(); 91 92 BString functionName = "instantiate_input_"; 93 functionName += type; 94 95 if (get_image_symbol(image, functionName.String(), B_SYMBOL_TYPE_TEXT, 96 (void**)&instantiateFunction) < B_OK) { 97 ERROR("AddOnManager::_RegisterAddOn(): can't find %s() in \"%s\"\n", 98 functionName.String(), path); 99 return NULL; 100 } 101 102 T* addOn = (*instantiateFunction)(); 103 if (addOn == NULL) { 104 ERROR("AddOnManager::_RegisterAddOn(): %s() in \"%s\" returned " 105 "NULL\n", functionName.String(), path); 106 return NULL; 107 } 108 109 status_t status = addOn->InitCheck(); 110 if (status != B_OK) { 111 ERROR("AddOnManager::_RegisterAddOn(): InitCheck() in \"%s\" " 112 "returned %s\n", path, strerror(status)); 113 delete addOn; 114 return NULL; 115 } 116 117 return addOn; 118 } 119 120 121 // #pragma mark - AddOnManager 122 123 124 AddOnManager::AddOnManager() 125 : 126 AddOnMonitor(), 127 fHandler(new(std::nothrow) MonitorHandler(this)) 128 { 129 SetHandler(fHandler); 130 } 131 132 133 AddOnManager::~AddOnManager() 134 { 135 delete fHandler; 136 } 137 138 139 void 140 AddOnManager::MessageReceived(BMessage* message) 141 { 142 CALLED(); 143 144 BMessage reply; 145 status_t status; 146 147 TRACE("%s what: %.4s\n", __PRETTY_FUNCTION__, (char*)&message->what); 148 149 switch (message->what) { 150 case IS_FIND_DEVICES: 151 status = _HandleFindDevices(message, &reply); 152 break; 153 case IS_WATCH_DEVICES: 154 status = _HandleWatchDevices(message, &reply); 155 break; 156 case IS_IS_DEVICE_RUNNING: 157 status = _HandleIsDeviceRunning(message, &reply); 158 break; 159 case IS_START_DEVICE: 160 status = _HandleStartStopDevices(message, &reply); 161 break; 162 case IS_STOP_DEVICE: 163 status = _HandleStartStopDevices(message, &reply); 164 break; 165 case IS_CONTROL_DEVICES: 166 status = _HandleControlDevices(message, &reply); 167 break; 168 case SYSTEM_SHUTTING_DOWN: 169 status = _HandleSystemShuttingDown(message, &reply); 170 break; 171 case IS_METHOD_REGISTER: 172 status = _HandleMethodReplicant(message, &reply); 173 break; 174 175 case B_PATH_MONITOR: 176 _HandleDeviceMonitor(message); 177 return; 178 179 default: 180 AddOnMonitor::MessageReceived(message); 181 return; 182 } 183 184 reply.AddInt32("status", status); 185 message->SendReply(&reply); 186 } 187 188 189 void 190 AddOnManager::LoadState() 191 { 192 _RegisterAddOns(); 193 } 194 195 196 void 197 AddOnManager::SaveState() 198 { 199 CALLED(); 200 _UnregisterAddOns(); 201 } 202 203 204 status_t 205 AddOnManager::StartMonitoringDevice(DeviceAddOn* addOn, const char* device) 206 { 207 CALLED(); 208 209 BString path; 210 if (device[0] != '/') 211 path = "/dev/"; 212 path += device; 213 214 TRACE("AddOnMonitor::StartMonitoringDevice(%s)\n", path.String()); 215 216 bool newPath; 217 status_t status = _AddDevicePath(addOn, path.String(), newPath); 218 if (status == B_OK && newPath) { 219 status = BPathMonitor::StartWatching(path.String(), 220 B_WATCH_FILES_ONLY | B_WATCH_RECURSIVELY, this); 221 if (status != B_OK) { 222 bool lastPath; 223 _RemoveDevicePath(addOn, path.String(), lastPath); 224 } 225 } 226 227 return status; 228 } 229 230 231 status_t 232 AddOnManager::StopMonitoringDevice(DeviceAddOn* addOn, const char *device) 233 { 234 CALLED(); 235 236 BString path; 237 if (device[0] != '/') 238 path = "/dev/"; 239 path += device; 240 241 TRACE("AddOnMonitor::StopMonitoringDevice(%s)\n", path.String()); 242 243 bool lastPath; 244 status_t status = _RemoveDevicePath(addOn, path.String(), lastPath); 245 if (status == B_OK && lastPath) 246 BPathMonitor::StopWatching(path.String(), this); 247 248 return status; 249 } 250 251 252 // #pragma mark - 253 254 255 void 256 AddOnManager::_RegisterAddOns() 257 { 258 CALLED(); 259 BAutolock locker(this); 260 261 fHandler->AddAddOnDirectories("input_server/devices"); 262 fHandler->AddAddOnDirectories("input_server/filters"); 263 fHandler->AddAddOnDirectories("input_server/methods"); 264 } 265 266 267 void 268 AddOnManager::_UnregisterAddOns() 269 { 270 BAutolock locker(this); 271 272 // We have to stop manually the add-ons because the monitor doesn't 273 // disable them on exit 274 275 while (device_info* info = fDeviceList.RemoveItemAt(0)) { 276 gInputServer->StartStopDevices(*info->add_on, false); 277 delete info; 278 } 279 280 // TODO: what about the filters/methods lists in the input_server? 281 282 while (filter_info* info = fFilterList.RemoveItemAt(0)) { 283 delete info; 284 } 285 286 while (method_info* info = fMethodList.RemoveItemAt(0)) { 287 delete info; 288 } 289 } 290 291 292 bool 293 AddOnManager::_IsDevice(const char* path) const 294 { 295 return strstr(path, "input_server/devices") != 0; 296 } 297 298 299 bool 300 AddOnManager::_IsFilter(const char* path) const 301 { 302 return strstr(path, "input_server/filters") != 0; 303 } 304 305 306 bool 307 AddOnManager::_IsMethod(const char* path) const 308 { 309 return strstr(path, "input_server/methods") != 0; 310 } 311 312 313 status_t 314 AddOnManager::_RegisterAddOn(BEntry& entry) 315 { 316 BPath path(&entry); 317 318 entry_ref ref; 319 status_t status = entry.GetRef(&ref); 320 if (status < B_OK) 321 return status; 322 323 TRACE("AddOnManager::RegisterAddOn(): trying to load \"%s\"\n", 324 path.Path()); 325 326 image_id image = load_add_on(path.Path()); 327 if (image < B_OK) { 328 ERROR("load addon %s failed\n", path.Path()); 329 return image; 330 } 331 332 status = B_ERROR; 333 334 if (_IsDevice(path.Path())) { 335 BInputServerDevice* device = instantiate_add_on<BInputServerDevice>( 336 image, path.Path(), "device"); 337 if (device != NULL) 338 status = _RegisterDevice(device, ref, image); 339 } else if (_IsFilter(path.Path())) { 340 BInputServerFilter* filter = instantiate_add_on<BInputServerFilter>( 341 image, path.Path(), "filter"); 342 if (filter != NULL) 343 status = _RegisterFilter(filter, ref, image); 344 } else if (_IsMethod(path.Path())) { 345 BInputServerMethod* method = instantiate_add_on<BInputServerMethod>( 346 image, path.Path(), "method"); 347 if (method != NULL) 348 status = _RegisterMethod(method, ref, image); 349 } else { 350 ERROR("AddOnManager::_RegisterAddOn(): addon type not found for " 351 "\"%s\" \n", path.Path()); 352 } 353 354 if (status != B_OK) 355 unload_add_on(image); 356 357 return status; 358 } 359 360 361 status_t 362 AddOnManager::_UnregisterAddOn(BEntry& entry) 363 { 364 BPath path(&entry); 365 366 entry_ref ref; 367 status_t status = entry.GetRef(&ref); 368 if (status < B_OK) 369 return status; 370 371 TRACE("AddOnManager::UnregisterAddOn(): trying to unload \"%s\"\n", 372 path.Path()); 373 374 BAutolock _(this); 375 376 if (_IsDevice(path.Path())) { 377 for (int32 i = fDeviceList.CountItems(); i-- > 0;) { 378 device_info* info = fDeviceList.ItemAt(i); 379 if (!strcmp(info->ref.name, ref.name)) { 380 gInputServer->StartStopDevices(*info->add_on, false); 381 delete fDeviceList.RemoveItemAt(i); 382 break; 383 } 384 } 385 } else if (_IsFilter(path.Path())) { 386 for (int32 i = fFilterList.CountItems(); i-- > 0;) { 387 filter_info* info = fFilterList.ItemAt(i); 388 if (!strcmp(info->ref.name, ref.name)) { 389 BAutolock locker(InputServer::gInputFilterListLocker); 390 InputServer::gInputFilterList.RemoveItem(info->add_on); 391 delete fFilterList.RemoveItemAt(i); 392 break; 393 } 394 } 395 } else if (_IsMethod(path.Path())) { 396 BInputServerMethod* method = NULL; 397 398 for (int32 i = fMethodList.CountItems(); i-- > 0;) { 399 method_info* info = fMethodList.ItemAt(i); 400 if (!strcmp(info->ref.name, ref.name)) { 401 BAutolock locker(InputServer::gInputMethodListLocker); 402 InputServer::gInputMethodList.RemoveItem(info->add_on); 403 method = info->add_on; 404 // this will only be used as a cookie, and not referenced 405 // anymore 406 delete fMethodList.RemoveItemAt(i); 407 break; 408 } 409 } 410 411 if (fMethodList.CountItems() <= 0) { 412 // we remove the method replicant 413 BDeskbar().RemoveItem(REPLICANT_CTL_NAME); 414 gInputServer->SetMethodReplicant(NULL); 415 } else if (method != NULL) { 416 BMessage msg(IS_REMOVE_METHOD); 417 msg.AddInt32("cookie", method->fOwner->Cookie()); 418 if (gInputServer->MethodReplicant()) 419 gInputServer->MethodReplicant()->SendMessage(&msg); 420 } 421 } 422 423 return B_OK; 424 } 425 426 427 //! Takes over ownership of the \a device, regardless of success. 428 status_t 429 AddOnManager::_RegisterDevice(BInputServerDevice* device, const entry_ref& ref, 430 image_id addOnImage) 431 { 432 BAutolock locker(this); 433 434 for (int32 i = fDeviceList.CountItems(); i-- > 0;) { 435 device_info* info = fDeviceList.ItemAt(i); 436 if (!strcmp(info->ref.name, ref.name)) { 437 // we already know this device 438 delete device; 439 return B_NAME_IN_USE; 440 } 441 } 442 443 TRACE("AddOnManager::RegisterDevice, name %s\n", ref.name); 444 445 device_info* info = new(std::nothrow) device_info; 446 if (info == NULL) { 447 delete device; 448 return B_NO_MEMORY; 449 } 450 451 info->ref = ref; 452 info->add_on = device; 453 454 if (!fDeviceList.AddItem(info)) { 455 delete info; 456 return B_NO_MEMORY; 457 } 458 459 info->image = addOnImage; 460 461 return B_OK; 462 } 463 464 465 //! Takes over ownership of the \a filter, regardless of success. 466 status_t 467 AddOnManager::_RegisterFilter(BInputServerFilter* filter, const entry_ref& ref, 468 image_id addOnImage) 469 { 470 BAutolock _(this); 471 472 for (int32 i = fFilterList.CountItems(); i-- > 0;) { 473 filter_info* info = fFilterList.ItemAt(i); 474 if (strcmp(info->ref.name, ref.name) == 0) { 475 // we already know this ref 476 delete filter; 477 return B_NAME_IN_USE; 478 } 479 } 480 481 TRACE("%s, name %s\n", __PRETTY_FUNCTION__, ref.name); 482 483 filter_info* info = new(std::nothrow) filter_info; 484 if (info == NULL) { 485 delete filter; 486 return B_NO_MEMORY; 487 } 488 489 info->ref = ref; 490 info->add_on = filter; 491 492 if (!fFilterList.AddItem(info)) { 493 delete info; 494 return B_NO_MEMORY; 495 } 496 497 BAutolock locker(InputServer::gInputFilterListLocker); 498 if (!InputServer::gInputFilterList.AddItem(filter)) { 499 fFilterList.RemoveItem(info, false); 500 delete info; 501 return B_NO_MEMORY; 502 } 503 504 info->image = addOnImage; 505 506 return B_OK; 507 } 508 509 510 //! Takes over ownership of the \a method, regardless of success. 511 status_t 512 AddOnManager::_RegisterMethod(BInputServerMethod* method, const entry_ref& ref, 513 image_id addOnImage) 514 { 515 BAutolock _(this); 516 517 for (int32 i = fMethodList.CountItems(); i-- > 0;) { 518 method_info* info = fMethodList.ItemAt(i); 519 if (!strcmp(info->ref.name, ref.name)) { 520 // we already know this ref 521 delete method; 522 return B_NAME_IN_USE; 523 } 524 } 525 526 TRACE("%s, name %s\n", __PRETTY_FUNCTION__, ref.name); 527 528 method_info* info = new(std::nothrow) method_info; 529 if (info == NULL) { 530 delete method; 531 return B_NO_MEMORY; 532 } 533 534 info->ref = ref; 535 info->add_on = method; 536 537 if (!fMethodList.AddItem(info)) { 538 delete info; 539 return B_NO_MEMORY; 540 } 541 542 BAutolock locker(InputServer::gInputMethodListLocker); 543 if (!InputServer::gInputMethodList.AddItem(method)) { 544 fMethodList.RemoveItem(info); 545 delete info; 546 return B_NO_MEMORY; 547 } 548 549 info->image = addOnImage; 550 551 if (gInputServer->MethodReplicant() == NULL) { 552 _LoadReplicant(); 553 554 if (gInputServer->MethodReplicant()) { 555 _BMethodAddOn_ *addon = InputServer::gKeymapMethod.fOwner; 556 addon->AddMethod(); 557 } 558 } 559 560 if (gInputServer->MethodReplicant() != NULL) { 561 _BMethodAddOn_ *addon = method->fOwner; 562 addon->AddMethod(); 563 } 564 565 return B_OK; 566 } 567 568 569 // #pragma mark - 570 571 572 void 573 AddOnManager::_UnloadReplicant() 574 { 575 BDeskbar().RemoveItem(REPLICANT_CTL_NAME); 576 } 577 578 579 void 580 AddOnManager::_LoadReplicant() 581 { 582 CALLED(); 583 app_info info; 584 be_app->GetAppInfo(&info); 585 586 status_t err = BDeskbar().AddItem(&info.ref); 587 if (err != B_OK) 588 ERROR("Deskbar refuses to add method replicant: %s\n", strerror(err)); 589 590 BMessage request(B_GET_PROPERTY); 591 BMessenger to; 592 BMessenger status; 593 594 request.AddSpecifier("Messenger"); 595 request.AddSpecifier("Shelf"); 596 597 // In the Deskbar the Shelf is in the View "Status" in Window "Deskbar" 598 request.AddSpecifier("View", "Status"); 599 request.AddSpecifier("Window", "Deskbar"); 600 to = BMessenger("application/x-vnd.Be-TSKB", -1); 601 602 BMessage reply; 603 604 if (to.SendMessage(&request, &reply) == B_OK 605 && reply.FindMessenger("result", &status) == B_OK) { 606 // enum replicant in Status view 607 int32 index = 0; 608 int32 uid; 609 while ((uid = _GetReplicantAt(status, index++)) >= B_OK) { 610 BMessage replicantInfo; 611 if (_GetReplicantName(status, uid, &replicantInfo) != B_OK) 612 continue; 613 614 const char *name; 615 if (replicantInfo.FindString("result", &name) == B_OK 616 && !strcmp(name, REPLICANT_CTL_NAME)) { 617 BMessage replicant; 618 if (_GetReplicantView(status, uid, &replicant) == B_OK) { 619 BMessenger result; 620 if (replicant.FindMessenger("result", &result) == B_OK) { 621 gInputServer->SetMethodReplicant(new BMessenger(result)); 622 } 623 } 624 } 625 } 626 } 627 628 if (!gInputServer->MethodReplicant()) { 629 ERROR("LoadReplicant(): Method replicant not found!\n"); 630 } 631 } 632 633 634 int32 635 AddOnManager::_GetReplicantAt(BMessenger target, int32 index) const 636 { 637 // So here we want to get the Unique ID of the replicant at the given index 638 // in the target Shelf. 639 640 BMessage request(B_GET_PROPERTY);// We're getting the ID property 641 BMessage reply; 642 status_t err; 643 644 request.AddSpecifier("ID");// want the ID 645 request.AddSpecifier("Replicant", index);// of the index'th replicant 646 647 if ((err = target.SendMessage(&request, &reply)) != B_OK) 648 return err; 649 650 int32 uid; 651 if ((err = reply.FindInt32("result", &uid)) != B_OK) 652 return err; 653 654 return uid; 655 } 656 657 658 status_t 659 AddOnManager::_GetReplicantName(BMessenger target, int32 uid, 660 BMessage* reply) const 661 { 662 // We send a message to the target shelf, asking it for the Name of the 663 // replicant with the given unique id. 664 665 BMessage request(B_GET_PROPERTY); 666 BMessage uid_specifier(B_ID_SPECIFIER);// specifying via ID 667 status_t err; 668 status_t e; 669 670 request.AddSpecifier("Name");// ask for the Name of the replicant 671 672 // IDs are specified using code like the following 3 lines: 673 uid_specifier.AddInt32("id", uid); 674 uid_specifier.AddString("property", "Replicant"); 675 request.AddSpecifier(&uid_specifier); 676 677 if ((err = target.SendMessage(&request, reply)) != B_OK) 678 return err; 679 680 if (((err = reply->FindInt32("error", &e)) != B_OK) || (e != B_OK)) 681 return err ? err : e; 682 683 return B_OK; 684 } 685 686 687 status_t 688 AddOnManager::_GetReplicantView(BMessenger target, int32 uid, 689 BMessage* reply) const 690 { 691 // We send a message to the target shelf, asking it for the Name of the 692 // replicant with the given unique id. 693 694 BMessage request(B_GET_PROPERTY); 695 BMessage uid_specifier(B_ID_SPECIFIER); 696 // specifying via ID 697 status_t err; 698 status_t e; 699 700 request.AddSpecifier("View"); 701 // ask for the Name of the replicant 702 703 // IDs are specified using code like the following 3 lines: 704 uid_specifier.AddInt32("id", uid); 705 uid_specifier.AddString("property", "Replicant"); 706 request.AddSpecifier(&uid_specifier); 707 708 if ((err = target.SendMessage(&request, reply)) != B_OK) 709 return err; 710 711 if (((err = reply->FindInt32("error", &e)) != B_OK) || (e != B_OK)) 712 return err ? err : e; 713 714 return B_OK; 715 } 716 717 718 status_t 719 AddOnManager::_HandleStartStopDevices(BMessage* message, BMessage* reply) 720 { 721 const char *name = NULL; 722 int32 type = 0; 723 if (!((message->FindInt32("type", &type) != B_OK) 724 ^ (message->FindString("device", &name) != B_OK))) 725 return B_ERROR; 726 727 return gInputServer->StartStopDevices(name, (input_device_type)type, 728 message->what == IS_START_DEVICE); 729 } 730 731 732 status_t 733 AddOnManager::_HandleFindDevices(BMessage* message, BMessage* reply) 734 { 735 CALLED(); 736 const char *name = NULL; 737 input_device_type type; 738 if (message->FindString("device", &name) == B_OK) { 739 if (gInputServer->GetDeviceInfo(name, &type) != B_OK) 740 return B_NAME_NOT_FOUND; 741 reply->AddString("device", name); 742 reply->AddInt32("type", type); 743 } else { 744 gInputServer->GetDeviceInfos(reply); 745 } 746 return B_OK; 747 } 748 749 750 status_t 751 AddOnManager::_HandleWatchDevices(BMessage* message, BMessage* reply) 752 { 753 // TODO 754 return B_OK; 755 } 756 757 758 status_t 759 AddOnManager::_HandleIsDeviceRunning(BMessage* message, BMessage* reply) 760 { 761 const char* name; 762 bool running; 763 if (message->FindString("device", &name) != B_OK 764 || gInputServer->GetDeviceInfo(name, NULL, &running) != B_OK) 765 return B_NAME_NOT_FOUND; 766 767 return running ? B_OK : B_ERROR; 768 } 769 770 771 status_t 772 AddOnManager::_HandleControlDevices(BMessage* message, BMessage* reply) 773 { 774 CALLED(); 775 const char *name = NULL; 776 int32 type = 0; 777 if (!((message->FindInt32("type", &type) != B_OK) 778 ^ (message->FindString("device", &name) != B_OK))) 779 return B_BAD_VALUE; 780 781 uint32 code = 0; 782 BMessage controlMessage; 783 bool hasMessage = true; 784 if (message->FindInt32("code", (int32*)&code) != B_OK) 785 return B_BAD_VALUE; 786 if (message->FindMessage("message", &controlMessage) != B_OK) 787 hasMessage = false; 788 789 return gInputServer->ControlDevices(name, (input_device_type)type, 790 code, hasMessage ? &controlMessage : NULL); 791 } 792 793 794 status_t 795 AddOnManager::_HandleSystemShuttingDown(BMessage* message, BMessage* reply) 796 { 797 CALLED(); 798 799 for (int32 i = 0; i < fDeviceList.CountItems(); i++) { 800 device_info* info = fDeviceList.ItemAt(i); 801 info->add_on->SystemShuttingDown(); 802 } 803 804 return B_OK; 805 } 806 807 808 status_t 809 AddOnManager::_HandleMethodReplicant(BMessage* message, BMessage* reply) 810 { 811 CALLED(); 812 813 if (InputServer::gInputMethodList.CountItems() == 0) { 814 _UnloadReplicant(); 815 return B_OK; 816 } 817 818 _LoadReplicant(); 819 820 BAutolock lock(InputServer::gInputMethodListLocker); 821 822 if (gInputServer->MethodReplicant()) { 823 _BMethodAddOn_* addon = InputServer::gKeymapMethod.fOwner; 824 addon->AddMethod(); 825 826 for (int32 i = 0; i < InputServer::gInputMethodList.CountItems(); i++) { 827 BInputServerMethod* method 828 = (BInputServerMethod*)InputServer::gInputMethodList.ItemAt(i); 829 830 _BMethodAddOn_* addon = method->fOwner; 831 addon->AddMethod(); 832 } 833 } 834 835 return B_OK; 836 } 837 838 839 void 840 AddOnManager::_HandleDeviceMonitor(BMessage* message) 841 { 842 int32 opcode; 843 if (message->FindInt32("opcode", &opcode) != B_OK) 844 return; 845 846 switch (opcode) { 847 case B_ENTRY_CREATED: 848 case B_ENTRY_REMOVED: 849 { 850 const char* path; 851 const char* watchedPath; 852 if (message->FindString("watched_path", &watchedPath) != B_OK 853 || message->FindString("path", &path) != B_OK) { 854 #if DEBUG 855 char string[1024]; 856 sprintf(string, "message does not contain all fields - " 857 "watched_path: %d, path: %d\n", 858 message->HasString("watched_path"), 859 message->HasString("path")); 860 debugger(string); 861 #endif 862 return; 863 } 864 865 // Notify all watching devices 866 867 for (int32 i = 0; i < fDeviceAddOns.CountItems(); i++) { 868 DeviceAddOn* addOn = fDeviceAddOns.ItemAt(i); 869 if (!addOn->HasPath(watchedPath)) 870 continue; 871 872 addOn->Device()->Control(NULL, NULL, B_NODE_MONITOR, message); 873 } 874 break; 875 } 876 } 877 } 878 879 880 status_t 881 AddOnManager::_AddDevicePath(DeviceAddOn* addOn, const char* path, 882 bool& newPath) 883 { 884 newPath = !fDevicePaths.HasPath(path); 885 886 status_t status = fDevicePaths.AddPath(path); 887 if (status == B_OK) { 888 status = addOn->AddPath(path); 889 if (status == B_OK) { 890 if (!fDeviceAddOns.HasItem(addOn) 891 && !fDeviceAddOns.AddItem(addOn)) { 892 addOn->RemovePath(path); 893 status = B_NO_MEMORY; 894 } 895 } else 896 fDevicePaths.RemovePath(path); 897 } 898 899 return status; 900 } 901 902 903 status_t 904 AddOnManager::_RemoveDevicePath(DeviceAddOn* addOn, const char* path, 905 bool& lastPath) 906 { 907 if (!fDevicePaths.HasPath(path) || !addOn->HasPath(path)) 908 return B_ENTRY_NOT_FOUND; 909 910 fDevicePaths.RemovePath(path); 911 912 lastPath = !fDevicePaths.HasPath(path); 913 914 addOn->RemovePath(path); 915 if (addOn->CountPaths() == 0) 916 fDeviceAddOns.RemoveItem(addOn); 917 918 return B_OK; 919 } 920