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