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