1 /* 2 ** Copyright 2004, the OpenBeOS project. All rights reserved. 3 ** Distributed under the terms of the OpenBeOS License. 4 ** 5 ** Author : Jérôme Duval 6 ** Original authors: Marcus Overhagen, Axel Dörfler 7 */ 8 9 10 #include <Autolock.h> 11 #include <Directory.h> 12 #include <Entry.h> 13 #include <FindDirectory.h> 14 #include <Path.h> 15 #include <String.h> 16 17 #include <image.h> 18 #include <stdio.h> 19 #include <string.h> 20 21 #include "AddOnManager.h" 22 #include "InputServer.h" 23 24 25 AddOnManager::AddOnManager() 26 : 27 fLock("add-on manager") 28 { 29 } 30 31 32 AddOnManager::~AddOnManager() 33 { 34 } 35 36 37 void 38 AddOnManager::LoadState() 39 { 40 RegisterAddOns(); 41 } 42 43 44 void 45 AddOnManager::SaveState() 46 { 47 CALLED(); 48 UnregisterAddOns(); 49 } 50 51 52 status_t 53 AddOnManager::RegisterAddOn(BEntry &entry) 54 { 55 BPath path(&entry); 56 57 entry_ref ref; 58 status_t status = entry.GetRef(&ref); 59 if (status < B_OK) 60 return status; 61 62 printf("AddOnManager::RegisterAddOn(): trying to load \"%s\"\n", path.Path()); 63 64 image_id addon_image = load_add_on(path.Path()); 65 66 if (addon_image < B_OK) 67 return addon_image; 68 69 BEntry parent; 70 entry.GetParent(&parent); 71 BPath parentPath(&parent); 72 BString pathString = parentPath.Path(); 73 74 if (pathString.FindFirst("input_server/devices")>0) { 75 BInputServerDevice *(*instantiate_func)(); 76 77 if (get_image_symbol(addon_image, "instantiate_input_device", 78 B_SYMBOL_TYPE_TEXT, (void **)&instantiate_func) < B_OK) { 79 printf("AddOnManager::RegisterAddOn(): can't find instantiate_input_device in \"%s\"\n", 80 path.Path()); 81 goto exit_error; 82 } 83 84 BInputServerDevice *isd = (*instantiate_func)(); 85 if (isd == NULL) { 86 printf("AddOnManager::RegisterAddOn(): instantiate_input_device in \"%s\" returned NULL\n", 87 path.Path()); 88 goto exit_error; 89 } 90 status_t status = isd->InitCheck(); 91 if (status != B_OK) { 92 printf("AddOnManager::RegisterAddOn(): BInputServerDevice.InitCheck in \"%s\" returned %s\n", 93 path.Path(), strerror(status)); 94 delete isd; 95 goto exit_error; 96 } 97 98 RegisterDevice(isd, ref, addon_image); 99 100 101 } else if (pathString.FindFirst("input_server/filters")>0) { 102 BInputServerFilter *(*instantiate_func)(); 103 104 if (get_image_symbol(addon_image, "instantiate_input_filter", 105 B_SYMBOL_TYPE_TEXT, (void **)&instantiate_func) < B_OK) { 106 printf("AddOnManager::RegisterAddOn(): can't find instantiate_input_filter in \"%s\"\n", 107 path.Path()); 108 goto exit_error; 109 } 110 111 BInputServerFilter *isf = (*instantiate_func)(); 112 if (isf == NULL) { 113 printf("AddOnManager::RegisterAddOn(): instantiate_input_filter in \"%s\" returned NULL\n", 114 path.Path()); 115 goto exit_error; 116 } 117 status_t status = isf->InitCheck(); 118 if (status != B_OK) { 119 printf("AddOnManager::RegisterAddOn(): BInputServerFilter.InitCheck in \"%s\" returned %s\n", 120 path.Path(), strerror(status)); 121 delete isf; 122 goto exit_error; 123 } 124 125 RegisterFilter(isf, ref, addon_image); 126 127 } else if (pathString.FindFirst("input_server/methods")>0) { 128 BInputServerMethod *(*instantiate_func)(); 129 130 if (get_image_symbol(addon_image, "instantiate_input_method", 131 B_SYMBOL_TYPE_TEXT, (void **)&instantiate_func) < B_OK) { 132 printf("AddOnManager::RegisterAddOn(): can't find instantiate_input_method in \"%s\"\n", 133 path.Path()); 134 goto exit_error; 135 } 136 137 BInputServerMethod *ism = (*instantiate_func)(); 138 if (ism == NULL) { 139 printf("AddOnManager::RegisterAddOn(): instantiate_input_method in \"%s\" returned NULL\n", 140 path.Path()); 141 goto exit_error; 142 } 143 status_t status = ism->InitCheck(); 144 if (status != B_OK) { 145 printf("AddOnManager::RegisterAddOn(): BInputServerMethod.InitCheck in \"%s\" returned %s\n", 146 path.Path(), strerror(status)); 147 delete ism; 148 goto exit_error; 149 } 150 151 RegisterMethod(ism, ref, addon_image); 152 153 } 154 155 return B_OK; 156 exit_error: 157 unload_add_on(addon_image); 158 159 return status; 160 } 161 162 163 status_t 164 AddOnManager::UnregisterAddOn(BEntry &entry) 165 { 166 BPath path(&entry); 167 168 entry_ref ref; 169 status_t status = entry.GetRef(&ref); 170 if (status < B_OK) 171 return status; 172 173 PRINT(("AddOnManager::UnregisterAddOn(): trying to unload \"%s\"\n", path.Path())); 174 175 BEntry parent; 176 entry.GetParent(&parent); 177 BPath parentPath(&parent); 178 BString pathString = parentPath.Path(); 179 180 BAutolock locker(fLock); 181 182 if (pathString.FindFirst("input_server/devices")>0) { 183 device_info *pinfo; 184 for (fDeviceList.Rewind(); fDeviceList.GetNext(&pinfo);) { 185 if (!strcmp(pinfo->ref.name, ref.name)) { 186 InputServer::StartStopDevices(pinfo->isd, false); 187 delete pinfo->isd; 188 if (pinfo->addon_image >= B_OK) 189 unload_add_on(pinfo->addon_image); 190 fDeviceList.RemoveCurrent(); 191 break; 192 } 193 } 194 } else if (pathString.FindFirst("input_server/filters")>0) { 195 filter_info *pinfo; 196 for (fFilterList.Rewind(); fFilterList.GetNext(&pinfo);) { 197 if (!strcmp(pinfo->ref.name, ref.name)) { 198 delete pinfo->isf; 199 if (pinfo->addon_image >= B_OK) 200 unload_add_on(pinfo->addon_image); 201 fFilterList.RemoveCurrent(); 202 break; 203 } 204 } 205 } else if (pathString.FindFirst("input_server/methods")>0) { 206 method_info *pinfo; 207 for (fMethodList.Rewind(); fMethodList.GetNext(&pinfo);) { 208 if (!strcmp(pinfo->ref.name, ref.name)) { 209 delete pinfo->ism; 210 if (pinfo->addon_image >= B_OK) 211 unload_add_on(pinfo->addon_image); 212 fMethodList.RemoveCurrent(); 213 break; 214 } 215 } 216 } 217 218 return B_OK; 219 } 220 221 void 222 AddOnManager::RegisterAddOns() 223 { 224 class IAHandler : public AddOnMonitorHandler { 225 private: 226 AddOnManager * fManager; 227 public: 228 IAHandler(AddOnManager * manager) { 229 fManager = manager; 230 } 231 virtual void AddOnCreated(const add_on_entry_info * entry_info) { 232 } 233 virtual void AddOnEnabled(const add_on_entry_info * entry_info) { 234 CALLED(); 235 entry_ref ref; 236 make_entry_ref(entry_info->dir_nref.device, entry_info->dir_nref.node, 237 entry_info->name, &ref); 238 BEntry entry(&ref, false); 239 fManager->RegisterAddOn(entry); 240 } 241 virtual void AddOnDisabled(const add_on_entry_info * entry_info) { 242 CALLED(); 243 entry_ref ref; 244 make_entry_ref(entry_info->dir_nref.device, entry_info->dir_nref.node, 245 entry_info->name, &ref); 246 BEntry entry(&ref, false); 247 fManager->UnregisterAddOn(entry); 248 } 249 virtual void AddOnRemoved(const add_on_entry_info * entry_info) { 250 } 251 }; 252 253 const directory_which directories[] = { 254 B_USER_ADDONS_DIRECTORY, 255 B_COMMON_ADDONS_DIRECTORY, 256 B_BEOS_ADDONS_DIRECTORY, 257 }; 258 const char subDirectories[][24] = { 259 "input_server/devices", 260 "input_server/filters", 261 "input_server/methods", 262 }; 263 fHandler = new IAHandler(this); 264 fAddOnMonitor = new AddOnMonitor(fHandler); 265 266 node_ref nref; 267 BDirectory directory; 268 BPath path; 269 for (uint i = 0 ; i < sizeof(directories) / sizeof(directory_which) ; i++) 270 for (uint j = 0 ; j < sizeof(subDirectories) / sizeof(char[24]) ; j++) { 271 if ((find_directory(directories[i], &path) == B_OK) 272 && (path.Append(subDirectories[j]) == B_OK) 273 && (directory.SetTo(path.Path()) == B_OK) 274 && (directory.GetNodeRef(&nref) == B_OK)) { 275 fHandler->AddDirectory(&nref); 276 } 277 } 278 279 } 280 281 282 void 283 AddOnManager::UnregisterAddOns() 284 { 285 BMessenger messenger(fAddOnMonitor); 286 messenger.SendMessage(B_QUIT_REQUESTED); 287 int32 exit_value; 288 wait_for_thread(fAddOnMonitor->Thread(), &exit_value); 289 delete fHandler; 290 291 BAutolock locker(fLock); 292 293 // we have to stop manually the addons because the monitor doesn't disable them on exit 294 295 { 296 device_info *pinfo; 297 for (fDeviceList.Rewind(); fDeviceList.GetNext(&pinfo);) { 298 InputServer::StartStopDevices(pinfo->isd, false); 299 delete pinfo->isd; 300 if (pinfo->addon_image >= B_OK) 301 unload_add_on(pinfo->addon_image); 302 fDeviceList.RemoveCurrent(); 303 } 304 } 305 306 { 307 filter_info *pinfo; 308 for (fFilterList.Rewind(); fFilterList.GetNext(&pinfo);) { 309 delete pinfo->isf; 310 if (pinfo->addon_image >= B_OK) 311 unload_add_on(pinfo->addon_image); 312 fFilterList.RemoveCurrent(); 313 } 314 } 315 316 { 317 method_info *pinfo; 318 for (fMethodList.Rewind(); fMethodList.GetNext(&pinfo);) { 319 delete pinfo->ism; 320 if (pinfo->addon_image >= B_OK) 321 unload_add_on(pinfo->addon_image); 322 fMethodList.RemoveCurrent(); 323 } 324 } 325 } 326 327 328 void 329 AddOnManager::RegisterDevice(BInputServerDevice *device, const entry_ref &ref, image_id addon_image) 330 { 331 BAutolock locker(fLock); 332 333 device_info *pinfo; 334 for (fDeviceList.Rewind(); fDeviceList.GetNext(&pinfo);) { 335 if (!strcmp(pinfo->ref.name, ref.name)) { 336 // we already know this device 337 return; 338 } 339 } 340 341 PRINT(("AddOnManager::RegisterDevice, name %s\n", ref.name)); 342 343 device_info info; 344 info.ref = ref; 345 info.addon_image = addon_image; 346 info.isd = device; 347 348 fDeviceList.Insert(info); 349 } 350 351 352 void 353 AddOnManager::RegisterFilter(BInputServerFilter *filter, const entry_ref &ref, image_id addon_image) 354 { 355 BAutolock locker(fLock); 356 357 filter_info *pinfo; 358 for (fFilterList.Rewind(); fFilterList.GetNext(&pinfo);) { 359 if (!strcmp(pinfo->ref.name, ref.name)) { 360 // we already know this ref 361 return; 362 } 363 } 364 365 PRINT(("%s, name %s\n", __PRETTY_FUNCTION__, ref.name)); 366 367 filter_info info; 368 info.ref = ref; 369 info.addon_image = addon_image; 370 info.isf = filter; 371 372 fFilterList.Insert(info); 373 374 BAutolock lock2(InputServer::gInputFilterListLocker); 375 376 InputServer::gInputFilterList.AddItem(filter); 377 } 378 379 380 void 381 AddOnManager::RegisterMethod(BInputServerMethod *method, const entry_ref &ref, image_id addon_image) 382 { 383 BAutolock locker(fLock); 384 385 method_info *pinfo; 386 for (fMethodList.Rewind(); fMethodList.GetNext(&pinfo);) { 387 if (!strcmp(pinfo->ref.name, ref.name)) { 388 // we already know this ref 389 return; 390 } 391 } 392 393 PRINT(("%s, name %s\n", __PRETTY_FUNCTION__, ref.name)); 394 395 method_info info; 396 info.ref = ref; 397 info.addon_image = addon_image; 398 info.ism = method; 399 400 fMethodList.Insert(info); 401 402 BAutolock lock2(InputServer::gInputMethodListLocker); 403 404 InputServer::gInputMethodList.AddItem(method); 405 } 406 407 408