xref: /haiku/src/servers/input/AddOnManager.cpp (revision 683cbefe9ec156fe9587b9a64a5e1b666a21654d)
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