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 26 namespace BPrivate { 27 28 29 DecorInfo::DecorInfo() 30 : 31 fVersion(0), 32 fModificationTime(0), 33 fInitStatus(B_NO_INIT) 34 { 35 } 36 37 38 DecorInfo::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 52 DecorInfo::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 66 DecorInfo::~DecorInfo() 67 { 68 } 69 70 71 status_t 72 DecorInfo::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 85 status_t 86 DecorInfo::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 95 status_t 96 DecorInfo::InitCheck() const 97 { 98 return fInitStatus; 99 } 100 101 102 void 103 DecorInfo::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 119 bool 120 DecorInfo::IsDefault() const 121 { 122 return fPath == "Default"; 123 } 124 125 126 BString 127 DecorInfo::Path() const 128 { 129 return fPath; 130 } 131 132 133 const entry_ref* 134 DecorInfo::Ref() const 135 { 136 if (InitCheck() != B_OK || IsDefault()) 137 return NULL; 138 return &fRef; 139 } 140 141 142 BString 143 DecorInfo::Name() const 144 { 145 return fName; 146 } 147 148 149 BString 150 DecorInfo::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 161 BString 162 DecorInfo::Authors() const 163 { 164 return fAuthors; 165 } 166 167 168 BString 169 DecorInfo::ShortDescription() const 170 { 171 return fShortDescription; 172 } 173 174 175 BString 176 DecorInfo::LongDescription() const 177 { 178 return fLongDescription; 179 } 180 181 182 BString 183 DecorInfo::LicenseURL() const 184 { 185 return fLicenseURL; 186 } 187 188 189 BString 190 DecorInfo::LicenseName() const 191 { 192 return fLicenseName; 193 } 194 195 196 BString 197 DecorInfo::SupportURL() const 198 { 199 return fSupportURL; 200 } 201 202 203 float 204 DecorInfo::Version() const 205 { 206 return fVersion; 207 } 208 209 210 time_t 211 DecorInfo::ModificationTime() const 212 { 213 return fModificationTime; 214 } 215 216 217 bool 218 DecorInfo::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 249 void 250 DecorInfo::_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 356 DecorInfoUtility::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 376 DecorInfoUtility::~DecorInfoUtility() 377 { 378 BAutolock _(fLock); 379 for (int i = fList.CountItems() - 1; i >= 0; --i) 380 delete fList.ItemAt(i); 381 } 382 383 384 status_t 385 DecorInfoUtility::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 469 int32 470 DecorInfoUtility::CountDecorators() 471 { 472 BAutolock _(fLock); 473 if (!fHasScanned) 474 ScanDecorators(); 475 476 return fList.CountItems(); 477 } 478 479 480 DecorInfo* 481 DecorInfoUtility::DecoratorAt(int32 index) 482 { 483 BAutolock _(fLock); 484 return fList.ItemAt(index); 485 } 486 487 488 DecorInfo* 489 DecorInfoUtility::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 517 DecorInfo* 518 DecorInfoUtility::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 530 DecorInfo* 531 DecorInfoUtility::DefaultDecorator() 532 { 533 BAutolock _(fLock); 534 return fList.ItemAt(0); 535 } 536 537 538 bool 539 DecorInfoUtility::IsCurrentDecorator(DecorInfo* decor) 540 { 541 BAutolock _(fLock); 542 if (decor == NULL) 543 return false; 544 return decor->Path() == CurrentDecorator()->Path(); 545 } 546 547 548 status_t 549 DecorInfoUtility::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 562 status_t 563 DecorInfoUtility::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 577 status_t 578 DecorInfoUtility::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 590 DecorInfo* 591 DecorInfoUtility::_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 619 status_t 620 DecorInfoUtility::_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