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