1 /* 2 * Public domain source code. 3 * 4 * Author: 5 * Joseph "looncraz" Groover <looncraz@satx.rr.com> 6 */ 7 8 9 #include <DecorInfo.h> 10 11 #include <new> 12 #include <stdio.h> 13 14 #include <Autolock.h> 15 #include <Directory.h> 16 #include <FindDirectory.h> 17 #include <Path.h> 18 #include <Resources.h> 19 20 #include <DecoratorPrivate.h> 21 22 23 namespace BPrivate { 24 25 26 DecorInfo::DecorInfo() 27 : 28 fVersion(0), 29 fModificationTime(0), 30 fInitStatus(B_NO_INIT) 31 { 32 } 33 34 35 DecorInfo::DecorInfo(const BString& path) 36 : 37 fPath(path), 38 fVersion(0), 39 fModificationTime(0), 40 fInitStatus(B_NO_INIT) 41 { 42 BEntry entry(path.String(), true); 43 entry.GetRef(&fRef); 44 45 _Init(); 46 } 47 48 49 DecorInfo::DecorInfo(const entry_ref& ref) 50 : 51 fRef(ref), 52 fVersion(0), 53 fModificationTime(0), 54 fInitStatus(B_NO_INIT) 55 { 56 BPath path(&ref); 57 fPath = path.Path(); 58 59 _Init(); 60 } 61 62 63 DecorInfo::~DecorInfo() 64 { 65 } 66 67 68 status_t 69 DecorInfo::SetTo(const entry_ref& ref) 70 { 71 Unset(); 72 73 BPath path(&ref); 74 fPath = path.Path(); 75 fRef = ref; 76 _Init(); 77 78 return InitCheck(); 79 } 80 81 82 status_t 83 DecorInfo::SetTo(BString path) 84 { 85 BEntry entry(path.String(), true); 86 entry_ref ref; 87 entry.GetRef(&ref); 88 return SetTo(ref); 89 } 90 91 92 status_t 93 DecorInfo::InitCheck() const 94 { 95 return fInitStatus; 96 } 97 98 99 void 100 DecorInfo::Unset() 101 { 102 fRef = entry_ref(); 103 fPath = ""; 104 fName = ""; 105 fAuthors = ""; 106 fShortDescription = ""; 107 fLicenseURL = ""; 108 fLicenseName = ""; 109 fSupportURL = ""; 110 fVersion = 0; 111 fModificationTime = 0; 112 fInitStatus = B_NO_INIT; 113 } 114 115 116 bool 117 DecorInfo::IsDefault() const 118 { 119 return fInitStatus == B_OK && fPath == "Default"; 120 } 121 122 123 BString 124 DecorInfo::Path() const 125 { 126 return fPath; 127 } 128 129 130 const entry_ref* 131 DecorInfo::Ref() const 132 { 133 if (InitCheck() != B_OK || IsDefault()) 134 return NULL; 135 return &fRef; 136 } 137 138 139 BString 140 DecorInfo::Name() const 141 { 142 return fName; 143 } 144 145 146 BString 147 DecorInfo::ShortcutName() const 148 { 149 if (Ref()) 150 return fRef.name; 151 return Name(); 152 } 153 154 155 BString 156 DecorInfo::Authors() const 157 { 158 return fAuthors; 159 } 160 161 162 BString 163 DecorInfo::ShortDescription() const 164 { 165 return fShortDescription; 166 } 167 168 169 BString 170 DecorInfo::LongDescription() const 171 { 172 return fLongDescription; 173 } 174 175 176 BString 177 DecorInfo::LicenseURL() const 178 { 179 return fLicenseURL; 180 } 181 182 183 BString 184 DecorInfo::LicenseName() const 185 { 186 return fLicenseName; 187 } 188 189 190 BString 191 DecorInfo::SupportURL() const 192 { 193 return fSupportURL; 194 } 195 196 197 float 198 DecorInfo::Version() const 199 { 200 return fVersion; 201 } 202 203 204 time_t 205 DecorInfo::ModificationTime() const 206 { 207 return fModificationTime; 208 } 209 210 211 bool 212 DecorInfo::CheckForChanges(bool& deleted) 213 { 214 if (InitCheck() != B_OK) 215 return false; 216 217 BEntry entry(&fRef); 218 219 if (entry.InitCheck() != B_OK) 220 return false; 221 222 if (!entry.Exists()) { 223 deleted = true; 224 return true; 225 } 226 227 time_t modtime = 0; 228 if (entry.GetModificationTime(&modtime) != B_OK) { 229 fprintf(stderr, "DecorInfo::CheckForChanges()\tERROR: " 230 "BEntry:GetModificationTime() failed\n"); 231 return false; 232 } 233 234 if (fModificationTime != modtime) { 235 _Init(true); 236 return true; 237 } 238 239 return false; 240 } 241 242 243 void 244 DecorInfo::_Init(bool isUpdate) 245 { 246 if (!isUpdate && InitCheck() != B_NO_INIT) { 247 // TODO: remove after validation 248 fprintf(stderr, "DecorInfo::_Init()\tImproper init state\n"); 249 return; 250 } 251 252 BEntry entry; 253 254 if (fPath == "Default") { 255 if (isUpdate){ 256 // should never happen 257 fprintf(stderr, "DecorInfo::_Init(true)\tBUG BUG updating default" 258 "decorator!?!?!\n"); 259 return; 260 } 261 262 fName = "Default"; 263 fAuthors = "DarkWyrm, Stephan Aßmus, Clemens Zeidler, Ingo Weinhold"; 264 fShortDescription = "Default Haiku window decorator."; 265 fLongDescription = fShortDescription; 266 fLicenseURL = "http://"; 267 fLicenseName = "MIT"; 268 fSupportURL = "http://www.haiku-os.org/"; 269 fVersion = 0.5; 270 fInitStatus = B_OK; 271 272 // The following is to get the modification time of the app_server 273 // and, thusly, the Default decorator... 274 // If you can make it more simple, please do! 275 BPath path; 276 find_directory(B_BEOS_SERVERS_DIRECTORY, &path); 277 path.Append("app_server"); 278 entry.SetTo(path.Path(), true); 279 if (!entry.Exists()) { 280 fprintf(stderr, "Server MIA the world has become its slave! " 281 "Call the CIA!\n"); 282 return; 283 } 284 285 entry.GetModificationTime(&fModificationTime); 286 return; 287 } 288 289 // Is a file system object... 290 291 entry.SetTo(&fRef, true); // follow link 292 if (entry.InitCheck() != B_OK) { 293 fInitStatus = entry.InitCheck(); 294 return; 295 } 296 297 if (!entry.Exists()) { 298 if (isUpdate) { 299 fprintf(stderr, "DecorInfo::_Init()\tERROR: decorator deleted" 300 " after CheckForChanges() found it!\n"); 301 fprintf(stderr, "DecorInfo::_Init()\tERROR: DecorInfo will " 302 "Unset\n"); 303 Unset(); 304 } 305 return; 306 } 307 308 // update fRef to match file system object 309 entry.GetRef(&fRef); 310 entry.GetModificationTime(&fModificationTime); 311 312 BResources resources(&fRef); 313 if (resources.InitCheck() != B_OK) { 314 fprintf(stderr, "DecorInfo::_Init()\t BResource InitCheck() failure\n"); 315 return; 316 } 317 318 size_t infoSize = 0; 319 const void* infoData = resources.LoadResource(B_MESSAGE_TYPE, 320 "be:decor:info", &infoSize); 321 BMessage infoMessage; 322 323 if (infoData == NULL || infoSize == 0 324 || infoMessage.Unflatten((const char*)infoData) != B_OK) { 325 fprintf(stderr, "DecorInfo::_init()\tNo extended information found for" 326 " \"%s\"\n", fRef.name); 327 } else { 328 infoMessage.FindString("name", &fName); 329 infoMessage.FindString("authors", &fAuthors); 330 infoMessage.FindString("short_descr", &fShortDescription); 331 infoMessage.FindString("long_descr", &fLongDescription); 332 infoMessage.FindString("lic_url", &fLicenseURL); 333 infoMessage.FindString("lic_name", &fLicenseName); 334 infoMessage.FindString("support_url", &fSupportURL); 335 infoMessage.FindFloat ("version", &fVersion); 336 } 337 338 fInitStatus = B_OK; 339 fName = fRef.name; 340 } 341 342 343 // #pragma mark - DecorInfoUtility 344 345 346 DecorInfoUtility::DecorInfoUtility(bool scanNow) 347 : 348 fHasScanned(false) 349 { 350 // get default decorator from app_server 351 DecorInfo* info = new(std::nothrow) DecorInfo("Default"); 352 if (info == NULL || info->InitCheck() != B_OK) { 353 delete info; 354 fprintf(stderr, "DecorInfoUtility::constructor\tdefault decorator's " 355 "DecorInfo failed InitCheck()\n"); 356 return; 357 } 358 359 fList.AddItem(info); 360 361 if (scanNow) 362 ScanDecorators(); 363 } 364 365 366 DecorInfoUtility::~DecorInfoUtility() 367 { 368 BAutolock _(fLock); 369 for (int i = fList.CountItems() - 1; i >= 0; --i) 370 delete fList.ItemAt(i); 371 } 372 373 374 status_t 375 DecorInfoUtility::ScanDecorators() 376 { 377 BPath decorPath; 378 status_t ret = find_directory(B_USER_ADDONS_DIRECTORY, &decorPath); 379 if (ret != B_OK) 380 return ret; 381 ret = decorPath.Append("decorators"); 382 if (ret != B_OK) 383 return ret; 384 385 BDirectory dir(decorPath.Path()); 386 ret = dir.InitCheck(); 387 if (ret != B_OK) { 388 fprintf(stderr, "DecorInfoUtility::ScanDecorators:\tERROR: " 389 "DECORATORS_DIR not found!\n"); 390 return ret; 391 } 392 393 BAutolock _(fLock); 394 // First, run through our list and DecorInfos CheckForChanges() 395 396 if (fHasScanned) { 397 for (int i = fList.CountItems() - 1; i > 0; --i) { 398 DecorInfo* decorInfo = fList.ItemAt(i); 399 400 bool deleted = false; 401 decorInfo->CheckForChanges(deleted); 402 403 if (deleted) { 404 fList.RemoveItem(decorInfo); 405 delete decorInfo; 406 } 407 } 408 } 409 410 BPath path; 411 entry_ref ref; 412 // Now, look at file system, skip the entries for which we already have 413 // a DecorInfo in the list. 414 while (dir.GetNextRef(&ref) == B_OK) { 415 path.SetTo(decorPath.Path()); 416 path.Append(ref.name); 417 if (_FindDecor(path.Path()) != NULL) 418 continue; 419 420 DecorInfo* decorInfo = new(std::nothrow) DecorInfo(ref); 421 if (decorInfo == NULL || decorInfo->InitCheck() != B_OK) { 422 fprintf(stderr, "DecorInfoUtility::ScanDecorators()\tInitCheck() " 423 "failure on decorator, skipping\n"); 424 delete decorInfo; 425 continue; 426 } 427 428 fList.AddItem(decorInfo); 429 } 430 431 fHasScanned = true; 432 433 return B_OK; 434 } 435 436 437 int32 438 DecorInfoUtility::CountDecorators() 439 { 440 BAutolock _(fLock); 441 if (!fHasScanned) 442 ScanDecorators(); 443 444 return fList.CountItems(); 445 } 446 447 448 DecorInfo* 449 DecorInfoUtility::DecoratorAt(int32 index) 450 { 451 BAutolock _(fLock); 452 return fList.ItemAt(index); 453 } 454 455 456 DecorInfo* 457 DecorInfoUtility::FindDecorator(const BString& string) 458 { 459 if (string.Length() == 0) 460 return CurrentDecorator(); 461 462 if (string.ICompare("default") == 0) 463 return DefaultDecorator(); 464 465 BAutolock _(fLock); 466 if (!fHasScanned) 467 ScanDecorators(); 468 469 // search by path 470 DecorInfo* decor = _FindDecor(string); 471 if (decor != NULL) 472 return decor; 473 474 // search by name or short cut name 475 for (int i = 1; i < fList.CountItems(); ++i) { 476 decor = fList.ItemAt(i); 477 if (string.ICompare(decor->ShortcutName()) == 0 478 || string.ICompare(decor->Name()) == 0) { 479 return decor; 480 } 481 } 482 483 return NULL; 484 } 485 486 487 DecorInfo* 488 DecorInfoUtility::CurrentDecorator() 489 { 490 BAutolock _(fLock); 491 if (!fHasScanned) 492 ScanDecorators(); 493 494 BString name; 495 get_decorator(name); 496 return FindDecorator(name); 497 } 498 499 500 DecorInfo* 501 DecorInfoUtility::DefaultDecorator() 502 { 503 BAutolock _(fLock); 504 return fList.ItemAt(0); 505 } 506 507 508 bool 509 DecorInfoUtility::IsCurrentDecorator(DecorInfo* decor) 510 { 511 BAutolock _(fLock); 512 if (decor == NULL) 513 return false; 514 return decor->Path() == CurrentDecorator()->Path(); 515 } 516 517 518 status_t 519 DecorInfoUtility::SetDecorator(DecorInfo* decor) 520 { 521 if (decor == NULL) 522 return B_BAD_VALUE; 523 524 BAutolock _(fLock); 525 if (decor->IsDefault()) 526 return set_decorator("Default"); 527 528 return set_decorator(decor->Path()); 529 } 530 531 532 status_t 533 DecorInfoUtility::SetDecorator(int32 index) 534 { 535 BAutolock _(fLock); 536 if (!fHasScanned) 537 return B_ERROR; 538 539 DecorInfo* decor = DecoratorAt(index); 540 if (decor == NULL) 541 return B_BAD_INDEX; 542 543 return SetDecorator(decor); 544 } 545 546 547 status_t 548 DecorInfoUtility::Preview(DecorInfo* decor, BWindow* window) 549 { 550 if (decor == NULL) 551 return B_BAD_VALUE; 552 553 return preview_decorator(decor->Path(), window); 554 } 555 556 557 // #pargma mark - private 558 559 560 DecorInfo* 561 DecorInfoUtility::_FindDecor(const BString& pathString) 562 { 563 // find decor by path and path alone! 564 if (!fLock.IsLocked()) { 565 fprintf(stderr, "DecorInfoUtility::_find_decor()\tfailure to lock! - " 566 "BUG BUG BUG\n"); 567 return NULL; 568 } 569 570 if (pathString == "Default") 571 return fList.ItemAt(0); 572 573 for (int i = 1; i < fList.CountItems(); ++i) { 574 DecorInfo* decor = fList.ItemAt(i); 575 // Find the DecoratorInfo either by its true current location or by 576 // what we still think the location is (before we had a chance to 577 // update). NOTE: This will only catch the case when the user moved the 578 // folder in which the add-on file lives. It will not work when the user 579 // moves the add-on file itself or renames it. 580 BPath path(decor->Ref()); 581 if (path.Path() == pathString || decor->Path() == pathString) 582 return decor; 583 } 584 585 return NULL; 586 } 587 588 589 } // namespace BPrivate 590