xref: /haiku/src/servers/input/AddOnManager.cpp (revision 123406799ff074ff1367777f8751d935cfa95f47)
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:
MonitorHandler(AddOnManager * manager)53 	MonitorHandler(AddOnManager* manager)
54 	{
55 		fManager = manager;
56 	}
57 
AddOnEnabled(const add_on_entry_info * entryInfo)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 
AddOnDisabled(const add_on_entry_info * entryInfo)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*
instantiate_add_on(image_id image,const char * path,const char * type)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 
AddOnManager()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 
~AddOnManager()135 AddOnManager::~AddOnManager()
136 {
137 	delete fHandler;
138 }
139 
140 
141 void
MessageReceived(BMessage * message)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
LoadState()195 AddOnManager::LoadState()
196 {
197 	_RegisterAddOns();
198 }
199 
200 
201 void
SaveState()202 AddOnManager::SaveState()
203 {
204 	CALLED();
205 	_UnregisterAddOns();
206 }
207 
208 
209 status_t
StartMonitoringDevice(DeviceAddOn * addOn,const char * device)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
StopMonitoringDevice(DeviceAddOn * addOn,const char * device)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
_RegisterAddOns()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
_UnregisterAddOns()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
_IsDevice(const char * path) const298 AddOnManager::_IsDevice(const char* path) const
299 {
300 	return strstr(path, "input_server/devices") != 0;
301 }
302 
303 
304 bool
_IsFilter(const char * path) const305 AddOnManager::_IsFilter(const char* path) const
306 {
307 	return strstr(path, "input_server/filters") != 0;
308 }
309 
310 
311 bool
_IsMethod(const char * path) const312 AddOnManager::_IsMethod(const char* path) const
313 {
314 	return strstr(path, "input_server/methods") != 0;
315 }
316 
317 
318 status_t
_RegisterAddOn(BEntry & entry)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
_UnregisterAddOn(BEntry & entry)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
_RegisterDevice(BInputServerDevice * device,const entry_ref & ref,image_id addOnImage)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
_RegisterFilter(BInputServerFilter * filter,const entry_ref & ref,image_id addOnImage)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
_RegisterMethod(BInputServerMethod * method,const entry_ref & ref,image_id addOnImage)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
_UnloadReplicant()578 AddOnManager::_UnloadReplicant()
579 {
580 	BDeskbar().RemoveItem(REPLICANT_CTL_NAME);
581 }
582 
583 
584 void
_LoadReplicant()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
_GetReplicantAt(BMessenger target,int32 index) const640 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
_GetReplicantName(BMessenger target,int32 uid,BMessage * reply) const664 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
_GetReplicantView(BMessenger target,int32 uid,BMessage * reply) const693 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
_HandleStartStopDevices(BMessage * message,BMessage * reply)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
_HandleFindDevices(BMessage * message,BMessage * reply)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
_HandleWatchDevices(BMessage * message,BMessage * reply)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
_HandleNotifyDevice(BMessage * message,BMessage * reply)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
_HandleIsDeviceRunning(BMessage * message,BMessage * reply)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
_HandleControlDevices(BMessage * message,BMessage * reply)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
_HandleSystemShuttingDown(BMessage * message,BMessage * reply)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
_HandleMethodReplicant(BMessage * message,BMessage * reply)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
_HandleDeviceMonitor(BMessage * message)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
_AddDevicePath(DeviceAddOn * addOn,const char * path,bool & newPath)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
_RemoveDevicePath(DeviceAddOn * addOn,const char * path,bool & lastPath)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