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