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