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