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