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