1 /* 2 ** Copyright 2004, the Haiku project. All rights reserved. 3 ** Distributed under the terms of the Haiku License. 4 ** 5 ** Author : Jérôme Duval 6 ** Original authors: Marcus Overhagen, Axel Dörfler 7 */ 8 9 10 #include <Autolock.h> 11 #include <Deskbar.h> 12 #include <Directory.h> 13 #include <Entry.h> 14 #include <FindDirectory.h> 15 #include <Path.h> 16 #include <Roster.h> 17 #include <String.h> 18 19 #include <image.h> 20 #include <stdio.h> 21 #include <string.h> 22 23 #include "AddOnManager.h" 24 #include "InputServer.h" 25 #include "InputServerTypes.h" 26 #include "MethodReplicant.h" 27 28 AddOnManager::AddOnManager(bool safeMode) 29 : BLooper("addon_manager"), 30 fLock("add-on manager"), 31 fSafeMode(safeMode) 32 { 33 Run(); 34 } 35 36 37 AddOnManager::~AddOnManager() 38 { 39 } 40 41 42 void 43 AddOnManager::LoadState() 44 { 45 RegisterAddOns(); 46 } 47 48 49 void 50 AddOnManager::SaveState() 51 { 52 CALLED(); 53 UnregisterAddOns(); 54 } 55 56 57 status_t 58 AddOnManager::RegisterAddOn(BEntry &entry) 59 { 60 BPath path(&entry); 61 62 entry_ref ref; 63 status_t status = entry.GetRef(&ref); 64 if (status < B_OK) 65 return status; 66 67 PRINT(("AddOnManager::RegisterAddOn(): trying to load \"%s\"\n", path.Path())); 68 69 image_id addon_image = load_add_on(path.Path()); 70 71 if (addon_image < B_OK) { 72 PRINT(("load addon %s failed\n", path.Path())); 73 return addon_image; 74 } 75 76 BString pathString = path.Path(); 77 78 if (pathString.FindFirst("input_server/devices")>0) { 79 BInputServerDevice *(*instantiate_func)(); 80 81 if (get_image_symbol(addon_image, "instantiate_input_device", 82 B_SYMBOL_TYPE_TEXT, (void **)&instantiate_func) < B_OK) { 83 PRINTERR(("AddOnManager::RegisterAddOn(): can't find instantiate_input_device in \"%s\"\n", 84 path.Path())); 85 goto exit_error; 86 } 87 88 BInputServerDevice *isd = (*instantiate_func)(); 89 if (isd == NULL) { 90 PRINTERR(("AddOnManager::RegisterAddOn(): instantiate_input_device in \"%s\" returned NULL\n", 91 path.Path())); 92 goto exit_error; 93 } 94 status_t status = isd->InitCheck(); 95 if (status != B_OK) { 96 PRINTERR(("AddOnManager::RegisterAddOn(): BInputServerDevice.InitCheck in \"%s\" returned %s\n", 97 path.Path(), strerror(status))); 98 delete isd; 99 goto exit_error; 100 } 101 102 RegisterDevice(isd, ref, addon_image); 103 104 105 } else if (pathString.FindFirst("input_server/filters")>0) { 106 BInputServerFilter *(*instantiate_func)(); 107 108 if (get_image_symbol(addon_image, "instantiate_input_filter", 109 B_SYMBOL_TYPE_TEXT, (void **)&instantiate_func) < B_OK) { 110 PRINTERR(("AddOnManager::RegisterAddOn(): can't find instantiate_input_filter in \"%s\"\n", 111 path.Path())); 112 goto exit_error; 113 } 114 115 BInputServerFilter *isf = (*instantiate_func)(); 116 if (isf == NULL) { 117 PRINTERR(("AddOnManager::RegisterAddOn(): instantiate_input_filter in \"%s\" returned NULL\n", 118 path.Path())); 119 goto exit_error; 120 } 121 status_t status = isf->InitCheck(); 122 if (status != B_OK) { 123 PRINTERR(("AddOnManager::RegisterAddOn(): BInputServerFilter.InitCheck in \"%s\" returned %s\n", 124 path.Path(), strerror(status))); 125 delete isf; 126 goto exit_error; 127 } 128 129 RegisterFilter(isf, ref, addon_image); 130 131 } else if (pathString.FindFirst("input_server/methods")>0) { 132 BInputServerMethod *(*instantiate_func)(); 133 134 if (get_image_symbol(addon_image, "instantiate_input_method", 135 B_SYMBOL_TYPE_TEXT, (void **)&instantiate_func) < B_OK) { 136 PRINTERR(("AddOnManager::RegisterAddOn(): can't find instantiate_input_method in \"%s\"\n", 137 path.Path())); 138 goto exit_error; 139 } 140 141 BInputServerMethod *ism = (*instantiate_func)(); 142 if (ism == NULL) { 143 PRINTERR(("AddOnManager::RegisterAddOn(): instantiate_input_method in \"%s\" returned NULL\n", 144 path.Path())); 145 goto exit_error; 146 } 147 status_t status = ism->InitCheck(); 148 if (status != B_OK) { 149 PRINTERR(("AddOnManager::RegisterAddOn(): BInputServerMethod.InitCheck in \"%s\" returned %s\n", 150 path.Path(), strerror(status))); 151 delete ism; 152 goto exit_error; 153 } 154 155 RegisterMethod(ism, ref, addon_image); 156 157 } else { 158 PRINTERR(("AddOnManager::RegisterAddOn(): addon type not found for \"%s\" \n", path.Path())); 159 goto exit_error; 160 } 161 162 return B_OK; 163 exit_error: 164 unload_add_on(addon_image); 165 166 return status; 167 } 168 169 170 status_t 171 AddOnManager::UnregisterAddOn(BEntry &entry) 172 { 173 BPath path(&entry); 174 175 entry_ref ref; 176 status_t status = entry.GetRef(&ref); 177 if (status < B_OK) 178 return status; 179 180 PRINT(("AddOnManager::UnregisterAddOn(): trying to unload \"%s\"\n", path.Path())); 181 182 BEntry parent; 183 entry.GetParent(&parent); 184 BPath parentPath(&parent); 185 BString pathString = parentPath.Path(); 186 187 BAutolock locker(fLock); 188 189 if (pathString.FindFirst("input_server/devices")>0) { 190 device_info *pinfo; 191 for (fDeviceList.Rewind(); fDeviceList.GetNext(&pinfo);) { 192 if (!strcmp(pinfo->ref.name, ref.name)) { 193 InputServer::StartStopDevices(pinfo->isd, false); 194 delete pinfo->isd; 195 if (pinfo->addon_image >= B_OK) 196 unload_add_on(pinfo->addon_image); 197 fDeviceList.RemoveCurrent(); 198 break; 199 } 200 } 201 } else if (pathString.FindFirst("input_server/filters")>0) { 202 filter_info *pinfo; 203 for (fFilterList.Rewind(); fFilterList.GetNext(&pinfo);) { 204 if (!strcmp(pinfo->ref.name, ref.name)) { 205 delete pinfo->isf; 206 if (pinfo->addon_image >= B_OK) 207 unload_add_on(pinfo->addon_image); 208 fFilterList.RemoveCurrent(); 209 break; 210 } 211 } 212 } else if (pathString.FindFirst("input_server/methods")>0) { 213 method_info *pinfo; 214 for (fMethodList.Rewind(); fMethodList.GetNext(&pinfo);) { 215 if (!strcmp(pinfo->ref.name, ref.name)) { 216 delete pinfo->ism; 217 if (pinfo->addon_image >= B_OK) 218 unload_add_on(pinfo->addon_image); 219 fMethodList.RemoveCurrent(); 220 break; 221 } 222 } 223 224 if (fMethodList.CountItems()<=0) { 225 // we remove the method replicant 226 BDeskbar().RemoveItem(REPLICANT_CTL_NAME); 227 ((InputServer*)be_app)->SetMethodReplicant(NULL); 228 } else { 229 BMessage msg(IS_REMOVE_METHOD); 230 msg.AddInt32("cookie", (uint32)pinfo->ism); 231 if (((InputServer*)be_app)->MethodReplicant()) 232 ((InputServer*)be_app)->MethodReplicant()->SendMessage(&msg); 233 } 234 } 235 236 return B_OK; 237 } 238 239 void 240 AddOnManager::RegisterAddOns() 241 { 242 CALLED(); 243 status_t err; 244 245 class IAHandler : public AddOnMonitorHandler { 246 private: 247 AddOnManager * fManager; 248 public: 249 IAHandler(AddOnManager * manager) { 250 fManager = manager; 251 } 252 virtual void AddOnCreated(const add_on_entry_info * entry_info) { 253 } 254 virtual void AddOnEnabled(const add_on_entry_info * entry_info) { 255 CALLED(); 256 entry_ref ref; 257 make_entry_ref(entry_info->dir_nref.device, entry_info->dir_nref.node, 258 entry_info->name, &ref); 259 BEntry entry(&ref, false); 260 fManager->RegisterAddOn(entry); 261 } 262 virtual void AddOnDisabled(const add_on_entry_info * entry_info) { 263 CALLED(); 264 entry_ref ref; 265 make_entry_ref(entry_info->dir_nref.device, entry_info->dir_nref.node, 266 entry_info->name, &ref); 267 BEntry entry(&ref, false); 268 fManager->UnregisterAddOn(entry); 269 } 270 virtual void AddOnRemoved(const add_on_entry_info * entry_info) { 271 } 272 }; 273 274 fHandler = new IAHandler(this); 275 fAddOnMonitor = new AddOnMonitor(fHandler); 276 277 #ifndef APPSERVER_TEST_MODE 278 err = fAddOnMonitor->InitCheck(); 279 if (err != B_OK) { 280 PRINTERR(("AddOnManager::RegisterAddOns(): fAddOnMonitor->InitCheck() returned %s\n", 281 strerror(err))); 282 return; 283 } 284 285 const directory_which directories[] = { 286 B_USER_ADDONS_DIRECTORY, 287 B_COMMON_ADDONS_DIRECTORY, 288 B_BEOS_ADDONS_DIRECTORY 289 }; 290 const char subDirectories[][24] = { 291 "input_server/devices", 292 "input_server/filters", 293 "input_server/methods" 294 }; 295 296 node_ref nref; 297 BDirectory directory; 298 BPath path; 299 // when safemode, only B_BEOS_ADDONS_DIRECTORY is used 300 for (uint32 i = fSafeMode ? 2 : 0 ; i < sizeof(directories) / sizeof(directory_which) ; i++) 301 for (uint32 j = 0 ; j < sizeof(subDirectories) / sizeof(char[24]) ; j++) { 302 if ((find_directory(directories[i], &path) == B_OK) 303 && (path.Append(subDirectories[j]) == B_OK) 304 && (directory.SetTo(path.Path()) == B_OK) 305 && (directory.GetNodeRef(&nref) == B_OK)) { 306 fHandler->AddDirectory(&nref); 307 } 308 } 309 #else 310 BEntry entry("/boot/home/svnhaiku/trunk/tests/servers/input/view_input_device/input_server/devices/ViewInputDevice"); 311 RegisterAddOn(entry); 312 #endif 313 314 } 315 316 317 void 318 AddOnManager::UnregisterAddOns() 319 { 320 BMessenger messenger(fAddOnMonitor); 321 messenger.SendMessage(B_QUIT_REQUESTED); 322 int32 exit_value; 323 wait_for_thread(fAddOnMonitor->Thread(), &exit_value); 324 delete fHandler; 325 326 BAutolock locker(fLock); 327 328 // we have to stop manually the addons because the monitor doesn't disable them on exit 329 330 { 331 device_info *pinfo; 332 for (fDeviceList.Rewind(); fDeviceList.GetNext(&pinfo);) { 333 InputServer::StartStopDevices(pinfo->isd, false); 334 delete pinfo->isd; 335 if (pinfo->addon_image >= B_OK) 336 unload_add_on(pinfo->addon_image); 337 fDeviceList.RemoveCurrent(); 338 } 339 } 340 341 { 342 filter_info *pinfo; 343 for (fFilterList.Rewind(); fFilterList.GetNext(&pinfo);) { 344 delete pinfo->isf; 345 if (pinfo->addon_image >= B_OK) 346 unload_add_on(pinfo->addon_image); 347 fFilterList.RemoveCurrent(); 348 } 349 } 350 351 { 352 method_info *pinfo; 353 for (fMethodList.Rewind(); fMethodList.GetNext(&pinfo);) { 354 delete pinfo->ism; 355 if (pinfo->addon_image >= B_OK) 356 unload_add_on(pinfo->addon_image); 357 fMethodList.RemoveCurrent(); 358 } 359 } 360 } 361 362 363 void 364 AddOnManager::RegisterDevice(BInputServerDevice *device, const entry_ref &ref, image_id addon_image) 365 { 366 BAutolock locker(fLock); 367 368 device_info *pinfo; 369 for (fDeviceList.Rewind(); fDeviceList.GetNext(&pinfo);) { 370 if (!strcmp(pinfo->ref.name, ref.name)) { 371 // we already know this device 372 return; 373 } 374 } 375 376 PRINT(("AddOnManager::RegisterDevice, name %s\n", ref.name)); 377 378 device_info info; 379 info.ref = ref; 380 info.addon_image = addon_image; 381 info.isd = device; 382 383 fDeviceList.Insert(info); 384 } 385 386 387 void 388 AddOnManager::RegisterFilter(BInputServerFilter *filter, const entry_ref &ref, image_id addon_image) 389 { 390 BAutolock locker(fLock); 391 392 filter_info *pinfo; 393 for (fFilterList.Rewind(); fFilterList.GetNext(&pinfo);) { 394 if (!strcmp(pinfo->ref.name, ref.name)) { 395 // we already know this ref 396 return; 397 } 398 } 399 400 PRINT(("%s, name %s\n", __PRETTY_FUNCTION__, ref.name)); 401 402 filter_info info; 403 info.ref = ref; 404 info.addon_image = addon_image; 405 info.isf = filter; 406 407 fFilterList.Insert(info); 408 409 BAutolock lock2(InputServer::gInputFilterListLocker); 410 411 InputServer::gInputFilterList.AddItem(filter); 412 } 413 414 415 void 416 AddOnManager::RegisterMethod(BInputServerMethod *method, const entry_ref &ref, image_id addon_image) 417 { 418 BAutolock locker(fLock); 419 420 method_info *pinfo; 421 for (fMethodList.Rewind(); fMethodList.GetNext(&pinfo);) { 422 if (!strcmp(pinfo->ref.name, ref.name)) { 423 // we already know this ref 424 return; 425 } 426 } 427 428 PRINT(("%s, name %s\n", __PRETTY_FUNCTION__, ref.name)); 429 430 method_info info; 431 info.ref = ref; 432 info.addon_image = addon_image; 433 info.ism = method; 434 435 fMethodList.Insert(info); 436 437 BAutolock lock2(InputServer::gInputMethodListLocker); 438 439 InputServer::gInputMethodList.AddItem(method); 440 441 if (((InputServer*)be_app)->MethodReplicant() == NULL) { 442 LoadReplicant(); 443 444 if (((InputServer*)be_app)->MethodReplicant()) { 445 _BMethodAddOn_ *addon = InputServer::gKeymapMethod.fOwner; 446 addon->AddMethod(); 447 } 448 } 449 450 if (((InputServer*)be_app)->MethodReplicant()) { 451 _BMethodAddOn_ *addon = method->fOwner; 452 addon->AddMethod(); 453 } 454 } 455 456 457 void 458 AddOnManager::LoadReplicant() 459 { 460 CALLED(); 461 app_info info; 462 be_app->GetAppInfo(&info); 463 464 status_t err = BDeskbar().AddItem(&info.ref); 465 if (err!=B_OK) { 466 PRINTERR(("Deskbar refuses to add method replicant: %s\n", strerror(err))); 467 } 468 BMessage request(B_GET_PROPERTY); 469 BMessenger to; 470 BMessenger status; 471 472 request.AddSpecifier("Messenger"); 473 request.AddSpecifier("Shelf"); 474 475 // In the Deskbar the Shelf is in the View "Status" in Window "Deskbar" 476 request.AddSpecifier("View", "Status"); 477 request.AddSpecifier("Window", "Deskbar"); 478 to = BMessenger("application/x-vnd.Be-TSKB", -1); 479 480 BMessage reply; 481 482 if ((to.SendMessage(&request, &reply) == B_OK) 483 && (reply.FindMessenger("result", &status) == B_OK)) { 484 485 // enum replicant in Status view 486 int32 index = 0; 487 int32 uid; 488 while ((uid = GetReplicantAt(status, index++)) >= B_OK) { 489 BMessage rep_info; 490 if (GetReplicantName(status, uid, &rep_info) != B_OK) { 491 continue; 492 } 493 const char *name; 494 if ((rep_info.FindString("result", &name) == B_OK) 495 && (strcmp(name, REPLICANT_CTL_NAME)==0)) { 496 BMessage rep_view; 497 if (GetReplicantView(status, uid, &rep_view)==0) { 498 BMessenger result; 499 if (rep_view.FindMessenger("result", &result) == B_OK) { 500 ((InputServer*)be_app)->SetMethodReplicant(new BMessenger(result)); 501 } 502 } 503 } 504 } 505 } 506 } 507 508 509 // 510 int32 511 AddOnManager::GetReplicantAt(BMessenger target, int32 index) const 512 { 513 /* 514 So here we want to get the Unique ID of the replicant at the given index 515 in the target Shelf. 516 */ 517 518 BMessage request(B_GET_PROPERTY);// We're getting the ID property 519 BMessage reply; 520 status_t err; 521 522 request.AddSpecifier("ID");// want the ID 523 request.AddSpecifier("Replicant", index);// of the index'th replicant 524 525 if ((err = target.SendMessage(&request, &reply)) != B_OK) 526 return err; 527 528 int32 uid; 529 if ((err = reply.FindInt32("result", &uid)) != B_OK) 530 return err; 531 532 return uid; 533 } 534 535 536 // 537 status_t 538 AddOnManager::GetReplicantName(BMessenger target, int32 uid, BMessage *reply) const 539 { 540 /* 541 We send a message to the target shelf, asking it for the Name of the 542 replicant with the given unique id. 543 */ 544 545 BMessage request(B_GET_PROPERTY); 546 BMessage uid_specifier(B_ID_SPECIFIER);// specifying via ID 547 status_t err; 548 status_t e; 549 550 request.AddSpecifier("Name");// ask for the Name of the replicant 551 552 // IDs are specified using code like the following 3 lines: 553 uid_specifier.AddInt32("id", uid); 554 uid_specifier.AddString("property", "Replicant"); 555 request.AddSpecifier(&uid_specifier); 556 557 if ((err = target.SendMessage(&request, reply)) != B_OK) 558 return err; 559 560 if (((err = reply->FindInt32("error", &e)) != B_OK) || (e != B_OK)) 561 return err ? err : e; 562 563 return B_OK; 564 } 565 566 // 567 status_t 568 AddOnManager::GetReplicantView(BMessenger target, int32 uid, BMessage *reply) const 569 { 570 /* 571 We send a message to the target shelf, asking it for the Name of the 572 replicant with the given unique id. 573 */ 574 575 BMessage request(B_GET_PROPERTY); 576 BMessage uid_specifier(B_ID_SPECIFIER);// specifying via ID 577 status_t err; 578 status_t e; 579 580 request.AddSpecifier("View");// ask for the Name of the replicant 581 582 // IDs are specified using code like the following 3 lines: 583 uid_specifier.AddInt32("id", uid); 584 uid_specifier.AddString("property", "Replicant"); 585 request.AddSpecifier(&uid_specifier); 586 587 if ((err = target.SendMessage(&request, reply)) != B_OK) 588 return err; 589 590 if (((err = reply->FindInt32("error", &e)) != B_OK) || (e != B_OK)) 591 return err ? err : e; 592 593 return B_OK; 594 } 595 596 597 /* 598 * Method: AddOnManager::MessageReceived() 599 * Descr: 600 */ 601 void 602 AddOnManager::MessageReceived(BMessage *message) 603 { 604 CALLED(); 605 606 BMessage reply; 607 status_t status = B_OK; 608 609 PRINT(("%s what:%c%c%c%c\n", __PRETTY_FUNCTION__, message->what>>24, message->what>>16, message->what>>8, message->what)); 610 611 switch(message->what) 612 { 613 case IS_FIND_DEVICES: 614 status = HandleFindDevices(message, &reply); 615 break; 616 case IS_WATCH_DEVICES: 617 status = HandleWatchDevices(message, &reply); 618 break; 619 case IS_IS_DEVICE_RUNNING: 620 status = HandleIsDeviceRunning(message, &reply); 621 break; 622 case IS_START_DEVICE: 623 status = HandleStartStopDevices(message, &reply); 624 break; 625 case IS_STOP_DEVICE: 626 status = HandleStartStopDevices(message, &reply); 627 break; 628 case IS_CONTROL_DEVICES: 629 status = HandleControlDevices(message, &reply); 630 break; 631 case SYSTEM_SHUTTING_DOWN: 632 status = HandleSystemShuttingDown(message, &reply); 633 break; 634 case IS_METHOD_REGISTER: 635 status = HandleMethodReplicant(message, &reply); 636 break; 637 default: 638 { 639 return; 640 } 641 } 642 643 reply.AddInt32("status", status); 644 message->SendReply(&reply); 645 } 646 647 648 /* 649 * Method: AddOnManager::HandleStartStopDevices() 650 * Descr: 651 */ 652 status_t 653 AddOnManager::HandleStartStopDevices(BMessage *message, 654 BMessage *reply) 655 { 656 const char *name = NULL; 657 int32 type = 0; 658 if (! ((message->FindInt32("type", &type)!=B_OK) ^ (message->FindString("device", &name)!=B_OK))) 659 return B_ERROR; 660 661 return InputServer::StartStopDevices(name, (input_device_type)type, message->what == IS_START_DEVICE); 662 } 663 664 665 /* 666 * Method: AddOnManager::HandleFindDevices() 667 * Descr: 668 */ 669 status_t 670 AddOnManager::HandleFindDevices(BMessage *message, 671 BMessage *reply) 672 { 673 CALLED(); 674 const char *name = NULL; 675 message->FindString("device", &name); 676 677 for (int i = InputServer::gInputDeviceList.CountItems() - 1; i >= 0; i--) { 678 InputDeviceListItem* item = (InputDeviceListItem*)InputServer::gInputDeviceList.ItemAt(i); 679 if (!item) 680 continue; 681 682 if (!name || strcmp(name, item->mDev.name) == 0) { 683 reply->AddString("device", item->mDev.name); 684 reply->AddInt32("type", item->mDev.type); 685 if (name) 686 return B_OK; 687 } 688 } 689 690 return B_OK; 691 } 692 693 694 /* 695 * Method: AddOnManager::HandleWatchDevices() 696 * Descr: 697 */ 698 status_t 699 AddOnManager::HandleWatchDevices(BMessage *message, 700 BMessage *reply) 701 { 702 // TODO 703 return B_OK; 704 } 705 706 707 /* 708 * Method: AddOnManager::HandleIsDeviceRunning() 709 * Descr: 710 */ 711 status_t 712 AddOnManager::HandleIsDeviceRunning(BMessage *message, 713 BMessage *reply) 714 { 715 const char *name = NULL; 716 if (message->FindString("device", &name)!=B_OK) 717 return B_ERROR; 718 719 for (int i = InputServer::gInputDeviceList.CountItems() - 1; i >= 0; i--) { 720 InputDeviceListItem* item = (InputDeviceListItem*)InputServer::gInputDeviceList.ItemAt(i); 721 if (!item) 722 continue; 723 724 if (strcmp(name, item->mDev.name) == 0) 725 return (item->mStarted) ? B_OK : B_ERROR; 726 } 727 728 return B_ERROR; 729 } 730 731 732 /* 733 * Method: AddOnManager::HandleControlDevices() 734 * Descr: 735 */ 736 status_t 737 AddOnManager::HandleControlDevices(BMessage *message, 738 BMessage *reply) 739 { 740 CALLED(); 741 const char *name = NULL; 742 int32 type = 0; 743 if (! ((message->FindInt32("type", &type)!=B_OK) ^ (message->FindString("device", &name)!=B_OK))) 744 return B_ERROR; 745 746 uint32 code = 0; 747 BMessage msg; 748 bool isMessage = true; 749 if (message->FindInt32("code", (int32*)&code)!=B_OK) 750 return B_ERROR; 751 if (message->FindMessage("message", &msg)!=B_OK) 752 isMessage = false; 753 754 return InputServer::ControlDevices(name, (input_device_type)type, code, isMessage ? &msg : NULL); 755 } 756 757 758 /* 759 * Method: AddOnManager::HandleSystemShuttingDown() 760 * Descr: 761 */ 762 status_t 763 AddOnManager::HandleSystemShuttingDown(BMessage *message, 764 BMessage *reply) 765 { 766 CALLED(); 767 768 // TODO 769 return B_OK; 770 } 771 772 /* 773 * Method: AddOnManager::HandleMethodReplicant() 774 * Descr: 775 */ 776 status_t 777 AddOnManager::HandleMethodReplicant(BMessage *message, 778 BMessage *reply) 779 { 780 CALLED(); 781 LoadReplicant(); 782 783 BAutolock lock(InputServer::gInputMethodListLocker); 784 785 if (((InputServer*)be_app)->MethodReplicant()) { 786 _BMethodAddOn_ *addon = InputServer::gKeymapMethod.fOwner; 787 addon->AddMethod(); 788 789 for (int32 i=0; i<InputServer::gInputMethodList.CountItems(); i++) { 790 BInputServerMethod *method = 791 (BInputServerMethod *)InputServer::gInputMethodList.ItemAt(i); 792 _BMethodAddOn_ *addon = method->fOwner; 793 addon->AddMethod(); 794 } 795 } 796 797 return B_OK; 798 } 799