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